Compare commits

...

143 Commits

Author SHA1 Message Date
minjaesong
4510cbb617 using gdx functions for clipboard 2023-11-08 23:46:48 +09:00
minjaesong
2f11988353 updating Gdx.audio on separate thread 2023-11-08 23:42:17 +09:00
minjaesong
beb7f1fb73 music disc jockeying wip 2023-11-08 16:59:22 +09:00
minjaesong
31b328fb48 option and warning msg for loading script mods 2023-11-08 13:10:42 +09:00
minjaesong
797bad3014 audiomanager wip 2023-11-07 18:44:58 +09:00
minjaesong
5d32e6da33 terrain is harder to get damaged by falling 2023-11-07 17:00:05 +09:00
minjaesong
bf2826438f radar ringing artefacts simulation 2023-11-07 16:40:06 +09:00
minjaesong
e4dc3ac146 worldgen estimation change 2023-11-07 14:43:36 +09:00
minjaesong
19f08de756 fix: pickaxe tooltip showing when other overlaying UI is opened 2023-11-07 14:43:15 +09:00
minjaesong
94a207d72a loadscreen texts 2023-11-07 00:38:33 +09:00
minjaesong
3cc51aa774 settings menu reordering 2023-11-07 00:19:35 +09:00
minjaesong
6f0f756fe4 new oregen params 2023-11-06 22:54:56 +09:00
minjaesong
37138656f8 item codes for ores 2023-11-06 21:22:39 +09:00
minjaesong
026cfa5284 more ores 2023-11-06 21:07:12 +09:00
minjaesong
31e19874ae more ores 2023-11-06 20:36:10 +09:00
minjaesong
f2974fc854 more ore variants 2023-11-06 18:16:37 +09:00
minjaesong
a3e0f7b0b3 splash screen default backdrop is now image; logo customisation via mod 2023-11-05 12:18:46 +09:00
minjaesong
98c94017ba faster window startup by deferring postinit
...for real this time
2023-11-05 01:33:50 +09:00
minjaesong
4bea5e9bf9 different randomising for different layers 2023-11-04 21:49:40 +09:00
minjaesong
79ffaf6294 ore autotiling and tile randomiser to use BlockAddr 2023-11-04 19:21:12 +09:00
minjaesong
cada008fca randomised tiling fixes 2023-11-04 18:44:10 +09:00
minjaesong
46234d3d9d assets updates for randomised tiling 2023-11-04 17:45:31 +09:00
minjaesong
eaef2f0c6a randomised tiling 2023-11-04 17:21:15 +09:00
minjaesong
6ae39d38e3 cavegen after the oregen 2023-11-04 00:54:15 +09:00
minjaesong
1128fb7f0e radar penetration sim 2023-11-02 22:08:44 +09:00
minjaesong
3acefebfcb gaussian blurring on the radar reading 2023-11-02 13:01:35 +09:00
minjaesong
1ddd012e19 fix app-breaking typo 2023-11-02 01:32:09 +09:00
minjaesong
4cffe64286 rcs for sands 2023-11-02 00:53:27 +09:00
minjaesong
8a1dfbeedd radar code cleanup 2023-11-02 00:36:16 +09:00
minjaesong
47a7e55910 radar reading rcs from materials 2023-11-02 00:15:08 +09:00
minjaesong
1aa00d564d more plausible ground radar (2) 2023-11-01 21:24:03 +09:00
minjaesong
4c04267cb8 more plausible ground radar 2023-11-01 19:46:30 +09:00
minjaesong
b39a4bd008 ground radar: using linear gamma 2023-11-01 18:19:47 +09:00
minjaesong
b49556a5a1 test ground radar thing 2023-11-01 16:22:47 +09:00
minjaesong
9bb7ab6956 non solid block can be place over actors 2023-11-01 15:19:19 +09:00
minjaesong
b0bdfd9f43 locale update 2023-11-01 12:26:52 +09:00
minjaesong
2be8bb2aea black background to the load bar 2023-10-31 17:42:12 +09:00
minjaesong
6b24182de2 smooth progress bar 2023-10-31 16:22:38 +09:00
minjaesong
15f27726b8 loadscr texture stylised 2023-10-31 15:37:43 +09:00
minjaesong
cbbe5d3e34 worldgen estimation change; common worldgen variables moved to Worldgen.kt 2023-10-31 15:18:51 +09:00
minjaesong
706f5ac507 separating stage value from the progress 2023-10-31 14:29:29 +09:00
minjaesong
aef55bdc22 lesser actor speed mult for landing-on-ground particle 2023-10-31 14:28:50 +09:00
minjaesong
fa21800541 ore texture retrieved from old laptop 2023-10-31 01:44:34 +09:00
minjaesong
8d23714832 rudimentary randomisation for loadscreen tiles 2023-10-31 00:51:56 +09:00
minjaesong
ef6aa842c8 smaller tile gap 2023-10-31 00:15:32 +09:00
minjaesong
0079bc5378 new loadscreen for worldgen 2023-10-31 00:11:43 +09:00
minjaesong
3f3e4ad2e7 working new loadscreen (not worldgen) 2023-10-30 21:47:31 +09:00
minjaesong
4c09588dc2 new loadscreen mockup 2023-10-30 20:53:49 +09:00
minjaesong
3764ee21e9 new loadscreen assets 2023-10-30 17:24:36 +09:00
minjaesong
f199307353 worldgen sliced evenly 2023-10-30 17:24:00 +09:00
minjaesong
4244a2c395 exportmap cmd reworked 2023-10-30 16:43:34 +09:00
minjaesong
6df348bf86 materialid for ore items 2023-10-30 00:40:29 +09:00
minjaesong
b8b0611479 ore item sprites 2023-10-29 23:12:25 +09:00
minjaesong
4de7722fc3 shorter music intermission 2023-10-29 18:45:09 +09:00
minjaesong
4262dbec5e default light passes to 3 2023-10-29 18:26:51 +09:00
minjaesong
868e41ee70 yet yet another coal 2023-10-29 16:19:49 +09:00
minjaesong
f07182dfb6 yet another coal layer texture 2023-10-29 15:04:02 +09:00
minjaesong
56974eeb8c removed bad import 2023-10-29 02:04:49 +09:00
minjaesong
757207cf9b lightbox fixed once again 2023-10-29 02:03:47 +09:00
minjaesong
cc5b9616fe new ore gen params 2023-10-29 01:06:06 +09:00
minjaesong
f7c32e74cd max light pass limited to 4 2023-10-29 00:30:44 +09:00
minjaesong
33e93b8e10 new config for light update pass count 2023-10-28 23:57:40 +09:00
minjaesong
acae5dab8b better ore texture 2023-10-28 23:15:56 +09:00
minjaesong
991a16e6a7 btex using xml wip 2023-10-28 16:51:23 +09:00
minjaesong
76d6579ce9 new oregen param: ratio 2023-10-28 16:49:34 +09:00
minjaesong
208bf79353 fix: rapid typing of bksp-char would be recognised as two bksp 2023-10-27 20:55:23 +09:00
minjaesong
00f8d8f850 text updates 2023-10-27 15:16:37 +09:00
minjaesong
0f82a67a63 cursor sprite 2023-10-27 15:15:13 +09:00
minjaesong
23a78fc345 pickaxe: hide tooltip when unequipped 2023-10-27 15:13:48 +09:00
minjaesong
ffac61fbc5 options for ore spawn tiling; actual ore tile textures 2023-10-27 13:21:29 +09:00
minjaesong
19f1eb2278 pickaxe ore tooltip; working item pickup and throw effects 2023-10-27 02:55:13 +09:00
minjaesong
012d3482dc worldgen: actually generating ores 2023-10-26 15:37:48 +09:00
minjaesong
2bd54c8316 ore generation test 2023-10-26 00:10:45 +09:00
minjaesong
1667e622bd hematite sprite 2023-10-25 20:07:06 +09:00
minjaesong
9da2be0b17 removing stray pixels of an acorn 2023-10-25 19:34:50 +09:00
minjaesong
c83c83a395 current terragen code backported to the noise sandbox 2023-10-25 18:26:44 +09:00
minjaesong
8e2f3254ff oregen test 2023-10-25 17:05:42 +09:00
minjaesong
98813fb4df buildingmaker: zoom using z key 2023-10-25 14:17:08 +09:00
minjaesong
9a233b8c55 buildingmaker: better handling of mouse latching for pens 2023-10-25 13:46:28 +09:00
minjaesong
98d7c9f326 jsoner is always newly generated when accessed 2023-10-24 22:25:13 +09:00
minjaesong
43cb9ec00e buildingmaker: palette can stay open for painting 2023-10-24 20:02:01 +09:00
minjaesong
074c27c6cc config: empty resolution input to use default; also accepts 720p and 1080p 2023-10-24 17:25:20 +09:00
minjaesong
5322cb7b2b buildingmaker: ore pen wip 2023-10-24 17:14:11 +09:00
minjaesong
a8b44c1cac buildingmaker import pen click latch 2023-10-24 16:49:04 +09:00
minjaesong
a5a2c98041 buildingmaker: import penmode 2023-10-24 14:21:53 +09:00
minjaesong
18ab292e24 buildingmaker: import using filename 2023-10-24 13:47:16 +09:00
minjaesong
9145acf741 buildingmaker palette titlebar colour change 2023-10-24 13:07:35 +09:00
minjaesong
228b0962d6 splash screen backdrop 2023-10-24 12:48:10 +09:00
minjaesong
18b2b3c8d6 add: POI Editor on the locale 2023-10-24 01:13:08 +09:00
minjaesong
d1d75b88ca export poi to file 2023-10-23 22:25:33 +09:00
minjaesong
d9deabb644 fix: buildingmaker exporter still reads deselected tile 2023-10-23 18:28:08 +09:00
minjaesong
a432099f19 poi import wip 2023-10-23 17:08:40 +09:00
minjaesong
5806388bee poi read wip 2023-10-23 15:46:12 +09:00
minjaesong
56d915cd71 more item sprites 2023-10-23 13:01:10 +09:00
minjaesong
143f789ea1 more item sprites 2023-10-23 02:16:34 +09:00
minjaesong
1b2940637c more item sprites 2023-10-23 00:46:25 +09:00
minjaesong
872ab8d946 more buildingmaker functions 2023-10-22 14:27:38 +09:00
minjaesong
ed2a46e1a6 poi json out test 2023-10-22 13:42:36 +09:00
minjaesong
d53ab6ffee json out test wip 2023-10-22 01:24:03 +09:00
minjaesong
69345eab57 queueing for notifications 2023-10-21 21:29:14 +09:00
minjaesong
6e90d3521b buildingmaker working terrain/wall palette 2023-10-21 20:03:03 +09:00
minjaesong
e88b595320 more test music play stuffs 2023-10-21 18:33:13 +09:00
minjaesong
f37a28eb17 test play music from appdata/Custom/Music 2023-10-21 15:08:55 +09:00
minjaesong
d57f23d4f1 remaining time gauge for notifier 2023-10-21 02:47:55 +09:00
minjaesong
6634a8dccb poi wip 2023-10-20 20:24:14 +09:00
minjaesong
647c7ea865 gamemode on savegame format 2023-10-20 20:23:38 +09:00
minjaesong
90eb033431 another way to scroll 2023-10-16 23:50:33 +09:00
minjaesong
20f2f2f7b1 buildingmaker palette 2023-10-15 12:39:04 +09:00
minjaesong
1af172d354 buildingmaker palette scrollbar 2023-10-15 12:04:32 +09:00
minjaesong
35c46d9a91 buildingmaker markers working again 2023-10-15 01:42:03 +09:00
minjaesong
8613d804e7 tile number change 2023-10-15 00:27:42 +09:00
minjaesong
1cce4e6ee2 tree foliage tiles 2023-10-15 00:01:52 +09:00
minjaesong
0a65794756 more buildingmaker ui stuffs 2023-10-14 22:01:41 +09:00
minjaesong
d5074e30eb UINSMenu is working again 2023-10-14 20:56:03 +09:00
minjaesong
228c9b8127 buildingmaker resurrection wip 2023-10-14 18:42:06 +09:00
minjaesong
3c79586410 particles to spawn on their true position 2023-10-14 18:06:15 +09:00
minjaesong
d546b081f0 mod config 2023-10-14 16:24:12 +09:00
minjaesong
4362966128 super rudimentary mod config 2023-10-14 15:34:04 +09:00
minjaesong
108c4d3e3f phys: reduced number of collision checks on x axis 2023-10-14 03:34:53 +09:00
minjaesong
fd65541c35 fall damage deals terrain damage 2023-10-14 03:21:42 +09:00
minjaesong
65997764e6 particles when actors collide the world 2023-10-14 02:26:13 +09:00
minjaesong
d8abec381b wooden pickaxe adjustments 2023-10-12 19:54:16 +09:00
minjaesong
58fa1dd56c particles when blocks are being mined 2023-10-12 15:47:51 +09:00
minjaesong
93f1430c5c more particles 2023-10-12 14:58:01 +09:00
minjaesong
93d33b793c better particle emission on block break 2023-10-12 14:28:39 +09:00
minjaesong
3a3d789777 particles to disappear when it hits the ground 2023-10-12 01:56:07 +09:00
minjaesong
6bf535e968 pick and hammer spawns particles 2023-10-12 01:47:00 +09:00
minjaesong
00ca1d3e1a self-connect tiles are working again 2023-10-11 20:33:36 +09:00
minjaesong
552cfd5f06 pickaxe to drop ores when they were mined 2023-10-11 17:59:10 +09:00
minjaesong
e63300339e corner occlusion should render now 2023-10-11 02:51:50 +09:00
minjaesong
1e15719b9c overlaying tile breakage over ores 2023-10-10 20:08:55 +09:00
minjaesong
64d30728ff removing terrain block also removes its ore 2023-10-10 18:45:58 +09:00
minjaesong
3b32242a2b tiling optimisation 2.2ms -> 1.7ms 2023-10-10 18:16:35 +09:00
minjaesong
26936fde09 fluids to their own block layer 2023-10-10 05:33:40 +09:00
minjaesong
caffdbf861 save/load ore layer 2023-10-10 04:10:05 +09:00
minjaesong
e76ff58b3e Generalised BlockLayer 2023-10-10 03:56:02 +09:00
minjaesong
8f1ca485f6 adding ore textures to the atlas 2023-10-10 01:20:04 +09:00
minjaesong
23c445f014 new layer 'ores' 2023-10-09 19:38:04 +09:00
minjaesong
d9218a2dd6 fluids separated from blocks 2023-10-09 17:35:26 +09:00
minjaesong
dd1e53f761 saved game will not be loaded if it's newer than the current version 2023-10-09 15:17:24 +09:00
minjaesong
d8cafe7f12 new item sprite: woods 2023-10-09 02:19:20 +09:00
minjaesong
ae3a6e9c61 materials update 2023-10-08 03:43:26 +09:00
minjaesong
f5bc2c9be3 removing 'GAME_ACTION_CRAFT' from the custom locales: already exists on the Polyglot 2023-10-08 01:37:07 +09:00
190 changed files with 6999 additions and 1921 deletions

Binary file not shown.

Binary file not shown.

BIN
assets/graphics/logo.png LFS Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -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",

View File

@@ -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 youre 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."
}

View File

@@ -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": "성능",

View File

@@ -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신뢰할 수 있는 모드만을 사용하십시오."
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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.

View 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>

View 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}

View 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>

View File

@@ -3,6 +3,7 @@ CheatWarnTest
CodexEdictis
ExportCodices
ExportMap
ExportMap2
ExportWorld
ForceGC
GetAV
1 CatStdout
3 CodexEdictis
4 ExportCodices
5 ExportMap
6 ExportMap2
7 ExportWorld
8 ForceGC
9 GetAV

View 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
1 ->Lang:MENU_OPTIONS_GAMEPLAY->h1
2 gameplay_max_crafting->Lang:MENU_OPTIONS_MAX_CRAFTING->spinner,100,1000,100
3 showpickaxetooltip->Lang:MENU_OPTIONS_SHOW_ORES_TOOLTIP_WHEN_MINING->toggle

View File

@@ -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

View 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
}

View File

@@ -1,3 +1,4 @@
{
"gameplay_max_crafting": 100
"gameplay_max_crafting": 100,
"showpickaxetooltip": true
}

View 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"
1 id name shdr shdg shdb shduv str dsty mate lumr lumg lumb lumuv colour vscs refl tags
2 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
3 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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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
1 id classname
12 11 net.torvald.terrarum.modulebasegame.gameitems.ItemWallCalendar
13 12 net.torvald.terrarum.modulebasegame.gameitems.SledgehammerCopper
14 13 net.torvald.terrarum.modulebasegame.gameitems.SledgehammerSteel
15 16 14 net.torvald.terrarum.modulebasegame.gameitems.ItemWorkbench net.torvald.terrarum.modulebasegame.gameitems.PickaxeWood
16 15 net.torvald.terrarum.modulebasegame.gameitems.SledgehammerWood
17 256 16 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak net.torvald.terrarum.modulebasegame.gameitems.ItemWorkbench
18 17 net.torvald.terrarum.modulebasegame.gameitems.ItemCoalCoke
19 128 net.torvald.terrarum.modulebasegame.gameitems.OreCopper
20 129 net.torvald.terrarum.modulebasegame.gameitems.OreIron
21 130 net.torvald.terrarum.modulebasegame.gameitems.OreCoal
22 131 net.torvald.terrarum.modulebasegame.gameitems.OreZinc
23 132 net.torvald.terrarum.modulebasegame.gameitems.OreTin
24 133 net.torvald.terrarum.modulebasegame.gameitems.OreGold
25 134 net.torvald.terrarum.modulebasegame.gameitems.OreSilver
26 256 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
27 257 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony
28 258 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorBirch
29 259 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorRosewood

Binary file not shown.

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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": "살얼음",

View File

@@ -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": "텔레포트하기",

View File

@@ -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": "강철 곡괭이",

View File

@@ -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
#
1 idst tens impf dsty fmod endurance tcond reach rcs comments
2 ROCK WOOD 15 10 210 10 3000 800 1 0.42 0.173 1.0 0.17 5 18 data is that of marble just a generic wood
3 OORE ROCK 15 210 3000 1 0.42 1.0 2.9 5 48 data is that of marble
4 OGEM OORE 15 210 3000 1 0.42 1.0 2.9 5 100 data is that of marble
5 CUPR OGEM 210 15 770 210 8960 3000 2 1 1.00 0.42 401.0 2.9 5 80 copper data is that of marble
6 EGLS CUPR 33 210 1000 770 2325 8960 4 2 0.82 1.00 1.0 401.0 6 5 120 elven glass/moldavite copper
7 IRON EGLS 350 33 1085 1000 7874 2325 5 4 1.42 0.82 1.0 6 10 not wrought iron,just natural iron elven glass/moldavite
8 ARGN IRON 170 350 595 1085 10490 7874 9 5 0.91 1.42 1.0 80.4 6 120 argentum/silver not wrought iron,just natural iron
9 STAL ARGN 531 170 2520 595 7874 10490 14 9 1.73 0.91 1.0 429.0 7 6 120 steel argentum/silver
10 EAUR AURM 768 120 0 350 8192 19300 21 9 1.36 0.88 1.0 318.0 7 6 120 elven aurichalcum aurum/gold
11 TIAL STAL 900 531 0 2520 4420 7874 33 14 2.16 1.73 1.0 26.0 8 7 120 titanium alloy (Ti6Al4V) steel
12 ADMT EAUR 2000 768 4090 0 2700 8192 71 21 3.42 1.36 1.0 8 7 120 adamant elven aurichalcum
13 OOZE TIAL 20 900 0 1000 4420 1 33 0.08 2.16 0.5 1.0 0 8 120 genetic ooze,data is about human skin titanium alloy (Ti6Al4V)
14 BONE ADMT 130 2000 0 4090 2000 2700 1 71 0.23 3.42 0.55 1.0 4 8 120 data is that of bovine bone adamant
15 OOZE 20 0 1000 1 0.08 0.5 0 10 genetic ooze,data is about human skin
16 BONE 130 0 2000 1 0.23 0.55 4 10 data is that of bovine bone
17 BRAS 315 1015 8530 3 1.00 120 5 120 brass
18 BRNZ 310 843 8770 3 1.20 75 5 120 bronze
19 TINN 220 350 7310 2 1.00 69 5 120 tin
20 ZINC 90 525 7140 2 1.00 116 5 120 zinc
21 DIRT 1 1 1400 0.0 0.0 36 0 10 dirt
22 PLST 1 1 1400 0.0 0.0 36 0 16 TODO plastic (polyethylene)
23 AIIR 1 1 1 0.0 0.0 36 0 1 air
24 SAND 1 1 2400 0.0 0.0 36 0 36 sand
25 GRVL 1 1 2400 0.0 0.0 36 0 36 gravel
26 # idst: ID_STRING, ALL CAPS
27 #
28 # tens: tensile strength (= ultimate stringth)
44 # reach: Tool Reach in blocks. Default is 6 (iron)
45 #
46 # Comments: do nothing # rcs: Radar Cross Section -- how well the material reflects the radio wave used by the Ground Penetrating Radar.
47 #
48 # Comments: do nothing do not parse
49 #
50 ## These values are being used by the phys simulator (blocks) and for attack power calculation (items)
51

View File

@@ -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

Binary file not shown.

BIN
assets/mods/basegame/ores/2.tga LFS Normal file

Binary file not shown.

BIN
assets/mods/basegame/ores/3.tga LFS Normal file

Binary file not shown.

BIN
assets/mods/basegame/ores/4.tga LFS Normal file

Binary file not shown.

BIN
assets/mods/basegame/ores/5.tga LFS Normal file

Binary file not shown.

BIN
assets/mods/basegame/ores/6.tga LFS Normal file

Binary file not shown.

BIN
assets/mods/basegame/ores/7.tga LFS Normal file

Binary file not shown.

View 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.

View 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
1 id freq power scale ratio tiling comment
2 1 0.032 0.010 0.507 1.0 a16x16 copper (malachite)
3 2 0.056 0.011 0.507 1.0 a16x16 iron (haematite)
4 3 0.021 0.070 0.501 3.8 a16x4 coal
5 4 0.024 0.011 0.501 1.0 a16x16 zinc (sphalerite)
6 5 0.021 0.020 0.501 1.0 a16x16 tin (cassiterite)
7 6 0.011 0.300 0.465 1.0 a16x16 natural gold
8 7 0.016 0.300 0.467 1.0 a16x16 natural silver
9 ################################################################################
10 # id: ore ID to spawn, the ID must exist on the ores.csv
11 #
12 # freq: frequency value used to set up noise generator. Larger = ore veins are closer together
13 # 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
14 # 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
15 # ratio: how elongated (or squeeze) the ore veins are. >1.0 = stretched horizontally, <1.0 = stretched vertically
16 #
17 # tiling: determines how the tiles are tiled
18 # - a16: use 4-neighbour autotiling (16 possible cases)
19 # - a16x4: 4 variants of a16 (typically 4 rotations, or 2 rotations x 2 flips)
20 # - a16x8: 8 variants of a16 (typically 4 rotations x 2 flips) -- horz/vert flip do not matter, both produces same sets of shapes
21 # - a16x16: 16 variants of a16 (typically 4 rotations x 2 flips x 2 styles)
22 # - a47: use 8-neighbour autotiling (47 possible cases)
23 # - a47x4: 4 variants of a47 (typically 4 rotations, or 2 rotations x 2 flips)
24 # - r16: use the hash of the tile position as a variant selection, module 16
25 # - r8: use the hash of the tile position as a variant selection, module 8
26 #
27 # comment: human-readable comments, not actually parsed

Binary file not shown.

View 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;
}
}

View 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")
}
}

View 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) {
}

View File

@@ -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);
}
}
}

View 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
}
}
}

View 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
}
}
}
}

View File

@@ -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,

View File

@@ -128,6 +128,10 @@ object DefaultConfig {
"bgmvolume" to 1.0,
"sfxvolume" to 1.0,
"lightpasses" to 3,
"enablescriptmods" to false,
// settings regarding debugger

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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

View File

@@ -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/"

View File

@@ -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() {

View 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() {
}
}

View File

@@ -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) {

View File

@@ -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
)

View File

@@ -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() }
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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,

View File

@@ -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]

View File

@@ -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
}

View 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 = ""
}

View 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)
}

View File

@@ -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

View File

@@ -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()
}

View File

@@ -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"
}

View File

@@ -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 {

View File

@@ -198,6 +198,8 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
).let { drop ->
INGAME.queueActorAddition(drop)
}
// apply item effect
ItemCodex[item]!!.effectOnThrow(player)
}
}
}

View File

@@ -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))
}

View File

@@ -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@")

View File

@@ -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) {

View File

@@ -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
}
}
/**

View File

@@ -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
}
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View File

@@ -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
}

View File

@@ -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)
}
/**

View File

@@ -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
}

View File

@@ -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
}
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
}
}
}

View File

@@ -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()
}
}

View 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()
}
}

View File

@@ -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)
}

View File

@@ -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() }
}
}

View File

@@ -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