mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa2172b396 | ||
|
|
f3e2fa8441 | ||
|
|
a3d132d26c | ||
|
|
a4afb0bfe9 | ||
|
|
67092d4ab9 | ||
|
|
07680592d2 | ||
|
|
844ec6bd4f | ||
|
|
c87bd182b0 | ||
|
|
6d2764933f | ||
|
|
d4672df208 | ||
|
|
4d1ea45a0f | ||
|
|
8e1c586a5c | ||
|
|
7690d3d672 | ||
|
|
8e8c206e3a | ||
|
|
d35a73c7a5 | ||
|
|
ec76eb2685 | ||
|
|
a1a6dc5801 | ||
|
|
708dccb015 | ||
|
|
4e739963d3 | ||
|
|
8bf3d9666f | ||
|
|
b856574d20 | ||
|
|
f696a54d2d | ||
|
|
ca766719d3 | ||
|
|
d027ff7d7e | ||
|
|
2785a67823 | ||
|
|
33671d6e52 | ||
|
|
7bfff29a79 | ||
|
|
aef1db49d6 | ||
|
|
09e5b175b8 | ||
|
|
37b4fa1e7b | ||
|
|
d63be072cc | ||
|
|
d22f421bc4 | ||
|
|
cb756cbf3a | ||
|
|
b24a3da2ed | ||
|
|
b0adc9efc7 | ||
|
|
c0a8118717 | ||
|
|
336dfad207 | ||
|
|
ef7199fd8b | ||
|
|
3481502c1a | ||
|
|
5b462a2559 | ||
|
|
6abb6f84ef | ||
|
|
2abc8b19b9 | ||
|
|
7c2b5468bd | ||
|
|
c829245b41 | ||
|
|
b05ae829cc | ||
|
|
8aa866f040 | ||
|
|
5a18ba4b06 | ||
|
|
707abe8c6d | ||
|
|
60eeeae759 | ||
|
|
ef2413f33d | ||
|
|
2943f4119c | ||
|
|
a298d6663b | ||
|
|
fa49874971 | ||
|
|
247cf9bd33 | ||
|
|
c6999e0794 | ||
|
|
877d26667b | ||
|
|
3e81b80bb1 | ||
|
|
47c82aba49 | ||
|
|
c627096503 | ||
|
|
9994235342 | ||
|
|
bfaa50aea4 | ||
|
|
0d09a21028 | ||
|
|
d480a735a0 | ||
|
|
2340cb7419 | ||
|
|
dbff2610ac | ||
|
|
9f399b8722 | ||
|
|
9a6f45756b | ||
|
|
bbbc5e22a5 | ||
|
|
8d3d6242d7 | ||
|
|
3182843a48 | ||
|
|
1dcdd8867a | ||
|
|
a3bf1ed3f6 | ||
|
|
10f8e4a662 | ||
|
|
bb1a45db27 | ||
|
|
5b5534bcb9 | ||
|
|
0090cc7d40 | ||
|
|
5014381cbd | ||
|
|
caf238d6df | ||
|
|
4602cb5bc1 | ||
|
|
1c39036cc8 | ||
|
|
6c224c79bf | ||
|
|
88c9bc4a27 | ||
|
|
659976b880 | ||
|
|
3959de68b1 |
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.
@@ -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"
|
||||
|
||||
# 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"
|
||||
"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"
|
||||
"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,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"
|
||||
"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"
|
||||
|
||||
# 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"
|
||||
|
||||
# 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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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,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,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,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,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,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"
|
||||
"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.
|
@@ -10,11 +10,13 @@ GetAV
|
||||
GetFaction
|
||||
GetLocale
|
||||
GetTime
|
||||
HasItem
|
||||
ImportLayerData
|
||||
ImportWorld
|
||||
Inventory
|
||||
KillActor
|
||||
LangTest
|
||||
MakeSign
|
||||
MoneyDisp
|
||||
MusicTest
|
||||
Possess
|
||||
|
||||
|
@@ -32,11 +32,30 @@
|
||||
]
|
||||
},
|
||||
"item@basegame:36": { /* wire rolling mill */
|
||||
"workbench": "basiccrafting",
|
||||
"workbench": "basiccrafting,metalworking",
|
||||
"ingredients": [
|
||||
[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 */
|
||||
"workbench": "basiccrafting",
|
||||
@@ -90,7 +109,7 @@
|
||||
"item@basegame:30": { /* turntable */
|
||||
"workbench": "basiccrafting",
|
||||
"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 */
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
17
assets/mods/basegame/crafting/masonry.json
Normal file
17
assets/mods/basegame/crafting/masonry.json
Normal 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"]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -61,5 +61,9 @@
|
||||
"item@basegame:9": { /* wire cutter */
|
||||
"workbench": "basiccrafting,metalworking",
|
||||
"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 */
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,18 @@
|
||||
[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 */
|
||||
"workbench": "wirerollingmill",
|
||||
@@ -34,11 +46,73 @@
|
||||
[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 */
|
||||
"workbench": "basiccrafting",
|
||||
"workbench": "soldering",
|
||||
"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) */
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,8 @@ id;classname;tags
|
||||
31;net.torvald.terrarum.modulebasegame.gameitems.ItemGunpowder;POWDER,EXPLOSIVE
|
||||
32;net.torvald.terrarum.modulebasegame.gameitems.ItemCherryBomb;EXPLOSIVE,THROWABLE
|
||||
33;net.torvald.terrarum.modulebasegame.gameitems.ItemTorch;FIXTURE,LIGHT
|
||||
34;net.torvald.terrarum.modulebasegame.gameitems.ItemSignalSwitchManual;FIXTURE,SIGNAL
|
||||
35;net.torvald.terrarum.modulebasegame.gameitems.ItemSignalBulb;FIXTURE,SIGNAL
|
||||
34;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalSwitchManual;FIXTURE,SIGNAL
|
||||
35;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalBulb;FIXTURE,SIGNAL
|
||||
36;net.torvald.terrarum.modulebasegame.gameitems.ItemWireRollingMill;FIXTURE,CRAFTING
|
||||
37;net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestEbony;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
|
||||
42;net.torvald.terrarum.modulebasegame.gameitems.ItemTableBirch;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
|
||||
26;net.torvald.terrarum.modulebasegame.gameitems.IngotSteel;INGOT
|
||||
112;net.torvald.terrarum.modulebasegame.gameitems.IngotCopper;INGOT
|
||||
113;net.torvald.terrarum.modulebasegame.gameitems.IngotIron;INGOT
|
||||
114;net.torvald.terrarum.modulebasegame.gameitems.ItemCoalCoke;COMBUSTIBLE
|
||||
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
|
||||
118;net.torvald.terrarum.modulebasegame.gameitems.IngotSilver;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
|
||||
128;net.torvald.terrarum.modulebasegame.gameitems.OreCopper;SMELTABLE
|
||||
129;net.torvald.terrarum.modulebasegame.gameitems.OreIron;SMELTABLE
|
||||
@@ -78,10 +96,10 @@ id;classname;tags
|
||||
163;net.torvald.terrarum.modulebasegame.gameitems.ItemSeedRosewood;SEEDLING
|
||||
|
||||
# tree logs
|
||||
168;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsOak;COMBUSTIBLE,SMELTABLE
|
||||
169;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsEbony;COMBUSTIBLE,SMELTABLE
|
||||
170;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsBirch;COMBUSTIBLE,SMELTABLE
|
||||
171;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsRosewood;COMBUSTIBLE,SMELTABLE
|
||||
168;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsOak;COMBUSTIBLE,SMELTABLE,LOGS
|
||||
169;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsEbony;COMBUSTIBLE,SMELTABLE,LOGS
|
||||
170;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsBirch;COMBUSTIBLE,SMELTABLE,LOGS
|
||||
171;net.torvald.terrarum.modulebasegame.gameitems.ItemLogsRosewood;COMBUSTIBLE,SMELTABLE,LOGS
|
||||
|
||||
|
||||
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak;FIXTURE
|
||||
@@ -104,16 +122,21 @@ id;classname;tags
|
||||
32777;net.torvald.terrarum.modulebasegame.gameitems.MusicDisc09;MUSIC,PHONO
|
||||
|
||||
# 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
|
||||
# preferably autogenerated
|
||||
# 10000h..100FFh : Fluid type 0 (water) x container type 0..255
|
||||
# 10100h..101FFh : Fluid type 1 (lava) x container type 0..255
|
||||
# 10200h..102FFh : Fluid type 2 (crude oil) x container type 0..255
|
||||
# 10300h..103FFh : Fluid type 3 (petroleum) x container type 0..255
|
||||
# 10400h..104FFh : Fluid type 4 (compressed air) x container type 0..255
|
||||
# 10500h..105FFh : Fluid type 5 (steam) x container type 0..255
|
||||
# 100000h..1000FFh : Fluid type 0 (water) x container type 0..255
|
||||
# 100100h..1001FFh : Fluid type 1 (lava) x container type 0..255
|
||||
# 100200h..1002FFh : Fluid type 2 (crude oil) x container type 0..255
|
||||
# 100300h..1003FFh : Fluid type 3 (petroleum) x container type 0..255
|
||||
# 100400h..1004FFh : Fluid type 4 (compressed air) 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
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"CONTEXT_ENGRAVER_TEXT": "Text",
|
||||
"CONTEXT_GENERATOR_SEED": "Seed",
|
||||
"CONTEXT_ITEM_FIXTURES": "Fixtures",
|
||||
"CONTEXT_ITEM_MAP": "Map",
|
||||
@@ -18,7 +19,7 @@
|
||||
"GAME_ACTION_QUICKSEL": "Quick Select",
|
||||
"GAME_ACTION_SELECT_SLOT": "Select Slot",
|
||||
"GAME_ACTION_TELEPORT": "Teleport",
|
||||
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
|
||||
"GAME_CRAFTABLE_ITEMS": "Recipes",
|
||||
"GAME_CRAFTING": "Crafting",
|
||||
"GAME_INVENTORY_BLOCKS": "Blocks",
|
||||
"GAME_INVENTORY_FAVORITES": "Favorites",
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
"TOOLTIP_wire@basegame:8192": "Carries signals",
|
||||
"TOOLTIP_wire@basegame:8193": "Carries signals",
|
||||
"TOOLTIP_wire@basegame:8194": "Carries signals",
|
||||
"TOOLTIP_wire@basegame:8196": "Carries power",
|
||||
"TOOLTIP_wire@basegame:8197": "Carries power",
|
||||
"TOOLTIP_wire@basegame:8198": "Carries information",
|
||||
"TOOLTIP_wire@basegame:8195": "Carries signals",
|
||||
"TOOLTIP_wire@basegame:8196": "Carries signals",
|
||||
"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:2": "Breaks rocks",
|
||||
@@ -19,8 +21,7 @@
|
||||
"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:39": "“I am sworn to keep your burdens.”", /* skyrim/lydia reference */
|
||||
"TOOLTIP_item@basegame:8": "Emits a signal",
|
||||
"TOOLTIP_item@basegame:9": "An electricians’ best friend",
|
||||
"TOOLTIP_item@basegame:9": "Push {MOUSE:config_mousesecondary} to change the colour",
|
||||
"TOOLTIP_item@basegame:10": "“Who needs a Book and Quill when you’ve got this?”", /* a jab on the Minecraft item Book and Quill */
|
||||
"TOOLTIP_item@basegame:11": "Tells what day it is",
|
||||
"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:29": "A coal lookalike that burns just as well and is renewable",
|
||||
"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: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"
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
{
|
||||
"ITEM_ALLOYING_FURNACE": "Alloying Furnace",
|
||||
"ITEM_CALENDAR": "Calendar",
|
||||
"ITEM_CHARCOAL": "Charcoal",
|
||||
"ITEM_CHERRY_BOMB": "Bomb",
|
||||
"ITEM_COAL_COKE": "Coal Coke",
|
||||
"ITEM_COPPER_BULB": "Copper Bulb",
|
||||
"ITEM_COPPER_SIGN": "Copper Sign",
|
||||
"ITEM_DOOR_OAK": "Oak Door",
|
||||
"ITEM_DOOR_EBONY": "Ebony Door",
|
||||
"ITEM_DOOR_BIRCH": "Birch Door",
|
||||
"ITEM_DOOR_ROSEWOOD": "Rosewood Door",
|
||||
"ITEM_ELECTRIC_WORKBENCH": "Electric Workbench",
|
||||
"ITEM_ENGRAVING_WORKBENCH": "Engraving Workbench",
|
||||
"ITEM_FURNACE_AND_ANVIL": "Furnace and Anvil",
|
||||
"ITEM_GEM_RUBY": "Raw Ruby",
|
||||
"ITEM_GEM_EMERALD": "Raw Emerald",
|
||||
@@ -37,12 +41,18 @@
|
||||
"ITEM_INGOT_TIN": "Tin Ingot",
|
||||
"ITEM_INGOT_ZINC": "Zinc Ingot",
|
||||
"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_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_LOGS_BIRCH": "Birch Logs",
|
||||
"ITEM_LOGS_EBONY": "Ebony Logs",
|
||||
"ITEM_LOGS_OAK": "Oak Logs",
|
||||
"ITEM_LOGS_ROSEWOOD": "Rosewood Logs",
|
||||
"ITEM_MULTIMETER": "Multimeter",
|
||||
"ITEM_NITRE": "Nitre",
|
||||
"ITEM_ORE_CASSITERITE": "Tin Ore",
|
||||
"ITEM_ORE_COAL": "Coal",
|
||||
@@ -65,6 +75,7 @@
|
||||
"ITEM_SLEDGEHAMMER_COPPER": "Copper Sledgehammer",
|
||||
"ITEM_SLEDGEHAMMER_IRON": "Iron Sledgehammer",
|
||||
"ITEM_SLEDGEHAMMER_STEEL": "Steel Sledgehammer",
|
||||
"ITEM_SOLDERING_WIRE": "Soldering Wire",
|
||||
"ITEM_SMELTER_SMALL": "Small Smelter",
|
||||
"ITEM_STORAGE_CHEST": "Storage Chest",
|
||||
"ITEM_TABLE_OAK": "Oak Table",
|
||||
@@ -81,7 +92,8 @@
|
||||
"ITEM_WOODEN_MALLET": "Wooden Mallet",
|
||||
"ITEM_WORKBENCH": "Workbench",
|
||||
"ITEM_WORLD_PORTAL": "Teleportation Station",
|
||||
|
||||
"ITEM_WRENCH": "Wrench",
|
||||
/* below are placeholders; please do not translate */
|
||||
"ACTORBLOCK_ALLOW_MOVE_DOWN": "Urist Arôlcustith",
|
||||
"ACTORBLOCK_FULL_COLLISION": "Urist Berdanrifot",
|
||||
"ACTORBLOCK_NO_COLLISION": "Urist Zafal",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"CONTEXT_ENGRAVER_TEXT": "문구",
|
||||
"CONTEXT_GENERATOR_SEED": "시드",
|
||||
"CONTEXT_ITEM_FIXTURES": "기구",
|
||||
"CONTEXT_ITEM_MAP": "지도",
|
||||
@@ -17,7 +18,7 @@
|
||||
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
||||
"GAME_ACTION_SELECT_SLOT": "슬롯 선택",
|
||||
"GAME_ACTION_TELEPORT": "텔레포트하기",
|
||||
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
||||
"GAME_CRAFTABLE_ITEMS": "제작 레시피",
|
||||
"GAME_CRAFTING": "제작",
|
||||
"GAME_INVENTORY_BLOCKS": "블록",
|
||||
"GAME_INVENTORY_FAVORITES": "즐겨찾기",
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
"TOOLTIP_wire@basegame:8192": "신호를 전달합니다",
|
||||
"TOOLTIP_wire@basegame:8193": "신호를 전달합니다",
|
||||
"TOOLTIP_wire@basegame:8194": "신호를 전달합니다",
|
||||
"TOOLTIP_wire@basegame:8196": "전력을 전달합니다",
|
||||
"TOOLTIP_wire@basegame:8197": "전력을 전달합니다",
|
||||
"TOOLTIP_wire@basegame:8198": "정보를 전달합니다",
|
||||
"TOOLTIP_wire@basegame:8195": "신호를 전달합니다",
|
||||
"TOOLTIP_wire@basegame:1": "전력을 전달합니다",
|
||||
"TOOLTIP_wire@basegame:2": "전력을 전달합니다",
|
||||
"TOOLTIP_wire@basegame:16": "정보를 전달합니다",
|
||||
|
||||
"TOOLTIP_item@basegame:1": "돌을 부숩니다",
|
||||
"TOOLTIP_item@basegame:2": "돌을 부숩니다",
|
||||
@@ -19,8 +20,7 @@
|
||||
"TOOLTIP_item@basegame:37": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */
|
||||
"TOOLTIP_item@basegame:38": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */
|
||||
"TOOLTIP_item@basegame:39": "“짐을 맡아두기로 한 몸이니까요.”", /* skyrim/lydia reference */
|
||||
"TOOLTIP_item@basegame:8": "신호를 만들어냅니다",
|
||||
"TOOLTIP_item@basegame:9": "전기공의 친한 친구",
|
||||
"TOOLTIP_item@basegame:9": "{MOUSE:config_mousesecondary} 버튼을 눌러 색깔 변경",
|
||||
"TOOLTIP_item@basegame:10": "“이게 있는데 책과 깃펜이 왜 필요하죠?”", /* a jab on the Minecraft item Book and Quill */
|
||||
"TOOLTIP_item@basegame:11": "오늘이 무슨 날인지 알려줍니다",
|
||||
"TOOLTIP_item@basegame:12": "벽을 부숩니다",
|
||||
@@ -42,8 +42,19 @@
|
||||
"TOOLTIP_item@basegame:28": "음악 자판기입이다 (무료 플레이)",
|
||||
"TOOLTIP_item@basegame:29": "석탄과 비슷하고 똑같이 잘 타지만 재생 가능합니다",
|
||||
"TOOLTIP_item@basegame:36": "금속 주괴를 사용해 철사를 뽑아냅니다",
|
||||
"TOOLTIP_item@basegame:47": "기기의 방향을 바꿉니다",
|
||||
"TOOLTIP_item@basegame:48": "두 금속 괴를 녹여 합금을 만듭니다",
|
||||
"TOOLTIP_item@basegame:50": "전자 작업대에서 사용하세요",
|
||||
|
||||
"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": "들어오는 신호의 합을 구합니다"
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
{
|
||||
"ITEM_ALLOYING_FURNACE": "합금 화로",
|
||||
"ITEM_CALENDAR": "달력",
|
||||
"ITEM_CHARCOAL": "목탄",
|
||||
"ITEM_CHERRY_BOMB": "폭탄",
|
||||
"ITEM_COAL_COKE": "코크스",
|
||||
"ITEM_COPPER_BULB": "구리 전구",
|
||||
"ITEM_COPPER_SIGN": "구리 간판",
|
||||
"ITEM_DOOR_OAK": "나무 문",
|
||||
"ITEM_DOOR_EBONY": "흑단 문",
|
||||
"ITEM_DOOR_BIRCH": "백단 문",
|
||||
"ITEM_DOOR_ROSEWOOD": "자단 문",
|
||||
"ITEM_ELECTRIC_WORKBENCH": "전기 작업대",
|
||||
"ITEM_ENGRAVING_WORKBENCH": "조각 작업대",
|
||||
"ITEM_FURNACE_AND_ANVIL": "화로와 모루",
|
||||
"ITEM_GEM_RUBY": "홍옥석",
|
||||
"ITEM_GEM_EMERALD": "취옥석",
|
||||
@@ -32,17 +36,23 @@
|
||||
"ITEM_INGOT_ROSEGOLD": "분홍금괴",
|
||||
"ITEM_INGOT_SILVER": "은괴",
|
||||
"ITEM_INGOT_SILVER_BILLON": "은동괴",
|
||||
"ITEM_INGOT_SOLDER": "땜납",
|
||||
"ITEM_INGOT_SOLDER": "막대납",
|
||||
"ITEM_INGOT_STEEL": "강철괴",
|
||||
"ITEM_INGOT_TIN": "주석괴",
|
||||
"ITEM_INGOT_ZINC": "아연괴",
|
||||
"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_LOGS_BIRCH": "백단 통나무",
|
||||
"ITEM_LOGS_EBONY": "흑단 통나무",
|
||||
"ITEM_LOGS_OAK": "통나무",
|
||||
"ITEM_LOGS_ROSEWOOD": "자단 통나무",
|
||||
"ITEM_MULTIMETER": "멀티미터",
|
||||
"ITEM_NITRE": "초석",
|
||||
"ITEM_ORE_CASSITERITE": "주석석",
|
||||
"ITEM_ORE_COAL": "석탄",
|
||||
@@ -65,6 +75,7 @@
|
||||
"ITEM_SLEDGEHAMMER_COPPER": "구리 해머",
|
||||
"ITEM_SLEDGEHAMMER_IRON": "철 해머",
|
||||
"ITEM_SLEDGEHAMMER_STEEL": "강철 해머",
|
||||
"ITEM_SOLDERING_WIRE": "실납",
|
||||
"ITEM_SMELTER_SMALL": "소형 고로",
|
||||
"ITEM_STORAGE_CHEST": "보관상자",
|
||||
"ITEM_TABLE_OAK": "나무 탁자",
|
||||
@@ -80,5 +91,6 @@
|
||||
"ITEM_WOOD_STICK": "막대기",
|
||||
"ITEM_WOODEN_MALLET": "나무 망치",
|
||||
"ITEM_WORKBENCH": "작업대",
|
||||
"ITEM_WORLD_PORTAL": "텔레포트 스테이션"
|
||||
"ITEM_WORLD_PORTAL": "텔레포트 스테이션",
|
||||
"ITEM_WRENCH": "렌치"
|
||||
}
|
||||
@@ -44,10 +44,10 @@ package=net.torvald.terrarum.modulebasegame
|
||||
entrypoint=net.torvald.terrarum.modulebasegame.EntryPoint
|
||||
|
||||
# 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/)
|
||||
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";
|
||||
# Due to security reasons, loading an arbitrary JAR is not allowed.
|
||||
|
||||
27
assets/mods/basegame/smelting/alloys.json
Normal file
27
assets/mods/basegame/smelting/alloys.json
Normal 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"]
|
||||
}
|
||||
}
|
||||
48
assets/mods/basegame/smelting/single_item.json
Normal file
48
assets/mods/basegame/smelting/single_item.json
Normal 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"]
|
||||
}
|
||||
}
|
||||
BIN
assets/mods/basegame/sprites/fixtures/alloying_furnace.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/alloying_furnace.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/alloying_furnace_emsv.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/alloying_furnace_emsv.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/electric_workbench.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/electric_workbench.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/engraving_workbench.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/engraving_workbench.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/sevenseg.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/sevenseg.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_adder.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_adder.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_adder_emsv.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_adder_emsv.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_blocker.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_blocker.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_blocker_emsv.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_blocker_emsv.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_latch.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_latch.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_latch_emsv.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_latch_emsv.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_repeater.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_repeater.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_repeater_emsv.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_repeater_emsv.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/signal_switch_glow.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/signal_switch_glow.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/text_sign_glass_copper.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/text_sign_glass_copper.tga
LFS
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/mods/basegame/wires/1.tga
LFS
Normal file
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.
9
assets/mods/basegame/wires/decayconsts.csv
Normal file
9
assets/mods/basegame/wires/decayconsts.csv
Normal 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
|
||||
|
||||
|
Binary file not shown.
5
assets/mods/basegame/wires/wireports.csv
Normal file
5
assets/mods/basegame/wires/wireports.csv
Normal 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
|
||||
|
@@ -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"
|
||||
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"
|
||||
#8195;8195;WIRE_BUNDLE;signal;digital_3bits;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,0,0;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"
|
||||
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"
|
||||
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_PURPLE;signal;digital_bit;3;N/A;N/A;net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire;basegame.items,4,4;1;"SIGNALWIRE"
|
||||
|
||||
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)
|
||||
|
||||
|
@@ -3,8 +3,8 @@ description=Simple music player widget
|
||||
author=CuriousTo\uA75Bvald
|
||||
package=net.torvald.terrarum.musicplayer
|
||||
entrypoint=net.torvald.terrarum.musicplayer.EntryPoint
|
||||
releasedate=2024-03-03
|
||||
version=1.0.1
|
||||
releasedate=2024-03-28
|
||||
version=1.0.2
|
||||
jar=MusicPlayer.jar
|
||||
jarhash=53248a70a8cbfbcdd76e11549a132400305e91785ff98af514e68e8cafacdc19
|
||||
dependency=basegame 0.4.1
|
||||
jarhash=8ab074e9dc6312ea4d3f6f500e362afb65001d3770f4f8da1d9f2e47cb294de0
|
||||
dependency=basegame 0.4.2+
|
||||
|
||||
@@ -70,16 +70,11 @@ public class App implements ApplicationListener {
|
||||
public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG;
|
||||
|
||||
public static final String 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 + ")"));
|
||||
return TerrarumAppConfiguration.INSTANCE.getVERSION_STRING();
|
||||
}
|
||||
|
||||
public static final String getVERSION_STRING_WITHOUT_SNAPSHOT() {
|
||||
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) +
|
||||
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG);
|
||||
return TerrarumAppConfiguration.INSTANCE.getVERSION_STRING_WITHOUT_SNAPSHOT();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1731,7 +1726,7 @@ public class App implements ApplicationListener {
|
||||
return DefaultConfig.INSTANCE.getHashMap();
|
||||
}
|
||||
|
||||
private static Object getConfigMaster(String key1) {
|
||||
public static Object getConfigMaster(String key1) {
|
||||
String key = key1.toLowerCase();
|
||||
|
||||
Object config;
|
||||
|
||||
@@ -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 playerDisk: VirtualDisk; internal set
|
||||
@@ -186,7 +187,6 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
|
||||
blockMarkingActor.let {
|
||||
it.unsetGhost()
|
||||
it.setGhostColourNone()
|
||||
}
|
||||
|
||||
gameInitialised = true
|
||||
@@ -231,7 +231,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
actorContainerInactive.forEach { it.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> {
|
||||
val outList = ArrayList<ActorWithBody>()
|
||||
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) {}
|
||||
return outList
|
||||
|
||||
@@ -14,6 +14,7 @@ import net.torvald.terrarum.blockproperties.OreCodex
|
||||
import net.torvald.terrarum.blockproperties.WireCodex
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.gamecontroller.IME
|
||||
import net.torvald.terrarum.gameitems.FixtureInteractionBlocked
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.itemproperties.CraftingCodex
|
||||
@@ -564,11 +565,13 @@ object ModMgr {
|
||||
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(
|
||||
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 baseToolSize: Double? = null
|
||||
override var inventoryCategory = if (isWall) Category.WALL else Category.BLOCK
|
||||
@@ -844,11 +847,16 @@ object ModMgr {
|
||||
|
||||
object GameCraftingRecipeLoader {
|
||||
const val recipePath = "crafting/"
|
||||
const val smeltingPath = "smelting/"
|
||||
|
||||
@JvmStatic operator fun invoke(module: String) {
|
||||
getFile(module, recipePath).listFiles { it: File -> it.name.lowercase().endsWith(".json") }?.forEach { jsonFile ->
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@ object ReferencingRanges {
|
||||
val ITEMS_DYNAMIC = 0x10_0000..0x0FFF_FFFF // 267 386 880 pseudo-items
|
||||
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.
|
||||
// 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.
|
||||
val ACTORS_WIRES = 0x7FFF_C000..0x7FFF_EFFF // Rendered front--wires
|
||||
val ACTORS_WIRES_HELPER = 0x7FFF_F000..0x7FFF_FEFF // Rendered overlay--wiring port icons and logic gates
|
||||
val ACTORS_WIRE_PORTS = 0x7FFF_8000..0x7FFF_BEFF // Rendered front--wires
|
||||
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!
|
||||
|
||||
|
||||
@@ -477,7 +477,8 @@ fun blendMul(batch: SpriteBatch) {
|
||||
|
||||
fun blendAlphaMask(batch: SpriteBatch) {
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,13 +69,29 @@ basegame
|
||||
* 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.1: 2278
|
||||
// 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.4.0: 3631
|
||||
// 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 = ForcedSnapshot("24w07d") // for snapshot release
|
||||
@@ -83,6 +99,70 @@ basegame
|
||||
|
||||
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 //
|
||||
// MAKE SURE THESE VALUES ARE UNIQUE IN THE SOURCE CODE //
|
||||
|
||||
@@ -350,7 +350,7 @@ object TerrarumPostProcessor : Disposable {
|
||||
private val defaultResStr = "Ingame UI Area"
|
||||
private val currentResStr = "${App.scr.width}x${App.scr.height}"
|
||||
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"
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.WireEmissionType
|
||||
import net.torvald.terrarum.utils.CSVFetcher
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.apache.commons.csv.CSVRecord
|
||||
@@ -17,9 +19,12 @@ import java.io.IOException
|
||||
class WireCodex {
|
||||
|
||||
@Transient val wireProps = HashMap<ItemID, WireProp>()
|
||||
|
||||
@Transient private val nullProp = WireProp()
|
||||
|
||||
@Transient val wirePorts = HashMap<WireEmissionType, Triple<TextureRegionPack, Int, Int>>()
|
||||
|
||||
@Transient val wireDecays = HashMap<ItemID, Double>()
|
||||
|
||||
fun 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 get(index: Int): WireProp {
|
||||
@@ -159,4 +220,8 @@ class WireCodex {
|
||||
fun getAllWiresThatAccepts(accept: String): List<Pair<ItemID, WireProp>> {
|
||||
return wireProps.filter { it.value.accepts == accept }.toList()
|
||||
}
|
||||
|
||||
fun getWirePortSpritesheet(emissionType: WireEmissionType): Triple<TextureRegionPack, Int, Int>? {
|
||||
return wirePorts[emissionType]
|
||||
}
|
||||
}
|
||||
@@ -122,6 +122,8 @@ object AVKey {
|
||||
|
||||
const val __PLAYER_QUICKSLOTSEL = "__quickslotselection"
|
||||
|
||||
const val __PLAYER_WIRECUTTERSEL = "__wirecutterselection"
|
||||
|
||||
/** Double
|
||||
* 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
|
||||
|
||||
@@ -51,6 +51,7 @@ abstract class Actor : Comparable<Actor>, Runnable {
|
||||
|
||||
|
||||
enum class RenderOrder {
|
||||
FAR_BEHIND, // wires
|
||||
BEHIND, // tapestries, some particles (obstructed by terrain)
|
||||
MIDDLE, // actors
|
||||
MIDTOP, // bullets, thrown items
|
||||
|
||||
@@ -23,6 +23,7 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellCommonRes.tooltipShowing
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.worlddrawer.CreateTileAtlas
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
@@ -97,6 +98,8 @@ open class ActorWithBody : Actor {
|
||||
val mouseUp: Boolean
|
||||
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
|
||||
protected set
|
||||
var hitboxTranslateY: Int = 0// relative to spritePosY
|
||||
@@ -669,11 +672,15 @@ open class ActorWithBody : Actor {
|
||||
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 (!mouseUp && INGAME.getTooltipMessage() == this.tooltipText) INGAME.setTooltipMessage(null)
|
||||
if (tooltipText == null || !mouseUp || flagDespawn) {
|
||||
tooltipShowing[tooltipHash] = false
|
||||
}
|
||||
|
||||
// isStationary = (hitbox - oldHitbox).magnitudeSquared < PHYS_EPSILON_VELO
|
||||
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")
|
||||
}
|
||||
/* 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
|
||||
debug1("translate x by $t")
|
||||
}
|
||||
@@ -972,7 +979,8 @@ open class ActorWithBody : Actor {
|
||||
debug1("offendingTileWorldY=$offendingTileWorldY, offendingHitboxPointY=$offendingHitboxPointY")
|
||||
|
||||
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()
|
||||
)
|
||||
|
||||
@@ -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?) {
|
||||
// do nothing
|
||||
}
|
||||
@@ -1922,6 +1947,7 @@ open class ActorWithBody : Actor {
|
||||
|
||||
internal open fun flagDespawn() {
|
||||
flagDespawn = true
|
||||
tooltipShowing.remove(tooltipHash)
|
||||
}
|
||||
|
||||
open fun getSpriteHead(): TextureRegion? {
|
||||
@@ -2245,6 +2271,7 @@ open class ActorWithBody : Actor {
|
||||
App.disposables.add(sprite)
|
||||
App.disposables.add(spriteGlow)
|
||||
App.disposables.add(spriteEmissive)
|
||||
tooltipShowing.remove(tooltipHash)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import kotlin.math.floor
|
||||
class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = PhysProperties.MOBILE_OBJECT()), NoSerialise {
|
||||
|
||||
enum class MarkerMode {
|
||||
FIXTURE_GHOST, BLOCK_MARKER
|
||||
FIXTURE_GHOST, BLOCK_MARKER, HIDDEN
|
||||
}
|
||||
|
||||
private val defaultSize = 16.0
|
||||
@@ -45,12 +45,14 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
|
||||
|
||||
|
||||
init {
|
||||
this.isVisible = false
|
||||
this.isVisible = true
|
||||
renderOrder = Actor.RenderOrder.OVERLAY // for some reason the constructor didn't work
|
||||
}
|
||||
|
||||
|
||||
override fun drawBody(frameDelta: Float, batch: SpriteBatch) {
|
||||
this.isVisible = true
|
||||
|
||||
if (isVisible) {
|
||||
if (markerMode == MarkerMode.FIXTURE_GHOST) {
|
||||
if (INGAME.actorNowPlaying != null) {
|
||||
@@ -114,6 +116,16 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
|
||||
ghost = null
|
||||
setGhostColourNone()
|
||||
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 }
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.spriteanimation.SheetSpriteAnimation
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
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.
|
||||
*/
|
||||
class WireActor : ActorWithBody, NoSerialise {
|
||||
|
||||
companion object {
|
||||
val WIRE_NEARBY = arrayOf(
|
||||
(+1 to 0), // tileR
|
||||
(0 to +1), // tileB
|
||||
(-1 to 0), // tileL
|
||||
(0 to -1) // tileT
|
||||
)
|
||||
}
|
||||
class WireActor : ActorWithBody, NoSerialise, InternalActor {
|
||||
|
||||
private constructor()
|
||||
|
||||
@@ -34,7 +36,6 @@ class WireActor : ActorWithBody, NoSerialise {
|
||||
private var worldX = 0
|
||||
private var worldY = 0
|
||||
|
||||
|
||||
/**
|
||||
* @param itemID must start with "wire@"
|
||||
*/
|
||||
@@ -60,34 +61,99 @@ class WireActor : ActorWithBody, NoSerialise {
|
||||
(sprite as SheetSpriteAnimation).currentFrame = cnx
|
||||
}
|
||||
|
||||
private fun getNearbyTilesPos(x: Int, y: Int): Array<Point2i> {
|
||||
return arrayOf(
|
||||
Point2i(x + 1, y),
|
||||
Point2i(x, y + 1),
|
||||
Point2i(x - 1, y),
|
||||
Point2i(x, y - 1)
|
||||
)
|
||||
override fun updateImpl(delta: Float) {
|
||||
}
|
||||
|
||||
private fun essfun0(x: Double) = -cos(Math.PI * x) / 2.0 + 0.5
|
||||
private fun essfun(x: Double) = essfun0(x)
|
||||
|
||||
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 drawBody(frameDelta: Float, batch: SpriteBatch) {
|
||||
if (isVisible && sprite != null) {
|
||||
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()
|
||||
}
|
||||
|
||||
if (isVisible && sprite != null && (Terrarum.ingame!! as TerrarumIngame).selectedWireRenderClass.isNotBlank()) {
|
||||
BlendMode.resolve(drawMode, batch)
|
||||
drawSpriteInGoodPosition(frameDelta, sprite!!, batch)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
if (keycode == Input.Keys.GRAVE) {
|
||||
@@ -233,7 +233,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
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
|
||||
if (keycode == Input.Keys.F12) f12Down = false
|
||||
@@ -243,27 +243,25 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
private fun tTouchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
// don't separate Player from this! Physics will break, esp. airborne manoeuvre
|
||||
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?
|
||||
// disable the IFs: the "unlatching" must happen no matter what, even if a UI is been opened
|
||||
|
||||
if (
|
||||
terrarumIngame.actorNowPlaying != null &&
|
||||
(button == App.getConfigInt("config_mouseprimary") ||
|
||||
button == App.getConfigInt("config_mousesecondary"))) {
|
||||
// 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 (button == App.getConfigInt("config_mouseprimary")) {
|
||||
terrarumIngame.worldPrimaryClickEnd(terrarumIngame.actorNowPlaying!!, App.UPDATE_RATE)
|
||||
}
|
||||
if (button == App.getConfigInt("config_mousesecondary")) {
|
||||
terrarumIngame.worldSecondaryClickEnd(terrarumIngame.actorNowPlaying!!, App.UPDATE_RATE)
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
// }
|
||||
|
||||
// pie menu
|
||||
if (button == App.getConfigInt("control_mouse_quicksel")) {
|
||||
@@ -271,7 +269,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -289,17 +287,17 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
if (button == App.getConfigInt("control_mouse_quicksel")) {
|
||||
|
||||
@@ -47,8 +47,6 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
*/
|
||||
@Transient open var smokiness = Float.POSITIVE_INFINITY
|
||||
|
||||
@Transient open var smeltingProduct: ItemID? = null
|
||||
|
||||
open var dynamicID: ItemID = originalID
|
||||
/**
|
||||
* 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()
|
||||
|
||||
/** Single-use then destroyed (e.g. Tiles), same as "consumable" */
|
||||
/** Single-use then destroyed (e.g. Tiles) */
|
||||
@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>()
|
||||
|
||||
/**
|
||||
* Tags added/removed by dynamic items
|
||||
* Tags added/removed by dynamic items (e.g. enchanting)
|
||||
*/
|
||||
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()
|
||||
|
||||
@@ -256,8 +256,6 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
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
|
||||
* 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!
|
||||
*/
|
||||
//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 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
|
||||
@@ -370,7 +368,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
@JvmStatic val MISC = "misc"
|
||||
}
|
||||
|
||||
override public fun clone(): GameItem {
|
||||
public override fun clone(): GameItem {
|
||||
val clonedItem = super.clone()
|
||||
// properly clone ItemValue
|
||||
(clonedItem as GameItem).itemProperties = this.itemProperties.clone()
|
||||
@@ -378,8 +376,17 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
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)}"
|
||||
ItemCodex.registerNewDynamicItem(dynamicID, this)
|
||||
return this
|
||||
@@ -397,7 +404,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
fun generateUniqueDynamicID(inventory: ActorInventory): Int {
|
||||
var ret: Int
|
||||
do {
|
||||
ret = (1..2147483647).random()
|
||||
ret = (1..999999999).random()
|
||||
} while (inventory.contains("$PREFIX_DYNAMICITEM:$ret"))
|
||||
|
||||
return ret
|
||||
@@ -451,3 +458,8 @@ fun ItemID.isBlock() = !this.contains('@') && !this.isDynamic()
|
||||
fun ItemID.isWall() = this.startsWith("wall@")
|
||||
fun ItemID.isFluid() = this.startsWith("fluid@")
|
||||
fun ItemID.isOre() = this.startsWith("ores@")
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2024-03-06.
|
||||
*/
|
||||
interface FixtureInteractionBlocked
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.gameworld.WorldSimulator.FLUID_MIN_MASS
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
import net.torvald.util.Float16
|
||||
|
||||
const val FLUID_MIN_MASS = 1f / 1024f //Ignore cells that are almost dry (smaller than epsilon of float16)
|
||||
|
||||
/**
|
||||
* * Memory layout:
|
||||
* * ```
|
||||
|
||||
@@ -12,6 +12,7 @@ import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameitems.isFluid
|
||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||
import net.torvald.terrarum.itemproperties.ItemTable
|
||||
import net.torvald.terrarum.modulebasegame.WorldSimulator
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package net.torvald.terrarum.itemproperties
|
||||
|
||||
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.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameitems.isBlock
|
||||
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.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 smeltingProps = HashMap<String, SmeltingRecipe>()
|
||||
|
||||
fun addRecipe(recipe: CraftingRecipe) {
|
||||
val product = recipe.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
|
||||
*
|
||||
@@ -98,6 +119,55 @@ class CraftingCodex {
|
||||
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`.
|
||||
*
|
||||
@@ -118,6 +188,7 @@ class CraftingCodex {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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 CraftingIngredients(val key: String, val keyMode: CraftingItemKeyMode, val qty: Long) {
|
||||
override fun toString() = "$qty ${if (keyMode == CraftingItemKeyMode.TAG) "\$$key" else "$key"}"
|
||||
|
||||
@@ -7,7 +7,6 @@ object Item {
|
||||
|
||||
const val TREE_STICK = "item@basegame:18"
|
||||
|
||||
const val TREE_SEED_OAK = "item@basegame:160"
|
||||
const val TREE_LOGS_OAK = "item@basegame:168"
|
||||
const val COPPER_SIGN = "item@basegame:33280"
|
||||
|
||||
}
|
||||
@@ -84,6 +84,8 @@ class ItemCodex {
|
||||
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>"
|
||||
*/
|
||||
fun registerNewDynamicItem(dynamicID: ItemID, item: GameItem) {
|
||||
|
||||
@@ -2,9 +2,13 @@ package net.torvald.terrarum.langpack
|
||||
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.tail
|
||||
import net.torvald.terrarum.utils.JsonFetcher
|
||||
import net.torvald.unicode.getKeycapPC
|
||||
import net.torvald.unicode.getMouseButton
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
class LangObject(val key: String, val fromLang: Boolean) {
|
||||
fun get() = if (fromLang) Lang[key] else key
|
||||
@@ -137,25 +141,38 @@ object Lang {
|
||||
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"
|
||||
|
||||
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() }
|
||||
if (args.isEmpty()) return ""
|
||||
val sb = StringBuilder()
|
||||
val formatter = Formatter(sb)
|
||||
|
||||
val sb = StringBuilder()
|
||||
val formatter = Formatter(sb)
|
||||
sb.append(getstr(args[0]))
|
||||
args.subList(1, args.size).forEach {
|
||||
val oldstr = sb.toString()
|
||||
sb.clear()
|
||||
formatter.format(getstr(it), oldstr)
|
||||
}
|
||||
|
||||
sb.append(getstr(args[0]))
|
||||
args.subList(1, args.size).forEach {
|
||||
val oldstr = sb.toString()
|
||||
sb.clear()
|
||||
formatter.format(getstr(it), oldstr)
|
||||
if (decodeCache[App.GAME_LOCALE] == null) {
|
||||
decodeCache[App.GAME_LOCALE] = HashMap()
|
||||
}
|
||||
decodeCache[App.GAME_LOCALE]!!["$key+$capitalise"] = sb.toString()
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun getAndUseTemplate(key: String, capitalise: Boolean = false, vararg arguments: Any?): String {
|
||||
var raw = get(key, capitalise)
|
||||
fun getAndUseTemplate(key: String, capitalise: Boolean = false, vararg arguments: Any?): String? {
|
||||
var raw = getOrNull(key, capitalise) ?: return null
|
||||
|
||||
arguments.forEachIndexed { index, it0 ->
|
||||
val it = if (capitalise) it0.toString().capitalize() else it0.toString()
|
||||
raw = raw.replace("{${index}}", it)
|
||||
@@ -174,6 +191,7 @@ object Lang {
|
||||
}
|
||||
|
||||
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? {
|
||||
val ret = langpack["${key}_$locale"] ?: return null
|
||||
@@ -191,18 +209,49 @@ object Lang {
|
||||
private fun NOCAP(key: String, locale: String): String? {
|
||||
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? {
|
||||
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}"
|
||||
else if (locale.startsWith("sr"))
|
||||
"${App.fontGame.charsetOverrideSerbian}$s${App.fontGame.charsetOverrideDefault}"
|
||||
else
|
||||
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()
|
||||
|
||||
@@ -432,7 +432,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
wireActor.renderOrder = Actor.RenderOrder.OVERLAY
|
||||
}
|
||||
else {
|
||||
wireActor.renderOrder = Actor.RenderOrder.BEHIND
|
||||
wireActor.renderOrder = Actor.RenderOrder.FAR_BEHIND
|
||||
}
|
||||
|
||||
wireActor.isUpdate = true
|
||||
@@ -458,14 +458,15 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
_testMarkerDrawCalls = 0L
|
||||
|
||||
IngameRenderer.invoke(delta, false,
|
||||
screenZoom,
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
if (showSelection) actorsRenderOverlay + essentialOverlays else essentialOverlays,
|
||||
particles,
|
||||
uiContainer = uiContainer
|
||||
screenZoom,
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
if (showSelection) actorsRenderOverlay + essentialOverlays else essentialOverlays,
|
||||
particles,
|
||||
uiContainer = uiContainer
|
||||
)
|
||||
|
||||
App.setDebugTime("Test.MarkerDrawCalls", _testMarkerDrawCalls)
|
||||
|
||||
@@ -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!")
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.*
|
||||
@@ -230,6 +231,7 @@ object IngameRenderer : Disposable {
|
||||
frameDelta: Float,
|
||||
gamePaused: Boolean,
|
||||
zoom: Float = 1f,
|
||||
actorsRenderFarBehind : List<ActorWithBody>,
|
||||
actorsRenderBehind : List<ActorWithBody>,
|
||||
actorsRenderMiddle : List<ActorWithBody>,
|
||||
actorsRenderMidTop : List<ActorWithBody>,
|
||||
@@ -239,11 +241,13 @@ object IngameRenderer : Disposable {
|
||||
player: ActorWithBody? = null,
|
||||
uiContainer: UIContainer? = null,
|
||||
) {
|
||||
renderingActorsCount = (actorsRenderBehind.size) +
|
||||
(actorsRenderMiddle.size) +
|
||||
(actorsRenderMidTop.size) +
|
||||
(actorsRenderFront.size) +
|
||||
(actorsRenderOverlay.size)
|
||||
renderingActorsCount =
|
||||
(actorsRenderFarBehind.size) +
|
||||
(actorsRenderBehind.size) +
|
||||
(actorsRenderMiddle.size) +
|
||||
(actorsRenderMidTop.size) +
|
||||
(actorsRenderFront.size) +
|
||||
(actorsRenderOverlay.size)
|
||||
renderingUIsCount = uiContainer?.countVisible() ?: 0
|
||||
|
||||
invokeInit()
|
||||
@@ -258,15 +262,15 @@ object IngameRenderer : Disposable {
|
||||
measureDebugTime("Renderer.LightRun*") {
|
||||
// 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) {
|
||||
LightmapRenderer.recalculate(actorsRenderBehind + actorsRenderFront + actorsRenderMidTop + actorsRenderMiddle + actorsRenderOverlay)
|
||||
LightmapRenderer.recalculate(actorsRenderFarBehind + actorsRenderBehind + actorsRenderFront + actorsRenderMidTop + actorsRenderMiddle + actorsRenderOverlay)
|
||||
}
|
||||
oldCamX = WorldCamera.x
|
||||
}
|
||||
|
||||
prepLightmapRGBA()
|
||||
BlocksDrawer.renderData()
|
||||
drawToRGB(frameDelta, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer)
|
||||
drawToA(frameDelta, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer)
|
||||
drawToRGB(frameDelta, actorsRenderFarBehind, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer)
|
||||
drawToA(frameDelta, actorsRenderFarBehind, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer)
|
||||
drawOverlayActors(frameDelta, actorsRenderOverlay)
|
||||
|
||||
if (player != null && player is Pocketed) drawAimGuide(frameDelta, player)
|
||||
@@ -463,6 +467,7 @@ object IngameRenderer : Disposable {
|
||||
|
||||
private fun drawToRGB(
|
||||
frameDelta: Float,
|
||||
actorsRenderFarBehind: List<ActorWithBody>?,
|
||||
actorsRenderBehind: List<ActorWithBody>?,
|
||||
actorsRenderMiddle: List<ActorWithBody>?,
|
||||
actorsRenderMidTop: List<ActorWithBody>?,
|
||||
@@ -484,6 +489,7 @@ object IngameRenderer : Disposable {
|
||||
batch.shader = shaderForActors
|
||||
batch.color = Color.WHITE
|
||||
moveCameraToWorldCoord()
|
||||
actorsRenderFarBehind?.forEach { it.drawBody(frameDelta, batch) }
|
||||
actorsRenderBehind?.forEach { it.drawBody(frameDelta, batch) }
|
||||
particlesContainer?.forEach { it.drawBody(frameDelta, batch) }
|
||||
}
|
||||
@@ -522,6 +528,7 @@ object IngameRenderer : Disposable {
|
||||
batch.shader = shaderForActors
|
||||
batch.color = Color.WHITE
|
||||
moveCameraToWorldCoord()
|
||||
actorsRenderFarBehind?.forEach { it.drawEmissive(frameDelta, batch) }
|
||||
actorsRenderBehind?.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.draw(
|
||||
lightTex,
|
||||
xrem, yrem,
|
||||
xrem, yrem - TILE_SIZEF * 0.5f,
|
||||
lightTex.regionWidth * lightmapDownsample,
|
||||
lightTex.regionHeight * lightmapDownsample
|
||||
)
|
||||
@@ -627,6 +634,7 @@ object IngameRenderer : Disposable {
|
||||
|
||||
private fun drawToA(
|
||||
frameDelta: Float,
|
||||
actorsRenderFarBehind: List<ActorWithBody>?,
|
||||
actorsRenderBehind: List<ActorWithBody>?,
|
||||
actorsRenderMiddle: List<ActorWithBody>?,
|
||||
actorsRenderMidTop: List<ActorWithBody>?,
|
||||
@@ -651,6 +659,7 @@ object IngameRenderer : Disposable {
|
||||
batch.color = Color.WHITE
|
||||
|
||||
moveCameraToWorldCoord()
|
||||
actorsRenderFarBehind?.forEach { it.drawGlow(frameDelta, batch) }
|
||||
actorsRenderBehind?.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("u_pattern", 1)
|
||||
batch.draw(lightTex,
|
||||
xrem, yrem,
|
||||
xrem, yrem - TILE_SIZEF * 0.5f,
|
||||
lightTex.regionWidth * lightmapDownsample,
|
||||
lightTex.regionHeight * lightmapDownsample
|
||||
)
|
||||
@@ -765,25 +774,24 @@ object IngameRenderer : Disposable {
|
||||
private val cubeSize = 7.0
|
||||
private val externalV = Vector2()
|
||||
private val maxStep = 56
|
||||
private val trajectoryFlow = 30
|
||||
private fun drawTrajectoryForThrowable(frameBuffer: FrameBuffer, batch: SpriteBatch, frameDelta: Float, player: ActorWithBody, world: GameWorld, item: ItemThrowable) {
|
||||
val ww = world.width * TILE_SIZEF
|
||||
|
||||
|
||||
mouseInInteractableRange(player) { mx, my, mtx, mty ->
|
||||
val (throwPos, throwVector) = getThrowPosAndVector(player)
|
||||
val grav = world.gravitation
|
||||
val toff = (App.GLOBAL_RENDER_TIMER % trajectoryFlow) / trajectoryFlow.toFloat()
|
||||
externalV.set(throwVector)
|
||||
|
||||
val points = ArrayList<Pair<Float, Float>>()
|
||||
|
||||
var c = 0
|
||||
while (c < maxStep) {
|
||||
batch.color = Color(0.9f, 0.9f, 0.9f, 0.9f * (1f - (c.toFloat() / maxStep).sqr()))
|
||||
|
||||
// plot a dot
|
||||
if (c > 0) {
|
||||
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)
|
||||
}
|
||||
points.add(throwPos.x.toFloat() to throwPos.y.toFloat())
|
||||
|
||||
// simulate physics
|
||||
applyGravitation(grav, cubeSize) // TODO use actual value instead of `cubeSize`
|
||||
@@ -807,16 +815,40 @@ object IngameRenderer : Disposable {
|
||||
BlockCodex[tile].isSolid
|
||||
}
|
||||
|
||||
if (hitSolid)
|
||||
if (hitSolid) {
|
||||
points.add(throwPos.x.toFloat() to throwPos.y.toFloat())
|
||||
break
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private val bodyFriction = BlockCodex[Block.AIR].friction.frictionToMult()
|
||||
|
||||
@@ -23,11 +23,11 @@ import net.torvald.terrarum.gameactors.*
|
||||
import net.torvald.terrarum.gamecontroller.IngameController
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||
import net.torvald.terrarum.gameitems.FixtureInteractionBlocked
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.mouseInInteractableRange
|
||||
import net.torvald.terrarum.gameparticles.ParticleBase
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.gameworld.WorldSimulator
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
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.worlddrawer.BlocksDrawer
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer.LIGHTMAP_OVERRENDER
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.unicode.EMDASH
|
||||
import net.torvald.util.CircularArray
|
||||
@@ -91,6 +90,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
val particlesContainer = CircularArray<ParticleBase>(PARTICLES_MAX, true)
|
||||
|
||||
// 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 visibleActorsRenderMiddle: 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.")
|
||||
}
|
||||
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")
|
||||
|
||||
@@ -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
|
||||
override fun worldPrimaryClickStart(actor: ActorWithBody, delta: Float) {
|
||||
//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)]
|
||||
// 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
|
||||
// don't want to open the UI and use the item at the same time, would ya?
|
||||
if (itemOnGrip != null) {
|
||||
val consumptionSuccessful = itemOnGrip.startPrimaryUse(actor, delta)
|
||||
if (consumptionSuccessful > -1)
|
||||
(actor as Pocketed).inventory.consumeItem(itemOnGrip, consumptionSuccessful)
|
||||
}
|
||||
// #2. If I'm not holding any item and I can do barehandaction (size big enough that barehandactionminheight check passes), perform it
|
||||
else if (itemOnGrip == null) {
|
||||
mouseInInteractableRange(actor) { mwx, mwy, mtx, mty ->
|
||||
performBarehandAction(actor, delta, mwx, mwy, mtx, mty)
|
||||
0L
|
||||
mouseInInteractableRange(actor) { mwx, mwy, mtx, mty ->
|
||||
// #1. interact with the fixture if NOT FixtureInteractionBlocked
|
||||
// scan for the one with non-null UI.
|
||||
// what if there's multiple of such fixtures? whatever, you are supposed to DISALLOW such situation.
|
||||
if (fixtureUnderMouse != null && itemOnGrip !is FixtureInteractionBlocked) {
|
||||
if (!worldPrimaryClickLatch) {
|
||||
worldPrimaryClickLatch = true
|
||||
fixtureUnderMouse.let { fixture ->
|
||||
fixture.mainUI?.let { ui ->
|
||||
uiOpened = true
|
||||
|
||||
// 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) {
|
||||
endPerformBarehandAction(actor)
|
||||
}
|
||||
|
||||
worldPrimaryClickLatch = false
|
||||
}
|
||||
|
||||
// right click: use fixture
|
||||
override fun worldSecondaryClickStart(actor: ActorWithBody, delta: Float) {
|
||||
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
|
||||
// scan for the one with non-null UI.
|
||||
// what if there's multiple of such fixtures? whatever, you are supposed to DISALLOW such situation.
|
||||
for (kk in actorsUnderMouse.indices) {
|
||||
if (mouseInInteractableRange(actor) { _, _, _, _ ->
|
||||
actorsUnderMouse[kk].let { fixture ->
|
||||
fixture.mainUI?.let { ui ->
|
||||
uiOpened = true
|
||||
|
||||
// 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?
|
||||
)
|
||||
// if (fixture.mainUIopenFun == null)
|
||||
ui.setAsOpen()
|
||||
// else
|
||||
// fixture.mainUIopenFun!!.invoke(ui)
|
||||
}
|
||||
if (!worldSecondaryClickLatch) {
|
||||
// #1. Perform item's secondaryUse
|
||||
val consumptionSuccessful = itemOnGrip?.startSecondaryUse(actor, delta) ?: -1
|
||||
if (consumptionSuccessful > -1)
|
||||
(actor as Pocketed).inventory.consumeItem(itemOnGrip!!, consumptionSuccessful)
|
||||
// #2. If #1 failed, try to pick up the fixture
|
||||
else {
|
||||
mouseInInteractableRange(actor) { mwx, mwy, mtx, mty ->
|
||||
pickupFixture(actor, delta, mwx, mwy, mtx, mty)
|
||||
0L
|
||||
}
|
||||
0L
|
||||
} == 0L) break
|
||||
}
|
||||
}
|
||||
|
||||
if (!uiOpened) {
|
||||
//...
|
||||
worldSecondaryClickLatch = true
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
measureDebugTime("Ingame.FillUpWirePortsView*") {
|
||||
if (WORLD_UPDATE_TIMER % 2 == 0) {
|
||||
val fixtures = INGAME.actorContainerActive.filterIsInstance<Electric>()
|
||||
fillUpWirePortsView(fixtures)
|
||||
}
|
||||
}
|
||||
oldCamX = WorldCamera.x
|
||||
oldPlayerX = actorNowPlaying?.hitbox?.canonicalX ?: 0.0
|
||||
|
||||
@@ -1059,6 +1095,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
frameDelta,
|
||||
paused,
|
||||
screenZoom,
|
||||
visibleActorsRenderFarBehind,
|
||||
visibleActorsRenderBehind,
|
||||
visibleActorsRenderMiddle,
|
||||
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 maxRenderablePorts = ReferencingRanges.ACTORS_WIRE_PORTS.last - ReferencingRanges.ACTORS_WIRE_PORTS.first + 1
|
||||
private val wireActorsContainer = Array(maxRenderableWires) { WireActor(ReferencingRanges.ACTORS_WIRES.first + it).let {
|
||||
forceAddActor(it)
|
||||
/*^let*/ it
|
||||
} }
|
||||
private val wirePortActorsContainer = Array(maxRenderablePorts) { WirePortActor(ReferencingRanges.ACTORS_WIRE_PORTS.first + it).let {
|
||||
forceAddActor(it)
|
||||
/*^let*/ it
|
||||
} }
|
||||
|
||||
private fun fillUpWiresBuffer() {
|
||||
val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorToInt() - LIGHTMAP_OVERRENDER
|
||||
val for_y_end = for_y_start + BlocksDrawer.tilesInVertical + 2*LIGHTMAP_OVERRENDER
|
||||
val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorToInt() - 1
|
||||
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_end = for_x_start + BlocksDrawer.tilesInHorizontal + 2*LIGHTMAP_OVERRENDER
|
||||
val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorToInt() - 1
|
||||
val for_x_end = for_x_start + BlocksDrawer.tilesInHorizontal + 2*1
|
||||
|
||||
var wiringCounter = 0
|
||||
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
|
||||
}
|
||||
else {
|
||||
wireActor.renderOrder = Actor.RenderOrder.BEHIND
|
||||
wireActor.renderOrder = Actor.RenderOrder.FAR_BEHIND
|
||||
}
|
||||
|
||||
wireActor.isUpdate = true
|
||||
@@ -1235,13 +1277,44 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
for (i in wiringCounter until maxRenderableWires) {
|
||||
wireActorsContainer[i].isUpdate = false
|
||||
wireActorsContainer[i].isVisible = false
|
||||
wireActorsContainer[i].forceDormant = true
|
||||
val wireActor = wireActorsContainer[i]
|
||||
wireActor.isUpdate = false
|
||||
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() {
|
||||
visibleActorsRenderFarBehind.clear()
|
||||
visibleActorsRenderBehind.clear()
|
||||
visibleActorsRenderMiddle.clear()
|
||||
visibleActorsRenderMidTop.clear()
|
||||
@@ -1441,6 +1514,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
private fun actorToRenderQueue(actor: ActorWithBody): ArrayList<ActorWithBody> {
|
||||
return when (actor.renderOrder) {
|
||||
Actor.RenderOrder.FAR_BEHIND -> visibleActorsRenderFarBehind
|
||||
Actor.RenderOrder.BEHIND -> visibleActorsRenderBehind
|
||||
Actor.RenderOrder.MIDDLE -> visibleActorsRenderMiddle
|
||||
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
|
||||
val canAttackOrDig =
|
||||
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 =
|
||||
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 = actor.scale * actor.actorValue.getAsDouble(AVKey.BAREHAND_BASE_DIGSIZE)!!
|
||||
val punchSize = getPunchSize(actor)
|
||||
val punchBlockSize = punchSize.div(TILE_SIZED).floorToInt()
|
||||
|
||||
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
|
||||
else if (mouseUnderPunchableTree) {
|
||||
if (mouseUnderPunchableTree) {
|
||||
barehandAxeInUse = true
|
||||
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() {
|
||||
uiContainer.forEach { it?.handler?.dispose() }
|
||||
}
|
||||
@@ -1685,6 +1776,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
visibleActorsRenderFarBehind.forEach { it.dispose() }
|
||||
visibleActorsRenderBehind.forEach { it.dispose() }
|
||||
visibleActorsRenderMiddle.forEach { it.dispose() }
|
||||
visibleActorsRenderMidTop.forEach { it.dispose() }
|
||||
|
||||
@@ -194,7 +194,7 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
||||
protected var ambState = 0
|
||||
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 playCaller: Any? = null; private set
|
||||
|
||||
@@ -372,6 +372,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
particles,
|
||||
uiContainer = uiContainer
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.utils.Queue
|
||||
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.Controllable
|
||||
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.gameactors.*
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.AxeCore
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.lang.Math.pow
|
||||
import kotlin.math.cosh
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sqrt
|
||||
|
||||
/**
|
||||
* 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_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 minFlow = 0.01f
|
||||
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.fluids") { /*moveFluids(delta)*/ }
|
||||
App.measureDebugTime("WorldSimulator.fallables") { displaceFallables(delta) }
|
||||
if (ingame.WORLD_UPDATE_TIMER % 2 == 1) {
|
||||
App.measureDebugTime("WorldSimulator.wires") { simulateWires(delta) }
|
||||
}
|
||||
else {
|
||||
// TODO update logic
|
||||
}
|
||||
App.measureDebugTime("WorldSimulator.wires") { simulateWires(delta) }
|
||||
App.measureDebugTime("WorldSimulator.collisionDroppedItem") { collideDroppedItems() }
|
||||
App.measureDebugTime("WorldSimulator.dropTreeLeaves") { dropTreeLeaves() }
|
||||
|
||||
@@ -508,7 +503,7 @@ object WorldSimulator {
|
||||
wiresimGetSourceBlocks().let { sources ->
|
||||
// signal-emitting fixtures must set emitState of its own tiles via update()
|
||||
sources.forEach {
|
||||
it.wireEmitterTypes.forEach { bbi, wireType ->
|
||||
it.wireEmitterTypes.forEach { (bbi, wireType) ->
|
||||
|
||||
val startingPoint = it.worldBlockPos!! + it.blockBoxIndexToPoint2i(bbi)
|
||||
val signal = it.wireEmission[bbi] ?: Vector2(0.0, 0.0)
|
||||
@@ -517,14 +512,19 @@ object WorldSimulator {
|
||||
val simStartingPoint = WireGraphCursor(startingPoint, wire)
|
||||
wireSimMarked.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
|
||||
|
||||
@@ -542,7 +542,7 @@ object WorldSimulator {
|
||||
wireSimMarked.add(point.longHash())
|
||||
oldTraversedNodes.add(point.copy())
|
||||
// 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())
|
||||
40
src/net/torvald/terrarum/modulebasegame/console/HasItem.kt
Normal file
40
src/net/torvald/terrarum/modulebasegame/console/HasItem.kt
Normal 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")
|
||||
}
|
||||
}
|
||||
41
src/net/torvald/terrarum/modulebasegame/console/MakeSign.kt
Normal file
41
src/net/torvald/terrarum/modulebasegame/console/MakeSign.kt
Normal 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.")
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ class ActorInventory() : FixtureInventory() {
|
||||
|
||||
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)
|
||||
}
|
||||
else if (item.isUnique) {
|
||||
@@ -115,10 +115,8 @@ class ActorInventory() : FixtureInventory() {
|
||||
remove(item, 1)
|
||||
|
||||
|
||||
newItem = item.clone()
|
||||
newItem.generateUniqueDynamicID(this)
|
||||
newItem = item.makeDynamic(this)
|
||||
|
||||
newItem.stackable = false
|
||||
add(newItem)
|
||||
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) {
|
||||
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 ->
|
||||
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")
|
||||
|
||||
actor.equipItem(itm)
|
||||
|
||||
200
src/net/torvald/terrarum/modulebasegame/gameactors/Electric.kt
Normal file
200
src/net/torvald/terrarum/modulebasegame/gameactors/Electric.kt
Normal 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)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -6,129 +6,16 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
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)
|
||||
@@ -141,6 +28,9 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
|
||||
@Transient open val spawnNeedsWall: Boolean = false
|
||||
@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 */
|
||||
@Transient var spawnRequestedTime: Long = 0L
|
||||
@@ -172,6 +62,19 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
*/
|
||||
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:
|
||||
*
|
||||
@@ -267,25 +170,94 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
|
||||
cannotSpawn = everyBlockboxPos.any { (x, y) -> !BlockCodex[world!!.getTileFromTerrain(x, y)].hasTag("INCONSEQUENTIAL") }
|
||||
|
||||
|
||||
var cannotSpawnNoWall = false
|
||||
var cannotSpawnNoFloor = false
|
||||
|
||||
// check for walls, if spawnNeedsWall = true
|
||||
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
|
||||
if (spawnNeedsFloor) {
|
||||
val y = posY + blockBox.height
|
||||
if (spawnNeedsFloor || spawnNeedsCeiling) {
|
||||
val y = posY + if (spawnNeedsFloor) blockBox.height else -1
|
||||
val xs = posX until posX + blockBox.width
|
||||
cannotSpawn = cannotSpawn or xs.any { x ->
|
||||
cannotSpawnNoFloor = xs.any { x ->
|
||||
world!!.getTileFromTerrain(x, y).let {
|
||||
!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
|
||||
}
|
||||
|
||||
/**
|
||||
* @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].
|
||||
*
|
||||
@@ -346,53 +318,6 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
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].
|
||||
* 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)
|
||||
|
||||
onSpawn(posX0, posY0)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -536,6 +463,14 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
} 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 {
|
||||
@@ -556,7 +491,6 @@ interface CuedByWireChange {
|
||||
fun updateForWireChange(cue: IngameInstance.BlockChangeQueueItem)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Standard 32-bit binary flags.
|
||||
*
|
||||
|
||||
@@ -336,6 +336,11 @@ class InventoryPair : Comparable<InventoryPair> {
|
||||
override fun toString(): String {
|
||||
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)
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,9 +11,9 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
/**
|
||||
* 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
|
||||
|
||||
constructor() : super(
|
||||
@@ -49,11 +49,8 @@ class FixtureSignalBulb : Electric {
|
||||
(spriteEmissive as SheetSpriteAnimation).currentRow = state.toInt()
|
||||
}
|
||||
|
||||
override fun onSignalHigh(readFrom: BlockBoxIndex) {
|
||||
light(true)
|
||||
}
|
||||
|
||||
override fun onSignalLow(readFrom: BlockBoxIndex) {
|
||||
light(false)
|
||||
override fun updateImpl(delta: Float) {
|
||||
super.updateImpl(delta)
|
||||
light(getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
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 org.dyn4j.geometry.Vector2
|
||||
|
||||
@@ -12,7 +14,8 @@ import org.dyn4j.geometry.Vector2
|
||||
*/
|
||||
class FixtureLogicSignalEmitter : Electric {
|
||||
|
||||
@Transient override val spawnNeedsFloor = false
|
||||
@Transient override val spawnNeedsFloor = true
|
||||
@Transient override val spawnNeedsWall = true
|
||||
|
||||
constructor() : super(
|
||||
BlockBox(BlockBox.NO_COLLISION, 1, 1),
|
||||
@@ -35,7 +38,13 @@ class FixtureLogicSignalEmitter : Electric {
|
||||
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 {
|
||||
const val MASS = 1.0
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.spriteanimation.SheetSpriteAnimation
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
||||
import net.torvald.terrarum.toInt
|
||||
import net.torvald.terrarum.ui.MouseLatch
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.dyn4j.geometry.Vector2
|
||||
|
||||
/**
|
||||
* 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(
|
||||
BlockBox(BlockBox.NO_COLLISION, 1, 1),
|
||||
@@ -28,6 +27,7 @@ class FixtureSignalSwitchManual : Electric {
|
||||
|
||||
init {
|
||||
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_switch.tga")
|
||||
val itemImage2 = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/signal_switch_glow.tga")
|
||||
|
||||
density = 1400.0
|
||||
setHitboxDimension(TerrarumAppConfiguration.TILE_SIZE, TerrarumAppConfiguration.TILE_SIZE, 0, 1)
|
||||
@@ -37,6 +37,11 @@ class FixtureSignalSwitchManual : Electric {
|
||||
it.currentFrame = variant
|
||||
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
|
||||
|
||||
@@ -53,19 +58,9 @@ class FixtureSignalSwitchManual : Electric {
|
||||
setWireEmissionAt(0, 0, Vector2(state.toInt().toDouble(), 0.0))
|
||||
}
|
||||
|
||||
@Transient private val clickLatch = MouseLatch(listOf(App.getConfigInt("config_mousesecondary")))
|
||||
|
||||
override fun updateImpl(delta: Float) {
|
||||
super.updateImpl(delta)
|
||||
|
||||
// right click
|
||||
if (mouseUp) {
|
||||
clickLatch.latch {
|
||||
state = !state
|
||||
(sprite as SheetSpriteAnimation).currentRow = state.toInt()
|
||||
setWireEmissionAt(0, 0, Vector2(state.toInt().toDouble(), 0.0))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInteract(mx: Double, my: Double) {
|
||||
state = !state
|
||||
(sprite as SheetSpriteAnimation).currentRow = state.toInt()
|
||||
setWireEmissionAt(0, 0, Vector2(state.toInt().toDouble(), 0.0))
|
||||
}
|
||||
}
|
||||
@@ -65,42 +65,36 @@ class FixtureMusicalTurntable : Electric, PlaysMusic {
|
||||
|
||||
internal var disc: ItemID? = null
|
||||
|
||||
@Transient private val clickLatch = MouseLatch(listOf(App.getConfigInt("config_mousesecondary")))
|
||||
|
||||
override val canBeDespawned: Boolean
|
||||
get() = disc == null
|
||||
|
||||
override fun updateImpl(delta: Float) {
|
||||
super.updateImpl(delta)
|
||||
override fun onInteract(mx: Double, my: Double) {
|
||||
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 (mouseUp) {
|
||||
clickLatch.latch {
|
||||
if (disc == null) {
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateImpl(delta: Float) {
|
||||
super.updateImpl(delta)
|
||||
|
||||
// supress the normal background music playback
|
||||
if (musicIsPlaying && !flagDespawn) {
|
||||
@@ -172,6 +166,8 @@ class FixtureMusicalTurntable : Electric, PlaysMusic {
|
||||
super.reload()
|
||||
// cannot resume playback, just stop the music
|
||||
musicNowPlaying = null
|
||||
// update sprite
|
||||
(sprite as SheetSpriteAnimation).currentRow = (disc == null).toInt()
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.random.HQRNG
|
||||
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.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
|
||||
@@ -25,26 +24,102 @@ import net.torvald.terrarum.modulebasegame.ui.UISmelterBasic
|
||||
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.
|
||||
*/
|
||||
class FixtureSmelterBasic : FixtureBase, CraftingStation {
|
||||
class FixtureSmelterBasic : 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
|
||||
|
||||
var oreItem: InventoryPair? = null
|
||||
var fireboxItem: InventoryPair? = null
|
||||
var productItem: InventoryPair? = null
|
||||
internal var oreItem: InventoryPair? = null
|
||||
internal var fireboxItem: 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
|
||||
get() = oreItem == null && fireboxItem == null && productItem == null
|
||||
|
||||
@Transient override val tags = listOf("basicsmelter")
|
||||
|
||||
init {
|
||||
CommonResourcePool.addToLoadingList("basegame/sprites/fixtures/smelter_tall.tga") {
|
||||
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 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(
|
||||
arrayOf(Block.ACTORBLOCK_NO_COLLISION, Block.ACTORBLOCK_NO_COLLISION, null),
|
||||
@@ -112,27 +187,6 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
|
||||
|
||||
@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) {
|
||||
if (isVisible && spriteEmissive != null) {
|
||||
BlendMode.resolve(drawMode, batch)
|
||||
@@ -198,7 +252,6 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
|
||||
override fun updateImpl(delta: Float) {
|
||||
super.updateImpl(delta)
|
||||
|
||||
val oreItemProp = ItemCodex[oreItem?.itm]
|
||||
val fuelItemProp = ItemCodex[fireboxItem?.itm]
|
||||
|
||||
// consume fuel
|
||||
@@ -215,7 +268,7 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
|
||||
nextDelayBase = fuelItemProp.smokiness
|
||||
nextDelay = (nextDelayBase * (1.0 + RNG.nextTriangularBal() * 0.1)).toFloat()
|
||||
|
||||
changeFireboxItemCount(-1)
|
||||
fireboxItemStatus.changeCount(-1)
|
||||
}
|
||||
// no item on the slot
|
||||
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)
|
||||
}
|
||||
|
||||
val smeltingProduct = CraftingRecipeCodex.getSmeltingProductOf(oreItem?.itm)
|
||||
|
||||
// roast items
|
||||
if (oreItem != null &&
|
||||
temperature > 0f &&
|
||||
oreItemProp?.smeltingProduct != null &&
|
||||
(productItem == null || oreItemProp.smeltingProduct == productItem!!.itm)
|
||||
smeltingProduct != null &&
|
||||
(productItem == null || smeltingProduct.item == productItem!!.itm)
|
||||
) {
|
||||
|
||||
progress += temperature
|
||||
|
||||
if (progress >= CALORIES_PER_ROASTING) {
|
||||
val smeltingProduct = oreItemProp.smeltingProduct!!
|
||||
val smeltingProductItem = smeltingProduct.item
|
||||
|
||||
// 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)
|
||||
productItem = InventoryPair(smeltingProduct, 1L)
|
||||
productItem = InventoryPair(smeltingProductItem, 1L)
|
||||
else
|
||||
changeProductItemCount(1)
|
||||
productItemStatus.changeCount(1)
|
||||
|
||||
// take the ore item
|
||||
changeOreItemCount(-1)
|
||||
oreItemStatus.changeCount(-1)
|
||||
|
||||
progress = 0f
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user