Compare commits

..

84 Commits

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,11 +3,11 @@
"1";"N/A";"N/A";"BLOCK_UPDATE";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"AIIR";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INTERNAL,NORANDTILE"
# 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.

View File

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

View File

@@ -32,11 +32,30 @@
]
},
"item@basegame:36": { /* wire rolling mill */
"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 */
]
},

View File

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

View File

@@ -61,5 +61,9 @@
"item@basegame:9": { /* wire cutter */
"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 */
}
}

View File

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

View File

@@ -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
1 id classname tags
32 32 net.torvald.terrarum.modulebasegame.gameitems.ItemCherryBomb EXPLOSIVE,THROWABLE
33 33 net.torvald.terrarum.modulebasegame.gameitems.ItemTorch FIXTURE,LIGHT
34 34 net.torvald.terrarum.modulebasegame.gameitems.ItemSignalSwitchManual net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalSwitchManual FIXTURE,SIGNAL
35 35 net.torvald.terrarum.modulebasegame.gameitems.ItemSignalBulb net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalBulb FIXTURE,SIGNAL
36 36 net.torvald.terrarum.modulebasegame.gameitems.ItemWireRollingMill FIXTURE,CRAFTING
37 37 net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestEbony FIXTURE,STORAGE
38 38 net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestBirch FIXTURE,STORAGE
39 39 net.torvald.terrarum.modulebasegame.gameitems.ItemStorageChestRosewood FIXTURE,STORAGE
42 42 net.torvald.terrarum.modulebasegame.gameitems.ItemTableBirch FIXTURE,SURFACE
43 43 net.torvald.terrarum.modulebasegame.gameitems.ItemTableRosewood FIXTURE,SURFACE
44 # ingots 44 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalBlocker FIXTURE,SIGNAL
45 45 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalLatch FIXTURE,SIGNAL
46 46 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalRepeaterHorz FIXTURE,SIGNAL
47 47 net.torvald.terrarum.modulebasegame.gameitems.ItemWrench TOOL,WRENCH
48 48 net.torvald.terrarum.modulebasegame.gameitems.ItemAlloyingFurnace FIXTURE,STATION
49 49 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalAdder FIXTURE,SIGNAL
50 50 net.torvald.terrarum.modulebasegame.gameitems.ItemSolderingWire
51 51 net.torvald.terrarum.modulebasegame.gameitems.ItemElectricWorkbench FIXTURE,CRAFTING
52 52 net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalSevenSeg FIXTURE,SIGNAL
53 53 net.torvald.terrarum.modulebasegame.gameitems.ItemEngravingWorkbench FIXTURE,CRAFTING
54 # ingots
55 26 112 net.torvald.terrarum.modulebasegame.gameitems.IngotSteel net.torvald.terrarum.modulebasegame.gameitems.IngotCopper INGOT
56 112 113 net.torvald.terrarum.modulebasegame.gameitems.IngotCopper net.torvald.terrarum.modulebasegame.gameitems.IngotIron INGOT
113 net.torvald.terrarum.modulebasegame.gameitems.IngotIron INGOT
57 114 net.torvald.terrarum.modulebasegame.gameitems.ItemCoalCoke COMBUSTIBLE
58 115 net.torvald.terrarum.modulebasegame.gameitems.IngotZinc INGOT
59 116 net.torvald.terrarum.modulebasegame.gameitems.IngotTin INGOT INGOT,SEMICONDUCTOR
60 117 net.torvald.terrarum.modulebasegame.gameitems.IngotGold INGOT
61 118 net.torvald.terrarum.modulebasegame.gameitems.IngotSilver INGOT
62 119 net.torvald.terrarum.modulebasegame.gameitems.IngotLead INGOT
63 # ores # alloys
64 128 26 net.torvald.terrarum.modulebasegame.gameitems.OreCopper net.torvald.terrarum.modulebasegame.gameitems.IngotSteel SMELTABLE INGOT,ALLOY
65 129 176 net.torvald.terrarum.modulebasegame.gameitems.OreIron net.torvald.terrarum.modulebasegame.gameitems.IngotBronze SMELTABLE INGOT,ALLOY
66 177 net.torvald.terrarum.modulebasegame.gameitems.IngotBrass INGOT,ALLOY
67 178 net.torvald.terrarum.modulebasegame.gameitems.IngotElectrum INGOT,ALLOY
68 179 net.torvald.terrarum.modulebasegame.gameitems.IngotSilverBillon INGOT,ALLOY
69 180 net.torvald.terrarum.modulebasegame.gameitems.IngotRosegold INGOT,ALLOY
70 181 net.torvald.terrarum.modulebasegame.gameitems.IngotSolder INGOT,ALLOY
71 # ores
72 128 net.torvald.terrarum.modulebasegame.gameitems.OreCopper SMELTABLE
73 129 net.torvald.terrarum.modulebasegame.gameitems.OreIron SMELTABLE
74 130 net.torvald.terrarum.modulebasegame.gameitems.OreCoal SMELTABLE,COMBUSTIBLE
75 130 131 net.torvald.terrarum.modulebasegame.gameitems.OreCoal net.torvald.terrarum.modulebasegame.gameitems.OreZinc SMELTABLE,COMBUSTIBLE SMELTABLE
76 131 132 net.torvald.terrarum.modulebasegame.gameitems.OreZinc net.torvald.terrarum.modulebasegame.gameitems.OreTin SMELTABLE
77 132 133 net.torvald.terrarum.modulebasegame.gameitems.OreTin net.torvald.terrarum.modulebasegame.gameitems.OreGold SMELTABLE
96 256 257 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony FIXTURE
97 257 258 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorBirch FIXTURE
98 258 259 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorBirch net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorRosewood FIXTURE
99 259 320 net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorRosewood net.torvald.terrarum.modulebasegame.gameitems.ItemWorldPortal FIXTURE FIXTURE,STATION
100 320 # data storage (discs net.torvald.terrarum.modulebasegame.gameitems.ItemWorldPortal 256)
101 # data storage (discs # 32768 is a reserved number for a blank disc
102 # 32768 is a reserved number for a blank disc 32769 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc01 MUSIC,PHONO
103 32769 32770 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc01 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc02 MUSIC,PHONO
104 32770 32771 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc02 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc03 MUSIC,PHONO
105 32771 32772 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc03 net.torvald.terrarum.modulebasegame.gameitems.MusicDisc04 MUSIC,PHONO
122 # ... # 100500h..1005FFh : Fluid type 5 (steam) x container type 0..255
123 # 1FF00h..1FFFFh : Fluid type 255 (???) x container type 0..255 # ...
124 # 10FF00h..10FFFFh : Fluid type 255 (???) x container type 0..255
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,5 @@
{
"CONTEXT_ENGRAVER_TEXT": "Text",
"CONTEXT_GENERATOR_SEED": "Seed",
"CONTEXT_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",

View File

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

View File

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

View File

@@ -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": "즐겨찾기",

View File

@@ -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": "들어오는 신호의 합을 구합니다"
}

View File

@@ -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": "렌치"
}

View File

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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

Binary file not shown.

View File

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

View File

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

View File

@@ -3,8 +3,8 @@ description=Simple music player widget
author=CuriousTo\uA75Bvald
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+

View File

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

View File

@@ -63,7 +63,8 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
}
}
val disposables = HashSet<Disposable>()
/** things to be disposed of when the current instance of the game disposed of */
// val disposables = HashSet<Disposable>()
lateinit var worldDisk: VirtualDisk; internal set
lateinit var 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,6 +23,7 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameactors.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)
}
}

View File

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

View File

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

View File

@@ -208,7 +208,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
}
}
terrarumIngame.uiContainer.forEach { it?.keyDown(keycode) } // for KeyboardControlled UIcanvases
terrarumIngame.uiContainer.forEach { if (it?.justOpened == false) it.keyDown(keycode) } // for KeyboardControlled UIcanvases
// Debug UIs
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")) {

View File

@@ -47,8 +47,6 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
*/
@Transient open var smokiness = Float.POSITIVE_INFINITY
@Transient open var 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

View File

@@ -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:
* * ```

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,6 +9,7 @@ import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.graphics.glutils.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()

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
package net.torvald.terrarum.gameworld
package net.torvald.terrarum.modulebasegame
import com.badlogic.gdx.utils.Queue
import 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())

View File

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

View File

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

View File

@@ -100,7 +100,7 @@ class ActorInventory() : FixtureInventory() {
if (amount < 0) throw IllegalArgumentException("Consuming negative amount of an item (expected >=0, got $amount)")
if (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)

View File

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

View File

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

View File

@@ -6,129 +6,16 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.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.
*

View File

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

View File

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

View File

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

View File

@@ -11,9 +11,9 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2024-03-01.
*/
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)
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,22 +1,21 @@
package net.torvald.terrarum.modulebasegame.gameactors
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))
}
}

View File

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

View File

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