mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
Compare commits
143 Commits
v0.3.3
...
v0.4.0-23w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4510cbb617 | ||
|
|
2f11988353 | ||
|
|
beb7f1fb73 | ||
|
|
31b328fb48 | ||
|
|
797bad3014 | ||
|
|
5d32e6da33 | ||
|
|
bf2826438f | ||
|
|
e4dc3ac146 | ||
|
|
19f08de756 | ||
|
|
94a207d72a | ||
|
|
3cc51aa774 | ||
|
|
6f0f756fe4 | ||
|
|
37138656f8 | ||
|
|
026cfa5284 | ||
|
|
31e19874ae | ||
|
|
f2974fc854 | ||
|
|
a3e0f7b0b3 | ||
|
|
98c94017ba | ||
|
|
4bea5e9bf9 | ||
|
|
79ffaf6294 | ||
|
|
cada008fca | ||
|
|
46234d3d9d | ||
|
|
eaef2f0c6a | ||
|
|
6ae39d38e3 | ||
|
|
1128fb7f0e | ||
|
|
3acefebfcb | ||
|
|
1ddd012e19 | ||
|
|
4cffe64286 | ||
|
|
8a1dfbeedd | ||
|
|
47a7e55910 | ||
|
|
1aa00d564d | ||
|
|
4c04267cb8 | ||
|
|
b39a4bd008 | ||
|
|
b49556a5a1 | ||
|
|
9bb7ab6956 | ||
|
|
b0bdfd9f43 | ||
|
|
2be8bb2aea | ||
|
|
6b24182de2 | ||
|
|
15f27726b8 | ||
|
|
cbbe5d3e34 | ||
|
|
706f5ac507 | ||
|
|
aef55bdc22 | ||
|
|
fa21800541 | ||
|
|
8d23714832 | ||
|
|
ef6aa842c8 | ||
|
|
0079bc5378 | ||
|
|
3f3e4ad2e7 | ||
|
|
4c09588dc2 | ||
|
|
3764ee21e9 | ||
|
|
f199307353 | ||
|
|
4244a2c395 | ||
|
|
6df348bf86 | ||
|
|
b8b0611479 | ||
|
|
4de7722fc3 | ||
|
|
4262dbec5e | ||
|
|
868e41ee70 | ||
|
|
f07182dfb6 | ||
|
|
56974eeb8c | ||
|
|
757207cf9b | ||
|
|
cc5b9616fe | ||
|
|
f7c32e74cd | ||
|
|
33e93b8e10 | ||
|
|
acae5dab8b | ||
|
|
991a16e6a7 | ||
|
|
76d6579ce9 | ||
|
|
208bf79353 | ||
|
|
00f8d8f850 | ||
|
|
0f82a67a63 | ||
|
|
23a78fc345 | ||
|
|
ffac61fbc5 | ||
|
|
19f1eb2278 | ||
|
|
012d3482dc | ||
|
|
2bd54c8316 | ||
|
|
1667e622bd | ||
|
|
9da2be0b17 | ||
|
|
c83c83a395 | ||
|
|
8e2f3254ff | ||
|
|
98813fb4df | ||
|
|
9a233b8c55 | ||
|
|
98d7c9f326 | ||
|
|
43cb9ec00e | ||
|
|
074c27c6cc | ||
|
|
5322cb7b2b | ||
|
|
a8b44c1cac | ||
|
|
a5a2c98041 | ||
|
|
18ab292e24 | ||
|
|
9145acf741 | ||
|
|
228b0962d6 | ||
|
|
18b2b3c8d6 | ||
|
|
d1d75b88ca | ||
|
|
d9deabb644 | ||
|
|
a432099f19 | ||
|
|
5806388bee | ||
|
|
56d915cd71 | ||
|
|
143f789ea1 | ||
|
|
1b2940637c | ||
|
|
872ab8d946 | ||
|
|
ed2a46e1a6 | ||
|
|
d53ab6ffee | ||
|
|
69345eab57 | ||
|
|
6e90d3521b | ||
|
|
e88b595320 | ||
|
|
f37a28eb17 | ||
|
|
d57f23d4f1 | ||
|
|
6634a8dccb | ||
|
|
647c7ea865 | ||
|
|
90eb033431 | ||
|
|
20f2f2f7b1 | ||
|
|
1af172d354 | ||
|
|
35c46d9a91 | ||
|
|
8613d804e7 | ||
|
|
1cce4e6ee2 | ||
|
|
0a65794756 | ||
|
|
d5074e30eb | ||
|
|
228c9b8127 | ||
|
|
3c79586410 | ||
|
|
d546b081f0 | ||
|
|
4362966128 | ||
|
|
108c4d3e3f | ||
|
|
fd65541c35 | ||
|
|
65997764e6 | ||
|
|
d8abec381b | ||
|
|
58fa1dd56c | ||
|
|
93f1430c5c | ||
|
|
93d33b793c | ||
|
|
3a3d789777 | ||
|
|
6bf535e968 | ||
|
|
00ca1d3e1a | ||
|
|
552cfd5f06 | ||
|
|
e63300339e | ||
|
|
1e15719b9c | ||
|
|
64d30728ff | ||
|
|
3b32242a2b | ||
|
|
26936fde09 | ||
|
|
caffdbf861 | ||
|
|
e76ff58b3e | ||
|
|
8f1ca485f6 | ||
|
|
23c445f014 | ||
|
|
d9218a2dd6 | ||
|
|
dd1e53f761 | ||
|
|
d8cafe7f12 | ||
|
|
ae3a6e9c61 | ||
|
|
f5bc2c9be3 |
Binary file not shown.
Binary file not shown.
BIN
assets/graphics/logo.png
LFS
Normal file
BIN
assets/graphics/logo.png
LFS
Normal file
Binary file not shown.
Binary file not shown.
@@ -32,7 +32,9 @@
|
||||
"MENU_OPTIONS_BLUR": "Blur",
|
||||
"MENU_OPTIONS_DEBUG_CONSOLE": "Debug Console",
|
||||
"MENU_OPTIONS_DITHER": "Dithering",
|
||||
"MENU_OPTIONS_ENABLE_SCRIPT_MODS": "Enable Script Mods",
|
||||
"MENU_OPTIONS_JVM_HEAP_MAX": "Max Heap Memory",
|
||||
"MENU_OPTIONS_LIGHT_UPDATE_PASSES": "Light Calculation Depth",
|
||||
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show notification for",
|
||||
"MENU_OPTIONS_PARTICLES": "Particles",
|
||||
"MENU_OPTIONS_PERFORMANCE": "Performance",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"ERROR_FILE_NOT_FOUND": "File not found.",
|
||||
"ERROR_SAVE_IS_FROM_NEWER_VERSION": "Saved game is newer than the current game version.",
|
||||
"GAME_32BIT_WARNING1": "It looks like you’re running a 32-Bit version of Java.",
|
||||
"GAME_32BIT_WARNING2": "Please download and install the latest 64-Bit Java at:",
|
||||
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
||||
@@ -7,11 +8,18 @@
|
||||
"GAME_APPLE_ROSETTA_WARNING2": "Please use the native build for improved performance and gameplay experiences.",
|
||||
"APP_NOMODULE_1": "No Module is currently loaded.",
|
||||
"APP_NOMODULE_2": "Please configure your Load Order and restart:",
|
||||
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
|
||||
"GAME_PREV_SAVE_WAS_LOADED1": "The most recently saved game was corrupted.",
|
||||
"GAME_PREV_SAVE_WAS_LOADED2": "The previously saved game was loaded.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE1": "The Autosave is more recent than the manual save.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE2": "Please select the saved game you wish to play:",
|
||||
"MENU_IO_LOAD_UPDATING_BLOCK_MAPPINGS": "Updating Block Mappings...",
|
||||
"MENU_IO_WORLDGEN_CARVING_EARTH": "Carving Earth...",
|
||||
"MENU_IO_WORLDGEN_PAINTING_GREEN": "Painting Green...",
|
||||
"MENU_IO_WORLDGEN_GROWING_MINERALS": "Growing Minerals...",
|
||||
"MENU_IO_WORLDGEN_POSITIONING_ROCKS": "Positioning Rocks...",
|
||||
"MENU_IO_WORLDGEN_RETICULATING_SPLINES": "Reticulating Splines...",
|
||||
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
|
||||
"MENU_LABEL_SAVE_WILL_BE_DELETED": "The selected save file will be deleted.",
|
||||
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "Unsaved progress will be lost."
|
||||
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "Unsaved progress will be lost.",
|
||||
"MENU_LABEL_WARN_ACE": "Script mods may damage your game or result in other unexpected behaviour.\nOnly use the mods you know they can be trusted."
|
||||
}
|
||||
@@ -32,7 +32,9 @@
|
||||
"MENU_OPTIONS_BLUR": "흐림",
|
||||
"MENU_OPTIONS_DEBUG_CONSOLE": "디버그 콘솔",
|
||||
"MENU_OPTIONS_DITHER": "디더링",
|
||||
"MENU_OPTIONS_ENABLE_SCRIPT_MODS": "스크립트 모드 활성화",
|
||||
"MENU_OPTIONS_JVM_HEAP_MAX": "최대 힙 메모리",
|
||||
"MENU_OPTIONS_LIGHT_UPDATE_PASSES": "빛 계산 반복 횟수",
|
||||
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "알림 표시 시간",
|
||||
"MENU_OPTIONS_PARTICLES": "입자 수",
|
||||
"MENU_OPTIONS_PERFORMANCE": "성능",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"ERROR_FILE_NOT_FOUND": "파일을 찾을 수 없습니다.",
|
||||
"ERROR_SAVE_IS_FROM_NEWER_VERSION": "저장된 게임이 현재 게임보다 더 최신입니다.",
|
||||
"GAME_32BIT_WARNING1": "32비트 버전의 Java를 사용중인 것 같습니다.",
|
||||
"GAME_32BIT_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
|
||||
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
|
||||
@@ -7,11 +8,18 @@
|
||||
"GAME_APPLE_ROSETTA_WARNING2": "최적의 성능과 게임 경험을 위해 Apple Silicon용 빌드의 게임을 이용해 주십시오.",
|
||||
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
|
||||
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
|
||||
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
|
||||
"GAME_PREV_SAVE_WAS_LOADED1": "가장 최근에 저장된 게임이 손상되었습니다.",
|
||||
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
|
||||
"MENU_IO_LOAD_UPDATING_BLOCK_MAPPINGS": "Updating Block Mappings...",
|
||||
"MENU_IO_WORLDGEN_CARVING_EARTH": "Carving Earth...",
|
||||
"MENU_IO_WORLDGEN_PAINTING_GREEN": "Painting Green...",
|
||||
"MENU_IO_WORLDGEN_GROWING_MINERALS": "Growing Minerals...",
|
||||
"MENU_IO_WORLDGEN_POSITIONING_ROCKS": "Positioning Rocks...",
|
||||
"MENU_IO_WORLDGEN_RETICULATING_SPLINES": "Reticulating Splines...",
|
||||
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
|
||||
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다.",
|
||||
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "저장하지 않은 진행 상황을 잃게 됩니다."
|
||||
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "저장하지 않은 진행 상황을 잃게 됩니다.",
|
||||
"MENU_LABEL_WARN_ACE": "스크립트 모드는 게임을 손상시키거나 다른 예상치 못한 결과를 가져올 수 있습니다.\n신뢰할 수 있는 모드만을 사용하십시오."
|
||||
}
|
||||
|
||||
BIN
assets/mods/basegame/blocks/112.tga
LFS
Normal file
BIN
assets/mods/basegame/blocks/112.tga
LFS
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
assets/mods/basegame/blocks/273.tga
LFS
Normal file
BIN
assets/mods/basegame/blocks/273.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/blocks/274.tga
LFS
Normal file
BIN
assets/mods/basegame/blocks/274.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/blocks/275.tga
LFS
Normal file
BIN
assets/mods/basegame/blocks/275.tga
LFS
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,25 +1,25 @@
|
||||
"id";"drop";"spawn";"name";"shdr";"shdg";"shdb";"shduv";"str";"dsty";"mate";"solid";"wall";"grav";"dlfn";"fv";"fr";"lumr";"lumg";"lumb";"lumuv";"colour";"vscs";"refl";"tags"
|
||||
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INCONSEQUENTIAL,AIR"
|
||||
"1";"0";"0";"BLOCK_UPDATE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INTERNAL"
|
||||
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"AIIR";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INCONSEQUENTIAL,AIR,NORANDTILE"
|
||||
"1";"0";"0";"BLOCK_UPDATE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"AIIR";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INTERNAL,NORANDTILE"
|
||||
"16";"17";"17";"BLOCK_STONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURAL"
|
||||
"17";"17";"17";"BLOCK_STONE_QUARRIED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK"
|
||||
"18";"18";"18";"BLOCK_STONE_TILE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.18";"STONE"
|
||||
"19";"19";"19";"BLOCK_STONE_BRICKS";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"STONE"
|
||||
"17";"17";"17";"BLOCK_STONE_QUARRIED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURAL"
|
||||
"18";"18";"18";"BLOCK_STONE_TILE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.18";"STONE,NORANDTILE"
|
||||
"19";"19";"19";"BLOCK_STONE_BRICKS";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"STONE,NORANDTILE"
|
||||
"20";"20";"20";"BLOCK_STONE_DEEP";"0.1252";"0.1252";"0.1252";"0.1252";"80";"24600";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURAL"
|
||||
"21";"21";"21";"BLOCK_STONE_MARBLE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.1";"ROCK,NATURAL"
|
||||
"32";"32";"32";"BLOCK_DIRT";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"DIRT";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"DIRT,NATURAL"
|
||||
"33";"32";"32";"BLOCK_GRASS";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
"34";"34";"34";"BLOCK_GRASSWALL";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
"35";"35";"35";"BLOCK_FOLIAGE_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LEAVES,NATURAL"
|
||||
"36";"36";"36";"BLOCK_FOLIAGE_LIME";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LEAVES,NATURAL"
|
||||
"37";"37";"37";"BLOCK_FOLIAGE_GOLD";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LEAVES,NATURAL"
|
||||
"38";"38";"38";"BLOCK_FOLIAGE_RED";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LEAVES,NATURAL"
|
||||
"39";"39";"39";"BLOCK_FOLIAGE_ICEBLUE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LEAVES,NATURAL"
|
||||
"40";"40";"40";"BLOCK_FOLIAGE_PURPLE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LEAVES,NATURAL"
|
||||
"48";"48";"48";"BLOCK_PLANK_NORMAL";"0.1252";"0.1252";"0.1252";"0.1252";"16";"740";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD"
|
||||
"49";"49";"49";"BLOCK_PLANK_EBONY";"0.1252";"0.1252";"0.1252";"0.1252";"19";"1200";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD"
|
||||
"50";"50";"50";"BLOCK_PLANK_BIRCH";"0.1252";"0.1252";"0.1252";"0.1252";"15";"670";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD"
|
||||
"51";"51";"51";"BLOCK_PLANK_ROSEWOOD";"0.1252";"0.1252";"0.1252";"0.1252";"17";"900";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD"
|
||||
#"35";"35";"35";"BLOCK_FOLIAGE_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
#"36";"36";"36";"BLOCK_FOLIAGE_LIME";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
#"37";"37";"37";"BLOCK_FOLIAGE_GOLD";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
#"38";"38";"38";"BLOCK_FOLIAGE_RED";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
#"39";"39";"39";"BLOCK_FOLIAGE_ICEBLUE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
#"40";"40";"40";"BLOCK_FOLIAGE_PURPLE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"1400";"GRSS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRASS,NATURAL"
|
||||
"48";"48";"48";"BLOCK_PLANK_NORMAL";"0.1252";"0.1252";"0.1252";"0.1252";"16";"740";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD,NORANDTILE"
|
||||
"49";"49";"49";"BLOCK_PLANK_EBONY";"0.1252";"0.1252";"0.1252";"0.1252";"19";"1200";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD,NORANDTILE"
|
||||
"50";"50";"50";"BLOCK_PLANK_BIRCH";"0.1252";"0.1252";"0.1252";"0.1252";"15";"670";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD,NORANDTILE"
|
||||
"51";"51";"51";"BLOCK_PLANK_ROSEWOOD";"0.1252";"0.1252";"0.1252";"0.1252";"17";"900";"WOOD";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"WOOD,NORANDTILE"
|
||||
"64";"64";"64";"BLOCK_TRUNK_NORMAL";"0.0312";"0.0312";"0.0312";"0.0312";"16";"740";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
||||
"65";"65";"65";"BLOCK_TRUNK_EBONY";"0.0312";"0.0312";"0.0312";"0.0312";"19";"1200";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
||||
"66";"66";"66";"BLOCK_TRUNK_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"15";"670";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
||||
@@ -32,23 +32,27 @@
|
||||
"85";"85";"85";"BLOCK_SAND_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
|
||||
"96";"96";"96";"BLOCK_GRAVEL";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
|
||||
"97";"97";"97";"BLOCK_GRAVEL_GREY";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
|
||||
"112";"112";"112";"BLOCK_ORE_MALACHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
"113";"113";"113";"BLOCK_ORE_HEMATITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
"114";"114";"114";"BLOCK_ORE_NATURAL_GOLD";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
"115";"115";"115";"BLOCK_ORE_COAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
"116";"116";"116";"BLOCK_ORE_SPHALERITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
"117";"117";"117";"BLOCK_ORE_RUTILE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
"128";"128";"128";"BLOCK_GEM_RUBY";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"129";"129";"129";"BLOCK_GEM_EMERALD";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"130";"130";"130";"BLOCK_GEM_SAPPHIRE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"131";"131";"131";"BLOCK_GEM_TOPAZ";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"132";"132";"132";"BLOCK_GEM_DIAMOND";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"133";"133";"133";"BLOCK_GEM_AMETHYST";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"134";"134";"134";"BLOCK_GEM_QUARTZ";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"112";"112";"112";"BLOCK_FOLIAGE_NORMAL";"0.0312";"0.0312";"0.0312";"0.0312";"16";"740";"GRSS";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,LEAVES,NATURAL"
|
||||
#"113";"113";"113";"BLOCK_FOLIAGE_EBONY";"0.0312";"0.0312";"0.0312";"0.0312";"19";"1200";"GRSS";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,LEAVES,NATURAL"
|
||||
#"114";"114";"114";"BLOCK_FOLIAGE_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"15";"670";"GRSS";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,LEAVES,NATURAL"
|
||||
#"115";"115";"115";"BLOCK_FOLIAGE_ROSEWOOD";"0.0312";"0.0312";"0.0312";"0.0312";"17";"900";"GRSS";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,LEAVES,NATURAL"
|
||||
#"112";"112";"112";"BLOCK_ORE_MALACHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
#"113";"113";"113";"BLOCK_ORE_HEMATITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
#"114";"114";"114";"BLOCK_ORE_NATURAL_GOLD";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
#"115";"115";"115";"BLOCK_ORE_COAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
#"116";"116";"116";"BLOCK_ORE_SPHALERITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
#"117";"117";"117";"BLOCK_ORE_RUTILE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||
#"128";"128";"128";"BLOCK_GEM_RUBY";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
#"129";"129";"129";"BLOCK_GEM_EMERALD";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
#"130";"130";"130";"BLOCK_GEM_SAPPHIRE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
#"131";"131";"131";"BLOCK_GEM_TOPAZ";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
#"132";"132";"132";"BLOCK_GEM_DIAMOND";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
#"133";"133";"133";"BLOCK_GEM_AMETHYST";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
#"134";"134";"134";"BLOCK_GEM_QUARTZ";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||
"144";"144";"144";"BLOCK_SNOW";"0.1252";"0.1252";"0.1252";"0.1252";"24";"500";"SNOW";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SNOW,NATURAL,COLD"
|
||||
"145";"N/A";"N/A";"BLOCK_ICE_FRAGILE";"0.0508";"0.0508";"0.0508";"0.0508";"5";"930";"ICEI";"1";"0";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,FRAGILE,COLD"
|
||||
"146";"146";"146";"BLOCK_ICE_NATURAL";"0.1016";"0.1016";"0.1016";"0.1016";"35";"930";"ICEI";"1";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,COLD"
|
||||
"147";"147";"147";"BLOCK_ICE_CLEAR_MAGICAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"3720";"ICEX";"1";"1";"N/A";"0";"0";"4";"0.0744";"0.1252";"0.2268";"0.0000";"N/A";"N/A";"0.0";"ICE,COLD"
|
||||
#"146";"146";"146";"BLOCK_ICE_NATURAL";"0.1016";"0.1016";"0.1016";"0.1016";"35";"930";"ICEI";"1";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,COLD"
|
||||
#"147";"147";"147";"BLOCK_ICE_CLEAR_MAGICAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"3720";"ICEX";"1";"1";"N/A";"0";"0";"4";"0.0744";"0.1252";"0.2268";"0.0000";"N/A";"N/A";"0.0";"ICE,COLD"
|
||||
"148";"148";"148";"BLOCK_GLASS_CRUDE";"0.0876";"0.0424";"0.0876";"0.1252";"5";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
|
||||
"149";"149";"149";"BLOCK_GLASS_CLEAN";"0.0424";"0.0424";"0.0424";"0.0636";"5";"2203";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
|
||||
"160";"160";"160";"BLOCK_PLATFORM_STONE";"0.0312";"0.0312";"0.0312";"0.0312";"5";"2400";"ROCK";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"PLATFORM"
|
||||
@@ -57,82 +61,80 @@
|
||||
"163";"163";"163";"BLOCK_PLATFORM_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"5";"670";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"PLATFORM"
|
||||
"164";"164";"164";"BLOCK_PLATFORM_ROSEWOOD";"0.0312";"0.0312";"0.0312";"0.0312";"5";"900";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"PLATFORM"
|
||||
"176";"176";"176";"BLOCK_TORCH";"0.0312";"0.0312";"0.0312";"0.0312";"1";"800";"FXTR";"0";"0";"N/A";"1";"0";"16";"1.0000";"0.6372";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"177";"177";"177";"BLOCK_TORCH_FROST";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1100";"FXTR";"0";"0";"N/A";"1";"0";"16";"0.3048";"0.4848";"1.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
#"177";"177";"177";"BLOCK_TORCH_FROST";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1100";"FXTR";"0";"0";"N/A";"1";"0";"16";"0.3048";"0.4848";"1.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"192";"176";"176";"BLOCK_TORCH";"0.0312";"0.0312";"0.0312";"0.0312";"1";"800";"FXTR";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"193";"177";"177";"BLOCK_TORCH_FROST";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1100";"FXTR";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"208";"208";"208";"BLOCK_ILLUMINATOR_WHITE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.9270";"0.9414";"0.8519";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"209";"209";"209";"BLOCK_ILLUMINATOR_YELLOW";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"1.0000";"0.8408";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"210";"210";"210";"BLOCK_ILLUMINATOR_ORANGE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"1.0000";"0.5294";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"211";"211";"211";"BLOCK_ILLUMINATOR_RED";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.9188";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"212";"212";"212";"BLOCK_ILLUMINATOR_FUCHSIA";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.9188";"0.0000";"0.7156";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"213";"213";"213";"BLOCK_ILLUMINATOR_PURPLE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.7156";"0.0000";"0.9188";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"214";"214";"214";"BLOCK_ILLUMINATOR_BLUE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.1996";"0.9188";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"215";"215";"215";"BLOCK_ILLUMINATOR_CYAN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.4621";"1.4188";"1.2368";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"216";"216";"216";"BLOCK_ILLUMINATOR_GREEN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.2112";"1.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"217";"217";"217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.1252";"0.4068";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"218";"218";"218";"BLOCK_ILLUMINATOR_BROWN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.3324";"0.1252";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"219";"219";"219";"BLOCK_ILLUMINATOR_TAN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.5864";"0.4068";"0.2032";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"220";"220";"220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.7392";"0.7392";"0.7392";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"221";"221";"221";"BLOCK_ILLUMINATOR_GREY_MED";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.4576";"0.4576";"0.4576";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"222";"222";"222";"BLOCK_ILLUMINATOR_GREY_DARK";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.2540";"0.2540";"0.2540";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"223";"223";"223";"BLOCK_ILLUMINATOR_BLACK";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.2140";"0.0000";"0.4932";"3.7499";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"224";"208";"208";"BLOCK_ILLUMINATOR_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"225";"209";"209";"BLOCK_ILLUMINATOR_YELLOW";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"226";"210";"210";"BLOCK_ILLUMINATOR_ORANGE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"227";"211";"211";"BLOCK_ILLUMINATOR_RED";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"228";"212";"212";"BLOCK_ILLUMINATOR_FUCHSIA";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"229";"213";"213";"BLOCK_ILLUMINATOR_PURPLE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"230";"214";"214";"BLOCK_ILLUMINATOR_BLUE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"231";"215";"215";"BLOCK_ILLUMINATOR_CYAN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"232";"216";"216";"BLOCK_ILLUMINATOR_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"233";"217";"217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"234";"218";"218";"BLOCK_ILLUMINATOR_BROWN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"235";"219";"219";"BLOCK_ILLUMINATOR_TAN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"236";"220";"220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"237";"221";"221";"BLOCK_ILLUMINATOR_GREY_MED";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"238";"222";"222";"BLOCK_ILLUMINATOR_GREY_DARK";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"239";"223";"223";"BLOCK_ILLUMINATOR_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"240";"240";"240";"BLOCK_SANDSTONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE"
|
||||
"241";"241";"241";"BLOCK_SANDSTONE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE"
|
||||
"242";"242";"242";"BLOCK_SANDSTONE_RED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE"
|
||||
"243";"243";"243";"BLOCK_SANDSTONE_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE"
|
||||
"244";"244";"244";"BLOCK_SANDSTONE_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE"
|
||||
"245";"245";"245";"BLOCK_SANDSTONE_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE"
|
||||
"256";"256";"256";"BLOCK_LANTERN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1800";"FXTR";"0";"0";"N/A";"0";"0";"16";"1.0000";"0.6372";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"257";"257";"257";"BLOCK_SUNSTONE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"ROCK";"1";"0";"N/A";"2";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"258";"258";"258";"BLOCK_DAYLIGHT_CAPACITOR";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"0";"N/A";"3";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT"
|
||||
"272";"272";"272";"BLOCK_SCAFFOLDING_NORMAL";"0.0312";"0.0312";"0.0312";"0.0312";"1";"740";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM"
|
||||
"273";"273";"273";"BLOCK_SCAFFOLDING_EBONY";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1400";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM"
|
||||
"274";"274";"274";"BLOCK_SCAFFOLDING_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"1";"670";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM"
|
||||
"275";"275";"275";"BLOCK_SCAFFOLDING_ROSEWOOD";"0.0312";"0.0312";"0.0312";"0.0312";"1";"900";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM"
|
||||
#"193";"177";"177";"BLOCK_TORCH_FROST";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1100";"FXTR";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL"
|
||||
"208";"208";"208";"BLOCK_ILLUMINATOR_WHITE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.9270";"0.9414";"0.8519";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"209";"209";"209";"BLOCK_ILLUMINATOR_YELLOW";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"1.0000";"0.8408";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"210";"210";"210";"BLOCK_ILLUMINATOR_ORANGE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"1.0000";"0.5294";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"211";"211";"211";"BLOCK_ILLUMINATOR_RED";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.9188";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"212";"212";"212";"BLOCK_ILLUMINATOR_FUCHSIA";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.9188";"0.0000";"0.7156";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"213";"213";"213";"BLOCK_ILLUMINATOR_PURPLE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.7156";"0.0000";"0.9188";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"214";"214";"214";"BLOCK_ILLUMINATOR_BLUE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.1996";"0.9188";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"215";"215";"215";"BLOCK_ILLUMINATOR_CYAN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.4621";"1.4188";"1.2368";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"216";"216";"216";"BLOCK_ILLUMINATOR_GREEN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.2112";"1.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"217";"217";"217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.1252";"0.4068";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"218";"218";"218";"BLOCK_ILLUMINATOR_BROWN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.3324";"0.1252";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"219";"219";"219";"BLOCK_ILLUMINATOR_TAN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.5864";"0.4068";"0.2032";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"220";"220";"220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.7392";"0.7392";"0.7392";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"221";"221";"221";"BLOCK_ILLUMINATOR_GREY_MED";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.4576";"0.4576";"0.4576";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"222";"222";"222";"BLOCK_ILLUMINATOR_GREY_DARK";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.2540";"0.2540";"0.2540";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"223";"223";"223";"BLOCK_ILLUMINATOR_BLACK";"0.0312";"0.0312";"0.0312";"0.0312";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.2140";"0.0000";"0.4932";"3.7499";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"224";"208";"208";"BLOCK_ILLUMINATOR_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"225";"209";"209";"BLOCK_ILLUMINATOR_YELLOW";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"226";"210";"210";"BLOCK_ILLUMINATOR_ORANGE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"227";"211";"211";"BLOCK_ILLUMINATOR_RED";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"228";"212";"212";"BLOCK_ILLUMINATOR_FUCHSIA";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"229";"213";"213";"BLOCK_ILLUMINATOR_PURPLE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"230";"214";"214";"BLOCK_ILLUMINATOR_BLUE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"231";"215";"215";"BLOCK_ILLUMINATOR_CYAN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"232";"216";"216";"BLOCK_ILLUMINATOR_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"233";"217";"217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"234";"218";"218";"BLOCK_ILLUMINATOR_BROWN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"235";"219";"219";"BLOCK_ILLUMINATOR_TAN";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"236";"220";"220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"237";"221";"221";"BLOCK_ILLUMINATOR_GREY_MED";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"238";"222";"222";"BLOCK_ILLUMINATOR_GREY_DARK";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"239";"223";"223";"BLOCK_ILLUMINATOR_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,UNLIT,INTERNAL,NORANDTILE"
|
||||
"240";"240";"240";"BLOCK_SANDSTONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE,NORANDTILE"
|
||||
"241";"241";"241";"BLOCK_SANDSTONE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE,NORANDTILE"
|
||||
"242";"242";"242";"BLOCK_SANDSTONE_RED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE,NORANDTILE"
|
||||
"243";"243";"243";"BLOCK_SANDSTONE_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE,NORANDTILE"
|
||||
"244";"244";"244";"BLOCK_SANDSTONE_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE,NORANDTILE"
|
||||
"245";"245";"245";"BLOCK_SANDSTONE_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"48";"1900";"ROCK";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.16";"STONE,NORANDTILE"
|
||||
"256";"256";"256";"BLOCK_LANTERN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1800";"FXTR";"0";"0";"N/A";"0";"0";"16";"1.0000";"0.6372";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"257";"257";"257";"BLOCK_SUNSTONE";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"ROCK";"1";"0";"N/A";"2";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"258";"258";"258";"BLOCK_DAYLIGHT_CAPACITOR";"0.1252";"0.1252";"0.1252";"0.1252";"1";"2500";"GLAS";"1";"0";"N/A";"3";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"LIGHT,NORANDTILE"
|
||||
"272";"272";"272";"BLOCK_SCAFFOLDING_NORMAL";"0.0312";"0.0312";"0.0312";"0.0312";"1";"740";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM,NORANDTILE"
|
||||
"273";"273";"273";"BLOCK_SCAFFOLDING_EBONY";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1400";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM,NORANDTILE"
|
||||
"274";"274";"274";"BLOCK_SCAFFOLDING_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"1";"670";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM,NORANDTILE"
|
||||
"275";"275";"275";"BLOCK_SCAFFOLDING_ROSEWOOD";"0.0312";"0.0312";"0.0312";"0.0312";"1";"900";"WOOD";"0";"0";"6";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"PLATFORM,NORANDTILE"
|
||||
|
||||
"288";"288";"288";"BLOCK_PLASTIC_WHITE"; "0.0903";"0.0903";"0.0903";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"289";"289";"289";"BLOCK_PLASTIC_YELLOW"; "0.0894";"0.0919";"0.1234";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"290";"290";"290";"BLOCK_PLASTIC_ORANGE"; "0.0892";"0.0981";"0.1240";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"291";"291";"291";"BLOCK_PLASTIC_RED"; "0.0905";"0.1230";"0.1245";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"292";"292";"292";"BLOCK_PLASTIC_FUCHSIA"; "0.0905";"0.1237";"0.0941";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"293";"293";"293";"BLOCK_PLASTIC_PURPLE"; "0.0941";"0.1234";"0.0905";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"294";"294";"294";"BLOCK_PLASTIC_BLUE"; "0.1218";"0.1078";"0.0905";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"295";"295";"295";"BLOCK_PLASTIC_CYAN"; "0.1032";"0.0892";"0.0914";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"296";"296";"296";"BLOCK_PLASTIC_GREEN"; "0.1078";"0.0892";"0.1231";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"297";"297";"297";"BLOCK_PLASTIC_GREEN_DARK"; "0.1109";"0.1010";"0.1240";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"298";"298";"298";"BLOCK_PLASTIC_BROWN"; "0.1032";"0.1109";"0.1245";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"299";"299";"299";"BLOCK_PLASTIC_TAN"; "0.0967";"0.1010";"0.1078";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"300";"300";"300";"BLOCK_PLASTIC_GREY_LIGHT"; "0.0938";"0.0938";"0.0938";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"301";"301";"301";"BLOCK_PLASTIC_GREY_MED"; "0.0997";"0.0997";"0.0997";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"302";"302";"302";"BLOCK_PLASTIC_GREY_DARK"; "0.1059";"0.1059";"0.1059";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"303";"303";"303";"BLOCK_PLASTIC_BLACK"; "0.1197";"0.1197";"0.1197";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"3";"N/A";"N/A";"0.0";"THERMOPLASTIC"
|
||||
"288";"288";"288";"BLOCK_PLASTIC_WHITE"; "0.0903";"0.0903";"0.0903";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"289";"289";"289";"BLOCK_PLASTIC_YELLOW"; "0.0894";"0.0919";"0.1234";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"290";"290";"290";"BLOCK_PLASTIC_ORANGE"; "0.0892";"0.0981";"0.1240";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"291";"291";"291";"BLOCK_PLASTIC_RED"; "0.0905";"0.1230";"0.1245";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"292";"292";"292";"BLOCK_PLASTIC_FUCHSIA"; "0.0905";"0.1237";"0.0941";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"293";"293";"293";"BLOCK_PLASTIC_PURPLE"; "0.0941";"0.1234";"0.0905";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"294";"294";"294";"BLOCK_PLASTIC_BLUE"; "0.1218";"0.1078";"0.0905";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"295";"295";"295";"BLOCK_PLASTIC_CYAN"; "0.1032";"0.0892";"0.0914";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"296";"296";"296";"BLOCK_PLASTIC_GREEN"; "0.1078";"0.0892";"0.1231";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"297";"297";"297";"BLOCK_PLASTIC_GREEN_DARK"; "0.1109";"0.1010";"0.1240";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"298";"298";"298";"BLOCK_PLASTIC_BROWN"; "0.1032";"0.1109";"0.1245";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"299";"299";"299";"BLOCK_PLASTIC_TAN"; "0.0967";"0.1010";"0.1078";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"300";"300";"300";"BLOCK_PLASTIC_GREY_LIGHT"; "0.0938";"0.0938";"0.0938";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"301";"301";"301";"BLOCK_PLASTIC_GREY_MED"; "0.0997";"0.0997";"0.0997";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"302";"302";"302";"BLOCK_PLASTIC_GREY_DARK"; "0.1059";"0.1059";"0.1059";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"0";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
"303";"303";"303";"BLOCK_PLASTIC_BLACK"; "0.1197";"0.1197";"0.1197";"0.1752";"36";"660";"PLST";"1";"1";"N/A";"0";"0";"16";"0";"0";"0";"3";"N/A";"N/A";"0.0";"THERMOPLASTIC,NORANDTILE"
|
||||
|
||||
|
||||
"4090";"N/A";"N/A";"ACTORBLOCK_TILING_PLACEHOLDER";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,DORENDER"
|
||||
"4091";"N/A";"N/A";"ACTORBLOCK_NO_COLLISION";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"4";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK"
|
||||
"4092";"N/A";"N/A";"ACTORBLOCK_FULL_COLLISION";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"1";"0";"N/A";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK"
|
||||
"4093";"N/A";"N/A";"ACTORBLOCK_ALLOW_MOVE_DOWN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,PLATFORM"
|
||||
"4094";"N/A";"N/A";"ACTORBLOCK_NO_PASS_RIGHT";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"4";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK"
|
||||
"4095";"N/A";"N/A";"ACTORBLOCK_NO_PASS_LEFT";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"4";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK"
|
||||
"65536";"N/A";"N/A";"BLOCK_WATER";"0.1016";"0.0744";"0.0508";"0.0826";"100";"1000";"WATR";"0";"0";"0";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"005599A6";"16";"0.0";"NATURAL"
|
||||
"65537";"N/A";"N/A";"BLOCK_LAVA";"0.9696";"0.9696";"0.9696";"0.9696";"100";"2600";"ROCK";"0";"0";"0";"0";"0";"16";"0.7664";"0.2032";"0.0000";"0.0000";"FF4600E6";"32";"0.0";"NATURAL"
|
||||
"-1";"N/A";"N/A";"BLOCK_NULL";"4.0000";"4.0000";"4.0000";"4.0000";"-1";"2600";"NULL";"0";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INTERNAL"
|
||||
"4090";"N/A";"N/A";"ACTORBLOCK_TILING_PLACEHOLDER";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,DORENDER,NORANDTILE"
|
||||
"4091";"N/A";"N/A";"ACTORBLOCK_NO_COLLISION";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"4";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,NORANDTILE"
|
||||
"4092";"N/A";"N/A";"ACTORBLOCK_FULL_COLLISION";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"1";"0";"N/A";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,NORANDTILE"
|
||||
"4093";"N/A";"N/A";"ACTORBLOCK_ALLOW_MOVE_DOWN";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"16";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,PLATFORM,NORANDTILE"
|
||||
"4094";"N/A";"N/A";"ACTORBLOCK_NO_PASS_RIGHT";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"4";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,NORANDTILE"
|
||||
"4095";"N/A";"N/A";"ACTORBLOCK_NO_PASS_LEFT";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"N/A";"0";"0";"4";"0.0";"0.0";"0.0";"0.0";"N/A";"N/A";"0.0";"INTERNAL,ACTORBLOCK,NORANDTILE"
|
||||
"-1";"N/A";"N/A";"BLOCK_NULL";"4.0000";"4.0000";"4.0000";"4.0000";"-1";"2600";"NULL";"0";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INTERNAL,NORANDTILE"
|
||||
|
||||
|
||||
## Notes ##
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 13 and column 2.
|
49
assets/mods/basegame/books/btex.xml
Normal file
49
assets/mods/basegame/books/btex.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<btex cover="hardcover" inner="standard" papersize="standard">
|
||||
<cover>
|
||||
<title>The Way to Mastery of Lorem Ipsum<br />Or, How To Write and Publish a Book</title>
|
||||
<author>Terran Publishing</author>
|
||||
<edition>Test Edition</edition>
|
||||
</cover>
|
||||
|
||||
<toc><tableofcontents /></toc>
|
||||
|
||||
<manuscript>
|
||||
|
||||
<chapter>What Is a Book</chapter>
|
||||
|
||||
<p>This example book is designed to give you the exampe of the Book Language.</p>
|
||||
|
||||
<section>What Really Is a Book</section>
|
||||
|
||||
<p>A book is a collection of texts printed in a special way that allows them to be read easily, with enumerable pages and insertion of other helpful resources, such as illustrations and hyperlinks.</p>
|
||||
|
||||
<newpage />
|
||||
|
||||
<fullpagebox>
|
||||
<span colour="grey">
|
||||
<p>this page is intentionally left blank</p>
|
||||
</span>
|
||||
</fullpagebox>
|
||||
|
||||
<chapter>Writing Book Using Pen and Papers</chapter>
|
||||
|
||||
<p>If you open a book on a writing table, you will be welcomed with a toolbar used to put other book elements, such as chapters, sections.</p>
|
||||
|
||||
<chapter>Writing Book Using Typewriter</chapter>
|
||||
|
||||
<p>Typewriters can only write single style of font, therefore chapters and sections are not available.</p>
|
||||
|
||||
<chapter>Writing Book using Computer</chapter>
|
||||
|
||||
<p>Writing book using a computer requires a use of the Book Typesetting Engine Extended, or <BTeX /></p>
|
||||
|
||||
<section>Full Control of the Shape</section>
|
||||
|
||||
<p>With <BTeX /> you can fully control how your publishing would look like, from a pile of papers that look like they have been typed out using typewriter, a pile of papers but a fully-featured printouts that have illustrations in it, to a fully-featured hardcover book.</p>
|
||||
|
||||
<p>This style is controlled using the <code>cover</code> attribute on the root tag, with following values: <code>typewriter</code>, <code>printout</code>, <code>hardcover</code></p>
|
||||
|
||||
<p>Typewriter and Printout are considered not bound and readers will only see one page at a time, while Hardcover is considered bound and two pages are presented to the readers.</p>
|
||||
|
||||
</manuscript>
|
||||
</btex>
|
||||
60
assets/mods/basegame/books/examination.btex
Normal file
60
assets/mods/basegame/books/examination.btex
Normal file
@@ -0,0 +1,60 @@
|
||||
\usestyle{examination}
|
||||
|
||||
\begin{blocklut}
|
||||
\0\{basegame:0}
|
||||
\1\{basegame:32}
|
||||
\100\{wall@basegame:32}
|
||||
\end{blocklut}
|
||||
|
||||
|
||||
\begin{examination}
|
||||
|
||||
\section{Introduction}
|
||||
|
||||
\begin{tiles}{5x4}
|
||||
\terr{
|
||||
0,1,1,1,0,
|
||||
1,0,0,0,1,
|
||||
1,0,0,0,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\wall{
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\end{tiles}
|
||||
|
||||
This is the first page of the Examination.
|
||||
|
||||
Examination is a way to instruct the player certain gameplay concepts.
|
||||
|
||||
The system is popularised by the Minecraft Mod called ``Create'', of which it was called Pondering.
|
||||
|
||||
Terrarum borrows the concept and implements it using its own language.
|
||||
|
||||
\section{Language}
|
||||
|
||||
\begin{tiles}{5x4}
|
||||
\terr{
|
||||
0,1,1,1,0,
|
||||
1,0,1,0,1,
|
||||
1,0,1,0,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\wall{
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\end{tiles}
|
||||
|
||||
Examination relies on the script written in \BTeX.
|
||||
|
||||
\BTeX\ is a \TeX-inspired language to write texts to be displayed onto the game, one example being a book.
|
||||
|
||||
Examination is a special format of the "book" that operates on the same book system.
|
||||
|
||||
\end{examination}
|
||||
57
assets/mods/basegame/books/examination.xml
Normal file
57
assets/mods/basegame/books/examination.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<btex def="examination">
|
||||
<blocklut>
|
||||
<pair key="0" value="basegame:0" />
|
||||
<pair key="1" value="basegame:32" />
|
||||
</blocklut>
|
||||
|
||||
<manuscript>
|
||||
<section>Introduction</section>
|
||||
|
||||
<tiles w="5" h="4">
|
||||
<terr>
|
||||
0,1,1,1,0,
|
||||
1,0,0,0,1,
|
||||
1,0,0,0,1,
|
||||
0,1,1,1,0
|
||||
</terr>
|
||||
<wall>
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
</wall>
|
||||
</tiles>
|
||||
|
||||
<p>This is the first page of the Examination.</p>
|
||||
|
||||
<p>Examination is a way to instruct the player certain gameplay concepts.</p>
|
||||
|
||||
<p>The system is popularised by the Minecraft Mod called “Create”, of which it was called Pondering.</p>
|
||||
|
||||
<p>Terrarum borrows the concept and implements it using its own language.</p>
|
||||
|
||||
<section>Language</section>
|
||||
|
||||
<tiles w="5" h="4">
|
||||
<terr>
|
||||
0,1,1,1,0,
|
||||
1,0,1,0,1,
|
||||
1,0,1,0,1,
|
||||
0,1,1,1,0
|
||||
</terr>
|
||||
<wall>
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
</wall>
|
||||
</tiles>
|
||||
|
||||
<p>Examination relies on the script written in <BTeX />.</p>
|
||||
|
||||
<p><BTeX /> is a XML-like markup language to write texts to be displayed onto the game, one example being a book.</p>
|
||||
|
||||
<p>Examination is a special format of the “book” that operates on the same book system.</p>
|
||||
|
||||
</manuscript>
|
||||
</btex>
|
||||
@@ -3,6 +3,7 @@ CheatWarnTest
|
||||
CodexEdictis
|
||||
ExportCodices
|
||||
ExportMap
|
||||
ExportMap2
|
||||
ExportWorld
|
||||
ForceGC
|
||||
GetAV
|
||||
|
||||
|
3
assets/mods/basegame/configplan.csv
Normal file
3
assets/mods/basegame/configplan.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
->Lang:MENU_OPTIONS_GAMEPLAY->h1
|
||||
gameplay_max_crafting->Lang:MENU_OPTIONS_MAX_CRAFTING->spinner,100,1000,100
|
||||
showpickaxetooltip->Lang:MENU_OPTIONS_SHOW_ORES_TOOLTIP_WHEN_MINING->toggle
|
||||
|
@@ -10,12 +10,12 @@
|
||||
"accel": 0.67,
|
||||
|
||||
"speed": 3.0,
|
||||
"speedmult": [100,100,100,100,100,100,100],
|
||||
"speedmult": [90,95,98,100,102,105,110],
|
||||
|
||||
"vertstride": 12,
|
||||
|
||||
"jumppower": 13.0,
|
||||
"jumppowermult": [100,100,100,100,100,100,100],
|
||||
"jumppowermult": [90,95,98,100,102,105,110],
|
||||
|
||||
"scale": 1.0,
|
||||
"scalemult": [100,100,100,100,100,100,100],
|
||||
@@ -25,7 +25,7 @@
|
||||
"reach": 100,
|
||||
|
||||
"toolsize": 15,
|
||||
|
||||
|
||||
"intelligent": true,
|
||||
"barehandactionminheight": 80,
|
||||
"basebarehanddiggingsize": 8
|
||||
|
||||
33
assets/mods/basegame/creatures/CreaturePlayer.json
Normal file
33
assets/mods/basegame/creatures/CreaturePlayer.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"racename": "RACE_HUMAN",
|
||||
"racenameplural": "RACE_HUMAN_PLURAL",
|
||||
"baseheight": 40,
|
||||
"basemass": 60.0,
|
||||
|
||||
"strength": 1000,
|
||||
"strengthmult": [100,100,100,100,100,100,100],
|
||||
|
||||
"accel": 0.67,
|
||||
|
||||
"speed": 3.0,
|
||||
"speedmult": [100,100,100,100,100,100,100],
|
||||
|
||||
"vertstride": 12,
|
||||
|
||||
"jumppower": 13.0,
|
||||
"jumppowermult": [100,100,100,100,100,100,100],
|
||||
|
||||
"scale": 1.0,
|
||||
"scalemult": [100,100,100,100,100,100,100],
|
||||
|
||||
"encumbrance": 1000,
|
||||
"defence": 100,
|
||||
"reach": 100,
|
||||
|
||||
"toolsize": 15,
|
||||
|
||||
"intelligent": true,
|
||||
"barehandactionminheight": 80,
|
||||
"basebarehanddiggingsize": 8
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"gameplay_max_crafting": 100
|
||||
"gameplay_max_crafting": 100,
|
||||
"showpickaxetooltip": true
|
||||
}
|
||||
3
assets/mods/basegame/fluids/fluids.csv
Normal file
3
assets/mods/basegame/fluids/fluids.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
"id";"name";"shdr";"shdg";"shdb";"shduv";"str";"dsty";"mate";"lumr";"lumg";"lumb";"lumuv";"colour";"vscs";"refl";"tags"
|
||||
"1";"BLOCK_WATER";"0.1016";"0.0744";"0.0508";"0.0826";"100";"1000";"WATR";"0.0000";"0.0000";"0.0000";"0.0000";"005599A6";"16";"0.0";"NATURAL"
|
||||
"2";"BLOCK_LAVA";"0.9696";"0.9696";"0.9696";"0.9696";"100";"2600";"ROCK"; "0.7664";"0.2032";"0.0000";"0.0000";"FF4600E6";"32";"0.0";"NATURAL,MOLTEN"
|
||||
|
BIN
assets/mods/basegame/gui/loadscr_layer01.png
LFS
Normal file
BIN
assets/mods/basegame/gui/loadscr_layer01.png
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/gui/loadscr_layer02.png
LFS
Normal file
BIN
assets/mods/basegame/gui/loadscr_layer02.png
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/gui/loadscr_layer03.png
LFS
Normal file
BIN
assets/mods/basegame/gui/loadscr_layer03.png
LFS
Normal file
Binary file not shown.
@@ -12,8 +12,18 @@ id;classname
|
||||
11;net.torvald.terrarum.modulebasegame.gameitems.ItemWallCalendar
|
||||
12;net.torvald.terrarum.modulebasegame.gameitems.SledgehammerCopper
|
||||
13;net.torvald.terrarum.modulebasegame.gameitems.SledgehammerSteel
|
||||
|
||||
14;net.torvald.terrarum.modulebasegame.gameitems.PickaxeWood
|
||||
15;net.torvald.terrarum.modulebasegame.gameitems.SledgehammerWood
|
||||
16;net.torvald.terrarum.modulebasegame.gameitems.ItemWorkbench
|
||||
17;net.torvald.terrarum.modulebasegame.gameitems.ItemCoalCoke
|
||||
|
||||
128;net.torvald.terrarum.modulebasegame.gameitems.OreCopper
|
||||
129;net.torvald.terrarum.modulebasegame.gameitems.OreIron
|
||||
130;net.torvald.terrarum.modulebasegame.gameitems.OreCoal
|
||||
131;net.torvald.terrarum.modulebasegame.gameitems.OreZinc
|
||||
132;net.torvald.terrarum.modulebasegame.gameitems.OreTin
|
||||
133;net.torvald.terrarum.modulebasegame.gameitems.OreGold
|
||||
134;net.torvald.terrarum.modulebasegame.gameitems.OreSilver
|
||||
|
||||
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
|
||||
257;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony
|
||||
|
||||
|
Binary file not shown.
@@ -35,20 +35,6 @@
|
||||
"BLOCK_GRAVEL": "Gravel",
|
||||
"BLOCK_GRAVEL_GREY": "Grey Gravel",
|
||||
|
||||
"BLOCK_ORE_MALACHITE": "Malachite",
|
||||
"BLOCK_ORE_HEMATITE": "Hematite",
|
||||
"BLOCK_ORE_NATURAL_GOLD": "Natural Gold",
|
||||
"BLOCK_ORE_NATURAL_SILVER": "Natural Silver",
|
||||
"BLOCK_ORE_RUTILE": "Rutile",
|
||||
"BLOCK_ORE_AURICHALCUMITE": "Aurichalcumite",
|
||||
|
||||
"BLOCK_GEM_RUBY": "Raw Ruby",
|
||||
"BLOCK_GEM_EMERALD": "Raw Emerald",
|
||||
"BLOCK_GEM_SAPPHIRE": "Raw Sapphire",
|
||||
"BLOCK_GEM_TOPAZ": "Raw Topaz",
|
||||
"BLOCK_GEM_DIAMOND": "Raw Diamond",
|
||||
"BLOCK_GEM_AMETHYST": "Raw Amethyst",
|
||||
|
||||
"BLOCK_SNOW": "Snow",
|
||||
|
||||
"BLOCK_ICE_FRAGILE": "Thin Ice",
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
"MENU_LABEL_PREV_SAVES": "Previous Saves",
|
||||
"MENU_LABEL_RENAME": "Rename",
|
||||
"MENU_LABEL_USE_CODE": "Use Code",
|
||||
"MENU_MODE_BUILDINGMAKER": "POI Editor",
|
||||
"MENU_MONITOR_CALI_TITLE": "Check Monitor",
|
||||
"MENU_OPTIONS_SHOW_ORES_TOOLTIP_WHEN_MINING": "Show Ores Tooltip When Mining",
|
||||
"MENU_OPTIONS_MAX_CRAFTING": "Max Number of Items For Crafting",
|
||||
"MENU_UPDATE_UPDATE_AVAILABLE": "Update Available!",
|
||||
"GAME_ACTION_CRAFT": "Craft",
|
||||
"GAME_ACTION_GRAPPLE": "Grapple",
|
||||
"GAME_ACTION_QUICKSEL": "Quick Select",
|
||||
"GAME_ACTION_TELEPORT": "Teleport",
|
||||
|
||||
@@ -4,7 +4,20 @@
|
||||
"ITEM_DOOR_EBONY": "Ebony Door",
|
||||
"ITEM_DOOR_BIRCH": "Birch Door",
|
||||
"ITEM_DOOR_ROSEWOOD": "Rosewood Door",
|
||||
"ITEM_GEM_RUBY": "Raw Ruby",
|
||||
"ITEM_GEM_EMERALD": "Raw Emerald",
|
||||
"ITEM_GEM_SAPPHIRE": "Raw Sapphire",
|
||||
"ITEM_GEM_TOPAZ": "Raw Topaz",
|
||||
"ITEM_GEM_DIAMOND": "Raw Diamond",
|
||||
"ITEM_GEM_AMETHYST": "Raw Amethyst",
|
||||
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
|
||||
"ITEM_ORE_CASSITERITE": "Tin Ore",
|
||||
"ITEM_ORE_COAL": "Coal",
|
||||
"ITEM_ORE_HAEMATITE": "Iron Ore",
|
||||
"ITEM_ORE_MALACHITE": "Copper Ore",
|
||||
"ITEM_ORE_NATURAL_GOLD": "Natural Gold",
|
||||
"ITEM_ORE_NATURAL_SILVER": "Natural Silver",
|
||||
"ITEM_ORE_SPHALERITE": "Zinc Ore",
|
||||
"ITEM_PICK_COPPER": "Copper Pickaxe",
|
||||
"ITEM_PICK_IRON": "Iron Pickaxe",
|
||||
"ITEM_PICK_STEEL": "Steel Pickaxe",
|
||||
|
||||
@@ -35,20 +35,6 @@
|
||||
"BLOCK_GRAVEL": "자갈",
|
||||
"BLOCK_GRAVEL_GREY": "회색 자갈",
|
||||
|
||||
"BLOCK_ORE_MALACHITE": "공작석",
|
||||
"BLOCK_ORE_HEMATITE": "적철석",
|
||||
"BLOCK_ORE_NATURAL_GOLD": "금덩어리",
|
||||
"BLOCK_ORE_NATURAL_SILVER": "은덩어리",
|
||||
"BLOCK_ORE_RUTILE": "금홍석",
|
||||
"BLOCK_ORE_AURICHALCUMITE": "진금석",
|
||||
|
||||
"BLOCK_GEM_RUBY": "홍옥석",
|
||||
"BLOCK_GEM_EMERALD": "취옥석",
|
||||
"BLOCK_GEM_SAPPHIRE": "청옥석",
|
||||
"BLOCK_GEM_TOPAZ": "황옥석",
|
||||
"BLOCK_GEM_DIAMOND": "금강석",
|
||||
"BLOCK_GEM_AMETHYST": "자수정석",
|
||||
|
||||
"BLOCK_SNOW": "눈",
|
||||
|
||||
"BLOCK_ICE_FRAGILE": "살얼음",
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||
"MENU_LABEL_USE_CODE": "코드 사용",
|
||||
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
|
||||
"MENU_OPTIONS_SHOW_ORES_TOOLTIP_WHEN_MINING": "채굴 시 광석 툴팁 보이기",
|
||||
"MENU_OPTIONS_MAX_CRAFTING": "한번에 제작할 최대 아이템 수",
|
||||
"MENU_UPDATE_UPDATE_AVAILABLE": "새 업데이트가 있습니다!",
|
||||
"GAME_ACTION_CRAFT": "제작하기",
|
||||
"GAME_ACTION_GRAPPLE": "매달리기",
|
||||
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
||||
"GAME_ACTION_TELEPORT": "텔레포트하기",
|
||||
|
||||
@@ -4,7 +4,20 @@
|
||||
"ITEM_DOOR_EBONY": "흑단 문",
|
||||
"ITEM_DOOR_BIRCH": "백단 문",
|
||||
"ITEM_DOOR_ROSEWOOD": "자단 문",
|
||||
"ITEM_GEM_RUBY": "홍옥석",
|
||||
"ITEM_GEM_EMERALD": "취옥석",
|
||||
"ITEM_GEM_SAPPHIRE": "청옥석",
|
||||
"ITEM_GEM_TOPAZ": "황옥석",
|
||||
"ITEM_GEM_DIAMOND": "금강석",
|
||||
"ITEM_GEM_AMETHYST": "자수정석",
|
||||
"ITEM_LOGIC_SIGNAL_EMITTER": "신호발생기",
|
||||
"ITEM_ORE_CASSITERITE": "주석석",
|
||||
"ITEM_ORE_COAL": "석탄",
|
||||
"ITEM_ORE_HAEMATITE": "철광석",
|
||||
"ITEM_ORE_MALACHITE": "동광석",
|
||||
"ITEM_ORE_NATURAL_GOLD": "금덩이",
|
||||
"ITEM_ORE_NATURAL_SILVER": "은덩이",
|
||||
"ITEM_ORE_SPHALERITE": "아연석",
|
||||
"ITEM_PICK_COPPER": "구리 곡괭이",
|
||||
"ITEM_PICK_IRON": "철 곡괭이",
|
||||
"ITEM_PICK_STEEL": "강철 곡괭이",
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
idst;tens;impf;dsty;fmod;endurance;tcond;reach;comments
|
||||
ROCK;15;210;3000;1;0.42;1.0;5;data is that of marble
|
||||
OORE;15;210;3000;1;0.42;1.0;5;data is that of marble
|
||||
OGEM;15;210;3000;1;0.42;1.0;5;data is that of marble
|
||||
CUPR;210;770;8960;2;1.00;401.0;5;copper
|
||||
EGLS;33;1000;2325;4;0.82;1.0;6;elven glass/moldavite
|
||||
IRON;350;1085;7874;5;1.42;1.0;6;not wrought iron,just natural iron
|
||||
ARGN;170;595;10490;9;0.91;1.0;6;argentum/silver
|
||||
STAL;531;2520;7874;14;1.73;1.0;7;steel
|
||||
EAUR;768;0;8192;21;1.36;1.0;7;elven aurichalcum
|
||||
TIAL;900;0;4420;33;2.16;1.0;8;titanium alloy (Ti6Al4V)
|
||||
ADMT;2000;4090;2700;71;3.42;1.0;8;adamant
|
||||
OOZE;20;0;1000;1;0.08;0.5;0;genetic ooze,data is about human skin
|
||||
BONE;130;0;2000;1;0.23;0.55;4;data is that of bovine bone
|
||||
idst;tens;impf;dsty;fmod;endurance;tcond;reach;rcs;comments
|
||||
WOOD;10;10;800;1;0.173;0.17;5;18;just a generic wood
|
||||
ROCK;15;210;3000;1;0.42;2.9;5;48;data is that of marble
|
||||
OORE;15;210;3000;1;0.42;2.9;5;100;data is that of marble
|
||||
OGEM;15;210;3000;1;0.42;2.9;5;80;data is that of marble
|
||||
CUPR;210;770;8960;2;1.00;401.0;5;120;copper
|
||||
EGLS;33;1000;2325;4;0.82;1.0;6;10;elven glass/moldavite
|
||||
IRON;350;1085;7874;5;1.42;80.4;6;120;not wrought iron,just natural iron
|
||||
ARGN;170;595;10490;9;0.91;429.0;6;120;argentum/silver
|
||||
AURM;120;350;19300;9;0.88;318.0;6;120;aurum/gold
|
||||
STAL;531;2520;7874;14;1.73;26.0;7;120;steel
|
||||
EAUR;768;0;8192;21;1.36;1.0;7;120;elven aurichalcum
|
||||
TIAL;900;0;4420;33;2.16;1.0;8;120;titanium alloy (Ti6Al4V)
|
||||
ADMT;2000;4090;2700;71;3.42;1.0;8;120;adamant
|
||||
OOZE;20;0;1000;1;0.08;0.5;0;10;genetic ooze,data is about human skin
|
||||
BONE;130;0;2000;1;0.23;0.55;4;10;data is that of bovine bone
|
||||
BRAS;315;1015;8530;3;1.00;120;5;120;brass
|
||||
BRNZ;310;843;8770;3;1.20;75;5;120;bronze
|
||||
TINN;220;350;7310;2;1.00;69;5;120;tin
|
||||
ZINC;90;525;7140;2;1.00;116;5;120;zinc
|
||||
DIRT;1;1;1400;0.0;0.0;36;0;10;dirt
|
||||
PLST;1;1;1400;0.0;0.0;36;0;16;TODO plastic (polyethylene)
|
||||
AIIR;1;1;1;0.0;0.0;36;0;1;air
|
||||
SAND;1;1;2400;0.0;0.0;36;0;36;sand
|
||||
GRVL;1;1;2400;0.0;0.0;36;0;36;gravel
|
||||
|
||||
# idst: ID_STRING, ALL CAPS
|
||||
#
|
||||
@@ -33,6 +44,8 @@ BONE;130;0;2000;1;0.23;0.55;4;data is that of bovine bone
|
||||
#
|
||||
# reach: Tool Reach in blocks. Default is 6 (iron)
|
||||
#
|
||||
# rcs: Radar Cross Section -- how well the material reflects the radio wave used by the Ground Penetrating Radar.
|
||||
#
|
||||
# Comments: do nothing;do not parse
|
||||
#
|
||||
|
||||
|
||||
|
@@ -47,7 +47,7 @@ entrypoint=net.torvald.terrarum.modulebasegame.EntryPoint
|
||||
releasedate=2023-10-06
|
||||
|
||||
# The version, must follow Semver 2.0.0 scheme (https://semver.org/)
|
||||
version=0.3.3
|
||||
version=0.4.0
|
||||
|
||||
# External JAR that the module is compiled. If your module requires yet another library, the JAR must be compiled as a "Fatjar";
|
||||
# Due to security reasons, loading an arbitrary JAR is not allowed.
|
||||
|
||||
BIN
assets/mods/basegame/ores/1.tga
LFS
Normal file
BIN
assets/mods/basegame/ores/1.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/ores/2.tga
LFS
Normal file
BIN
assets/mods/basegame/ores/2.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/ores/3.tga
LFS
Normal file
BIN
assets/mods/basegame/ores/3.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/ores/4.tga
LFS
Normal file
BIN
assets/mods/basegame/ores/4.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/ores/5.tga
LFS
Normal file
BIN
assets/mods/basegame/ores/5.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/ores/6.tga
LFS
Normal file
BIN
assets/mods/basegame/ores/6.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/ores/7.tga
LFS
Normal file
BIN
assets/mods/basegame/ores/7.tga
LFS
Normal file
Binary file not shown.
20
assets/mods/basegame/ores/ores.csv
Normal file
20
assets/mods/basegame/ores/ores.csv
Normal file
@@ -0,0 +1,20 @@
|
||||
"id";"item";"tags"
|
||||
"1";"item@basegame:128";"COPPER,MALACHITE"
|
||||
"2";"item@basegame:129";"IRON,HAEMATITE"
|
||||
"3";"item@basegame:130";"COAL,CARBON"
|
||||
"4";"item@basegame:131";"ZINC,SPHALERITE"
|
||||
"5";"item@basegame:132";"TIN,CASSITERITE"
|
||||
"6";"item@basegame:133";"GOLD,NATURAL_GOLD"
|
||||
"7";"item@basegame:134";"SILVER,NATURAL_SILVER"
|
||||
# "8";"item@basegame:135";"GEM,RUBY"
|
||||
# "9";"item@basegame:136";"GEM,EMERALD"
|
||||
#"10";"item@basegame:137";"GEM,SAPPHIRE"
|
||||
#"11";"item@basegame:138";"GEM,TOPAZ"
|
||||
#"12";"item@basegame:139";"GEM,DIAMOND"
|
||||
#"13";"item@basegame:140";"GEM,SIO2,AMETHYST"
|
||||
#"14";"item@basegame:141";"GEM,SIO2,QUARTZ"
|
||||
#"15";"item@basegame:142";"LEAD,GALENA"
|
||||
#"16";"item@basegame:143";"TITANIUM,RUTILE"
|
||||
|
||||
#"256";"macro@BASETILE";"GRASS"
|
||||
#"257";"macro@BASETILE";"MOSS"
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 3.
|
29
assets/mods/basegame/ores/worldgen.csv
Normal file
29
assets/mods/basegame/ores/worldgen.csv
Normal file
@@ -0,0 +1,29 @@
|
||||
"id";"freq";"power";"scale";"ratio";"tiling";"comment"
|
||||
"1";"0.032";"0.010";"0.507";"1.0";"a16x16";"copper (malachite)"
|
||||
"2";"0.056";"0.011";"0.507";"1.0";"a16x16";"iron (haematite)"
|
||||
"3";"0.021";"0.070";"0.501";"3.8";"a16x4";"coal"
|
||||
"4";"0.024";"0.011";"0.501";"1.0";"a16x16";"zinc (sphalerite)"
|
||||
"5";"0.021";"0.020";"0.501";"1.0";"a16x16";"tin (cassiterite)"
|
||||
"6";"0.011";"0.300";"0.465";"1.0";"a16x16";"natural gold"
|
||||
"7";"0.016";"0.300";"0.467";"1.0";"a16x16";"natural silver"
|
||||
|
||||
################################################################################
|
||||
|
||||
# id: ore ID to spawn, the ID must exist on the ores.csv
|
||||
#
|
||||
# freq: frequency value used to set up noise generator. Larger = ore veins are closer together
|
||||
# power: power value (as in: randomNumber ^ power) used to set up the noise generator. Larger = veins are larger as you go deeper. 0.01 almost negates this effect
|
||||
# scale: scale value used to set up the noise generator. Larger = thicker veins. A valid value tend to play around the 0.5; you'll need figure out this value by trial and error
|
||||
# ratio: how elongated (or squeeze) the ore veins are. >1.0 = stretched horizontally, <1.0 = stretched vertically
|
||||
#
|
||||
# tiling: determines how the tiles are tiled
|
||||
# - a16: use 4-neighbour autotiling (16 possible cases)
|
||||
# - a16x4: 4 variants of a16 (typically 4 rotations, or 2 rotations x 2 flips)
|
||||
# - a16x8: 8 variants of a16 (typically 4 rotations x 2 flips) -- horz/vert flip do not matter, both produces same sets of shapes
|
||||
# - a16x16: 16 variants of a16 (typically 4 rotations x 2 flips x 2 styles)
|
||||
# - a47: use 8-neighbour autotiling (47 possible cases)
|
||||
# - a47x4: 4 variants of a47 (typically 4 rotations, or 2 rotations x 2 flips)
|
||||
# - r16: use the hash of the tile position as a variant selection, module 16
|
||||
# - r8: use the hash of the tile position as a variant selection, module 8
|
||||
#
|
||||
# comment: human-readable comments, not actually parsed
|
||||
|
BIN
assets/mods/basegame/splashback.png
LFS
Normal file
BIN
assets/mods/basegame/splashback.png
LFS
Normal file
Binary file not shown.
676
src/com/badlogic/gdx/backends/lwjgl3/Lwjgl3Application.java
Normal file
676
src/com/badlogic/gdx/backends/lwjgl3/Lwjgl3Application.java
Normal file
@@ -0,0 +1,676 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2011 See AUTHORS file.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
package com.badlogic.gdx.backends.lwjgl3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import com.badlogic.gdx.ApplicationLogger;
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.Lwjgl3Audio;
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio;
|
||||
import com.badlogic.gdx.graphics.glutils.GLVersion;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.opengl.AMDDebugOutput;
|
||||
import org.lwjgl.opengl.ARBDebugOutput;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.opengl.GLUtil;
|
||||
import org.lwjgl.opengl.KHRDebug;
|
||||
import org.lwjgl.system.Callback;
|
||||
|
||||
import com.badlogic.gdx.Application;
|
||||
import com.badlogic.gdx.ApplicationListener;
|
||||
import com.badlogic.gdx.Audio;
|
||||
import com.badlogic.gdx.Files;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Graphics;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.LifecycleListener;
|
||||
import com.badlogic.gdx.Net;
|
||||
import com.badlogic.gdx.Preferences;
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.mock.MockAudio;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Clipboard;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import com.badlogic.gdx.utils.SharedLibraryLoader;
|
||||
import org.lwjgl.system.Configuration;
|
||||
|
||||
/**
|
||||
* This version of code is based on GDX 1.12.0 and was modified for the Terrarum project.
|
||||
*
|
||||
* Created by minjaesong on 2023-11-08.
|
||||
*/
|
||||
public class Lwjgl3Application implements Lwjgl3ApplicationBase {
|
||||
private final Lwjgl3ApplicationConfiguration config;
|
||||
final Array<Lwjgl3Window> windows = new Array<Lwjgl3Window>();
|
||||
private volatile Lwjgl3Window currentWindow;
|
||||
private Lwjgl3Audio audio;
|
||||
private final Files files;
|
||||
private final Net net;
|
||||
private final ObjectMap<String, Preferences> preferences = new ObjectMap<String, Preferences>();
|
||||
private final Lwjgl3Clipboard clipboard;
|
||||
private int logLevel = LOG_INFO;
|
||||
private ApplicationLogger applicationLogger;
|
||||
private volatile boolean running = true;
|
||||
private final Array<Runnable> runnables = new Array<Runnable>();
|
||||
private final Array<Runnable> executedRunnables = new Array<Runnable>();
|
||||
private final Array<LifecycleListener> lifecycleListeners = new Array<LifecycleListener>();
|
||||
private static GLFWErrorCallback errorCallback;
|
||||
private static GLVersion glVersion;
|
||||
private static Callback glDebugCallback;
|
||||
private final Sync sync;
|
||||
|
||||
static void initializeGlfw () {
|
||||
if (errorCallback == null) {
|
||||
if (SharedLibraryLoader.isMac) loadGlfwAwtMacos();
|
||||
Lwjgl3NativesLoader.load();
|
||||
errorCallback = GLFWErrorCallback.createPrint(Lwjgl3ApplicationConfiguration.errorStream);
|
||||
GLFW.glfwSetErrorCallback(errorCallback);
|
||||
if (SharedLibraryLoader.isMac) GLFW.glfwInitHint(GLFW.GLFW_ANGLE_PLATFORM_TYPE, GLFW.GLFW_ANGLE_PLATFORM_TYPE_METAL);
|
||||
GLFW.glfwInitHint(GLFW.GLFW_JOYSTICK_HAT_BUTTONS, GLFW.GLFW_FALSE);
|
||||
if (!GLFW.glfwInit()) {
|
||||
throw new GdxRuntimeException("Unable to initialize GLFW");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void loadANGLE () {
|
||||
try {
|
||||
Class angleLoader = Class.forName("com.badlogic.gdx.backends.lwjgl3.angle.ANGLELoader");
|
||||
Method load = angleLoader.getMethod("load");
|
||||
load.invoke(angleLoader);
|
||||
} catch (ClassNotFoundException t) {
|
||||
return;
|
||||
} catch (Throwable t) {
|
||||
throw new GdxRuntimeException("Couldn't load ANGLE.", t);
|
||||
}
|
||||
}
|
||||
|
||||
static void postLoadANGLE () {
|
||||
try {
|
||||
Class angleLoader = Class.forName("com.badlogic.gdx.backends.lwjgl3.angle.ANGLELoader");
|
||||
Method load = angleLoader.getMethod("postGlfwInit");
|
||||
load.invoke(angleLoader);
|
||||
} catch (ClassNotFoundException t) {
|
||||
return;
|
||||
} catch (Throwable t) {
|
||||
throw new GdxRuntimeException("Couldn't load ANGLE.", t);
|
||||
}
|
||||
}
|
||||
|
||||
static void loadGlfwAwtMacos () {
|
||||
try {
|
||||
Class loader = Class.forName("com.badlogic.gdx.backends.lwjgl3.awt.GlfwAWTLoader");
|
||||
Method load = loader.getMethod("load");
|
||||
File sharedLib = (File)load.invoke(loader);
|
||||
Configuration.GLFW_LIBRARY_NAME.set(sharedLib.getAbsolutePath());
|
||||
Configuration.GLFW_CHECK_THREAD0.set(false);
|
||||
} catch (ClassNotFoundException t) {
|
||||
return;
|
||||
} catch (Throwable t) {
|
||||
throw new GdxRuntimeException("Couldn't load GLFW AWT for macOS.", t);
|
||||
}
|
||||
}
|
||||
|
||||
public Lwjgl3Application (ApplicationListener listener) {
|
||||
this(listener, new Lwjgl3ApplicationConfiguration());
|
||||
}
|
||||
|
||||
public Lwjgl3Application (ApplicationListener listener, Lwjgl3ApplicationConfiguration config) {
|
||||
if (config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.ANGLE_GLES20) loadANGLE();
|
||||
initializeGlfw();
|
||||
setApplicationLogger(new Lwjgl3ApplicationLogger());
|
||||
|
||||
this.config = config = Lwjgl3ApplicationConfiguration.copy(config);
|
||||
if (config.title == null) config.title = listener.getClass().getSimpleName();
|
||||
|
||||
Gdx.app = this;
|
||||
if (!config.disableAudio) {
|
||||
try {
|
||||
this.audio = createAudio(config);
|
||||
} catch (Throwable t) {
|
||||
log("Lwjgl3Application", "Couldn't initialize audio, disabling audio", t);
|
||||
this.audio = new MockAudio();
|
||||
}
|
||||
} else {
|
||||
this.audio = new MockAudio();
|
||||
}
|
||||
Gdx.audio = audio;
|
||||
this.files = Gdx.files = createFiles();
|
||||
this.net = Gdx.net = new Lwjgl3Net(config);
|
||||
this.clipboard = new Lwjgl3Clipboard();
|
||||
|
||||
this.sync = new Sync();
|
||||
|
||||
Lwjgl3Window window = createWindow(config, listener, 0);
|
||||
if (config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.ANGLE_GLES20) postLoadANGLE();
|
||||
windows.add(window);
|
||||
try {
|
||||
loop();
|
||||
cleanupWindows();
|
||||
} catch (Throwable t) {
|
||||
if (t instanceof RuntimeException)
|
||||
throw (RuntimeException)t;
|
||||
else
|
||||
throw new GdxRuntimeException(t);
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
protected void loop () {
|
||||
Array<Lwjgl3Window> closedWindows = new Array<Lwjgl3Window>();
|
||||
while (running && windows.size > 0) {
|
||||
// System.out.println("aaaaaaaaaaaaaaaaaaaaa");
|
||||
|
||||
// audio.update(); // is handled on net.torvald.terrarum.AudioManager.update(float)
|
||||
|
||||
boolean haveWindowsRendered = false;
|
||||
closedWindows.clear();
|
||||
int targetFramerate = -2;
|
||||
for (Lwjgl3Window window : windows) {
|
||||
window.makeCurrent();
|
||||
currentWindow = window;
|
||||
if (targetFramerate == -2) targetFramerate = window.getConfig().foregroundFPS;
|
||||
synchronized (lifecycleListeners) {
|
||||
haveWindowsRendered |= window.update();
|
||||
}
|
||||
if (window.shouldClose()) {
|
||||
closedWindows.add(window);
|
||||
}
|
||||
}
|
||||
GLFW.glfwPollEvents();
|
||||
|
||||
boolean shouldRequestRendering;
|
||||
synchronized (runnables) {
|
||||
shouldRequestRendering = runnables.size > 0;
|
||||
executedRunnables.clear();
|
||||
executedRunnables.addAll(runnables);
|
||||
runnables.clear();
|
||||
}
|
||||
for (Runnable runnable : executedRunnables) {
|
||||
runnable.run();
|
||||
}
|
||||
if (shouldRequestRendering) {
|
||||
// Must follow Runnables execution so changes done by Runnables are reflected
|
||||
// in the following render.
|
||||
for (Lwjgl3Window window : windows) {
|
||||
if (!window.getGraphics().isContinuousRendering()) window.requestRendering();
|
||||
}
|
||||
}
|
||||
|
||||
for (Lwjgl3Window closedWindow : closedWindows) {
|
||||
if (windows.size == 1) {
|
||||
// Lifecycle listener methods have to be called before ApplicationListener methods. The
|
||||
// application will be disposed when _all_ windows have been disposed, which is the case,
|
||||
// when there is only 1 window left, which is in the process of being disposed.
|
||||
for (int i = lifecycleListeners.size - 1; i >= 0; i--) {
|
||||
LifecycleListener l = lifecycleListeners.get(i);
|
||||
l.pause();
|
||||
l.dispose();
|
||||
}
|
||||
lifecycleListeners.clear();
|
||||
}
|
||||
closedWindow.dispose();
|
||||
|
||||
windows.removeValue(closedWindow, false);
|
||||
}
|
||||
|
||||
if (!haveWindowsRendered) {
|
||||
// Sleep a few milliseconds in case no rendering was requested
|
||||
// with continuous rendering disabled.
|
||||
try {
|
||||
Thread.sleep(1000 / config.idleFPS);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
} else if (targetFramerate > 0) {
|
||||
sync.sync(targetFramerate); // sleep as needed to meet the target framerate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void cleanupWindows () {
|
||||
synchronized (lifecycleListeners) {
|
||||
for (LifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.pause();
|
||||
lifecycleListener.dispose();
|
||||
}
|
||||
}
|
||||
for (Lwjgl3Window window : windows) {
|
||||
window.dispose();
|
||||
}
|
||||
windows.clear();
|
||||
}
|
||||
|
||||
protected void cleanup () {
|
||||
Lwjgl3Cursor.disposeSystemCursors();
|
||||
audio.dispose();
|
||||
errorCallback.free();
|
||||
errorCallback = null;
|
||||
if (glDebugCallback != null) {
|
||||
glDebugCallback.free();
|
||||
glDebugCallback = null;
|
||||
}
|
||||
GLFW.glfwTerminate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationListener getApplicationListener () {
|
||||
return currentWindow.getListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graphics getGraphics () {
|
||||
return currentWindow.getGraphics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Audio getAudio () {
|
||||
return audio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Input getInput () {
|
||||
return currentWindow.getInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Files getFiles () {
|
||||
return files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Net getNet () {
|
||||
return net;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug (String tag, String message) {
|
||||
if (logLevel >= LOG_DEBUG) getApplicationLogger().debug(tag, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug (String tag, String message, Throwable exception) {
|
||||
if (logLevel >= LOG_DEBUG) getApplicationLogger().debug(tag, message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log (String tag, String message) {
|
||||
if (logLevel >= LOG_INFO) getApplicationLogger().log(tag, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log (String tag, String message, Throwable exception) {
|
||||
if (logLevel >= LOG_INFO) getApplicationLogger().log(tag, message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error (String tag, String message) {
|
||||
if (logLevel >= LOG_ERROR) getApplicationLogger().error(tag, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error (String tag, String message, Throwable exception) {
|
||||
if (logLevel >= LOG_ERROR) getApplicationLogger().error(tag, message, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogLevel (int logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLogLevel () {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationLogger (ApplicationLogger applicationLogger) {
|
||||
this.applicationLogger = applicationLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationLogger getApplicationLogger () {
|
||||
return applicationLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationType getType () {
|
||||
return ApplicationType.Desktop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion () {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getJavaHeap () {
|
||||
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNativeHeap () {
|
||||
return getJavaHeap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Preferences getPreferences (String name) {
|
||||
if (preferences.containsKey(name)) {
|
||||
return preferences.get(name);
|
||||
} else {
|
||||
Preferences prefs = new Lwjgl3Preferences(
|
||||
new Lwjgl3FileHandle(new File(config.preferencesDirectory, name), config.preferencesFileType));
|
||||
preferences.put(name, prefs);
|
||||
return prefs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard getClipboard () {
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRunnable (Runnable runnable) {
|
||||
synchronized (runnables) {
|
||||
runnables.add(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit () {
|
||||
running = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLifecycleListener (LifecycleListener listener) {
|
||||
synchronized (lifecycleListeners) {
|
||||
lifecycleListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLifecycleListener (LifecycleListener listener) {
|
||||
synchronized (lifecycleListeners) {
|
||||
lifecycleListeners.removeValue(listener, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lwjgl3Audio createAudio (Lwjgl3ApplicationConfiguration config) {
|
||||
return new OpenALLwjgl3Audio(config.audioDeviceSimultaneousSources, config.audioDeviceBufferCount,
|
||||
config.audioDeviceBufferSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lwjgl3Input createInput (Lwjgl3Window window) {
|
||||
return new DefaultLwjgl3Input(window);
|
||||
}
|
||||
|
||||
protected Files createFiles () {
|
||||
return new Lwjgl3Files();
|
||||
}
|
||||
|
||||
/** Creates a new {@link Lwjgl3Window} using the provided listener and {@link Lwjgl3WindowConfiguration}.
|
||||
*
|
||||
* This function only just instantiates a {@link Lwjgl3Window} and returns immediately. The actual window creation is postponed
|
||||
* with {@link Application#postRunnable(Runnable)} until after all existing windows are updated. */
|
||||
public Lwjgl3Window newWindow (ApplicationListener listener, Lwjgl3WindowConfiguration config) {
|
||||
Lwjgl3ApplicationConfiguration appConfig = Lwjgl3ApplicationConfiguration.copy(this.config);
|
||||
appConfig.setWindowConfiguration(config);
|
||||
if (appConfig.title == null) appConfig.title = listener.getClass().getSimpleName();
|
||||
return createWindow(appConfig, listener, windows.get(0).getWindowHandle());
|
||||
}
|
||||
|
||||
private Lwjgl3Window createWindow (final Lwjgl3ApplicationConfiguration config, ApplicationListener listener,
|
||||
final long sharedContext) {
|
||||
final Lwjgl3Window window = new Lwjgl3Window(listener, config, this);
|
||||
if (sharedContext == 0) {
|
||||
// the main window is created immediately
|
||||
createWindow(window, config, sharedContext);
|
||||
} else {
|
||||
// creation of additional windows is deferred to avoid GL context trouble
|
||||
postRunnable(new Runnable() {
|
||||
public void run () {
|
||||
createWindow(window, config, sharedContext);
|
||||
windows.add(window);
|
||||
}
|
||||
});
|
||||
}
|
||||
return window;
|
||||
}
|
||||
|
||||
void createWindow (Lwjgl3Window window, Lwjgl3ApplicationConfiguration config, long sharedContext) {
|
||||
long windowHandle = createGlfwWindow(config, sharedContext);
|
||||
window.create(windowHandle);
|
||||
window.setVisible(config.initialVisible);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
GL11.glClearColor(config.initialBackgroundColor.r, config.initialBackgroundColor.g, config.initialBackgroundColor.b,
|
||||
config.initialBackgroundColor.a);
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
GLFW.glfwSwapBuffers(windowHandle);
|
||||
}
|
||||
}
|
||||
|
||||
static long createGlfwWindow (Lwjgl3ApplicationConfiguration config, long sharedContextWindow) {
|
||||
GLFW.glfwDefaultWindowHints();
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, config.windowResizable ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_MAXIMIZED, config.windowMaximized ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_AUTO_ICONIFY, config.autoIconify ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_RED_BITS, config.r);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_GREEN_BITS, config.g);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_BLUE_BITS, config.b);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_ALPHA_BITS, config.a);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_STENCIL_BITS, config.stencil);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_DEPTH_BITS, config.depth);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, config.samples);
|
||||
|
||||
if (config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.GL30
|
||||
|| config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.GL31
|
||||
|| config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.GL32) {
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, config.gles30ContextMajorVersion);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, config.gles30ContextMinorVersion);
|
||||
if (SharedLibraryLoader.isMac) {
|
||||
// hints mandatory on OS X for GL 3.2+ context creation, but fail on Windows if the
|
||||
// WGL_ARB_create_context extension is not available
|
||||
// see: http://www.glfw.org/docs/latest/compat.html
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
||||
}
|
||||
} else {
|
||||
if (config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.ANGLE_GLES20) {
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_CREATION_API, GLFW.GLFW_EGL_CONTEXT_API);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_CLIENT_API, GLFW.GLFW_OPENGL_ES_API);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.transparentFramebuffer) {
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_TRANSPARENT_FRAMEBUFFER, GLFW.GLFW_TRUE);
|
||||
}
|
||||
|
||||
if (config.debug) {
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE);
|
||||
}
|
||||
|
||||
long windowHandle = 0;
|
||||
|
||||
if (config.fullscreenMode != null) {
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_REFRESH_RATE, config.fullscreenMode.refreshRate);
|
||||
windowHandle = GLFW.glfwCreateWindow(config.fullscreenMode.width, config.fullscreenMode.height, config.title,
|
||||
config.fullscreenMode.getMonitor(), sharedContextWindow);
|
||||
} else {
|
||||
GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, config.windowDecorated ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||
windowHandle = GLFW.glfwCreateWindow(config.windowWidth, config.windowHeight, config.title, 0, sharedContextWindow);
|
||||
}
|
||||
if (windowHandle == 0) {
|
||||
throw new GdxRuntimeException("Couldn't create window");
|
||||
}
|
||||
Lwjgl3Window.setSizeLimits(windowHandle, config.windowMinWidth, config.windowMinHeight, config.windowMaxWidth,
|
||||
config.windowMaxHeight);
|
||||
if (config.fullscreenMode == null) {
|
||||
if (config.windowX == -1 && config.windowY == -1) {
|
||||
int windowWidth = Math.max(config.windowWidth, config.windowMinWidth);
|
||||
int windowHeight = Math.max(config.windowHeight, config.windowMinHeight);
|
||||
if (config.windowMaxWidth > -1) windowWidth = Math.min(windowWidth, config.windowMaxWidth);
|
||||
if (config.windowMaxHeight > -1) windowHeight = Math.min(windowHeight, config.windowMaxHeight);
|
||||
|
||||
long monitorHandle = GLFW.glfwGetPrimaryMonitor();
|
||||
if (config.windowMaximized && config.maximizedMonitor != null) {
|
||||
monitorHandle = config.maximizedMonitor.monitorHandle;
|
||||
}
|
||||
|
||||
IntBuffer areaXPos = BufferUtils.createIntBuffer(1);
|
||||
IntBuffer areaYPos = BufferUtils.createIntBuffer(1);
|
||||
IntBuffer areaWidth = BufferUtils.createIntBuffer(1);
|
||||
IntBuffer areaHeight = BufferUtils.createIntBuffer(1);
|
||||
GLFW.glfwGetMonitorWorkarea(monitorHandle, areaXPos, areaYPos, areaWidth, areaHeight);
|
||||
|
||||
GLFW.glfwSetWindowPos(windowHandle, Math.max(0, areaXPos.get(0) + areaWidth.get(0) / 2 - windowWidth / 2),
|
||||
Math.max(0, areaYPos.get(0) + areaHeight.get(0) / 2 - windowHeight / 2));
|
||||
} else {
|
||||
GLFW.glfwSetWindowPos(windowHandle, config.windowX, config.windowY);
|
||||
}
|
||||
|
||||
if (config.windowMaximized) {
|
||||
GLFW.glfwMaximizeWindow(windowHandle);
|
||||
}
|
||||
}
|
||||
if (config.windowIconPaths != null) {
|
||||
Lwjgl3Window.setIcon(windowHandle, config.windowIconPaths, config.windowIconFileType);
|
||||
}
|
||||
GLFW.glfwMakeContextCurrent(windowHandle);
|
||||
GLFW.glfwSwapInterval(config.vSyncEnabled ? 1 : 0);
|
||||
if (config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.ANGLE_GLES20) {
|
||||
try {
|
||||
Class gles = Class.forName("org.lwjgl.opengles.GLES");
|
||||
gles.getMethod("createCapabilities").invoke(gles);
|
||||
} catch (Throwable e) {
|
||||
throw new GdxRuntimeException("Couldn't initialize GLES", e);
|
||||
}
|
||||
} else {
|
||||
GL.createCapabilities();
|
||||
}
|
||||
|
||||
initiateGL(config.glEmulation == Lwjgl3ApplicationConfiguration.GLEmulation.ANGLE_GLES20);
|
||||
if (!glVersion.isVersionEqualToOrHigher(2, 0))
|
||||
throw new GdxRuntimeException("OpenGL 2.0 or higher with the FBO extension is required. OpenGL version: "
|
||||
+ GL11.glGetString(GL11.GL_VERSION) + "\n" + glVersion.getDebugVersionString());
|
||||
|
||||
if (config.glEmulation != Lwjgl3ApplicationConfiguration.GLEmulation.ANGLE_GLES20 && !supportsFBO()) {
|
||||
throw new GdxRuntimeException("OpenGL 2.0 or higher with the FBO extension is required. OpenGL version: "
|
||||
+ GL11.glGetString(GL11.GL_VERSION) + ", FBO extension: false\n" + glVersion.getDebugVersionString());
|
||||
}
|
||||
|
||||
if (config.debug) {
|
||||
glDebugCallback = GLUtil.setupDebugMessageCallback(config.debugStream);
|
||||
setGLDebugMessageControl(GLDebugMessageSeverity.NOTIFICATION, false);
|
||||
}
|
||||
|
||||
return windowHandle;
|
||||
}
|
||||
|
||||
private static void initiateGL (boolean useGLES20) {
|
||||
if (!useGLES20) {
|
||||
String versionString = GL11.glGetString(GL11.GL_VERSION);
|
||||
String vendorString = GL11.glGetString(GL11.GL_VENDOR);
|
||||
String rendererString = GL11.glGetString(GL11.GL_RENDERER);
|
||||
glVersion = new GLVersion(Application.ApplicationType.Desktop, versionString, vendorString, rendererString);
|
||||
} else {
|
||||
try {
|
||||
Class gles = Class.forName("org.lwjgl.opengles.GLES20");
|
||||
Method getString = gles.getMethod("glGetString", int.class);
|
||||
String versionString = (String)getString.invoke(gles, GL11.GL_VERSION);
|
||||
String vendorString = (String)getString.invoke(gles, GL11.GL_VENDOR);
|
||||
String rendererString = (String)getString.invoke(gles, GL11.GL_RENDERER);
|
||||
glVersion = new GLVersion(Application.ApplicationType.Desktop, versionString, vendorString, rendererString);
|
||||
} catch (Throwable e) {
|
||||
throw new GdxRuntimeException("Couldn't get GLES version string.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean supportsFBO () {
|
||||
// FBO is in core since OpenGL 3.0, see https://www.opengl.org/wiki/Framebuffer_Object
|
||||
return glVersion.isVersionEqualToOrHigher(3, 0) || GLFW.glfwExtensionSupported("GL_EXT_framebuffer_object")
|
||||
|| GLFW.glfwExtensionSupported("GL_ARB_framebuffer_object");
|
||||
}
|
||||
|
||||
public enum GLDebugMessageSeverity {
|
||||
HIGH(GL43.GL_DEBUG_SEVERITY_HIGH, KHRDebug.GL_DEBUG_SEVERITY_HIGH, ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB,
|
||||
AMDDebugOutput.GL_DEBUG_SEVERITY_HIGH_AMD), MEDIUM(GL43.GL_DEBUG_SEVERITY_MEDIUM, KHRDebug.GL_DEBUG_SEVERITY_MEDIUM,
|
||||
ARBDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_ARB, AMDDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_AMD), LOW(
|
||||
GL43.GL_DEBUG_SEVERITY_LOW, KHRDebug.GL_DEBUG_SEVERITY_LOW, ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB,
|
||||
AMDDebugOutput.GL_DEBUG_SEVERITY_LOW_AMD), NOTIFICATION(GL43.GL_DEBUG_SEVERITY_NOTIFICATION,
|
||||
KHRDebug.GL_DEBUG_SEVERITY_NOTIFICATION, -1, -1);
|
||||
|
||||
final int gl43, khr, arb, amd;
|
||||
|
||||
GLDebugMessageSeverity (int gl43, int khr, int arb, int amd) {
|
||||
this.gl43 = gl43;
|
||||
this.khr = khr;
|
||||
this.arb = arb;
|
||||
this.amd = amd;
|
||||
}
|
||||
}
|
||||
|
||||
/** Enables or disables GL debug messages for the specified severity level. Returns false if the severity level could not be
|
||||
* set (e.g. the NOTIFICATION level is not supported by the ARB and AMD extensions).
|
||||
*
|
||||
* See {@link Lwjgl3ApplicationConfiguration#enableGLDebugOutput(boolean, PrintStream)} */
|
||||
public static boolean setGLDebugMessageControl (GLDebugMessageSeverity severity, boolean enabled) {
|
||||
GLCapabilities caps = GL.getCapabilities();
|
||||
final int GL_DONT_CARE = 0x1100; // not defined anywhere yet
|
||||
|
||||
if (caps.OpenGL43) {
|
||||
GL43.glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, severity.gl43, (IntBuffer)null, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (caps.GL_KHR_debug) {
|
||||
KHRDebug.glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, severity.khr, (IntBuffer)null, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (caps.GL_ARB_debug_output && severity.arb != -1) {
|
||||
ARBDebugOutput.glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, severity.arb, (IntBuffer)null, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (caps.GL_AMD_debug_output && severity.amd != -1) {
|
||||
AMDDebugOutput.glDebugMessageEnableAMD(GL_DONT_CARE, severity.amd, (IntBuffer)null, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
93
src/net/torvald/btex/BTeXDocument.kt
Normal file
93
src/net/torvald/btex/BTeXDocument.kt
Normal file
@@ -0,0 +1,93 @@
|
||||
package net.torvald.terrarum.btex
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-28.
|
||||
*/
|
||||
class BTeXDocument {
|
||||
var context = "tome" // tome (cover=hardcover), sheets (cover=typewriter or cover=printout), examination (def=examination)
|
||||
var font = "default" // default or typewriter
|
||||
var inner = "standard"
|
||||
var papersize = "standard"
|
||||
|
||||
var pageWidth = 420
|
||||
var pageHeight = 25 * 24
|
||||
|
||||
companion object {
|
||||
val DEFAULT_PAGE_BACK = Color(0xe1e1d7ff.toInt())
|
||||
val DEFAULT_PAGE_FORE = Color(0x131311ff)
|
||||
}
|
||||
|
||||
private val pages = ArrayList<BTeXPage>()
|
||||
|
||||
|
||||
|
||||
fun addNewPage(back: Color = DEFAULT_PAGE_BACK) {
|
||||
pages.add(BTeXPage(back, pageWidth, pageHeight))
|
||||
}
|
||||
|
||||
fun appendDrawCall(drawCall: BTeXDrawCall) {
|
||||
pages.last().appendDrawCall(drawCall)
|
||||
}
|
||||
|
||||
fun render(batch: SpriteBatch, page: Int, x: Int, y: Int) {
|
||||
pages[page].render(batch, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
class BTeXPage(
|
||||
val back: Color,
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
) {
|
||||
private val drawCalls = ArrayList<BTeXDrawCall>()
|
||||
|
||||
fun appendDrawCall(drawCall: BTeXDrawCall) {
|
||||
drawCalls.add(drawCall)
|
||||
}
|
||||
|
||||
fun render(batch: SpriteBatch, x: Int, y: Int) {
|
||||
batch.color = back
|
||||
Toolkit.fillArea(batch, x, y, width, height)
|
||||
drawCalls.forEach {
|
||||
it.draw(batch, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BTeXDrawCall(
|
||||
val posX: Int,
|
||||
val posY: Int,
|
||||
val theme: String,
|
||||
val colour: Color,
|
||||
val font: BitmapFont,
|
||||
val text: String? = null,
|
||||
val texture: TextureRegion? = null,
|
||||
) {
|
||||
|
||||
fun draw(batch: SpriteBatch, x: Int, y: Int) {
|
||||
val px = (posX + x).toFloat()
|
||||
val py = (posY + y).toFloat()
|
||||
|
||||
if (theme == "code") {
|
||||
// todo draw code background
|
||||
}
|
||||
|
||||
batch.color = colour
|
||||
|
||||
if (text != null && texture == null) {
|
||||
font.draw(batch, text, px, py)
|
||||
}
|
||||
else if (text == null && texture != null) {
|
||||
batch.draw(texture, px, py)
|
||||
}
|
||||
else throw Error("Text and Texture are both non-null")
|
||||
}
|
||||
|
||||
}
|
||||
159
src/net/torvald/btex/BTeXParser.kt
Normal file
159
src/net/torvald/btex/BTeXParser.kt
Normal file
@@ -0,0 +1,159 @@
|
||||
package net.torvald.btex
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.btex.BTeXDocument
|
||||
import net.torvald.terrarum.btex.BTeXDrawCall
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import org.xml.sax.Attributes
|
||||
import org.xml.sax.helpers.DefaultHandler
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
import javax.xml.parsers.SAXParserFactory
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-28.
|
||||
*/
|
||||
object BTeXParser {
|
||||
|
||||
operator fun invoke(file: FileHandle) = invoke(file.file())
|
||||
|
||||
operator fun invoke(file: File): BTeXDocument {
|
||||
val doc = BTeXDocument()
|
||||
val parser = SAXParserFactory.newDefaultInstance().newSAXParser()
|
||||
val stream = FileInputStream(file)
|
||||
parser.parse(stream, BTeXHandler(doc))
|
||||
return doc
|
||||
}
|
||||
|
||||
private class BTeXHandler(val doc: BTeXDocument) : DefaultHandler() {
|
||||
private val DEFAULT_FONTCOL = Color(0x222222ff)
|
||||
private val LINE_HEIGHT = 24
|
||||
|
||||
private var cover = ""
|
||||
private var inner = ""
|
||||
private var papersize = ""
|
||||
private var def = ""
|
||||
|
||||
private var pageWidth = 420
|
||||
private var pageLines = 25
|
||||
private var pageHeight = 25 * LINE_HEIGHT
|
||||
|
||||
private val blockLut = HashMap<String, ItemID>()
|
||||
|
||||
private val tagStack = ArrayList<String>() // index zero should be "btex"
|
||||
|
||||
|
||||
private var spanColour: String? = null
|
||||
|
||||
|
||||
private var typeX = 0
|
||||
private var typeY = 0
|
||||
|
||||
override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) {
|
||||
val tag = qName; if (tagStack.isEmpty() && tag != "btex") throw BTeXParsingException("Document is not btex")
|
||||
tagStack.add(tag)
|
||||
|
||||
val attribs = HashMap<String, String>().also {
|
||||
it.putAll((0 until attributes.length).map { attributes.getQName(it) to attributes.getValue(it) })
|
||||
}
|
||||
|
||||
val mode = tagStack.getOrNull(1)
|
||||
|
||||
when (tag) {
|
||||
"btex" -> {
|
||||
if (attribs.containsKey("def"))
|
||||
def = attribs["def"]!!
|
||||
else {
|
||||
cover = attribs["cover"] ?: "printout"
|
||||
inner = attribs["inner"] ?: "standard"
|
||||
papersize = attribs["papersize"] ?: "standard"
|
||||
|
||||
pageWidth = pageWidthMap[papersize]!!
|
||||
pageLines = pageHeightMap[papersize]!!
|
||||
pageHeight = pageLines * LINE_HEIGHT
|
||||
|
||||
doc.pageWidth = pageWidth
|
||||
doc.pageHeight = pageHeight
|
||||
}
|
||||
}
|
||||
"pair" -> {
|
||||
if (tagStack.size == 3 && mode == "blocklut") {
|
||||
blockLut[attribs["key"]!!] = attribs["value"]!!
|
||||
}
|
||||
else {
|
||||
throw BTeXParsingException("<pair> used outside of <blocklut>")
|
||||
}
|
||||
}
|
||||
"span" -> {
|
||||
attribs["span"]?.let {
|
||||
spanColour = it
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun endElement(uri: String, localName: String, qName: String) {
|
||||
tagStack.removeLast()
|
||||
|
||||
when (qName) {
|
||||
"span" -> {
|
||||
spanColour = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun characters(ch: CharArray, start: Int, length: Int) {
|
||||
val str = String(ch.sliceArray(start until start+length)).replace('\n',' ').replace(Regex(" +"), " ").trim()
|
||||
val font = getFont()
|
||||
advanceCursorPre(font.getWidth(str), 0)
|
||||
doc.appendDrawCall(BTeXDrawCall(typeX, typeY, inner, getSpanColour(), font, str))
|
||||
advanceCursorPost(font.getWidth(str), 0)
|
||||
}
|
||||
|
||||
private fun advanceCursorPre(w: Int, h: Int) {
|
||||
if (typeX + w > pageWidth) {
|
||||
typeY += LINE_HEIGHT
|
||||
typeX = 0
|
||||
}
|
||||
|
||||
if (typeY + h > pageHeight) {
|
||||
typeX = 0
|
||||
typeY = 0
|
||||
doc.addNewPage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun advanceCursorPost(w: Int, h: Int) {
|
||||
typeX += w
|
||||
typeY += h
|
||||
}
|
||||
|
||||
|
||||
private fun getFont() = when (cover) {
|
||||
"typewriter" -> TODO()
|
||||
else -> App.fontGame
|
||||
}
|
||||
|
||||
private fun getSpanColour(): Color = spanColourMap.getOrDefault(spanColour, DEFAULT_FONTCOL)
|
||||
|
||||
private val spanColourMap = hashMapOf(
|
||||
"grey" to Color.LIGHT_GRAY
|
||||
)
|
||||
|
||||
private val pageWidthMap = hashMapOf(
|
||||
"standard" to 420
|
||||
)
|
||||
private val pageHeightMap = hashMapOf(
|
||||
"standard" to 25
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BTeXParsingException(s: String) : RuntimeException(s) {
|
||||
|
||||
}
|
||||
@@ -12,8 +12,8 @@ import com.badlogic.gdx.graphics.glutils.*;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
import com.badlogic.gdx.utils.JsonValue;
|
||||
import com.badlogic.gdx.utils.SharedLibraryLoader;
|
||||
import com.github.strikerx3.jxinput.XInputDevice;
|
||||
import kotlin.text.Charsets;
|
||||
import net.torvald.getcpuname.GetCpuName;
|
||||
import net.torvald.terrarum.controller.GdxControllerAdapter;
|
||||
import net.torvald.terrarum.controller.TerrarumController;
|
||||
@@ -41,6 +41,8 @@ import net.torvald.unsafe.AddressOverflowException;
|
||||
import net.torvald.unsafe.DanglingPointerException;
|
||||
import net.torvald.unsafe.UnsafeHelper;
|
||||
import net.torvald.util.DebugTimers;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
@@ -72,6 +74,11 @@ public class App implements ApplicationListener {
|
||||
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG) + (snap == null ? "" : (" (" + snap + ")"));
|
||||
}
|
||||
|
||||
public static final String getVERSION_STRING_WITHOUT_SNAPSHOT() {
|
||||
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) +
|
||||
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* when FALSE, some assertion and print code will not execute
|
||||
*/
|
||||
@@ -186,7 +193,6 @@ public class App implements ApplicationListener {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean splashDisplayed = false;
|
||||
private static boolean postInitFired = false;
|
||||
private static boolean screenshotRequested = false;
|
||||
private static boolean resizeRequested = false;
|
||||
@@ -242,8 +248,7 @@ public class App implements ApplicationListener {
|
||||
|
||||
|
||||
public static Texture[] ditherPatterns = new Texture[4];
|
||||
private static ShaderProgram shaderBayerSkyboxFill; // ONLY to be used by the splash screen
|
||||
public static ShaderProgram shaderHicolour;
|
||||
// public static ShaderProgram shaderHicolour;
|
||||
public static ShaderProgram shaderDebugDiff;
|
||||
public static ShaderProgram shaderPassthruRGBA;
|
||||
public static ShaderProgram shaderColLUT;
|
||||
@@ -254,7 +259,8 @@ public class App implements ApplicationListener {
|
||||
public static Mesh fullscreenQuad;
|
||||
private static OrthographicCamera camera;
|
||||
private static FlippingSpriteBatch logoBatch;
|
||||
public static TextureRegion logo;
|
||||
public static TextureRegion splashScreenLogo;
|
||||
private static TextureRegion splashBackdrop;
|
||||
public static AudioDevice audioDevice;
|
||||
|
||||
public static FlippingSpriteBatch batch;
|
||||
@@ -339,6 +345,8 @@ public class App implements ApplicationListener {
|
||||
|
||||
public static boolean gl40capable = false;
|
||||
|
||||
public static Thread audioManagerThread;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
long st = System.nanoTime();
|
||||
@@ -474,9 +482,54 @@ public class App implements ApplicationListener {
|
||||
new GameCrashHandler(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Color splashTextCol = new Color(0x282828FF);
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
File loadOrderFile = new File(App.loadOrderDir);
|
||||
if (loadOrderFile.exists()) {
|
||||
// load modules
|
||||
CSVParser loadOrderCSVparser = null;
|
||||
try {
|
||||
loadOrderCSVparser = CSVParser.parse(
|
||||
loadOrderFile,
|
||||
Charsets.UTF_8,
|
||||
CSVFormat.DEFAULT.withCommentMarker('#')
|
||||
);
|
||||
var loadOrder = loadOrderCSVparser.getRecords();
|
||||
|
||||
if (loadOrder.size() > 0) {
|
||||
var modname = loadOrder.get(0).get(0);
|
||||
|
||||
var textureFile = Gdx.files.internal("assets/mods/"+modname+"/splashback.png");
|
||||
if (textureFile.exists()) {
|
||||
splashBackdrop = new TextureRegion(new Texture(textureFile));
|
||||
splashTextCol = new Color(0xeeeeeeff);
|
||||
}
|
||||
|
||||
var logoFile = Gdx.files.internal("assets/mods/"+modname+"/splashlogo.png");
|
||||
if (logoFile.exists()) {
|
||||
splashScreenLogo = new TextureRegion(new Texture(logoFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
||||
}
|
||||
finally {
|
||||
try {loadOrderCSVparser.close();}
|
||||
catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (splashBackdrop == null) {
|
||||
splashBackdrop = new TextureRegion(new Texture("assets/graphics/background_white.png"));
|
||||
}
|
||||
if (splashScreenLogo == null) {
|
||||
splashScreenLogo = new TextureRegion(new Texture("assets/graphics/logo.png"));
|
||||
}
|
||||
|
||||
Gdx.graphics.setContinuousRendering(true);
|
||||
|
||||
GAME_LOCALE = getConfigString("language");
|
||||
@@ -504,10 +557,6 @@ public class App implements ApplicationListener {
|
||||
|
||||
initViewPort(scr.getWidth(), scr.getHeight());
|
||||
|
||||
// logo here :p
|
||||
logo = new TextureRegion(new Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga")));
|
||||
logo.flip(false, false);
|
||||
|
||||
// set GL graphics constants
|
||||
for (int i = 0; i < ditherPatterns.length; i++) {
|
||||
Texture t = new Texture(Gdx.files.classpath("shaders/dither_512_"+i+".tga"));
|
||||
@@ -516,9 +565,6 @@ public class App implements ApplicationListener {
|
||||
ditherPatterns[i] = t;
|
||||
}
|
||||
|
||||
shaderBayerSkyboxFill = loadShaderFromClasspath("shaders/default.vert",
|
||||
"shaders/float_to_disp_dither_static.frag"
|
||||
);
|
||||
shaderPassthruRGBA = loadShaderFromClasspath("shaders/gl32spritebatch.vert", "shaders/gl32spritebatch.frag");
|
||||
shaderReflect = loadShaderFromClasspath("shaders/default.vert", "shaders/reflect.frag");
|
||||
hq2x = new Hq2x(2);
|
||||
@@ -545,20 +591,22 @@ public class App implements ApplicationListener {
|
||||
private FrameBuffer postProcessorOutFBO;
|
||||
private FrameBuffer postProcessorOutFBO2;
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
// Gdx.gl.glDisable(GL20.GL_DITHER);
|
||||
|
||||
if (splashDisplayed && !postInitFired) {
|
||||
private void firePostInit() {
|
||||
if (!postInitFired) {
|
||||
postInitFired = true;
|
||||
postInit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
// Gdx.gl.glDisable(GL20.GL_DITHER);
|
||||
|
||||
App.setDebugTime("GDX.rawDelta", (long) (Gdx.graphics.getDeltaTime() * 1000_000_000f));
|
||||
|
||||
|
||||
FrameBufferManager.begin(renderFBO);
|
||||
gdxClearAndEnableBlend(.094f, .094f, .094f, 0f);
|
||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f);
|
||||
setCameraPosition(0, 0);
|
||||
|
||||
|
||||
@@ -571,6 +619,8 @@ public class App implements ApplicationListener {
|
||||
loadTimer += Gdx.graphics.getDeltaTime();
|
||||
|
||||
if (loadTimer >= showupTime) {
|
||||
firePostInit();
|
||||
|
||||
// hand over the scene control to this single class; Terrarum must call
|
||||
// 'AppLoader.getINSTANCE().screen.render(delta)', this is not redundant at all!
|
||||
|
||||
@@ -590,10 +640,13 @@ public class App implements ApplicationListener {
|
||||
}
|
||||
// draw the screen
|
||||
else {
|
||||
firePostInit();
|
||||
|
||||
currentScreen.render(UPDATE_RATE);
|
||||
postProcessorOutFBO = TerrarumPostProcessor.INSTANCE.draw(camera.combined, renderFBO);
|
||||
}
|
||||
|
||||
|
||||
KeyToggler.INSTANCE.update(currentScreen instanceof TerrarumIngame);
|
||||
|
||||
|
||||
@@ -649,7 +702,6 @@ public class App implements ApplicationListener {
|
||||
|
||||
|
||||
|
||||
splashDisplayed = true;
|
||||
GLOBAL_RENDER_TIMER += 1;
|
||||
|
||||
}
|
||||
@@ -688,50 +740,78 @@ public class App implements ApplicationListener {
|
||||
}
|
||||
|
||||
private void drawSplash() {
|
||||
getCurrentDitherTex().bind(0);
|
||||
shaderBayerSkyboxFill.bind();
|
||||
shaderBayerSkyboxFill.setUniformMatrix("u_projTrans", camera.combined);
|
||||
shaderBayerSkyboxFill.setUniformi("u_texture", 0);
|
||||
shaderBayerSkyboxFill.setUniformf("parallax_size", 0f);
|
||||
shaderBayerSkyboxFill.setUniformf("topColor", gradWhiteTop.r, gradWhiteTop.g, gradWhiteTop.b, 1f);
|
||||
shaderBayerSkyboxFill.setUniformf("bottomColor", gradWhiteBottom.r, gradWhiteBottom.g, gradWhiteBottom.b, 1f);
|
||||
fullscreenQuad.render(shaderBayerSkyboxFill, GL20.GL_TRIANGLE_FAN);
|
||||
|
||||
|
||||
setCameraPosition(0f, 0f);
|
||||
|
||||
logoBatch.setColor(Color.WHITE);
|
||||
logoBatch.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
|
||||
int drawWidth = Toolkit.INSTANCE.getDrawWidth();
|
||||
int safetyTextLen = fontGame.getWidth(Lang.INSTANCE.get("APP_WARNING_HEALTH_AND_SAFETY", true));
|
||||
int logoPosX = (drawWidth - logo.getRegionWidth() - safetyTextLen) >>> 1;
|
||||
int logoPosX = (drawWidth - splashScreenLogo.getRegionWidth() - safetyTextLen) >>> 1;
|
||||
int logoPosY = Math.round(scr.getHeight() / 15f);
|
||||
int textY = logoPosY + logo.getRegionHeight() - 16;
|
||||
int textY = logoPosY + splashScreenLogo.getRegionHeight() - 16;
|
||||
|
||||
// draw custom backdrop (if exists)
|
||||
if (splashBackdrop != null) {
|
||||
logoBatch.setShader(null);
|
||||
logoBatch.begin();
|
||||
|
||||
|
||||
var size = ((float) Math.max(scr.getWidth(), scr.getHeight()));
|
||||
var x = 0f;
|
||||
var y = 0f;
|
||||
if (scr.getWidth() > scr.getHeight()) {
|
||||
y = (scr.getHeight() - size) / 2f;
|
||||
}
|
||||
else {
|
||||
x = (scr.getWidth() - size) / 2f;
|
||||
}
|
||||
|
||||
logoBatch.draw(splashBackdrop, x, y, size, size);
|
||||
|
||||
|
||||
logoBatch.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// draw logo reflection
|
||||
logoBatch.setShader(shaderReflect);
|
||||
logoBatch.setColor(Color.WHITE);
|
||||
logoBatch.begin();
|
||||
|
||||
if (getConfigBoolean("showhealthmessageonstartup")) {
|
||||
logoBatch.draw(logo, logoPosX, logoPosY + logo.getRegionHeight());
|
||||
logoBatch.draw(splashScreenLogo, logoPosX, logoPosY + splashScreenLogo.getRegionHeight());
|
||||
}
|
||||
else {
|
||||
logoBatch.draw(logo, (drawWidth - logo.getRegionWidth()) / 2f,
|
||||
(scr.getHeight() - logo.getRegionHeight() * 2) / 2f + logo.getRegionHeight()
|
||||
logoBatch.draw(splashScreenLogo, (drawWidth - splashScreenLogo.getRegionWidth()) / 2f,
|
||||
(scr.getHeight() - splashScreenLogo.getRegionHeight() * 2) / 2f + splashScreenLogo.getRegionHeight()
|
||||
);
|
||||
}
|
||||
logoBatch.end();
|
||||
logoBatch.setShader(null);
|
||||
logoBatch.begin();
|
||||
if (getConfigBoolean("showhealthmessageonstartup")) {
|
||||
logoBatch.draw(splashScreenLogo, logoPosX, logoPosY);
|
||||
}
|
||||
else {
|
||||
logoBatch.draw(splashScreenLogo, (drawWidth - splashScreenLogo.getRegionWidth()) / 2f,
|
||||
(scr.getHeight() - splashScreenLogo.getRegionHeight() * 2) / 2f
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
logoBatch.end();
|
||||
|
||||
// draw health messages
|
||||
logoBatch.setShader(null);
|
||||
logoBatch.begin();
|
||||
|
||||
if (getConfigBoolean("showhealthmessageonstartup")) {
|
||||
logoBatch.setShader(null);
|
||||
logoBatch.begin();
|
||||
|
||||
logoBatch.draw(logo, logoPosX, logoPosY);
|
||||
logoBatch.setColor(new Color(0x282828ff));
|
||||
logoBatch.setColor(splashTextCol);
|
||||
fontGame.draw(logoBatch, Lang.INSTANCE.get("APP_WARNING_HEALTH_AND_SAFETY", true),
|
||||
logoPosX + logo.getRegionWidth(),
|
||||
logoPosX + splashScreenLogo.getRegionWidth(),
|
||||
textY
|
||||
);
|
||||
|
||||
@@ -747,22 +827,17 @@ public class App implements ApplicationListener {
|
||||
}
|
||||
}
|
||||
|
||||
logoBatch.setColor(new Color(0x282828ff));
|
||||
Texture tex1 = CommonResourcePool.INSTANCE.getAsTexture("title_health1");
|
||||
Texture tex2 = CommonResourcePool.INSTANCE.getAsTexture("title_health2");
|
||||
int virtualHeight = scr.getHeight() - logoPosY - logo.getRegionHeight() / 4;
|
||||
int virtualHeight = scr.getHeight() - logoPosY - splashScreenLogo.getRegionHeight() / 4;
|
||||
int virtualHeightOffset = scr.getHeight() - virtualHeight;
|
||||
logoBatch.drawFlipped(tex1, (drawWidth - tex1.getWidth()) >>> 1, virtualHeightOffset + (virtualHeight >>> 1) - 16, tex1.getWidth(), -tex1.getHeight());
|
||||
logoBatch.drawFlipped(tex2, (drawWidth - tex2.getWidth()) >>> 1, virtualHeightOffset + (virtualHeight >>> 1) + 16 + tex2.getHeight(), tex2.getWidth(), -tex2.getHeight());
|
||||
|
||||
}
|
||||
else {
|
||||
logoBatch.draw(logo, (drawWidth - logo.getRegionWidth()) / 2f,
|
||||
(scr.getHeight() - logo.getRegionHeight() * 2) / 2f
|
||||
);
|
||||
}
|
||||
|
||||
logoBatch.end();
|
||||
batch.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -840,6 +915,7 @@ public class App implements ApplicationListener {
|
||||
public void dispose() {
|
||||
System.out.println("Goodbye !");
|
||||
|
||||
audioManagerThread.interrupt();
|
||||
|
||||
if (currentScreen != null) {
|
||||
currentScreen.hide();
|
||||
@@ -854,8 +930,7 @@ public class App implements ApplicationListener {
|
||||
for (Texture texture : ditherPatterns) {
|
||||
texture.dispose();
|
||||
}
|
||||
shaderBayerSkyboxFill.dispose();
|
||||
shaderHicolour.dispose();
|
||||
// shaderHicolour.dispose();
|
||||
shaderDebugDiff.dispose();
|
||||
shaderPassthruRGBA.dispose();
|
||||
shaderColLUT.dispose();
|
||||
@@ -875,7 +950,8 @@ public class App implements ApplicationListener {
|
||||
fontBigNumbers.dispose();
|
||||
ItemSlotImageFactory.INSTANCE.dispose();
|
||||
|
||||
logo.getTexture().dispose();
|
||||
splashScreenLogo.getTexture().dispose();
|
||||
splashBackdrop.getTexture().dispose();
|
||||
|
||||
ModMgr.INSTANCE.disposeMods();
|
||||
|
||||
@@ -962,6 +1038,9 @@ public class App implements ApplicationListener {
|
||||
* Init stuffs which needs GL context
|
||||
*/
|
||||
private void postInit() {
|
||||
long t1 = System.nanoTime();
|
||||
|
||||
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("blockmarkings_common", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("blockmarking_actor", () -> new BlockMarkerActor());
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("loading_circle_64", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/loading_circle_64.tga"), 64, 64, 0, 0, 0, 0, false, false, false));
|
||||
@@ -969,7 +1048,7 @@ public class App implements ApplicationListener {
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("inventory_category", () -> new TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.loadAll();
|
||||
|
||||
shaderHicolour = loadShaderFromClasspath("shaders/default.vert", "shaders/hicolour.frag");
|
||||
// shaderHicolour = loadShaderFromClasspath("shaders/default.vert", "shaders/hicolour.frag");
|
||||
shaderDebugDiff = loadShaderFromClasspath("shaders/default.vert", "shaders/diff.frag");
|
||||
shaderColLUT = loadShaderFromClasspath("shaders/default.vert", "shaders/rgbonly.frag");
|
||||
shaderGhastlyWhite = loadShaderFromClasspath("shaders/default.vert", "shaders/ghastlywhite.frag");
|
||||
@@ -1106,6 +1185,10 @@ public class App implements ApplicationListener {
|
||||
}
|
||||
|
||||
|
||||
AudioManager.INSTANCE.getMasterVolume();
|
||||
audioManagerThread = new Thread(new AudioManagerRunnable(), "TerrarumAudioManager");
|
||||
audioManagerThread.start();
|
||||
|
||||
Terrarum.initialise();
|
||||
|
||||
|
||||
@@ -1122,7 +1205,9 @@ public class App implements ApplicationListener {
|
||||
printdbg(this, "Has update: " + hasUpdate);
|
||||
|
||||
|
||||
printdbg(this, "PostInit done");
|
||||
long t2 = System.nanoTime();
|
||||
double tms = (t2 - t1) / 1000000000.0;
|
||||
printdbg(this, "PostInit done; took "+tms+" seconds");
|
||||
}
|
||||
|
||||
|
||||
@@ -1245,6 +1330,10 @@ public class App implements ApplicationListener {
|
||||
public static String recycledPlayersDir;
|
||||
/** defaultDir + "/Recycled/Worlds" */
|
||||
public static String recycledWorldsDir;
|
||||
/** defaultDir + "/Custom/" */
|
||||
public static String customDir;
|
||||
/** defaultDir + "/Custom/Music" */
|
||||
public static String customMusicDir;
|
||||
|
||||
private static void getDefaultDirectory() {
|
||||
String OS = OSName.toUpperCase();
|
||||
@@ -1278,6 +1367,8 @@ public class App implements ApplicationListener {
|
||||
recycledPlayersDir = defaultDir + "/Recycled/Players";
|
||||
recycledWorldsDir = defaultDir + "/Recycled/Worlds";
|
||||
importDir = defaultDir + "/Imports";
|
||||
customDir = defaultDir + "/Custom";
|
||||
customMusicDir = customDir + "/Music";
|
||||
|
||||
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
|
||||
System.out.println(String.format("os.version = %s", OSVersion));
|
||||
@@ -1293,7 +1384,9 @@ public class App implements ApplicationListener {
|
||||
new File(worldsDir),
|
||||
new File(recycledPlayersDir),
|
||||
new File(recycledWorldsDir),
|
||||
new File(importDir)
|
||||
new File(importDir),
|
||||
new File(customDir),
|
||||
new File(customMusicDir)
|
||||
};
|
||||
|
||||
for (File it : dirs) {
|
||||
@@ -1599,7 +1692,7 @@ public class App implements ApplicationListener {
|
||||
System.out.println(prompt+"null");
|
||||
}
|
||||
else {
|
||||
String indentation = " ".repeat(out.length() + 15);
|
||||
String indentation = " ".repeat(out.length() + 16);
|
||||
String[] msgLines = message.toString().split("\\n");
|
||||
for (int i = 0; i < msgLines.length; i++) {
|
||||
System.out.println((i == 0 ? prompt : indentation) + msgLines[i]);
|
||||
@@ -1621,10 +1714,10 @@ public class App implements ApplicationListener {
|
||||
System.out.println(prompt+"null"+csi0);
|
||||
}
|
||||
else {
|
||||
String indentation = " ".repeat(out.length() + 11);
|
||||
String indentation = " ".repeat(out.length() + 16);
|
||||
String[] msgLines = message.toString().split("\\n");
|
||||
for (int i = 0; i < msgLines.length; i++) {
|
||||
System.out.println((i == 0 ? prompt : indentation) + msgLines[i] + csi0);
|
||||
System.out.println((i == 0 ? prompt : indentation) + csiR + msgLines[i] + csi0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
116
src/net/torvald/terrarum/AudioManager.kt
Normal file
116
src/net/torvald/terrarum/AudioManager.kt
Normal file
@@ -0,0 +1,116 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.Lwjgl3Audio
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
|
||||
/**
|
||||
* Any audio reference fed into this manager will get lost; you must manually store and dispose of them on your own.
|
||||
*
|
||||
* Created by minjaesong on 2023-11-07.
|
||||
*/
|
||||
object AudioManager {
|
||||
const val DEFAULT_FADEOUT_LEN = 2.4f
|
||||
|
||||
/** Returns a master volume */
|
||||
val masterVolume: Float
|
||||
get() = App.getConfigDouble("mastervolume").toFloat()
|
||||
|
||||
/** Returns a (master volume * bgm volume) */
|
||||
val musicVolume: Float
|
||||
get() = (App.getConfigDouble("bgmvolume") * App.getConfigDouble("mastervolume")).toFloat()
|
||||
|
||||
/** Returns a (master volume * sfx volume */
|
||||
val ambientVolume: Float
|
||||
get() = (App.getConfigDouble("sfxvolume") * App.getConfigDouble("mastervolume")).toFloat()
|
||||
|
||||
|
||||
var currentMusic: MusicContainer? = null
|
||||
var currentAmbient: MusicContainer? = null
|
||||
|
||||
private var nextMusic: MusicContainer? = null
|
||||
|
||||
private var fadeAkku = 0f
|
||||
private var fadeLength = DEFAULT_FADEOUT_LEN
|
||||
|
||||
private var fadeoutFired = false
|
||||
private var fadeinFired = false
|
||||
|
||||
fun update(delta: Float) {
|
||||
(Gdx.audio as? Lwjgl3Audio)?.update()
|
||||
|
||||
|
||||
if (fadeoutFired) {
|
||||
fadeAkku += delta
|
||||
currentMusic?.gdxMusic?.volume = (musicVolume * (1f - (fadeAkku / fadeLength))).coerceIn(0f, 1f)
|
||||
|
||||
// printdbg(this, "Fadeout fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
||||
|
||||
if (fadeAkku >= fadeLength) {
|
||||
fadeoutFired = false
|
||||
currentMusic?.gdxMusic?.volume = 0f
|
||||
// currentMusic?.gdxMusic?.pause()
|
||||
currentMusic = null
|
||||
|
||||
// printdbg(this, "Fadeout end")
|
||||
}
|
||||
}
|
||||
// process fadein request
|
||||
else if (fadeinFired) {
|
||||
fadeAkku += delta
|
||||
currentMusic?.gdxMusic?.volume = (musicVolume * (fadeAkku / fadeLength)).coerceIn(0f, 1f)
|
||||
|
||||
// printdbg(this, "Fadein fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
||||
|
||||
if (currentMusic?.gdxMusic?.isPlaying == false) {
|
||||
currentMusic?.gdxMusic?.play()
|
||||
// printdbg(this, "Fadein starting music ${currentMusic?.name}")
|
||||
}
|
||||
|
||||
if (fadeAkku >= fadeLength) {
|
||||
currentMusic?.gdxMusic?.volume = musicVolume
|
||||
fadeinFired = false
|
||||
|
||||
// printdbg(this, "Fadein end")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (currentMusic?.gdxMusic?.isPlaying != true && nextMusic != null) {
|
||||
// printdbg(this, "Playing next music: ${nextMusic!!.name}")
|
||||
currentMusic = nextMusic
|
||||
nextMusic = null
|
||||
currentMusic!!.gdxMusic.volume = musicVolume
|
||||
currentMusic!!.gdxMusic.play()
|
||||
}
|
||||
}
|
||||
|
||||
fun startMusic(song: MusicContainer) {
|
||||
if (currentMusic?.gdxMusic?.isPlaying == true) {
|
||||
requestFadeOut(DEFAULT_FADEOUT_LEN)
|
||||
}
|
||||
nextMusic = song
|
||||
}
|
||||
|
||||
fun stopMusic() {
|
||||
requestFadeOut(DEFAULT_FADEOUT_LEN)
|
||||
}
|
||||
|
||||
fun requestFadeOut(length: Float) {
|
||||
if (!fadeoutFired) {
|
||||
fadeLength = length.coerceAtLeast(1f/1024f)
|
||||
fadeAkku = 0f
|
||||
fadeoutFired = true
|
||||
}
|
||||
}
|
||||
|
||||
fun requestFadeIn(length: Float) {
|
||||
if (!fadeinFired) {
|
||||
fadeLength = length.coerceAtLeast(1f/1024f)
|
||||
fadeAkku = 0f
|
||||
fadeinFired = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
29
src/net/torvald/terrarum/AudioManagerRunnable.kt
Normal file
29
src/net/torvald/terrarum/AudioManagerRunnable.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import net.torvald.terrarum.gamecontroller.InputStrober
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-11-08.
|
||||
*/
|
||||
class AudioManagerRunnable : Runnable {
|
||||
|
||||
var oldT = System.nanoTime()
|
||||
var dT = 0f
|
||||
|
||||
override fun run() {
|
||||
while (!Thread.interrupted()) {
|
||||
try {
|
||||
val T = System.nanoTime()
|
||||
dT = (T - oldT) / 1000000000f
|
||||
oldT = T;
|
||||
AudioManager.update(dT)
|
||||
// println("AudioManagerRunnable dT = ${dT * 1000f} ms")
|
||||
Thread.sleep(30L)
|
||||
}
|
||||
catch (e: InterruptedException) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import java.net.http.HttpResponse
|
||||
*/
|
||||
object CheckUpdate {
|
||||
|
||||
private val versionNumFull = App.getVERSION_STRING()
|
||||
private val versionNumFull = App.getVERSION_STRING_WITHOUT_SNAPSHOT()
|
||||
private val versionNumOnly = String.format(
|
||||
"%d.%d.%d",
|
||||
App.VERSION_RAW ushr 48,
|
||||
|
||||
@@ -128,6 +128,10 @@ object DefaultConfig {
|
||||
"bgmvolume" to 1.0,
|
||||
"sfxvolume" to 1.0,
|
||||
|
||||
"lightpasses" to 3,
|
||||
|
||||
"enablescriptmods" to false,
|
||||
|
||||
|
||||
|
||||
// settings regarding debugger
|
||||
|
||||
@@ -9,7 +9,7 @@ import net.torvald.terrarum.langpack.Lang
|
||||
|
||||
object ErrorDisp : Screen {
|
||||
|
||||
private val logoTex = App.logo
|
||||
private val logoTex = App.splashScreenLogo
|
||||
private val font = App.fontGame
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ object ErrorDisp : Screen {
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
gdxClearAndEnableBlend(.094f, .094f, .094f, 0f)
|
||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
@@ -22,6 +22,7 @@ import net.torvald.terrarum.modulebasegame.ui.UITooltip
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.savegame.VirtualDisk
|
||||
import net.torvald.terrarum.ui.ConsoleWindow
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.util.CircularArray
|
||||
import net.torvald.util.SortedArrayList
|
||||
import org.khelekore.prtree.*
|
||||
@@ -90,7 +91,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
init {
|
||||
consoleHandler.setPosition(0, 0)
|
||||
notifier.setPosition(
|
||||
(App.scr.width - notifier.width) / 2,
|
||||
(Toolkit.drawWidth - notifier.width) / 2,
|
||||
App.scr.height - notifier.height - App.scr.tvSafeGraphicsHeight
|
||||
)
|
||||
|
||||
@@ -186,6 +187,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
}
|
||||
|
||||
override fun render(updateRate: Float) {
|
||||
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
@@ -333,10 +335,10 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
|
||||
protected open fun forceRemoveActor(actor: Actor, caller: Throwable = StackTraceRecorder()) {
|
||||
arrayOf(actorContainerActive, actorContainerInactive).forEach { actorContainer ->
|
||||
val indexToDelete = actorContainer.searchFor(actor.referenceID) { it.referenceID }
|
||||
val indexToDelete = actorContainer.searchForIndex(actor.referenceID) { it.referenceID }
|
||||
if (indexToDelete != null) {
|
||||
actor.dispose()
|
||||
actorContainer.remove(indexToDelete)
|
||||
actorContainer.removeAt(indexToDelete)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,7 +350,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
throw ReferencedActorAlreadyExistsException(actor, caller)
|
||||
}
|
||||
else {
|
||||
actorAdditionQueue.add(actor to StackTraceRecorder())
|
||||
actorContainerActive.add(actor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,6 +547,8 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
|
||||
fun onConfigChange() {
|
||||
}
|
||||
|
||||
open val musicGovernor: MusicGovernor = MusicGovernor()
|
||||
}
|
||||
|
||||
inline fun Lock.lock(body: () -> Unit) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.util.CircularArray
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
open class LoadScreenBase : ScreenAdapter(), Disposable, TerrarumGamescreen {
|
||||
|
||||
@@ -26,6 +27,9 @@ open class LoadScreenBase : ScreenAdapter(), Disposable, TerrarumGamescreen {
|
||||
|
||||
var camera = OrthographicCamera(App.scr.wf, App.scr.hf)
|
||||
|
||||
var progress = AtomicLong(0L) // generic variable, interpretation will vary by the screen
|
||||
var stageValue = 0
|
||||
|
||||
override fun show() {
|
||||
messages.clear()
|
||||
doContextChange = false
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.utils.JsonValue
|
||||
import net.torvald.terrarum.App.*
|
||||
import net.torvald.terrarum.App.setToGameConfig
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.blockproperties.OreCodex
|
||||
import net.torvald.terrarum.blockproperties.WireCodex
|
||||
import net.torvald.terrarum.gamecontroller.IME
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
@@ -14,6 +15,9 @@ import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.itemproperties.MaterialCodex
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.OregenParams
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen
|
||||
import net.torvald.terrarum.serialise.Common
|
||||
import net.torvald.terrarum.utils.CSVFetcher
|
||||
import net.torvald.terrarum.utils.JsonFetcher
|
||||
import net.torvald.terrarum.utils.forEachSiblings
|
||||
@@ -66,8 +70,10 @@ object ModMgr {
|
||||
val version: String,
|
||||
val jar: String,
|
||||
val dependencies: Array<String>,
|
||||
val isInternal: Boolean
|
||||
val isInternal: Boolean,
|
||||
val configPlan: List<String>
|
||||
) {
|
||||
|
||||
override fun toString() =
|
||||
"\tModule #$order -- $properName | $version | $author\n" +
|
||||
"\t$description | $releaseDate\n" +
|
||||
@@ -120,7 +126,7 @@ object ModMgr {
|
||||
|
||||
|
||||
init {
|
||||
val loadOrderFile = FileSystems.getDefault().getPath("${App.defaultDir}/LoadOrder.txt").toFile()
|
||||
val loadOrderFile = File(App.loadOrderDir)
|
||||
if (loadOrderFile.exists()) {
|
||||
|
||||
// load modules
|
||||
@@ -134,6 +140,10 @@ object ModMgr {
|
||||
|
||||
|
||||
loadOrder.forEachIndexed { index, it ->
|
||||
|
||||
val loadScriptMod = if (App.getConfigBoolean("enablescriptmods")) true else (index == 0)
|
||||
|
||||
|
||||
val moduleName = it[0]
|
||||
this.loadOrder.add(moduleName)
|
||||
printmsg(this, "Loading module $moduleName")
|
||||
@@ -191,7 +201,14 @@ object ModMgr {
|
||||
val dependency = modMetadata.getProperty("dependency").split(Regex(""";[ ]*""")).filter { it.isNotEmpty() }.toTypedArray()
|
||||
val isDir = FileSystems.getDefault().getPath("$modDir/$moduleName").toFile().isDirectory
|
||||
|
||||
module = ModuleMetadata(index, isDir, getGdxFile("$modDir/$moduleName/icon.png"), properName, description, descTranslations, author, packageName, entryPoint, releaseDate, version, jar, dependency, isInternal)
|
||||
val configPlan = ArrayList<String>()
|
||||
File("$modDir/$moduleName/configplan.csv").let {
|
||||
if (it.exists() && it.isFile) {
|
||||
configPlan.addAll(it.readLines(Common.CHARSET).filter { it.isNotBlank() })
|
||||
}
|
||||
}
|
||||
|
||||
module = ModuleMetadata(index, isDir, getGdxFile("$modDir/$moduleName/icon.png"), properName, description, descTranslations, author, packageName, entryPoint, releaseDate, version, jar, dependency, isInternal, configPlan)
|
||||
|
||||
val versionNumeral = version.split('.')
|
||||
val versionNumber = versionNumeral.toVersionNumber()
|
||||
@@ -237,6 +254,11 @@ object ModMgr {
|
||||
|
||||
// run entry script in entry point
|
||||
if (entryPoint.isNotBlank()) {
|
||||
if (!loadScriptMod) {
|
||||
throw ScriptModDisallowedException()
|
||||
}
|
||||
|
||||
|
||||
var newClass: Class<*>? = null
|
||||
try {
|
||||
// for modules that has JAR defined
|
||||
@@ -316,6 +338,14 @@ object ModMgr {
|
||||
moduleInfo.remove(moduleName)
|
||||
if (module != null) moduleInfoErrored[moduleName] = module
|
||||
}
|
||||
catch (noScriptModule: ScriptModDisallowedException) {
|
||||
printmsgerr(this, noScriptModule.message)
|
||||
|
||||
logError(LoadErrorType.MY_FAULT, moduleName, noScriptModule)
|
||||
|
||||
moduleInfo.remove(moduleName)
|
||||
if (module != null) moduleInfoErrored[moduleName] = module
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// TODO: Instead of skipping module with error, just display the error message onto the face?
|
||||
|
||||
@@ -339,6 +369,8 @@ object ModMgr {
|
||||
private class ModuleDependencyNotSatisfied(want: String, have: String) :
|
||||
RuntimeException("Required: $want, Installed: $have")
|
||||
|
||||
private class ScriptModDisallowedException : RuntimeException("Script Mods disabled")
|
||||
|
||||
operator fun invoke() { }
|
||||
|
||||
/*fun reloadModules() {
|
||||
@@ -475,7 +507,7 @@ object ModMgr {
|
||||
}
|
||||
|
||||
fun getLoadOrderTextForSavegame(): String {
|
||||
return loadOrder.map { "$it ${moduleInfo[it]!!.version}" }.joinToString("\n")
|
||||
return loadOrder.filter { moduleInfo[it] != null }.map { "$it ${moduleInfo[it]!!.version}" }.joinToString("\n")
|
||||
}
|
||||
|
||||
|
||||
@@ -491,6 +523,34 @@ object ModMgr {
|
||||
}
|
||||
}
|
||||
|
||||
object GameOreLoader {
|
||||
init {
|
||||
Terrarum.oreCodex = OreCodex()
|
||||
}
|
||||
|
||||
@JvmStatic operator fun invoke(module: String) {
|
||||
// register ore codex
|
||||
Terrarum.oreCodex.fromModule(module, "ores/ores.csv")
|
||||
|
||||
// register to worldgen
|
||||
try {
|
||||
CSVFetcher.readFromModule(module, "ores/worldgen.csv").forEach { rec ->
|
||||
val tile = "ores@$module:${rec.get("id")}"
|
||||
val freq = rec.get("freq").toDouble()
|
||||
val power = rec.get("power").toDouble()
|
||||
val scale = rec.get("scale").toDouble()
|
||||
val ratio = rec.get("ratio").toDouble()
|
||||
val tiling = rec.get("tiling")
|
||||
|
||||
Worldgen.registerOre(OregenParams(tile, freq, power, scale, ratio, tiling))
|
||||
}
|
||||
}
|
||||
catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object GameItemLoader {
|
||||
const val itemPath = "items/"
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.ui.ControlPanelCommon
|
||||
import net.torvald.terrarum.modulebasegame.ui.ControlPanelOptions
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UIItemTextSelector
|
||||
import net.torvald.unicode.TIMES
|
||||
|
||||
class ModOptionsHost(val remoCon: UIRemoCon) : UICanvas() {
|
||||
init {
|
||||
@@ -14,13 +22,80 @@ class ModOptionsHost(val remoCon: UIRemoCon) : UICanvas() {
|
||||
private val moduleAreaHMargin = 48
|
||||
private val moduleAreaBorder = 8
|
||||
|
||||
override var width = App.scr.width - UIRemoCon.remoConWidth - moduleAreaHMargin
|
||||
override var width = 560
|
||||
override var height = App.scr.height - moduleAreaHMargin * 2
|
||||
|
||||
private val drawX = (Toolkit.drawWidth - width) / 2
|
||||
private val drawY = (App.scr.height - height) / 2
|
||||
|
||||
private var currentlySelectedModule = "basegame"
|
||||
|
||||
// List<Pair<proper name, mod key>>
|
||||
val configurableMods = ModMgr.moduleInfo.filter { it.value.configPlan.isNotEmpty() }.map { it.value.properName to it.key }.toList().sortedBy { it.second }
|
||||
|
||||
private val modSelectorWidth = 360
|
||||
private val modSelector = UIItemTextSelector(this, drawX + (width - modSelectorWidth) / 2, drawY,
|
||||
configurableMods.map { { it.first } }, 0, modSelectorWidth, false
|
||||
).also { item ->
|
||||
item.selectionChangeListener = {
|
||||
currentlySelectedModule = configurableMods[it].second
|
||||
|
||||
defer {
|
||||
uiItems.clear()
|
||||
makeConfig(currentlySelectedModule)
|
||||
addUIitem(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
printdbg(this, "configurableMods = ${configurableMods.map { it.second }}")
|
||||
|
||||
addUIitem(modSelector)
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
super.show()
|
||||
|
||||
makeConfig(currentlySelectedModule)
|
||||
}
|
||||
|
||||
private var deferred = {}
|
||||
private fun defer(what: () -> Unit) {
|
||||
deferred = what
|
||||
}
|
||||
|
||||
|
||||
private fun makeConfig(modname: String) {
|
||||
val mod = ModMgr.moduleInfo[modname]!!
|
||||
if (mod.configPlan.isEmpty()) return
|
||||
|
||||
val modOptions: ControlPanelOptions = mod.configPlan.map {
|
||||
val options = it.split("->")
|
||||
val labelfun = if (options[1].startsWith("Lang:")) {
|
||||
{ Lang[options[1].substringAfter(":")] }
|
||||
}
|
||||
else {
|
||||
{ options[1] }
|
||||
}
|
||||
if (options[0].isBlank())
|
||||
arrayOf("", labelfun, options[2])
|
||||
else
|
||||
arrayOf("$modname:${options[0]}", labelfun, options[2])
|
||||
}.toTypedArray()
|
||||
|
||||
ControlPanelCommon.register(this, width, "basegame.modcontrolpanel.$modname", modOptions)
|
||||
}
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
uiItems.forEach { it.update(delta) }
|
||||
deferred(); deferred = {}
|
||||
}
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: OrthographicCamera) {
|
||||
// the actual control panel
|
||||
ControlPanelCommon.render("basegame.modcontrolpanel.$currentlySelectedModule", width, batch)
|
||||
uiItems.forEach { it.render(batch, camera) }
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
|
||||
19
src/net/torvald/terrarum/MusicGovernor.kt
Normal file
19
src/net/torvald/terrarum/MusicGovernor.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
open class MusicGovernor {
|
||||
|
||||
open fun update(ingameInstance: IngameInstance, delta: Float) {
|
||||
|
||||
}
|
||||
|
||||
protected var state = 0 // 0: disabled, 1: playing, 2: waiting
|
||||
protected var intermissionAkku = 0f
|
||||
protected var intermissionLength = 1f
|
||||
protected var musicFired = false
|
||||
|
||||
|
||||
open fun dispose() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,6 +58,8 @@ class NoModuleDefaultTitlescreen(batch: FlippingSpriteBatch) : IngameInstance(ba
|
||||
}
|
||||
|
||||
override fun render(updateRate: Float) {
|
||||
super.render(updateRate)
|
||||
|
||||
gdxClearAndEnableBlend(0f, 0f, 0f, 0f)
|
||||
|
||||
if (!init) {
|
||||
|
||||
@@ -79,7 +79,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
|
||||
|
||||
|
||||
gdxClearAndEnableBlend(.094f, .094f, .094f, 0f)
|
||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
||||
|
||||
textFbo.inAction(null, null) {
|
||||
gdxClearAndEnableBlend(0f, 0f, 0f, 0f)
|
||||
@@ -127,9 +127,9 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
// draw colour overlay, flipped
|
||||
it.draw(textOverlayTex,
|
||||
(textFbo.width - textWidth) / 2f,
|
||||
App.fontGame.lineHeight,
|
||||
0f,
|
||||
textWidth,
|
||||
-App.fontGame.lineHeight
|
||||
App.fontGame.lineHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
// --> original text
|
||||
if (genuineSonic) {
|
||||
it.color = Color.WHITE
|
||||
it.draw(textTex, textX, glideDispY - 2f)
|
||||
it.draw(textTex, textX, glideDispY - 2f + textTex.height, textTex.width.toFloat(), -textTex.height.toFloat())
|
||||
}
|
||||
|
||||
// --> ghost
|
||||
@@ -167,9 +167,9 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
val drawHeight = getPulseEffWidthMul() * textTex.height
|
||||
it.draw(textTex,
|
||||
textX - (drawWidth - textTex.width) / 2f,
|
||||
glideDispY - 2f - (drawHeight - textTex.height) / 2f,
|
||||
glideDispY - 2f - (drawHeight - textTex.height) / 2f + drawHeight,
|
||||
drawWidth,
|
||||
drawHeight
|
||||
-drawHeight
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class SavegameCollection(files0: List<DiskSkimmer>, prefiltered: Boolean) {
|
||||
val manualSaves = files.filter { !it.diskFile.extension.matches(Regex("[a-z]")) }
|
||||
|
||||
init {
|
||||
printdbg(this, "Rebuilding skimmers (${files.size})")
|
||||
// printdbg(this, "Rebuilding skimmers (${files.size})")
|
||||
// files.forEach { it.rebuild() }
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ import net.torvald.terrarum.App.*
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.blockproperties.FluidCodex
|
||||
import net.torvald.terrarum.blockproperties.OreCodex
|
||||
import net.torvald.terrarum.blockproperties.WireCodex
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorID
|
||||
@@ -76,6 +78,8 @@ object Terrarum : Disposable {
|
||||
var factionCodex = FactionCodex(); internal set
|
||||
var craftingCodex = CraftingCodex(); internal set
|
||||
var apocryphas = HashMap<String, Any>(); internal set
|
||||
var fluidCodex = FluidCodex(); internal set
|
||||
var oreCodex = OreCodex(); internal set
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
@@ -258,6 +262,8 @@ object Terrarum : Disposable {
|
||||
get() = 1.0 / Gdx.graphics.deltaTime
|
||||
val mouseDown: Boolean
|
||||
get() = Gdx.input.isButtonPressed(App.getConfigInt("config_mouseprimary"))
|
||||
val mouseJustDown: Boolean
|
||||
get() = Gdx.input.isButtonJustPressed(App.getConfigInt("config_mouseprimary"))
|
||||
|
||||
|
||||
/**
|
||||
@@ -761,6 +767,10 @@ val CraftingRecipeCodex: CraftingCodex
|
||||
get() = Terrarum.craftingCodex
|
||||
val Apocryphas: HashMap<String, Any>
|
||||
get() = Terrarum.apocryphas
|
||||
val FluidCodex: FluidCodex
|
||||
get() = Terrarum.fluidCodex
|
||||
val OreCodex: OreCodex
|
||||
get() = Terrarum.oreCodex
|
||||
|
||||
class Codex : KVHashMap() {
|
||||
|
||||
@@ -784,7 +794,7 @@ fun AppUpdateListOfSavegames() {
|
||||
|
||||
|
||||
// create list of worlds
|
||||
printdbg("ListSavegames", "Listing saved worlds...")
|
||||
// printdbg("ListSavegames", "Listing saved worlds...")
|
||||
val worldsDirLs = File(worldsDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.mapNotNull { file ->
|
||||
try {
|
||||
DiskSkimmer(file, true)
|
||||
@@ -810,16 +820,16 @@ fun AppUpdateListOfSavegames() {
|
||||
}
|
||||
filteringResults.forEachIndexed { index, list ->
|
||||
val it = list.first()
|
||||
printdbg("ListSavegames", " ${index+1}.\t${it.diskFile.absolutePath}")
|
||||
// printdbg("ListSavegames", " ${index+1}.\t${it.diskFile.absolutePath}")
|
||||
|
||||
printdbg("ListSavegames", " collecting...")
|
||||
// printdbg("ListSavegames", " collecting...")
|
||||
val collection = SavegameCollection.collectFromBaseFilename(list, it.diskFile.name)
|
||||
printdbg("ListSavegames", " disk rebuilding...")
|
||||
// printdbg("ListSavegames", " disk rebuilding...")
|
||||
collection.rebuildLoadable()
|
||||
printdbg("ListSavegames", " get UUID...")
|
||||
// printdbg("ListSavegames", " get UUID...")
|
||||
val worldUUID = collection.getUUID()
|
||||
|
||||
printdbg("ListSavegames", " registration...")
|
||||
// printdbg("ListSavegames", " registration...")
|
||||
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
||||
if (!App.savegameWorlds.contains(worldUUID)) {
|
||||
App.savegameWorlds[worldUUID] = collection
|
||||
@@ -830,7 +840,7 @@ fun AppUpdateListOfSavegames() {
|
||||
|
||||
|
||||
// create list of players
|
||||
printdbg("ListSavegames", "Listing saved players...")
|
||||
// printdbg("ListSavegames", "Listing saved players...")
|
||||
val playersDirLs = File(playersDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.mapNotNull { file ->
|
||||
try {
|
||||
DiskSkimmer(file, true)
|
||||
@@ -856,16 +866,16 @@ fun AppUpdateListOfSavegames() {
|
||||
}
|
||||
filteringResults2.forEachIndexed { index, list ->
|
||||
val it = list.first()
|
||||
printdbg("ListSavegames", " ${index+1}.\t${it.diskFile.absolutePath}")
|
||||
// printdbg("ListSavegames", " ${index+1}.\t${it.diskFile.absolutePath}")
|
||||
|
||||
printdbg("ListSavegames", " collecting...")
|
||||
// printdbg("ListSavegames", " collecting...")
|
||||
val collection = SavegameCollection.collectFromBaseFilename(list, it.diskFile.name)
|
||||
printdbg("ListSavegames", " disk rebuilding...")
|
||||
// printdbg("ListSavegames", " disk rebuilding...")
|
||||
collection.rebuildLoadable()
|
||||
printdbg("ListSavegames", " get UUID...")
|
||||
// printdbg("ListSavegames", " get UUID...")
|
||||
val playerUUID = collection.getUUID()
|
||||
|
||||
printdbg("ListSavegames", " registration...")
|
||||
// printdbg("ListSavegames", " registration...")
|
||||
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
||||
if (!App.savegamePlayers.contains(playerUUID)) {
|
||||
App.savegamePlayers[playerUUID] = collection
|
||||
|
||||
@@ -64,11 +64,11 @@ basegame
|
||||
* e.g. 0x02010034 will be translated as 2.1.52
|
||||
*
|
||||
*/
|
||||
const val VERSION_RAW: Long = 0x0000_000003_000003
|
||||
const val VERSION_RAW: Long = 0x0000_000004_000000
|
||||
// Commit counts up to the Release 0.3.0: 2259
|
||||
// Commit counts up to the Release 0.3.1: 2278
|
||||
// Commit counts up to the Release 0.3.2: 2732
|
||||
// Commit counts up to the Release 0.3.3: ????
|
||||
// Commit counts up to the Release 0.3.3: 3020
|
||||
|
||||
val VERSION_SNAPSHOT = if (App.IS_DEVELOPMENT_BUILD) Snapshot(0) else null
|
||||
|
||||
@@ -100,6 +100,9 @@ data class Snapshot(var revision: Int) {
|
||||
}
|
||||
|
||||
init {
|
||||
if (revision !in 0..7) {
|
||||
throw IllegalArgumentException("Revision out of range -- expected 0..7 (a..h), got $revision")
|
||||
}
|
||||
update()
|
||||
}
|
||||
|
||||
@@ -112,4 +115,8 @@ data class Snapshot(var revision: Int) {
|
||||
revision = (b[0].toUint() ushr 7 shl 2) or b[1].toUint().and(3)
|
||||
update()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return year.shl(24) or week.shl(16) or revision
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,7 @@ object TerrarumPostProcessor : Disposable {
|
||||
outFBO.inAction(camera, batch) {
|
||||
App.measureDebugTime("Renderer.PostProcessor") {
|
||||
|
||||
gdxClearAndEnableBlend(.094f, .094f, .094f, 0f)
|
||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
||||
|
||||
fbo.colorBufferTexture.setFilter(
|
||||
Texture.TextureFilter.Linear,
|
||||
|
||||
@@ -4,8 +4,7 @@ import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.ReferencingRanges.PREFIX_VIRTUALTILE
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameworld.FluidType
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.gameitems.isWall
|
||||
import net.torvald.terrarum.utils.CSVFetcher
|
||||
import net.torvald.util.SortedArrayList
|
||||
import org.apache.commons.csv.CSVRecord
|
||||
@@ -65,7 +64,7 @@ class BlockCodex {
|
||||
}
|
||||
|
||||
fun fromCSV(module: String, csvString: String) {
|
||||
printdbg(this, "Building wire properties table for module $module")
|
||||
printdbg(this, "Building block properties table for module $module")
|
||||
|
||||
val csvParser = org.apache.commons.csv.CSVParser.parse(
|
||||
csvString,
|
||||
@@ -146,7 +145,7 @@ class BlockCodex {
|
||||
}
|
||||
|
||||
try {
|
||||
return if (blockID.startsWith("wall@"))
|
||||
return if (blockID.isWall())
|
||||
blockProps[blockID.substring(5)]!!
|
||||
else
|
||||
blockProps[blockID]!!
|
||||
@@ -156,10 +155,10 @@ class BlockCodex {
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(fluidType: FluidType?): BlockProp {
|
||||
/*operator fun get(fluidType: FluidType?): BlockProp {
|
||||
// TODO fluid from other mods
|
||||
|
||||
if (fluidType == null || fluidType.value == 0) {
|
||||
if (fluidType == null || fluidType == Fluid.NULL) {
|
||||
return blockProps[Block.AIR]!!
|
||||
}
|
||||
|
||||
@@ -169,7 +168,7 @@ class BlockCodex {
|
||||
catch (e: NullPointerException) {
|
||||
throw NullPointerException("Blockprop with id $fluidType does not exist.")
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
fun getOrNull(blockID: ItemID?): BlockProp? {//<O>
|
||||
return blockProps[blockID]
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import net.torvald.terrarum.gameworld.FluidType
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-08-06.
|
||||
*/
|
||||
object Fluid {
|
||||
|
||||
val NULL = FluidType(0)
|
||||
|
||||
val WATER = FluidType(1)
|
||||
val STATIC_WATER = FluidType(-1)
|
||||
|
||||
val LAVA = FluidType(2)
|
||||
val STATIC_LAVA = FluidType(-2)
|
||||
val NULL = "fluid@basegame:0"
|
||||
val WATER = "fluid@basegame:1"
|
||||
val LAVA = "fluid@basegame:2"
|
||||
|
||||
|
||||
val fluidRange = 1..2 // TODO MANUAL UPDATE
|
||||
}
|
||||
41
src/net/torvald/terrarum/blockproperties/FluidCodex.kt
Normal file
41
src/net/torvald/terrarum/blockproperties/FluidCodex.kt
Normal file
@@ -0,0 +1,41 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-09.
|
||||
*/
|
||||
class FluidCodex {
|
||||
|
||||
@Transient val blockProps = HashMap<ItemID, FluidProp>()
|
||||
|
||||
@Transient private val nullProp = FluidProp()
|
||||
|
||||
|
||||
operator fun get(fluidID: ItemID?): FluidProp {
|
||||
if (fluidID == null || fluidID == Fluid.NULL) {
|
||||
return nullProp
|
||||
}
|
||||
|
||||
try {
|
||||
return if (fluidID.startsWith("fluid@"))
|
||||
blockProps[fluidID.substring(6)]!!
|
||||
else
|
||||
blockProps[fluidID]!!
|
||||
}
|
||||
catch (e: NullPointerException) {
|
||||
throw NullPointerException("Fluidprop with id $fluidID does not exist.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
class FluidProp {
|
||||
val opacity: Cvec = Cvec()
|
||||
val lumCol: Cvec = Cvec()
|
||||
var id: ItemID = ""
|
||||
var nameKey: String = ""
|
||||
}
|
||||
84
src/net/torvald/terrarum/blockproperties/OreCodex.kt
Normal file
84
src/net/torvald/terrarum/blockproperties/OreCodex.kt
Normal file
@@ -0,0 +1,84 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.utils.CSVFetcher
|
||||
import org.apache.commons.csv.CSVRecord
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-11.
|
||||
*/
|
||||
class OreCodex {
|
||||
|
||||
@Transient val oreProps = HashMap<ItemID, OreProp>()
|
||||
@Transient private val nullProp = OreProp()
|
||||
|
||||
internal constructor()
|
||||
|
||||
/**
|
||||
* Later entry (possible from other modules) will replace older ones
|
||||
*/
|
||||
fun fromModule(module: String, path: String) {
|
||||
App.printdbg(this, "Building ore properties table")
|
||||
try {
|
||||
register(module, CSVFetcher.readFromModule(module, path))
|
||||
}
|
||||
catch (e: IOException) { e.printStackTrace() }
|
||||
}
|
||||
|
||||
fun fromCSV(module: String, csvString: String) {
|
||||
App.printdbg(this, "Building ore properties table for module $module")
|
||||
|
||||
val csvParser = org.apache.commons.csv.CSVParser.parse(
|
||||
csvString,
|
||||
CSVFetcher.terrarumCSVFormat
|
||||
)
|
||||
val csvRecordList = csvParser.records
|
||||
csvParser.close()
|
||||
|
||||
register(module, csvRecordList)
|
||||
}
|
||||
|
||||
private fun register(module: String, records: List<CSVRecord>) {
|
||||
records.forEach {
|
||||
setProp(module, it.intVal("id"), it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setProp(modname: String, key: Int, record: CSVRecord) {
|
||||
val prop = OreProp()
|
||||
prop.id = "ores@$modname:$key"
|
||||
prop.tags = record.get("tags").split(',').map { it.trim() }.toHashSet()
|
||||
prop.item = record.get("item").let { if (it == null) "" else if (it.contains(':')) it else "$modname:$it" }
|
||||
|
||||
oreProps[prop.id] = prop
|
||||
|
||||
App.printdbg(this, "Setting prop ${prop.id}")
|
||||
}
|
||||
|
||||
fun getAll() = oreProps.values
|
||||
|
||||
operator fun get(oreID: ItemID?): OreProp {
|
||||
if (oreID == null || oreID == Block.NULL) {
|
||||
return nullProp
|
||||
}
|
||||
|
||||
try {
|
||||
return oreProps[oreID]!!
|
||||
}
|
||||
catch (e: NullPointerException) {
|
||||
throw NullPointerException("Oreprop with id $oreID does not exist.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class OreProp {
|
||||
var id: String = ""
|
||||
var item: ItemID = ""
|
||||
var tags = HashSet<String>()
|
||||
|
||||
fun hasTag(s: String) = tags.contains(s)
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIM
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryMinimap.Companion.MINIMAP_WIDTH
|
||||
import net.torvald.terrarum.sqr
|
||||
import net.torvald.terrarum.toInt
|
||||
import net.torvald.terrarum.worlddrawer.CreateTileAtlas.Companion.WALL_OVERLAY_COLOUR
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.math.absoluteValue
|
||||
@@ -150,7 +151,7 @@ object MinimapComposer : Disposable {
|
||||
val tileTerr = world.getTileFromTerrain(x, y)
|
||||
val wallTerr = world.getTileFromWall(x, y)
|
||||
val colTerr = App.tileMaker.terrainTileColourMap.get(tileTerr)!!.toGdxColor()
|
||||
val colWall = App.tileMaker.terrainTileColourMap.get(wallTerr)!!.toGdxColor().mul(App.tileMaker.wallOverlayColour)
|
||||
val colWall = App.tileMaker.terrainTileColourMap.get(wallTerr)!!.toGdxColor().mul(WALL_OVERLAY_COLOUR)
|
||||
|
||||
var outCol = if (y < 0)
|
||||
oobColTop
|
||||
|
||||
@@ -33,14 +33,14 @@ internal object Authenticator : ConsoleCommand {
|
||||
val pwd = args[1]
|
||||
val hashedPwd = DigestUtils.sha256Hex(pwd)
|
||||
|
||||
println("auth passwd: '$pwd'")
|
||||
println("hash: $hashedPwd")
|
||||
// println("auth passwd: '$pwd'")
|
||||
// println("hash: $hashedPwd")
|
||||
|
||||
if ("2d962f949f55906ac47f16095ded190c9e44d95920259b8f36c2e54bd75df173".equals(hashedPwd, ignoreCase = true)) {
|
||||
if ("c40232ae7b8020da3ab1449a015e7cc23f249a790856b63b1b69c6a5de019fed".equals(hashedPwd, ignoreCase = true)) {
|
||||
// beedle
|
||||
val msg = if (a) "Locked" else "Authenticated"
|
||||
Echo(msg)
|
||||
println("[Authenticator] " + msg)
|
||||
println("[Authenticator] $msg")
|
||||
a = !a
|
||||
INGAME.consoleHandler.reset()
|
||||
}
|
||||
|
||||
@@ -158,4 +158,11 @@ object AVKey {
|
||||
* This value is only used for IngamePlayers
|
||||
*/
|
||||
const val GAMEMODE = "gamemode"
|
||||
|
||||
/** String
|
||||
* Comma-separated ItemIDs for the item the ore drops (`item@basegame:128` instead of `ores@basegame:1`)
|
||||
*
|
||||
* When the player gets the ore item, its itemID is appended to this actorvalue.
|
||||
*/
|
||||
const val ORE_DICT = "oredict"
|
||||
}
|
||||
@@ -15,20 +15,20 @@ import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockProp
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameparticles.createRandomBlockParticle
|
||||
import net.torvald.terrarum.gameworld.BlockAddress
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.worlddrawer.CreateTileAtlas
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.*
|
||||
|
||||
|
||||
/**
|
||||
@@ -564,17 +564,36 @@ open class ActorWithBody : Actor {
|
||||
// Codes that (SHOULD) displaces hitbox directly //
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
val vecSum = (externalV + (controllerV ?: Vector2(0.0, 0.0)))
|
||||
/**
|
||||
* solveCollision()?
|
||||
* If and only if:
|
||||
* This body is NON-STATIC and the other body is STATIC
|
||||
*/
|
||||
if (!isNoCollideWorld) {
|
||||
displaceHitbox()
|
||||
val (collisionStatus, collisionDamage) = displaceHitbox()
|
||||
|
||||
|
||||
if (collisionStatus != 0 && collisionDamage >= 1.0) {
|
||||
val terrainDamage = collisionDamage / 1000.0
|
||||
getWalledTiles(hitbox, collisionStatus).let {
|
||||
if (it.isNotEmpty()) {
|
||||
// printdbg(this, "Dmg to terrain: $terrainDamage, affected: ${it.size}")
|
||||
// printdbg(this, it)
|
||||
val dmgPerTile = terrainDamage / it.size
|
||||
it.forEach { (x, y) ->
|
||||
world?.inflictTerrainDamage(x, y, dmgPerTile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make dusts
|
||||
if (collisionStatus != 0)
|
||||
makeDust(collisionDamage, vecSum)
|
||||
}
|
||||
else {
|
||||
stairPenaltyCounter = 999
|
||||
val vecSum = externalV + (controllerV ?: Vector2(0.0, 0.0))
|
||||
hitbox.translate(vecSum)
|
||||
}
|
||||
|
||||
@@ -599,6 +618,9 @@ open class ActorWithBody : Actor {
|
||||
clampHitbox()
|
||||
|
||||
if (stairPenaltyCounter < 999) stairPenaltyCounter += 1
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -703,7 +725,11 @@ open class ActorWithBody : Actor {
|
||||
}
|
||||
}
|
||||
|
||||
private fun displaceHitbox() {
|
||||
/**
|
||||
* @return Collision Status, Collision damage in Newtons
|
||||
*/
|
||||
private fun displaceHitbox(): Pair<Int, Double> {
|
||||
var collisionDamage = 0.0
|
||||
val printdbg1 = false && App.IS_DEVELOPMENT_BUILD
|
||||
// // HOW IT SHOULD WORK // //
|
||||
// ////////////////////////
|
||||
@@ -1072,10 +1098,21 @@ open class ActorWithBody : Actor {
|
||||
debug1("resulting hitbox: $newHitbox")
|
||||
|
||||
|
||||
// var feetTileCount = 0
|
||||
// var feetTileStregthSum = 0
|
||||
// forEachFeetTile { it?.let {
|
||||
// feetTileCount += 1
|
||||
// feetTileStregthSum += it.strength
|
||||
// }}
|
||||
// val avrFeetTileStrength = feetTileStregthSum.toDouble() / feetTileCount
|
||||
// val adjustedTileStr = avrFeetTileStrength / 1176
|
||||
// val fallDamageDampenMult = (adjustedTileStr / (adjustedTileStr + 1)).sqr()
|
||||
val fallDamageDampenMult = (32.0 / 1176.0).sqr()
|
||||
// slam-into-whatever damage (such dirty; much hack; wow)
|
||||
// vvvv hack (supposed to be 1.0) vvv 50% hack
|
||||
val collisionDamage = mass * (vectorSum.magnitude / (10.0 / Terrarum.PHYS_TIME_FRAME).sqr()) / fallDamageDampening.sqr() * GAME_TO_SI_ACC
|
||||
collisionDamage = mass * (vectorSum.magnitude / (10.0 / Terrarum.PHYS_TIME_FRAME).sqr()) * fallDamageDampenMult * GAME_TO_SI_ACC
|
||||
// kg * m / s^2 (mass * acceleration), acceleration -> (vectorMagn / (0.01)^2).gameToSI()
|
||||
// take material softness(?) into account
|
||||
if (collisionDamage != 0.0) debug1("Collision damage: $collisionDamage N")
|
||||
// FIXME instead of 0.5mv^2, we can model after "change of velocity (aka accel)", just as in real-life; big change of accel on given unit time is what kills
|
||||
|
||||
@@ -1091,13 +1128,14 @@ open class ActorWithBody : Actor {
|
||||
|
||||
|
||||
|
||||
return
|
||||
return selfCollisionStatus to collisionDamage
|
||||
|
||||
|
||||
|
||||
// if collision not detected, just don't care; it's not your job to apply moveDelta
|
||||
|
||||
} // end of (world != null)
|
||||
return 0 to collisionDamage
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1202,6 +1240,68 @@ open class ActorWithBody : Actor {
|
||||
|
||||
}
|
||||
|
||||
private fun getWalledTiles(hitbox: Hitbox, option: Int): List<Point2i> {
|
||||
/*
|
||||
The structure:
|
||||
|
||||
####### // TOP
|
||||
=+-----+=
|
||||
=| |=
|
||||
=+-----+=
|
||||
####### // BOTTOM
|
||||
|
||||
IMPORTANT AF NOTE: things are ASYMMETRIC!
|
||||
*/
|
||||
|
||||
if (option.popcnt() == 1) {
|
||||
val (x1, x2, y1, y2) = hitbox.getWallDetection(option)
|
||||
|
||||
val txStart = x1.floorToInt().div(TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||
val txEnd = x2.floorToInt().div(TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||
val tyStart = y1.floorToInt().div(TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||
val tyEnd = y2.floorToInt().div(TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||
|
||||
return getWalledTiles0(txStart, tyStart, txEnd, tyEnd, option == COLLIDING_BOTTOM)
|
||||
}
|
||||
else if (option == 0) {
|
||||
return emptyList()
|
||||
}
|
||||
else {
|
||||
return intArrayOf(1, 2, 4, 8).flatMap {
|
||||
getWalledTiles(hitbox, option and it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWalledTiles0(pxStart: Int, pyStart: Int, pxEnd: Int, pyEnd: Int, feet: Boolean): List<Point2i> {
|
||||
val ret = ArrayList<Point2i>()
|
||||
if (world == null) return emptyList()
|
||||
val ys = pyStart..pyEnd
|
||||
val xs = pxStart..pxEnd
|
||||
val feetY = pyEnd // round down toward negative infinity // TODO reverse gravity adaptation?
|
||||
|
||||
for (ty in ys) {
|
||||
val isFeetTileHeight = (ty == feetY)
|
||||
|
||||
for (tx in xs) {
|
||||
val tile = world!!.getTileFromTerrain(tx, ty)
|
||||
|
||||
if (feet && isFeetTileHeight) {
|
||||
if (shouldICollideWithThisFeet(tile)) {
|
||||
ret.add(Point2i(tx, ty))
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (shouldICollideWithThis(tile)) {
|
||||
ret.add(Point2i(tx, ty))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// printdbg(this, "ys=$ys, xs=$xs, ret=$ret")
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* @return First int: 0 - no collision, 1 - staircasing, 2 - "bonk" to the wall; Second int: stair height
|
||||
*/
|
||||
@@ -1289,10 +1389,9 @@ open class ActorWithBody : Actor {
|
||||
(pxStart + sub)..(pxEnd - sub)
|
||||
}
|
||||
else*/
|
||||
pxStart..pxEnd
|
||||
(pxStart / TILE_SIZED).floorToInt()..(pxEnd / TILE_SIZED).floorToInt()
|
||||
|
||||
for (x in xs) {
|
||||
val tx = (x / TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||
for (tx in xs) {
|
||||
val tile = world!!.getTileFromTerrain(tx, ty)
|
||||
|
||||
if (feet && isFeetTileHeight) {
|
||||
@@ -1917,6 +2016,82 @@ open class ActorWithBody : Actor {
|
||||
return tileProps.forEach(consumer)
|
||||
}
|
||||
|
||||
fun getFeetTiles(): List<Pair<Point2i, ItemID>> {
|
||||
val y = intTilewiseHitbox.height.toInt() + 1
|
||||
return (0..intTilewiseHitbox.width.toInt()).map { x ->
|
||||
val px = x + intTilewiseHitbox.startX.toInt()
|
||||
val py = y + intTilewiseHitbox.startY.toInt()
|
||||
Point2i(px, py) to world!!.getTileFromTerrain(px, py)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeDust(collisionDamage: Double, vecSum: Vector2) {
|
||||
val particleCount = (collisionDamage / 24.0).pow(0.75)
|
||||
val trueParticleCount = particleCount.toInt() + (Math.random() < (particleCount % 1.0)).toInt()
|
||||
|
||||
if (collisionDamage > 1.0 / 1024.0) {
|
||||
// printdbg(this, "Collision damage: $collisionDamage N, count: $particleCount, velocity: $vecSum, mass: ${this.mass}")
|
||||
|
||||
val feetTiles = getFeetTiles()
|
||||
val feetTileIndices = feetTiles.indices.toList().toIntArray()
|
||||
|
||||
for (i in 0 until trueParticleCount) {
|
||||
if (i % feetTiles.size == 0) feetTileIndices.shuffle()
|
||||
|
||||
feetTiles[feetTileIndices[i % feetTiles.size]].second.let { tile ->
|
||||
val px = hitbox.startX + Math.random() * hitbox.width
|
||||
val py = hitbox.endY
|
||||
makeDust0(tile, px, py, particleCount, collisionDamage, vecSum)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val pixelOffs = intArrayOf(2, 7, 12) // hard-coded assuming TILE_SIZE=16
|
||||
|
||||
/**
|
||||
* @param wx World-X position
|
||||
*/
|
||||
private fun makeDust0(tile: ItemID, wx: Double, wy: Double, count: Double, fallDamage: Double, vecSum: Vector2) {
|
||||
val pw = 3
|
||||
val ph = 3
|
||||
|
||||
val renderTag = App.tileMaker.getRenderTag(tile)
|
||||
val baseTilenum = renderTag.tileNumber
|
||||
val representativeTilenum = when (renderTag.maskType) {
|
||||
CreateTileAtlas.RenderTag.MASK_47 -> 17
|
||||
CreateTileAtlas.RenderTag.MASK_PLATFORM -> 7
|
||||
else -> 0
|
||||
}
|
||||
val tileNum = baseTilenum + representativeTilenum // the particle won't match the visible tile anyway because of the seasons stuff
|
||||
|
||||
val vi = if (vecSum.y > PHYS_EPSILON_VELO) 0 else if (vecSum.y < -PHYS_EPSILON_VELO) 2 else (Math.random() * 3).toInt()
|
||||
val u = (wx.toInt() % TILE_SIZE).coerceIn(0..TILE_SIZE - pw)
|
||||
val v = pixelOffs[vi]
|
||||
val pos = Vector2(
|
||||
wx,
|
||||
wy,
|
||||
)
|
||||
val veloXvar = (Math.random() + Math.random()) * (if (Math.random() < 0.5) -1 else 1) * 0.5 // avr at 0.5
|
||||
val veloYvar = brownianRand()
|
||||
val veloMult = Vector2(
|
||||
vecSum.x * 0.8 + veloXvar,
|
||||
(count.pow(0.5) + veloYvar) * vecSum.y.sign
|
||||
)
|
||||
createRandomBlockParticle(tileNum, pos, veloMult, u, v, pw, ph).let {
|
||||
it.despawnUponCollision = true
|
||||
it.drawColour.set(Color.WHITE)
|
||||
(Terrarum.ingame as TerrarumIngame).addParticle(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return random number between 0-1, of which 0 is the most likely and 1 is the least
|
||||
*/
|
||||
private fun brownianRand(): Double {
|
||||
return Math.abs(Math.random() + Math.random() - 1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -198,6 +198,8 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
).let { drop ->
|
||||
INGAME.queueActorAddition(drop)
|
||||
}
|
||||
// apply item effect
|
||||
ItemCodex[item]!!.effectOnThrow(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ object InputStrober {
|
||||
val keymap = IME.getLowLayerByName(App.getConfigString("basekeyboardlayout"))
|
||||
|
||||
if (stroboStatus % 2 == 0 && keybuf[0] != 0) {
|
||||
// println("Key strobed: ${keybuf.joinToString()}; ${oldKeys.joinToString()}; changed = $keyChanged")
|
||||
// println("Key strobed: ${keybuf.joinToString()}; old: ${oldKeys.joinToString()}; changed = $keyChanged")
|
||||
|
||||
stroboStatus += 1
|
||||
stroboTime = System.nanoTime()
|
||||
@@ -82,11 +82,11 @@ object InputStrober {
|
||||
val headKeyCode = if (keyDiff.size < 1) keybuf[0] else keyDiff[0]
|
||||
|
||||
if (!keyChanged) {
|
||||
// println("KEY_DOWN '$keysym' ($headKeyCode) $repeatCount; ${keys.joinToString()}")
|
||||
// println("KEY_DOWN '$keysym' ($headKeyCode) $repeatCount")
|
||||
App.inputStrobed(TerrarumKeyboardEvent(KEY_DOWN, keysym, headKeyCode, repeatCount, keybuf))
|
||||
}
|
||||
else if (newKeysym != null) {
|
||||
// println("KEY_DOWC '$newKeysym' ($headKeyCode) $repeatCount; ${keys.joinToString()}")
|
||||
// println("KEY_DOWC '$newKeysym' ($headKeyCode) $repeatCount")
|
||||
App.inputStrobed(TerrarumKeyboardEvent(KEY_DOWN, newKeysym, headKeyCode, repeatCount, keybuf))
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
/**
|
||||
* Effects applied immediately only once when picked up
|
||||
*/
|
||||
open fun effectOnPickup(actor: ActorWithBody, delta: Float) { }
|
||||
open fun effectOnPickup(actor: ActorWithBody) { }
|
||||
|
||||
/**
|
||||
* Apply effects (continuously or not) while primary button is down.
|
||||
@@ -249,7 +249,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
/**
|
||||
* Effects applied immediately only once when thrown (discarded) from pocket
|
||||
*/
|
||||
open fun effectOnThrow(actor: ActorWithBody, delta: Float) { }
|
||||
open fun effectOnThrow(actor: ActorWithBody) { }
|
||||
|
||||
/**
|
||||
* Effects applied (continuously or not) while being equipped (drawn/pulled out)
|
||||
@@ -259,7 +259,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
/**
|
||||
* Effects applied only once when unequipped
|
||||
*/
|
||||
open fun effectOnUnequip(actor: ActorWithBody, delta: Float) { }
|
||||
open fun effectOnUnequip(actor: ActorWithBody) { }
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -417,8 +417,10 @@ fun mouseInInteractableRangeTools(actor: ActorWithBody, item: GameItem?, reachMu
|
||||
|
||||
fun ItemID.isItem() = this.startsWith("item@")
|
||||
fun ItemID.isWire() = this.startsWith("wire@")
|
||||
fun ItemID.isDynamic() = this.startsWith("$PREFIX_DYNAMICITEM:")
|
||||
fun ItemID.isDynamic() = this.startsWith("$PREFIX_DYNAMICITEM:") // aka module name 'dyn'
|
||||
fun ItemID.isActor() = this.startsWith("$PREFIX_ACTORITEM@")
|
||||
fun ItemID.isVirtual() = this.startsWith("$PREFIX_VIRTUALTILE@")
|
||||
fun ItemID.isBlock() = !this.contains('@') && !this.isDynamic()
|
||||
fun ItemID.isWall() = this.startsWith("wall@")
|
||||
fun ItemID.isFluid() = this.startsWith("fluid@")
|
||||
fun ItemID.isOre() = this.startsWith("ores@")
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.dyn4j.geometry.Vector2
|
||||
*
|
||||
* Created by minjaesong on 2017-01-20.
|
||||
*/
|
||||
open class ParticleBase(renderOrder: Actor.RenderOrder, val despawnUponCollision: Boolean, val noCollision: Boolean = true, maxLifeTime: Second? = null) : Runnable {
|
||||
open class ParticleBase(renderOrder: Actor.RenderOrder, var despawnUponCollision: Boolean, var noCollision: Boolean = true, maxLifeTime: Second? = null) : Runnable {
|
||||
|
||||
/** Will NOT actually delete from the CircularArray */
|
||||
@Volatile var flagDespawn = false
|
||||
@@ -22,7 +22,7 @@ open class ParticleBase(renderOrder: Actor.RenderOrder, val despawnUponCollision
|
||||
override fun run() = update(App.UPDATE_RATE)
|
||||
|
||||
var isNoSubjectToGrav = false
|
||||
var dragCoefficient = 3.0
|
||||
var dragCoefficient = 40.0
|
||||
|
||||
val lifetimeMax = maxLifeTime ?: 5f
|
||||
var lifetimeCounter = 0f
|
||||
@@ -55,8 +55,8 @@ open class ParticleBase(renderOrder: Actor.RenderOrder, val despawnUponCollision
|
||||
)].isSolid) {
|
||||
|
||||
|
||||
if (despawnUponCollision) flagDespawn = true
|
||||
if (!noCollision) velocity.y = 0.0
|
||||
if (despawnUponCollision && lifetimeCounter >= 0.1f) flagDespawn = true
|
||||
if (!noCollision && lifetimeCounter >= 0.1f) velocity.y = 0.0
|
||||
}
|
||||
|
||||
if (lifetimeCounter >= lifetimeMax) {
|
||||
|
||||
@@ -2,12 +2,20 @@ package net.torvald.terrarum.gameparticles
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.drawBodyInGoodPosition
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.imagefont.TinyAlphNum
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import net.torvald.terrarum.worlddrawer.CreateTileAtlas.RenderTag
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.dyn4j.geometry.Vector2
|
||||
|
||||
/**
|
||||
* The texture must be manually discarded.
|
||||
*
|
||||
* @param tex image
|
||||
* @param x x-coord of the particle's initial spawn position, bottom-centre
|
||||
* @param y y-coord of the particle's initial spawn position, bottom-centre
|
||||
@@ -29,6 +37,31 @@ open class ParticleVanishingTexture(val tex: TextureRegion, x: Double, y: Double
|
||||
|
||||
drawColour.a = (lifetimeMax - lifetimeCounter) / lifetimeMax
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// pickaxe sparks must use different create- function
|
||||
fun createRandomBlockParticle(tileNum: Int, position: Vector2, velocityMult: Vector2, tx: Int, ty: Int, tw: Int, th: Int): ParticleBase {
|
||||
val velocity = Vector2(
|
||||
(Math.random() + Math.random()) * velocityMult.x,
|
||||
-velocityMult.y
|
||||
) // triangular distribution with mean of 1.0 * velocityMult
|
||||
|
||||
val atlasX = tileNum % BlocksDrawer.weatherTerrains[1].horizontalCount
|
||||
val atlasY = tileNum / BlocksDrawer.weatherTerrains[1].horizontalCount
|
||||
// take base texture
|
||||
val texBody = BlocksDrawer.weatherTerrains[1].get(atlasX, atlasY)
|
||||
val texGlow = BlocksDrawer.tilesGlow.get(atlasX, atlasY)
|
||||
|
||||
// take random square part
|
||||
val texRegionBody = TextureRegion(texBody.texture, texBody.regionX + tx, texBody.regionY + ty, tw, th)
|
||||
val texRegionGlow = TextureRegion(texGlow.texture, texGlow.regionX + tx, texGlow.regionY + ty, tw, th)
|
||||
|
||||
return ParticleVanishingTexture(texRegionBody, position.x, position.y).also {
|
||||
it.glow = texRegionGlow
|
||||
it.velocity.set(velocity)
|
||||
it.isNoSubjectToGrav = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,110 +1,15 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
|
||||
/**
|
||||
* Memory layout:
|
||||
* ```
|
||||
* a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 ||
|
||||
* ```
|
||||
* where a_n is a tile number
|
||||
*
|
||||
* Original version Created by minjaesong on 2016-01-17.
|
||||
* Unsafe version Created by minjaesong on 2019-06-08.
|
||||
*
|
||||
* Note to self: refrain from using shorts--just do away with two bytes: different system have different endianness
|
||||
* Created by minjaesong on 2023-10-10.
|
||||
*/
|
||||
open class BlockLayer(val width: Int, val height: Int) : Disposable {
|
||||
// for some reason, all the efforts of saving the memory space were futile.
|
||||
interface BlockLayer : Disposable {
|
||||
|
||||
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
|
||||
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * BYTES_PER_BLOCK)
|
||||
val bytesPerBlock: Long
|
||||
fun unsafeToBytes(x: Int, y: Int): ByteArray
|
||||
fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray)
|
||||
fun unsafeGetTile(x: Int, y: Int): Int
|
||||
|
||||
val ptrDestroyed: Boolean
|
||||
get() = ptr.destroyed
|
||||
|
||||
init {
|
||||
ptr.fillWith(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data Byte array representation of the layer
|
||||
*/
|
||||
constructor(width: Int, height: Int, data: ByteArray) : this(width, height) {
|
||||
TODO()
|
||||
data.forEachIndexed { index, byte -> UnsafeHelper.unsafe.putByte(ptr.ptr + index, byte) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over stored bytes.
|
||||
*
|
||||
* @return an Iterator.
|
||||
*/
|
||||
fun bytesIterator(): Iterator<Byte> {
|
||||
return object : Iterator<Byte> {
|
||||
private var iteratorCount = 0L
|
||||
override fun hasNext(): Boolean {
|
||||
return iteratorCount < width * height * BYTES_PER_BLOCK
|
||||
}
|
||||
override fun next(): Byte {
|
||||
iteratorCount += 1
|
||||
return ptr[iteratorCount - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun unsafeGetTile(x: Int, y: Int): Int {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
val lsb = ptr[offset]
|
||||
val msb = ptr[offset + 1]
|
||||
|
||||
return lsb.toUint() + msb.toUint().shl(8)
|
||||
}
|
||||
|
||||
internal fun unsafeSetTile(x: Int, y: Int, tile: Int) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
|
||||
// try {
|
||||
ptr[offset] = lsb
|
||||
ptr[offset + 1] = msb
|
||||
// }
|
||||
// catch (e: IndexOutOfBoundsException) {
|
||||
// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset")
|
||||
// throw e
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @param blockOffset Offset in blocks. BlockOffset of 0x100 is equal to ```layerPtr + 0x200```
|
||||
*/
|
||||
/*internal fun unsafeSetTile(blockOffset: Long, tile: Int) {
|
||||
val offset = BYTES_PER_BLOCK * blockOffset
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
unsafe.putByte(layerPtr + offset, lsb)
|
||||
unsafe.putByte(layerPtr + offset + 1, msb)
|
||||
}*/
|
||||
|
||||
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
|
||||
|
||||
override fun dispose() {
|
||||
ptr.destroy()
|
||||
printdbg(this, "BlockLayer with ptr ($ptr) successfully freed")
|
||||
}
|
||||
|
||||
override fun toString(): String = ptr.toString()
|
||||
|
||||
companion object {
|
||||
@Transient val BYTES_PER_BLOCK = 2L
|
||||
}
|
||||
}
|
||||
}
|
||||
123
src/net/torvald/terrarum/gameworld/BlockLayerI16.kt
Normal file
123
src/net/torvald/terrarum/gameworld/BlockLayerI16.kt
Normal file
@@ -0,0 +1,123 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
|
||||
/**
|
||||
* Memory layout:
|
||||
* ```
|
||||
* a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 ||
|
||||
* ```
|
||||
* where a_n is a tile number
|
||||
*
|
||||
* Original version Created by minjaesong on 2016-01-17.
|
||||
* Unsafe version Created by minjaesong on 2019-06-08.
|
||||
*
|
||||
* Note to self: refrain from using shorts--just do away with two bytes: different system have different endianness
|
||||
*/
|
||||
open class BlockLayerI16(val width: Int, val height: Int) : BlockLayer {
|
||||
override val bytesPerBlock = BYTES_PER_BLOCK
|
||||
|
||||
// for some reason, all the efforts of saving the memory space were futile.
|
||||
|
||||
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
|
||||
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * BYTES_PER_BLOCK)
|
||||
|
||||
val ptrDestroyed: Boolean
|
||||
get() = ptr.destroyed
|
||||
|
||||
init {
|
||||
ptr.fillWith(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data Byte array representation of the layer
|
||||
*/
|
||||
constructor(width: Int, height: Int, data: ByteArray) : this(width, height) {
|
||||
TODO()
|
||||
data.forEachIndexed { index, byte -> UnsafeHelper.unsafe.putByte(ptr.ptr + index, byte) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over stored bytes.
|
||||
*
|
||||
* @return an Iterator.
|
||||
*/
|
||||
fun bytesIterator(): Iterator<Byte> {
|
||||
return object : Iterator<Byte> {
|
||||
private var iteratorCount = 0L
|
||||
override fun hasNext(): Boolean {
|
||||
return iteratorCount < width * height * BYTES_PER_BLOCK
|
||||
}
|
||||
override fun next(): Byte {
|
||||
iteratorCount += 1
|
||||
return ptr[iteratorCount - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun unsafeGetTile(x: Int, y: Int): Int {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
val lsb = ptr[offset]
|
||||
val msb = ptr[offset + 1]
|
||||
|
||||
return lsb.toUint() + msb.toUint().shl(8)
|
||||
}
|
||||
|
||||
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
return byteArrayOf(ptr[offset + 1], ptr[offset + 0])
|
||||
}
|
||||
|
||||
internal fun unsafeSetTile(x: Int, y: Int, tile: Int) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
|
||||
// try {
|
||||
ptr[offset] = lsb
|
||||
ptr[offset + 1] = msb
|
||||
// }
|
||||
// catch (e: IndexOutOfBoundsException) {
|
||||
// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset")
|
||||
// throw e
|
||||
// }
|
||||
}
|
||||
|
||||
override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
ptr[offset] = bytes[1]
|
||||
ptr[offset + 1] = bytes[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param blockOffset Offset in blocks. BlockOffset of 0x100 is equal to ```layerPtr + 0x200```
|
||||
*/
|
||||
/*internal fun unsafeSetTile(blockOffset: Long, tile: Int) {
|
||||
val offset = BYTES_PER_BLOCK * blockOffset
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
unsafe.putByte(layerPtr + offset, lsb)
|
||||
unsafe.putByte(layerPtr + offset + 1, msb)
|
||||
}*/
|
||||
|
||||
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
|
||||
|
||||
override fun dispose() {
|
||||
ptr.destroy()
|
||||
printdbg(this, "BlockLayerI16 with ptr ($ptr) successfully freed")
|
||||
}
|
||||
|
||||
override fun toString(): String = ptr.toString("BlockLayerI16")
|
||||
|
||||
companion object {
|
||||
@Transient val BYTES_PER_BLOCK = 2L
|
||||
}
|
||||
}
|
||||
137
src/net/torvald/terrarum/gameworld/BlockLayerI16F16.kt
Normal file
137
src/net/torvald/terrarum/gameworld/BlockLayerI16F16.kt
Normal file
@@ -0,0 +1,137 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.gameworld.WorldSimulator.FLUID_MIN_MASS
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
import net.torvald.util.Float16
|
||||
|
||||
/**
|
||||
* * Memory layout:
|
||||
* * ```
|
||||
* * a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 | f7 f6 f5 f4 f3 f2 f1 f0 | fF fE fD fC fB fA f9 f8 ||
|
||||
* * ```
|
||||
* * where a_n is a fluid number, f_n is a fluid fill
|
||||
*
|
||||
* Created by minjaesong on 2023-10-10.
|
||||
*/
|
||||
class BlockLayerI16F16(val width: Int, val height: Int) : BlockLayer {
|
||||
override val bytesPerBlock = BYTES_PER_BLOCK
|
||||
|
||||
// for some reason, all the efforts of saving the memory space were futile.
|
||||
|
||||
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
|
||||
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * BYTES_PER_BLOCK)
|
||||
|
||||
val ptrDestroyed: Boolean
|
||||
get() = ptr.destroyed
|
||||
|
||||
init {
|
||||
ptr.fillWith(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data Byte array representation of the layer
|
||||
*/
|
||||
constructor(width: Int, height: Int, data: ByteArray) : this(width, height) {
|
||||
TODO()
|
||||
data.forEachIndexed { index, byte -> UnsafeHelper.unsafe.putByte(ptr.ptr + index, byte) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over stored bytes.
|
||||
*
|
||||
* @return an Iterator.
|
||||
*/
|
||||
fun bytesIterator(): Iterator<Byte> {
|
||||
return object : Iterator<Byte> {
|
||||
private var iteratorCount = 0L
|
||||
override fun hasNext(): Boolean {
|
||||
return iteratorCount < width * height * BYTES_PER_BLOCK
|
||||
}
|
||||
override fun next(): Byte {
|
||||
iteratorCount += 1
|
||||
return ptr[iteratorCount - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun unsafeGetTile(x: Int, y: Int): Int {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
val lsb = ptr[offset]
|
||||
val msb = ptr[offset + 1]
|
||||
val hbits = (ptr[offset + 2].toUint() or ptr[offset + 3].toUint().shl(8)).toShort()
|
||||
val fill = Float16.toFloat(hbits)
|
||||
|
||||
return lsb.toUint() + msb.toUint().shl(8)
|
||||
}
|
||||
|
||||
internal fun unsafeGetTile1(x: Int, y: Int): Pair<Int, Float> {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
val lsb = ptr[offset]
|
||||
val msb = ptr[offset + 1]
|
||||
val hbits = (ptr[offset + 2].toUint() or ptr[offset + 3].toUint().shl(8)).toShort()
|
||||
val fill = Float16.toFloat(hbits)
|
||||
|
||||
return lsb.toUint() + msb.toUint().shl(8) to fill
|
||||
}
|
||||
|
||||
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 3], ptr[offset + 2])
|
||||
}
|
||||
|
||||
internal fun unsafeSetTile(x: Int, y: Int, tile0: Int, fill: Float) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
val hbits = Float16.fromFloat(fill).toInt().and(0xFFFF)
|
||||
|
||||
val tile = if (fill < FLUID_MIN_MASS) 0 else tile0
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
val hlsb = hbits.and(0xff).toByte()
|
||||
val hmsb = hbits.ushr(8).and(0xff).toByte()
|
||||
|
||||
ptr[offset] = lsb
|
||||
ptr[offset + 1] = msb
|
||||
ptr[offset + 2] = hlsb
|
||||
ptr[offset + 3] = hmsb
|
||||
|
||||
}
|
||||
|
||||
override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
ptr[offset] = bytes[1]
|
||||
ptr[offset + 1] = bytes[0]
|
||||
ptr[offset + 2] = bytes[3]
|
||||
ptr[offset + 3] = bytes[2]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param blockOffset Offset in blocks. BlockOffset of 0x100 is equal to ```layerPtr + 0x200```
|
||||
*/
|
||||
/*internal fun unsafeSetTile(blockOffset: Long, tile: Int) {
|
||||
val offset = BYTES_PER_BLOCK * blockOffset
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
unsafe.putByte(layerPtr + offset, lsb)
|
||||
unsafe.putByte(layerPtr + offset + 1, msb)
|
||||
}*/
|
||||
|
||||
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
|
||||
|
||||
override fun dispose() {
|
||||
ptr.destroy()
|
||||
App.printdbg(this, "BlockLayerI16F16 with ptr ($ptr) successfully freed")
|
||||
}
|
||||
|
||||
override fun toString(): String = ptr.toString("BlockLayerI16F16")
|
||||
|
||||
companion object {
|
||||
@Transient val BYTES_PER_BLOCK = 4L
|
||||
}
|
||||
}
|
||||
140
src/net/torvald/terrarum/gameworld/BlockLayerI16I8.kt
Normal file
140
src/net/torvald/terrarum/gameworld/BlockLayerI16I8.kt
Normal file
@@ -0,0 +1,140 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
|
||||
/**
|
||||
* Memory layout:
|
||||
* ```
|
||||
* a7 a6 a5 a4 a3 a2 a1 a0 | aF aE aD aC aB aA a9 a8 | p7 p6 p5 p4 p3 p2 p1 p0 ||
|
||||
* ```
|
||||
* where a_n is a tile number, p_n is a placement index
|
||||
* Created by minjaesong on 2023-10-10.
|
||||
*/
|
||||
class BlockLayerI16I8 (val width: Int, val height: Int) : BlockLayer {
|
||||
override val bytesPerBlock = BYTES_PER_BLOCK
|
||||
|
||||
// for some reason, all the efforts of saving the memory space were futile.
|
||||
|
||||
// using unsafe pointer gets you 100 fps, whereas using directbytebuffer gets you 90
|
||||
internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * BYTES_PER_BLOCK)
|
||||
|
||||
val ptrDestroyed: Boolean
|
||||
get() = ptr.destroyed
|
||||
|
||||
init {
|
||||
ptr.fillWith(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data Byte array representation of the layer
|
||||
*/
|
||||
constructor(width: Int, height: Int, data: ByteArray) : this(width, height) {
|
||||
TODO()
|
||||
data.forEachIndexed { index, byte -> UnsafeHelper.unsafe.putByte(ptr.ptr + index, byte) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over stored bytes.
|
||||
*
|
||||
* @return an Iterator.
|
||||
*/
|
||||
fun bytesIterator(): Iterator<Byte> {
|
||||
return object : Iterator<Byte> {
|
||||
private var iteratorCount = 0L
|
||||
override fun hasNext(): Boolean {
|
||||
return iteratorCount < width * height * BYTES_PER_BLOCK
|
||||
}
|
||||
override fun next(): Byte {
|
||||
iteratorCount += 1
|
||||
return ptr[iteratorCount - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun unsafeGetTile(x: Int, y: Int): Int {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
val lsb = ptr[offset]
|
||||
val msb = ptr[offset + 1]
|
||||
val placement = ptr[offset + 2]
|
||||
|
||||
return lsb.toUint() + msb.toUint().shl(8)
|
||||
}
|
||||
|
||||
internal fun unsafeGetTile1(x: Int, y: Int): Pair<Int, Int> {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
val lsb = ptr[offset]
|
||||
val msb = ptr[offset + 1]
|
||||
val placement = ptr[offset + 2]
|
||||
|
||||
return lsb.toUint() + msb.toUint().shl(8) to placement.toUint()
|
||||
}
|
||||
|
||||
override fun unsafeToBytes(x: Int, y: Int): ByteArray {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 2])
|
||||
}
|
||||
|
||||
internal fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: Int) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
|
||||
// try {
|
||||
ptr[offset] = lsb
|
||||
ptr[offset + 1] = msb
|
||||
ptr[offset + 2] = placement.toByte()
|
||||
// }
|
||||
// catch (e: IndexOutOfBoundsException) {
|
||||
// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset")
|
||||
// throw e
|
||||
// }
|
||||
}
|
||||
|
||||
override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
ptr[offset] = bytes[1]
|
||||
ptr[offset + 1] = bytes[0]
|
||||
ptr[offset + 2] = bytes[2]
|
||||
}
|
||||
|
||||
internal fun unsafeSetTileKeepPlacement(x: Int, y: Int, tile: Int) {
|
||||
val offset = BYTES_PER_BLOCK * (y * width + x)
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
ptr[offset] = lsb
|
||||
ptr[offset + 1] = msb
|
||||
}
|
||||
|
||||
/**
|
||||
* @param blockOffset Offset in blocks. BlockOffset of 0x100 is equal to ```layerPtr + 0x200```
|
||||
*/
|
||||
/*internal fun unsafeSetTile(blockOffset: Long, tile: Int) {
|
||||
val offset = BYTES_PER_BLOCK * blockOffset
|
||||
|
||||
val lsb = tile.and(0xff).toByte()
|
||||
val msb = tile.ushr(8).and(0xff).toByte()
|
||||
|
||||
unsafe.putByte(layerPtr + offset, lsb)
|
||||
unsafe.putByte(layerPtr + offset + 1, msb)
|
||||
}*/
|
||||
|
||||
fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height)
|
||||
|
||||
override fun dispose() {
|
||||
ptr.destroy()
|
||||
App.printdbg(this, "BlockLayerI16I8 with ptr ($ptr) successfully freed")
|
||||
}
|
||||
|
||||
override fun toString(): String = ptr.toString("BlockLayerI16I8")
|
||||
|
||||
companion object {
|
||||
@Transient val BYTES_PER_BLOCK = 3L
|
||||
}
|
||||
}
|
||||
@@ -7,21 +7,20 @@ import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.Fluid
|
||||
import net.torvald.terrarum.concurrent.ThreadExecutor
|
||||
import net.torvald.terrarum.gameactors.ActorID
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameitems.isFluid
|
||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||
import net.torvald.terrarum.itemproperties.ItemTable
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.utils.*
|
||||
import net.torvald.terrarum.weather.WeatherMixer
|
||||
import net.torvald.terrarum.weather.WeatherSchedule
|
||||
import net.torvald.terrarum.weather.Weatherbox
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import net.torvald.util.SortedArrayList
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
typealias BlockAddress = Long
|
||||
|
||||
@@ -39,8 +38,8 @@ class PhysicalStatus() {
|
||||
* Special version of GameWorld where everything, including layer data, are saved in a single JSON file (i.e. not chunked)
|
||||
*/
|
||||
class SimpleGameWorld(width: Int, height: Int) : GameWorld(width, height) {
|
||||
override lateinit var layerWall: BlockLayer
|
||||
override lateinit var layerTerrain: BlockLayer
|
||||
override lateinit var layerWall: BlockLayerI16
|
||||
override lateinit var layerTerrain: BlockLayerI16
|
||||
constructor() : this(0, 0)
|
||||
}
|
||||
|
||||
@@ -82,8 +81,14 @@ open class GameWorld(
|
||||
}
|
||||
|
||||
//layers
|
||||
@Transient lateinit open var layerWall: BlockLayer
|
||||
@Transient lateinit open var layerTerrain: BlockLayer
|
||||
@Transient lateinit open var layerWall: BlockLayerI16
|
||||
@Transient lateinit open var layerTerrain: BlockLayerI16
|
||||
@Transient lateinit open var layerOres: BlockLayerI16I8 // damage to the block follows `terrainDamages`
|
||||
@Transient lateinit open var layerFluids: BlockLayerI16F16
|
||||
val wallDamages = HashArray<Float>()
|
||||
val terrainDamages = HashArray<Float>()
|
||||
|
||||
|
||||
|
||||
//val layerThermal: MapLayerHalfFloat // in Kelvins
|
||||
//val layerFluidPressure: MapLayerHalfFloat // (milibar - 1000)
|
||||
@@ -101,10 +106,7 @@ open class GameWorld(
|
||||
}
|
||||
var portalPoint: Point2i? = null
|
||||
|
||||
val wallDamages = HashArray<Float>()
|
||||
val terrainDamages = HashArray<Float>()
|
||||
val fluidTypes = HashedFluidType()
|
||||
val fluidFills = HashArray<Float>()
|
||||
|
||||
|
||||
/**
|
||||
* Single block can have multiple conduits, different types of conduits are stored separately.
|
||||
@@ -140,10 +142,27 @@ open class GameWorld(
|
||||
30L * WorldTime.MINUTE_SEC
|
||||
)
|
||||
|
||||
|
||||
val tileNumberToNameMap = HashArray<ItemID>()
|
||||
@Transient private val forcedTileNumberToNames = hashSetOf(
|
||||
Block.AIR, Block.UPDATE
|
||||
)
|
||||
@Transient private val forcedFluidNumberToTiles = hashSetOf(
|
||||
Fluid.NULL
|
||||
)
|
||||
val tileNumberToNameMap = HashArray<ItemID>().also {
|
||||
it[0] = Block.AIR
|
||||
it[2] = Block.UPDATE
|
||||
}
|
||||
val fluidNumberToNameMap = HashArray<ItemID>().also {
|
||||
it[0] = Fluid.NULL
|
||||
}
|
||||
// does not go to the savefile
|
||||
@Transient val tileNameToNumberMap = HashMap<ItemID, Int>()
|
||||
@Transient val tileNameToNumberMap = HashMap<ItemID, Int>().also {
|
||||
it[Block.AIR] = 0
|
||||
it[Block.UPDATE] = 2
|
||||
}
|
||||
@Transient val fluidNameToNumberMap = HashMap<ItemID, Int>().also {
|
||||
it[Fluid.NULL] = 0
|
||||
}
|
||||
|
||||
val extraFields = HashMap<String, Any?>()
|
||||
|
||||
@@ -197,8 +216,10 @@ open class GameWorld(
|
||||
this.spawnX = width / 2
|
||||
this.spawnY = 150
|
||||
|
||||
layerTerrain = BlockLayer(width, height)
|
||||
layerWall = BlockLayer(width, height)
|
||||
layerTerrain = BlockLayerI16(width, height)
|
||||
layerWall = BlockLayerI16(width, height)
|
||||
layerOres = BlockLayerI16I8(width, height)
|
||||
layerFluids = BlockLayerI16F16(width, height)
|
||||
|
||||
// temperature layer: 2x2 is one cell
|
||||
//layerThermal = MapLayerHalfFloat(width, height, averageTemperature)
|
||||
@@ -214,26 +235,15 @@ open class GameWorld(
|
||||
if (App.tileMaker != null) {
|
||||
App.tileMaker.tags.forEach {
|
||||
if (!forcedTileNumberToNames.contains(it.key)) {
|
||||
printdbg(this, "tileNumber ${it.value.tileNumber} <-> tileName ${it.key}")
|
||||
printdbg(this, "newworld tileNumber ${it.value.tileNumber} <-> tileName ${it.key}")
|
||||
|
||||
tileNumberToNameMap[it.value.tileNumber.toLong()] = it.key
|
||||
tileNameToNumberMap[it.key] = it.value.tileNumber
|
||||
}
|
||||
}
|
||||
|
||||
// AN EXCEPTIONAL TERM: tilenum 0 is always redirected to Air tile, even if the tilenum for actual Air tile is not zero
|
||||
tileNumberToNameMap[0] = Block.AIR
|
||||
tileNameToNumberMap[Block.AIR] = 0
|
||||
|
||||
tileNumberToNameMap[2] = Block.UPDATE
|
||||
tileNameToNumberMap[Block.UPDATE] = 2
|
||||
}
|
||||
}
|
||||
|
||||
@Transient private val forcedTileNumberToNames = hashSetOf(
|
||||
Block.AIR, Block.UPDATE
|
||||
)
|
||||
|
||||
fun coordInWorld(x: Int, y: Int) = y in 0 until height // ROUNDWORLD implementation
|
||||
fun coordInWorldStrict(x: Int, y: Int) = x in 0 until width && y in 0 until height // ROUNDWORLD implementation
|
||||
|
||||
@@ -243,6 +253,8 @@ open class GameWorld(
|
||||
tileNumberToNameMap.clear()
|
||||
tileNameToNumberMap.clear()
|
||||
App.tileMaker.tags.forEach {
|
||||
printdbg(this, "afterload tileNumber ${it.value.tileNumber} <-> tileName ${it.key}")
|
||||
|
||||
tileNumberToNameMap[it.value.tileNumber.toLong()] = it.key
|
||||
tileNameToNumberMap[it.key] = it.value.tileNumber
|
||||
}
|
||||
@@ -252,15 +264,20 @@ open class GameWorld(
|
||||
for (x in 0 until layerTerrain.width) {
|
||||
layerTerrain.unsafeSetTile(x, y, tileNameToNumberMap[oldTileNumberToNameMap[layerTerrain.unsafeGetTile(x, y).toLong()]]!!)
|
||||
layerWall.unsafeSetTile(x, y, tileNameToNumberMap[oldTileNumberToNameMap[layerWall.unsafeGetTile(x, y).toLong()]]!!)
|
||||
layerOres.unsafeSetTileKeepPlacement(x, y, tileNameToNumberMap[oldTileNumberToNameMap[layerOres.unsafeGetTile(x, y).toLong()]]!!)
|
||||
}
|
||||
}
|
||||
|
||||
// AN EXCEPTIONAL TERM: tilenum 0 is always redirected to Air tile, even if the tilenum for actual Air tile is not zero
|
||||
// force this rule to the old saves
|
||||
tileNumberToNameMap[0] = Block.AIR
|
||||
tileNameToNumberMap[Block.AIR] = 0
|
||||
|
||||
tileNumberToNameMap[2] = Block.UPDATE
|
||||
tileNameToNumberMap[Block.AIR] = 0
|
||||
tileNameToNumberMap[Block.UPDATE] = 2
|
||||
fluidNumberToNameMap[0] = Fluid.NULL
|
||||
fluidNameToNumberMap[Fluid.NULL] = 0
|
||||
|
||||
|
||||
BlocksDrawer.rebuildInternalPrecalculations()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,8 +288,9 @@ open class GameWorld(
|
||||
// get() = layerWire.data
|
||||
|
||||
fun getLayer(index: Int) = when(index) {
|
||||
0 -> layerTerrain
|
||||
1 -> layerWall
|
||||
TERRAIN -> layerTerrain
|
||||
WALL -> layerWall
|
||||
ORES -> layerOres
|
||||
else -> null//throw IllegalArgumentException("Unknown layer index: $index")
|
||||
}
|
||||
|
||||
@@ -357,14 +375,25 @@ open class GameWorld(
|
||||
terrainDamages.remove(blockAddr)
|
||||
|
||||
if (BlockCodex[itemID].isSolid) {
|
||||
fluidFills.remove(blockAddr)
|
||||
fluidTypes.remove(blockAddr)
|
||||
layerFluids.unsafeSetTile(x, y, fluidNameToNumberMap[Fluid.NULL]!!, 0f)
|
||||
// Terrarum.ingame?.modified(LandUtil.LAYER_FLUID, x, y)
|
||||
}
|
||||
// fluid tiles-item should be modified so that they will also place fluid onto their respective map
|
||||
|
||||
val oldOre = layerOres.unsafeGetTile(x, y)
|
||||
val deleteOldOre = (oldOre != 0 && !BlockCodex[itemID].isSolid)
|
||||
|
||||
if (deleteOldOre) {
|
||||
layerOres.unsafeSetTile(x, y, 0, 0)
|
||||
}
|
||||
|
||||
if (!bypassEvent && oldTerrain != itemID) {
|
||||
Terrarum.ingame?.queueTerrainChangedEvent(oldTerrain, itemID, x, y)
|
||||
Terrarum.ingame?.modified(LandUtil.LAYER_TERR, x, y)
|
||||
|
||||
if (deleteOldOre) {
|
||||
Terrarum.ingame?.modified(LandUtil.LAYER_ORES, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +410,7 @@ open class GameWorld(
|
||||
|
||||
if (!bypassEvent) {
|
||||
Terrarum.ingame?.queueWireChangedEvent(tile, false, x, y)
|
||||
Terrarum.ingame?.modified(LandUtil.LAYER_WIRE, x, y)
|
||||
// Terrarum.ingame?.modified(LandUtil.LAYER_WIRE, x, y)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -405,6 +434,13 @@ open class GameWorld(
|
||||
setWireGraphOfUnsafe(blockAddr, tile, connection)
|
||||
}
|
||||
|
||||
fun setTileOnLayerUnsafe(layer: Int, x: Int, y: Int, tile: Int) {
|
||||
(getLayer(layer) ?: throw IllegalArgumentException("Unknown layer index: $layer")).let {
|
||||
if (it !is BlockLayerI16) throw IllegalArgumentException("Block layers other than BlockLayer16 is not supported yet)")
|
||||
it.unsafeSetTile(x, y, tile)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeTileWire(x: Int, y: Int, tile: ItemID, bypassEvent: Boolean) {
|
||||
val (x, y) = coerceXY(x, y)
|
||||
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
||||
@@ -413,7 +449,7 @@ open class GameWorld(
|
||||
if (wireNode != null) {
|
||||
if (!bypassEvent) {
|
||||
Terrarum.ingame?.queueWireChangedEvent(tile, true, x, y)
|
||||
Terrarum.ingame?.modified(LandUtil.LAYER_WIRE, x, y)
|
||||
// Terrarum.ingame?.modified(LandUtil.LAYER_WIRE, x, y)
|
||||
}
|
||||
|
||||
// disconnect neighbouring nodes
|
||||
@@ -543,11 +579,26 @@ open class GameWorld(
|
||||
return getTileFromWall(x, y)
|
||||
}
|
||||
else
|
||||
throw IllegalArgumentException("illegal mode input: " + mode.toString())
|
||||
throw IllegalArgumentException("illegal mode input: $mode")
|
||||
}
|
||||
|
||||
fun terrainIterator(): Iterator<ItemID> {
|
||||
return object : Iterator<ItemID> {
|
||||
/**
|
||||
* Will return (Block.AIR, 0) if there is no ore
|
||||
*/
|
||||
fun getTileFromOre(rawX: Int, rawY: Int): OrePlacement {
|
||||
val (x, y) = coerceXY(rawX, rawY)
|
||||
val (tileNum, placement) = layerOres.unsafeGetTile1(x, y)
|
||||
val tileName = tileNumberToNameMap[tileNum.toLong()]
|
||||
return OrePlacement(tileName ?: Block.UPDATE, placement)
|
||||
}
|
||||
|
||||
fun setTileOre(rawX: Int, rawY: Int, ore: ItemID, placement: Int) {
|
||||
val (x, y) = coerceXY(rawX, rawY)
|
||||
layerOres.unsafeSetTile(x, y, tileNameToNumberMap[ore]!!, placement)
|
||||
}
|
||||
|
||||
fun terrainIterator(): Iterator<List<ItemID>> {
|
||||
return object : Iterator<List<ItemID>> {
|
||||
|
||||
private var iteratorCount = 0
|
||||
|
||||
@@ -555,13 +606,13 @@ open class GameWorld(
|
||||
return iteratorCount < width * height
|
||||
}
|
||||
|
||||
override fun next(): ItemID {
|
||||
override fun next(): List<ItemID> {
|
||||
val y = iteratorCount / width
|
||||
val x = iteratorCount % width
|
||||
// advance counter
|
||||
iteratorCount += 1
|
||||
|
||||
return getTileFromTerrain(x, y)
|
||||
return listOf(getTileFromTerrain(x, y), getTileFromWall(x, y), getTileFromOre(x, y).item)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -609,7 +660,7 @@ open class GameWorld(
|
||||
//println("[GameWorld] accumulated damage: ${terrainDamages[addr]}")
|
||||
|
||||
// remove tile from the world
|
||||
if (terrainDamages[addr] ?: 0f >= BlockCodex[getTileFromTerrain(x, y)].strength) {
|
||||
if ((terrainDamages[addr] ?: 0f) >= BlockCodex[getTileFromTerrain(x, y)].strength) {
|
||||
val tileBroke = getTileFromTerrain(x, y)
|
||||
setTileTerrain(x, y, Block.AIR, false)
|
||||
terrainDamages.remove(addr)
|
||||
@@ -651,7 +702,9 @@ open class GameWorld(
|
||||
fun getWallDamage(x: Int, y: Int): Float =
|
||||
wallDamages[LandUtil.getBlockAddr(this, x, y)] ?: 0f
|
||||
|
||||
fun setFluid(x: Int, y: Int, fluidType: FluidType, fill: Float) {
|
||||
fun setFluid(x: Int, y: Int, fluidType: ItemID, fill: Float) {
|
||||
if (!fluidType.isFluid()) throw IllegalArgumentException("Fluid type is not actually fluid: $fluidType")
|
||||
|
||||
/*if (x == 60 && y == 256) {
|
||||
printdbg(this, "Setting fluid $fill at ($x,$y)")
|
||||
}*/
|
||||
@@ -664,15 +717,14 @@ open class GameWorld(
|
||||
|
||||
val addr = LandUtil.getBlockAddr(this, x, y)
|
||||
|
||||
val fluidNumber = fluidNameToNumberMap[fluidType]!!
|
||||
|
||||
if (fill > WorldSimulator.FLUID_MIN_MASS) {
|
||||
//setTileTerrain(x, y, fluidTypeToBlock(fluidType))
|
||||
fluidFills[addr] = fill
|
||||
fluidTypes[addr] = fluidType
|
||||
layerFluids.unsafeSetTile(x, y, fluidNumber, fill)
|
||||
}
|
||||
else {
|
||||
fluidFills.remove(addr)
|
||||
fluidTypes.remove(addr)
|
||||
|
||||
layerFluids.unsafeSetTile(x, y, fluidNumber, 0f)
|
||||
}
|
||||
|
||||
|
||||
@@ -684,23 +736,24 @@ open class GameWorld(
|
||||
}
|
||||
|
||||
fun getFluid(x: Int, y: Int): FluidInfo {
|
||||
val addr = LandUtil.getBlockAddr(this, x, y)
|
||||
val fill = fluidFills[addr]
|
||||
val type = fluidTypes[addr]
|
||||
return if (type == null) FluidInfo(Fluid.NULL, 0f) else FluidInfo(type, fill!!)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
val (type, fill) = layerFluids.unsafeGetTile1(x, y)
|
||||
val fluidID = fluidNumberToNameMap[type.toLong()] ?: throw NullPointerException("No such fluid: $type")
|
||||
|
||||
return FluidInfo(fluidID, fill)
|
||||
}
|
||||
|
||||
private fun fluidTypeToBlock(type: FluidType) = when (type.abs()) {
|
||||
/*private fun fluidTypeToBlock(type: FluidType) = when (type.abs()) {
|
||||
Fluid.NULL.value -> Block.AIR
|
||||
in Fluid.fluidRange -> GameWorld.TILES_SUPPORTED - type.abs()
|
||||
else -> throw IllegalArgumentException("Unsupported fluid type: $type")
|
||||
}
|
||||
}*/
|
||||
|
||||
data class FluidInfo(val type: FluidType = Fluid.NULL, val amount: Float = 0f) {
|
||||
data class FluidInfo(val type: ItemID = Fluid.NULL, val amount: Float = 0f) {
|
||||
/** test if this fluid should be considered as one */
|
||||
fun isFluid() = type != Fluid.NULL && amount >= WorldSimulator.FLUID_MIN_MASS
|
||||
fun getProp() = BlockCodex[type]
|
||||
override fun toString() = "Fluid type: ${type.value}, amount: $amount"
|
||||
fun getProp(): Nothing = TODO()
|
||||
override fun toString() = "Fluid type: ${type}, amount: $amount"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -747,9 +800,9 @@ open class GameWorld(
|
||||
override fun equals(other: Any?) = layerTerrain.ptr == (other as GameWorld).layerTerrain.ptr
|
||||
|
||||
companion object {
|
||||
@Transient const val WALL = 0
|
||||
@Transient const val TERRAIN = 1
|
||||
@Transient const val WIRE = 2
|
||||
@Transient const val TERRAIN = 0
|
||||
@Transient const val WALL = 1
|
||||
@Transient const val ORES = 2
|
||||
|
||||
@Transient val TILES_SUPPORTED = ReferencingRanges.TILES.last + 1
|
||||
//@Transient val SIZEOF: Byte = 2
|
||||
@@ -776,10 +829,3 @@ infix fun Int.fmod(other: Int) = Math.floorMod(this, other)
|
||||
infix fun Long.fmod(other: Long) = Math.floorMod(this, other)
|
||||
infix fun Float.fmod(other: Float) = if (this >= 0f) this % other else (this % other) + other
|
||||
infix fun Double.fmod(other: Double) = if (this >= 0.0) this % other else (this % other) + other
|
||||
|
||||
@JvmInline
|
||||
value class FluidType(val value: Int) {
|
||||
infix fun sameAs(other: FluidType) = this.value.absoluteValue == other.value.absoluteValue
|
||||
fun abs() = this.value.absoluteValue
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ object WorldSimulator {
|
||||
|
||||
const val FLUID_MAX_MASS = 1f // The normal, un-pressurized mass of a full water cell
|
||||
const val FLUID_MAX_COMP = 0.02f // How much excess water a cell can store, compared to the cell above it. A tile of fluid can contain more than MaxMass water.
|
||||
const val FLUID_MIN_MASS = 0.0001f //Ignore cells that are almost dry
|
||||
const val FLUID_MIN_MASS = 1f / 1024f //Ignore cells that are almost dry (smaller than epsilon of float16)
|
||||
const val WIRE_MIN_FLOW = 0.0001f
|
||||
const val minFlow = 0.01f
|
||||
const val maxSpeed = 1f // max units of water moved out of one block to another, per timestamp
|
||||
@@ -151,6 +151,7 @@ object WorldSimulator {
|
||||
if (result.distance < pickupDistSqr) {
|
||||
droppedItem.flagDespawn = true
|
||||
(actor as Pocketed).inventory.add(droppedItem.itemID, droppedItem.itemCount)
|
||||
ItemCodex[droppedItem.itemID]!!.effectOnPickup(actor)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -178,12 +179,12 @@ object WorldSimulator {
|
||||
fluidmapToWorld()
|
||||
}
|
||||
|
||||
fun isFlowable(type: FluidType, worldX: Int, worldY: Int): Boolean {
|
||||
fun isFlowable(type: ItemID, worldX: Int, worldY: Int): Boolean {
|
||||
val fluid = world.getFluid(worldX, worldY)
|
||||
val tile = world.getTileFromTerrain(worldX, worldY)
|
||||
|
||||
// true if target's type is the same as mine, or it's NULL (air)
|
||||
return ((fluid.type sameAs type || fluid.type sameAs Fluid.NULL) && !BlockCodex[tile].isSolid)
|
||||
return ((fluid.type == type || fluid.type == Fluid.NULL) && !BlockCodex[tile].isSolid)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,6 +29,8 @@ class Material {
|
||||
|
||||
var toolReach: Int = 6
|
||||
|
||||
var rcs: Int = 10
|
||||
|
||||
/**
|
||||
* Mainly intended to be used by third-party modules
|
||||
*/
|
||||
@@ -70,6 +72,7 @@ class MaterialCodex {
|
||||
prop.thermalConductivity = it.floatVal("tcond")
|
||||
prop.identifier = it.get("idst").toUpperCase()
|
||||
prop.toolReach = it.intVal("reach")
|
||||
prop.rcs = it.intVal("rcs")
|
||||
|
||||
materialProps[prop.identifier] = prop
|
||||
|
||||
@@ -86,6 +89,6 @@ class MaterialCodex {
|
||||
throw NullPointerException("Material with id $identifier does not exist.")
|
||||
}
|
||||
|
||||
fun getOrDefault(identifier: String) = materialProps[identifier.toUpperCase()] ?: nullMaterial
|
||||
fun getOrDefault(identifier: String?) = materialProps[identifier?.toUpperCase()] ?: nullMaterial
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import com.badlogic.gdx.InputAdapter
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
@@ -14,16 +13,26 @@ import net.torvald.terrarum.gameactors.*
|
||||
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameparticles.ParticleBase
|
||||
import net.torvald.terrarum.gameworld.BlockLayerI16
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.gameworld.WorldTime
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerBlockChooser
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerPenMenu
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIPaletteSelector
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIScreenZoom
|
||||
import net.torvald.terrarum.serialise.Common
|
||||
import net.torvald.terrarum.serialise.PointOfInterest
|
||||
import net.torvald.terrarum.serialise.POILayer
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.weather.WeatherMixer
|
||||
import net.torvald.terrarum.ui.UINSMenu
|
||||
import net.torvald.terrarum.utils.OrePlacement
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.util.CircularArray
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-07-06.
|
||||
@@ -32,72 +41,37 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
private val menuYaml = Yaml("""
|
||||
- File
|
||||
- New flat ter.
|
||||
- New rand. ter.
|
||||
- Export…
|
||||
- Export sel…
|
||||
- Import…
|
||||
- Save terrain…
|
||||
- Load terrain…
|
||||
-
|
||||
- New Flat ter. : net.torvald.terrarum.modulebasegame.YamlCommandNewFlatTerrain
|
||||
- New Rand. ter.
|
||||
- Export… : net.torvald.terrarum.modulebasegame.YamlCommandToolExportTest
|
||||
- Import… : net.torvald.terrarum.modulebasegame.YamlCommandToolImportTest
|
||||
- Exit to Title : net.torvald.terrarum.modulebasegame.YamlCommandExit
|
||||
- Tool
|
||||
- Pencil : net.torvald.terrarum.modulebasegame.YamlCommandToolPencil
|
||||
- Eraser : net.torvald.terrarum.modulebasegame.YamlCommandToolPencilErase
|
||||
- Wall Hammer : net.torvald.terrarum.modulebasegame.YamlCommandToolPencilEraseWall
|
||||
- Eyedropper : net.torvald.terrarum.modulebasegame.YamlCommandToolEyedropper
|
||||
- Add Selection : net.torvald.terrarum.modulebasegame.YamlCommandToolMarquee
|
||||
- Remove Sel. : net.torvald.terrarum.modulebasegame.YamlCommandToolMarqueeErase
|
||||
- Clear Sel. : net.torvald.terrarum.modulebasegame.YamlCommandToolMarqueeClear
|
||||
- Move Selected
|
||||
-
|
||||
- Hide/Show Sel. : net.torvald.terrarum.modulebasegame.YamlCommandToolToggleMarqueeOverlay
|
||||
-
|
||||
- Undo
|
||||
- Redo
|
||||
- Edit
|
||||
- Clear Selections : net.torvald.terrarum.modulebasegame.YamlCommandClearSelection
|
||||
- Time
|
||||
- Dawn : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeDawn
|
||||
- Sunrise : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeSunrise
|
||||
- Morning : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeMorning
|
||||
- Noon : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeNoon
|
||||
- Dusk : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeDusk
|
||||
- Sunset : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeSunset
|
||||
- Night : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeNight
|
||||
- Midnight : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeMidnight
|
||||
- Set…
|
||||
- Weather
|
||||
- Sunny
|
||||
- Raining
|
||||
""".trimIndent())
|
||||
|
||||
private val timeNow = System.currentTimeMillis() / 1000
|
||||
lateinit var gameWorld: GameWorld
|
||||
|
||||
val gameWorld = GameWorld(90*12, 90*4, timeNow, timeNow)
|
||||
override val musicGovernor = TerrarumMusicGovernor()
|
||||
|
||||
init {
|
||||
// ghetto world for building
|
||||
gameUpdateGovernor = ConsistentUpdateRate
|
||||
YamlCommandNewFlatTerrain().invoke(arrayOf(this))
|
||||
}
|
||||
|
||||
println("[BuildingMaker] Generating builder world...")
|
||||
|
||||
for (y in 0 until gameWorld.height) {
|
||||
gameWorld.setTileWall(0, y, Block.ILLUMINATOR_RED, true)
|
||||
gameWorld.setTileWall(gameWorld.width - 1, y, Block.ILLUMINATOR_RED, true)
|
||||
gameWorld.setTileTerrain(0, y, Block.ILLUMINATOR_RED_OFF, true)
|
||||
gameWorld.setTileTerrain(gameWorld.width - 1, y, Block.ILLUMINATOR_RED_OFF, true)
|
||||
}
|
||||
|
||||
for (y in 150 until gameWorld.height) {
|
||||
for (x in 1 until gameWorld.width - 1) {
|
||||
// wall layer
|
||||
gameWorld.setTileWall(x, y, Block.DIRT, true)
|
||||
|
||||
// terrain layer
|
||||
gameWorld.setTileTerrain(x, y, if (y == 150) Block.GRASS else Block.DIRT, true)
|
||||
}
|
||||
}
|
||||
|
||||
// set time to summer
|
||||
gameWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
|
||||
|
||||
world = gameWorld
|
||||
|
||||
gameUpdateGovernor = ConsistentUpdateRate.also { it.reset() }
|
||||
internal fun reset() {
|
||||
gameUpdateGovernor.reset()
|
||||
WeatherMixer.forceSolarElev = 5.0
|
||||
}
|
||||
|
||||
|
||||
@@ -108,9 +82,13 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
val uiPalette = UIBuildingMakerBlockChooser(this)
|
||||
val uiPenMenu = UIBuildingMakerPenMenu(this)
|
||||
|
||||
val uiGetPoiName = UIBuildingMakerGetFilename() // used for both import and export
|
||||
|
||||
val uiContainer = UIContainer()
|
||||
|
||||
val keyboardUsedByTextInput: Boolean
|
||||
get() = uiGetPoiName.textInput.isEnabled
|
||||
|
||||
private val pensMustShowSelection = arrayOf(
|
||||
PENMODE_MARQUEE, PENMODE_MARQUEE_ERASE
|
||||
)
|
||||
@@ -124,7 +102,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
var currentPenTarget = PENTARGET_TERRAIN
|
||||
|
||||
val selection = ArrayList<Point2i>()
|
||||
val selection = ArrayList<Long>()
|
||||
|
||||
val blockMarkings = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common")
|
||||
internal var showSelection = true
|
||||
@@ -227,41 +205,52 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
internal fun addBlockMarker(x: Int, y: Int) {
|
||||
try {
|
||||
val a = generateNewBlockMarkerVisible(x, y)
|
||||
queueActorAddition(a)
|
||||
actorsRenderOverlay.add(a)
|
||||
selection.add(Point2i(x, y))
|
||||
if (!theGameHasActor(a.referenceID)) {
|
||||
selection.add(toAddr(x, y))
|
||||
actorsRenderOverlay.add(a)
|
||||
queueActorAddition(a)
|
||||
}
|
||||
}
|
||||
catch (e: Error) { }
|
||||
}
|
||||
|
||||
internal fun removeBlockMarker(x: Int, y: Int) {
|
||||
try {
|
||||
selection.remove(toAddr(x, y))
|
||||
val a = getActorByID(blockPosToRefID(x, y))
|
||||
queueActorAddition(a)
|
||||
actorsRenderOverlay.remove(a)
|
||||
selection.remove(Point2i(x, y))
|
||||
queueActorRemoval(a)
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
catch (e: Throwable) {
|
||||
// no actor to erase, do nothing
|
||||
// e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
internal var imported: PointOfInterest? = null
|
||||
|
||||
companion object {
|
||||
const val PENMODE_PENCIL = 0
|
||||
const val PENMODE_PENCIL_ERASE = 1
|
||||
const val PENMODE_MARQUEE = 2
|
||||
const val PENMODE_MARQUEE_ERASE = 3
|
||||
const val PENMODE_EYEDROPPER = 4
|
||||
const val PENMODE_IMPORT = 8
|
||||
|
||||
const val PENTARGET_TERRAIN = 1
|
||||
const val PENTARGET_WALL = 2
|
||||
const val PENTARGET_ORE = 4
|
||||
|
||||
val toolCursorColour = arrayOf(
|
||||
Color.YELLOW,
|
||||
Color.YELLOW,
|
||||
Color.MAGENTA,
|
||||
Color.MAGENTA,
|
||||
Color.WHITE
|
||||
Color.YELLOW,
|
||||
Color.YELLOW,
|
||||
Color.MAGENTA,
|
||||
Color.MAGENTA,
|
||||
Color.WHITE,
|
||||
Color.WHITE,
|
||||
Color.WHITE,
|
||||
Color.WHITE,
|
||||
Color.MAGENTA,
|
||||
)
|
||||
|
||||
const val DEFAULT_POI_NAME = "The Yucky Panopticon"
|
||||
@@ -271,16 +260,17 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
private val essentialOverlays = ArrayList<ActorWithBody>()
|
||||
|
||||
init {
|
||||
gameWorld.worldTime.setTimeOfToday(WorldTime.HOUR_SEC * 10)
|
||||
gameWorld.globalLight = Cvec(.8f, .8f, .8f, .8f)
|
||||
|
||||
essentialOverlays.add(blockPointingCursor)
|
||||
|
||||
uiContainer.add(uiToolbox)
|
||||
uiContainer.add(uiPaletteSelector)
|
||||
uiContainer.add(notifier)
|
||||
uiContainer.add(uiPalette)
|
||||
uiContainer.add(uiPenMenu)
|
||||
uiContainer.add(
|
||||
uiToolbox,
|
||||
uiPaletteSelector,
|
||||
notifier,
|
||||
uiPalette,
|
||||
uiPenMenu,
|
||||
uiGetPoiName,
|
||||
UIScreenZoom(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -288,11 +278,13 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
uiToolbox.isVisible = true
|
||||
uiToolbox.invocationArgument = arrayOf(this)
|
||||
|
||||
uiPaletteSelector.setPosition(App.scr.width - uiPaletteSelector.width, 0)
|
||||
uiPaletteSelector.setPosition(0, App.scr.height - uiPaletteSelector.height)
|
||||
uiPaletteSelector.isVisible = true
|
||||
|
||||
notifier.setPosition(
|
||||
(App.scr.width - notifier.width) / 2, App.scr.height - notifier.height)
|
||||
(Toolkit.drawWidth - notifier.width) / 2,
|
||||
App.scr.height - notifier.height - App.scr.tvSafeGraphicsHeight
|
||||
)
|
||||
|
||||
|
||||
actorNowPlaying?.setPosition(512 * 16.0, 149 * 16.0)
|
||||
@@ -311,7 +303,14 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
|
||||
private var disableMouseClick = false
|
||||
var mousePrimaryJustDown = false; private set
|
||||
|
||||
override fun render(updateRate: Float) {
|
||||
super.render(updateRate)
|
||||
|
||||
|
||||
|
||||
Gdx.graphics.setTitle(TerrarumIngame.getCanonicalTitle())
|
||||
|
||||
|
||||
@@ -329,6 +328,11 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
if (!Gdx.input.isButtonPressed(App.getConfigInt("config_mouseprimary"))) {
|
||||
disableMouseClick = false
|
||||
}
|
||||
}
|
||||
|
||||
private var mouseOnUI = false
|
||||
@@ -337,9 +341,12 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
private val updateGame = { delta: Float ->
|
||||
|
||||
WeatherMixer.update(delta, actorNowPlaying, gameWorld)
|
||||
blockPointingCursor.update(delta)
|
||||
actorNowPlaying?.update(delta)
|
||||
|
||||
if (!keyboardUsedByTextInput) {
|
||||
actorNowPlaying?.update(delta)
|
||||
}
|
||||
|
||||
var overwriteMouseOnUI = false
|
||||
uiContainer.forEach {
|
||||
it?.update(delta)
|
||||
@@ -348,7 +355,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
}
|
||||
|
||||
mouseOnUI = (overwriteMouseOnUI || uiPenMenu.isVisible)
|
||||
mouseOnUI = (overwriteMouseOnUI || uiPenMenu.isVisible /*|| uiPalette.isVisible*/ || uiGetPoiName.isVisible)
|
||||
|
||||
|
||||
WorldCamera.update(world, actorNowPlaying)
|
||||
@@ -374,7 +381,74 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
uiPenMenu.setAsOpen()
|
||||
}
|
||||
|
||||
|
||||
actorAdditionQueue.forEach { forceAddActor(it.first, it.second) }
|
||||
actorAdditionQueue.clear()
|
||||
actorRemovalQueue.forEach { forceRemoveActor(it.first, it.second) }
|
||||
actorRemovalQueue.clear()
|
||||
|
||||
|
||||
BlockPropUtil.dynamicLumFuncTickClock()
|
||||
WeatherMixer.update(delta, actorNowPlaying, gameWorld)
|
||||
if (WORLD_UPDATE_TIMER % 2 == 1) {
|
||||
fillUpWiresBuffer()
|
||||
}
|
||||
|
||||
|
||||
musicGovernor.update(this, delta)
|
||||
}
|
||||
|
||||
|
||||
private val maxRenderableWires = ReferencingRanges.ACTORS_WIRES.last - ReferencingRanges.ACTORS_WIRES.first + 1
|
||||
private val wireActorsContainer = Array(maxRenderableWires) { WireActor(ReferencingRanges.ACTORS_WIRES.first + it).let {
|
||||
forceAddActor(it)
|
||||
/*^let*/ it
|
||||
} }
|
||||
var selectedWireRenderClass = ""
|
||||
private var oldSelectedWireRenderClass = ""
|
||||
|
||||
|
||||
private fun fillUpWiresBuffer() {
|
||||
val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorToInt() - LightmapRenderer.LIGHTMAP_OVERRENDER
|
||||
val for_y_end = for_y_start + BlocksDrawer.tilesInVertical + 2* LightmapRenderer.LIGHTMAP_OVERRENDER
|
||||
|
||||
val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorToInt() - LightmapRenderer.LIGHTMAP_OVERRENDER
|
||||
val for_x_end = for_x_start + BlocksDrawer.tilesInHorizontal + 2* LightmapRenderer.LIGHTMAP_OVERRENDER
|
||||
|
||||
var wiringCounter = 0
|
||||
for (y in for_y_start..for_y_end) {
|
||||
for (x in for_x_start..for_x_end) {
|
||||
if (wiringCounter >= maxRenderableWires) break
|
||||
|
||||
val (wires, nodes) = world.getAllWiresFrom(x, y)
|
||||
|
||||
wires?.forEach {
|
||||
val wireActor = wireActorsContainer[wiringCounter]
|
||||
|
||||
wireActor.setWire(it, x, y, nodes!![it]!!.cnx)
|
||||
|
||||
if (WireCodex[it].renderClass == selectedWireRenderClass || selectedWireRenderClass == "wire_render_all") {
|
||||
wireActor.renderOrder = Actor.RenderOrder.OVERLAY
|
||||
}
|
||||
else {
|
||||
wireActor.renderOrder = Actor.RenderOrder.BEHIND
|
||||
}
|
||||
|
||||
wireActor.isUpdate = true
|
||||
wireActor.isVisible = true
|
||||
wireActor.forceDormant = false
|
||||
|
||||
wiringCounter += 1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (i in wiringCounter until maxRenderableWires) {
|
||||
wireActorsContainer[i].isUpdate = false
|
||||
wireActorsContainer[i].isVisible = false
|
||||
wireActorsContainer[i].forceDormant = true
|
||||
}
|
||||
}
|
||||
|
||||
private val particles = CircularArray<ParticleBase>(16, true)
|
||||
@@ -383,7 +457,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
_testMarkerDrawCalls = 0L
|
||||
|
||||
IngameRenderer.invoke(false,
|
||||
1f,
|
||||
screenZoom,
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
@@ -398,9 +472,13 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
IngameRenderer.resize(App.scr.width, App.scr.height)
|
||||
val drawWidth = Toolkit.drawWidth
|
||||
|
||||
uiToolbox.setPosition(0, 0)
|
||||
notifier.setPosition(
|
||||
(App.scr.width - notifier.width) / 2, App.scr.height - notifier.height)
|
||||
(Toolkit.drawWidth - notifier.width) / 2,
|
||||
App.scr.height - notifier.height - App.scr.tvSafeGraphicsHeight
|
||||
)
|
||||
|
||||
println("[BuildingMaker] Resize event")
|
||||
}
|
||||
@@ -412,95 +490,136 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
blockMarkings.dispose()
|
||||
// blockMarkings.dispose()
|
||||
uiPenMenu.dispose()
|
||||
uiGetPoiName.dispose()
|
||||
musicGovernor.dispose()
|
||||
}
|
||||
|
||||
override fun inputStrobed(e: TerrarumKeyboardEvent) {
|
||||
fun getPoiNameForExport(w: Int, h: Int, callback: (String) -> Unit) {
|
||||
uiGetPoiName.let {
|
||||
it.title = "Export"
|
||||
it.labelDo = "Export"
|
||||
it.text = listOf("WH: $w\u00D7$h", "Name of the POI:")
|
||||
it.confirmCallback = { s ->
|
||||
callback(s)
|
||||
disableMouseClick = true
|
||||
}
|
||||
it.cancelCallback = {
|
||||
disableMouseClick = true
|
||||
}
|
||||
it.setPosition(
|
||||
240,
|
||||
32
|
||||
)
|
||||
it.reset()
|
||||
it.setAsOpen()
|
||||
}
|
||||
}
|
||||
|
||||
fun getPoiNameForImport(callback: (String) -> Unit) {
|
||||
uiGetPoiName.let {
|
||||
it.title = "Import"
|
||||
it.labelDo = "Import"
|
||||
it.text = listOf("Name of the POI:")
|
||||
it.confirmCallback = { s ->
|
||||
callback(s)
|
||||
disableMouseClick = true
|
||||
}
|
||||
it.cancelCallback = {
|
||||
disableMouseClick = true
|
||||
}
|
||||
it.setPosition(
|
||||
240,
|
||||
32
|
||||
)
|
||||
it.reset()
|
||||
it.setAsOpen()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNearbyTilesPos8(x: Int, y: Int): Array<Point2i> {
|
||||
return arrayOf(
|
||||
Point2i(x + 1, y),
|
||||
Point2i(x + 1, y + 1),
|
||||
Point2i(x, y + 1),
|
||||
Point2i(x - 1, y + 1),
|
||||
Point2i(x - 1, y),
|
||||
Point2i(x - 1, y - 1),
|
||||
Point2i(x, y - 1),
|
||||
Point2i(x + 1, y - 1)
|
||||
)
|
||||
}
|
||||
private fun getNearbyOres8(x: Int, y: Int): List<OrePlacement> {
|
||||
return getNearbyTilesPos8(x, y).map { world.getTileFromOre(it.x, it.y) }
|
||||
}
|
||||
|
||||
private fun makePenWork(x: Int, y: Int) {
|
||||
val world = gameWorld
|
||||
val palSelection = uiPaletteSelector.fore
|
||||
|
||||
when (currentPenMode) {
|
||||
// test paint terrain layer
|
||||
PENMODE_PENCIL -> {
|
||||
if (palSelection.startsWith("wall@"))
|
||||
world.setTileWall(x, y, palSelection.substring(5), true)
|
||||
else
|
||||
world.setTileTerrain(x, y, palSelection, true)
|
||||
}
|
||||
PENMODE_PENCIL_ERASE -> {
|
||||
if (currentPenTarget and PENTARGET_WALL != 0)
|
||||
world.setTileWall(x, y, Block.AIR, true)
|
||||
else
|
||||
world.setTileTerrain(x, y, Block.AIR, true)
|
||||
}
|
||||
PENMODE_EYEDROPPER -> {
|
||||
uiPaletteSelector.fore = if (world.getTileFromTerrain(x, y) == Block.AIR)
|
||||
"wall@"+world.getTileFromWall(x, y)
|
||||
else
|
||||
world.getTileFromTerrain(x, y)
|
||||
}
|
||||
PENMODE_MARQUEE -> {
|
||||
addBlockMarker(x, y)
|
||||
}
|
||||
PENMODE_MARQUEE_ERASE -> {
|
||||
removeBlockMarker(x, y)
|
||||
if (!disableMouseClick) {
|
||||
when (currentPenMode) {
|
||||
// test paint terrain layer
|
||||
PENMODE_PENCIL -> {
|
||||
if (palSelection.startsWith("wall@"))
|
||||
world.setTileWall(x, y, palSelection.substring(5), true)
|
||||
else if (palSelection.startsWith("ore@")) {
|
||||
// get autotiling placement
|
||||
val autotiled = getNearbyOres8(x, y).foldIndexed(0) { index, acc, placement ->
|
||||
acc or (placement.item == palSelection).toInt(index)
|
||||
}
|
||||
val placement = BlocksDrawer.connectLut16[autotiled]
|
||||
|
||||
world.setTileOre(x, y, palSelection, placement)
|
||||
}
|
||||
else
|
||||
world.setTileTerrain(x, y, palSelection, true)
|
||||
}
|
||||
|
||||
PENMODE_PENCIL_ERASE -> {
|
||||
if (currentPenTarget and PENTARGET_TERRAIN != 0)
|
||||
world.setTileTerrain(x, y, Block.AIR, true)
|
||||
if (currentPenTarget and PENTARGET_WALL != 0)
|
||||
world.setTileWall(x, y, Block.AIR, true)
|
||||
if (currentPenTarget and PENTARGET_ORE != 0)
|
||||
world.setTileOre(x, y, Block.NULL, 0)
|
||||
}
|
||||
|
||||
PENMODE_EYEDROPPER -> {
|
||||
uiPaletteSelector.fore = if (world.getTileFromTerrain(x, y) == Block.AIR)
|
||||
"wall@" + world.getTileFromWall(x, y)
|
||||
else
|
||||
world.getTileFromTerrain(x, y)
|
||||
}
|
||||
|
||||
PENMODE_MARQUEE -> {
|
||||
addBlockMarker(x, y)
|
||||
}
|
||||
|
||||
PENMODE_MARQUEE_ERASE -> {
|
||||
removeBlockMarker(x, y)
|
||||
}
|
||||
|
||||
PENMODE_IMPORT -> {
|
||||
importPoi(x, y)
|
||||
disableMouseClick = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectionTotalDimension(): Point2i {
|
||||
selection.sortBy { it.y * world.width + it.x }
|
||||
return selection.last() - selection.first()
|
||||
private fun importPoi(x: Int, y: Int) {
|
||||
imported?.let {
|
||||
it.placeOnWorld(listOf(it.layers.first().name), world, x, y) // TODO show layer list and ticker using right click?
|
||||
}
|
||||
}
|
||||
|
||||
/*private fun serialiseSelection(outfile: File) {
|
||||
// save format: sparse list encoded in following binary format:
|
||||
/*
|
||||
Header: TEaT0bLD -- magic: Terrarum Attachment
|
||||
Int8 version number -- always 1
|
||||
Int8 number of layers -- always 2 or 3
|
||||
Int8 number of payloads -- always 2 or 3
|
||||
int8 compression algorithm -- always 1 (DEFLATE)
|
||||
Int16 width
|
||||
|
||||
The rest: payloads defined in the map data format
|
||||
Payloads: array of (Int48 tileAddress, UInt16 blockID)
|
||||
Payload names: TerL, WalL, WirL for Terrain, Wall and Wire respectively
|
||||
|
||||
Footer: EndTEM \xFF\xFE -- magic: end of attachment with BOM
|
||||
|
||||
Endian: LITTLE
|
||||
*/
|
||||
// proc:
|
||||
// translate boxes so that leftmost point is (0,0)
|
||||
// write to the list using translated coords
|
||||
|
||||
val payloads = arrayOf("WalL", "TerL", "WirL")
|
||||
|
||||
val selectionDim = getSelectionTotalDimension()
|
||||
val fos = FileOutputStream(outfile)
|
||||
// write header
|
||||
fos.write("TEaT0bLD".toByteArray())
|
||||
fos.write(byteArrayOf(1,3,3,1))
|
||||
fos.write(selectionDim.x.toLittleShort())
|
||||
// write wall -> terrain -> wire (order defined in GameWorld.TERRAIN/WALL/WIRE)
|
||||
payloads.forEachIndexed { index, it ->
|
||||
fos.write(PAYLOAD_HEADER); fos.write(it.toByteArray())
|
||||
selection.forEach {
|
||||
val tile = world.getTileFrom(index, it.x, it.y)!!
|
||||
val addr = LandUtil.getBlockAddr(world, it.x - selectionDim.x, it.y - selectionDim.y)
|
||||
fos.write(addr.toULittle48())
|
||||
fos.write(tile.toLittle())
|
||||
}
|
||||
fos.write(PAYLOAD_FOOTER)
|
||||
override fun inputStrobed(e: TerrarumKeyboardEvent) {
|
||||
uiContainer.forEach {
|
||||
it?.inputStrobed(e)
|
||||
}
|
||||
fos.write(FILE_FOOTER)
|
||||
fos.close()
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
class BuildingMakerController(val screen: BuildingMaker) : InputAdapter() {
|
||||
@@ -592,27 +711,59 @@ class YamlCommandExit : YamlInvokable {
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeDawn : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("6h00"))
|
||||
WeatherMixer.forceSolarElev = -3.0
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeSunrise : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("6h00"))
|
||||
WeatherMixer.forceSolarElev = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeMorning : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("7h00"))
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("6h00"))
|
||||
WeatherMixer.forceSolarElev = 5.0
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeNoon : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("12h30"))
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("12h00"))
|
||||
WeatherMixer.forceSolarElev = 30.0
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeDusk : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("18h40"))
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("18h00"))
|
||||
WeatherMixer.forceSolarElev = 3.0
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeSunset : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("18h00"))
|
||||
WeatherMixer.forceSolarElev = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeNight : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("0h30"))
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("18h00"))
|
||||
WeatherMixer.forceSolarElev = -8.0
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandSetTimeMidnight : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).gameWorld.worldTime.setTimeOfToday(WorldTime.parseTime("0h00"))
|
||||
WeatherMixer.forceSolarElev = -30.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,7 +810,8 @@ class YamlCommandToolMarqueeErase : YamlInvokable {
|
||||
class YamlCommandToolMarqueeClear : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
(args[0] as BuildingMaker).selection.toList().forEach {
|
||||
(args[0] as BuildingMaker).removeBlockMarker(it.x, it.y)
|
||||
val (x, y) = (it % 4294967296).toInt() to (it / 4294967296).toInt()
|
||||
(args[0] as BuildingMaker).removeBlockMarker(x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -669,3 +821,146 @@ class YamlCommandToolToggleMarqueeOverlay : YamlInvokable {
|
||||
(args[0] as BuildingMaker).showSelection = !(args[0] as BuildingMaker).showSelection
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandToolExportTest : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
val ui = (args[0] as BuildingMaker)
|
||||
if (ui.selection.isEmpty()) return
|
||||
|
||||
val marked = HashSet<Long>()
|
||||
fun isMarked(x: Int, y: Int) = marked.contains(toAddr(x, y))
|
||||
|
||||
|
||||
// get the bounding box
|
||||
var minX = 2147483647
|
||||
var minY = 2147483647
|
||||
var maxX = -1
|
||||
var maxY = -1
|
||||
ui.selection.forEach {
|
||||
val (x, y) = (it % 4294967296).toInt() to (it / 4294967296).toInt()
|
||||
|
||||
if (x < minX) minX = x
|
||||
if (y < minY) minY = y
|
||||
if (x > maxX) maxX = x
|
||||
if (y > maxY) maxY = y
|
||||
|
||||
marked.add(it)
|
||||
}
|
||||
|
||||
ui.getPoiNameForExport(maxX - minX + 1, maxY - minY + 1) { name ->
|
||||
// prepare POI
|
||||
val poi = PointOfInterest(
|
||||
name,
|
||||
maxX - minX + 1,
|
||||
maxY - minY + 1,
|
||||
ui.world.tileNumberToNameMap,
|
||||
ui.world.tileNameToNumberMap
|
||||
)
|
||||
val layer = POILayer(name)
|
||||
val terr = BlockLayerI16(poi.w, poi.h)
|
||||
val wall = BlockLayerI16(poi.w, poi.h)
|
||||
layer.blockLayer = arrayListOf(terr, wall)
|
||||
poi.layers.add(layer)
|
||||
|
||||
for (x in minX..maxX) {
|
||||
for (y in minY..maxY) {
|
||||
if (isMarked(x, y)) {
|
||||
terr.unsafeSetTile(x - minX, y - minY, ui.world.getTileFromTerrainRaw(x, y))
|
||||
wall.unsafeSetTile(x - minX, y - minY, ui.world.getTileFromWallRaw(x, y))
|
||||
}
|
||||
else {
|
||||
terr.unsafeSetTile(x - minX, y - minY, -1)
|
||||
wall.unsafeSetTile(x - minX, y - minY, -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// process POI for export
|
||||
val json = Common.jsoner
|
||||
val jsonStr = json.toJson(poi)
|
||||
|
||||
|
||||
val dir = App.defaultDir + "/Exports/"
|
||||
val dirAsFile = File(dir)
|
||||
if (!dirAsFile.exists()) {
|
||||
dirAsFile.mkdir()
|
||||
}
|
||||
|
||||
File(dirAsFile, "$name.poi").writeText(jsonStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Point2i.toAddr() = toAddr(this.x, this.y)
|
||||
private fun toAddr(x: Int, y: Int) = (y.toLong().shl(32) or x.toLong().and(0xFFFFFFFFL))
|
||||
|
||||
class YamlCommandClearSelection : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
val ui = (args[0] as BuildingMaker)
|
||||
try {
|
||||
(ui.selection.clone() as ArrayList<Long>).forEach { i ->
|
||||
ui.removeBlockMarker((i % 4294967296).toInt(), (i / 4294967296).toInt())
|
||||
}
|
||||
}
|
||||
catch (e: NullPointerException) {}
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandNewFlatTerrain : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
YamlCommandClearSelection().invoke(args)
|
||||
val ui = (args[0] as BuildingMaker)
|
||||
|
||||
println("[BuildingMaker] Generating builder world...")
|
||||
|
||||
val timeNow = System.currentTimeMillis() / 1000
|
||||
ui.gameWorld = GameWorld(90*12, 90*4, timeNow, timeNow)
|
||||
|
||||
for (y in 0 until ui.gameWorld.height) {
|
||||
ui.gameWorld.setTileWall(0, y, Block.ILLUMINATOR_RED, true)
|
||||
ui.gameWorld.setTileWall(ui.gameWorld.width - 1, y, Block.ILLUMINATOR_RED, true)
|
||||
ui.gameWorld.setTileTerrain(0, y, Block.ILLUMINATOR_RED_OFF, true)
|
||||
ui.gameWorld.setTileTerrain(ui.gameWorld.width - 1, y, Block.ILLUMINATOR_RED_OFF, true)
|
||||
}
|
||||
|
||||
for (y in 150 until ui.gameWorld.height) {
|
||||
for (x in 1 until ui.gameWorld.width - 1) {
|
||||
// wall layer
|
||||
ui.gameWorld.setTileWall(x, y, Block.DIRT, true)
|
||||
|
||||
// terrain layer
|
||||
ui.gameWorld.setTileTerrain(x, y, if (y == 150) Block.GRASS else Block.DIRT, true)
|
||||
}
|
||||
}
|
||||
ui.world = ui.gameWorld
|
||||
|
||||
|
||||
// set time to summer morning
|
||||
ui.gameWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
|
||||
ui.gameWorld.worldTime.setTimeOfToday(18062)
|
||||
|
||||
ui.reset()
|
||||
}
|
||||
}
|
||||
|
||||
class YamlCommandToolImportTest : YamlInvokable {
|
||||
override fun invoke(args: Array<Any>) {
|
||||
val ui = (args[0] as BuildingMaker)
|
||||
ui.getPoiNameForImport { name ->
|
||||
YamlCommandClearSelection().invoke(args)
|
||||
|
||||
val jsonFile = File(App.defaultDir, "/Exports/$name.poi")
|
||||
if (jsonFile.exists()) {
|
||||
val json = jsonFile.readText()
|
||||
|
||||
val poi = Common.jsoner.fromJson(PointOfInterest().javaClass, json).also {
|
||||
it.getReadyToBeUsed(ui.world.tileNameToNumberMap)
|
||||
}
|
||||
|
||||
ui.imported = poi
|
||||
ui.currentPenMode = BuildingMaker.PENMODE_IMPORT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class ChunkLoadingLoadScreen(screenToBeLoaded: IngameInstance, private val world
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
gdxClearAndEnableBlend(.094f, .094f, .094f, 0f)
|
||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
||||
|
||||
val drawWidth = Toolkit.drawWidth
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.IS_DEVELOPMENT_BUILD
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.blockproperties.BlockProp
|
||||
import net.torvald.terrarum.blockproperties.OreProp
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.itemproperties.CraftingCodex
|
||||
@@ -39,6 +40,7 @@ class EntryPoint : ModuleEntryPoint() {
|
||||
ModMgr.GameMaterialLoader.invoke(moduleName)
|
||||
ModMgr.GameItemLoader.invoke(moduleName)
|
||||
ModMgr.GameBlockLoader.invoke(moduleName)
|
||||
ModMgr.GameOreLoader.invoke(moduleName)
|
||||
ModMgr.GameLanguageLoader.invoke(moduleName)
|
||||
ModMgr.GameCraftingRecipeLoader.invoke(moduleName)
|
||||
|
||||
@@ -60,7 +62,7 @@ class EntryPoint : ModuleEntryPoint() {
|
||||
printdbg(this, "recording item ID ")
|
||||
|
||||
// blocks.csvs are loaded by ModMgr beforehand
|
||||
// block items (blocks and walls are the same thing basically)
|
||||
// register blocks as items
|
||||
for (tile in BlockCodex.getAll()) {
|
||||
ItemCodex[tile.id] = makeNewItemObj(tile, false)
|
||||
|
||||
@@ -93,7 +95,7 @@ class EntryPoint : ModuleEntryPoint() {
|
||||
private fun makeNewItemObj(tile: BlockProp, isWall: Boolean) = object : GameItem(
|
||||
if (isWall) "wall@"+tile.id else tile.id
|
||||
) {
|
||||
override var baseMass: Double = tile.density / 1000.0
|
||||
override var baseMass: Double = tile.density / 100.0
|
||||
override var baseToolSize: Double? = null
|
||||
override var inventoryCategory = if (isWall) Category.WALL else Category.BLOCK
|
||||
override var isDynamic = false
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
|
||||
import net.torvald.terrarum.realestate.LandUtil.CHUNK_W
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sqrt
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-30.
|
||||
*/
|
||||
open class FancyWorldReadLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidth: Int, private val worldheight: Int, override var preLoadJob: (LoadScreenBase) -> Unit) : LoadScreenBase() {
|
||||
|
||||
init {
|
||||
CommonResourcePool.addToLoadingList("basegame-gui-loadscrlayer01") {
|
||||
Texture(ModMgr.getGdxFile("basegame", "gui/loadscr_layer01.png"))
|
||||
}
|
||||
CommonResourcePool.addToLoadingList("basegame-gui-loadscrlayer02") {
|
||||
Texture(ModMgr.getGdxFile("basegame", "gui/loadscr_layer02.png"))
|
||||
}
|
||||
CommonResourcePool.addToLoadingList("basegame-gui-loadscrlayer03") {
|
||||
Texture(ModMgr.getGdxFile("basegame", "gui/loadscr_layer03.png"))
|
||||
}
|
||||
CommonResourcePool.loadAll()
|
||||
|
||||
App.disposables.add(this)
|
||||
}
|
||||
|
||||
|
||||
override var screenToLoad: IngameInstance? = screenToBeLoaded
|
||||
|
||||
val ratio = worldwidth * sqrt(2.0 / (worldwidth.sqr() + worldheight.sqr())) // world size is always wider than tall
|
||||
val htilesCount = worldwidth / CHUNK_W
|
||||
val vtilesCount = worldheight / CHUNK_H
|
||||
|
||||
val unitSize = ((540 * ratio) / htilesCount).roundToInt() // (visible tilesize + gapSize)
|
||||
val previewWidth = unitSize * htilesCount
|
||||
val previewHeight = unitSize * vtilesCount
|
||||
|
||||
val xoff = (Math.random() * (1024-764)/2).toInt()
|
||||
|
||||
val baseTileTex = arrayOf(
|
||||
CommonResourcePool.getAsTexture("basegame-gui-loadscrlayer01"),
|
||||
CommonResourcePool.getAsTexture("basegame-gui-loadscrlayer02"),
|
||||
CommonResourcePool.getAsTexture("basegame-gui-loadscrlayer03"),
|
||||
)
|
||||
|
||||
val drawWidth = Toolkit.drawWidth
|
||||
|
||||
val imgYoff = (252 - previewHeight * 0.28f).toInt()
|
||||
|
||||
val tiles = baseTileTex.map {
|
||||
TextureRegionPack(it, 1, imgYoff + previewHeight, 0, 0, xoff, 0)
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
||||
|
||||
App.batch.inUse { val it = it as FlippingSpriteBatch
|
||||
val previewX = (drawWidth - previewWidth).div(2f).roundToFloat()
|
||||
val previewY = (App.scr.height - previewHeight.times(1.5f)).div(2f).roundToFloat()
|
||||
|
||||
it.color = Color.BLACK
|
||||
Toolkit.fillArea(it, previewX, previewY, previewWidth.toFloat(), previewHeight.toFloat())
|
||||
|
||||
// it sets the colour by itself
|
||||
drawTiles(it, getStage(), getProgress(), previewX, previewY - imgYoff)
|
||||
|
||||
|
||||
it.color = Color.WHITE
|
||||
Toolkit.drawBoxBorder(it, previewX.toInt()-1, previewY.toInt()-1, previewWidth+2, previewHeight+2)
|
||||
val text = messages.getHeadElem() ?: ""
|
||||
App.fontGame.draw(it,
|
||||
text,
|
||||
(drawWidth - App.fontGame.getWidth(text)).div(2f).roundToFloat(),
|
||||
previewY + previewHeight + 98 - App.fontGame.lineHeight
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
super.render(delta)
|
||||
}
|
||||
|
||||
private val totalChunkCount = (worldwidth / CHUNK_W) * (worldheight / CHUNK_H)
|
||||
protected open fun getProgress(): Double {
|
||||
return progress.get().toDouble() / totalChunkCount * previewWidth
|
||||
}
|
||||
|
||||
protected open fun getStage(): Int {
|
||||
return 3 // fixed value for Read screen
|
||||
}
|
||||
|
||||
protected val batchColour = Color(-1) // create new Color instance just for the progress bar
|
||||
|
||||
protected open fun drawTiles(batch: FlippingSpriteBatch, layerCount: Int, tileCount: Double, x: Float, y: Float) {
|
||||
batch.color = batchColour
|
||||
for (layer in 0 until layerCount) {
|
||||
for (i in 0 until tileCount.ceilToInt()) {
|
||||
batch.color.a = (tileCount - i).toFloat().coerceIn(0f, 1f)
|
||||
batch.draw(tiles[layer].get(i, 0), x + i, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FancyWorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidth: Int, private val worldheight: Int) : FancyWorldReadLoadScreen(screenToBeLoaded, worldwidth, worldheight, {}) {
|
||||
|
||||
override fun getProgress(): Double {
|
||||
return progress.get().toDouble() / worldwidth * previewWidth
|
||||
}
|
||||
|
||||
override fun getStage(): Int {
|
||||
return stageValue
|
||||
}
|
||||
|
||||
override fun drawTiles(batch: FlippingSpriteBatch, layerCount: Int, tileCount: Double, x: Float, y: Float) {
|
||||
batch.color = batchColour
|
||||
for (layer in 0 until layerCount) {
|
||||
val isOldLayer = (layer != layerCount - 1)
|
||||
for (i in 0 until if (!isOldLayer) tileCount.ceilToInt() else previewWidth) {
|
||||
batch.color.a = if (!isOldLayer) (tileCount - i).toFloat().coerceIn(0f, 1f) else 1f
|
||||
batch.draw(tiles[layer].get(i, 0), x + i, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,6 +258,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
override var gameFullyLoaded = false
|
||||
internal set
|
||||
|
||||
override val musicGovernor = TerrarumMusicGovernor()
|
||||
|
||||
|
||||
//////////////
|
||||
@@ -489,7 +490,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
//WorldGenerator.SEED = worldParams.worldGenSeed
|
||||
//WorldGenerator.generateMap()
|
||||
Worldgen.attachMap(world, WorldgenParams(worldParams.worldGenSeed))
|
||||
Worldgen.generateMap()
|
||||
Worldgen.generateMap(App.getLoadScreen())
|
||||
|
||||
|
||||
historicalFigureIDBucket = ArrayList<Int>()
|
||||
@@ -731,7 +732,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
internal var autosaveTimer = 0f
|
||||
|
||||
override fun render(`_`: Float) {
|
||||
override fun render(updateRate: Float) {
|
||||
// Q&D solution for LoadScreen and Ingame, where while LoadScreen is working, Ingame now no longer has GL Context
|
||||
// there's still things to load which needs GL context to be present
|
||||
if (!gameFullyLoaded) {
|
||||
@@ -756,6 +757,8 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
gameFullyLoaded = true
|
||||
}
|
||||
|
||||
super.render(updateRate)
|
||||
|
||||
ingameController.update()
|
||||
|
||||
|
||||
@@ -883,12 +886,11 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
oldSelectedWireRenderClass = selectedWireRenderClass
|
||||
}
|
||||
|
||||
musicGovernor.update(this, delta)
|
||||
|
||||
////////////////////////
|
||||
// ui-related updates //
|
||||
////////////////////////
|
||||
//uiContainer.forEach { it.update(delta) }
|
||||
//debugWindow.update(delta)
|
||||
//notifier.update(delta)
|
||||
// open/close fake blur UI according to what's opened
|
||||
if (uiInventoryPlayer.isVisible ||
|
||||
getUIFixture.get()?.isVisible == true || worldTransitionOngoing) {
|
||||
@@ -1477,7 +1479,9 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
// resize UIs
|
||||
|
||||
notifier.setPosition(
|
||||
(drawWidth - notifier.width) / 2, App.scr.height - notifier.height)
|
||||
(Toolkit.drawWidth - notifier.width) / 2,
|
||||
App.scr.height - notifier.height - App.scr.tvSafeGraphicsHeight
|
||||
)
|
||||
uiQuickBar.setPosition((drawWidth - uiQuickBar.width) / 2, App.scr.tvSafeGraphicsHeight)
|
||||
|
||||
// inventory
|
||||
@@ -1520,6 +1524,8 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
catch (e: IllegalArgumentException) {}
|
||||
}
|
||||
|
||||
musicGovernor.dispose()
|
||||
|
||||
super.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
122
src/net/torvald/terrarum/modulebasegame/TerrarumMusicGovernor.kt
Normal file
122
src/net/torvald/terrarum/modulebasegame/TerrarumMusicGovernor.kt
Normal file
@@ -0,0 +1,122 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.audio.Music
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.unicode.EMDASH
|
||||
import java.io.File
|
||||
|
||||
data class MusicContainer(
|
||||
val name: String,
|
||||
val file: File,
|
||||
val gdxMusic: Music
|
||||
) {
|
||||
override fun toString() = if (name.isEmpty()) file.nameWithoutExtension else name
|
||||
}
|
||||
|
||||
class TerrarumMusicGovernor : MusicGovernor() {
|
||||
|
||||
private val songs: List<MusicContainer> =
|
||||
File(App.customMusicDir).listFiles()?.mapNotNull {
|
||||
printdbg(this, "Music: ${it.absolutePath}")
|
||||
try {
|
||||
MusicContainer(
|
||||
it.nameWithoutExtension.replace('_', ' ').split(" ").map { it.capitalize() }.joinToString(" "),
|
||||
it,
|
||||
Gdx.audio.newMusic(Gdx.files.absolute(it.absolutePath)).also {
|
||||
it.setOnCompletionListener {
|
||||
stopMusic()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
catch (e: GdxRuntimeException) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
} ?: emptyList() // TODO test code
|
||||
|
||||
private var musicBin: ArrayList<Int> = ArrayList(songs.indices.toList().shuffled())
|
||||
|
||||
|
||||
init {
|
||||
songs.forEach {
|
||||
App.disposables.add(it.gdxMusic)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var warningPrinted = false
|
||||
|
||||
|
||||
private val STATE_INIT = 0
|
||||
private val STATE_FIREPLAY = 1
|
||||
private val STATE_PLAYING = 2
|
||||
private val STATE_INTERMISSION = 3
|
||||
|
||||
|
||||
private fun stopMusic() {
|
||||
AudioManager.stopMusic()
|
||||
state = STATE_INTERMISSION
|
||||
intermissionAkku = 0f
|
||||
intermissionLength = 30f + 30f * Math.random().toFloat() // 30s-60s
|
||||
musicFired = false
|
||||
printdbg(this, "Intermission: $intermissionLength seconds")
|
||||
}
|
||||
|
||||
private fun startMusic(song: MusicContainer) {
|
||||
AudioManager.startMusic(song)
|
||||
printdbg(this, "Now playing: $song")
|
||||
INGAME.sendNotification("Now Playing $EMDASH ${song.name}")
|
||||
state = STATE_PLAYING
|
||||
}
|
||||
|
||||
|
||||
override fun update(ingame: IngameInstance, delta: Float) {
|
||||
if (songs.isEmpty()) {
|
||||
if (!warningPrinted) {
|
||||
warningPrinted = true
|
||||
printdbg(this, "Warning: songs list is empty")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// val ingame = ingame as TerrarumIngame
|
||||
if (state == 0) state = STATE_INTERMISSION
|
||||
|
||||
|
||||
when (state) {
|
||||
STATE_FIREPLAY -> {
|
||||
if (!musicFired) {
|
||||
musicFired = true
|
||||
|
||||
val song = songs[musicBin.removeAt(0)]
|
||||
// prevent same song to play twice
|
||||
if (musicBin.isEmpty()) {
|
||||
musicBin = ArrayList(songs.indices.toList().shuffled())
|
||||
}
|
||||
|
||||
startMusic(song)
|
||||
}
|
||||
}
|
||||
STATE_PLAYING -> {
|
||||
// stopMusic() will be called when the music finishes; it's on the setOnCompletionListener
|
||||
}
|
||||
STATE_INTERMISSION -> {
|
||||
intermissionAkku += delta
|
||||
|
||||
if (intermissionAkku >= intermissionLength) {
|
||||
intermissionAkku = 0f
|
||||
state = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
stopMusic()
|
||||
}
|
||||
}
|
||||
@@ -175,6 +175,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
printdbg(this, "Demo world not found, using empty world")
|
||||
}
|
||||
|
||||
demoWorld.renumberTilesAfterLoad()
|
||||
this.world = demoWorld
|
||||
|
||||
// set initial time to summer
|
||||
@@ -301,6 +302,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
private var introUncoverDeltaCounter = 0f
|
||||
|
||||
override fun render(updateRate: Float) {
|
||||
super.render(updateRate)
|
||||
// async update and render
|
||||
gameUpdateGovernor.update(Gdx.graphics.deltaTime, App.UPDATE_RATE, updateScreen, renderScreen)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.ui.*
|
||||
import net.torvald.terrarum.ui.UIItemTextButtonList.Companion.DEFAULT_BACKGROUNDCOL
|
||||
import net.torvald.terrarum.ui.UINSMenu.Companion.LINE_HEIGHT
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class UIBuildingMakerGetFilename : UICanvas() {
|
||||
|
||||
var confirmCallback: (String) -> Unit = {}
|
||||
var cancelCallback: () -> Unit = {}
|
||||
var title = "Export"
|
||||
var text = listOf("")
|
||||
|
||||
var labelDo = "OK"
|
||||
var labelDont = "Cancel"
|
||||
|
||||
override var width = 280
|
||||
override var height = 160
|
||||
|
||||
private val textWidth = width - LINE_HEIGHT
|
||||
private val buttonWidth = 101
|
||||
private val buttonGap = (width - buttonWidth*2) / 3
|
||||
|
||||
override var openCloseTime = OPENCLOSE_GENERIC
|
||||
|
||||
val textInput = UIItemTextLineInput(
|
||||
this,
|
||||
(width - textWidth) / 2,
|
||||
LINE_HEIGHT * (text.size + 2),
|
||||
textWidth,
|
||||
{ "The Yucky Panopticon" },
|
||||
InputLenCap(250, InputLenCap.CharLenUnit.UTF8_BYTES)
|
||||
)
|
||||
|
||||
val buttonOk = UIItemTextButton(
|
||||
this,
|
||||
{ labelDo },
|
||||
buttonGap,
|
||||
height - LINE_HEIGHT - LINE_HEIGHT/2,
|
||||
buttonWidth
|
||||
).also {
|
||||
it.clickOnceListener = { _, _ ->
|
||||
|
||||
textInput.getTextOrPlaceholder().let { name ->
|
||||
if (name.isNotBlank())
|
||||
confirmCallback(name.trim())
|
||||
}
|
||||
|
||||
this.setAsClose()
|
||||
}
|
||||
}
|
||||
|
||||
val buttonCancel = UIItemTextButton(
|
||||
this,
|
||||
{ labelDont },
|
||||
width - buttonWidth - buttonGap,
|
||||
height - LINE_HEIGHT - LINE_HEIGHT/2,
|
||||
buttonWidth
|
||||
).also {
|
||||
it.clickOnceListener = { _, _ ->
|
||||
reset()
|
||||
cancelCallback()
|
||||
this.setAsClose()
|
||||
}
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
textInput.clearText()
|
||||
}
|
||||
|
||||
init {
|
||||
addUIitem(textInput)
|
||||
addUIitem(buttonOk)
|
||||
addUIitem(buttonCancel)
|
||||
}
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
uiItems.forEach { it.update(delta) }
|
||||
}
|
||||
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: OrthographicCamera) {
|
||||
blendNormalStraightAlpha(batch)
|
||||
|
||||
// draw border
|
||||
batch.color = Toolkit.Theme.COL_INACTIVE
|
||||
Toolkit.drawBoxBorder(batch, -1, -1 - LINE_HEIGHT, width + 2, height + LINE_HEIGHT + 2)
|
||||
|
||||
// draw title bar
|
||||
batch.color = UINSMenu.DEFAULT_TITLEBACKCOL
|
||||
Toolkit.fillArea(batch, 0, 0 - LINE_HEIGHT, width, LINE_HEIGHT)
|
||||
|
||||
batch.color = UINSMenu.DEFAULT_TITLETEXTCOL
|
||||
App.fontGame.draw(batch, title, UINSMenu.TEXT_OFFSETX + 0, UINSMenu.TEXT_OFFSETY + 0 - LINE_HEIGHT)
|
||||
|
||||
// draw the back
|
||||
batch.color = DEFAULT_BACKGROUNDCOL
|
||||
Toolkit.fillArea(batch, 0, 0, width, height)
|
||||
|
||||
|
||||
// draw the list
|
||||
batch.color = Color.WHITE
|
||||
val textWidth: Int = text.maxOf { App.fontGame.getWidth(it) }
|
||||
|
||||
text.forEachIndexed { index, str ->
|
||||
App.fontGame.draw(batch, str, 0 + LINE_HEIGHT / 2, 0 + LINE_HEIGHT / 2 + LINE_HEIGHT * index)
|
||||
}
|
||||
|
||||
uiItems.forEach { it.render(batch, camera) }
|
||||
}
|
||||
|
||||
private var dragOriginX = 0 // relative mousepos
|
||||
private var dragOriginY = 0 // relative mousepos
|
||||
private var dragForReal = false
|
||||
|
||||
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||
if (mouseInScreen(screenX, screenY)) {
|
||||
if (dragForReal) {
|
||||
handler.setPosition(
|
||||
(screenX / App.scr.magn - dragOriginX).roundToInt(),
|
||||
(screenY / App.scr.magn - dragOriginY).roundToInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
uiItems.forEach { it.touchDragged(screenX, screenY, pointer) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun mouseOnTitleBar() =
|
||||
relativeMouseX in 0 until width && relativeMouseY in -LINE_HEIGHT until 0
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
if (mouseOnTitleBar()) {
|
||||
dragOriginX = relativeMouseX
|
||||
dragOriginY = relativeMouseY
|
||||
dragForReal = true
|
||||
}
|
||||
else {
|
||||
dragForReal = false
|
||||
}
|
||||
|
||||
uiItems.forEach { it.touchDown(screenX, screenY, pointer, button) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
uiItems.forEach { it.tryDispose() }
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class WorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidt
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
gdxClearAndEnableBlend(.094f, .094f, .094f, 0f)
|
||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
||||
|
||||
val drawWidth = Toolkit.drawWidth
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user