Compare commits

..

84 Commits

Author SHA1 Message Date
minjaesong
aa2172b396 forgot to remove snapshot info 2024-03-28 00:46:40 +09:00
minjaesong
f3e2fa8441 Alpha 1.2 release candidate 2024-03-28 00:43:18 +09:00
minjaesong
a3d132d26c itemdesc change for solder wire 2024-03-27 23:47:42 +09:00
minjaesong
a4afb0bfe9 item autoreload is restricted to tools only 2024-03-24 03:55:06 +09:00
minjaesong
67092d4ab9 alloy yield doubled; turntable now requires brass for crafting 2024-03-23 23:47:20 +09:00
minjaesong
07680592d2 fix: text pos for sign preview wouldnt match the text on the fixture 2024-03-22 23:14:57 +09:00
minjaesong
844ec6bd4f recipe for engraving workbench 2024-03-22 22:27:47 +09:00
minjaesong
c87bd182b0 fix: text cursor darting around everywhere 2024-03-22 22:15:27 +09:00
minjaesong
6d2764933f better element positioning 2024-03-22 21:49:51 +09:00
minjaesong
d4672df208 sign engraver ui 2024-03-22 21:37:56 +09:00
minjaesong
4d1ea45a0f sign engraver wip 3 2024-03-22 21:15:39 +09:00
minjaesong
8e1c586a5c sign engraver wip 2 2024-03-22 20:52:19 +09:00
minjaesong
7690d3d672 sign engraver wip 2024-03-22 18:34:34 +09:00
minjaesong
8e8c206e3a engraver sprite 2024-03-22 04:16:08 +09:00
minjaesong
d35a73c7a5 signs persisting through load/save 2024-03-21 20:57:12 +09:00
minjaesong
ec76eb2685 THE cheapest way to resolve right-sided phys bug 2024-03-21 14:25:41 +09:00
minjaesong
a1a6dc5801 more sign stuffs 2024-03-21 00:42:34 +09:00
minjaesong
708dccb015 working sign 2024-03-20 22:32:09 +09:00
minjaesong
4e739963d3 copper sign actually spawns but still wip 2024-03-20 14:44:26 +09:00
minjaesong
8bf3d9666f test copper sign and it has no sprite 2024-03-20 03:33:24 +09:00
minjaesong
b856574d20 fix: multimeter's block cursor would break fixture ghost 2024-03-19 04:55:37 +09:00
minjaesong
f696a54d2d text sign wip 2 2024-03-18 03:46:15 +09:00
minjaesong
ca766719d3 text sign wip 2024-03-18 01:01:11 +09:00
minjaesong
d027ff7d7e toned down label colour 2024-03-17 23:35:38 +09:00
minjaesong
2785a67823 fix: item desc 2024-03-17 20:26:12 +09:00
minjaesong
33671d6e52 labels for inventory side buttons 2024-03-17 19:51:40 +09:00
minjaesong
7bfff29a79 seven seg display 2024-03-17 18:01:27 +09:00
minjaesong
aef1db49d6 animated trajectory 2024-03-17 17:20:49 +09:00
minjaesong
09e5b175b8 alloying furnace gui minor changes 2024-03-16 05:12:14 +09:00
minjaesong
37b4fa1e7b forgot to update itemsprites 2024-03-15 23:22:29 +09:00
minjaesong
d63be072cc better colourblind-friendly wires 2024-03-15 23:15:54 +09:00
minjaesong
d22f421bc4 wire debugger tooltip fix/electronic components now need floor OR wall to spawn 2024-03-15 22:44:46 +09:00
minjaesong
cb756cbf3a fix: non-ensapsulated CraftingUI would not pause the game 2024-03-15 02:32:14 +09:00
minjaesong
b24a3da2ed colour changing wire cutter 2024-03-15 02:26:42 +09:00
minjaesong
b0adc9efc7 Lang: get-from-config tags 2024-03-15 01:45:35 +09:00
minjaesong
c0a8118717 variable wire cutter uisng right click (no sprite change yet) 2024-03-14 21:14:30 +09:00
minjaesong
336dfad207 five-coloured wiring 2024-03-14 05:29:03 +09:00
minjaesong
ef7199fd8b electric workbench 2024-03-14 02:49:00 +09:00
minjaesong
3481502c1a sprite for electric workbench 2024-03-14 02:12:55 +09:00
minjaesong
5b462a2559 wire colour fade by signal strength 2024-03-14 00:18:25 +09:00
minjaesong
6abb6f84ef fourth purple wire because four-colour theorem 2024-03-13 23:45:10 +09:00
minjaesong
2abc8b19b9 wire signal loss sim wip 2024-03-13 17:00:28 +09:00
minjaesong
7c2b5468bd smelter ui changes; longer music interval 2024-03-13 04:54:59 +09:00
minjaesong
c829245b41 some changes 2024-03-11 23:59:21 +09:00
minjaesong
b05ae829cc tapestry now persists after load 2024-03-11 23:54:02 +09:00
minjaesong
8aa866f040 fix: actor tooltip was repeatedly showing and hiding itself 2024-03-11 22:28:19 +09:00
minjaesong
5a18ba4b06 torch sprites to the spritesheet 2024-03-11 17:25:39 +09:00
minjaesong
707abe8c6d devcycle-based version name (alpha, beta thing) 2024-03-11 02:44:05 +09:00
minjaesong
60eeeae759 soldering wire 2024-03-11 01:57:36 +09:00
minjaesong
ef2413f33d alloying furnace gui 2024-03-10 22:05:45 +09:00
minjaesong
2943f4119c signal adder 2024-03-10 19:44:16 +09:00
minjaesong
a298d6663b alloying furnace gui wip 2024-03-10 01:36:52 +09:00
minjaesong
fa49874971 minor edit 2024-03-10 00:47:06 +09:00
minjaesong
247cf9bd33 using 'smelting dictionary' for smelter recipes 2024-03-10 00:46:46 +09:00
minjaesong
c6999e0794 more codes 2024-03-09 18:19:15 +09:00
minjaesong
877d26667b smelter gui behav is now a factory 2024-03-09 17:03:03 +09:00
minjaesong
3e81b80bb1 assets for alloying furnace 2024-03-09 02:52:08 +09:00
minjaesong
47c82aba49 fix: untranslated strings are shown as 'null' on bgBG 2024-03-08 15:01:19 +09:00
minjaesong
c627096503 wrench 2024-03-08 04:15:07 +09:00
minjaesong
9994235342 signal repeater 2024-03-08 00:52:02 +09:00
minjaesong
bfaa50aea4 wire ports view 2024-03-07 23:46:30 +09:00
minjaesong
0d09a21028 logic component recipes and strings 2024-03-07 02:13:58 +09:00
minjaesong
d480a735a0 worldsimulator moved to modulebasegame package 2024-03-07 01:06:53 +09:00
minjaesong
2340cb7419 some random shits 2024-03-06 03:30:50 +09:00
minjaesong
dbff2610ac fix: emissive blocks were not tiled correctly 2024-03-06 02:35:28 +09:00
minjaesong
9f399b8722 fix: lightmap draw was off by half block 2024-03-06 02:13:49 +09:00
minjaesong
9a6f45756b fix: fixture pickup was only working sparingly 2024-03-06 01:43:45 +09:00
minjaesong
bbbc5e22a5 FixtureInteractionBlocked on blocks, walls and wires 2024-03-06 00:59:54 +09:00
minjaesong
8d3d6242d7 successfully altered the control scheme 2024-03-06 00:46:21 +09:00
minjaesong
3182843a48 fixture clicking action is now integrated into the FixtureBase 2024-03-05 23:59:32 +09:00
minjaesong
1dcdd8867a adjusting position of the noticelet 2024-03-05 22:11:49 +09:00
minjaesong
a3bf1ed3f6 d flipflop with full sprite 2024-03-05 21:20:51 +09:00
minjaesong
10f8e4a662 d flipflop wip 2024-03-05 18:51:50 +09:00
minjaesong
bb1a45db27 fix: placing a switch also flips it up as soon as it's been placed 2024-03-05 05:50:20 +09:00
minjaesong
5b5534bcb9 LR click behav change/mouse clicks were sticky and causes unwanted behaviour on some fixture UIs 2024-03-05 05:21:17 +09:00
minjaesong
0090cc7d40 removing wall requirements to the circuit components for convenience 2024-03-05 02:10:13 +09:00
minjaesong
5014381cbd what a stupid typo 2024-03-04 22:49:44 +09:00
minjaesong
caf238d6df logic gate actually blinking sprites 2024-03-04 21:39:21 +09:00
minjaesong
4602cb5bc1 propagation delay is now consistent; cosmetic wip 2024-03-04 19:07:25 +09:00
minjaesong
1c39036cc8 signal blocker spritesheet 2024-03-04 16:04:01 +09:00
minjaesong
6c224c79bf wires are simulated every tick 2024-03-04 05:28:42 +09:00
minjaesong
88c9bc4a27 working logic circuit except for the sprite 2024-03-04 05:02:44 +09:00
minjaesong
659976b880 signal blocker wip 2024-03-04 02:39:03 +09:00
minjaesong
3959de68b1 switch glow sprite 2024-03-03 21:18:23 +09:00
172 changed files with 5102 additions and 1095 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,11 +3,11 @@
"1";"N/A";"N/A";"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" "1";"N/A";"N/A";"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"
# rocks # rocks
"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,OREBEARING,SHALLOWROCK" "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,OREBEARING,SHALLOWROCK,BRICKROCK"
"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,OREBEARING,SHALLOWROCK" "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,OREBEARING,SHALLOWROCK,BRICKROCK"
"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" "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" "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";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURA,OREBEARING,DEEPROCK" "20";"20";"20";"BLOCK_STONE_DEEP";"0.1252";"0.1252";"0.1252";"0.1252";"80";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURA,OREBEARING,DEEPROCK,BRICKROCK"
"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,DEEPROCK" "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,DEEPROCK"
# dirts # dirts
@@ -41,12 +41,12 @@
"75";"item@basegame:171";"item@basegame:171";"BLOCK_TRUNK_ROSEWOOD";"0.0312";"0.0312";"0.0312";"0.0312";"17";"900";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,TREETRUNK,TREELARGE,NATURAL" "75";"item@basegame:171";"item@basegame:171";"BLOCK_TRUNK_ROSEWOOD";"0.0312";"0.0312";"0.0312";"0.0312";"17";"900";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,TREETRUNK,TREELARGE,NATURAL"
# sabulous # sabulous
"80";"80";"80";"BLOCK_SAND";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM" "80";"80";"80";"BLOCK_SAND";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM,SMELTABLE"
"81";"81";"81";"BLOCK_SAND_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM" "81";"81";"81";"BLOCK_SAND_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM,SMELTABLE"
"82";"82";"82";"BLOCK_SAND_RED";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM" "82";"82";"82";"BLOCK_SAND_RED";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM,SMELTABLE"
"83";"83";"83";"BLOCK_SAND_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM" "83";"83";"83";"BLOCK_SAND_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM,SMELTABLE"
"84";"84";"84";"BLOCK_SAND_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM" "84";"84";"84";"BLOCK_SAND_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM,SMELTABLE"
"85";"85";"85";"BLOCK_SAND_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM" "85";"85";"85";"BLOCK_SAND_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1600";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SAND,NATURAL,WARM,SMELTABLE"
"96";"96";"96";"BLOCK_GRAVEL";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1700";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL" "96";"96";"96";"BLOCK_GRAVEL";"0.1252";"0.1252";"0.1252";"0.1252";"12";"1700";"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";"12";"1700";"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";"12";"1700";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
Can't render this file because it contains an unexpected character in line 18 and column 2.

View File

@@ -10,11 +10,13 @@ GetAV
GetFaction GetFaction
GetLocale GetLocale
GetTime GetTime
HasItem
ImportLayerData ImportLayerData
ImportWorld ImportWorld
Inventory Inventory
KillActor KillActor
LangTest LangTest
MakeSign
MoneyDisp MoneyDisp
MusicTest MusicTest
Possess Possess
1 CatStdout
10 GetFaction
11 GetLocale
12 GetTime
13 HasItem
14 ImportLayerData
15 ImportWorld
16 Inventory
17 KillActor
18 LangTest
19 MakeSign
20 MoneyDisp
21 MusicTest
22 Possess

View File

@@ -32,11 +32,30 @@
] ]
}, },
"item@basegame:36": { /* wire rolling mill */ "item@basegame:36": { /* wire rolling mill */
"workbench": "basiccrafting", "workbench": "basiccrafting,metalworking",
"ingredients": [ "ingredients": [
[1, 1, "$WOOD", 2, "$ROCK", 5, "item@basegame:113"] /* 1 plank, 2 stone, 5 iron ingot */ [1, 1, "$WOOD", 2, "$ROCK", 5, "item@basegame:113"] /* 1 plank, 2 stone, 5 iron ingot */
] ]
}, },
"item@basegame:48": { /* alloying furnace */
"workbench": "basiccrafting,metalworking",
"ingredients": [
[1, 15, "$ROCK", 10, "item@basegame:25", 15, "item@basegame:113"] /* 1 smelter = 15 rocks, 10 clay balls, 15 iron ingot */
]
},
"item@basegame:51": { /* electric workbench */
"workbench": "basiccrafting",
"ingredients": [
[1, 12, "$WOOD", 5, "item@basegame:113"] /* 12 wood, 5 iron */
]
},
"item@basegame:53": { /* engraving workbench */
"workbench": "basiccrafting",
"ingredients": [
[1, 12, "$WOOD", 8, "item@basegame:113"] /* 12 wood, 8 iron */
]
},
"item@basegame:256": { /* oak door */ "item@basegame:256": { /* oak door */
"workbench": "basiccrafting", "workbench": "basiccrafting",
@@ -90,7 +109,7 @@
"item@basegame:30": { /* turntable */ "item@basegame:30": { /* turntable */
"workbench": "basiccrafting", "workbench": "basiccrafting",
"ingredients": [ "ingredients": [
[1, 4, "item@basegame:144", 14, "$WOOD", 10, "item@basegame:113"] /* 1 turntable = 4 quartz, 14 wood, 10 iron */ [1, 4, "item@basegame:144", 14, "$WOOD", 10, "item@basegame:177"] /* 1 turntable = 4 quartz, 14 wood, 10 brass */
] ]
}, },

View File

@@ -0,0 +1,17 @@
{
/* stone brick */
"basegame:19": {
"workbench": "masonry",
"ingredients": [
[1, 1, "$BRICKROCK"]
]
},
/* white stone tile */
"basegame:18": {
"workbench": "masonry",
"ingredients": [
[1, 1, "basegame:21"],
[1, 3, "$BRICKROCK"]
]
}
}

View File

@@ -61,5 +61,9 @@
"item@basegame:9": { /* wire cutter */ "item@basegame:9": { /* wire cutter */
"workbench": "basiccrafting,metalworking", "workbench": "basiccrafting,metalworking",
"ingredients": [[1, 1, "item@basegame:112", 1, "item@basegame:113"]] /* 1 copper ingot, 1 iron ingot */ "ingredients": [[1, 1, "item@basegame:112", 1, "item@basegame:113"]] /* 1 copper ingot, 1 iron ingot */
},
"item@basegame:47": { /* wrench */
"workbench": "basiccrafting,metalworking",
"ingredients": [[1, 4, "item@basegame:113"]] /* 4 iron ingots */
} }
} }

View File

@@ -16,6 +16,18 @@
[1, 1, "$SIGNALWIRE"] /* 1 other signal wire */ [1, 1, "$SIGNALWIRE"] /* 1 other signal wire */
] ]
}, },
"wire@basegame:8195": { /* signal wire yellow */
"workbench": "",
"ingredients": [
[1, 1, "$SIGNALWIRE"] /* 1 other signal wire */
]
},
"wire@basegame:8196": { /* signal wire purple */
"workbench": "",
"ingredients": [
[1, 1, "$SIGNALWIRE"] /* 1 other signal wire */
]
},
"wire@basegame:8192": { /* signal wire red */ "wire@basegame:8192": { /* signal wire red */
"workbench": "wirerollingmill", "workbench": "wirerollingmill",
@@ -34,11 +46,73 @@
[10, 1, "item@basegame:112"] /* 1 copper */ [10, 1, "item@basegame:112"] /* 1 copper */
] ]
}, },
"wire@basegame:8195": { /* signal wire yellow */
"workbench": "wirerollingmill",
"ingredients": [
[10, 1, "item@basegame:112"] /* 1 copper */
]
},
"wire@basegame:8196": { /* signal wire purple */
"workbench": "wirerollingmill",
"ingredients": [
[10, 1, "item@basegame:112"] /* 1 copper */
]
},
"item@basegame:50": { /* soldering wire */
"workbench": "wirerollingmill",
"ingredients": [
[10, 1, "item@basegame:181"] /* 1 solder bar */
]
},
"item@basegame:7": { /* multimeter */
"workbench": "soldering",
"ingredients": [
[2, 5, "item@basegame:112", 5, "item@basegame:117", 5, "item@basegame:177", 5, "$SEMICONDUCTOR", 1, "item@basegame:50"] /* 5 copper, 5 gold, 5 brass, 5 iron, 5 tin, 1 soldering wire (temporary) */
]
},
"item@basegame:35": { /* copper bulb */ "item@basegame:35": { /* copper bulb */
"workbench": "basiccrafting", "workbench": "soldering",
"ingredients": [ "ingredients": [
[2, 1, "item@basegame:112", 1, "item@basegame:113"] /* 1 copper, 1 iron */ [2, 1, "item@basegame:112", 1, "item@basegame:113", 1, "item@basegame:50"] /* 1 copper, 1 iron, 1 soldering wire (temporary) */
]
},
"item@basegame:44": { /* signal blocker */
"workbench": "soldering",
"ingredients": [
[1, 2, "$ROCK", 1, "$SEMICONDUCTOR", 1, "item@basegame:112", 1, "item@basegame:50"] /* 2 rocks, 1 tin, 1 copper, 1 soldering wire (temporary) */
]
},
"item@basegame:45": { /* signal latch */
"workbench": "soldering",
"ingredients": [
[1, 3, "$ROCK", 1, "$SEMICONDUCTOR", 2, "item@basegame:112", 1, "item@basegame:50"] /* 3 rocks, 3 tin, 3 copper, 1 soldering wire (temporary) */
]
},
"item@basegame:8": { /* signal emitter */
"workbench": "soldering",
"ingredients": [
[2, 1, "$ROCK", 1, "$SEMICONDUCTOR", 1, "item@basegame:50"] /* 1 rocks, 1 tin, 1 copper, 1 soldering wire (temporary) */
]
},
"item@basegame:46": { /* signal repeater */
"workbench": "soldering",
"ingredients": [
[1, 1, "$ROCK", 1, "$SEMICONDUCTOR", 1, "item@basegame:50"] /* 1 rocks, 1 tin, 1 copper, 1 soldering wire (temporary) */
]
},
"item@basegame:49": { /* signal adder */
"workbench": "soldering",
"ingredients": [
[1, 1, "$ROCK", 1, "$SEMICONDUCTOR", 1, "item@basegame:50"] /* 2 rocks, 2 tin, 2 copper, 1 soldering wire (temporary) */
]
},
"item@basegame:52": { /* seven seg disp */
"workbench": "soldering",
"ingredients": [
[1, 4, "$ROCK", 7, "item@basegame:35", 5, "$SEMICONDUCTOR", 2, "item@basegame:112", 1, "item@basegame:50"] /* 4 rocks, 7 copper bulbs, 5 tin, 2 copper, 1 soldering wire (temporary) */
] ]
} }
} }

View File

@@ -32,8 +32,8 @@ id;classname;tags
31;net.torvald.terrarum.modulebasegame.gameitems.ItemGunpowder;POWDER,EXPLOSIVE 31;net.torvald.terrarum.modulebasegame.gameitems.ItemGunpowder;POWDER,EXPLOSIVE
32;net.torvald.terrarum.modulebasegame.gameitems.ItemCherryBomb;EXPLOSIVE,THROWABLE 32;net.torvald.terrarum.modulebasegame.gameitems.ItemCherryBomb;EXPLOSIVE,THROWABLE
33;net.torvald.terrarum.modulebasegame.gameitems.ItemTorch;FIXTURE,LIGHT 33;net.torvald.terrarum.modulebasegame.gameitems.ItemTorch;FIXTURE,LIGHT
34;net.torvald.terrarum.modulebasegame.gameitems.ItemSignalSwitchManual;FIXTURE,SIGNAL 34;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalSwitchManual;FIXTURE,SIGNAL
35;net.torvald.terrarum.modulebasegame.gameitems.ItemSignalBulb;FIXTURE,SIGNAL 35;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalBulb;FIXTURE,SIGNAL
36;net.torvald.terrarum.modulebasegame.gameitems.ItemWireRollingMill;FIXTURE,CRAFTING 36;net.torvald.terrarum.modulebasegame.gameitems.ItemWireRollingMill;FIXTURE,CRAFTING
37;net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestEbony;FIXTURE,STORAGE 37;net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestEbony;FIXTURE,STORAGE
38;net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestBirch;FIXTURE,STORAGE 38;net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestBirch;FIXTURE,STORAGE
@@ -42,18 +42,36 @@ id;classname;tags
41;net.torvald.terrarum.modulebasegame.gameitems.ItemTableEbony;FIXTURE,SURFACE 41;net.torvald.terrarum.modulebasegame.gameitems.ItemTableEbony;FIXTURE,SURFACE
42;net.torvald.terrarum.modulebasegame.gameitems.ItemTableBirch;FIXTURE,SURFACE 42;net.torvald.terrarum.modulebasegame.gameitems.ItemTableBirch;FIXTURE,SURFACE
43;net.torvald.terrarum.modulebasegame.gameitems.ItemTableRosewood;FIXTURE,SURFACE 43;net.torvald.terrarum.modulebasegame.gameitems.ItemTableRosewood;FIXTURE,SURFACE
44;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalBlocker;FIXTURE,SIGNAL
45;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalLatch;FIXTURE,SIGNAL
46;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalRepeaterHorz;FIXTURE,SIGNAL
47;net.torvald.terrarum.modulebasegame.gameitems.ItemWrench;TOOL,WRENCH
48;net.torvald.terrarum.modulebasegame.gameitems.ItemAlloyingFurnace;FIXTURE,STATION
49;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalAdder;FIXTURE,SIGNAL
50;net.torvald.terrarum.modulebasegame.gameitems.ItemSolderingWire;
51;net.torvald.terrarum.modulebasegame.gameitems.ItemElectricWorkbench;FIXTURE,CRAFTING
52;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalSevenSeg;FIXTURE,SIGNAL
53;net.torvald.terrarum.modulebasegame.gameitems.ItemEngravingWorkbench;FIXTURE,CRAFTING
# ingots # ingots
26;net.torvald.terrarum.modulebasegame.gameitems.IngotSteel;INGOT
112;net.torvald.terrarum.modulebasegame.gameitems.IngotCopper;INGOT 112;net.torvald.terrarum.modulebasegame.gameitems.IngotCopper;INGOT
113;net.torvald.terrarum.modulebasegame.gameitems.IngotIron;INGOT 113;net.torvald.terrarum.modulebasegame.gameitems.IngotIron;INGOT
114;net.torvald.terrarum.modulebasegame.gameitems.ItemCoalCoke;COMBUSTIBLE 114;net.torvald.terrarum.modulebasegame.gameitems.ItemCoalCoke;COMBUSTIBLE
115;net.torvald.terrarum.modulebasegame.gameitems.IngotZinc;INGOT 115;net.torvald.terrarum.modulebasegame.gameitems.IngotZinc;INGOT
116;net.torvald.terrarum.modulebasegame.gameitems.IngotTin;INGOT 116;net.torvald.terrarum.modulebasegame.gameitems.IngotTin;INGOT,SEMICONDUCTOR
117;net.torvald.terrarum.modulebasegame.gameitems.IngotGold;INGOT 117;net.torvald.terrarum.modulebasegame.gameitems.IngotGold;INGOT
118;net.torvald.terrarum.modulebasegame.gameitems.IngotSilver;INGOT 118;net.torvald.terrarum.modulebasegame.gameitems.IngotSilver;INGOT
119;net.torvald.terrarum.modulebasegame.gameitems.IngotLead;INGOT 119;net.torvald.terrarum.modulebasegame.gameitems.IngotLead;INGOT
# alloys
26;net.torvald.terrarum.modulebasegame.gameitems.IngotSteel;INGOT,ALLOY
176;net.torvald.terrarum.modulebasegame.gameitems.IngotBronze;INGOT,ALLOY
177;net.torvald.terrarum.modulebasegame.gameitems.IngotBrass;INGOT,ALLOY
178;net.torvald.terrarum.modulebasegame.gameitems.IngotElectrum;INGOT,ALLOY
179;net.torvald.terrarum.modulebasegame.gameitems.IngotSilverBillon;INGOT,ALLOY
180;net.torvald.terrarum.modulebasegame.gameitems.IngotRosegold;INGOT,ALLOY
181;net.torvald.terrarum.modulebasegame.gameitems.IngotSolder;INGOT,ALLOY
# ores # ores
128;net.torvald.terrarum.modulebasegame.gameitems.OreCopper;SMELTABLE 128;net.torvald.terrarum.modulebasegame.gameitems.OreCopper;SMELTABLE
129;net.torvald.terrarum.modulebasegame.gameitems.OreIron;SMELTABLE 129;net.torvald.terrarum.modulebasegame.gameitems.OreIron;SMELTABLE
@@ -78,10 +96,10 @@ id;classname;tags
163;net.torvald.terrarum.modulebasegame.gameitems.ItemSeedRosewood;SEEDLING 163;net.torvald.terrarum.modulebasegame.gameitems.ItemSeedRosewood;SEEDLING
# tree logs # tree logs
168;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsOak;COMBUSTIBLE,SMELTABLE 168;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsOak;COMBUSTIBLE,SMELTABLE,LOGS
169;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsEbony;COMBUSTIBLE,SMELTABLE 169;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsEbony;COMBUSTIBLE,SMELTABLE,LOGS
170;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsBirch;COMBUSTIBLE,SMELTABLE 170;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsBirch;COMBUSTIBLE,SMELTABLE,LOGS
171;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsRosewood;COMBUSTIBLE,SMELTABLE 171;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsRosewood;COMBUSTIBLE,SMELTABLE,LOGS
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak;FIXTURE 256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak;FIXTURE
@@ -104,16 +122,21 @@ id;classname;tags
32777;net.torvald.terrarum.modulebasegame.gameitems.MusicDisc09;MUSIC,PHONO 32777;net.torvald.terrarum.modulebasegame.gameitems.MusicDisc09;MUSIC,PHONO
# data storage (tapestries; 256) # data storage (tapestries; 256)
#33023;net.torvald.terrarum.modulebasegame.gameitems.ItemTapestry;FIXTURE #33024;net.torvald.terrarum.modulebasegame.gameitems.ItemTapestry;FIXTURE,BASEOBJECT
# data storage (text signs; 256)
33280;net.torvald.terrarum.modulebasegame.gameitems.ItemTextSignCopper;FIXTURE,BASEOBJECT
# fluids on storage # fluids on storage
# preferably autogenerated # preferably autogenerated
# 10000h..100FFh : Fluid type 0 (water) x container type 0..255 # 100000h..1000FFh : Fluid type 0 (water) x container type 0..255
# 10100h..101FFh : Fluid type 1 (lava) x container type 0..255 # 100100h..1001FFh : Fluid type 1 (lava) x container type 0..255
# 10200h..102FFh : Fluid type 2 (crude oil) x container type 0..255 # 100200h..1002FFh : Fluid type 2 (crude oil) x container type 0..255
# 10300h..103FFh : Fluid type 3 (petroleum) x container type 0..255 # 100300h..1003FFh : Fluid type 3 (petroleum) x container type 0..255
# 10400h..104FFh : Fluid type 4 (compressed air) x container type 0..255 # 100400h..1004FFh : Fluid type 4 (compressed air) x container type 0..255
# 10500h..105FFh : Fluid type 5 (steam) x container type 0..255 # 100500h..1005FFh : Fluid type 5 (steam) x container type 0..255
# ... # ...
# 1FF00h..1FFFFh : Fluid type 255 (???) x container type 0..255 # 10FF00h..10FFFFh : Fluid type 255 (???) x container type 0..255
1 id classname tags
32 32 net.torvald.terrarum.modulebasegame.gameitems.ItemCherryBomb EXPLOSIVE,THROWABLE
33 33 net.torvald.terrarum.modulebasegame.gameitems.ItemTorch FIXTURE,LIGHT
34 34 net.torvald.terrarum.modulebasegame.gameitems.ItemSignalSwitchManual net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalSwitchManual FIXTURE,SIGNAL
35 35 net.torvald.terrarum.modulebasegame.gameitems.ItemSignalBulb net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalBulb FIXTURE,SIGNAL
36 36 net.torvald.terrarum.modulebasegame.gameitems.ItemWireRollingMill FIXTURE,CRAFTING
37 37 net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestEbony FIXTURE,STORAGE
38 38 net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestBirch FIXTURE,STORAGE
39 39 net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestRosewood FIXTURE,STORAGE
42 42 net.torvald.terrarum.modulebasegame.gameitems.ItemTableBirch FIXTURE,SURFACE
43 43 net.torvald.terrarum.modulebasegame.gameitems.ItemTableRosewood FIXTURE,SURFACE
44 # ingots 44 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalBlocker FIXTURE,SIGNAL
45 45 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalLatch FIXTURE,SIGNAL
46 46 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalRepeaterHorz FIXTURE,SIGNAL
47 47 net.torvald.terrarum.modulebasegame.gameitems.ItemWrench TOOL,WRENCH
48 48 net.torvald.terrarum.modulebasegame.gameitems.ItemAlloyingFurnace FIXTURE,STATION
49 49 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalAdder FIXTURE,SIGNAL
50 50 net.torvald.terrarum.modulebasegame.gameitems.ItemSolderingWire
51 51 net.torvald.terrarum.modulebasegame.gameitems.ItemElectricWorkbench FIXTURE,CRAFTING
52 52 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalSevenSeg FIXTURE,SIGNAL
53 53 net.torvald.terrarum.modulebasegame.gameitems.ItemEngravingWorkbench FIXTURE,CRAFTING
54 # ingots
55 26 112 net.torvald.terrarum.modulebasegame.gameitems.IngotSteel net.torvald.terrarum.modulebasegame.gameitems.IngotCopper INGOT
56 112 113 net.torvald.terrarum.modulebasegame.gameitems.IngotCopper net.torvald.terrarum.modulebasegame.gameitems.IngotIron INGOT
113 net.torvald.terrarum.modulebasegame.gameitems.IngotIron INGOT
57 114 net.torvald.terrarum.modulebasegame.gameitems.ItemCoalCoke COMBUSTIBLE
58 115 net.torvald.terrarum.modulebasegame.gameitems.IngotZinc INGOT
59 116 net.torvald.terrarum.modulebasegame.gameitems.IngotTin INGOT INGOT,SEMICONDUCTOR
60 117 net.torvald.terrarum.modulebasegame.gameitems.IngotGold INGOT
61 118 net.torvald.terrarum.modulebasegame.gameitems.IngotSilver INGOT
62 119 net.torvald.terrarum.modulebasegame.gameitems.IngotLead INGOT
63 # ores # alloys
64 128 26 net.torvald.terrarum.modulebasegame.gameitems.OreCopper net.torvald.terrarum.modulebasegame.gameitems.IngotSteel SMELTABLE INGOT,ALLOY
65 129 176 net.torvald.terrarum.modulebasegame.gameitems.OreIron net.torvald.terrarum.modulebasegame.gameitems.IngotBronze SMELTABLE INGOT,ALLOY
66 177 net.torvald.terrarum.modulebasegame.gameitems.IngotBrass INGOT,ALLOY
67 178 net.torvald.terrarum.modulebasegame.gameitems.IngotElectrum INGOT,ALLOY
68 179 net.torvald.terrarum.modulebasegame.gameitems.IngotSilverBillon INGOT,ALLOY
69 180 net.torvald.terrarum.modulebasegame.gameitems.IngotRosegold INGOT,ALLOY
70 181 net.torvald.terrarum.modulebasegame.gameitems.IngotSolder INGOT,ALLOY
71 # ores
72 128 net.torvald.terrarum.modulebasegame.gameitems.OreCopper SMELTABLE
73 129 net.torvald.terrarum.modulebasegame.gameitems.OreIron SMELTABLE
74 130 net.torvald.terrarum.modulebasegame.gameitems.OreCoal SMELTABLE,COMBUSTIBLE
75 130 131 net.torvald.terrarum.modulebasegame.gameitems.OreCoal net.torvald.terrarum.modulebasegame.gameitems.OreZinc SMELTABLE,COMBUSTIBLE SMELTABLE
76 131 132 net.torvald.terrarum.modulebasegame.gameitems.OreZinc net.torvald.terrarum.modulebasegame.gameitems.OreTin SMELTABLE
77 132 133 net.torvald.terrarum.modulebasegame.gameitems.OreTin net.torvald.terrarum.modulebasegame.gameitems.OreGold SMELTABLE
96 256 257 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony FIXTURE
97 257 258 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorBirch FIXTURE
98 258 259 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorBirch net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorRosewood FIXTURE
99 259 320 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorRosewood net.torvald.terrarum.modulebasegame.gameitems.ItemWorldPortal FIXTURE FIXTURE,STATION
100 320 # data storage (discs net.torvald.terrarum.modulebasegame.gameitems.ItemWorldPortal 256)
101 # data storage (discs # 32768 is a reserved number for a blank disc
102 # 32768 is a reserved number for a blank disc 32769 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc01 MUSIC,PHONO
103 32769 32770 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc01 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc02 MUSIC,PHONO
104 32770 32771 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc02 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc03 MUSIC,PHONO
105 32771 32772 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc03 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc04 MUSIC,PHONO
122 # ... # 100500h..1005FFh : Fluid type 5 (steam) x container type 0..255
123 # 1FF00h..1FFFFh : Fluid type 255 (???) x container type 0..255 # ...
124 # 10FF00h..10FFFFh : Fluid type 255 (???) x container type 0..255
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,5 @@
{ {
"CONTEXT_ENGRAVER_TEXT": "Text",
"CONTEXT_GENERATOR_SEED": "Seed", "CONTEXT_GENERATOR_SEED": "Seed",
"CONTEXT_ITEM_FIXTURES": "Fixtures", "CONTEXT_ITEM_FIXTURES": "Fixtures",
"CONTEXT_ITEM_MAP": "Map", "CONTEXT_ITEM_MAP": "Map",
@@ -18,7 +19,7 @@
"GAME_ACTION_QUICKSEL": "Quick Select", "GAME_ACTION_QUICKSEL": "Quick Select",
"GAME_ACTION_SELECT_SLOT": "Select Slot", "GAME_ACTION_SELECT_SLOT": "Select Slot",
"GAME_ACTION_TELEPORT": "Teleport", "GAME_ACTION_TELEPORT": "Teleport",
"GAME_CRAFTABLE_ITEMS": "Craftable Items", "GAME_CRAFTABLE_ITEMS": "Recipes",
"GAME_CRAFTING": "Crafting", "GAME_CRAFTING": "Crafting",
"GAME_INVENTORY_BLOCKS": "Blocks", "GAME_INVENTORY_BLOCKS": "Blocks",
"GAME_INVENTORY_FAVORITES": "Favorites", "GAME_INVENTORY_FAVORITES": "Favorites",

View File

@@ -6,9 +6,11 @@
"TOOLTIP_wire@basegame:8192": "Carries signals", "TOOLTIP_wire@basegame:8192": "Carries signals",
"TOOLTIP_wire@basegame:8193": "Carries signals", "TOOLTIP_wire@basegame:8193": "Carries signals",
"TOOLTIP_wire@basegame:8194": "Carries signals", "TOOLTIP_wire@basegame:8194": "Carries signals",
"TOOLTIP_wire@basegame:8196": "Carries power", "TOOLTIP_wire@basegame:8195": "Carries signals",
"TOOLTIP_wire@basegame:8197": "Carries power", "TOOLTIP_wire@basegame:8196": "Carries signals",
"TOOLTIP_wire@basegame:8198": "Carries information", "TOOLTIP_wire@basegame:1": "Carries power",
"TOOLTIP_wire@basegame:2": "Carries power",
"TOOLTIP_wire@basegame:16": "Carries information",
"TOOLTIP_item@basegame:1": "Breaks rocks", "TOOLTIP_item@basegame:1": "Breaks rocks",
"TOOLTIP_item@basegame:2": "Breaks rocks", "TOOLTIP_item@basegame:2": "Breaks rocks",
@@ -19,8 +21,7 @@
"TOOLTIP_item@basegame:37": "“I am sworn to keep your burdens.”", /* skyrim/lydia reference */ "TOOLTIP_item@basegame:37": "“I am sworn to keep your burdens.”", /* skyrim/lydia reference */
"TOOLTIP_item@basegame:38": "“I am sworn to keep your burdens.”", /* skyrim/lydia reference */ "TOOLTIP_item@basegame:38": "“I am sworn to keep your burdens.”", /* skyrim/lydia reference */
"TOOLTIP_item@basegame:39": "“I am sworn to keep your burdens.”", /* skyrim/lydia reference */ "TOOLTIP_item@basegame:39": "“I am sworn to keep your burdens.”", /* skyrim/lydia reference */
"TOOLTIP_item@basegame:8": "Emits a signal", "TOOLTIP_item@basegame:9": "Push {MOUSE:config_mousesecondary} to change the colour",
"TOOLTIP_item@basegame:9": "An electricians best friend",
"TOOLTIP_item@basegame:10": "“Who needs a Book and Quill when youve got this?”", /* a jab on the Minecraft item Book and Quill */ "TOOLTIP_item@basegame:10": "“Who needs a Book and Quill when youve got this?”", /* a jab on the Minecraft item Book and Quill */
"TOOLTIP_item@basegame:11": "Tells what day it is", "TOOLTIP_item@basegame:11": "Tells what day it is",
"TOOLTIP_item@basegame:12": "Breaks down walls", "TOOLTIP_item@basegame:12": "Breaks down walls",
@@ -43,8 +44,20 @@
"TOOLTIP_item@basegame:28": "A music vending machine (free to play)", "TOOLTIP_item@basegame:28": "A music vending machine (free to play)",
"TOOLTIP_item@basegame:29": "A coal lookalike that burns just as well and is renewable", "TOOLTIP_item@basegame:29": "A coal lookalike that burns just as well and is renewable",
"TOOLTIP_item@basegame:36": "Creates wires from metal ingots", "TOOLTIP_item@basegame:36": "Creates wires from metal ingots",
"TOOLTIP_item@basegame:47": "Reorients gadgets",
"TOOLTIP_item@basegame:48": "Melts two metal ingots to make a bar of alloy",
"TOOLTIP_item@basegame:50": "Use it on the Electronics Workbench",
"TOOLTIP_item@basegame:114": "A precious fuel for the steel production", "TOOLTIP_item@basegame:114": "A precious fuel for the steel production",
"TOOLTIP_item@basegame:320": "Travel multiverse!\nWarning: a pair is needed for the return trip" "TOOLTIP_item@basegame:320": "Travel multiverse!\nWarning: a pair is needed for the return trip",
"TOOLTIP_item@basegame:8": "Emits a signal",
"TOOLTIP_item@basegame:34": "Selectively emits a signal",
"TOOLTIP_item@basegame:35": "Shows a signal status",
"TOOLTIP_item@basegame:44": "Cuts the signal using the cutting signal",
"TOOLTIP_item@basegame:45": "Latches onto the signal on the latch signal",
"TOOLTIP_item@basegame:46": "Delays a signal by a short amount",
"TOOLTIP_item@basegame:49": "Logically adds two signals"
} }

View File

@@ -1,13 +1,17 @@
{ {
"ITEM_ALLOYING_FURNACE": "Alloying Furnace",
"ITEM_CALENDAR": "Calendar", "ITEM_CALENDAR": "Calendar",
"ITEM_CHARCOAL": "Charcoal", "ITEM_CHARCOAL": "Charcoal",
"ITEM_CHERRY_BOMB": "Bomb", "ITEM_CHERRY_BOMB": "Bomb",
"ITEM_COAL_COKE": "Coal Coke", "ITEM_COAL_COKE": "Coal Coke",
"ITEM_COPPER_BULB": "Copper Bulb", "ITEM_COPPER_BULB": "Copper Bulb",
"ITEM_COPPER_SIGN": "Copper Sign",
"ITEM_DOOR_OAK": "Oak Door", "ITEM_DOOR_OAK": "Oak Door",
"ITEM_DOOR_EBONY": "Ebony Door", "ITEM_DOOR_EBONY": "Ebony Door",
"ITEM_DOOR_BIRCH": "Birch Door", "ITEM_DOOR_BIRCH": "Birch Door",
"ITEM_DOOR_ROSEWOOD": "Rosewood Door", "ITEM_DOOR_ROSEWOOD": "Rosewood Door",
"ITEM_ELECTRIC_WORKBENCH": "Electric Workbench",
"ITEM_ENGRAVING_WORKBENCH": "Engraving Workbench",
"ITEM_FURNACE_AND_ANVIL": "Furnace and Anvil", "ITEM_FURNACE_AND_ANVIL": "Furnace and Anvil",
"ITEM_GEM_RUBY": "Raw Ruby", "ITEM_GEM_RUBY": "Raw Ruby",
"ITEM_GEM_EMERALD": "Raw Emerald", "ITEM_GEM_EMERALD": "Raw Emerald",
@@ -37,12 +41,18 @@
"ITEM_INGOT_TIN": "Tin Ingot", "ITEM_INGOT_TIN": "Tin Ingot",
"ITEM_INGOT_ZINC": "Zinc Ingot", "ITEM_INGOT_ZINC": "Zinc Ingot",
"ITEM_JUKEBOX": "Jukebox", "ITEM_JUKEBOX": "Jukebox",
"ITEM_LOGIC_SIGNAL_ADDER": "Logic Signal Adder",
"ITEM_LOGIC_SIGNAL_BLOCKER": "Logic Signal Blocker",
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter", "ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
"ITEM_LOGIC_SIGNAL_LATCH": "Logic Signal Latch",
"ITEM_LOGIC_SIGNAL_NUMERIC_DISPLAY": "Logic Signal Numeric Display",
"ITEM_LOGIC_SIGNAL_REPEATER": "Logic Signal Repeater",
"ITEM_LOGIC_SIGNAL_SWITCH": "Logic Signal Switch", "ITEM_LOGIC_SIGNAL_SWITCH": "Logic Signal Switch",
"ITEM_LOGS_BIRCH": "Birch Logs", "ITEM_LOGS_BIRCH": "Birch Logs",
"ITEM_LOGS_EBONY": "Ebony Logs", "ITEM_LOGS_EBONY": "Ebony Logs",
"ITEM_LOGS_OAK": "Oak Logs", "ITEM_LOGS_OAK": "Oak Logs",
"ITEM_LOGS_ROSEWOOD": "Rosewood Logs", "ITEM_LOGS_ROSEWOOD": "Rosewood Logs",
"ITEM_MULTIMETER": "Multimeter",
"ITEM_NITRE": "Nitre", "ITEM_NITRE": "Nitre",
"ITEM_ORE_CASSITERITE": "Tin Ore", "ITEM_ORE_CASSITERITE": "Tin Ore",
"ITEM_ORE_COAL": "Coal", "ITEM_ORE_COAL": "Coal",
@@ -65,6 +75,7 @@
"ITEM_SLEDGEHAMMER_COPPER": "Copper Sledgehammer", "ITEM_SLEDGEHAMMER_COPPER": "Copper Sledgehammer",
"ITEM_SLEDGEHAMMER_IRON": "Iron Sledgehammer", "ITEM_SLEDGEHAMMER_IRON": "Iron Sledgehammer",
"ITEM_SLEDGEHAMMER_STEEL": "Steel Sledgehammer", "ITEM_SLEDGEHAMMER_STEEL": "Steel Sledgehammer",
"ITEM_SOLDERING_WIRE": "Soldering Wire",
"ITEM_SMELTER_SMALL": "Small Smelter", "ITEM_SMELTER_SMALL": "Small Smelter",
"ITEM_STORAGE_CHEST": "Storage Chest", "ITEM_STORAGE_CHEST": "Storage Chest",
"ITEM_TABLE_OAK": "Oak Table", "ITEM_TABLE_OAK": "Oak Table",
@@ -81,7 +92,8 @@
"ITEM_WOODEN_MALLET": "Wooden Mallet", "ITEM_WOODEN_MALLET": "Wooden Mallet",
"ITEM_WORKBENCH": "Workbench", "ITEM_WORKBENCH": "Workbench",
"ITEM_WORLD_PORTAL": "Teleportation Station", "ITEM_WORLD_PORTAL": "Teleportation Station",
"ITEM_WRENCH": "Wrench",
/* below are placeholders; please do not translate */
"ACTORBLOCK_ALLOW_MOVE_DOWN": "Urist Arôlcustith", "ACTORBLOCK_ALLOW_MOVE_DOWN": "Urist Arôlcustith",
"ACTORBLOCK_FULL_COLLISION": "Urist Berdanrifot", "ACTORBLOCK_FULL_COLLISION": "Urist Berdanrifot",
"ACTORBLOCK_NO_COLLISION": "Urist Zafal", "ACTORBLOCK_NO_COLLISION": "Urist Zafal",

View File

@@ -1,4 +1,5 @@
{ {
"CONTEXT_ENGRAVER_TEXT": "문구",
"CONTEXT_GENERATOR_SEED": "시드", "CONTEXT_GENERATOR_SEED": "시드",
"CONTEXT_ITEM_FIXTURES": "기구", "CONTEXT_ITEM_FIXTURES": "기구",
"CONTEXT_ITEM_MAP": "지도", "CONTEXT_ITEM_MAP": "지도",
@@ -17,7 +18,7 @@
"GAME_ACTION_QUICKSEL": "빠른 선택", "GAME_ACTION_QUICKSEL": "빠른 선택",
"GAME_ACTION_SELECT_SLOT": "슬롯 선택", "GAME_ACTION_SELECT_SLOT": "슬롯 선택",
"GAME_ACTION_TELEPORT": "텔레포트하기", "GAME_ACTION_TELEPORT": "텔레포트하기",
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템", "GAME_CRAFTABLE_ITEMS": "제작 레시피",
"GAME_CRAFTING": "제작", "GAME_CRAFTING": "제작",
"GAME_INVENTORY_BLOCKS": "블록", "GAME_INVENTORY_BLOCKS": "블록",
"GAME_INVENTORY_FAVORITES": "즐겨찾기", "GAME_INVENTORY_FAVORITES": "즐겨찾기",

View File

@@ -6,9 +6,10 @@
"TOOLTIP_wire@basegame:8192": "신호를 전달합니다", "TOOLTIP_wire@basegame:8192": "신호를 전달합니다",
"TOOLTIP_wire@basegame:8193": "신호를 전달합니다", "TOOLTIP_wire@basegame:8193": "신호를 전달합니다",
"TOOLTIP_wire@basegame:8194": "신호를 전달합니다", "TOOLTIP_wire@basegame:8194": "신호를 전달합니다",
"TOOLTIP_wire@basegame:8196": "전력을 전달합니다", "TOOLTIP_wire@basegame:8195": "신호를 전달합니다",
"TOOLTIP_wire@basegame:8197": "전력을 전달합니다", "TOOLTIP_wire@basegame:1": "전력을 전달합니다",
"TOOLTIP_wire@basegame:8198": "정보를 전달합니다", "TOOLTIP_wire@basegame:2": "전력을 전달합니다",
"TOOLTIP_wire@basegame:16": "정보를 전달합니다",
"TOOLTIP_item@basegame:1": "돌을 부숩니다", "TOOLTIP_item@basegame:1": "돌을 부숩니다",
"TOOLTIP_item@basegame:2": "돌을 부숩니다", "TOOLTIP_item@basegame:2": "돌을 부숩니다",
@@ -19,8 +20,7 @@
"TOOLTIP_item@basegame:37": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */ "TOOLTIP_item@basegame:37": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */
"TOOLTIP_item@basegame:38": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */ "TOOLTIP_item@basegame:38": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */
"TOOLTIP_item@basegame:39": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */ "TOOLTIP_item@basegame:39": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */
"TOOLTIP_item@basegame:8": "신호를 만들어냅니다", "TOOLTIP_item@basegame:9": "{MOUSE:config_mousesecondary} 버튼을 눌러 색깔 변경",
"TOOLTIP_item@basegame:9": "전기공의 친한 친구",
"TOOLTIP_item@basegame:10": "“이게 있는데 책과 깃펜이 왜 필요하죠?”", /* a jab on the Minecraft item Book and Quill */ "TOOLTIP_item@basegame:10": "“이게 있는데 책과 깃펜이 왜 필요하죠?”", /* a jab on the Minecraft item Book and Quill */
"TOOLTIP_item@basegame:11": "오늘이 무슨 날인지 알려줍니다", "TOOLTIP_item@basegame:11": "오늘이 무슨 날인지 알려줍니다",
"TOOLTIP_item@basegame:12": "벽을 부숩니다", "TOOLTIP_item@basegame:12": "벽을 부숩니다",
@@ -42,8 +42,19 @@
"TOOLTIP_item@basegame:28": "음악 자판기입이다 (무료 플레이)", "TOOLTIP_item@basegame:28": "음악 자판기입이다 (무료 플레이)",
"TOOLTIP_item@basegame:29": "석탄과 비슷하고 똑같이 잘 타지만 재생 가능합니다", "TOOLTIP_item@basegame:29": "석탄과 비슷하고 똑같이 잘 타지만 재생 가능합니다",
"TOOLTIP_item@basegame:36": "금속 주괴를 사용해 철사를 뽑아냅니다", "TOOLTIP_item@basegame:36": "금속 주괴를 사용해 철사를 뽑아냅니다",
"TOOLTIP_item@basegame:47": "기기의 방향을 바꿉니다",
"TOOLTIP_item@basegame:48": "두 금속 괴를 녹여 합금을 만듭니다",
"TOOLTIP_item@basegame:50": "전자 작업대에서 사용하세요",
"TOOLTIP_item@basegame:114": "강철 생산의 소중한 연료입니다", "TOOLTIP_item@basegame:114": "강철 생산의 소중한 연료입니다",
"TOOLTIP_item@basegame:320": "멀티버스를 여행하세요!\n경고: 2개를 만들어야 왕복이 가능합니다" "TOOLTIP_item@basegame:320": "멀티버스를 여행하세요!\n경고: 2개를 만들어야 왕복이 가능합니다",
"TOOLTIP_item@basegame:8": "신호를 만들어냅니다",
"TOOLTIP_item@basegame:34": "선택적으로 신호를 만들어냅니다",
"TOOLTIP_item@basegame:35": "신호의 상태를 보여줍니다",
"TOOLTIP_item@basegame:44": "지나가는 신호를 자르기 신호에 따라 자릅니다",
"TOOLTIP_item@basegame:45": "들어오는 신호를 걸쇠 신호에 따라 잠시 저장합니다",
"TOOLTIP_item@basegame:46": "들어오는 신호를 살짝 지연시킵니다",
"TOOLTIP_item@basegame:49": "들어오는 신호의 합을 구합니다"
} }

View File

@@ -1,13 +1,17 @@
{ {
"ITEM_ALLOYING_FURNACE": "합금 화로",
"ITEM_CALENDAR": "달력", "ITEM_CALENDAR": "달력",
"ITEM_CHARCOAL": "목탄", "ITEM_CHARCOAL": "목탄",
"ITEM_CHERRY_BOMB": "폭탄", "ITEM_CHERRY_BOMB": "폭탄",
"ITEM_COAL_COKE": "코크스", "ITEM_COAL_COKE": "코크스",
"ITEM_COPPER_BULB": "구리 전구", "ITEM_COPPER_BULB": "구리 전구",
"ITEM_COPPER_SIGN": "구리 간판",
"ITEM_DOOR_OAK": "나무 문", "ITEM_DOOR_OAK": "나무 문",
"ITEM_DOOR_EBONY": "흑단 문", "ITEM_DOOR_EBONY": "흑단 문",
"ITEM_DOOR_BIRCH": "백단 문", "ITEM_DOOR_BIRCH": "백단 문",
"ITEM_DOOR_ROSEWOOD": "자단 문", "ITEM_DOOR_ROSEWOOD": "자단 문",
"ITEM_ELECTRIC_WORKBENCH": "전기 작업대",
"ITEM_ENGRAVING_WORKBENCH": "조각 작업대",
"ITEM_FURNACE_AND_ANVIL": "화로와 모루", "ITEM_FURNACE_AND_ANVIL": "화로와 모루",
"ITEM_GEM_RUBY": "홍옥석", "ITEM_GEM_RUBY": "홍옥석",
"ITEM_GEM_EMERALD": "취옥석", "ITEM_GEM_EMERALD": "취옥석",
@@ -32,17 +36,23 @@
"ITEM_INGOT_ROSEGOLD": "분홍금괴", "ITEM_INGOT_ROSEGOLD": "분홍금괴",
"ITEM_INGOT_SILVER": "은괴", "ITEM_INGOT_SILVER": "은괴",
"ITEM_INGOT_SILVER_BILLON": "은동괴", "ITEM_INGOT_SILVER_BILLON": "은동괴",
"ITEM_INGOT_SOLDER": "납", "ITEM_INGOT_SOLDER": "막대납",
"ITEM_INGOT_STEEL": "강철괴", "ITEM_INGOT_STEEL": "강철괴",
"ITEM_INGOT_TIN": "주석괴", "ITEM_INGOT_TIN": "주석괴",
"ITEM_INGOT_ZINC": "아연괴", "ITEM_INGOT_ZINC": "아연괴",
"ITEM_JUKEBOX": "주크박스", "ITEM_JUKEBOX": "주크박스",
"ITEM_LOGIC_SIGNAL_EMITTER": "신호발생기", "ITEM_LOGIC_SIGNAL_ADDER": "신호 가산기",
"ITEM_LOGIC_SIGNAL_BLOCKER": "신호 차단기",
"ITEM_LOGIC_SIGNAL_EMITTER": "신호 발생기",
"ITEM_LOGIC_SIGNAL_LATCH": "신호 걸쇠",
"ITEM_LOGIC_SIGNAL_NUMERIC_DISPLAY": "신호 숫자 표시기",
"ITEM_LOGIC_SIGNAL_REPEATER": "신호 리피터",
"ITEM_LOGIC_SIGNAL_SWITCH": "신호 스위치", "ITEM_LOGIC_SIGNAL_SWITCH": "신호 스위치",
"ITEM_LOGS_BIRCH": "백단 통나무", "ITEM_LOGS_BIRCH": "백단 통나무",
"ITEM_LOGS_EBONY": "흑단 통나무", "ITEM_LOGS_EBONY": "흑단 통나무",
"ITEM_LOGS_OAK": "통나무", "ITEM_LOGS_OAK": "통나무",
"ITEM_LOGS_ROSEWOOD": "자단 통나무", "ITEM_LOGS_ROSEWOOD": "자단 통나무",
"ITEM_MULTIMETER": "멀티미터",
"ITEM_NITRE": "초석", "ITEM_NITRE": "초석",
"ITEM_ORE_CASSITERITE": "주석석", "ITEM_ORE_CASSITERITE": "주석석",
"ITEM_ORE_COAL": "석탄", "ITEM_ORE_COAL": "석탄",
@@ -65,6 +75,7 @@
"ITEM_SLEDGEHAMMER_COPPER": "구리 해머", "ITEM_SLEDGEHAMMER_COPPER": "구리 해머",
"ITEM_SLEDGEHAMMER_IRON": "철 해머", "ITEM_SLEDGEHAMMER_IRON": "철 해머",
"ITEM_SLEDGEHAMMER_STEEL": "강철 해머", "ITEM_SLEDGEHAMMER_STEEL": "강철 해머",
"ITEM_SOLDERING_WIRE": "실납",
"ITEM_SMELTER_SMALL": "소형 고로", "ITEM_SMELTER_SMALL": "소형 고로",
"ITEM_STORAGE_CHEST": "보관상자", "ITEM_STORAGE_CHEST": "보관상자",
"ITEM_TABLE_OAK": "나무 탁자", "ITEM_TABLE_OAK": "나무 탁자",
@@ -80,5 +91,6 @@
"ITEM_WOOD_STICK": "막대기", "ITEM_WOOD_STICK": "막대기",
"ITEM_WOODEN_MALLET": "나무 망치", "ITEM_WOODEN_MALLET": "나무 망치",
"ITEM_WORKBENCH": "작업대", "ITEM_WORKBENCH": "작업대",
"ITEM_WORLD_PORTAL": "텔레포트 스테이션" "ITEM_WORLD_PORTAL": "텔레포트 스테이션",
"ITEM_WRENCH": "렌치"
} }

View File

@@ -44,10 +44,10 @@ package=net.torvald.terrarum.modulebasegame
entrypoint=net.torvald.terrarum.modulebasegame.EntryPoint entrypoint=net.torvald.terrarum.modulebasegame.EntryPoint
# Release date in YYYY-MM-DD # Release date in YYYY-MM-DD
releasedate=2024-03-03 releasedate=2024-03-28
# The version, must follow Semver 2.0.0 scheme (https://semver.org/) # The version, must follow Semver 2.0.0 scheme (https://semver.org/)
version=0.4.1 version=0.4.2
# External JAR that the module is compiled. If your module requires yet another library, the JAR must be compiled as a "Fatjar"; # 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. # Due to security reasons, loading an arbitrary JAR is not allowed.

View File

@@ -0,0 +1,27 @@
{
/* as for the plus operator, the itemIDs must be sorted lexicographically and first word should come left */
"item@basegame:112+item@basegame:116": { /* copper + tin -> bronze */
"difficulty": 1.0,
"product": [2, "item@basegame:176"]
},
"item@basegame:112+item@basegame:115": { /* copper + zinc -> brass */
"difficulty": 1.0,
"product": [2, "item@basegame:177"]
},
"item@basegame:117+item@basegame:118": { /* gold + silver -> electrum */
"difficulty": 1.0,
"product": [2, "item@basegame:178"]
},
"item@basegame:112+item@basegame:118": { /* copper + silver -> silver billon */
"difficulty": 1.0,
"product": [2, "item@basegame:179"]
},
"item@basegame:112+item@basegame:117": { /* copper + gold -> rose gold */
"difficulty": 1.0,
"product": [2, "item@basegame:180"]
},
"item@basegame:116+item@basegame:119": { /* tin + lead -> solder */
"difficulty": 1.0,
"product": [2, "item@basegame:181"]
}
}

View File

@@ -0,0 +1,48 @@
{
"$SAND": { /* sand -> crude glass */
"difficulty": 1.0,
"product": [1, "basegame:148"]
},
"item@basegame:144": { /* quartz -> clean glass */
"difficulty": 1.0,
"product": [1, "basegame:149"]
},
"$LOGS": { /* logs -> charcoal */
"difficulty": 1.0,
"product": [1, "item@basegame:29"]
},
"item@basegame:128": { /* copper ore -> ingot */
"difficulty": 1.0,
"product": [1, "item@basegame:112"]
},
"item@basegame:129": { /* iron ore -> ingot */
"difficulty": 1.0,
"product": [1, "item@basegame:113"]
},
"item@basegame:130": { /* coal -> coke */
"difficulty": 1.0,
"product": [1, "item@basegame:114"]
},
"item@basegame:131": { /* zinc ore -> ingot */
"difficulty": 1.0,
"product": [1, "item@basegame:115"]
},
"item@basegame:132": { /* tin ore -> ingot */
"difficulty": 1.0,
"product": [1, "item@basegame:116"]
},
"item@basegame:133": { /* gold ore -> ingot */
"difficulty": 1.0,
"product": [1, "item@basegame:117"]
},
"item@basegame:134": { /* silver ore -> ingot */
"difficulty": 1.0,
"product": [1, "item@basegame:118"]
},
"item@basegame:135": { /* lead ore -> ingot */
"difficulty": 1.0,
"product": [1, "item@basegame:119"]
}
}

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.

BIN
assets/mods/basegame/wires/1.tga LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,9 @@
wireItemID;const
wire@basegame:8192;0.995
wire@basegame:8193;0.995
wire@basegame:8194;0.995
wire@basegame:8195;0.995
wire@basegame:8196;0.999
wire@basegame:8197;0.999
wire@basegame:8198;0.999
1 wireItemID const
2 wire@basegame:8192 0.995
3 wire@basegame:8193 0.995
4 wire@basegame:8194 0.995
5 wire@basegame:8195 0.995
6 wire@basegame:8196 0.999
7 wire@basegame:8197 0.999
8 wire@basegame:8198 0.999

Binary file not shown.

View File

@@ -0,0 +1,5 @@
"accepts";"fileModule";"file";"xpos";"ypos"
"digital_bit";"basegame";"wires/ports.tga";0;0
"power_low";"basegame";"wires/ports.tga";1;0
"power_high";"basegame";"wires/ports.tga";2;0
"10base2";"basegame";"wires/ports.tga";2;0
1 accepts fileModule file xpos ypos
2 digital_bit basegame wires/ports.tga 0 0
3 power_low basegame wires/ports.tga 1 0
4 power_high basegame wires/ports.tga 2 0
5 10base2 basegame wires/ports.tga 2 0

View File

@@ -2,10 +2,12 @@ id;drop;name;renderclass;accept;inputcount;inputtype;outputtype;javaclass;invent
8192;8192;WIRE_RED;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,0,4;1;"SIGNALWIRE" 8192;8192;WIRE_RED;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,0,4;1;"SIGNALWIRE"
8193;8193;WIRE_GREEN;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,1,4;1;"SIGNALWIRE" 8193;8193;WIRE_GREEN;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,1,4;1;"SIGNALWIRE"
8194;8194;WIRE_BLUE;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,2,4;1;"SIGNALWIRE" 8194;8194;WIRE_BLUE;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,2,4;1;"SIGNALWIRE"
#8195;8195;WIRE_BUNDLE;signal;digital_3bits;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,0,0;1;"SIGNALWIRE" 8195;8195;WIRE_YELLOW;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,3,4;1;"SIGNALWIRE"
8196;8196;WIRE_POWER_LOW;power;power_low;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,3,4;1;"POWERWIRE_LOW" 8196;8196;WIRE_PURPLE;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,4,4;1;"SIGNALWIRE"
8197;8197;WIRE_POWER_HIGH;power;power_high;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,4,4;1;"POWERWIRE_HIGH"
8198;8198;WIRE_ETHERNET;network;10base2;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,5,4;1;"ETHERNETWIRE" 1;1;WIRE_POWER_LOW;power;power_low;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,5,4;1;"POWERWIRE_LOW"
2;2;WIRE_POWER_HIGH;power;power_high;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,6,4;1;"POWERWIRE_HIGH"
16;16;WIRE_ETHERNET;network;10base2;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,7,4;1;"ETHERNETWIRE"
# accept: which wiretype (defined elsewhere) the wires acceps. Use comma to separate multiple. N/A for electronic components (aka not wires) # accept: which wiretype (defined elsewhere) the wires acceps. Use comma to separate multiple. N/A for electronic components (aka not wires)
1 id drop name renderclass accept inputcount inputtype outputtype javaclass inventoryimg branching tags
2 8192 8192 WIRE_RED signal digital_bit 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,0,4 1 SIGNALWIRE
3 8193 8193 WIRE_GREEN signal digital_bit 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,1,4 1 SIGNALWIRE
4 8194 8194 WIRE_BLUE signal digital_bit 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,2,4 1 SIGNALWIRE
5 #8195 8195 8195 WIRE_BUNDLE WIRE_YELLOW signal digital_3bits digital_bit 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,0,0 basegame.items,3,4 1 SIGNALWIRE
6 8196 8196 WIRE_POWER_LOW WIRE_PURPLE power signal power_low digital_bit 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,3,4 basegame.items,4,4 1 POWERWIRE_LOW SIGNALWIRE
7 8197 1 8197 1 WIRE_POWER_HIGH WIRE_POWER_LOW power power_high power_low 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,4,4 basegame.items,5,4 1 POWERWIRE_HIGH POWERWIRE_LOW
8 8198 2 8198 2 WIRE_ETHERNET WIRE_POWER_HIGH network power 10base2 power_high 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,5,4 basegame.items,6,4 1 ETHERNETWIRE POWERWIRE_HIGH
9 16 16 WIRE_ETHERNET network 10base2 3 N/A N/A net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire basegame.items,7,4 1 ETHERNETWIRE
10 # accept: which wiretype (defined elsewhere) the wires acceps. Use comma to separate multiple. N/A for electronic components (aka not wires)
11 # accept: which wiretype (defined elsewhere) the wires acceps. Use comma to separate multiple. N/A for electronic components (aka not wires) # inputcount: how many sides are input (outputcount is deduced from the inputcount). N/A for wires
12 # inputcount: how many sides are input (outputcount is deduced from the inputcount). N/A for wires # inputtype: which wiretype it accepts. N/A for wires
13 # inputtype: which wiretype it accepts. N/A for wires # outputtype: which wiretype it emits. N/A for wires

View File

@@ -3,8 +3,8 @@ description=Simple music player widget
author=CuriousTo\uA75Bvald author=CuriousTo\uA75Bvald
package=net.torvald.terrarum.musicplayer package=net.torvald.terrarum.musicplayer
entrypoint=net.torvald.terrarum.musicplayer.EntryPoint entrypoint=net.torvald.terrarum.musicplayer.EntryPoint
releasedate=2024-03-03 releasedate=2024-03-28
version=1.0.1 version=1.0.2
jar=MusicPlayer.jar jar=MusicPlayer.jar
jarhash=53248a70a8cbfbcdd76e11549a132400305e91785ff98af514e68e8cafacdc19 jarhash=8ab074e9dc6312ea4d3f6f500e362afb65001d3770f4f8da1d9f2e47cb294de0
dependency=basegame 0.4.1 dependency=basegame 0.4.2+

View File

@@ -70,16 +70,11 @@ public class App implements ApplicationListener {
public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG; public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG;
public static final String getVERSION_STRING() { public static final String getVERSION_STRING() {
return TerrarumAppConfiguration.INSTANCE.getVERSION_STRING();
var snap = TerrarumAppConfiguration.INSTANCE.getVERSION_SNAPSHOT();
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) +
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG) + (snap == null ? "" : (" (" + snap + ")"));
} }
public static final String getVERSION_STRING_WITHOUT_SNAPSHOT() { public static final String getVERSION_STRING_WITHOUT_SNAPSHOT() {
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) + return TerrarumAppConfiguration.INSTANCE.getVERSION_STRING_WITHOUT_SNAPSHOT();
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG);
} }
/** /**
@@ -1731,7 +1726,7 @@ public class App implements ApplicationListener {
return DefaultConfig.INSTANCE.getHashMap(); return DefaultConfig.INSTANCE.getHashMap();
} }
private static Object getConfigMaster(String key1) { public static Object getConfigMaster(String key1) {
String key = key1.toLowerCase(); String key = key1.toLowerCase();
Object config; Object config;

View File

@@ -63,7 +63,8 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
} }
} }
val disposables = HashSet<Disposable>() /** things to be disposed of when the current instance of the game disposed of */
// val disposables = HashSet<Disposable>()
lateinit var worldDisk: VirtualDisk; internal set lateinit var worldDisk: VirtualDisk; internal set
lateinit var playerDisk: VirtualDisk; internal set lateinit var playerDisk: VirtualDisk; internal set
@@ -186,7 +187,6 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
blockMarkingActor.let { blockMarkingActor.let {
it.unsetGhost() it.unsetGhost()
it.setGhostColourNone()
} }
gameInitialised = true gameInitialised = true
@@ -231,7 +231,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
actorContainerInactive.forEach { it.dispose() } actorContainerInactive.forEach { it.dispose() }
world.dispose() world.dispose()
disposables.forEach { it.tryDispose() } // disposables.forEach { it.tryDispose() }
} }
//////////// ////////////
@@ -533,7 +533,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
fun getActorsAt(worldX: Double, worldY: Double): List<ActorWithBody> { fun getActorsAt(worldX: Double, worldY: Double): List<ActorWithBody> {
val outList = ArrayList<ActorWithBody>() val outList = ArrayList<ActorWithBody>()
try { try {
actorsRTree.find(worldX, worldY, worldX, worldY, outList) actorsRTree.find(worldX - 0.5, worldY - 0.5, worldX + 0.5, worldY + 0.5, outList)
} }
catch (e: NullPointerException) {} catch (e: NullPointerException) {}
return outList return outList

View File

@@ -14,6 +14,7 @@ import net.torvald.terrarum.blockproperties.OreCodex
import net.torvald.terrarum.blockproperties.WireCodex import net.torvald.terrarum.blockproperties.WireCodex
import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gamecontroller.IME import net.torvald.terrarum.gamecontroller.IME
import net.torvald.terrarum.gameitems.FixtureInteractionBlocked
import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.itemproperties.CraftingCodex import net.torvald.terrarum.itemproperties.CraftingCodex
@@ -564,11 +565,13 @@ object ModMgr {
Terrarum.wireCodex.fromModule(module, "wires/") { wire -> Terrarum.wireCodex.fromModule(module, "wires/") { wire ->
} }
Terrarum.wireCodex.portsFromModule(module, "wires/")
Terrarum.wireCodex.wireDecaysFromModule(module, "wires/")
} }
private fun makeNewItemObj(tile: BlockProp, isWall: Boolean) = object : GameItem( private fun makeNewItemObj(tile: BlockProp, isWall: Boolean) = object : GameItem(
if (isWall) "wall@"+tile.id else tile.id if (isWall) "wall@"+tile.id else tile.id
) { ), FixtureInteractionBlocked {
override var baseMass: Double = (tile.density / 100.0) * (if (tile.isPlatform) 0.5 else 1.0) override var baseMass: Double = (tile.density / 100.0) * (if (tile.isPlatform) 0.5 else 1.0)
override var baseToolSize: Double? = null override var baseToolSize: Double? = null
override var inventoryCategory = if (isWall) Category.WALL else Category.BLOCK override var inventoryCategory = if (isWall) Category.WALL else Category.BLOCK
@@ -844,11 +847,16 @@ object ModMgr {
object GameCraftingRecipeLoader { object GameCraftingRecipeLoader {
const val recipePath = "crafting/" const val recipePath = "crafting/"
const val smeltingPath = "smelting/"
@JvmStatic operator fun invoke(module: String) { @JvmStatic operator fun invoke(module: String) {
getFile(module, recipePath).listFiles { it: File -> it.name.lowercase().endsWith(".json") }?.forEach { jsonFile -> getFile(module, recipePath).listFiles { it: File -> it.name.lowercase().endsWith(".json") }?.forEach { jsonFile ->
Terrarum.craftingCodex.addFromJson(JsonFetcher(jsonFile), module, jsonFile.name) Terrarum.craftingCodex.addFromJson(JsonFetcher(jsonFile), module, jsonFile.name)
} }
getFile(module, smeltingPath).listFiles { it: File -> it.name.lowercase().endsWith(".json") }?.forEach { jsonFile ->
Terrarum.craftingCodex.addSmeltingFromJson(JsonFetcher(jsonFile), module, jsonFile.name)
}
} }
} }

View File

@@ -12,13 +12,13 @@ object ReferencingRanges {
val ITEMS_DYNAMIC = 0x10_0000..0x0FFF_FFFF // 267 386 880 pseudo-items val ITEMS_DYNAMIC = 0x10_0000..0x0FFF_FFFF // 267 386 880 pseudo-items
val ACTORS = 0x1000_0000..0x7FFE_FFFF val ACTORS = 0x1000_0000..0x7FFE_FFFF
// there is a gap between 0x7FFF_0000..0x7FFF_BFFF // there is a gap between 0x7FFF_0000..0x7FFF_7FFF
// IDs doesn't effect the render order at all, but we're kinda enforcing these ID ranging. // IDs doesn't effect the render order at all, but we're kinda enforcing these ID ranging.
// However, these two wire-related actor will break the rule. But as we want them to render on top of others // However, these two wire-related actor will break the rule. But as we want them to render on top of others
// in the same render orders, we're giveng them relatively high IDs for them. // in the same render orders, we're giveng them relatively high IDs for them.
val ACTORS_WIRES = 0x7FFF_C000..0x7FFF_EFFF // Rendered front--wires val ACTORS_WIRE_PORTS = 0x7FFF_8000..0x7FFF_BEFF // Rendered front--wires
val ACTORS_WIRES_HELPER = 0x7FFF_F000..0x7FFF_FEFF // Rendered overlay--wiring port icons and logic gates val ACTORS_WIRES = 0x7FFF_BF00..0x7FFF_FEFF // Rendered overlay--wiring port icons
val ACTORS_INTERNAL_USE = 0x7FFF_FF00..0x7FFF_FFFF // Actor ID 0x7FFF_FFFF is pre-assigned to the block cursor! val ACTORS_INTERNAL_USE = 0x7FFF_FF00..0x7FFF_FFFF // Actor ID 0x7FFF_FFFF is pre-assigned to the block cursor!

View File

@@ -477,7 +477,8 @@ fun blendMul(batch: SpriteBatch) {
fun blendAlphaMask(batch: SpriteBatch) { fun blendAlphaMask(batch: SpriteBatch) {
batch.enableBlending() batch.enableBlending()
batch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_ALPHA) // batch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_ALPHA)
batch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_COLOR)
} }
/** /**

View File

@@ -69,13 +69,29 @@ basegame
* e.g. 0x02010034 will be translated as 2.1.52 * e.g. 0x02010034 will be translated as 2.1.52
* *
*/ */
const val VERSION_RAW: Long = 0x0000_000004_000001 const val VERSION_RAW: Long = 0x0000_000004_000002
// Commit counts up to the Release 0.3.0: 2259 // 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.1: 2278
// Commit counts up to the Release 0.3.2: 2732 // Commit counts up to the Release 0.3.2: 2732
// Commit counts up to the Release 0.3.3: 3020 // Commit counts up to the Release 0.3.3: 3020
// Commit counts up to the Release 0.4.0: 3631 // Commit counts up to the Release 0.4.0: 3631
// Commit counts up to the Release 0.4.1: 3678 // Commit counts up to the Release 0.4.1: 3678
// Commit counts up to the Release 0.4.2: 3762
val DEV_CYCLE: Map<String, Long> = mapOf(
"Alpha" to 0x0000_000004_000000,
"Beta" to 0x0000_FFFFFF_000000,
)
val VERSION_NUMBER: String = String.format(
"%d.%d.%d",
VERSION_RAW ushr 48,
(VERSION_RAW and 0xffff000000L) ushr 24,
VERSION_RAW and 0xffffffL
)
private val DEV_CYCLE_LIST_SORTED = DEV_CYCLE.toList().sortedBy { it.second }
val CURRENT_DEV_CYCLE: String? = DEV_CYCLE_LIST_SORTED.map { it.first to VERSION_RAW - it.second }.firstOrNull { it.second >= 0L }?.first
// val VERSION_SNAPSHOT = Snapshot(0) // for normal dev // val VERSION_SNAPSHOT = Snapshot(0) // for normal dev
// val VERSION_SNAPSHOT = ForcedSnapshot("24w07d") // for snapshot release // val VERSION_SNAPSHOT = ForcedSnapshot("24w07d") // for snapshot release
@@ -83,6 +99,70 @@ basegame
const val VERSION_TAG: String = "" const val VERSION_TAG: String = ""
val VERSION_STRING: String
get() {
val major = if (VERSION_RAW >= 0x0001_000000_000000)
VERSION_NUMBER
else if (CURRENT_DEV_CYCLE != null) {
val delta = VERSION_RAW - DEV_CYCLE[CURRENT_DEV_CYCLE]!!
CURRENT_DEV_CYCLE + " " + String.format("%d.%d", ((delta and 0xffff000000L) ushr 24) + 1, delta and 0xffffffL)
}
else
VERSION_NUMBER
val tag = if (VERSION_TAG.isNotBlank()) "-$VERSION_TAG" else ""
val snapshot = if (VERSION_SNAPSHOT == null) "" else " ($VERSION_SNAPSHOT)"
return "$major$tag$snapshot"
}
val VERSION_STRING_WITHOUT_SNAPSHOT: String
get() {
val major = if (VERSION_RAW >= 0x0001_000000_000000)
VERSION_NUMBER
else if (CURRENT_DEV_CYCLE != null) {
val delta = VERSION_RAW - DEV_CYCLE[CURRENT_DEV_CYCLE ?: ""]!!
CURRENT_DEV_CYCLE + " " + String.format("%d.%d", ((delta and 0xffff000000L) ushr 24) + 1, delta and 0xffffffL)
}
else
VERSION_NUMBER
val tag = if (VERSION_TAG.isNotBlank()) "-$VERSION_TAG" else ""
return "$major$tag"
}
fun convertVersionNumberToReadable(semverStr: String, snapshotObj: Snapshot? = null): String {
val numbers = semverStr.split('.')
val maj = numbers[0].toLong()
val min = numbers.getOrNull(1)?.toLong() ?: 0L
val pat = numbers.getOrNull(2)?.toLong() ?: 0L
val VERSION_RAW = maj.shl(48) or min.shl(24) or pat
val CURRENT_DEV_CYCLE: String? = DEV_CYCLE_LIST_SORTED.map { it.first to VERSION_RAW - it.second }.firstOrNull { it.second >= 0L }?.first
val major = if (VERSION_RAW >= 0x0001_000000_000000)
semverStr
else if (CURRENT_DEV_CYCLE != null) {
val delta = VERSION_RAW - DEV_CYCLE[CURRENT_DEV_CYCLE]!!
CURRENT_DEV_CYCLE + " " + String.format("%d.%d", ((delta and 0xffff000000L) ushr 24) + 1, delta and 0xffffffL)
}
else
semverStr
// val tag = if (VERSION_TAG.isNotBlank()) "-$VERSION_TAG" else ""
val snapshot = if (snapshotObj == null) "" else " (${snapshotObj})"
return "$major$snapshot"
}
fun convertVersionNumberToReadableShort(semverStr: String, snapshotObj: Snapshot? = null): String {
val s = convertVersionNumberToReadable(semverStr, snapshotObj)
return s.replace("Alpha", "α").replace("Beta", "β")
}
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
// CONFIGURATION FOR TILE MAKER // // CONFIGURATION FOR TILE MAKER //
// MAKE SURE THESE VALUES ARE UNIQUE IN THE SOURCE CODE // // MAKE SURE THESE VALUES ARE UNIQUE IN THE SOURCE CODE //

View File

@@ -350,7 +350,7 @@ object TerrarumPostProcessor : Disposable {
private val defaultResStr = "Ingame UI Area" private val defaultResStr = "Ingame UI Area"
private val currentResStr = "${App.scr.width}x${App.scr.height}" private val currentResStr = "${App.scr.width}x${App.scr.height}"
private val safeAreaStr = "TV Safe Area" private val safeAreaStr = "TV Safe Area"
private val versionStr = "Version ${App.getVERSION_STRING()}" private val versionStr = "${App.getVERSION_STRING()}"
internal val thisIsDebugStr = "${App.GAME_NAME} ${if (App.IS_DEVELOPMENT_BUILD) "Development Build" else "Release"} $versionStr" internal val thisIsDebugStr = "${App.GAME_NAME} ${if (App.IS_DEVELOPMENT_BUILD) "Development Build" else "Release"} $versionStr"
/** /**

View File

@@ -1,10 +1,12 @@
package net.torvald.terrarum.blockproperties package net.torvald.terrarum.blockproperties
import com.badlogic.gdx.files.FileHandle
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.modulebasegame.gameactors.WireEmissionType
import net.torvald.terrarum.utils.CSVFetcher import net.torvald.terrarum.utils.CSVFetcher
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
@@ -17,9 +19,12 @@ import java.io.IOException
class WireCodex { class WireCodex {
@Transient val wireProps = HashMap<ItemID, WireProp>() @Transient val wireProps = HashMap<ItemID, WireProp>()
@Transient private val nullProp = WireProp() @Transient private val nullProp = WireProp()
@Transient val wirePorts = HashMap<WireEmissionType, Triple<TextureRegionPack, Int, Int>>()
@Transient val wireDecays = HashMap<ItemID, Double>()
fun clear() { fun clear() {
wireProps.clear() wireProps.clear()
} }
@@ -81,6 +86,62 @@ class WireCodex {
} }
fun portsFromModule(module: String, path: String) {
printdbg(this, "Building wire ports table for module $module")
try {
registerPorts(module, path, CSVFetcher.readFromModule(module, path + "wireports.csv"))
}
catch (e: IOException) { e.printStackTrace() }
}
private fun registerPorts(module: String, path: String, records: List<CSVRecord>) {
val spriteSheetFiles = ArrayList<Pair<FileHandle, String>>()
val tempRecords = HashMap<WireEmissionType, Triple<String, Int, Int>>()
records.forEach {
val type = it.get("accepts")
val fileModule = it.get("fileModule")
val filePath = it.get("file")
val x = it.get("xpos").toInt()
val y = it.get("ypos").toInt()
val file = ModMgr.getGdxFile(fileModule, filePath)
val fileID = "wireport:$fileModule.${filePath.replace('\\','/')}"
spriteSheetFiles.add(file to fileID)
tempRecords[type] = Triple(fileID, x, y)
}
spriteSheetFiles.forEach { (file, id) ->
CommonResourcePool.addToLoadingList(id) {
TextureRegionPack(file, TILE_SIZE, TILE_SIZE)
}
}
CommonResourcePool.loadAll()
tempRecords.forEach { type, (fileID, x, y) ->
wirePorts[type] = Triple(CommonResourcePool.getAsTextureRegionPack(fileID), x, y)
}
}
fun wireDecaysFromModule(module: String, path: String) {
printdbg(this, "Building wire ports table for module $module")
try {
registerDecays(module, path, CSVFetcher.readFromModule(module, path + "decayconsts.csv"))
}
catch (e: IOException) { e.printStackTrace() }
}
private fun registerDecays(module: String, path: String, records: List<CSVRecord>) {
records.forEach {
val item = it.get("wireItemID")
val d = it.get("const").toDouble()
wireDecays[item] = d
}
}
fun getAll() = wireProps.values fun getAll() = wireProps.values
/*fun get(index: Int): WireProp { /*fun get(index: Int): WireProp {
@@ -159,4 +220,8 @@ class WireCodex {
fun getAllWiresThatAccepts(accept: String): List<Pair<ItemID, WireProp>> { fun getAllWiresThatAccepts(accept: String): List<Pair<ItemID, WireProp>> {
return wireProps.filter { it.value.accepts == accept }.toList() return wireProps.filter { it.value.accepts == accept }.toList()
} }
fun getWirePortSpritesheet(emissionType: WireEmissionType): Triple<TextureRegionPack, Int, Int>? {
return wirePorts[emissionType]
}
} }

View File

@@ -122,6 +122,8 @@ object AVKey {
const val __PLAYER_QUICKSLOTSEL = "__quickslotselection" const val __PLAYER_QUICKSLOTSEL = "__quickslotselection"
const val __PLAYER_WIRECUTTERSEL = "__wirecutterselection"
/** Double /** Double
* When using tool/arm/etc. how long action button is held, in milliseconds (Int) * When using tool/arm/etc. how long action button is held, in milliseconds (Int)
* Or for NPCs, how long it has been waiting for next move * Or for NPCs, how long it has been waiting for next move

View File

@@ -51,6 +51,7 @@ abstract class Actor : Comparable<Actor>, Runnable {
enum class RenderOrder { enum class RenderOrder {
FAR_BEHIND, // wires
BEHIND, // tapestries, some particles (obstructed by terrain) BEHIND, // tapestries, some particles (obstructed by terrain)
MIDDLE, // actors MIDDLE, // actors
MIDTOP, // bullets, thrown items MIDTOP, // bullets, thrown items

View File

@@ -23,6 +23,7 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellCommonRes.tooltipShowing
import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.worlddrawer.CreateTileAtlas import net.torvald.terrarum.worlddrawer.CreateTileAtlas
import net.torvald.terrarum.worlddrawer.WorldCamera import net.torvald.terrarum.worlddrawer.WorldCamera
@@ -97,6 +98,8 @@ open class ActorWithBody : Actor {
val mouseUp: Boolean val mouseUp: Boolean
get() = hitbox.containsPoint((world?.width ?: 0) * TILE_SIZED, Terrarum.mouseX, Terrarum.mouseY) get() = hitbox.containsPoint((world?.width ?: 0) * TILE_SIZED, Terrarum.mouseX, Terrarum.mouseY)
@Transient protected val tooltipHash = System.nanoTime()
var hitboxTranslateX: Int = 0// relative to spritePosX var hitboxTranslateX: Int = 0// relative to spritePosX
protected set protected set
var hitboxTranslateY: Int = 0// relative to spritePosY var hitboxTranslateY: Int = 0// relative to spritePosY
@@ -669,11 +672,15 @@ open class ActorWithBody : Actor {
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt()) feetPosTile.set(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
if (mouseUp && this.tooltipText != null) INGAME.setTooltipMessage(this.tooltipText) if (mouseUp && tooltipText != null && tooltipShowing[tooltipHash] != true) {
INGAME.setTooltipMessage(tooltipText)
tooltipShowing[tooltipHash] = true
}
} }
// make sure tooltip to disable even when the actor's update is paused at unfortunate time if (tooltipText == null || !mouseUp || flagDespawn) {
if (!mouseUp && INGAME.getTooltipMessage() == this.tooltipText) INGAME.setTooltipMessage(null) tooltipShowing[tooltipHash] = false
}
// isStationary = (hitbox - oldHitbox).magnitudeSquared < PHYS_EPSILON_VELO // isStationary = (hitbox - oldHitbox).magnitudeSquared < PHYS_EPSILON_VELO
isStationary = isCloseEnough(hitbox.startX, oldHitbox.startX) && // this is supposed to be more accurate, idk isStationary = isCloseEnough(hitbox.startX, oldHitbox.startX) && // this is supposed to be more accurate, idk
@@ -887,7 +894,7 @@ open class ActorWithBody : Actor {
debug1("translate x by $t") debug1("translate x by $t")
} }
/* 4, 14 */ COLLIDING_RIGHT, COLLIDING_RIGHT or COLLIDING_UD -> { /* 4, 14 */ COLLIDING_RIGHT, COLLIDING_RIGHT or COLLIDING_UD -> {
val t = -newHitbox.endX.modTileDelta() val t = -newHitbox.endX.modTileDelta() - PHYS_EPSILON_DIST // THE cheapest way to resolve right-sided phys bug
newHitbox.translatePosX(t); bounceX = true newHitbox.translatePosX(t); bounceX = true
debug1("translate x by $t") debug1("translate x by $t")
} }
@@ -972,7 +979,8 @@ open class ActorWithBody : Actor {
debug1("offendingTileWorldY=$offendingTileWorldY, offendingHitboxPointY=$offendingHitboxPointY") debug1("offendingTileWorldY=$offendingTileWorldY, offendingHitboxPointY=$offendingHitboxPointY")
val displacementAbs = Vector2( val displacementAbs = Vector2(
(offendingTileWorldX - offendingHitboxPointX).abs(), (offendingTileWorldX - offendingHitboxPointX).abs() +
if (selfCollisionStatus and COLLIDING_RIGHT != 0) PHYS_EPSILON_DIST else 0.0, // THE cheapest way to resolve right-sided phys bug
(offendingTileWorldY - offendingHitboxPointY).abs() (offendingTileWorldY - offendingHitboxPointY).abs()
) )
@@ -1856,6 +1864,23 @@ open class ActorWithBody : Actor {
} }
} }
fun drawTextureInGoodPosition(frameDelta: Float, texture: TextureRegion, batch: SpriteBatch, forcedColourFilter: Color? = null) {
if (world == null) return
val offsetX = 0f
val offsetY = 0f
val posX = hitbox.startX.plus(PHYS_EPSILON_DIST).toFloat()
val posY = hitbox.startY.plus(PHYS_EPSILON_DIST).toFloat()
drawBodyInGoodPosition(posX, posY) { x, y ->
val oldCol = batch.color.cpy()
batch.color = if (forcedColourFilter != null) forcedColourFilter else Color.WHITE
batch.draw(texture, x + offsetX, y + offsetY)
batch.color = oldCol
}
}
override fun onActorValueChange(key: String, value: Any?) { override fun onActorValueChange(key: String, value: Any?) {
// do nothing // do nothing
} }
@@ -1922,6 +1947,7 @@ open class ActorWithBody : Actor {
internal open fun flagDespawn() { internal open fun flagDespawn() {
flagDespawn = true flagDespawn = true
tooltipShowing.remove(tooltipHash)
} }
open fun getSpriteHead(): TextureRegion? { open fun getSpriteHead(): TextureRegion? {
@@ -2245,6 +2271,7 @@ open class ActorWithBody : Actor {
App.disposables.add(sprite) App.disposables.add(sprite)
App.disposables.add(spriteGlow) App.disposables.add(spriteGlow)
App.disposables.add(spriteEmissive) App.disposables.add(spriteEmissive)
tooltipShowing.remove(tooltipHash)
} }
} }

View File

@@ -25,7 +25,7 @@ import kotlin.math.floor
class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = PhysProperties.MOBILE_OBJECT()), NoSerialise { class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = PhysProperties.MOBILE_OBJECT()), NoSerialise {
enum class MarkerMode { enum class MarkerMode {
FIXTURE_GHOST, BLOCK_MARKER FIXTURE_GHOST, BLOCK_MARKER, HIDDEN
} }
private val defaultSize = 16.0 private val defaultSize = 16.0
@@ -45,12 +45,14 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
init { init {
this.isVisible = false this.isVisible = true
renderOrder = Actor.RenderOrder.OVERLAY // for some reason the constructor didn't work renderOrder = Actor.RenderOrder.OVERLAY // for some reason the constructor didn't work
} }
override fun drawBody(frameDelta: Float, batch: SpriteBatch) { override fun drawBody(frameDelta: Float, batch: SpriteBatch) {
this.isVisible = true
if (isVisible) { if (isVisible) {
if (markerMode == MarkerMode.FIXTURE_GHOST) { if (markerMode == MarkerMode.FIXTURE_GHOST) {
if (INGAME.actorNowPlaying != null) { if (INGAME.actorNowPlaying != null) {
@@ -114,6 +116,16 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
ghost = null ghost = null
setGhostColourNone() setGhostColourNone()
hitbox.setDimension(TILE_SIZED, TILE_SIZED) hitbox.setDimension(TILE_SIZED, TILE_SIZED)
markerMode = MarkerMode.HIDDEN
}
fun hideMarker() {
unsetGhost()
}
fun showMarker(shape: Int) {
markerShape = shape
markerMode = MarkerMode.BLOCK_MARKER
} }
fun setGhostColourNone() { ghostColour = Color.WHITE } fun setGhostColourNone() { ghostColour = Color.WHITE }

View File

@@ -1,26 +1,28 @@
package net.torvald.terrarum.gameactors package net.torvald.terrarum.gameactors
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.spriteanimation.SheetSpriteAnimation import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.WireEmissionType
import net.torvald.terrarum.ui.Toolkit
import kotlin.math.cos
/**
* Created by minjaesong on 2024-03-05.
*/
interface InternalActor {
}
/** /**
* FIXME Constructor is super expensive
*
* Created by minjaesong on 2021-07-30. * Created by minjaesong on 2021-07-30.
*/ */
class WireActor : ActorWithBody, NoSerialise { class WireActor : ActorWithBody, NoSerialise, InternalActor {
companion object {
val WIRE_NEARBY = arrayOf(
(+1 to 0), // tileR
(0 to +1), // tileB
(-1 to 0), // tileL
(0 to -1) // tileT
)
}
private constructor() private constructor()
@@ -34,7 +36,6 @@ class WireActor : ActorWithBody, NoSerialise {
private var worldX = 0 private var worldX = 0
private var worldY = 0 private var worldY = 0
/** /**
* @param itemID must start with "wire@" * @param itemID must start with "wire@"
*/ */
@@ -60,34 +61,99 @@ class WireActor : ActorWithBody, NoSerialise {
(sprite as SheetSpriteAnimation).currentFrame = cnx (sprite as SheetSpriteAnimation).currentFrame = cnx
} }
private fun getNearbyTilesPos(x: Int, y: Int): Array<Point2i> { override fun updateImpl(delta: Float) {
return arrayOf( }
Point2i(x + 1, y),
Point2i(x, y + 1), private fun essfun0(x: Double) = -cos(Math.PI * x) / 2.0 + 0.5
Point2i(x - 1, y), private fun essfun(x: Double) = essfun0(x)
Point2i(x, y - 1)
) override fun drawBody(frameDelta: Float, batch: SpriteBatch) {
if (isVisible && sprite != null) {
BlendMode.resolve(drawMode, batch)
// signal wires?
if (WireCodex.wireProps[wireID]?.accepts == "digital_bit") {
val strength = world?.getWireEmitStateOf(worldX, worldY, wireID)?.x ?: 0.0
// draw base (unlit) sprite
batch.color = Color.WHITE
(sprite as SheetSpriteAnimation).currentRow = 0
drawSpriteInGoodPosition(frameDelta, sprite!!, batch, 0, Color.WHITE)
// draw lit sprite
val alpha = Color(1f, 1f, 1f, essfun(strength.coerceIn(0.0, 1.0)).toFloat())
(sprite as SheetSpriteAnimation).currentRow = 1
drawSpriteInGoodPosition(frameDelta, sprite!!, batch, 0, alpha)
}
else {
(sprite as SheetSpriteAnimation).currentRow = 0
drawSpriteInGoodPosition(frameDelta, sprite!!, batch, 0, Color.WHITE)
}
}
}
}
/**
* Created by minjaesong on 2024-03-07.
*/
class WirePortActor : ActorWithBody, NoSerialise, InternalActor {
private constructor()
constructor(id: ActorID) : super(RenderOrder.OVERLAY, PhysProperties.IMMOBILE(), id)
init {
setHitboxDimension(TILE_SIZE, TILE_SIZE, 0, 0)
renderOrder = RenderOrder.OVERLAY
}
private var portID: WireEmissionType = ""
private var worldX = 0
private var worldY = 0
/**
*/
fun setPort(emissionType: WireEmissionType, worldX: Int, worldY: Int) {
setHitboxDimension(TILE_SIZE, TILE_SIZE, 0, 0)
if (portID != emissionType) {
WireCodex.getWirePortSpritesheet(emissionType)?.let { (sheet, x, y) ->
if (sprite == null) {
makeNewSprite(sheet).let {
it.delays = floatArrayOf(Float.POSITIVE_INFINITY,Float.POSITIVE_INFINITY,Float.POSITIVE_INFINITY,Float.POSITIVE_INFINITY)
it.setRowsAndFrames(1, 16)
}
}
else {
(sprite as SheetSpriteAnimation).let {
it.setSpriteImage(sheet)
}
}
(sprite as SheetSpriteAnimation).let {
it.currentFrame = x
it.currentRow = y
}
portID = emissionType
}
}
this.worldX = worldX
this.worldY = worldY
setPosition((worldX + 0.5) * TILE_SIZE, (worldY + 1.0) * TILE_SIZE - 1.0) // what the fuck?
} }
override fun updateImpl(delta: Float) { override fun updateImpl(delta: Float) {
} }
override fun drawBody(frameDelta: Float, batch: SpriteBatch) { override fun drawBody(frameDelta: Float, batch: SpriteBatch) {
if (isVisible && sprite != null) { if (isVisible && sprite != null && (Terrarum.ingame!! as TerrarumIngame).selectedWireRenderClass.isNotBlank()) {
if (WireCodex[wireID].accepts == "digital_3bits") {
// "digital_3bits" must come right after three wires it bundles
val rootID = wireID.substringBefore(':') + ":"
var row = 0
(WireCodex[wireID].numericID - 3 .. WireCodex[wireID].numericID - 1).forEachIndexed { index, it ->
val itemID = rootID + it
row = row or ((world?.getWireEmitStateOf(worldX, worldY, itemID)?.isNotZero == true).toInt() shl index)
}
(sprite as SheetSpriteAnimation).currentRow = row
}
else {
(sprite as SheetSpriteAnimation).currentRow = (world?.getWireEmitStateOf(worldX, worldY, wireID)?.isNotZero == true).toInt()
}
BlendMode.resolve(drawMode, batch) BlendMode.resolve(drawMode, batch)
drawSpriteInGoodPosition(frameDelta, sprite!!, batch) drawSpriteInGoodPosition(frameDelta, sprite!!, batch)
} }

View File

@@ -208,7 +208,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
} }
} }
terrarumIngame.uiContainer.forEach { it?.keyDown(keycode) } // for KeyboardControlled UIcanvases terrarumIngame.uiContainer.forEach { if (it?.justOpened == false) it.keyDown(keycode) } // for KeyboardControlled UIcanvases
// Debug UIs // Debug UIs
if (keycode == Input.Keys.GRAVE) { if (keycode == Input.Keys.GRAVE) {
@@ -233,7 +233,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
terrarumIngame.uiQuickBar.setAsOpen() terrarumIngame.uiQuickBar.setAsOpen()
} }
terrarumIngame.uiContainer.forEach { it?.keyUp(keycode) } // for KeyboardControlled UIcanvases terrarumIngame.uiContainer.forEach { if (it?.justOpened == false) it.keyUp(keycode) } // for KeyboardControlled UIcanvases
// screenshot key // screenshot key
if (keycode == Input.Keys.F12) f12Down = false if (keycode == Input.Keys.F12) f12Down = false
@@ -243,27 +243,25 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
} }
override fun keyTyped(character: Char): Boolean { override fun keyTyped(character: Char): Boolean {
terrarumIngame.uiContainer.forEach { if (it?.isVisible == true) it.keyTyped(character) } terrarumIngame.uiContainer.forEach { if (it?.justOpened == false && it.isVisible) it.keyTyped(character) }
return true return true
} }
private fun tTouchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean { private fun tTouchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
// don't separate Player from this! Physics will break, esp. airborne manoeuvre // disable the IFs: the "unlatching" must happen no matter what, even if a UI is been opened
if (!terrarumIngame.paused && !terrarumIngame.playerControlDisabled) {
// fire world click events; the event is defined as Ingame's (or any others') WorldClick event
if (terrarumIngame.uiContainer.map { if ((it?.isOpening == true || it?.isOpened == true) && it.mouseUp) 1 else 0 }.sum() == 0) { // no UI on the mouse, right?
if ( // if (!terrarumIngame.paused && !terrarumIngame.playerControlDisabled) {
terrarumIngame.actorNowPlaying != null && // fire world click events; the event is defined as Ingame's (or any others') WorldClick event
(button == App.getConfigInt("config_mouseprimary") || // if (terrarumIngame.uiContainer.map { if ((it?.isOpening == true || it?.isOpened == true) && it.mouseUp) 1 else 0 }.sum() == 0) { // no UI on the mouse, right?
button == App.getConfigInt("config_mousesecondary"))) {
if (button == App.getConfigInt("config_mouseprimary")) {
terrarumIngame.worldPrimaryClickEnd(terrarumIngame.actorNowPlaying!!, App.UPDATE_RATE) terrarumIngame.worldPrimaryClickEnd(terrarumIngame.actorNowPlaying!!, App.UPDATE_RATE)
} }
if (button == App.getConfigInt("config_mousesecondary")) { if (button == App.getConfigInt("config_mousesecondary")) {
terrarumIngame.worldSecondaryClickEnd(terrarumIngame.actorNowPlaying!!, App.UPDATE_RATE) terrarumIngame.worldSecondaryClickEnd(terrarumIngame.actorNowPlaying!!, App.UPDATE_RATE)
} }
} // }
} // }
// pie menu // pie menu
if (button == App.getConfigInt("control_mouse_quicksel")) { if (button == App.getConfigInt("control_mouse_quicksel")) {
@@ -271,7 +269,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
terrarumIngame.uiQuickBar.setAsOpen() terrarumIngame.uiQuickBar.setAsOpen()
} }
terrarumIngame.uiContainer.forEach { it?.touchUp(screenX, screenY, pointer, button) } // for MouseControlled UIcanvases terrarumIngame.uiContainer.forEach { if (it?.justOpened == false) it.touchUp(screenX, screenY, pointer, button) } // for MouseControlled UIcanvases
return true return true
} }
@@ -289,17 +287,17 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
it.actorValue.set(AVKey.__PLAYER_QUICKSLOTSEL, selection fmod UIQuickslotBar.SLOT_COUNT) it.actorValue.set(AVKey.__PLAYER_QUICKSLOTSEL, selection fmod UIQuickslotBar.SLOT_COUNT)
} }
} }
terrarumIngame.uiContainer.forEach { it?.scrolled(amountX, amountY) } terrarumIngame.uiContainer.forEach { if (it?.justOpened == false) it.scrolled(amountX, amountY) }
return true return true
} }
private fun tTouchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean { private fun tTouchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
terrarumIngame.uiContainer.forEach { it?.touchDragged(screenX, screenY, pointer) } terrarumIngame.uiContainer.forEach { if (it?.justOpened == false) it.touchDragged(screenX, screenY, pointer) }
return true return true
} }
private fun tTouchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean { private fun tTouchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
terrarumIngame.uiContainer.forEach { it?.touchDown(screenX, screenY, pointer, button) } terrarumIngame.uiContainer.forEach { if (it?.justOpened == false) it.touchDown(screenX, screenY, pointer, button) }
// pie menu // pie menu
if (button == App.getConfigInt("control_mouse_quicksel")) { if (button == App.getConfigInt("control_mouse_quicksel")) {

View File

@@ -47,8 +47,6 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
*/ */
@Transient open var smokiness = Float.POSITIVE_INFINITY @Transient open var smokiness = Float.POSITIVE_INFINITY
@Transient open var smeltingProduct: ItemID? = null
open var dynamicID: ItemID = originalID open var dynamicID: ItemID = originalID
/** /**
* if the ID is a Actor range, it's an actor contained in a pocket. * if the ID is a Actor range, it's an actor contained in a pocket.
@@ -103,8 +101,10 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
var itemProperties = ItemValue() var itemProperties = ItemValue()
/** Single-use then destroyed (e.g. Tiles), same as "consumable" */ /** Single-use then destroyed (e.g. Tiles) */
@Transient var stackable: Boolean = true @Transient var stackable: Boolean = true
val isConsumable: Boolean
get() = stackable && !canBeDynamic
/** /**
@@ -211,12 +211,12 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
@Transient var tags = HashSet<String>() @Transient var tags = HashSet<String>()
/** /**
* Tags added/removed by dynamic items * Tags added/removed by dynamic items (e.g. enchanting)
*/ */
var modifiers = HashSet<String>() var modifiers = HashSet<String>()
/** /**
* Mainly intended to be used by third-party modules * Used to hold extra data. Keys are case-insensitive and gets converted to lowercase.
*/ */
open val extra = Codex() open val extra = Codex()
@@ -256,8 +256,6 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
open fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long = -1 open fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long = -1
/** /**
* I have decided that left and right clicks must do the same thing, so no secondary use from now on. --Torvald on 2019-05-26
*
* Apply effects (continuously or not) while secondary button is down * Apply effects (continuously or not) while secondary button is down
* The item will NOT be consumed, so you will want to consume it yourself by inventory.consumeItem(item) * The item will NOT be consumed, so you will want to consume it yourself by inventory.consumeItem(item)
* *
@@ -267,10 +265,10 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
* *
* note: DO NOT super() this! * note: DO NOT super() this!
*/ */
//open fun startSecondaryUse(delta: Float): Boolean = false open fun startSecondaryUse(actor: ActorWithBody, delta: Float): Long = -1
open fun endPrimaryUse(actor: ActorWithBody, delta: Float): Boolean = false open fun endPrimaryUse(actor: ActorWithBody, delta: Float): Boolean = false
//open fun endSecondaryUse(actor: ActorWithBody, delta: Float): Boolean = false open fun endSecondaryUse(actor: ActorWithBody, delta: Float): Boolean = false
/** /**
* Effects applied immediately only once when thrown (discarded) from pocket * Effects applied immediately only once when thrown (discarded) from pocket
@@ -370,7 +368,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
@JvmStatic val MISC = "misc" @JvmStatic val MISC = "misc"
} }
override public fun clone(): GameItem { public override fun clone(): GameItem {
val clonedItem = super.clone() val clonedItem = super.clone()
// properly clone ItemValue // properly clone ItemValue
(clonedItem as GameItem).itemProperties = this.itemProperties.clone() (clonedItem as GameItem).itemProperties = this.itemProperties.clone()
@@ -378,8 +376,17 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
return clonedItem return clonedItem
} }
fun makeDynamic(inventory: ActorInventory): GameItem {
return this.clone().also {
it.generateUniqueDynamicID(inventory)
it.stackable = false
}
}
fun generateUniqueDynamicID(inventory: ActorInventory): GameItem {
private fun generateUniqueDynamicID(inventory: ActorInventory): GameItem {
dynamicID = "$PREFIX_DYNAMICITEM:${Companion.generateUniqueDynamicID(inventory)}" dynamicID = "$PREFIX_DYNAMICITEM:${Companion.generateUniqueDynamicID(inventory)}"
ItemCodex.registerNewDynamicItem(dynamicID, this) ItemCodex.registerNewDynamicItem(dynamicID, this)
return this return this
@@ -397,7 +404,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
fun generateUniqueDynamicID(inventory: ActorInventory): Int { fun generateUniqueDynamicID(inventory: ActorInventory): Int {
var ret: Int var ret: Int
do { do {
ret = (1..2147483647).random() ret = (1..999999999).random()
} while (inventory.contains("$PREFIX_DYNAMICITEM:$ret")) } while (inventory.contains("$PREFIX_DYNAMICITEM:$ret"))
return ret return ret
@@ -451,3 +458,8 @@ fun ItemID.isBlock() = !this.contains('@') && !this.isDynamic()
fun ItemID.isWall() = this.startsWith("wall@") fun ItemID.isWall() = this.startsWith("wall@")
fun ItemID.isFluid() = this.startsWith("fluid@") fun ItemID.isFluid() = this.startsWith("fluid@")
fun ItemID.isOre() = this.startsWith("ores@") fun ItemID.isOre() = this.startsWith("ores@")
/**
* Created by minjaesong on 2024-03-06.
*/
interface FixtureInteractionBlocked

View File

@@ -1,12 +1,13 @@
package net.torvald.terrarum.gameworld package net.torvald.terrarum.gameworld
import net.torvald.terrarum.App import net.torvald.terrarum.App
import net.torvald.terrarum.gameworld.WorldSimulator.FLUID_MIN_MASS
import net.torvald.terrarum.serialise.toUint import net.torvald.terrarum.serialise.toUint
import net.torvald.unsafe.UnsafeHelper import net.torvald.unsafe.UnsafeHelper
import net.torvald.unsafe.UnsafePtr import net.torvald.unsafe.UnsafePtr
import net.torvald.util.Float16 import net.torvald.util.Float16
const val FLUID_MIN_MASS = 1f / 1024f //Ignore cells that are almost dry (smaller than epsilon of float16)
/** /**
* * Memory layout: * * Memory layout:
* * ``` * * ```

View File

@@ -12,6 +12,7 @@ import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameitems.isFluid import net.torvald.terrarum.gameitems.isFluid
import net.torvald.terrarum.itemproperties.ItemRemapTable import net.torvald.terrarum.itemproperties.ItemRemapTable
import net.torvald.terrarum.itemproperties.ItemTable import net.torvald.terrarum.itemproperties.ItemTable
import net.torvald.terrarum.modulebasegame.WorldSimulator
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H import net.torvald.terrarum.realestate.LandUtil.CHUNK_H

View File

@@ -1,13 +1,11 @@
package net.torvald.terrarum.itemproperties package net.torvald.terrarum.itemproperties
import com.badlogic.gdx.utils.JsonValue import com.badlogic.gdx.utils.JsonValue
import net.torvald.terrarum.INGAME import net.torvald.terrarum.ItemCodex
import net.torvald.terrarum.Terrarum import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameitems.isBlock import net.torvald.terrarum.gameitems.isBlock
import net.torvald.terrarum.gameitems.isWall import net.torvald.terrarum.gameitems.isWall
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
import net.torvald.terrarum.utils.forEachSiblings import net.torvald.terrarum.utils.forEachSiblings
import net.torvald.terrarum.utils.forEachSiblingsIndexed import net.torvald.terrarum.utils.forEachSiblingsIndexed
@@ -22,6 +20,8 @@ class CraftingCodex {
*/ */
@Transient internal val props = HashMap<ItemID, ArrayList<CraftingRecipe>>() // the key ItemID and value.product must be equal @Transient internal val props = HashMap<ItemID, ArrayList<CraftingRecipe>>() // the key ItemID and value.product must be equal
@Transient internal val smeltingProps = HashMap<String, SmeltingRecipe>()
fun addRecipe(recipe: CraftingRecipe) { fun addRecipe(recipe: CraftingRecipe) {
val product = recipe.product val product = recipe.product
if (props.containsKey(product)) { if (props.containsKey(product)) {
@@ -88,6 +88,27 @@ class CraftingCodex {
} }
} }
fun addSmeltingFromJson(json: JsonValue, moduleName: String, fileName:String) {
if (moduleName.filter { it.code in 33..127 } .length < 5)
throw IllegalStateException("Invalid module name: ${moduleName}")
json.forEachSiblings { key0, details ->
val key = key0.split('+').map { it.trim() }.sorted().joinToString("+")
val difficulty = details["difficulty"].asFloat()
val recipes = ArrayList<SmeltingRecipe>()
val moq = details["product"][0].asLong()
val product = details["product"][1].asString()
// sanity check
if (moq !in 1..1000) {
throw IllegalStateException("Smelting Recipe for item '$product' has invalid moq of ${moq}")
}
// register to the main props
smeltingProps[key] = SmeltingRecipe(difficulty, key.split('+').toTypedArray(), moq, product, "$moduleName/$fileName")
}
}
/** /**
* Returns list of all possible recipes for the item; null if there is no recipe * Returns list of all possible recipes for the item; null if there is no recipe
* *
@@ -98,6 +119,55 @@ class CraftingCodex {
return it.ifEmpty { null } return it.ifEmpty { null }
} }
private fun getCombinations0(data: List<List<String>>): List<List<String>> {
if (data.isEmpty()) {
return listOf(emptyList())
}
val first = data.first()
val rest = data.subList(1, data.size)
val combinations = mutableListOf<List<String>>()
for (sublist in getCombinations0(rest)) {
for (item in first) {
combinations.add(listOf(item) + sublist)
}
}
return combinations
}
private fun getCombinations(data: List<List<String>>): List<String> {
val r = mutableListOf<String>()
val l = getCombinations0(data)
l.forEach {
r.add(it.sorted().joinToString("+"))
}
return r
}
/**
* @return Null if:
* - at least one of the vararg contains null
* - a smelting product of given items does not exist
* - Otherwise, a smelting product of the given items are returned
*/
fun getSmeltingProductOf(vararg item: ItemID?): SmeltingRecipe? {
if (item.contains(null)) return null
val keysPossible0: List<List<String>> =
(item.map { listOf(it!!) + (ItemCodex[it]?.tags?.toList()?.map { "\$" + it } ?: emptyList()) })
val keysPossible = getCombinations(keysPossible0)
// iterate through all the combinations of keys
var found: SmeltingRecipe? = null
var i = 0
while (found == null && i < keysPossible.size) {
found = smeltingProps[keysPossible[i]]
i += 1
}
return found
}
/** /**
* Returns list of items that uses the given `item`. * Returns list of items that uses the given `item`.
* *
@@ -118,6 +188,7 @@ class CraftingCodex {
} }
} }
/** /**
* @return list of itemIDs and corresponding recipes * @return list of itemIDs and corresponding recipes
*/ */
@@ -128,6 +199,7 @@ class CraftingCodex {
data class SmeltingRecipe(val difficulty: Float, val ingredients: Array<ItemID>, val moq: Long, val item: ItemID, val addedBy: String)
data class CraftingRecipe(val workbench: String, val ingredients: Array<CraftingIngredients>, val moq: Long, val product: ItemID, val addedBy: String) data class CraftingRecipe(val workbench: String, val ingredients: Array<CraftingIngredients>, val moq: Long, val product: ItemID, val addedBy: String)
data class CraftingIngredients(val key: String, val keyMode: CraftingItemKeyMode, val qty: Long) { data class CraftingIngredients(val key: String, val keyMode: CraftingItemKeyMode, val qty: Long) {
override fun toString() = "$qty ${if (keyMode == CraftingItemKeyMode.TAG) "\$$key" else "$key"}" override fun toString() = "$qty ${if (keyMode == CraftingItemKeyMode.TAG) "\$$key" else "$key"}"

View File

@@ -7,7 +7,6 @@ object Item {
const val TREE_STICK = "item@basegame:18" const val TREE_STICK = "item@basegame:18"
const val TREE_SEED_OAK = "item@basegame:160" const val COPPER_SIGN = "item@basegame:33280"
const val TREE_LOGS_OAK = "item@basegame:168"
} }

View File

@@ -84,6 +84,8 @@ class ItemCodex {
get() = CommonResourcePool.getAsTextureRegion("itemplaceholder_24") // copper pickaxe get() = CommonResourcePool.getAsTextureRegion("itemplaceholder_24") // copper pickaxe
/** /**
* Unused IDs are purged when the game saves, as only the active entries are written to the savegame.
*
* @param: dynamicID string of "dyn:<random id>" * @param: dynamicID string of "dyn:<random id>"
*/ */
fun registerNewDynamicItem(dynamicID: ItemID, item: GameItem) { fun registerNewDynamicItem(dynamicID: ItemID, item: GameItem) {

View File

@@ -2,9 +2,13 @@ package net.torvald.terrarum.langpack
import net.torvald.terrarum.App import net.torvald.terrarum.App
import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.tail
import net.torvald.terrarum.utils.JsonFetcher import net.torvald.terrarum.utils.JsonFetcher
import net.torvald.unicode.getKeycapPC
import net.torvald.unicode.getMouseButton
import java.io.File import java.io.File
import java.util.* import java.util.*
import kotlin.collections.HashMap
class LangObject(val key: String, val fromLang: Boolean) { class LangObject(val key: String, val fromLang: Boolean) {
fun get() = if (fromLang) Lang[key] else key fun get() = if (fromLang) Lang[key] else key
@@ -137,25 +141,38 @@ object Lang {
operator fun get(key: String, capitalise: Boolean = false): String { operator fun get(key: String, capitalise: Boolean = false): String {
fun getstr(s: String) = getByLocale(s, App.GAME_LOCALE, capitalise) ?: getByLocale(s, FALLBACK_LANG_CODE, capitalise) ?: "$$s" fun getstr(s: String) = getByLocale(s, App.GAME_LOCALE, capitalise) ?: getByLocale(s, FALLBACK_LANG_CODE, capitalise) ?: "$$s"
decodeCache[App.GAME_LOCALE]?.get("$key+$capitalise").let {
if (it != null) {
return it
}
else {
val args = key.split(bindOp).filter { it.isNotBlank() }.map { it.trim() }
if (args.isEmpty()) return ""
val args = key.split(bindOp).filter { it.isNotBlank() }.map { it.trim() } val sb = StringBuilder()
if (args.isEmpty()) return "" val formatter = Formatter(sb)
val sb = StringBuilder() sb.append(getstr(args[0]))
val formatter = Formatter(sb) args.subList(1, args.size).forEach {
val oldstr = sb.toString()
sb.clear()
formatter.format(getstr(it), oldstr)
}
sb.append(getstr(args[0])) if (decodeCache[App.GAME_LOCALE] == null) {
args.subList(1, args.size).forEach { decodeCache[App.GAME_LOCALE] = HashMap()
val oldstr = sb.toString() }
sb.clear() decodeCache[App.GAME_LOCALE]!!["$key+$capitalise"] = sb.toString()
formatter.format(getstr(it), oldstr)
return sb.toString()
}
} }
return sb.toString()
} }
fun getAndUseTemplate(key: String, capitalise: Boolean = false, vararg arguments: Any?): String { fun getAndUseTemplate(key: String, capitalise: Boolean = false, vararg arguments: Any?): String? {
var raw = get(key, capitalise) var raw = getOrNull(key, capitalise) ?: return null
arguments.forEachIndexed { index, it0 -> arguments.forEachIndexed { index, it0 ->
val it = if (capitalise) it0.toString().capitalize() else it0.toString() val it = if (capitalise) it0.toString().capitalize() else it0.toString()
raw = raw.replace("{${index}}", it) raw = raw.replace("{${index}}", it)
@@ -174,6 +191,7 @@ object Lang {
} }
private val capCache = HashMap<String/*Locale*/, HashMap<String/*Key*/, String/*Text*/>>() private val capCache = HashMap<String/*Locale*/, HashMap<String/*Key*/, String/*Text*/>>()
private val decodeCache = HashMap<String/*Locale*/, HashMap<String/*Key*/, String/*Text*/>>()
private fun CAP(key: String, locale: String): String? { private fun CAP(key: String, locale: String): String? {
val ret = langpack["${key}_$locale"] ?: return null val ret = langpack["${key}_$locale"] ?: return null
@@ -191,18 +209,49 @@ object Lang {
private fun NOCAP(key: String, locale: String): String? { private fun NOCAP(key: String, locale: String): String? {
return langpack["${key}_$locale"] ?: return null return langpack["${key}_$locale"] ?: return null
} }
private val tagRegex = Regex("""\{[A-Z]+:[0-9A-Za-z_\- ]+\}""")
/** /**
* Does NOT parse the operators * Does NOT parse the bind operators, but DO parse the precomposed tags
*/ */
fun getByLocale(key: String, locale: String, capitalise: Boolean = false): String? { fun getByLocale(key: String, locale: String, capitalise: Boolean = false): String? {
val s = if (capitalise) CAP(key, locale) else NOCAP(key, locale) val s = if (capitalise) CAP(key, locale) else NOCAP(key, locale)
return if (locale.startsWith("bg")) if (s == null) return null
val fetchedS = if (locale.startsWith("bg"))
"${App.fontGame.charsetOverrideBulgarian}$s${App.fontGame.charsetOverrideDefault}" "${App.fontGame.charsetOverrideBulgarian}$s${App.fontGame.charsetOverrideDefault}"
else if (locale.startsWith("sr")) else if (locale.startsWith("sr"))
"${App.fontGame.charsetOverrideSerbian}$s${App.fontGame.charsetOverrideDefault}" "${App.fontGame.charsetOverrideSerbian}$s${App.fontGame.charsetOverrideDefault}"
else else
s s
// apply {DOMAIN:argument} form of template
var ret = "$fetchedS" // make copy of the str
tagRegex.findAll(fetchedS).forEach {
val matched0 = it.groupValues[0]
val matched = matched0.substring(1 until matched0.lastIndex) // strip off the brackets
val mode = matched.substringBefore(':')
val key = matched.substringAfter(':')
val resolved = when (mode) {
"MOUSE" -> { // cognates to gdx.Input.Button
getMouseButton(App.getConfigInt(key)).toString()
}
"KEYCAP" -> { // cognates to gdx.Input.Keys
getKeycapPC(App.getConfigInt(key)).toString()
}
"CONFIG" -> {
App.getConfigMaster(key).toString()
}
else -> matched0
}
ret = ret.replace(matched0, resolved)
}
return ret
} }
private fun String.getEndTag() = this.split("_").last() private fun String.getEndTag() = this.split("_").last()

View File

@@ -432,7 +432,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
wireActor.renderOrder = Actor.RenderOrder.OVERLAY wireActor.renderOrder = Actor.RenderOrder.OVERLAY
} }
else { else {
wireActor.renderOrder = Actor.RenderOrder.BEHIND wireActor.renderOrder = Actor.RenderOrder.FAR_BEHIND
} }
wireActor.isUpdate = true wireActor.isUpdate = true
@@ -458,14 +458,15 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
_testMarkerDrawCalls = 0L _testMarkerDrawCalls = 0L
IngameRenderer.invoke(delta, false, IngameRenderer.invoke(delta, false,
screenZoom, screenZoom,
listOf(), listOf(),
listOf(), listOf(),
listOf(), listOf(),
listOf(), listOf(),
if (showSelection) actorsRenderOverlay + essentialOverlays else essentialOverlays, listOf(),
particles, if (showSelection) actorsRenderOverlay + essentialOverlays else essentialOverlays,
uiContainer = uiContainer particles,
uiContainer = uiContainer
) )
App.setDebugTime("Test.MarkerDrawCalls", _testMarkerDrawCalls) App.setDebugTime("Test.MarkerDrawCalls", _testMarkerDrawCalls)

View File

@@ -48,12 +48,6 @@ class EntryPoint : ModuleEntryPoint() {
} }
} }
// add smelting recipe for sands
BlockCodex.filter { it.hasTag("SAND") }.forEach { (itemID, _) ->
ItemCodex[itemID]!!.tags.add("SMELTABLE")
ItemCodex[itemID]!!.smeltingProduct = "basegame:148"
}
println("\n[Basegame.EntryPoint] Welcome back!") println("\n[Basegame.EntryPoint] Welcome back!")
} }

View File

@@ -9,6 +9,7 @@ import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.badlogic.gdx.graphics.glutils.ShaderProgram
import com.badlogic.gdx.utils.Disposable import com.badlogic.gdx.utils.Disposable
import com.jme3.math.FastMath
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.App.* import net.torvald.terrarum.App.*
@@ -230,6 +231,7 @@ object IngameRenderer : Disposable {
frameDelta: Float, frameDelta: Float,
gamePaused: Boolean, gamePaused: Boolean,
zoom: Float = 1f, zoom: Float = 1f,
actorsRenderFarBehind : List<ActorWithBody>,
actorsRenderBehind : List<ActorWithBody>, actorsRenderBehind : List<ActorWithBody>,
actorsRenderMiddle : List<ActorWithBody>, actorsRenderMiddle : List<ActorWithBody>,
actorsRenderMidTop : List<ActorWithBody>, actorsRenderMidTop : List<ActorWithBody>,
@@ -239,11 +241,13 @@ object IngameRenderer : Disposable {
player: ActorWithBody? = null, player: ActorWithBody? = null,
uiContainer: UIContainer? = null, uiContainer: UIContainer? = null,
) { ) {
renderingActorsCount = (actorsRenderBehind.size) + renderingActorsCount =
(actorsRenderMiddle.size) + (actorsRenderFarBehind.size) +
(actorsRenderMidTop.size) + (actorsRenderBehind.size) +
(actorsRenderFront.size) + (actorsRenderMiddle.size) +
(actorsRenderOverlay.size) (actorsRenderMidTop.size) +
(actorsRenderFront.size) +
(actorsRenderOverlay.size)
renderingUIsCount = uiContainer?.countVisible() ?: 0 renderingUIsCount = uiContainer?.countVisible() ?: 0
invokeInit() invokeInit()
@@ -258,15 +262,15 @@ object IngameRenderer : Disposable {
measureDebugTime("Renderer.LightRun*") { measureDebugTime("Renderer.LightRun*") {
// recalculate for even frames, or if the sign of the cam-x changed // recalculate for even frames, or if the sign of the cam-x changed
if (App.GLOBAL_RENDER_TIMER % 3 == 0 || Math.abs(WorldCamera.x - oldCamX) >= world.width * 0.85f * TILE_SIZEF || newWorldLoadedLatch) { if (App.GLOBAL_RENDER_TIMER % 3 == 0 || Math.abs(WorldCamera.x - oldCamX) >= world.width * 0.85f * TILE_SIZEF || newWorldLoadedLatch) {
LightmapRenderer.recalculate(actorsRenderBehind + actorsRenderFront + actorsRenderMidTop + actorsRenderMiddle + actorsRenderOverlay) LightmapRenderer.recalculate(actorsRenderFarBehind + actorsRenderBehind + actorsRenderFront + actorsRenderMidTop + actorsRenderMiddle + actorsRenderOverlay)
} }
oldCamX = WorldCamera.x oldCamX = WorldCamera.x
} }
prepLightmapRGBA() prepLightmapRGBA()
BlocksDrawer.renderData() BlocksDrawer.renderData()
drawToRGB(frameDelta, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer) drawToRGB(frameDelta, actorsRenderFarBehind, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer)
drawToA(frameDelta, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer) drawToA(frameDelta, actorsRenderFarBehind, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer)
drawOverlayActors(frameDelta, actorsRenderOverlay) drawOverlayActors(frameDelta, actorsRenderOverlay)
if (player != null && player is Pocketed) drawAimGuide(frameDelta, player) if (player != null && player is Pocketed) drawAimGuide(frameDelta, player)
@@ -463,6 +467,7 @@ object IngameRenderer : Disposable {
private fun drawToRGB( private fun drawToRGB(
frameDelta: Float, frameDelta: Float,
actorsRenderFarBehind: List<ActorWithBody>?,
actorsRenderBehind: List<ActorWithBody>?, actorsRenderBehind: List<ActorWithBody>?,
actorsRenderMiddle: List<ActorWithBody>?, actorsRenderMiddle: List<ActorWithBody>?,
actorsRenderMidTop: List<ActorWithBody>?, actorsRenderMidTop: List<ActorWithBody>?,
@@ -484,6 +489,7 @@ object IngameRenderer : Disposable {
batch.shader = shaderForActors batch.shader = shaderForActors
batch.color = Color.WHITE batch.color = Color.WHITE
moveCameraToWorldCoord() moveCameraToWorldCoord()
actorsRenderFarBehind?.forEach { it.drawBody(frameDelta, batch) }
actorsRenderBehind?.forEach { it.drawBody(frameDelta, batch) } actorsRenderBehind?.forEach { it.drawBody(frameDelta, batch) }
particlesContainer?.forEach { it.drawBody(frameDelta, batch) } particlesContainer?.forEach { it.drawBody(frameDelta, batch) }
} }
@@ -522,6 +528,7 @@ object IngameRenderer : Disposable {
batch.shader = shaderForActors batch.shader = shaderForActors
batch.color = Color.WHITE batch.color = Color.WHITE
moveCameraToWorldCoord() moveCameraToWorldCoord()
actorsRenderFarBehind?.forEach { it.drawEmissive(frameDelta, batch) }
actorsRenderBehind?.forEach { it.drawEmissive(frameDelta, batch) } actorsRenderBehind?.forEach { it.drawEmissive(frameDelta, batch) }
particlesContainer?.forEach { it.drawEmissive(frameDelta, batch) } particlesContainer?.forEach { it.drawEmissive(frameDelta, batch) }
} }
@@ -582,7 +589,7 @@ object IngameRenderer : Disposable {
batch.shader.setUniformi("u_pattern", 1) batch.shader.setUniformi("u_pattern", 1)
batch.draw( batch.draw(
lightTex, lightTex,
xrem, yrem, xrem, yrem - TILE_SIZEF * 0.5f,
lightTex.regionWidth * lightmapDownsample, lightTex.regionWidth * lightmapDownsample,
lightTex.regionHeight * lightmapDownsample lightTex.regionHeight * lightmapDownsample
) )
@@ -627,6 +634,7 @@ object IngameRenderer : Disposable {
private fun drawToA( private fun drawToA(
frameDelta: Float, frameDelta: Float,
actorsRenderFarBehind: List<ActorWithBody>?,
actorsRenderBehind: List<ActorWithBody>?, actorsRenderBehind: List<ActorWithBody>?,
actorsRenderMiddle: List<ActorWithBody>?, actorsRenderMiddle: List<ActorWithBody>?,
actorsRenderMidTop: List<ActorWithBody>?, actorsRenderMidTop: List<ActorWithBody>?,
@@ -651,6 +659,7 @@ object IngameRenderer : Disposable {
batch.color = Color.WHITE batch.color = Color.WHITE
moveCameraToWorldCoord() moveCameraToWorldCoord()
actorsRenderFarBehind?.forEach { it.drawGlow(frameDelta, batch) }
actorsRenderBehind?.forEach { it.drawGlow(frameDelta, batch) } actorsRenderBehind?.forEach { it.drawGlow(frameDelta, batch) }
particlesContainer?.forEach { it.drawGlow(frameDelta, batch) } particlesContainer?.forEach { it.drawGlow(frameDelta, batch) }
} }
@@ -700,7 +709,7 @@ object IngameRenderer : Disposable {
batch.shader.setUniformi("rnd", rng.nextInt(8192), rng.nextInt(8192)) batch.shader.setUniformi("rnd", rng.nextInt(8192), rng.nextInt(8192))
batch.shader.setUniformi("u_pattern", 1) batch.shader.setUniformi("u_pattern", 1)
batch.draw(lightTex, batch.draw(lightTex,
xrem, yrem, xrem, yrem - TILE_SIZEF * 0.5f,
lightTex.regionWidth * lightmapDownsample, lightTex.regionWidth * lightmapDownsample,
lightTex.regionHeight * lightmapDownsample lightTex.regionHeight * lightmapDownsample
) )
@@ -765,25 +774,24 @@ object IngameRenderer : Disposable {
private val cubeSize = 7.0 private val cubeSize = 7.0
private val externalV = Vector2() private val externalV = Vector2()
private val maxStep = 56 private val maxStep = 56
private val trajectoryFlow = 30
private fun drawTrajectoryForThrowable(frameBuffer: FrameBuffer, batch: SpriteBatch, frameDelta: Float, player: ActorWithBody, world: GameWorld, item: ItemThrowable) { private fun drawTrajectoryForThrowable(frameBuffer: FrameBuffer, batch: SpriteBatch, frameDelta: Float, player: ActorWithBody, world: GameWorld, item: ItemThrowable) {
val ww = world.width * TILE_SIZEF val ww = world.width * TILE_SIZEF
mouseInInteractableRange(player) { mx, my, mtx, mty -> mouseInInteractableRange(player) { mx, my, mtx, mty ->
val (throwPos, throwVector) = getThrowPosAndVector(player) val (throwPos, throwVector) = getThrowPosAndVector(player)
val grav = world.gravitation val grav = world.gravitation
val toff = (App.GLOBAL_RENDER_TIMER % trajectoryFlow) / trajectoryFlow.toFloat()
externalV.set(throwVector) externalV.set(throwVector)
val points = ArrayList<Pair<Float, Float>>()
var c = 0 var c = 0
while (c < maxStep) { while (c < maxStep) {
batch.color = Color(0.9f, 0.9f, 0.9f, 0.9f * (1f - (c.toFloat() / maxStep).sqr()))
// plot a dot // plot a dot
if (c > 0) { points.add(throwPos.x.toFloat() to throwPos.y.toFloat())
Toolkit.fillArea(batch, throwPos.x.toFloat(), throwPos.y.toFloat(), 2f, 2f)
Toolkit.fillArea(batch, throwPos.x.toFloat() + ww, throwPos.y.toFloat(), 2f, 2f)
Toolkit.fillArea(batch, throwPos.x.toFloat() - ww, throwPos.y.toFloat(), 2f, 2f)
}
// simulate physics // simulate physics
applyGravitation(grav, cubeSize) // TODO use actual value instead of `cubeSize` applyGravitation(grav, cubeSize) // TODO use actual value instead of `cubeSize`
@@ -807,16 +815,40 @@ object IngameRenderer : Disposable {
BlockCodex[tile].isSolid BlockCodex[tile].isSolid
} }
if (hitSolid) if (hitSolid) {
points.add(throwPos.x.toFloat() to throwPos.y.toFloat())
break break
}
c++ c++
} }
if (points.size > 4) {
var v0 = points[0]
var v1 = points[0]
var v2 = points[1]
var v3 = points[2]
for (i in 3 until points.size) {
// shift vars
v0 = v1; v1 = v2; v2 = v3; v3 = points[i]
val xp = FastMath.interpolateCatmullRom(toff, v0.first, v1.first, v2.first, v3.first)
val yp = FastMath.interpolateCatmullRom(toff, v0.second, v1.second, v2.second, v3.second)
batch.color = Color(0.9f, 0.9f, 0.9f, 0.9f * (1f - ((i-3+toff) / maxStep).sqr()))
Toolkit.fillArea(batch, xp, yp, 2f, 2f)
Toolkit.fillArea(batch, xp + ww, yp, 2f, 2f)
Toolkit.fillArea(batch, xp - ww, yp, 2f, 2f)
}
}
1L 1L
} }
} }
private val bodyFriction = BlockCodex[Block.AIR].friction.frictionToMult() private val bodyFriction = BlockCodex[Block.AIR].friction.frictionToMult()

View File

@@ -23,11 +23,11 @@ import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gamecontroller.IngameController import net.torvald.terrarum.gamecontroller.IngameController
import net.torvald.terrarum.gamecontroller.KeyToggler import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.gameitems.FixtureInteractionBlocked
import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.mouseInInteractableRange import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameparticles.ParticleBase import net.torvald.terrarum.gameparticles.ParticleBase
import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.WorldSimulator
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameactors.* import net.torvald.terrarum.modulebasegame.gameactors.*
@@ -57,7 +57,6 @@ import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.weather.WeatherMixer import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.worlddrawer.BlocksDrawer import net.torvald.terrarum.worlddrawer.BlocksDrawer
import net.torvald.terrarum.worlddrawer.FeaturesDrawer import net.torvald.terrarum.worlddrawer.FeaturesDrawer
import net.torvald.terrarum.worlddrawer.LightmapRenderer.LIGHTMAP_OVERRENDER
import net.torvald.terrarum.worlddrawer.WorldCamera import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.unicode.EMDASH import net.torvald.unicode.EMDASH
import net.torvald.util.CircularArray import net.torvald.util.CircularArray
@@ -91,6 +90,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
val particlesContainer = CircularArray<ParticleBase>(PARTICLES_MAX, true) val particlesContainer = CircularArray<ParticleBase>(PARTICLES_MAX, true)
// these are required because actors always change their position // these are required because actors always change their position
private var visibleActorsRenderFarBehind: ArrayList<ActorWithBody> = ArrayList(1)
private var visibleActorsRenderBehind: ArrayList<ActorWithBody> = ArrayList(1) private var visibleActorsRenderBehind: ArrayList<ActorWithBody> = ArrayList(1)
private var visibleActorsRenderMiddle: ArrayList<ActorWithBody> = ArrayList(1) private var visibleActorsRenderMiddle: ArrayList<ActorWithBody> = ArrayList(1)
private var visibleActorsRenderMidTop: ArrayList<ActorWithBody> = ArrayList(1) private var visibleActorsRenderMidTop: ArrayList<ActorWithBody> = ArrayList(1)
@@ -516,7 +516,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
printdbg(this, "loaded successfully.") printdbg(this, "loaded successfully.")
} }
else { else {
App.getLoadScreen().addMessage("${App.GAME_NAME} version ${App.getVERSION_STRING()}") App.getLoadScreen().addMessage("${App.GAME_NAME} ${App.getVERSION_STRING()}")
App.getLoadScreen().addMessage("Creating new world") App.getLoadScreen().addMessage("Creating new world")
@@ -691,6 +691,15 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
private var worldPrimaryClickLatch = false
private var worldSecondaryClickLatch = false
private fun fireFixtureInteractEvent(fixture: FixtureBase, mwx: Double, mwy: Double) {
if (fixture.mouseUp) {
fixture.onInteract(mwx, mwy)
}
}
// left click: use held item, attack, pick up fixture if i'm holding a pickaxe or hammer (aka tool), do 'bare hand action' if holding nothing // left click: use held item, attack, pick up fixture if i'm holding a pickaxe or hammer (aka tool), do 'bare hand action' if holding nothing
override fun worldPrimaryClickStart(actor: ActorWithBody, delta: Float) { override fun worldPrimaryClickStart(actor: ActorWithBody, delta: Float) {
//println("[Ingame] worldPrimaryClickStart $delta") //println("[Ingame] worldPrimaryClickStart $delta")
@@ -699,22 +708,59 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
val itemOnGrip = ItemCodex[(actor as Pocketed).inventory.itemEquipped.get(GameItem.EquipPosition.HAND_GRIP)] val itemOnGrip = ItemCodex[(actor as Pocketed).inventory.itemEquipped.get(GameItem.EquipPosition.HAND_GRIP)]
// bring up the UIs of the fixtures (e.g. crafting menu from a crafting table) // bring up the UIs of the fixtures (e.g. crafting menu from a crafting table)
var uiOpened = false
val fixtureUnderMouse0: List<FixtureBase> = getActorsUnderMouse(Terrarum.mouseX, Terrarum.mouseY).filterIsInstance<FixtureBase>()
if (fixtureUnderMouse0.size > 1) {
App.printdbgerr(this, "Multiple fixtures at tile coord ${Terrarum.mouseX / TILE_SIZED}, ${Terrarum.mouseY / TILE_SIZED}: [${fixtureUnderMouse0.map { it.javaClass.simpleName }.joinToString()}]")
}
val fixtureUnderMouse = fixtureUnderMouse0.firstOrNull()
//////////////////////////////// ////////////////////////////////
// #1. If ~~there is no UI under and~~ I'm holding an item, use it mouseInInteractableRange(actor) { mwx, mwy, mtx, mty ->
// don't want to open the UI and use the item at the same time, would ya? // #1. interact with the fixture if NOT FixtureInteractionBlocked
if (itemOnGrip != null) { // scan for the one with non-null UI.
val consumptionSuccessful = itemOnGrip.startPrimaryUse(actor, delta) // what if there's multiple of such fixtures? whatever, you are supposed to DISALLOW such situation.
if (consumptionSuccessful > -1) if (fixtureUnderMouse != null && itemOnGrip !is FixtureInteractionBlocked) {
(actor as Pocketed).inventory.consumeItem(itemOnGrip, consumptionSuccessful) if (!worldPrimaryClickLatch) {
} worldPrimaryClickLatch = true
// #2. If I'm not holding any item and I can do barehandaction (size big enough that barehandactionminheight check passes), perform it fixtureUnderMouse.let { fixture ->
else if (itemOnGrip == null) { fixture.mainUI?.let { ui ->
mouseInInteractableRange(actor) { mwx, mwy, mtx, mty -> uiOpened = true
performBarehandAction(actor, delta, mwx, mwy, mtx, mty)
0L // property 'uiFixture' is a dedicated property that the TerrarumIngame recognises.
// when it's not null, the UI will be updated and rendered
// when the UI is closed, it'll be replaced with a null value
uiFixture = ui
ui.setPosition(
(Toolkit.drawWidth - ui.width) / 4,
(App.scr.height - ui.height) / 4 // what the fuck?
)
ui.setAsOpen()
}
if (!uiOpened) {
fireFixtureInteractEvent(fixture, mwx, mwy)
}
}
}
} }
// #2. If no fixture under mouse or FixtureInteractionBlocked, use the item
else if (itemOnGrip != null) {
// click filtering (latch stuff) is handled by IngameController (see inventoryCategoryAllowClickAndDrag)
// To disable click dragging for tool/block/etc., put `override val disallowToolDragging = true` to the item's code
val consumptionSuccessful = itemOnGrip.startPrimaryUse(actor, delta)
if (consumptionSuccessful > -1)
(actor as Pocketed).inventory.consumeItem(itemOnGrip, consumptionSuccessful)
worldPrimaryClickLatch = true
}
// #3. If not holding any item and can do barehandaction (size big enough that barehandactionminheight check passes), do it
else {
performBarehandAction(actor, delta, mwx, mwy, mtx, mty)
}
0L
} }
} }
@@ -728,51 +774,35 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
if (canPerformBarehandAction) { if (canPerformBarehandAction) {
endPerformBarehandAction(actor) endPerformBarehandAction(actor)
} }
worldPrimaryClickLatch = false
} }
// right click: use fixture
override fun worldSecondaryClickStart(actor: ActorWithBody, delta: Float) { override fun worldSecondaryClickStart(actor: ActorWithBody, delta: Float) {
val itemOnGrip = ItemCodex[(actor as Pocketed).inventory.itemEquipped.get(GameItem.EquipPosition.HAND_GRIP)] val itemOnGrip = ItemCodex[(actor as Pocketed).inventory.itemEquipped.get(GameItem.EquipPosition.HAND_GRIP)]
var uiOpened = false
val actorsUnderMouse: List<FixtureBase> = getActorsAt(Terrarum.mouseX, Terrarum.mouseY).filterIsInstance<FixtureBase>()
if (actorsUnderMouse.size > 1) {
App.printdbgerr(this, "Multiple fixtures at world coord ${Terrarum.mouseX}, ${Terrarum.mouseY}")
}
// #1. Try to open a UI under the cursor if (!worldSecondaryClickLatch) {
// scan for the one with non-null UI. // #1. Perform item's secondaryUse
// what if there's multiple of such fixtures? whatever, you are supposed to DISALLOW such situation. val consumptionSuccessful = itemOnGrip?.startSecondaryUse(actor, delta) ?: -1
for (kk in actorsUnderMouse.indices) { if (consumptionSuccessful > -1)
if (mouseInInteractableRange(actor) { _, _, _, _ -> (actor as Pocketed).inventory.consumeItem(itemOnGrip!!, consumptionSuccessful)
actorsUnderMouse[kk].let { fixture -> // #2. If #1 failed, try to pick up the fixture
fixture.mainUI?.let { ui -> else {
uiOpened = true mouseInInteractableRange(actor) { mwx, mwy, mtx, mty ->
pickupFixture(actor, delta, mwx, mwy, mtx, mty)
// property 'uiFixture' is a dedicated property that the TerrarumIngame recognises. 0L
// when it's not null, the UI will be updated and rendered
// when the UI is closed, it'll be replaced with a null value
uiFixture = ui
ui.setPosition(
(Toolkit.drawWidth - ui.width) / 4,
(App.scr.height - ui.height) / 4 // what the fuck?
)
// if (fixture.mainUIopenFun == null)
ui.setAsOpen()
// else
// fixture.mainUIopenFun!!.invoke(ui)
}
} }
0L }
} == 0L) break
}
if (!uiOpened) { worldSecondaryClickLatch = true
//...
} }
} }
override fun worldSecondaryClickEnd(actor: ActorWithBody, delta: Float) { override fun worldSecondaryClickEnd(actor: ActorWithBody, delta: Float) {
// println("Secondary click start!") val itemOnGrip = (actor as Pocketed).inventory.itemEquipped.get(GameItem.EquipPosition.HAND_GRIP)
ItemCodex[itemOnGrip]?.endSecondaryUse(actor, delta)
worldSecondaryClickLatch = false
} }
@@ -922,6 +952,12 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
fillUpWiresBuffer() fillUpWiresBuffer()
} }
} }
measureDebugTime("Ingame.FillUpWirePortsView*") {
if (WORLD_UPDATE_TIMER % 2 == 0) {
val fixtures = INGAME.actorContainerActive.filterIsInstance<Electric>()
fillUpWirePortsView(fixtures)
}
}
oldCamX = WorldCamera.x oldCamX = WorldCamera.x
oldPlayerX = actorNowPlaying?.hitbox?.canonicalX ?: 0.0 oldPlayerX = actorNowPlaying?.hitbox?.canonicalX ?: 0.0
@@ -1059,6 +1095,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
frameDelta, frameDelta,
paused, paused,
screenZoom, screenZoom,
visibleActorsRenderFarBehind,
visibleActorsRenderBehind, visibleActorsRenderBehind,
visibleActorsRenderMiddle, visibleActorsRenderMiddle,
visibleActorsRenderMidTop, visibleActorsRenderMidTop,
@@ -1193,17 +1230,22 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
} }
private val maxRenderableWires = ReferencingRanges.ACTORS_WIRES.last - ReferencingRanges.ACTORS_WIRES.first + 1 private val maxRenderableWires = ReferencingRanges.ACTORS_WIRES.last - ReferencingRanges.ACTORS_WIRES.first + 1
private val maxRenderablePorts = ReferencingRanges.ACTORS_WIRE_PORTS.last - ReferencingRanges.ACTORS_WIRE_PORTS.first + 1
private val wireActorsContainer = Array(maxRenderableWires) { WireActor(ReferencingRanges.ACTORS_WIRES.first + it).let { private val wireActorsContainer = Array(maxRenderableWires) { WireActor(ReferencingRanges.ACTORS_WIRES.first + it).let {
forceAddActor(it) forceAddActor(it)
/*^let*/ it /*^let*/ it
} } } }
private val wirePortActorsContainer = Array(maxRenderablePorts) { WirePortActor(ReferencingRanges.ACTORS_WIRE_PORTS.first + it).let {
forceAddActor(it)
/*^let*/ it
} }
private fun fillUpWiresBuffer() { private fun fillUpWiresBuffer() {
val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorToInt() - LIGHTMAP_OVERRENDER val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorToInt() - 1
val for_y_end = for_y_start + BlocksDrawer.tilesInVertical + 2*LIGHTMAP_OVERRENDER val for_y_end = for_y_start + BlocksDrawer.tilesInVertical + 2*1
val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorToInt() - LIGHTMAP_OVERRENDER val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorToInt() - 1
val for_x_end = for_x_start + BlocksDrawer.tilesInHorizontal + 2*LIGHTMAP_OVERRENDER val for_x_end = for_x_start + BlocksDrawer.tilesInHorizontal + 2*1
var wiringCounter = 0 var wiringCounter = 0
for (y in for_y_start..for_y_end) { for (y in for_y_start..for_y_end) {
@@ -1221,7 +1263,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
wireActor.renderOrder = Actor.RenderOrder.OVERLAY wireActor.renderOrder = Actor.RenderOrder.OVERLAY
} }
else { else {
wireActor.renderOrder = Actor.RenderOrder.BEHIND wireActor.renderOrder = Actor.RenderOrder.FAR_BEHIND
} }
wireActor.isUpdate = true wireActor.isUpdate = true
@@ -1235,13 +1277,44 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
} }
for (i in wiringCounter until maxRenderableWires) { for (i in wiringCounter until maxRenderableWires) {
wireActorsContainer[i].isUpdate = false val wireActor = wireActorsContainer[i]
wireActorsContainer[i].isVisible = false wireActor.isUpdate = false
wireActorsContainer[i].forceDormant = true wireActor.isVisible = false
wireActor.forceDormant = true
}
}
private fun fillUpWirePortsView(fixtures: List<Electric>) {
var portsCounter = 0
fixtures.forEach {
(it.wireSinkTypes.toList() + it.wireEmitterTypes.toList()).forEach { (boxIndex, type) ->
if (portsCounter < wirePortActorsContainer.size) {
val wireActor = wirePortActorsContainer[portsCounter]
val (wx, wy) = it.worldBlockPos!! + it.blockBoxIndexToPoint2i(boxIndex)
wireActor.setPort(type, wx, wy)
wireActor.isUpdate = true
wireActor.isVisible = true
wireActor.forceDormant = false
portsCounter += 1
}
}
}
for (i in portsCounter until maxRenderablePorts) {
val wireActor = wirePortActorsContainer[i]
wireActor.isUpdate = false
wireActor.isVisible = false
wireActor.forceDormant = true
} }
} }
private fun filterVisibleActors() { private fun filterVisibleActors() {
visibleActorsRenderFarBehind.clear()
visibleActorsRenderBehind.clear() visibleActorsRenderBehind.clear()
visibleActorsRenderMiddle.clear() visibleActorsRenderMiddle.clear()
visibleActorsRenderMidTop.clear() visibleActorsRenderMidTop.clear()
@@ -1441,6 +1514,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
private fun actorToRenderQueue(actor: ActorWithBody): ArrayList<ActorWithBody> { private fun actorToRenderQueue(actor: ActorWithBody): ArrayList<ActorWithBody> {
return when (actor.renderOrder) { return when (actor.renderOrder) {
Actor.RenderOrder.FAR_BEHIND -> visibleActorsRenderFarBehind
Actor.RenderOrder.BEHIND -> visibleActorsRenderBehind Actor.RenderOrder.BEHIND -> visibleActorsRenderBehind
Actor.RenderOrder.MIDDLE -> visibleActorsRenderMiddle Actor.RenderOrder.MIDDLE -> visibleActorsRenderMiddle
Actor.RenderOrder.MIDTOP -> visibleActorsRenderMidTop Actor.RenderOrder.MIDTOP -> visibleActorsRenderMidTop
@@ -1546,8 +1620,20 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
} }
} }
fun performBarehandAction(actor: ActorWithBody, delta: Float, mwx: Double, mwy: Double, mtx: Int, mty: Int) { private fun getActorsAtVicinity(worldX: Double, worldY: Double, radius: Double): List<ActorWithBody> {
val outList = java.util.ArrayList<ActorWithBody>()
try {
actorsRTree.find(worldX - radius, worldY - radius, worldX + radius, worldY + radius, outList)
}
catch (e: NullPointerException) {
}
return outList
}
private fun getPunchSize(actor: ActorWithBody) = actor.scale * actor.actorValue.getAsDouble(AVKey.BAREHAND_BASE_DIGSIZE)!!
fun performBarehandAction(actor: ActorWithBody, delta: Float, mwx: Double, mwy: Double, mtx: Int, mty: Int) {
// for giant actors punching every structure pickaxe can dig out // for giant actors punching every structure pickaxe can dig out
val canAttackOrDig = val canAttackOrDig =
actor.scale * actor.baseHitboxH >= (actor.actorValue.getAsDouble(AVKey.BAREHAND_MINHEIGHT) ?: 4294967296.0) actor.scale * actor.baseHitboxH >= (actor.actorValue.getAsDouble(AVKey.BAREHAND_MINHEIGHT) ?: 4294967296.0)
@@ -1556,62 +1642,15 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
val canDigSoftTileOnly = val canDigSoftTileOnly =
actor is ActorHumanoid && (actor.baseHitboxH * actor.scale) >= 32f actor is ActorHumanoid && (actor.baseHitboxH * actor.scale) >= 32f
fun getActorsAtVicinity(worldX: Double, worldY: Double, radius: Double): List<ActorWithBody> {
val outList = java.util.ArrayList<ActorWithBody>()
try {
actorsRTree.find(worldX - radius, worldY - radius, worldX + radius, worldY + radius, outList)
}
catch (e: NullPointerException) {
}
return outList
}
val punchSize = getPunchSize(actor)
val punchSize = actor.scale * actor.actorValue.getAsDouble(AVKey.BAREHAND_BASE_DIGSIZE)!!
val punchBlockSize = punchSize.div(TILE_SIZED).floorToInt() val punchBlockSize = punchSize.div(TILE_SIZED).floorToInt()
val mouseUnderPunchableTree = BlockCodex[world.getTileFromTerrain(mtx, mty)].hasAnyTagOf("LEAVES", "TREESMALL") val mouseUnderPunchableTree = BlockCodex[world.getTileFromTerrain(mtx, mty)].hasAnyTagOf("LEAVES", "TREESMALL")
// if there are attackable actor or fixtures
val actorsUnderMouse: List<ActorWithBody> = getActorsAtVicinity(mwx, mwy, punchSize / 2.0).sortedBy {
(mwx - it.hitbox.centeredX).sqr() + (mwy - it.hitbox.centeredY).sqr()
} // sorted by the distance from the mouse
// prioritise actors
val fixturesUnderHand = ArrayList<FixtureBase>()
val mobsUnderHand = ArrayList<ActorWithBody>()
actorsUnderMouse.forEach {
if (it is FixtureBase) // && it.mainUI == null) // pickup avail check must be done against fixture.canBeDespawned
fixturesUnderHand.add(it)
else if (it !is FixtureBase)
mobsUnderHand.add(it)
}
// pickup a fixture
if (fixturesUnderHand.size > 0 && fixturesUnderHand[0].canBeDespawned &&
System.nanoTime() - fixturesUnderHand[0].spawnRequestedTime > 500000000) { // don't pick up the fixture if it was recently placed (0.5 seconds)
val fixture = fixturesUnderHand[0]
val fixtureItem = ItemCodex.fixtureToItemID(fixture)
printdbg(this, "Fixture pickup at F${WORLD_UPDATE_TIMER}: ${fixture.javaClass.canonicalName} -> $fixtureItem")
// 0. hide tooltips
setTooltipMessage(null)
// 1. put the fixture to the inventory
fixture.flagDespawn()
// 2. register this item(fixture) to the quickslot so that the player sprite would be actually lifting the fixture
if (actor is Pocketed) {
actor.inventory.add(fixtureItem)
actor.equipItem(fixtureItem)
actor.inventory.setQuickslotItemAtSelected(fixtureItem)
// 2-1. unregister if other slot has the same item
for (k in 0..9) {
if (actor.inventory.getQuickslotItem(k)?.itm == fixtureItem && k != actor.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)) {
actor.inventory.setQuickslotItem(k, null)
}
}
}
}
// punch a small tree/shrub // punch a small tree/shrub
else if (mouseUnderPunchableTree) { if (mouseUnderPunchableTree) {
barehandAxeInUse = true barehandAxeInUse = true
AxeCore.startPrimaryUse(actor, delta, null, mtx, mty, punchBlockSize.coerceAtLeast(1), punchBlockSize.coerceAtLeast(1), listOf("TREESMALL")) AxeCore.startPrimaryUse(actor, delta, null, mtx, mty, punchBlockSize.coerceAtLeast(1), punchBlockSize.coerceAtLeast(1), listOf("TREESMALL"))
} }
@@ -1634,6 +1673,58 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
} }
} }
fun getActorsUnderMouse(mwx: Double, mwy: Double): List<ActorWithBody> {
val actorsUnderMouse: List<ActorWithBody> = getActorsAt(mwx, mwy).filter { it !is InternalActor }.sortedBy {
(mwx - it.hitbox.centeredX).sqr() + (mwy - it.hitbox.centeredY).sqr()
} // sorted by the distance from the mouse
return actorsUnderMouse
}
fun pickupFixture(actor: ActorWithBody, delta: Float, mwx: Double, mwy: Double, mtx: Int, mty: Int, assignToQuickslot: Boolean = true) {
val actorsUnderMouse = getActorsUnderMouse(mwx, mwy)
val fixture = actorsUnderMouse.firstOrNull {
it is FixtureBase && it.canBeDespawned &&
System.nanoTime() - it.spawnRequestedTime > 500000000 // don't pick up the fixture if it was recently placed (0.5 seconds)
} as? FixtureBase
val mob = actorsUnderMouse.firstOrNull {
it !is FixtureBase && it.physProp.usePhysics && !it.physProp.immobileBody
} as? ActorWithBody
// pickup a fixture
if (fixture != null) {
val fixtureItem = fixture.itemise()
printdbg(this, "Fixture pickup at F${WORLD_UPDATE_TIMER}: ${fixture.javaClass.canonicalName} -> $fixtureItem")
// 0. hide tooltips
setTooltipMessage(null)
if (!fixture.flagDespawn) {
// 1. put the fixture to the inventory
fixture.flagDespawn()
// 2. register this item(fixture) to the quickslot so that the player sprite would be actually lifting the fixture
if (actor is Pocketed) {
actor.inventory.add(fixtureItem)
if (assignToQuickslot) {
actor.equipItem(fixtureItem)
actor.inventory.setQuickslotItemAtSelected(fixtureItem)
// 2-1. unregister if other slot has the same item
for (k in 0..9) {
if (actor.inventory.getQuickslotItem(k)?.itm == fixtureItem && k != actor.actorValue.getAsInt(
AVKey.__PLAYER_QUICKSLOTSEL
)
) {
actor.inventory.setQuickslotItem(k, null)
}
}
}
}
}
}
else if (mob != null) {
// TODO pickup a mob
}
}
override fun hide() { override fun hide() {
uiContainer.forEach { it?.handler?.dispose() } uiContainer.forEach { it?.handler?.dispose() }
} }
@@ -1685,6 +1776,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
} }
override fun dispose() { override fun dispose() {
visibleActorsRenderFarBehind.forEach { it.dispose() }
visibleActorsRenderBehind.forEach { it.dispose() } visibleActorsRenderBehind.forEach { it.dispose() }
visibleActorsRenderMiddle.forEach { it.dispose() } visibleActorsRenderMiddle.forEach { it.dispose() }
visibleActorsRenderMidTop.forEach { it.dispose() } visibleActorsRenderMidTop.forEach { it.dispose() }

View File

@@ -194,7 +194,7 @@ class TerrarumMusicGovernor : MusicGovernor() {
protected var ambState = 0 protected var ambState = 0
protected var ambFired = false protected var ambFired = false
fun getRandomMusicInterval() = 3.6f + Math.random().toFloat() * 1.2f // use shorter gap a la mixtape fun getRandomMusicInterval() = 20f + Math.random().toFloat() * 4f // longer gap (20s to 24s)
var stopCaller: Any? = null; private set var stopCaller: Any? = null; private set
var playCaller: Any? = null; private set var playCaller: Any? = null; private set

View File

@@ -372,6 +372,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
listOf(), listOf(),
listOf(), listOf(),
listOf(), listOf(),
listOf(),
particles, particles,
uiContainer = uiContainer uiContainer = uiContainer
) )

View File

@@ -1,4 +1,4 @@
package net.torvald.terrarum.gameworld package net.torvald.terrarum.modulebasegame
import com.badlogic.gdx.utils.Queue import com.badlogic.gdx.utils.Queue
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
@@ -11,16 +11,16 @@ import net.torvald.terrarum.blockproperties.Fluid
import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.Controllable import net.torvald.terrarum.gameactors.Controllable
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.inUpdateRange import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.inUpdateRange
import net.torvald.terrarum.modulebasegame.gameactors.* import net.torvald.terrarum.modulebasegame.gameactors.*
import net.torvald.terrarum.modulebasegame.gameitems.AxeCore import net.torvald.terrarum.modulebasegame.gameitems.AxeCore
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
import org.dyn4j.geometry.Vector2 import org.dyn4j.geometry.Vector2
import java.lang.Math.pow
import kotlin.math.cosh import kotlin.math.cosh
import kotlin.math.min import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt import kotlin.math.roundToInt
import kotlin.math.sqrt
/** /**
* Created by minjaesong on 2016-08-03. * Created by minjaesong on 2016-08-03.
@@ -47,7 +47,7 @@ object WorldSimulator {
const val FLUID_MAX_MASS = 1f // The normal, un-pressurized mass of a full water cell 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_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 = 1f / 1024f //Ignore cells that are almost dry (smaller than epsilon of float16) const val FLUID_MIN_MASS = net.torvald.terrarum.gameworld.FLUID_MIN_MASS //Ignore cells that are almost dry (smaller than epsilon of float16)
const val WIRE_MIN_FLOW = 0.0001f const val WIRE_MIN_FLOW = 0.0001f
const val minFlow = 0.01f const val minFlow = 0.01f
const val maxSpeed = 1f // max units of water moved out of one block to another, per timestamp const val maxSpeed = 1f // max units of water moved out of one block to another, per timestamp
@@ -92,12 +92,7 @@ object WorldSimulator {
App.measureDebugTime("WorldSimulator.growGrass") { growOrKillGrass() } App.measureDebugTime("WorldSimulator.growGrass") { growOrKillGrass() }
App.measureDebugTime("WorldSimulator.fluids") { /*moveFluids(delta)*/ } App.measureDebugTime("WorldSimulator.fluids") { /*moveFluids(delta)*/ }
App.measureDebugTime("WorldSimulator.fallables") { displaceFallables(delta) } App.measureDebugTime("WorldSimulator.fallables") { displaceFallables(delta) }
if (ingame.WORLD_UPDATE_TIMER % 2 == 1) { App.measureDebugTime("WorldSimulator.wires") { simulateWires(delta) }
App.measureDebugTime("WorldSimulator.wires") { simulateWires(delta) }
}
else {
// TODO update logic
}
App.measureDebugTime("WorldSimulator.collisionDroppedItem") { collideDroppedItems() } App.measureDebugTime("WorldSimulator.collisionDroppedItem") { collideDroppedItems() }
App.measureDebugTime("WorldSimulator.dropTreeLeaves") { dropTreeLeaves() } App.measureDebugTime("WorldSimulator.dropTreeLeaves") { dropTreeLeaves() }
@@ -508,7 +503,7 @@ object WorldSimulator {
wiresimGetSourceBlocks().let { sources -> wiresimGetSourceBlocks().let { sources ->
// signal-emitting fixtures must set emitState of its own tiles via update() // signal-emitting fixtures must set emitState of its own tiles via update()
sources.forEach { sources.forEach {
it.wireEmitterTypes.forEach { bbi, wireType -> it.wireEmitterTypes.forEach { (bbi, wireType) ->
val startingPoint = it.worldBlockPos!! + it.blockBoxIndexToPoint2i(bbi) val startingPoint = it.worldBlockPos!! + it.blockBoxIndexToPoint2i(bbi)
val signal = it.wireEmission[bbi] ?: Vector2(0.0, 0.0) val signal = it.wireEmission[bbi] ?: Vector2(0.0, 0.0)
@@ -517,14 +512,19 @@ object WorldSimulator {
val simStartingPoint = WireGraphCursor(startingPoint, wire) val simStartingPoint = WireGraphCursor(startingPoint, wire)
wireSimMarked.clear() wireSimMarked.clear()
wireSimPoints.clear() wireSimPoints.clear()
traverseWireGraph(world, wire, simStartingPoint, signal) traverseWireGraph(world, wire, simStartingPoint, signal, wireType)
} }
} }
} }
} }
} }
private fun traverseWireGraph(world: GameWorld, wire: ItemID, startingPoint: WireGraphCursor, signal: Vector2) { private fun calculateDecay(signal: Vector2, dist: Int, wire: ItemID, signalType: WireEmissionType): Vector2 {
val d = WireCodex.wireDecays[wire]!!
return signal * d.pow(dist.toDouble())
}
private fun traverseWireGraph(world: GameWorld, wire: ItemID, startingPoint: WireGraphCursor, signal: Vector2, signalType: WireEmissionType) {
val emissionType = WireCodex[wire].accepts val emissionType = WireCodex[wire].accepts
@@ -542,7 +542,7 @@ object WorldSimulator {
wireSimMarked.add(point.longHash()) wireSimMarked.add(point.longHash())
oldTraversedNodes.add(point.copy()) oldTraversedNodes.add(point.copy())
// do some signal action // do some signal action
world.setWireEmitStateOf(point.x, point.y, wire, signal) world.setWireEmitStateOf(point.x, point.y, wire, calculateDecay(signal, point.len, wire, signalType))
} }
fun isMarked(point: WireGraphCursor) = wireSimMarked.contains(point.longHash()) fun isMarked(point: WireGraphCursor) = wireSimMarked.contains(point.longHash())

View File

@@ -0,0 +1,40 @@
package net.torvald.terrarum.modulebasegame.console
import net.torvald.terrarum.*
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
/**
* Created by minjaesong on 2024-03-10.
*/
object HasItem : ConsoleCommand {
override fun execute(args: Array<String>) {
if (args.size != 2)
printUsage()
else {
val it = args[1]
val hasBlock = BlockCodex.getOrNull(it) != null
val blockTags = BlockCodex.getOrNull(it)?.tags?.toList()?.sorted()?.joinToString()?.let { "($it)" } ?: ""
val hasItem = ItemCodex[it] != null
val itemTags = ItemCodex[it]?.tags?.toList()?.sorted()?.joinToString()?.let { "($it)" } ?: ""
val hasWire = WireCodex.getOrNull(it) != null
val wireTags = WireCodex.getOrNull(it)?.tags?.toList()?.sorted()?.joinToString()?.let { "($it)" } ?: ""
val hasOre = OreCodex.getOrNull(it) != null
val oreTags = OreCodex.getOrNull(it)?.tags?.toList()?.sorted()?.joinToString()?.let { "($it)" } ?: ""
Echo("${ccY}hasBlock? $ccG$hasBlock $ccO$blockTags")
Echo("${ccY}hasWire? $ccG$hasWire $ccO$wireTags")
Echo("${ccY}hasOre? $ccG$hasOre $ccO$oreTags")
Echo("${ccM}hasItem? $ccG$hasItem $ccO$itemTags")
}
}
override fun printUsage() {
Echo("Usage: hasitem itemid")
Echo("Prints the information if the item exists in the game")
}
}

View File

@@ -0,0 +1,41 @@
package net.torvald.terrarum.modulebasegame.console
import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.console.ConsoleCommand
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.itemproperties.Item
import net.torvald.terrarum.modulebasegame.gameitems.ItemTextSignCopper
import net.torvald.unicode.TIMES
/**
* Created by minjaesong on 2024-03-21.
*/
class MakeSign : ConsoleCommand {
override fun execute(args: Array<String>) {
if (args.size !in 2..3) {
printUsage(); return
}
val text = args[1]
val textLen = App.fontGame.getWidth(text) + 4
val panelCount = (args.getOrNull(2)?.toInt() ?: (textLen / TILE_SIZEF).ceilToInt()).coerceAtLeast(2)
val actorInventory = INGAME.actorNowPlaying!!.inventory
val item = ItemTextSignCopper(Item.COPPER_SIGN).makeDynamic(actorInventory).also {
it.extra["signContent"] = text
it.extra["signPanelCount"] = panelCount
it.nameSecondary = "[$panelCount${TIMES}2] $text"
}
actorInventory.add(item)
Echo("Sign added: ${item.nameSecondary}")
}
override fun printUsage() {
Echo("Usage: makesign <text>")
Echo("Usage: makesign <text> <panelcount>")
Echo("If panel count is not given, smallest possible panel count will be used.")
}
}

View File

@@ -100,7 +100,7 @@ class ActorInventory() : FixtureInventory() {
if (amount < 0) throw IllegalArgumentException("Consuming negative amount of an item (expected >=0, got $amount)") if (amount < 0) throw IllegalArgumentException("Consuming negative amount of an item (expected >=0, got $amount)")
if (item.stackable && !item.canBeDynamic) { if (item.isConsumable) {
remove(item, amount) remove(item, amount)
} }
else if (item.isUnique) { else if (item.isUnique) {
@@ -115,10 +115,8 @@ class ActorInventory() : FixtureInventory() {
remove(item, 1) remove(item, 1)
newItem = item.clone() newItem = item.makeDynamic(this)
newItem.generateUniqueDynamicID(this)
newItem.stackable = false
add(newItem) add(newItem)
itemEquipped[newItem.equipPosition] = newItem.dynamicID //invSearchByDynamicID(newItem.dynamicID)!!.item // will test if some sketchy code is written. Test fail: kotlinNullpointerException itemEquipped[newItem.equipPosition] = newItem.dynamicID //invSearchByDynamicID(newItem.dynamicID)!!.item // will test if some sketchy code is written. Test fail: kotlinNullpointerException
@@ -147,9 +145,9 @@ class ActorInventory() : FixtureInventory() {
if (newItem.durability <= 0) { if (newItem.durability <= 0) {
remove(newItem, 1) remove(newItem, 1)
// auto pull the same item if the player has one // auto reload the same item if the player has one, tool only
(actor as Pocketed).inventory.let { inv -> (actor as Pocketed).inventory.let { inv ->
inv.itemList.filter { ItemCodex[it.itm]?.originalID == newItem.originalID }.firstOrNull()?.let { (itm, qty) -> inv.itemList.filter { ItemCodex[it.itm]?.originalID == newItem.originalID && ItemCodex[it.itm]?.hasTag("TOOL") == true }.firstOrNull()?.let { (itm, qty) ->
printdbg(this, "AutoEquip item $itm") printdbg(this, "AutoEquip item $itm")
actor.equipItem(itm) actor.equipItem(itm)

View File

@@ -0,0 +1,200 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.terrarum.*
import net.torvald.terrarum.gameactors.ActorID
import net.torvald.terrarum.gameactors.PhysProperties
import net.torvald.terrarum.ui.UICanvas
import org.dyn4j.geometry.Vector2
import java.util.ArrayList
typealias WireEmissionType = String
/**
* Created by minjaesong on 2021-08-10.
*/
open class Electric : FixtureBase {
protected constructor() : super() {
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
}
/**
* Making the sprite: do not address the CommonResourcePool directly; just do it like this snippet:
*
* ```makeNewSprite(FixtureBase.getSpritesheet("basegame", "sprites/fixtures/tiki_torch.tga", 16, 32))```
*/
constructor(
blockBox0: BlockBox,
blockBoxProps: BlockBoxProps = BlockBoxProps(0),
renderOrder: RenderOrder = RenderOrder.MIDDLE,
nameFun: () -> String,
mainUI: UICanvas? = null,
inventory: FixtureInventory? = null,
id: ActorID? = null
) : super(renderOrder, PhysProperties.IMMOBILE(), id) {
blockBox = blockBox0
setHitboxDimension(TerrarumAppConfiguration.TILE_SIZE * blockBox.width, TerrarumAppConfiguration.TILE_SIZE * blockBox.height, 0, 0)
this.blockBoxProps = blockBoxProps
this.renderOrder = renderOrder
this.nameFun = nameFun
this.mainUI = mainUI
this.inventory = inventory
if (mainUI != null)
App.disposables.add(mainUI)
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
newSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
}
companion object {
const val ELECTRIC_THRESHOLD_HIGH = 0.6666666666666666
const val ELECTRIC_THRESHOLD_LOW = 0.3333333333333333
const val ELECTRIC_THRESHOLD_EDGE_DELTA = 0.33333333333333337
}
fun getWireEmitterAt(blockBoxIndex: BlockBoxIndex) = this.wireEmitterTypes[blockBoxIndex]
fun getWireEmitterAt(point: Point2i) = this.wireEmitterTypes[pointToBlockBoxIndex(point)]
fun getWireEmitterAt(x: Int, y: Int) = this.wireEmitterTypes[pointToBlockBoxIndex(x, y)]
fun getWireSinkAt(blockBoxIndex: BlockBoxIndex) = this.wireSinkTypes[blockBoxIndex]
fun getWireSinkAt(point: Point2i) = this.wireSinkTypes[pointToBlockBoxIndex(point)]
fun getWireSinkAt(x: Int, y: Int) = this.wireSinkTypes[pointToBlockBoxIndex(x, y)]
fun setWireEmitterAt(x: Int, y: Int, type: WireEmissionType) { wireEmitterTypes[pointToBlockBoxIndex(x, y)] = type }
fun setWireSinkAt(x: Int, y: Int, type: WireEmissionType) { wireSinkTypes[pointToBlockBoxIndex(x, y)] = type }
fun setWireEmissionAt(x: Int, y: Int, emission: Vector2) { wireEmission[pointToBlockBoxIndex(x, y)] = emission }
fun setWireConsumptionAt(x: Int, y: Int, consumption: Vector2) { wireConsumption[pointToBlockBoxIndex(x, y)] = consumption }
fun clearStatus() {
wireSinkTypes.clear()
wireEmitterTypes.clear()
wireEmission.clear()
wireConsumption.clear()
}
// these are characteristic properties of the fixture (they have constant value) so must not be serialised
@Transient val wireEmitterTypes: HashMap<BlockBoxIndex, WireEmissionType> = HashMap()
@Transient val wireSinkTypes: HashMap<BlockBoxIndex, WireEmissionType> = HashMap()
val wireEmission: HashMap<BlockBoxIndex, Vector2> = HashMap()
val wireConsumption: HashMap<BlockBoxIndex, Vector2> = HashMap()
// these are NOT constant so they ARE serialised. Type: Map<SinkType (String) -> Charge (Double>
// Use case: signal buffer (sinkType=digital_bit), battery (sinkType=electricity), etc.
val chargeStored: HashMap<String, Double> = HashMap()
private val newStates = HashMap<BlockBoxIndex, Vector2>()
/** Triggered when 'digital_bit' rises from low to high. Edge detection only considers the real component (labeled as 'x') of the vector */
open fun onRisingEdge(readFrom: BlockBoxIndex) {}
/** Triggered when 'digital_bit' rises from high to low. Edge detection only considers the real component (labeled as 'x') of the vector */
open fun onFallingEdge(readFrom: BlockBoxIndex) {}
/** Triggered when 'digital_bit' is held high. This function WILL NOT be triggered simultaneously with the rising edge. Level detection only considers the real component (labeled as 'x') of the vector */
//open fun onSignalHigh(readFrom: BlockBoxIndex) {}
/** Triggered when 'digital_bit' is held low. This function WILL NOT be triggered simultaneously with the falling edge. Level detection only considers the real component (labeled as 'x') of the vector */
//open fun onSignalLow(readFrom: BlockBoxIndex) {}
open fun updateSignal() {}
fun getWireStateAt(offsetX: Int, offsetY: Int, sinkType: WireEmissionType): Vector2 {
val index = pointToBlockBoxIndex(offsetX, offsetY)
val wx = offsetX + intTilewiseHitbox.startX.toInt()
val wy = offsetY + intTilewiseHitbox.startY.toInt()
return WireCodex.getAllWiresThatAccepts(sinkType).fold(Vector2()) { acc, (id, _) ->
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
}
}
}
fun getWireEmissionAt(offsetX: Int, offsetY: Int): Vector2 {
return wireEmission[pointToBlockBoxIndex(offsetX, offsetY)] ?: Vector2()
}
/**
* returns true if at least one of following condition is `true`
* - `getWireStateAt(x, y, "digital_bit").x` is equal to or greater than `ELECTIC_THRESHOLD_HIGH`
* - `getWireEmissionAt(x, y).x` is equal to or greater than `ELECTIC_THRESHOLD_HIGH`
*
* This function does NOT check if the given port receives/emits `digital_bit` signal; if not, the result is undefined.
*/
fun isSignalHigh(offsetX: Int, offsetY: Int) =
getWireStateAt(offsetX, offsetY, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH ||
getWireEmissionAt(offsetX, offsetY).x >= ELECTRIC_THRESHOLD_HIGH
/**
* returns true if at least one of following condition is `true`
* - `getWireStateAt(x, y, "digital_bit").x` is equal to or lesser than `ELECTRIC_THRESHOLD_LOW`
* - `getWireEmissionAt(x, y).x` is equal to or lesser than `ELECTRIC_THRESHOLD_LOW`
*
* This function does NOT check if the given port receives/emits `digital_bit` signal; if not, the result is undefined.
*/
fun isSignalLow(offsetX: Int, offsetY: Int) =
getWireStateAt(offsetX, offsetY, "digital_bit").x <= ELECTRIC_THRESHOLD_LOW ||
getWireEmissionAt(offsetX, offsetY).x <= ELECTRIC_THRESHOLD_LOW
protected var oldSinkStatus: Array<Vector2>
protected var newSinkStatus: Array<Vector2>
open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) {
val index = pointToBlockBoxIndex(offsetX, offsetY)
val wx = offsetX + intTilewiseHitbox.startX.toInt()
val wy = offsetY + intTilewiseHitbox.startY.toInt()
val new2 = WireCodex.getAllWiresThatAccepts(wireSinkTypes[index] ?: "").fold(Vector2()) { acc, (id, _) ->
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
}
}
oldSinkStatus[index].set(new2)
}
/**
* Refrain from updating signal output from this function: there will be 1 extra tick delay if you do so
*/
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
val risingEdgeIndices = ArrayList<BlockBoxIndex>()
val fallingEdgeIndices = ArrayList<BlockBoxIndex>()
for (y in 0 until blockBox.height) {
for (x in 0 until blockBox.width) {
// get indices of "rising edges"
// get indices of "falling edges"
val wx = x + intTilewiseHitbox.startX.toInt()
val wy = y + intTilewiseHitbox.startY.toInt()
val new = WireCodex.getAllWiresThatAccepts(getWireSinkAt(x, y) ?: "").fold(Vector2()) { acc, (id, _) ->
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
}
}
val index = pointToBlockBoxIndex(x, y)
if (new.x - oldSinkStatus[index].x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x >= ELECTRIC_THRESHOLD_HIGH)
risingEdgeIndices.add(index)
else if (oldSinkStatus[index].x - new.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x <= ELECTRIC_THRESHOLD_LOW)
fallingEdgeIndices.add(index)
oldSinkStatus[index].set(new)
}
}
risingEdgeIndices.forEach { onRisingEdge(it) }
fallingEdgeIndices.forEach { onFallingEdge(it) }
updateSignal()
/*oldSinkStatus.indices.forEach { index ->
oldSinkStatus[index].set(new)
}*/
}
}

View File

@@ -0,0 +1,390 @@
package net.torvald.terrarum.modulebasegame.gameactors
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.gdx.graphics.Cvec
import net.torvald.random.HQRNG
import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.*
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.audio.MusicContainer
import net.torvald.terrarum.audio.dsp.Gain
import net.torvald.terrarum.audio.dsp.NullFilter
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.Hitbox
import net.torvald.terrarum.gameactors.Lightbox
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameparticles.ParticleVanishingSprite
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.ui.UIAlloyingFurnace
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2024-03-09.
*/
class FixtureAlloyingFurnace : FixtureBase {
var fuelCaloriesNow = 0.0 // arbitrary number, may as well be watts or joules
var fuelCaloriesMax: Double? = null
var temperature = 0f // 0f..1f
var progress = 0f // 0f..1f
internal var oreItem1: InventoryPair? = null
internal var oreItem2: InventoryPair? = null
internal var fireboxItem: InventoryPair? = null
internal var productItem: InventoryPair? = null
@Transient val oreItem1Status = object : SmelterItemStatus {
override fun set(itm: ItemID, qty: Long) {
if (oreItem1 != null) oreItem1!!.set(itm, qty)
else oreItem1 = InventoryPair(itm, qty)
}
override fun changeCount(delta: Long) {
oreItem1!!.qty += delta
if (oreItem1!!.qty <= 0L) {
oreItem1 = null
}
}
override fun nullify() {
oreItem1 = null
}
override fun isNull(): Boolean {
return oreItem1 == null
}
override val itm: ItemID?
get() = oreItem1?.itm
override val qty: Long?
get() = oreItem1?.qty
}
@Transient val oreItem2Status = object : SmelterItemStatus {
override fun set(itm: ItemID, qty: Long) {
if (oreItem2 != null) oreItem2!!.set(itm, qty)
else oreItem2 = InventoryPair(itm, qty)
}
override fun changeCount(delta: Long) {
oreItem2!!.qty += delta
if (oreItem2!!.qty <= 0L) {
oreItem2 = null
}
}
override fun nullify() {
oreItem2 = null
}
override fun isNull(): Boolean {
return oreItem2 == null
}
override val itm: ItemID?
get() = oreItem2?.itm
override val qty: Long?
get() = oreItem2?.qty
}
@Transient val fireboxItemStatus = object : SmelterItemStatus {
override fun set(itm: ItemID, qty: Long) {
if (fireboxItem != null) fireboxItem!!.set(itm, qty)
else fireboxItem = InventoryPair(itm, qty)
}
override fun changeCount(delta: Long) {
fireboxItem!!.qty += delta
if (fireboxItem!!.qty <= 0L) {
fireboxItem = null
}
}
override fun nullify() {
fireboxItem = null
}
override fun isNull(): Boolean {
return fireboxItem == null
}
override val itm: ItemID?
get() = fireboxItem?.itm
override val qty: Long?
get() = fireboxItem?.qty
}
@Transient val productItemStatus = object : SmelterItemStatus {
override fun set(itm: ItemID, qty: Long) {
if (productItem != null) productItem!!.set(itm, qty)
else productItem = InventoryPair(itm, qty)
}
override fun changeCount(delta: Long) {
productItem!!.qty += delta
if (productItem!!.qty <= 0L) {
productItem = null
}
}
override fun nullify() {
productItem = null
}
override fun isNull(): Boolean {
return productItem == null
}
override val itm: ItemID?
get() = productItem?.itm
override val qty: Long?
get() = productItem?.qty
}
override val canBeDespawned: Boolean
get() = oreItem1 == null && oreItem2 == null && fireboxItem == null && productItem == null
init {
CommonResourcePool.addToLoadingList("basegame/sprites/fixtures/alloying_furnace.tga") {
TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/fixtures/alloying_furnace.tga"), 32, 32)
}
CommonResourcePool.addToLoadingList("basegame/sprites/fixtures/alloying_furnace_emsv.tga") {
TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/fixtures/alloying_furnace_emsv.tga"), 32, 32)
}
CommonResourcePool.loadAll()
}
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 2), // temporary value, will be overwritten by spawn()
nameFun = { Lang["ITEM_ALLOYING_FURNACE"] },
) {
CommonResourcePool.addToLoadingList("particles-tiki_smoke.tga") {
TextureRegionPack(ModMgr.getGdxFile("basegame", "particles/bigger_smoke.tga"), 16, 16)
}
CommonResourcePool.loadAll()
density = BlockCodex[Block.STONE].density.toDouble()
setHitboxDimension(32, 32, 0, 0)
makeNewSprite(CommonResourcePool.getAsTextureRegionPack("basegame/sprites/fixtures/alloying_furnace.tga")).let {
it.setRowsAndFrames(1,1)
}
makeNewSpriteEmissive(CommonResourcePool.getAsTextureRegionPack("basegame/sprites/fixtures/alloying_furnace_emsv.tga")).let {
it.setRowsAndFrames(1,1)
}
actorValue[AVKey.BASEMASS] = 100.0
this.mainUI = UIAlloyingFurnace(this)
}
@Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), true)
@Transient val light = Cvec(0.5f, 0.18f, 0f, 0f)
@Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 0.0, TILE_SIZED * 2, TILE_SIZED * 2), light))
@Transient private val actorBlocks = arrayOf(
arrayOf(Block.ACTORBLOCK_NO_COLLISION, null),
arrayOf(Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION),
)
override fun placeActorBlocks() {
forEachBlockbox { x, y, ox, oy ->
val tile = actorBlocks[oy][ox]
if (tile != null) {
world!!.setTileTerrain(x, y, tile, true)
}
}
}
private var nextDelayBase = 0.25f // use smokiness value of the item
private var nextDelay = 0.25f // use smokiness value of the item
private var spawnTimer = 0f
@Transient private val RNG = HQRNG()
override fun drawEmissive(frameDelta: Float, batch: SpriteBatch) {
if (isVisible && spriteEmissive != null) {
BlendMode.resolve(drawMode, batch)
(spriteEmissive as SheetSpriteAnimation).currentFrame = 1 // unlit
drawSpriteInGoodPosition(frameDelta, spriteEmissive!!, batch, 2, Color.WHITE)
(spriteEmissive as SheetSpriteAnimation).currentFrame = 0 // lit
val r = 1f - (temperature - 1f).sqr()
val g = (2f * temperature - 1f).coerceIn(0f, 1f)
drawSpriteInGoodPosition(frameDelta, spriteEmissive!!, batch, 2, Color(r, g, g, 1f))
}
// debug display of hIntTilewiseHitbox
if (KeyToggler.isOn(Input.Keys.F9)) {
val blockMark = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common").get(0, 0)
for (y in 0..intTilewiseHitbox.height.toInt() + 1) {
batch.color = if (y == intTilewiseHitbox.height.toInt() + 1) HITBOX_COLOURS1 else HITBOX_COLOURS0
for (x in 0..intTilewiseHitbox.width.toInt()) {
batch.draw(blockMark,
(intTilewiseHitbox.startX.toFloat() + x) * TerrarumAppConfiguration.TILE_SIZEF,
(intTilewiseHitbox.startY.toFloat() + y) * TerrarumAppConfiguration.TILE_SIZEF
)
}
}
batch.color = Color.WHITE
}
}
override fun drawBody(frameDelta: Float, batch: SpriteBatch) {
if (isVisible && sprite != null) {
BlendMode.resolve(drawMode, batch)
(sprite as SheetSpriteAnimation).currentFrame = 1 // unlit
drawSpriteInGoodPosition(frameDelta, sprite!!, batch, forcedColourFilter = Color.WHITE)
(sprite as SheetSpriteAnimation).currentFrame = 2 // lit overlay
val r = 1f - (temperature - 1f).sqr()
val g = (2f * temperature - 1f).coerceIn(0f, 1f)
drawSpriteInGoodPosition(frameDelta, sprite!!, batch, forcedColourFilter = Color(1f, g, g, r))
}
// debug display of hIntTilewiseHitbox
if (KeyToggler.isOn(Input.Keys.F9)) {
val blockMark = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common").get(0, 0)
for (y in 0..intTilewiseHitbox.height.toInt() + 1) {
batch.color = if (y == intTilewiseHitbox.height.toInt() + 1) HITBOX_COLOURS1 else HITBOX_COLOURS0
for (x in 0..intTilewiseHitbox.width.toInt()) {
batch.draw(blockMark,
(intTilewiseHitbox.startX.toFloat() + x) * TerrarumAppConfiguration.TILE_SIZEF,
(intTilewiseHitbox.startY.toFloat() + y) * TerrarumAppConfiguration.TILE_SIZEF
)
}
}
batch.color = Color.WHITE
}
}
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
val fuelItemProp = ItemCodex[fireboxItem?.itm]
// consume fuel
if (fuelCaloriesNow > 0f) {
fuelCaloriesNow -= FixtureSmelterBasic.FUEL_CONSUMPTION
// raise temperature
temperature += 1f /2048f
}
// take fuel from the item slot
else if (fuelCaloriesNow <= 0f && fuelItemProp?.calories != null && fireboxItem!!.qty > 0L) {
fuelCaloriesNow = fuelItemProp.calories
fuelCaloriesMax = fuelItemProp.calories
nextDelayBase = fuelItemProp.smokiness
nextDelay = (nextDelayBase * (1.0 + RNG.nextTriangularBal() * 0.1)).toFloat()
fireboxItemStatus.changeCount(-1)
}
// no item on the slot
else if (fuelCaloriesNow <= 0f && fireboxItem == null) {
nextDelayBase = Float.POSITIVE_INFINITY
nextDelay = Float.POSITIVE_INFINITY
}
// tick a thermal loss
temperature -= 1f / 4096f
temperature = temperature.coerceIn(0f, 1f)
// emit smokes only when there is something burning
if (spawnTimer >= nextDelay) {
(Terrarum.ingame as TerrarumIngame).addParticle(
ParticleVanishingSprite(
CommonResourcePool.getAsTextureRegionPack("particles-tiki_smoke.tga"),
25f, true, hitbox.startX + TILE_SIZED / 2, hitbox.startY + 16, false, (Math.random() * 256).toInt()
)
)
spawnTimer -= nextDelay
nextDelay = (nextDelayBase * (1.0 + RNG.nextTriangularBal() * 0.1)).toFloat()
(sprite as? SheetSpriteAnimation)?.delays?.set(0, Math.random().toFloat() * 0.4f + 0.1f)
}
val smeltingProduct = CraftingRecipeCodex.getSmeltingProductOf(oreItem1?.itm, oreItem2?.itm)
// roast items
if (oreItem1 != null &&
oreItem2 != null &&
temperature > 0f &&
smeltingProduct != null &&
(productItem == null || smeltingProduct.item == productItem!!.itm)
) {
progress += temperature
if (progress >= FixtureSmelterBasic.CALORIES_PER_ROASTING) {
val moq = smeltingProduct.moq
val smeltingProduct = smeltingProduct.item
// check if the item even exists
if (ItemCodex[smeltingProduct] == null) throw NullPointerException("No item prop for $smeltingProduct")
if (productItem == null)
productItem = InventoryPair(smeltingProduct, moq)
else
productItemStatus.changeCount(1)
// take the ore item
oreItem1Status.changeCount(-1)
oreItem2Status.changeCount(-1)
progress = 0f
}
}
else if (oreItem1 == null || oreItem2 == null) {
progress = 0f
}
// update lightbox
lightBoxList.forEach {
it.light = light.cpy().mul(temperature)
}
if (temperature > 0.001f)
spawnTimer += delta
else
spawnTimer = 0f
// update sound randomiser
volRand.update(delta)
// manage audio
// FIXME this code is also killing the audio played by the other fixture (FixtureFurnaceAndAnvil)
getTrackByAudio(static).let {
if (it == null || (temperature > 0f && !it.isPlaying && !it.playRequested.get())) {
startAudio(static) {
it.filters[filterIndex] = Gain(0f)
}
}
else if (it != null && it.isPlaying && temperature <= 0f) {
stopAudio(static) {
it.filters[filterIndex] = NullFilter
}
}
if (it != null) {
if (it.filters[filterIndex] !is Gain) // just in case...
it.filters[filterIndex] = Gain(0f)
(it.filters[filterIndex] as Gain).gain = (it.maxVolume * temperature * volRand.get()).toFloat()
}
}
}
@Transient private val filterIndex = 0
@Transient private val volRand = ParamRandomiser(0.8f, 0.4f)
override fun dispose() {
super.dispose()
static.dispose()
}
}

View File

@@ -6,129 +6,16 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.* import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
import java.util.* import java.util.*
import kotlin.collections.HashMap
import kotlin.math.roundToInt import kotlin.math.roundToInt
typealias BlockBoxIndex = Int typealias BlockBoxIndex = Int
typealias WireEmissionType = String
open class Electric : FixtureBase {
protected constructor() : super() {
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
}
/**
* Making the sprite: do not address the CommonResourcePool directly; just do it like this snippet:
*
* ```makeNewSprite(FixtureBase.getSpritesheet("basegame", "sprites/fixtures/tiki_torch.tga", 16, 32))```
*/
constructor(
blockBox0: BlockBox,
blockBoxProps: BlockBoxProps = BlockBoxProps(0),
renderOrder: RenderOrder = RenderOrder.MIDDLE,
nameFun: () -> String,
mainUI: UICanvas? = null,
inventory: FixtureInventory? = null,
id: ActorID? = null
) : super(renderOrder, PhysProperties.IMMOBILE(), id) {
blockBox = blockBox0
setHitboxDimension(TILE_SIZE * blockBox.width, TILE_SIZE * blockBox.height, 0, 0)
this.blockBoxProps = blockBoxProps
this.renderOrder = renderOrder
this.nameFun = nameFun
this.mainUI = mainUI
this.inventory = inventory
if (mainUI != null)
App.disposables.add(mainUI)
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
}
companion object {
const val ELECTIC_THRESHOLD_HIGH = 0.9
const val ELECTRIC_THRESHOLD_LOW = 0.1
const val ELECTRIC_THRESHOLD_EDGE_DELTA = 0.7
}
fun getWireEmitterAt(point: Point2i) = this.wireEmitterTypes[pointToBlockBoxIndex(point)]
fun getWireEmitterAt(x: Int, y: Int) = this.wireEmitterTypes[pointToBlockBoxIndex(x, y)]
fun getWireSinkAt(point: Point2i) = this.wireSinkTypes[pointToBlockBoxIndex(point)]
fun getWireSinkAt(x: Int, y: Int) = this.wireSinkTypes[pointToBlockBoxIndex(x, y)]
fun setWireEmitterAt(x: Int, y: Int, type: WireEmissionType) { wireEmitterTypes[pointToBlockBoxIndex(x, y)] = type }
fun setWireSinkAt(x: Int, y: Int, type: WireEmissionType) { wireSinkTypes[pointToBlockBoxIndex(x, y)] = type }
fun setWireEmissionAt(x: Int, y: Int, emission: Vector2) { wireEmission[pointToBlockBoxIndex(x, y)] = emission }
fun setWireConsumptionAt(x: Int, y: Int, consumption: Vector2) { wireConsumption[pointToBlockBoxIndex(x, y)] = consumption }
// these are characteristic properties of the fixture (they have constant value) so must not be serialised
@Transient val wireEmitterTypes: HashMap<BlockBoxIndex, WireEmissionType> = HashMap()
@Transient val wireSinkTypes: HashMap<BlockBoxIndex, WireEmissionType> = HashMap()
@Transient val wireEmission: HashMap<BlockBoxIndex, Vector2> = HashMap()
@Transient val wireConsumption: HashMap<BlockBoxIndex, Vector2> = HashMap()
// these are NOT constant so they ARE serialised. Type: Map<SinkType (String) -> Charge (Double>
// Use case: signal buffer (sinkType=digital_bit), battery (sinkType=electricity), etc.
val chargeStored: HashMap<String, Double> = HashMap()
/** Triggered when 'digital_bit' rises from low to high. Edge detection only considers the real component (labeled as 'x') of the vector */
open fun onRisingEdge(readFrom: BlockBoxIndex) {}
/** Triggered when 'digital_bit' rises from high to low. Edge detection only considers the real component (labeled as 'x') of the vector */
open fun onFallingEdge(readFrom: BlockBoxIndex) {}
/** Triggered when 'digital_bit' is held high. This function WILL NOT be triggered simultaneously with the rising edge. Level detection only considers the real component (labeled as 'x') of the vector */
open fun onSignalHigh(readFrom: BlockBoxIndex) {}
/** Triggered when 'digital_bit' is held low. This function WILL NOT be triggered simultaneously with the falling edge. Level detection only considers the real component (labeled as 'x') of the vector */
open fun onSignalLow(readFrom: BlockBoxIndex) {}
private val oldSinkStatus: Array<Vector2>
open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) {
val index = pointToBlockBoxIndex(offsetX, offsetY)
val old = oldSinkStatus[index]
val wx = offsetX + intTilewiseHitbox.startX.toInt()
val wy = offsetY + intTilewiseHitbox.startY.toInt()
val new = WireCodex.getAllWiresThatAccepts("digital_bit").fold(Vector2()) { acc, (id, _) ->
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
}
}
if (sinkType == "digital_bit") {
if (new.x - old.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x >= ELECTIC_THRESHOLD_HIGH)
onRisingEdge(index)
else if (old.x - new.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x <= ELECTRIC_THRESHOLD_LOW)
onFallingEdge(index)
else if (new.x >= ELECTIC_THRESHOLD_HIGH)
onSignalHigh(index)
else if (new.y <= ELECTRIC_THRESHOLD_LOW)
onSignalLow(index)
}
}
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
oldSinkStatus.indices.forEach { index ->
val wx = (index % blockBox.width) + intTilewiseHitbox.startX.toInt()
val wy = (index / blockBox.width) + intTilewiseHitbox.startY.toInt()
val new = WireCodex.getAllWiresThatAccepts(getWireSinkAt(index % blockBox.width, index / blockBox.width) ?: "").fold(Vector2()) { acc, (id, _) ->
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
}
}
oldSinkStatus[index].set(new)
}
}
}
/** /**
* Protip: do not make child classes take any argument, especially no function (function "classes" have no zero-arg constructor) * Protip: do not make child classes take any argument, especially no function (function "classes" have no zero-arg constructor)
@@ -141,6 +28,9 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
@Transient open val spawnNeedsWall: Boolean = false @Transient open val spawnNeedsWall: Boolean = false
@Transient open val spawnNeedsFloor: Boolean = true @Transient open val spawnNeedsFloor: Boolean = true
@Transient open val spawnNeedsCeiling: Boolean = false
// if both spawnNeedsWall and spawnNeedsFloor are true, the condition will be interpreted as OR-condition
/** Real time, in nanoseconds */ /** Real time, in nanoseconds */
@Transient var spawnRequestedTime: Long = 0L @Transient var spawnRequestedTime: Long = 0L
@@ -172,6 +62,19 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
*/ */
open fun onSpawn(tx: Int, ty: Int) {} open fun onSpawn(tx: Int, ty: Int) {}
/**
* If the fixture has mainUI, do NOT override this function! Opening of the UI is handled by TerrarumIngame.worldPrimaryClickStart
*
* For someone might be concerened, you don't need to have a MouseLatch or worry about the `if (mouseUp)`; it's considered by the Ingame
*
* Fired when "just clicked" by mousePrimary
*
* @param mx Terrarum.mouseX (mouse position in the world)
* @param my Terrarum.omuseY (mouse position in the world)
*/
open fun onInteract(mx: Double, my: Double) {
}
/** /**
* Making the sprite: do not address the CommonResourcePool directly; just do it like this snippet: * Making the sprite: do not address the CommonResourcePool directly; just do it like this snippet:
* *
@@ -267,25 +170,94 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
cannotSpawn = everyBlockboxPos.any { (x, y) -> !BlockCodex[world!!.getTileFromTerrain(x, y)].hasTag("INCONSEQUENTIAL") } cannotSpawn = everyBlockboxPos.any { (x, y) -> !BlockCodex[world!!.getTileFromTerrain(x, y)].hasTag("INCONSEQUENTIAL") }
var cannotSpawnNoWall = false
var cannotSpawnNoFloor = false
// check for walls, if spawnNeedsWall = true // check for walls, if spawnNeedsWall = true
if (spawnNeedsWall) { if (spawnNeedsWall) {
cannotSpawn = cannotSpawn or everyBlockboxPos.any { (x, y) -> !BlockCodex[world!!.getTileFromWall(x, y)].isSolid } cannotSpawnNoWall = everyBlockboxPos.any { (x, y) -> !BlockCodex[world!!.getTileFromWall(x, y)].isSolid }
} }
// check for floors, if spawnNeedsFloor == true // check for floors, if spawnNeedsFloor == true
if (spawnNeedsFloor) { if (spawnNeedsFloor || spawnNeedsCeiling) {
val y = posY + blockBox.height val y = posY + if (spawnNeedsFloor) blockBox.height else -1
val xs = posX until posX + blockBox.width val xs = posX until posX + blockBox.width
cannotSpawn = cannotSpawn or xs.any { x -> cannotSpawnNoFloor = xs.any { x ->
world!!.getTileFromTerrain(x, y).let { world!!.getTileFromTerrain(x, y).let {
!canSpawnOnThisFloor(it) !canSpawnOnThisFloor(it)
} }
} }
} }
if (spawnNeedsWall && (spawnNeedsFloor || spawnNeedsCeiling))
cannotSpawn = cannotSpawn or (cannotSpawnNoWall && cannotSpawnNoFloor)
else if (spawnNeedsFloor || spawnNeedsCeiling)
cannotSpawn = cannotSpawn or cannotSpawnNoFloor
else if (spawnNeedsWall)
cannotSpawn = cannotSpawn or cannotSpawnNoWall
return !cannotSpawn return !cannotSpawn
} }
/**
* @param posX top-left
* @param posY top-left
*/
open fun makeNoiseAndDust(posX: Int, posY: Int) {
val posYb = posY + blockBox.height - 1
val posXc = posX + blockBox.width / 2
// make some noise
var soundSource =
if (spawnNeedsWall) 1
else if (spawnNeedsFloor) 0
else if (spawnNeedsCeiling) 3
else 2
// 1: wall, 0: floor, 2: if wall is not solid, use wall; else, use floor
val wallTile = world!!.getTileFromWall(posXc, posYb)
val terrTile = if (soundSource == 3)
world!!.getTileFromTerrain(posXc, posYb - blockBox.height)
else
world!!.getTileFromTerrain(posXc, posYb + 1)
if (soundSource == 2) {
soundSource = if (BlockCodex[wallTile].isSolid)
1
else
0
}
when (soundSource) {
1 -> PickaxeCore.makeNoiseTileBurst(this, wallTile)
0, 3 -> PickaxeCore.makeNoiseTileBurst(this, terrTile)
}
// make some dust
if (soundSource == 0) {
val y = posY + blockBox.height
for (x in posX until posX + blockBox.width) {
val tile = world!!.getTileFromTerrain(x, y)
PickaxeCore.makeDust(tile, x, y - 1, 4 + (Math.random() + Math.random()).roundToInt())
}
}
else if (soundSource == 3) {
val y = posY
for (x in posX until posX + blockBox.width) {
val tile = world!!.getTileFromTerrain(x, y)
PickaxeCore.makeDust(tile, x, y - 1, 4 + (Math.random() + Math.random()).roundToInt())
}
}
else {
for (y in posY until posY + blockBox.height) {
for (x in posX until posX + blockBox.width) {
val tile = world!!.getTileFromWall(x, y)
PickaxeCore.makeDust(tile, x, y, 2 + (Math.random() + Math.random()).roundToInt())
}
}
}
}
/** /**
* Adds this instance of the fixture to the world. Physical dimension is derived from [blockBox]. * Adds this instance of the fixture to the world. Physical dimension is derived from [blockBox].
* *
@@ -346,53 +318,6 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
return true return true
} }
/**
* @param posX top-left
* @param posY top-left
*/
open fun makeNoiseAndDust(posX: Int, posY: Int) {
val posYb = posY + blockBox.height - 1
val posXc = posX + blockBox.width / 2
// make some noise
var soundSource =
if (spawnNeedsWall) 1
else if (spawnNeedsFloor) 0
else 2
// 1: wall, 0: floor, 2: if wall is not solid, use wall; else, use floor
val wallTile = world!!.getTileFromWall(posXc, posYb)
val terrTile = world!!.getTileFromTerrain(posXc, posYb + 1)
if (soundSource == 2) {
soundSource = if (BlockCodex[wallTile].isSolid)
1
else
0
}
when (soundSource) {
1 -> PickaxeCore.makeNoiseTileBurst(this, wallTile)
0 -> PickaxeCore.makeNoiseTileBurst(this, terrTile)
}
// make some dust
if (soundSource == 0) {
val y = posY + blockBox.height
for (x in posX until posX + blockBox.width) {
val tile = world!!.getTileFromTerrain(x, y)
PickaxeCore.makeDust(tile, x, y - 1, 4 + (Math.random() + Math.random()).roundToInt())
}
}
else {
for (y in posY until posY + blockBox.height) {
for (x in posX until posX + blockBox.width) {
val tile = world!!.getTileFromWall(x, y)
PickaxeCore.makeDust(tile, x, y, 2 + (Math.random() + Math.random()).roundToInt())
}
}
}
}
/** /**
* Identical to `spawn(Int, Int)` except it takes user-defined hitbox dimension instead of taking value from [blockBox]. * Identical to `spawn(Int, Int)` except it takes user-defined hitbox dimension instead of taking value from [blockBox].
* Useful if [blockBox] cannot be determined on the time of the constructor call. * Useful if [blockBox] cannot be determined on the time of the constructor call.
@@ -447,6 +372,8 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
makeNoiseAndDust(posX, posY) makeNoiseAndDust(posX, posY)
onSpawn(posX0, posY0)
return true return true
} }
@@ -536,6 +463,14 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
} as TextureRegionPack) } as TextureRegionPack)
} }
} }
/**
* For some customisable fixtures, they must create new dynamicItem out of their static "template",
* register the new dynamicID to the ItemCodex, then return the dynamicID.
*/
open fun itemise(): ItemID {
return ItemCodex.fixtureToItemID(this)
}
} }
interface CuedByTerrainChange { interface CuedByTerrainChange {
@@ -556,7 +491,6 @@ interface CuedByWireChange {
fun updateForWireChange(cue: IngameInstance.BlockChangeQueueItem) fun updateForWireChange(cue: IngameInstance.BlockChangeQueueItem)
} }
/** /**
* Standard 32-bit binary flags. * Standard 32-bit binary flags.
* *

View File

@@ -336,6 +336,11 @@ class InventoryPair : Comparable<InventoryPair> {
override fun toString(): String { override fun toString(): String {
return if (qty == -1L) "$itm" else "$itm ($qty)" return if (qty == -1L) "$itm" else "$itm ($qty)"
} }
fun set(itm: ItemID, qty: Long) {
this.itm = itm
this.qty = qty
}
} }
class InventoryTransactionFailedError(msg: String) : Error(msg) class InventoryTransactionFailedError(msg: String) : Error(msg)

View File

@@ -0,0 +1,152 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.toInt
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
/**
* Created by minjaesong on 2024-03-10.
*/
class FixtureLogicSignalAdder : Electric, Reorientable {
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 2),
nameFun = { Lang["ITEM_LOGIC_SIGNAL_ADDER"] }
)
override var orientation = 0 // 0 1 2 3
private fun setEmitterAndSink() {
clearStatus()
when (orientation) {
0 -> {
setWireSinkAt(0, 0, "digital_bit")
setWireSinkAt(0, 1, "digital_bit")
setWireEmitterAt(1, 0, "digital_bit")
setWireEmitterAt(1, 1, "digital_bit")
}
1 -> {
setWireSinkAt(1, 0, "digital_bit")
setWireSinkAt(0, 0, "digital_bit")
setWireEmitterAt(1, 1, "digital_bit")
setWireEmitterAt(0, 1, "digital_bit")
}
2 -> {
setWireSinkAt(1, 1, "digital_bit")
setWireSinkAt(1, 0, "digital_bit")
setWireEmitterAt(0, 1, "digital_bit")
setWireEmitterAt(0, 0, "digital_bit")
}
3 -> {
setWireSinkAt(0, 1, "digital_bit")
setWireSinkAt(1, 1, "digital_bit")
setWireEmitterAt(0, 0, "digital_bit")
setWireEmitterAt(1, 0, "digital_bit")
}
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
}
private fun reorient() {
(sprite as SheetSpriteAnimation).currentFrame = orientation
(spriteEmissive as SheetSpriteAnimation).currentFrame = orientation
}
override fun orientClockwise() {
orientation = (orientation + 1) fmod 4
reorient(); setEmitterAndSink(); updateK()
}
override fun orientAnticlockwise() {
orientation = (orientation - 1) fmod 4
reorient(); setEmitterAndSink(); updateK()
}
init {
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_adder.tga")
val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_adder_emsv.tga")
density = 1400.0
setHitboxDimension(2*TILE_SIZE, 2*TILE_SIZE, 0, 1)
makeNewSprite(TextureRegionPack(itemImage.texture, 2*TILE_SIZE, 2*TILE_SIZE)).let {
it.setRowsAndFrames(16,4)
it.delays = FloatArray(16) { Float.POSITIVE_INFINITY }
}
makeNewSpriteEmissive(TextureRegionPack(itemImage2.texture, 2*TILE_SIZE, 2*TILE_SIZE)).let {
it.setRowsAndFrames(16,4)
it.delays = FloatArray(16) { Float.POSITIVE_INFINITY }
}
setEmitterAndSink()
}
override fun reload() {
super.reload()
reorient()
setEmitterAndSink()
updateK()
}
private val I: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
1 -> getWireStateAt(1, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
3 -> getWireStateAt(0, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private val J: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
1 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
3 -> getWireStateAt(1, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private fun updateK() {
val (x1, y1) = when (orientation) {
0 -> 1 to 0
1 -> 1 to 1
2 -> 0 to 1
3 -> 0 to 0
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
val (x2, y2) = when (orientation) {
0 -> 1 to 1
1 -> 0 to 1
2 -> 0 to 0
3 -> 1 to 0
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
val output1 = (I xor J).toInt().toDouble()
val output2 = (I and J).toInt().toDouble()
setWireEmissionAt(x1, y1, Vector2(output1, 0.0))
setWireEmissionAt(x2, y2, Vector2(output2, 0.0))
// update sprite
val one = isSignalHigh(0, 0)
val two = isSignalHigh(1, 0)
val four = isSignalHigh(0, 1)
val eight = isSignalHigh(1, 1)
val state = one.toInt(0) or two.toInt(1) or four.toInt(2) or eight.toInt(3)
(sprite as SheetSpriteAnimation).currentRow = state
(spriteEmissive as SheetSpriteAnimation).currentRow = state
}
override fun updateSignal() {
updateK()
}
}

View File

@@ -0,0 +1,161 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.toInt
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
/**
* Implements a Nimply gate.
*
* Created by minjaesong on 2024-03-04.
*/
interface Reorientable {
/**
* Usually includes code snippet of `orientation = (orientation + 1) % 4`
*/
fun orientClockwise()
/**
* Usually includes code snippet of `orientation = (orientation - 1) % 4`
*/
fun orientAnticlockwise()
/**
* strictly 0 1 2 3. If your fixture can only be oriented in two ways, use value 0 1(normal, 90 deg) or 0 2(normal, upside-down/flipped).
*/
var orientation: Int
}
/**
* Created by minjaesong on 2024-03-04.
*/
class FixtureLogicSignalBlocker : Electric, Reorientable {
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 2),
nameFun = { Lang["ITEM_LOGIC_SIGNAL_BLOCKER"] }
)
override var orientation = 0 // 0 1 2 3
private fun setEmitterAndSink() {
clearStatus()
when (orientation) {
0 -> {
setWireSinkAt(0, 0, "digital_bit")
setWireSinkAt(0, 1, "digital_bit")
setWireEmitterAt(1, 0, "digital_bit")
}
1 -> {
setWireSinkAt(1, 0, "digital_bit")
setWireSinkAt(0, 0, "digital_bit")
setWireEmitterAt(1, 1, "digital_bit")
}
2 -> {
setWireSinkAt(1, 1, "digital_bit")
setWireSinkAt(1, 0, "digital_bit")
setWireEmitterAt(0, 1, "digital_bit")
}
3 -> {
setWireSinkAt(0, 1, "digital_bit")
setWireSinkAt(1, 1, "digital_bit")
setWireEmitterAt(0, 0, "digital_bit")
}
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
}
private fun reorient() {
(sprite as SheetSpriteAnimation).currentFrame = orientation
(spriteEmissive as SheetSpriteAnimation).currentFrame = orientation
}
override fun orientClockwise() {
orientation = (orientation + 1) fmod 4
reorient(); setEmitterAndSink(); updateK()
}
override fun orientAnticlockwise() {
orientation = (orientation - 1) fmod 4
reorient(); setEmitterAndSink(); updateK()
}
init {
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_blocker.tga")
val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_blocker_emsv.tga")
density = 1400.0
setHitboxDimension(2*TILE_SIZE, 2*TILE_SIZE, 0, 1)
makeNewSprite(TextureRegionPack(itemImage.texture, 2*TILE_SIZE, 2*TILE_SIZE)).let {
it.setRowsAndFrames(16,4)
it.delays = FloatArray(16) { Float.POSITIVE_INFINITY }
}
makeNewSpriteEmissive(TextureRegionPack(itemImage2.texture, 2*TILE_SIZE, 2*TILE_SIZE)).let {
it.setRowsAndFrames(16,4)
it.delays = FloatArray(16) { Float.POSITIVE_INFINITY }
}
setEmitterAndSink()
}
override fun reload() {
super.reload()
reorient()
setEmitterAndSink()
updateK()
}
private val I: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
1 -> getWireStateAt(1, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
3 -> getWireStateAt(0, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private val J: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
1 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
3 -> getWireStateAt(1, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private fun updateK() {
val (x, y) = when (orientation) {
0 -> 1 to 0
1 -> 1 to 1
2 -> 0 to 1
3 -> 0 to 0
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
val output = I nimply J
setWireEmissionAt(x, y, Vector2(output.toDouble(), 0.0))
// update sprite
val one = isSignalHigh(0, 0)
val two = isSignalHigh(1, 0)
val four = isSignalHigh(0, 1)
val eight = isSignalHigh(1, 1)
val state = one.toInt(0) or two.toInt(1) or four.toInt(2) or eight.toInt(3)
(sprite as SheetSpriteAnimation).currentRow = state
(spriteEmissive as SheetSpriteAnimation).currentRow = state
}
private infix fun Boolean.nimply(other: Boolean) = (this && !other).toInt()
override fun updateSignal() {
updateK()
}
}

View File

@@ -11,9 +11,9 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/** /**
* Created by minjaesong on 2024-03-01. * Created by minjaesong on 2024-03-01.
*/ */
class FixtureSignalBulb : Electric { class FixtureLogicSignalBulb : Electric {
@Transient override val spawnNeedsFloor = false @Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true @Transient override val spawnNeedsWall = true
constructor() : super( constructor() : super(
@@ -49,11 +49,8 @@ class FixtureSignalBulb : Electric {
(spriteEmissive as SheetSpriteAnimation).currentRow = state.toInt() (spriteEmissive as SheetSpriteAnimation).currentRow = state.toInt()
} }
override fun onSignalHigh(readFrom: BlockBoxIndex) { override fun updateImpl(delta: Float) {
light(true) super.updateImpl(delta)
} light(getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH)
override fun onSignalLow(readFrom: BlockBoxIndex) {
light(false)
} }
} }

View File

@@ -4,6 +4,8 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellCommonRes
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellCommonRes.tooltipShowing
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2 import org.dyn4j.geometry.Vector2
@@ -12,7 +14,8 @@ import org.dyn4j.geometry.Vector2
*/ */
class FixtureLogicSignalEmitter : Electric { class FixtureLogicSignalEmitter : Electric {
@Transient override val spawnNeedsFloor = false @Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super( constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 1, 1), BlockBox(BlockBox.NO_COLLISION, 1, 1),
@@ -35,7 +38,13 @@ class FixtureLogicSignalEmitter : Electric {
setWireEmissionAt(0, 0, Vector2(1.0, 0.0)) setWireEmissionAt(0, 0, Vector2(1.0, 0.0))
} }
override fun dispose() { } override fun updateSignal() {
setWireEmissionAt(0, 0, Vector2(1.0, 0.0))
}
override fun dispose() {
tooltipShowing.remove(tooltipHash)
}
companion object { companion object {
const val MASS = 1.0 const val MASS = 1.0

View File

@@ -0,0 +1,164 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.toInt
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
/**
* Implements a D-Flip Flop with extra Set/Reset pins.
*
* Created by minjaesong on 2024-03-05.
*/
class FixtureLogicSignalLatch : Electric, Reorientable {
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 3),
nameFun = { Lang["ITEM_LOGIC_SIGNAL_LATCH"] }
)
override var orientation = 0 // 0 2, where 2 is a mirror-image rather than rotation
private fun setEmitterAndSink() {
clearStatus()
when (orientation) {
0 -> {
setWireSinkAt(0, 0, "digital_bit") // D
setWireEmitterAt(1, 0, "digital_bit") // Q
setWireSinkAt(0, 1, "digital_bit") // CLK
setWireSinkAt(0, 2, "digital_bit") // S
setWireSinkAt(1, 2, "digital_bit") // R
}
2 -> {
setWireSinkAt(1, 0, "digital_bit") // D
setWireEmitterAt(0, 0, "digital_bit") // Q
setWireSinkAt(1, 1, "digital_bit") // CLK
setWireSinkAt(1, 2, "digital_bit") // S
setWireSinkAt(0, 2, "digital_bit") // R
}
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
}
private fun reorient() {
(sprite as SheetSpriteAnimation).currentFrame = orientation / 2
(spriteEmissive as SheetSpriteAnimation).currentFrame = orientation / 2
}
override fun orientClockwise() {
orientation = (orientation + 2) fmod 4
reorient(); setEmitterAndSink(); updateQ()
}
override fun orientAnticlockwise() {
orientation = (orientation - 2) fmod 4
reorient(); setEmitterAndSink(); updateQ()
}
init {
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_latch.tga")
val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_latch_emsv.tga")
density = 1400.0
setHitboxDimension(2*TILE_SIZE, 3*TILE_SIZE, 0, 1)
makeNewSprite(TextureRegionPack(itemImage.texture, 2*TILE_SIZE, 3*TILE_SIZE)).let {
it.setRowsAndFrames(32,2)
it.delays = FloatArray(32) { Float.POSITIVE_INFINITY }
}
makeNewSpriteEmissive(TextureRegionPack(itemImage2.texture, 2*TILE_SIZE, 3*TILE_SIZE)).let {
it.setRowsAndFrames(32,2)
it.delays = FloatArray(32) { Float.POSITIVE_INFINITY }
}
setEmitterAndSink()
}
override fun reload() {
super.reload()
reorient()
setEmitterAndSink()
updateQ()
}
private var internalState = false
private val D: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private var CLK0old: Boolean = false
private val CLK0: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private val S: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 2, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 2, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private val R: Boolean
get() = when (orientation) {
0 -> getWireStateAt(1, 2, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(0, 2, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private fun updateQ() {
val (x, y) = when (orientation) {
0 -> 1 to 0
2 -> 0 to 0
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
// "capture" the input pin states
val D = this.D
val CLK0 = this.CLK0
val CLK = (!CLK0old && CLK0) // only TRUE on rising edge
val S = this.S
val R = this.R
// force set internal state
if (S && !R) internalState = true // Set
else if (!S && R) internalState = false // Reset
else if (S && R) internalState = !internalState // Toggle
else if (CLK) internalState = D
// if force set pin is not high and clock is pulsed, make transition; stay otherwise
val output = internalState
setWireEmissionAt(x, y, Vector2(output.toInt().toDouble(), 0.0))
CLK0old = CLK0
// update sprite
val one = isSignalHigh(0, 0)
val two = isSignalHigh(1, 0)
val four = isSignalHigh(0, 1) or isSignalHigh(1, 1)
val eight = isSignalHigh(0, 2)
val sixteen = isSignalHigh(1, 2)
val state = one.toInt(0) or two.toInt(1) or four.toInt(2) or eight.toInt(3) or sixteen.toInt(4)
(sprite as SheetSpriteAnimation).currentRow = state
(spriteEmissive as SheetSpriteAnimation).currentRow = state
}
override fun updateSignal() {
updateQ()
}
}

View File

@@ -0,0 +1,116 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.TerrarumAppConfiguration
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.toInt
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
/**
* Created by minjaesong on 2024-03-08.
*/
class FixtureLogicSignalRepeaterHorz : Electric, Reorientable {
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 2, 1),
nameFun = { Lang["ITEM_LOGIC_SIGNAL_REPEATER"] }
)
override var orientation = 0 // 0 2, where 2 is a mirror-image rather than rotation
private fun setEmitterAndSink() {
clearStatus()
when (orientation) {
0 -> {
setWireSinkAt(0, 0, "digital_bit") // D
setWireEmitterAt(1, 0, "digital_bit") // Q
}
2 -> {
setWireSinkAt(1, 0, "digital_bit") // D
setWireEmitterAt(0, 0, "digital_bit") // Q
}
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
}
private fun reorient() {
(sprite as SheetSpriteAnimation).currentFrame = orientation / 2
(spriteEmissive as SheetSpriteAnimation).currentFrame = orientation / 2
}
override fun orientClockwise() {
orientation = (orientation + 2) fmod 4
reorient(); setEmitterAndSink(); updateQ()
}
override fun orientAnticlockwise() {
orientation = (orientation - 2) fmod 4
reorient(); setEmitterAndSink(); updateQ()
}
init {
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_repeater.tga")
val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_repeater_emsv.tga")
density = 1400.0
setHitboxDimension(2*TILE_SIZE, 1*TILE_SIZE, 0, 1)
makeNewSprite(TextureRegionPack(itemImage.texture, 2*TILE_SIZE, 1*TILE_SIZE)).let {
it.setRowsAndFrames(4,2)
it.delays = FloatArray(4) { Float.POSITIVE_INFINITY }
}
makeNewSpriteEmissive(TextureRegionPack(itemImage2.texture, 2*TILE_SIZE, 1*TILE_SIZE)).let {
it.setRowsAndFrames(4,2)
it.delays = FloatArray(4) { Float.POSITIVE_INFINITY }
}
setEmitterAndSink()
}
override fun reload() {
super.reload()
reorient()
setEmitterAndSink()
updateQ()
}
private val D: Boolean
get() = when (orientation) {
0 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
2 -> getWireStateAt(1, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
private fun updateQ() {
val (x, y) = when (orientation) {
0 -> 1 to 0
2 -> 0 to 0
else -> throw IllegalStateException("Orientation not in range ($orientation)")
}
// "capture" the input pin states
val D = this.D
setWireEmissionAt(x, y, Vector2(D.toInt().toDouble(), 0.0))
// update sprite
val one = isSignalHigh(0, 0)
val two = isSignalHigh(1, 0)
val state = one.toInt(0) or two.toInt(1)
(sprite as SheetSpriteAnimation).currentRow = state
(spriteEmissive as SheetSpriteAnimation).currentRow = state
}
override fun updateSignal() {
updateQ()
}
}

View File

@@ -0,0 +1,87 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.toInt
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2024-03-16.
*/
class FixtureLogicSignalSevenSeg : Electric {
@Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 4, 4),
nameFun = { Lang["ITEM_LOGIC_SIGNAL_DISPLAY"] }
)
@Transient private val actorBlocks = arrayOf(
arrayOf(null, Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, null),
arrayOf(null, Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, null),
arrayOf(null, Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, null),
arrayOf(Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION),
)
override fun placeActorBlocks() {
forEachBlockbox { x, y, ox, oy ->
val tile = actorBlocks[oy][ox]
if (tile != null) {
world!!.setTileTerrain(x, y, tile, true)
}
}
}
init {
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/sevenseg.tga")
val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/sevenseg.tga")
density = 1400.0
setHitboxDimension(4*TILE_SIZE, 4*TILE_SIZE, 0, 1)
makeNewSprite(TextureRegionPack(itemImage.texture, 4*TILE_SIZE, 4*TILE_SIZE)).let {
it.setRowsAndFrames(2,16)
it.delays = FloatArray(16) { Float.POSITIVE_INFINITY }
}
makeNewSpriteEmissive(TextureRegionPack(itemImage2.texture, 4*TILE_SIZE, 4*TILE_SIZE)).let {
it.setRowsAndFrames(2,416)
it.delays = FloatArray(16) { Float.POSITIVE_INFINITY }
}
(sprite as SheetSpriteAnimation).currentRow = 0
(spriteEmissive as SheetSpriteAnimation).currentRow = 1
setWireSinkAt(0, 3, "digital_bit")
setWireSinkAt(1, 3, "digital_bit")
setWireSinkAt(2, 3, "digital_bit")
setWireSinkAt(3, 3, "digital_bit")
}
override fun reload() {
super.reload()
setWireSinkAt(0, 3, "digital_bit")
setWireSinkAt(1, 3, "digital_bit")
setWireSinkAt(2, 3, "digital_bit")
setWireSinkAt(3, 3, "digital_bit")
updateK()
}
override fun updateSignal() {
updateK()
}
private fun updateK() {
val state = isSignalHigh(0, 3).toInt(0) or
isSignalHigh(1, 3).toInt(1) or
isSignalHigh(2, 3).toInt(2) or
isSignalHigh(3, 3).toInt(3)
(sprite as SheetSpriteAnimation).currentFrame = state
(spriteEmissive as SheetSpriteAnimation).currentFrame = state
}
}

View File

@@ -1,22 +1,21 @@
package net.torvald.terrarum.modulebasegame.gameactors package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.spriteanimation.SheetSpriteAnimation import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.App
import net.torvald.terrarum.TerrarumAppConfiguration import net.torvald.terrarum.TerrarumAppConfiguration
import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.toInt import net.torvald.terrarum.toInt
import net.torvald.terrarum.ui.MouseLatch
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2 import org.dyn4j.geometry.Vector2
/** /**
* Created by minjaesong on 2024-03-01. * Created by minjaesong on 2024-03-01.
*/ */
class FixtureSignalSwitchManual : Electric { class FixtureLogicSignalSwitchManual : Electric {
@Transient override val spawnNeedsFloor = false @Transient override val spawnNeedsFloor = true
@Transient override val spawnNeedsWall = true
constructor() : super( constructor() : super(
BlockBox(BlockBox.NO_COLLISION, 1, 1), BlockBox(BlockBox.NO_COLLISION, 1, 1),
@@ -28,6 +27,7 @@ class FixtureSignalSwitchManual : Electric {
init { init {
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_switch.tga") val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_switch.tga")
val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_switch_glow.tga")
density = 1400.0 density = 1400.0
setHitboxDimension(TerrarumAppConfiguration.TILE_SIZE, TerrarumAppConfiguration.TILE_SIZE, 0, 1) setHitboxDimension(TerrarumAppConfiguration.TILE_SIZE, TerrarumAppConfiguration.TILE_SIZE, 0, 1)
@@ -37,6 +37,11 @@ class FixtureSignalSwitchManual : Electric {
it.currentFrame = variant it.currentFrame = variant
it.delays = floatArrayOf(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY) it.delays = floatArrayOf(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
} }
makeNewSpriteGlow(TextureRegionPack(itemImage2.texture, TerrarumAppConfiguration.TILE_SIZE, TerrarumAppConfiguration.TILE_SIZE)).let {
it.setRowsAndFrames(2,8)
it.currentFrame = variant
it.delays = floatArrayOf(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
}
actorValue[AVKey.BASEMASS] = FixtureLogicSignalEmitter.MASS actorValue[AVKey.BASEMASS] = FixtureLogicSignalEmitter.MASS
@@ -53,19 +58,9 @@ class FixtureSignalSwitchManual : Electric {
setWireEmissionAt(0, 0, Vector2(state.toInt().toDouble(), 0.0)) setWireEmissionAt(0, 0, Vector2(state.toInt().toDouble(), 0.0))
} }
@Transient private val clickLatch = MouseLatch(listOf(App.getConfigInt("config_mousesecondary"))) override fun onInteract(mx: Double, my: Double) {
state = !state
override fun updateImpl(delta: Float) { (sprite as SheetSpriteAnimation).currentRow = state.toInt()
super.updateImpl(delta) setWireEmissionAt(0, 0, Vector2(state.toInt().toDouble(), 0.0))
// right click
if (mouseUp) {
clickLatch.latch {
state = !state
(sprite as SheetSpriteAnimation).currentRow = state.toInt()
setWireEmissionAt(0, 0, Vector2(state.toInt().toDouble(), 0.0))
}
}
} }
} }

View File

@@ -65,42 +65,36 @@ class FixtureMusicalTurntable : Electric, PlaysMusic {
internal var disc: ItemID? = null internal var disc: ItemID? = null
@Transient private val clickLatch = MouseLatch(listOf(App.getConfigInt("config_mousesecondary")))
override val canBeDespawned: Boolean override val canBeDespawned: Boolean
get() = disc == null get() = disc == null
override fun updateImpl(delta: Float) { override fun onInteract(mx: Double, my: Double) {
super.updateImpl(delta) if (disc == null) {
if (INGAME.actorNowPlaying != null) {
val itemOnGrip =
INGAME.actorNowPlaying!!.inventory.itemEquipped.get(GameItem.EquipPosition.HAND_GRIP)
val itemProp = ItemCodex[itemOnGrip]
// right click if (itemProp?.hasAllTagOf("MUSIC", "PHONO") == true) {
if (mouseUp) { disc = itemOnGrip
clickLatch.latch { INGAME.actorNowPlaying!!.removeItem(itemOnGrip!!)
if (disc == null) { playDisc()
if (INGAME.actorNowPlaying != null) {
val itemOnGrip =
INGAME.actorNowPlaying!!.inventory.itemEquipped.get(GameItem.EquipPosition.HAND_GRIP)
val itemProp = ItemCodex[itemOnGrip]
if (itemProp?.hasAllTagOf("MUSIC", "PHONO") == true) {
disc = itemOnGrip
INGAME.actorNowPlaying!!.removeItem(itemOnGrip!!)
playDisc()
}
}
}
else {
stopGracefully()
PickaxeCore.dropItem(
disc!!,
intTilewiseHitbox.canonicalX.toInt(),
intTilewiseHitbox.canonicalY.toInt()
)
disc = null
} }
} }
} }
else {
stopGracefully()
PickaxeCore.dropItem(
disc!!,
intTilewiseHitbox.canonicalX.toInt(),
intTilewiseHitbox.canonicalY.toInt()
)
disc = null
}
}
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
// supress the normal background music playback // supress the normal background music playback
if (musicIsPlaying && !flagDespawn) { if (musicIsPlaying && !flagDespawn) {
@@ -172,6 +166,8 @@ class FixtureMusicalTurntable : Electric, PlaysMusic {
super.reload() super.reload()
// cannot resume playback, just stop the music // cannot resume playback, just stop the music
musicNowPlaying = null musicNowPlaying = null
// update sprite
(sprite as SheetSpriteAnimation).currentRow = (disc == null).toInt()
} }
override fun dispose() { override fun dispose() {

View File

@@ -1,10 +1,8 @@
package net.torvald.terrarum.modulebasegame.gameactors package net.torvald.terrarum.modulebasegame.gameactors
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.gdx.graphics.Cvec import net.torvald.gdx.graphics.Cvec
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import net.torvald.spriteanimation.SheetSpriteAnimation import net.torvald.spriteanimation.SheetSpriteAnimation
@@ -18,6 +16,7 @@ import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.Hitbox import net.torvald.terrarum.gameactors.Hitbox
import net.torvald.terrarum.gameactors.Lightbox import net.torvald.terrarum.gameactors.Lightbox
import net.torvald.terrarum.gamecontroller.KeyToggler import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameparticles.ParticleVanishingSprite import net.torvald.terrarum.gameparticles.ParticleVanishingSprite
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.TerrarumIngame
@@ -25,26 +24,102 @@ import net.torvald.terrarum.modulebasegame.ui.UISmelterBasic
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/** /**
* No GUI yet! * Created by minjaesong on 2024-03-09.
* */
interface SmelterItemStatus {
fun set(itm: ItemID, qty: Long)
fun changeCount(delta: Long)
fun nullify()
fun isNull(): Boolean
fun isNotNull(): Boolean = !isNull()
val itm: ItemID?
val qty: Long?
}
/**
* Created by minjaesong on 2023-12-04. * Created by minjaesong on 2023-12-04.
*/ */
class FixtureSmelterBasic : FixtureBase, CraftingStation { class FixtureSmelterBasic : FixtureBase {
var fuelCaloriesNow = 0.0 // arbitrary number, may as well be watts or joules var fuelCaloriesNow = 0.0 // arbitrary number, may as well be watts or joules
var fuelCaloriesMax: Double? = null var fuelCaloriesMax: Double? = null
var temperature = 0f // 0f..1f var temperature = 0f // 0f..1f
var progress = 0f // 0f..1f var progress = 0f // 0f..1f
var oreItem: InventoryPair? = null internal var oreItem: InventoryPair? = null
var fireboxItem: InventoryPair? = null internal var fireboxItem: InventoryPair? = null
var productItem: InventoryPair? = null internal var productItem: InventoryPair? = null
@Transient val oreItemStatus = object : SmelterItemStatus {
override fun set(itm: ItemID, qty: Long) {
if (oreItem != null) oreItem!!.set(itm, qty)
else oreItem = InventoryPair(itm, qty)
}
override fun changeCount(delta: Long) {
oreItem!!.qty += delta
if (oreItem!!.qty <= 0L) {
oreItem = null
}
}
override fun nullify() {
oreItem = null
}
override fun isNull(): Boolean {
return oreItem == null
}
override val itm: ItemID?
get() = oreItem?.itm
override val qty: Long?
get() = oreItem?.qty
}
@Transient val fireboxItemStatus = object : SmelterItemStatus {
override fun set(itm: ItemID, qty: Long) {
if (fireboxItem != null) fireboxItem!!.set(itm, qty)
else fireboxItem = InventoryPair(itm, qty)
}
override fun changeCount(delta: Long) {
fireboxItem!!.qty += delta
if (fireboxItem!!.qty <= 0L) {
fireboxItem = null
}
}
override fun nullify() {
fireboxItem = null
}
override fun isNull(): Boolean {
return fireboxItem == null
}
override val itm: ItemID?
get() = fireboxItem?.itm
override val qty: Long?
get() = fireboxItem?.qty
}
@Transient val productItemStatus = object : SmelterItemStatus {
override fun set(itm: ItemID, qty: Long) {
if (productItem != null) productItem!!.set(itm, qty)
else productItem = InventoryPair(itm, qty)
}
override fun changeCount(delta: Long) {
productItem!!.qty += delta
if (productItem!!.qty <= 0L) {
productItem = null
}
}
override fun nullify() {
productItem = null
}
override fun isNull(): Boolean {
return productItem == null
}
override val itm: ItemID?
get() = productItem?.itm
override val qty: Long?
get() = productItem?.qty
}
override val canBeDespawned: Boolean override val canBeDespawned: Boolean
get() = oreItem == null && fireboxItem == null && productItem == null get() = oreItem == null && fireboxItem == null && productItem == null
@Transient override val tags = listOf("basicsmelter")
init { init {
CommonResourcePool.addToLoadingList("basegame/sprites/fixtures/smelter_tall.tga") { CommonResourcePool.addToLoadingList("basegame/sprites/fixtures/smelter_tall.tga") {
TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/fixtures/smelter_tall.tga"), 48, 64) TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/fixtures/smelter_tall.tga"), 48, 64)
@@ -84,7 +159,7 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
@Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), true) @Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), true)
@Transient val light = Cvec(0.5f, 0.18f, 0f, 0f) @Transient val light = Cvec(0.5f, 0.18f, 0f, 0f)
@Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 2*TILE_SIZED, TILE_SIZED * 2, TILE_SIZED * 2), Cvec(0.5f, 0.18f, 0f, 0f))) @Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 2*TILE_SIZED, TILE_SIZED * 2, TILE_SIZED * 2), light))
@Transient private val actorBlocks = arrayOf( @Transient private val actorBlocks = arrayOf(
arrayOf(Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, null), arrayOf(Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, null),
@@ -112,27 +187,6 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
@Transient private val RNG = HQRNG() @Transient private val RNG = HQRNG()
fun changeFireboxItemCount(delta: Long) {
fireboxItem!!.qty += delta
if (fireboxItem!!.qty <= 0L) {
fireboxItem = null
}
}
fun changeOreItemCount(delta: Long) {
oreItem!!.qty += delta
if (oreItem!!.qty <= 0L) {
oreItem = null
}
}
fun changeProductItemCount(delta: Long) {
productItem!!.qty += delta
if (productItem!!.qty <= 0L) {
productItem = null
}
}
override fun drawEmissive(frameDelta: Float, batch: SpriteBatch) { override fun drawEmissive(frameDelta: Float, batch: SpriteBatch) {
if (isVisible && spriteEmissive != null) { if (isVisible && spriteEmissive != null) {
BlendMode.resolve(drawMode, batch) BlendMode.resolve(drawMode, batch)
@@ -198,7 +252,6 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
override fun updateImpl(delta: Float) { override fun updateImpl(delta: Float) {
super.updateImpl(delta) super.updateImpl(delta)
val oreItemProp = ItemCodex[oreItem?.itm]
val fuelItemProp = ItemCodex[fireboxItem?.itm] val fuelItemProp = ItemCodex[fireboxItem?.itm]
// consume fuel // consume fuel
@@ -215,7 +268,7 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
nextDelayBase = fuelItemProp.smokiness nextDelayBase = fuelItemProp.smokiness
nextDelay = (nextDelayBase * (1.0 + RNG.nextTriangularBal() * 0.1)).toFloat() nextDelay = (nextDelayBase * (1.0 + RNG.nextTriangularBal() * 0.1)).toFloat()
changeFireboxItemCount(-1) fireboxItemStatus.changeCount(-1)
} }
// no item on the slot // no item on the slot
else if (fuelCaloriesNow <= 0f && fireboxItem == null) { else if (fuelCaloriesNow <= 0f && fireboxItem == null) {
@@ -243,28 +296,30 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
(sprite as? SheetSpriteAnimation)?.delays?.set(0, Math.random().toFloat() * 0.4f + 0.1f) (sprite as? SheetSpriteAnimation)?.delays?.set(0, Math.random().toFloat() * 0.4f + 0.1f)
} }
val smeltingProduct = CraftingRecipeCodex.getSmeltingProductOf(oreItem?.itm)
// roast items // roast items
if (oreItem != null && if (oreItem != null &&
temperature > 0f && temperature > 0f &&
oreItemProp?.smeltingProduct != null && smeltingProduct != null &&
(productItem == null || oreItemProp.smeltingProduct == productItem!!.itm) (productItem == null || smeltingProduct.item == productItem!!.itm)
) { ) {
progress += temperature progress += temperature
if (progress >= CALORIES_PER_ROASTING) { if (progress >= CALORIES_PER_ROASTING) {
val smeltingProduct = oreItemProp.smeltingProduct!! val smeltingProductItem = smeltingProduct.item
// check if the item even exists // check if the item even exists
if (ItemCodex[smeltingProduct] == null) throw NullPointerException("No item prop for $smeltingProduct") if (ItemCodex[smeltingProductItem] == null) throw NullPointerException("No item prop for $smeltingProductItem")
if (productItem == null) if (productItem == null)
productItem = InventoryPair(smeltingProduct, 1L) productItem = InventoryPair(smeltingProductItem, 1L)
else else
changeProductItemCount(1) productItemStatus.changeCount(1)
// take the ore item // take the ore item
changeOreItemCount(-1) oreItemStatus.changeCount(-1)
progress = 0f progress = 0f
} }

Some files were not shown because too many files have changed in this diff Show More