Initial take on wires

This commit is contained in:
tobspr 2020-06-28 19:34:10 +02:00
parent b0cc9539d7
commit 0967d5114c
83 changed files with 2051 additions and 883 deletions

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cb9537349ef6920b23a1e1a601309a902d4eb05a1075c28b09189638686e2500
size 77571

BIN
artwork/twitch/brb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:22db7ba3795716bb5adf1d1eeb80af52ae7e4aa9e267324f5a541b90bf84e053
size 548633

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:27c8d1eaa48beb7187e37244bd6ef7f43429be84ac88fffa96a4d72eb0e6565b oid sha256:7f04a2e96f79d013838dc95e0fcc9c2c2b3519cedc5d44602ecde29b85558239
size 158809 size 174256

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:590751d33bdb2ffa0f3c7f533688f6f93c37940e1e906be7972c9d5757ab7f69 oid sha256:b0e6ae46466addd1bcb55a8005bbfb58fdf9e66c7fbae5620b723bdb21943b1c
size 57790 size 89487

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -872,9 +872,33 @@
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":16}, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":16},
"sourceSize": {"w":19,"h":19} "sourceSize": {"w":19,"h":19}
}, },
"sprites/blueprints/wire_left.png":
{
"frame": {"x":596,"y":71,"w":11,"h":11},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":11,"h":11},
"sourceSize": {"w":13,"h":13}
},
"sprites/blueprints/wire_right.png":
{
"frame": {"x":603,"y":54,"w":11,"h":11},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":11,"h":11},
"sourceSize": {"w":13,"h":13}
},
"sprites/blueprints/wire_top.png":
{
"frame": {"x":617,"y":20,"w":9,"h":13},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":9,"h":13},
"sourceSize": {"w":13,"h":13}
},
"sprites/buildings/belt_left.png": "sprites/buildings/belt_left.png":
{ {
"frame": {"x":570,"y":105,"w":13,"h":13}, "frame": {"x":603,"y":3,"w":13,"h":13},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -882,7 +906,7 @@
}, },
"sprites/buildings/belt_right.png": "sprites/buildings/belt_right.png":
{ {
"frame": {"x":582,"y":88,"w":13,"h":13}, "frame": {"x":570,"y":105,"w":13,"h":13},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -1080,6 +1104,30 @@
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":16}, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":16},
"sourceSize": {"w":19,"h":19} "sourceSize": {"w":19,"h":19}
}, },
"sprites/buildings/wire_left.png":
{
"frame": {"x":615,"y":37,"w":11,"h":11},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":11,"h":11},
"sourceSize": {"w":13,"h":13}
},
"sprites/buildings/wire_right.png":
{
"frame": {"x":587,"y":105,"w":11,"h":11},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":11,"h":11},
"sourceSize": {"w":13,"h":13}
},
"sprites/buildings/wire_top.png":
{
"frame": {"x":614,"y":84,"w":9,"h":13},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":9,"h":13},
"sourceSize": {"w":13,"h":13}
},
"sprites/debug/acceptor_slot.png": "sprites/debug/acceptor_slot.png":
{ {
"frame": {"x":82,"y":72,"w":6,"h":6}, "frame": {"x":82,"y":72,"w":6,"h":6},
@ -1122,7 +1170,7 @@
}, },
"sprites/misc/deletion_marker.png": "sprites/misc/deletion_marker.png":
{ {
"frame": {"x":603,"y":3,"w":10,"h":10}, "frame": {"x":602,"y":101,"w":10,"h":10},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":10,"h":10}, "spriteSourceSize": {"x":0,"y":0,"w":10,"h":10},
@ -1146,7 +1194,7 @@
}, },
"sprites/misc/slot_bad_arrow.png": "sprites/misc/slot_bad_arrow.png":
{ {
"frame": {"x":603,"y":3,"w":10,"h":10}, "frame": {"x":602,"y":101,"w":10,"h":10},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":10,"h":10}, "spriteSourceSize": {"x":0,"y":0,"w":10,"h":10},
@ -1154,7 +1202,7 @@
}, },
"sprites/misc/slot_good_arrow.png": "sprites/misc/slot_good_arrow.png":
{ {
"frame": {"x":603,"y":54,"w":10,"h":10}, "frame": {"x":602,"y":115,"w":10,"h":10},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":10,"h":10}, "spriteSourceSize": {"x":0,"y":0,"w":10,"h":10},
@ -1178,18 +1226,26 @@
}, },
"sprites/misc/wires_overlay_tile.png": "sprites/misc/wires_overlay_tile.png":
{ {
"frame": {"x":596,"y":71,"w":13,"h":13}, "frame": {"x":582,"y":88,"w":13,"h":13},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
"sourceSize": {"w":13,"h":13} "sourceSize": {"w":13,"h":13}
}, },
"sprites/wires/pin-energy-on.png": "sprites/wires/pin-negative-energy.png":
{ {
"frame": {"x":587,"y":105,"w":11,"h":11}, "frame": {"x":599,"y":86,"w":11,"h":11},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":11,"h":11}, "spriteSourceSize": {"x":1,"y":0,"w":11,"h":11},
"sourceSize": {"w":13,"h":13}
},
"sprites/wires/pin-positive-energy.png":
{
"frame": {"x":611,"y":69,"w":11,"h":11},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":11,"h":11},
"sourceSize": {"w":13,"h":13} "sourceSize": {"w":13,"h":13}
}}, }},
"meta": { "meta": {
@ -1197,8 +1253,8 @@
"version": "1.0", "version": "1.0",
"image": "atlas0_10.png", "image": "atlas0_10.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": {"w":616,"h":128}, "size": {"w":629,"h":128},
"scale": "0.1", "scale": "0.1",
"smartupdate": "$TexturePacker:SmartUpdate:1e5c68ef1fd4026b263679a3171f1832:b30cc36f2dfbe8399542e279c203efaf:f159918d23e5952766c6d23ab52278c6$" "smartupdate": "$TexturePacker:SmartUpdate:9ea1a09cb2003bf62ce57f52404292e0:0fc8d0e33f315e93d6d057148d691370:f159918d23e5952766c6d23ab52278c6$"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 63 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 201 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 471 KiB

After

Width:  |  Height:  |  Size: 476 KiB

View File

@ -2,7 +2,7 @@
"sprites/belt/forward_0.png": "sprites/belt/forward_0.png":
{ {
"frame": {"x":1880,"y":594,"w":77,"h":95}, "frame": {"x":1879,"y":594,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -18,7 +18,7 @@
}, },
"sprites/belt/forward_2.png": "sprites/belt/forward_2.png":
{ {
"frame": {"x":1509,"y":1071,"w":77,"h":95}, "frame": {"x":1960,"y":537,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -26,7 +26,7 @@
}, },
"sprites/belt/forward_3.png": "sprites/belt/forward_3.png":
{ {
"frame": {"x":1680,"y":923,"w":77,"h":95}, "frame": {"x":1838,"y":1153,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -34,7 +34,7 @@
}, },
"sprites/belt/forward_4.png": "sprites/belt/forward_4.png":
{ {
"frame": {"x":1680,"y":1022,"w":77,"h":95}, "frame": {"x":1757,"y":1252,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -42,7 +42,7 @@
}, },
"sprites/belt/forward_5.png": "sprites/belt/forward_5.png":
{ {
"frame": {"x":1770,"y":1049,"w":77,"h":95}, "frame": {"x":1838,"y":1252,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -50,7 +50,7 @@
}, },
"sprites/belt/forward_6.png": "sprites/belt/forward_6.png":
{ {
"frame": {"x":1770,"y":1148,"w":77,"h":95}, "frame": {"x":1919,"y":1185,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -58,7 +58,7 @@
}, },
"sprites/belt/forward_7.png": "sprites/belt/forward_7.png":
{ {
"frame": {"x":1768,"y":1247,"w":77,"h":95}, "frame": {"x":1919,"y":1284,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -66,7 +66,7 @@
}, },
"sprites/belt/forward_8.png": "sprites/belt/forward_8.png":
{ {
"frame": {"x":713,"y":1307,"w":77,"h":95}, "frame": {"x":1323,"y":1290,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -74,7 +74,7 @@
}, },
"sprites/belt/forward_9.png": "sprites/belt/forward_9.png":
{ {
"frame": {"x":974,"y":1239,"w":77,"h":95}, "frame": {"x":1404,"y":1293,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -90,7 +90,7 @@
}, },
"sprites/belt/forward_11.png": "sprites/belt/forward_11.png":
{ {
"frame": {"x":1428,"y":806,"w":77,"h":95}, "frame": {"x":1428,"y":816,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -106,7 +106,7 @@
}, },
"sprites/belt/forward_13.png": "sprites/belt/forward_13.png":
{ {
"frame": {"x":1509,"y":873,"w":77,"h":95}, "frame": {"x":1428,"y":915,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -114,7 +114,7 @@
}, },
"sprites/belt/forward_14.png": "sprites/belt/forward_14.png":
{ {
"frame": {"x":1428,"y":905,"w":77,"h":95}, "frame": {"x":1257,"y":920,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -122,7 +122,7 @@
}, },
"sprites/belt/forward_15.png": "sprites/belt/forward_15.png":
{ {
"frame": {"x":1509,"y":972,"w":77,"h":95}, "frame": {"x":1347,"y":1011,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -130,7 +130,7 @@
}, },
"sprites/belt/forward_16.png": "sprites/belt/forward_16.png":
{ {
"frame": {"x":692,"y":1121,"w":77,"h":95}, "frame": {"x":1428,"y":1014,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -138,7 +138,7 @@
}, },
"sprites/belt/forward_17.png": "sprites/belt/forward_17.png":
{ {
"frame": {"x":1257,"y":920,"w":77,"h":95}, "frame": {"x":1779,"y":865,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -146,7 +146,7 @@
}, },
"sprites/belt/forward_18.png": "sprites/belt/forward_18.png":
{ {
"frame": {"x":1428,"y":1004,"w":77,"h":95}, "frame": {"x":1779,"y":964,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -154,7 +154,7 @@
}, },
"sprites/belt/forward_19.png": "sprites/belt/forward_19.png":
{ {
"frame": {"x":1257,"y":1019,"w":77,"h":95}, "frame": {"x":1869,"y":1054,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -162,7 +162,7 @@
}, },
"sprites/belt/forward_20.png": "sprites/belt/forward_20.png":
{ {
"frame": {"x":1327,"y":1118,"w":77,"h":95}, "frame": {"x":1960,"y":636,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -170,7 +170,7 @@
}, },
"sprites/belt/forward_21.png": "sprites/belt/forward_21.png":
{ {
"frame": {"x":1417,"y":1193,"w":77,"h":95}, "frame": {"x":684,"y":1138,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -178,7 +178,7 @@
}, },
"sprites/belt/forward_22.png": "sprites/belt/forward_22.png":
{ {
"frame": {"x":1417,"y":1292,"w":77,"h":95}, "frame": {"x":988,"y":1239,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -186,7 +186,7 @@
}, },
"sprites/belt/forward_23.png": "sprites/belt/forward_23.png":
{ {
"frame": {"x":1961,"y":537,"w":77,"h":95}, "frame": {"x":1595,"y":1143,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -194,7 +194,7 @@
}, },
"sprites/belt/forward_24.png": "sprites/belt/forward_24.png":
{ {
"frame": {"x":1961,"y":636,"w":77,"h":95}, "frame": {"x":1676,"y":1140,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -202,7 +202,7 @@
}, },
"sprites/belt/forward_25.png": "sprites/belt/forward_25.png":
{ {
"frame": {"x":1880,"y":693,"w":77,"h":95}, "frame": {"x":1595,"y":1242,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -210,7 +210,7 @@
}, },
"sprites/belt/forward_26.png": "sprites/belt/forward_26.png":
{ {
"frame": {"x":1961,"y":735,"w":77,"h":95}, "frame": {"x":1676,"y":1239,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -218,7 +218,7 @@
}, },
"sprites/belt/forward_27.png": "sprites/belt/forward_27.png":
{ {
"frame": {"x":1680,"y":824,"w":77,"h":95}, "frame": {"x":1757,"y":1153,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -242,7 +242,7 @@
}, },
"sprites/belt/left_2.png": "sprites/belt/left_2.png":
{ {
"frame": {"x":1595,"y":734,"w":86,"h":86}, "frame": {"x":1590,"y":780,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -250,7 +250,7 @@
}, },
"sprites/belt/left_3.png": "sprites/belt/left_3.png":
{ {
"frame": {"x":1590,"y":1094,"w":86,"h":86}, "frame": {"x":1257,"y":1019,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -258,7 +258,7 @@
}, },
"sprites/belt/left_4.png": "sprites/belt/left_4.png":
{ {
"frame": {"x":1057,"y":1141,"w":86,"h":86}, "frame": {"x":1509,"y":1053,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -266,7 +266,7 @@
}, },
"sprites/belt/left_5.png": "sprites/belt/left_5.png":
{ {
"frame": {"x":1147,"y":1159,"w":86,"h":86}, "frame": {"x":1599,"y":1050,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -274,7 +274,7 @@
}, },
"sprites/belt/left_6.png": "sprites/belt/left_6.png":
{ {
"frame": {"x":1237,"y":1118,"w":86,"h":86}, "frame": {"x":1689,"y":1050,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -282,7 +282,7 @@
}, },
"sprites/belt/left_7.png": "sprites/belt/left_7.png":
{ {
"frame": {"x":1237,"y":1208,"w":86,"h":86}, "frame": {"x":1235,"y":1109,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -290,7 +290,7 @@
}, },
"sprites/belt/left_8.png": "sprites/belt/left_8.png":
{ {
"frame": {"x":1327,"y":1217,"w":86,"h":86}, "frame": {"x":1325,"y":1110,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -298,7 +298,7 @@
}, },
"sprites/belt/left_9.png": "sprites/belt/left_9.png":
{ {
"frame": {"x":1408,"y":1103,"w":86,"h":86}, "frame": {"x":1415,"y":1113,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -330,7 +330,7 @@
}, },
"sprites/belt/left_13.png": "sprites/belt/left_13.png":
{ {
"frame": {"x":1057,"y":1051,"w":86,"h":86}, "frame": {"x":1055,"y":1051,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -346,7 +346,7 @@
}, },
"sprites/belt/left_15.png": "sprites/belt/left_15.png":
{ {
"frame": {"x":1147,"y":1069,"w":86,"h":86}, "frame": {"x":1145,"y":1069,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -386,7 +386,7 @@
}, },
"sprites/belt/left_20.png": "sprites/belt/left_20.png":
{ {
"frame": {"x":1590,"y":824,"w":86,"h":86}, "frame": {"x":1680,"y":780,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -394,7 +394,7 @@
}, },
"sprites/belt/left_21.png": "sprites/belt/left_21.png":
{ {
"frame": {"x":1590,"y":914,"w":86,"h":86}, "frame": {"x":1509,"y":873,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -402,7 +402,7 @@
}, },
"sprites/belt/left_22.png": "sprites/belt/left_22.png":
{ {
"frame": {"x":1590,"y":1004,"w":86,"h":86}, "frame": {"x":1599,"y":870,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -410,7 +410,7 @@
}, },
"sprites/belt/left_23.png": "sprites/belt/left_23.png":
{ {
"frame": {"x":773,"y":1149,"w":86,"h":86}, "frame": {"x":1689,"y":870,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -418,7 +418,7 @@
}, },
"sprites/belt/left_24.png": "sprites/belt/left_24.png":
{ {
"frame": {"x":863,"y":1149,"w":86,"h":86}, "frame": {"x":1509,"y":963,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -426,7 +426,7 @@
}, },
"sprites/belt/left_25.png": "sprites/belt/left_25.png":
{ {
"frame": {"x":953,"y":1149,"w":86,"h":86}, "frame": {"x":1599,"y":960,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -434,7 +434,7 @@
}, },
"sprites/belt/left_26.png": "sprites/belt/left_26.png":
{ {
"frame": {"x":1338,"y":921,"w":86,"h":86}, "frame": {"x":1689,"y":960,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -442,7 +442,7 @@
}, },
"sprites/belt/left_27.png": "sprites/belt/left_27.png":
{ {
"frame": {"x":1338,"y":1011,"w":86,"h":86}, "frame": {"x":1338,"y":921,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -450,7 +450,7 @@
}, },
"sprites/belt/right_0.png": "sprites/belt/right_0.png":
{ {
"frame": {"x":1498,"y":1170,"w":86,"h":86}, "frame": {"x":1505,"y":1143,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -458,7 +458,7 @@
}, },
"sprites/belt/right_1.png": "sprites/belt/right_1.png":
{ {
"frame": {"x":1588,"y":1184,"w":86,"h":86}, "frame": {"x":1055,"y":1141,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -466,7 +466,7 @@
}, },
"sprites/belt/right_2.png": "sprites/belt/right_2.png":
{ {
"frame": {"x":1851,"y":972,"w":86,"h":86}, "frame": {"x":1950,"y":735,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -474,7 +474,7 @@
}, },
"sprites/belt/right_3.png": "sprites/belt/right_3.png":
{ {
"frame": {"x":1941,"y":1284,"w":86,"h":86}, "frame": {"x":808,"y":1239,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -482,7 +482,7 @@
}, },
"sprites/belt/right_4.png": "sprites/belt/right_4.png":
{ {
"frame": {"x":794,"y":1239,"w":86,"h":86}, "frame": {"x":898,"y":1239,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -490,7 +490,7 @@
}, },
"sprites/belt/right_5.png": "sprites/belt/right_5.png":
{ {
"frame": {"x":884,"y":1239,"w":86,"h":86}, "frame": {"x":718,"y":1329,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -498,7 +498,7 @@
}, },
"sprites/belt/right_6.png": "sprites/belt/right_6.png":
{ {
"frame": {"x":794,"y":1329,"w":86,"h":86}, "frame": {"x":808,"y":1329,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -506,7 +506,7 @@
}, },
"sprites/belt/right_7.png": "sprites/belt/right_7.png":
{ {
"frame": {"x":884,"y":1329,"w":86,"h":86}, "frame": {"x":898,"y":1329,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -514,7 +514,7 @@
}, },
"sprites/belt/right_8.png": "sprites/belt/right_8.png":
{ {
"frame": {"x":1055,"y":1231,"w":86,"h":86}, "frame": {"x":988,"y":1338,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -522,7 +522,7 @@
}, },
"sprites/belt/right_9.png": "sprites/belt/right_9.png":
{ {
"frame": {"x":1145,"y":1249,"w":86,"h":86}, "frame": {"x":1143,"y":1249,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -530,7 +530,7 @@
}, },
"sprites/belt/right_10.png": "sprites/belt/right_10.png":
{ {
"frame": {"x":1498,"y":1260,"w":86,"h":86}, "frame": {"x":1145,"y":1159,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -538,7 +538,7 @@
}, },
"sprites/belt/right_11.png": "sprites/belt/right_11.png":
{ {
"frame": {"x":1588,"y":1274,"w":86,"h":86}, "frame": {"x":1235,"y":1199,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -546,7 +546,7 @@
}, },
"sprites/belt/right_12.png": "sprites/belt/right_12.png":
{ {
"frame": {"x":1680,"y":1121,"w":86,"h":86}, "frame": {"x":1325,"y":1200,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -554,7 +554,7 @@
}, },
"sprites/belt/right_13.png": "sprites/belt/right_13.png":
{ {
"frame": {"x":1678,"y":1211,"w":86,"h":86}, "frame": {"x":1415,"y":1203,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -562,7 +562,7 @@
}, },
"sprites/belt/right_14.png": "sprites/belt/right_14.png":
{ {
"frame": {"x":1678,"y":1301,"w":86,"h":86}, "frame": {"x":1505,"y":1233,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -570,7 +570,7 @@
}, },
"sprites/belt/right_15.png": "sprites/belt/right_15.png":
{ {
"frame": {"x":1761,"y":779,"w":86,"h":86}, "frame": {"x":1770,"y":709,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -578,7 +578,7 @@
}, },
"sprites/belt/right_16.png": "sprites/belt/right_16.png":
{ {
"frame": {"x":1761,"y":869,"w":86,"h":86}, "frame": {"x":1779,"y":1063,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -586,7 +586,7 @@
}, },
"sprites/belt/right_17.png": "sprites/belt/right_17.png":
{ {
"frame": {"x":1761,"y":959,"w":86,"h":86}, "frame": {"x":1860,"y":709,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -594,7 +594,7 @@
}, },
"sprites/belt/right_18.png": "sprites/belt/right_18.png":
{ {
"frame": {"x":1851,"y":792,"w":86,"h":86}, "frame": {"x":1860,"y":799,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -602,7 +602,7 @@
}, },
"sprites/belt/right_19.png": "sprites/belt/right_19.png":
{ {
"frame": {"x":1851,"y":882,"w":86,"h":86}, "frame": {"x":1860,"y":889,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -610,7 +610,7 @@
}, },
"sprites/belt/right_20.png": "sprites/belt/right_20.png":
{ {
"frame": {"x":1941,"y":834,"w":86,"h":86}, "frame": {"x":1950,"y":825,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -618,7 +618,7 @@
}, },
"sprites/belt/right_21.png": "sprites/belt/right_21.png":
{ {
"frame": {"x":1941,"y":924,"w":86,"h":86}, "frame": {"x":1950,"y":915,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -626,7 +626,7 @@
}, },
"sprites/belt/right_22.png": "sprites/belt/right_22.png":
{ {
"frame": {"x":1941,"y":1014,"w":86,"h":86}, "frame": {"x":1950,"y":1005,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -634,7 +634,7 @@
}, },
"sprites/belt/right_23.png": "sprites/belt/right_23.png":
{ {
"frame": {"x":1851,"y":1062,"w":86,"h":86}, "frame": {"x":1950,"y":1095,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -642,7 +642,7 @@
}, },
"sprites/belt/right_24.png": "sprites/belt/right_24.png":
{ {
"frame": {"x":1851,"y":1152,"w":86,"h":86}, "frame": {"x":765,"y":1149,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -650,7 +650,7 @@
}, },
"sprites/belt/right_25.png": "sprites/belt/right_25.png":
{ {
"frame": {"x":1941,"y":1104,"w":86,"h":86}, "frame": {"x":855,"y":1149,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -658,7 +658,7 @@
}, },
"sprites/belt/right_26.png": "sprites/belt/right_26.png":
{ {
"frame": {"x":1941,"y":1194,"w":86,"h":86}, "frame": {"x":945,"y":1149,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -666,7 +666,7 @@
}, },
"sprites/belt/right_27.png": "sprites/belt/right_27.png":
{ {
"frame": {"x":1851,"y":1242,"w":86,"h":86}, "frame": {"x":718,"y":1239,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -690,7 +690,7 @@
}, },
"sprites/blueprints/belt_top.png": "sprites/blueprints/belt_top.png":
{ {
"frame": {"x":692,"y":1022,"w":79,"h":95}, "frame": {"x":690,"y":1022,"w":79,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":8,"y":0,"w":79,"h":95}, "spriteSourceSize": {"x":8,"y":0,"w":79,"h":95},
@ -794,7 +794,7 @@
}, },
"sprites/blueprints/splitter-compact-inverse.png": "sprites/blueprints/splitter-compact-inverse.png":
{ {
"frame": {"x":257,"y":1141,"w":142,"h":138}, "frame": {"x":3,"y":1286,"w":142,"h":138},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":142,"h":138}, "spriteSourceSize": {"x":0,"y":2,"w":142,"h":138},
@ -802,7 +802,7 @@
}, },
"sprites/blueprints/splitter-compact.png": "sprites/blueprints/splitter-compact.png":
{ {
"frame": {"x":543,"y":1162,"w":139,"h":138}, "frame": {"x":149,"y":1286,"w":139,"h":138},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":2,"w":139,"h":138}, "spriteSourceSize": {"x":5,"y":2,"w":139,"h":138},
@ -842,7 +842,7 @@
}, },
"sprites/blueprints/underground_belt_entry-tier2.png": "sprites/blueprints/underground_belt_entry-tier2.png":
{ {
"frame": {"x":3,"y":1286,"w":138,"h":125}, "frame": {"x":542,"y":1138,"w":138,"h":125},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":4,"y":19,"w":138,"h":125}, "spriteSourceSize": {"x":4,"y":19,"w":138,"h":125},
@ -850,7 +850,7 @@
}, },
"sprites/blueprints/underground_belt_entry.png": "sprites/blueprints/underground_belt_entry.png":
{ {
"frame": {"x":429,"y":1304,"w":138,"h":112}, "frame": {"x":576,"y":1267,"w":138,"h":112},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":4,"y":32,"w":138,"h":112}, "spriteSourceSize": {"x":4,"y":32,"w":138,"h":112},
@ -858,7 +858,7 @@
}, },
"sprites/blueprints/underground_belt_exit-tier2.png": "sprites/blueprints/underground_belt_exit-tier2.png":
{ {
"frame": {"x":286,"y":1304,"w":139,"h":112}, "frame": {"x":547,"y":1022,"w":139,"h":112},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":139,"h":112}, "spriteSourceSize": {"x":4,"y":0,"w":139,"h":112},
@ -866,15 +866,39 @@
}, },
"sprites/blueprints/underground_belt_exit.png": "sprites/blueprints/underground_belt_exit.png":
{ {
"frame": {"x":571,"y":1304,"w":138,"h":112}, "frame": {"x":1596,"y":594,"w":138,"h":112},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":138,"h":112}, "spriteSourceSize": {"x":4,"y":0,"w":138,"h":112},
"sourceSize": {"w":144,"h":144} "sourceSize": {"w":144,"h":144}
}, },
"sprites/blueprints/wire_left.png":
{
"frame": {"x":1428,"y":741,"w":71,"h":71},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":24,"w":71,"h":71},
"sourceSize": {"w":95,"h":95}
},
"sprites/blueprints/wire_right.png":
{
"frame": {"x":1860,"y":979,"w":71,"h":71},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":24,"y":24,"w":71,"h":71},
"sourceSize": {"w":95,"h":95}
},
"sprites/blueprints/wire_top.png":
{
"frame": {"x":1963,"y":3,"w":47,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":24,"y":0,"w":47,"h":95},
"sourceSize": {"w":95,"h":95}
},
"sprites/buildings/belt_left.png": "sprites/buildings/belt_left.png":
{ {
"frame": {"x":1235,"y":1298,"w":86,"h":86}, "frame": {"x":1078,"y":1339,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -882,7 +906,7 @@
}, },
"sprites/buildings/belt_right.png": "sprites/buildings/belt_right.png":
{ {
"frame": {"x":1325,"y":1307,"w":86,"h":86}, "frame": {"x":1168,"y":1339,"w":86,"h":86},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -890,7 +914,7 @@
}, },
"sprites/buildings/belt_top.png": "sprites/buildings/belt_top.png":
{ {
"frame": {"x":1880,"y":594,"w":77,"h":95}, "frame": {"x":1879,"y":594,"w":77,"h":95},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -938,7 +962,7 @@
}, },
"sprites/buildings/miner.png": "sprites/buildings/miner.png":
{ {
"frame": {"x":403,"y":1135,"w":136,"h":142}, "frame": {"x":402,"y":1135,"w":136,"h":142},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":142}, "spriteSourceSize": {"x":5,"y":0,"w":136,"h":142},
@ -1002,7 +1026,7 @@
}, },
"sprites/buildings/splitter-compact-inverse.png": "sprites/buildings/splitter-compact-inverse.png":
{ {
"frame": {"x":547,"y":1022,"w":141,"h":136}, "frame": {"x":257,"y":1141,"w":141,"h":136},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":3,"w":141,"h":136}, "spriteSourceSize": {"x":0,"y":3,"w":141,"h":136},
@ -1010,7 +1034,7 @@
}, },
"sprites/buildings/splitter-compact.png": "sprites/buildings/splitter-compact.png":
{ {
"frame": {"x":1596,"y":594,"w":139,"h":136}, "frame": {"x":292,"y":1281,"w":139,"h":136},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":3,"w":139,"h":136}, "spriteSourceSize": {"x":5,"y":3,"w":139,"h":136},
@ -1050,7 +1074,7 @@
}, },
"sprites/buildings/underground_belt_entry-tier2.png": "sprites/buildings/underground_belt_entry-tier2.png":
{ {
"frame": {"x":145,"y":1286,"w":137,"h":124}, "frame": {"x":435,"y":1281,"w":137,"h":124},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":20,"w":137,"h":124}, "spriteSourceSize": {"x":5,"y":20,"w":137,"h":124},
@ -1058,7 +1082,7 @@
}, },
"sprites/buildings/underground_belt_entry.png": "sprites/buildings/underground_belt_entry.png":
{ {
"frame": {"x":1739,"y":594,"w":137,"h":111}, "frame": {"x":1738,"y":594,"w":137,"h":111},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":33,"w":137,"h":111}, "spriteSourceSize": {"x":5,"y":33,"w":137,"h":111},
@ -1066,7 +1090,7 @@
}, },
"sprites/buildings/underground_belt_exit-tier2.png": "sprites/buildings/underground_belt_exit-tier2.png":
{ {
"frame": {"x":775,"y":1034,"w":137,"h":111}, "frame": {"x":773,"y":1034,"w":137,"h":111},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111}, "spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
@ -1074,15 +1098,39 @@
}, },
"sprites/buildings/underground_belt_exit.png": "sprites/buildings/underground_belt_exit.png":
{ {
"frame": {"x":916,"y":1034,"w":137,"h":111}, "frame": {"x":914,"y":1034,"w":137,"h":111},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111}, "spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
"sourceSize": {"w":144,"h":144} "sourceSize": {"w":144,"h":144}
}, },
"sprites/buildings/wire_left.png":
{
"frame": {"x":1069,"y":1231,"w":70,"h":70},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":25,"w":70,"h":70},
"sourceSize": {"w":95,"h":95}
},
"sprites/buildings/wire_right.png":
{
"frame": {"x":1485,"y":1323,"w":70,"h":70},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":25,"y":25,"w":70,"h":70},
"sourceSize": {"w":95,"h":95}
},
"sprites/buildings/wire_top.png":
{
"frame": {"x":1963,"y":102,"w":45,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":25,"y":0,"w":45,"h":95},
"sourceSize": {"w":95,"h":95}
},
"sprites/debug/acceptor_slot.png": "sprites/debug/acceptor_slot.png":
{ {
"frame": {"x":1963,"y":145,"w":38,"h":48}, "frame": {"x":2000,"y":1185,"w":38,"h":48},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":38,"h":48}, "spriteSourceSize": {"x":5,"y":0,"w":38,"h":48},
@ -1090,7 +1138,7 @@
}, },
"sprites/debug/ejector_slot.png": "sprites/debug/ejector_slot.png":
{ {
"frame": {"x":1685,"y":734,"w":38,"h":48}, "frame": {"x":2000,"y":1237,"w":38,"h":48},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":38,"h":48}, "spriteSourceSize": {"x":5,"y":0,"w":38,"h":48},
@ -1098,7 +1146,7 @@
}, },
"sprites/map_overview/belt_forward.png": "sprites/map_overview/belt_forward.png":
{ {
"frame": {"x":1768,"y":1346,"w":20,"h":24}, "frame": {"x":1836,"y":799,"w":20,"h":24},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24}, "spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -1106,7 +1154,7 @@
}, },
"sprites/map_overview/belt_left.png": "sprites/map_overview/belt_left.png":
{ {
"frame": {"x":1935,"y":537,"w":22,"h":22}, "frame": {"x":2014,"y":3,"w":22,"h":22},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":22,"h":22}, "spriteSourceSize": {"x":0,"y":2,"w":22,"h":22},
@ -1114,7 +1162,7 @@
}, },
"sprites/map_overview/belt_right.png": "sprites/map_overview/belt_right.png":
{ {
"frame": {"x":1935,"y":563,"w":22,"h":22}, "frame": {"x":684,"y":1237,"w":22,"h":22},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":22,"h":22}, "spriteSourceSize": {"x":2,"y":2,"w":22,"h":22},
@ -1122,7 +1170,7 @@
}, },
"sprites/misc/deletion_marker.png": "sprites/misc/deletion_marker.png":
{ {
"frame": {"x":1963,"y":79,"w":62,"h":62}, "frame": {"x":1770,"y":799,"w":62,"h":62},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":62,"h":62}, "spriteSourceSize": {"x":5,"y":5,"w":62,"h":62},
@ -1138,7 +1186,7 @@
}, },
"sprites/misc/lock_direction_indicator.png": "sprites/misc/lock_direction_indicator.png":
{ {
"frame": {"x":1498,"y":1350,"w":36,"h":24}, "frame": {"x":1069,"y":1305,"w":36,"h":24},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":36,"h":24}, "spriteSourceSize": {"x":0,"y":6,"w":36,"h":24},
@ -1146,7 +1194,7 @@
}, },
"sprites/misc/slot_bad_arrow.png": "sprites/misc/slot_bad_arrow.png":
{ {
"frame": {"x":1963,"y":79,"w":62,"h":62}, "frame": {"x":1770,"y":799,"w":62,"h":62},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":62,"h":62}, "spriteSourceSize": {"x":5,"y":5,"w":62,"h":62},
@ -1154,7 +1202,7 @@
}, },
"sprites/misc/slot_good_arrow.png": "sprites/misc/slot_good_arrow.png":
{ {
"frame": {"x":1963,"y":3,"w":62,"h":72}, "frame": {"x":1963,"y":201,"w":62,"h":72},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":62,"h":72}, "spriteSourceSize": {"x":5,"y":0,"w":62,"h":72},
@ -1162,7 +1210,7 @@
}, },
"sprites/misc/storage_overlay.png": "sprites/misc/storage_overlay.png":
{ {
"frame": {"x":1739,"y":709,"w":133,"h":66}, "frame": {"x":1595,"y":710,"w":133,"h":66},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":133,"h":66}, "spriteSourceSize": {"x":2,"y":2,"w":133,"h":66},
@ -1170,7 +1218,7 @@
}, },
"sprites/misc/waypoint.png": "sprites/misc/waypoint.png":
{ {
"frame": {"x":974,"y":1338,"w":20,"h":24}, "frame": {"x":1836,"y":827,"w":20,"h":24},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24}, "spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -1184,12 +1232,20 @@
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
"sourceSize": {"w":96,"h":96} "sourceSize": {"w":96,"h":96}
}, },
"sprites/wires/pin-energy-on.png": "sprites/wires/pin-negative-energy.png":
{ {
"frame": {"x":1428,"y":741,"w":61,"h":61}, "frame": {"x":1258,"y":1289,"w":61,"h":71},
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": {"x":17,"y":17,"w":61,"h":61}, "spriteSourceSize": {"x":17,"y":0,"w":61,"h":71},
"sourceSize": {"w":96,"h":96}
},
"sprites/wires/pin-positive-energy.png":
{
"frame": {"x":1559,"y":1341,"w":61,"h":71},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":17,"y":0,"w":61,"h":71},
"sourceSize": {"w":96,"h":96} "sourceSize": {"w":96,"h":96}
}}, }},
"meta": { "meta": {
@ -1197,8 +1253,8 @@
"version": "1.0", "version": "1.0",
"image": "atlas0_75.png", "image": "atlas0_75.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": {"w":2042,"h":1419}, "size": {"w":2042,"h":1428},
"scale": "0.75", "scale": "0.75",
"smartupdate": "$TexturePacker:SmartUpdate:1e5c68ef1fd4026b263679a3171f1832:b30cc36f2dfbe8399542e279c203efaf:f159918d23e5952766c6d23ab52278c6$" "smartupdate": "$TexturePacker:SmartUpdate:9ea1a09cb2003bf62ce57f52404292e0:0fc8d0e33f315e93d6d057148d691370:f159918d23e5952766c6d23ab52278c6$"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 980 KiB

After

Width:  |  Height:  |  Size: 956 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -1,5 +1,5 @@
$buildings: belt, cutter, miner, mixer, painter, rotater, splitter, stacker, trash, underground_belt, $buildings: belt, cutter, miner, mixer, painter, rotater, splitter, stacker, trash, underground_belt,
energy_generator; energy_generator, wire;
@each $building in $buildings { @each $building in $buildings {
[data-icon="building_icons/#{$building}.png"] { [data-icon="building_icons/#{$building}.png"] {

View File

@ -1,4 +1,4 @@
#ingame_HUD_buildings_toolbar { .ingame_buildingsToolbar {
position: fixed; position: fixed;
@include S(bottom, 0px); @include S(bottom, 0px);
left: 50%; left: 50%;

View File

@ -74,6 +74,7 @@ ingame_HUD_EntityDebugger,
ingame_HUD_InteractiveTutorial, ingame_HUD_InteractiveTutorial,
ingame_HUD_TutorialHints, ingame_HUD_TutorialHints,
ingame_HUD_buildings_toolbar, ingame_HUD_buildings_toolbar,
ingame_HUD_wires_toolbar,
ingame_HUD_BlueprintPlacer, ingame_HUD_BlueprintPlacer,
ingame_HUD_Waypoints_Hint, ingame_HUD_Waypoints_Hint,
ingame_HUD_Watermark, ingame_HUD_Watermark,

View File

@ -35,7 +35,7 @@ export default {
// Unlocks all buildings // Unlocks all buildings
// allBuildingsUnlocked: true, // allBuildingsUnlocked: true,
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
// Disables cost of bluepirnts // Disables cost of blueprints
// blueprintsNoCost: true, // blueprintsNoCost: true,
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
// Disables cost of upgrades // Disables cost of upgrades
@ -92,5 +92,8 @@ export default {
// Whether to check belt paths // Whether to check belt paths
// checkBeltPaths: true, // checkBeltPaths: true,
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
// Whether to items / s instead of items / m in stats
// detailedStatistics: true,
// -----------------------------------------------------------------------------------
/* dev:end */ /* dev:end */
}; };

View File

@ -5,6 +5,8 @@ import { BasicSerializableObject } from "../savegame/serialization";
export const enumItemType = { export const enumItemType = {
shape: "shape", shape: "shape",
color: "color", color: "color",
positiveEnergy: "positiveEnergy",
negativeEnergy: "negativeEnergy",
}; };
/** /**

View File

@ -5,7 +5,7 @@ import { epsilonCompare, round4Digits } from "../core/utils";
import { Vector } from "../core/vector"; import { Vector } from "../core/vector";
import { BaseItem } from "./base_item"; import { BaseItem } from "./base_item";
import { Entity } from "./entity"; import { Entity } from "./entity";
import { GameRoot } from "./root"; import { GameRoot, enumLayer } from "./root";
import { Rectangle } from "../core/rectangle"; import { Rectangle } from "../core/rectangle";
import { BasicSerializableObject, types } from "../savegame/serialization"; import { BasicSerializableObject, types } from "../savegame/serialization";
import { gItemRegistry } from "../core/global_registries"; import { gItemRegistry } from "../core/global_registries";
@ -120,6 +120,14 @@ export class BeltPath extends BasicSerializableObject {
return this.spacingToFirstItem >= globalConfig.itemSpacingOnBelts; return this.spacingToFirstItem >= globalConfig.itemSpacingOnBelts;
} }
/**
* Returns the layer of the this path
* @returns {enumLayer}
*/
get layer() {
return this.entityPath[0].layer;
}
/** /**
* Tries to accept the item * Tries to accept the item
* @param {BaseItem} item * @param {BaseItem} item
@ -1029,6 +1037,11 @@ export class BeltPath extends BasicSerializableObject {
return; return;
} }
if (this.entityPath[0].layer !== this.root.currentLayer) {
// Don't draw
return;
}
parameters.context.fillStyle = "#d79a25"; parameters.context.fillStyle = "#d79a25";
parameters.context.strokeStyle = "#d79a25"; parameters.context.strokeStyle = "#d79a25";
parameters.context.beginPath(); parameters.context.beginPath();

View File

@ -3,7 +3,7 @@ import { Loader } from "../core/loader";
import { createLogger } from "../core/logging"; import { createLogger } from "../core/logging";
import { Vector } from "../core/vector"; import { Vector } from "../core/vector";
import { Entity } from "./entity"; import { Entity } from "./entity";
import { GameRoot } from "./root"; import { GameRoot, enumLayer } from "./root";
import { findNiceIntegerValue } from "../core/utils"; import { findNiceIntegerValue } from "../core/utils";
import { blueprintShape } from "./upgrades"; import { blueprintShape } from "./upgrades";
import { globalConfig } from "../core/config"; import { globalConfig } from "../core/config";
@ -18,6 +18,17 @@ export class Blueprint {
this.entities = entities; this.entities = entities;
} }
/**
* Returns the layer of this blueprint
* @returns {enumLayer}
*/
get layer() {
if (this.entities.length === 0) {
return enumLayer.regular;
}
return this.entities[0].layer;
}
/** /**
* Creates a new blueprint from the given entity uids * Creates a new blueprint from the given entity uids
* @param {GameRoot} root * @param {GameRoot} root
@ -183,7 +194,7 @@ export class Blueprint {
rect.moveBy(tile.x, tile.y); rect.moveBy(tile.x, tile.y);
placementCheck: for (let x = rect.x; x < rect.right(); ++x) { placementCheck: for (let x = rect.x; x < rect.right(); ++x) {
for (let y = rect.y; y < rect.bottom(); ++y) { for (let y = rect.y; y < rect.bottom(); ++y) {
const contents = root.map.getTileContentXY(x, y); const contents = root.map.getLayerContentXY(x, y, entity.layer);
if (contents && !contents.components.ReplaceableMapEntity) { if (contents && !contents.components.ReplaceableMapEntity) {
placeable = false; placeable = false;
break placementCheck; break placementCheck;
@ -194,7 +205,7 @@ export class Blueprint {
if (placeable) { if (placeable) {
for (let x = rect.x; x < rect.right(); ++x) { for (let x = rect.x; x < rect.right(); ++x) {
for (let y = rect.y; y < rect.bottom(); ++y) { for (let y = rect.y; y < rect.bottom(); ++y) {
const contents = root.map.getTileContentXY(x, y); const contents = root.map.getLayerContentXY(x, y, entity.layer);
if (contents) { if (contents) {
assert( assert(
contents.components.ReplaceableMapEntity, contents.components.ReplaceableMapEntity,

View File

@ -9,7 +9,7 @@ import { ItemEjectorComponent } from "../components/item_ejector";
import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity"; import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building"; import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot, enumLayer } from "../root";
export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right]; export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right];
@ -146,7 +146,7 @@ export class MetaBeltBaseBuilding extends MetaBuilding {
const bottomDirection = enumAngleToDirection[(rotation + 180) % 360]; const bottomDirection = enumAngleToDirection[(rotation + 180) % 360];
const leftDirection = enumAngleToDirection[(rotation + 270) % 360]; const leftDirection = enumAngleToDirection[(rotation + 270) % 360];
const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile); const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile, enumLayer.regular);
let hasBottomEjector = false; let hasBottomEjector = false;
let hasRightEjector = false; let hasRightEjector = false;

View File

@ -2,11 +2,12 @@ import { enumDirection, Vector } from "../../core/vector";
import { ItemAcceptorComponent } from "../components/item_acceptor"; import { ItemAcceptorComponent } from "../components/item_acceptor";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building"; import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot, enumLayer } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals"; import { enumHubGoalRewards } from "../tutorial_goals";
import { EnergyGeneratorComponent } from "../components/energy_generator"; import { EnergyGeneratorComponent } from "../components/energy_generator";
import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins"; import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins";
import { enumItemType } from "../base_item"; import { enumItemType } from "../base_item";
import { ItemEjectorComponent } from "../components/item_ejector";
export class MetaEnergyGenerator extends MetaBuilding { export class MetaEnergyGenerator extends MetaBuilding {
constructor() { constructor() {
@ -71,6 +72,25 @@ export class MetaEnergyGenerator extends MetaBuilding {
directions: [enumDirection.bottom], directions: [enumDirection.bottom],
filter: enumItemType.shape, filter: enumItemType.shape,
}, },
{
pos: new Vector(1, 0),
directions: [enumDirection.top],
layer: enumLayer.wires,
filter: enumItemType.negativeEnergy,
},
],
})
);
entity.addComponent(
new ItemEjectorComponent({
slots: [
{
pos: new Vector(0, 0),
direction: enumDirection.top,
layer: enumLayer.wires,
},
], ],
}) })
); );
@ -87,19 +107,13 @@ export class MetaEnergyGenerator extends MetaBuilding {
slots: [ slots: [
{ {
pos: new Vector(0, 0), pos: new Vector(0, 0),
type: enumPinSlotType.energyEjector, type: enumPinSlotType.positiveEnergyEjector,
direction: enumDirection.top,
}, },
{ {
pos: new Vector(1, 0), pos: new Vector(1, 0),
type: enumPinSlotType.energyEjector, type: enumPinSlotType.negativeEnergyAcceptor,
}, direction: enumDirection.top,
{
pos: new Vector(0, 1),
type: enumPinSlotType.energyEjector,
},
{
pos: new Vector(1, 1),
type: enumPinSlotType.energyEjector,
}, },
], ],
}) })

View File

@ -5,7 +5,7 @@ import { ItemEjectorComponent } from "../components/item_ejector";
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot, enumLayer } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals"; import { enumHubGoalRewards } from "../tutorial_goals";
import { T } from "../../translations"; import { T } from "../../translations";
import { formatItemsPerSecond } from "../../core/utils"; import { formatItemsPerSecond } from "../../core/utils";
@ -128,8 +128,8 @@ export class MetaSplitterBuilding extends MetaBuilding {
]); ]);
entity.components.ItemAcceptor.beltUnderlays = [ entity.components.ItemAcceptor.beltUnderlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top }, { pos: new Vector(0, 0), direction: enumDirection.top, layer: enumLayer.regular },
{ pos: new Vector(1, 0), direction: enumDirection.top }, { pos: new Vector(1, 0), direction: enumDirection.top, layer: enumLayer.regular },
]; ];
break; break;
@ -156,7 +156,7 @@ export class MetaSplitterBuilding extends MetaBuilding {
]); ]);
entity.components.ItemAcceptor.beltUnderlays = [ entity.components.ItemAcceptor.beltUnderlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top }, { pos: new Vector(0, 0), direction: enumDirection.top, layer: enumLayer.regular },
]; ];
break; break;

View File

@ -5,7 +5,7 @@ import { ItemEjectorComponent } from "../components/item_ejector";
import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt"; import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot, enumLayer } from "../root";
import { globalConfig } from "../../core/config"; import { globalConfig } from "../../core/config";
import { enumHubGoalRewards } from "../tutorial_goals"; import { enumHubGoalRewards } from "../tutorial_goals";
import { formatItemsPerSecond } from "../../core/utils"; import { formatItemsPerSecond } from "../../core/utils";
@ -152,7 +152,8 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding {
) { ) {
tile = tile.addScalars(searchVector.x, searchVector.y); tile = tile.addScalars(searchVector.x, searchVector.y);
const contents = root.map.getTileContent(tile); /* WIRES: FIXME */
const contents = root.map.getTileContent(tile, enumLayer.regular);
if (contents) { if (contents) {
const undergroundComp = contents.components.UndergroundBelt; const undergroundComp = contents.components.UndergroundBelt;
if (undergroundComp && undergroundComp.tier === tier) { if (undergroundComp && undergroundComp.tier === tier) {

View File

@ -0,0 +1,226 @@
import { Loader } from "../../core/loader";
import { enumAngleToDirection, enumDirection, Vector } from "../../core/vector";
import { SOUNDS } from "../../platform/sound";
import { BeltComponent } from "../components/belt";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity";
import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { enumLayer, GameRoot } from "../root";
export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right];
export class MetaWireBaseBuilding extends MetaBuilding {
constructor() {
super("wire");
}
getSilhouetteColor() {
return "#c425d7";
}
getLayer() {
return enumLayer.wires;
}
getHasDirectionLockAvailable() {
return true;
}
getPreviewSprite(rotationVariant) {
switch (arrayBeltVariantToRotation[rotationVariant]) {
case enumDirection.top: {
return Loader.getSprite("sprites/buildings/wire_top.png");
}
case enumDirection.left: {
return Loader.getSprite("sprites/buildings/wire_left.png");
}
case enumDirection.right: {
return Loader.getSprite("sprites/buildings/wire_right.png");
}
default: {
assertAlways(false, "Invalid belt rotation variant");
}
}
}
getBlueprintSprite(rotationVariant) {
switch (arrayBeltVariantToRotation[rotationVariant]) {
case enumDirection.top: {
return Loader.getSprite("sprites/blueprints/wire_top.png");
}
case enumDirection.left: {
return Loader.getSprite("sprites/blueprints/wire_left.png");
}
case enumDirection.right: {
return Loader.getSprite("sprites/blueprints/wire_right.png");
}
default: {
assertAlways(false, "Invalid belt rotation variant");
}
}
}
getStayInPlacementMode() {
return true;
}
getRotateAutomaticallyWhilePlacing() {
return true;
}
getPlacementSound() {
return SOUNDS.placeBelt;
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new BeltComponent({
direction: enumDirection.top, // updated later
})
);
entity.addComponent(
new ItemAcceptorComponent({
slots: [
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
layer: enumLayer.wires,
},
],
animated: false,
})
);
entity.addComponent(
new ItemEjectorComponent({
slots: [
{
pos: new Vector(0, 0),
direction: enumDirection.top, // updated later
layer: enumLayer.wires,
},
],
instantEject: true,
})
);
// Make this entity replaceable
entity.addComponent(new ReplaceableMapEntityComponent());
}
/**
* @param {Entity} entity
* @param {number} rotationVariant
*/
updateVariants(entity, rotationVariant) {
entity.components.Belt.direction = arrayBeltVariantToRotation[rotationVariant];
entity.components.ItemEjector.slots[0].direction = arrayBeltVariantToRotation[rotationVariant];
entity.components.StaticMapEntity.spriteKey = null;
}
/**
* Computes optimal belt rotation variant
* @param {GameRoot} root
* @param {Vector} tile
* @param {number} rotation
* @param {string} variant
* @return {{ rotation: number, rotationVariant: number }}
*/
computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) {
const topDirection = enumAngleToDirection[rotation];
const rightDirection = enumAngleToDirection[(rotation + 90) % 360];
const bottomDirection = enumAngleToDirection[(rotation + 180) % 360];
const leftDirection = enumAngleToDirection[(rotation + 270) % 360];
const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile, enumLayer.wires);
let hasBottomEjector = false;
let hasRightEjector = false;
let hasLeftEjector = false;
let hasTopAcceptor = false;
let hasLeftAcceptor = false;
let hasRightAcceptor = false;
// Check all ejectors
for (let i = 0; i < ejectors.length; ++i) {
const ejector = ejectors[i];
if (ejector.toDirection === topDirection) {
hasBottomEjector = true;
} else if (ejector.toDirection === leftDirection) {
hasRightEjector = true;
} else if (ejector.toDirection === rightDirection) {
hasLeftEjector = true;
}
}
// Check all acceptors
for (let i = 0; i < acceptors.length; ++i) {
const acceptor = acceptors[i];
if (acceptor.fromDirection === bottomDirection) {
hasTopAcceptor = true;
} else if (acceptor.fromDirection === rightDirection) {
hasLeftAcceptor = true;
} else if (acceptor.fromDirection === leftDirection) {
hasRightAcceptor = true;
}
}
// Soo .. if there is any ejector below us we always prioritize
// this ejector
if (!hasBottomEjector) {
// When something ejects to us from the left and nothing from the right,
// do a curve from the left to the top
if (hasRightEjector && !hasLeftEjector) {
return {
rotation: (rotation + 270) % 360,
rotationVariant: 2,
};
}
// When something ejects to us from the right and nothing from the left,
// do a curve from the right to the top
if (hasLeftEjector && !hasRightEjector) {
return {
rotation: (rotation + 90) % 360,
rotationVariant: 1,
};
}
}
// When there is a top acceptor, ignore sides
// NOTICE: This makes the belt prefer side turns *way* too much!
if (!hasTopAcceptor) {
// When there is an acceptor to the right but no acceptor to the left,
// do a turn to the right
if (hasRightAcceptor && !hasLeftAcceptor) {
return {
rotation,
rotationVariant: 2,
};
}
// When there is an acceptor to the left but no acceptor to the right,
// do a turn to the left
if (hasLeftAcceptor && !hasRightAcceptor) {
return {
rotation,
rotationVariant: 1,
};
}
}
return {
rotation,
rotationVariant: 0,
};
}
}

View File

@ -3,7 +3,10 @@ import { BaseItem } from "../base_item";
import { Component } from "../component"; import { Component } from "../component";
import { ShapeItem } from "../items/shape_item"; import { ShapeItem } from "../items/shape_item";
const maxQueueSize = 10; const maxQueueSize = 4;
export const ENERGY_GENERATOR_EJECT_SLOT = 0;
export const ENERGY_GENERATOR_ACCEPT_SLOT = 4;
export class EnergyGeneratorComponent extends Component { export class EnergyGeneratorComponent extends Component {
static getId() { static getId() {
@ -12,7 +15,8 @@ export class EnergyGeneratorComponent extends Component {
static getSchema() { static getSchema() {
return { return {
requiredKey: types.string, requiredKey: types.nullable(types.string),
itemsInQueue: types.uint,
}; };
} }
@ -35,8 +39,14 @@ export class EnergyGeneratorComponent extends Component {
/** /**
* *
* @param {BaseItem} item * @param {BaseItem} item
* @param {number} slot
*/ */
tryTakeItem(item) { tryTakeItem(item, slot) {
if (slot === ENERGY_GENERATOR_ACCEPT_SLOT) {
// this is the acceptor slot on the wires layer
// just destroy it
return true;
} else {
if (/** @type {ShapeItem} */ (item).definition.getHash() !== this.requiredKey) { if (/** @type {ShapeItem} */ (item).definition.getHash() !== this.requiredKey) {
// Not our shape // Not our shape
return false; return false;
@ -52,3 +62,4 @@ export class EnergyGeneratorComponent extends Component {
return true; return true;
} }
} }
}

View File

@ -2,10 +2,12 @@ import { enumDirection, enumInvertedDirections, Vector } from "../../core/vector
import { types } from "../../savegame/serialization"; import { types } from "../../savegame/serialization";
import { BaseItem, enumItemType } from "../base_item"; import { BaseItem, enumItemType } from "../base_item";
import { Component } from "../component"; import { Component } from "../component";
import { enumLayer } from "../root";
/** @typedef {{ /** @typedef {{
* pos: Vector, * pos: Vector,
* directions: enumDirection[], * directions: enumDirection[],
* layer: enumLayer,
* filter?: enumItemType * filter?: enumItemType
* }} ItemAcceptorSlot */ * }} ItemAcceptorSlot */
@ -17,6 +19,13 @@ import { Component } from "../component";
* acceptedDirection: enumDirection * acceptedDirection: enumDirection
* }} ItemAcceptorLocatedSlot */ * }} ItemAcceptorLocatedSlot */
/** @typedef {{
* pos: Vector,
* directions: enumDirection[],
* layer?: enumLayer,
* filter?: enumItemType
* }} ItemAcceptorSlotConfig */
export class ItemAcceptorComponent extends Component { export class ItemAcceptorComponent extends Component {
static getId() { static getId() {
return "ItemAcceptor"; return "ItemAcceptor";
@ -29,6 +38,9 @@ export class ItemAcceptorComponent extends Component {
pos: types.vector, pos: types.vector,
directions: types.array(types.enum(enumDirection)), directions: types.array(types.enum(enumDirection)),
filter: types.nullable(types.enum(enumItemType)), filter: types.nullable(types.enum(enumItemType)),
// TODO: MIGRATE
layer: types.enum(enumLayer),
}) })
), ),
animated: types.bool, animated: types.bool,
@ -36,6 +48,9 @@ export class ItemAcceptorComponent extends Component {
types.structured({ types.structured({
pos: types.vector, pos: types.vector,
direction: types.enum(enumDirection), direction: types.enum(enumDirection),
// TODO: MIGRATE
layer: types.enum(enumLayer),
}) })
), ),
}; };
@ -49,6 +64,7 @@ export class ItemAcceptorComponent extends Component {
pos: slot.pos.copy(), pos: slot.pos.copy(),
directions: slot.directions.slice(), directions: slot.directions.slice(),
filter: slot.filter, filter: slot.filter,
layer: slot.layer,
}); });
} }
@ -58,6 +74,7 @@ export class ItemAcceptorComponent extends Component {
beltUnderlaysCopy.push({ beltUnderlaysCopy.push({
pos: underlay.pos.copy(), pos: underlay.pos.copy(),
direction: underlay.direction, direction: underlay.direction,
layer: underlay.layer,
}); });
} }
@ -71,9 +88,9 @@ export class ItemAcceptorComponent extends Component {
/** /**
* *
* @param {object} param0 * @param {object} param0
* @param {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemType}>} param0.slots The slots from which we accept items * @param {Array<ItemAcceptorSlotConfig>} param0.slots The slots from which we accept items
* @param {boolean=} param0.animated Whether to animate item consumption * @param {boolean=} param0.animated Whether to animate item consumption
* @param {Array<{pos: Vector, direction: enumDirection}>=} param0.beltUnderlays Where to render belt underlays * @param {Array<{pos: Vector, direction: enumDirection, layer: enumLayer}>=} param0.beltUnderlays Where to render belt underlays
*/ */
constructor({ slots = [], beltUnderlays = [], animated = true }) { constructor({ slots = [], beltUnderlays = [], animated = true }) {
super(); super();
@ -94,16 +111,17 @@ export class ItemAcceptorComponent extends Component {
/** /**
* *
* @param {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemType}>} slots * @param {Array<ItemAcceptorSlotConfig>} slots
*/ */
setSlots(slots) { setSlots(slots) {
/** @type {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemType}>} */ /** @type {Array<ItemAcceptorSlot>} */
this.slots = []; this.slots = [];
for (let i = 0; i < slots.length; ++i) { for (let i = 0; i < slots.length; ++i) {
const slot = slots[i]; const slot = slots[i];
this.slots.push({ this.slots.push({
pos: slot.pos, pos: slot.pos,
directions: slot.directions, directions: slot.directions,
layer: slot.layer || enumLayer.regular,
// Which type of item to accept (shape | color | all) @see enumItemType // Which type of item to accept (shape | color | all) @see enumItemType
filter: slot.filter, filter: slot.filter,
@ -142,9 +160,10 @@ export class ItemAcceptorComponent extends Component {
* Tries to find a slot which accepts the current item * Tries to find a slot which accepts the current item
* @param {Vector} targetLocalTile * @param {Vector} targetLocalTile
* @param {enumDirection} fromLocalDirection * @param {enumDirection} fromLocalDirection
* @param {enumLayer} layer
* @returns {ItemAcceptorLocatedSlot|null} * @returns {ItemAcceptorLocatedSlot|null}
*/ */
findMatchingSlot(targetLocalTile, fromLocalDirection) { findMatchingSlot(targetLocalTile, fromLocalDirection, layer) {
// We need to invert our direction since the acceptor specifies *from* which direction // We need to invert our direction since the acceptor specifies *from* which direction
// it accepts items, but the ejector specifies *into* which direction it ejects items. // it accepts items, but the ejector specifies *into* which direction it ejects items.
// E.g.: Ejector ejects into "right" direction but acceptor accepts from "left" direction. // E.g.: Ejector ejects into "right" direction but acceptor accepts from "left" direction.
@ -159,6 +178,11 @@ export class ItemAcceptorComponent extends Component {
continue; continue;
} }
// Make sure the layer matches
if (slot.layer !== layer) {
continue;
}
// Check if the acceptor slot accepts items from our direction // Check if the acceptor slot accepts items from our direction
for (let i = 0; i < slot.directions.length; ++i) { for (let i = 0; i < slot.directions.length; ++i) {
// const localDirection = targetStaticComp.localDirectionToWorld(slot.directions[l]); // const localDirection = targetStaticComp.localDirectionToWorld(slot.directions[l]);

View File

@ -4,12 +4,14 @@ import { Component } from "../component";
import { types } from "../../savegame/serialization"; import { types } from "../../savegame/serialization";
import { gItemRegistry } from "../../core/global_registries"; import { gItemRegistry } from "../../core/global_registries";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { enumLayer } from "../root";
/** /**
* @typedef {{ * @typedef {{
* pos: Vector, * pos: Vector,
* direction: enumDirection, * direction: enumDirection,
* item: BaseItem, * item: BaseItem,
* layer: enumLayer,
* progress: number?, * progress: number?,
* cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot, * cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot,
* cachedTargetEntity?: Entity * cachedTargetEntity?: Entity
@ -32,6 +34,9 @@ export class ItemEjectorComponent extends Component {
direction: types.enum(enumDirection), direction: types.enum(enumDirection),
item: types.nullable(types.obj(gItemRegistry)), item: types.nullable(types.obj(gItemRegistry)),
progress: types.float, progress: types.float,
// TODO: Migrate
layer: types.enum(enumLayer),
}) })
), ),
}; };
@ -44,6 +49,7 @@ export class ItemEjectorComponent extends Component {
slotsCopy.push({ slotsCopy.push({
pos: slot.pos.copy(), pos: slot.pos.copy(),
direction: slot.direction, direction: slot.direction,
layer: slot.layer,
}); });
} }
@ -56,7 +62,7 @@ export class ItemEjectorComponent extends Component {
/** /**
* *
* @param {object} param0 * @param {object} param0
* @param {Array<{pos: Vector, direction: enumDirection}>=} param0.slots The slots to eject on * @param {Array<{pos: Vector, direction: enumDirection, layer?: enumLayer}>=} param0.slots The slots to eject on
* @param {boolean=} param0.instantEject If the ejection is instant * @param {boolean=} param0.instantEject If the ejection is instant
*/ */
constructor({ slots = [], instantEject = false }) { constructor({ slots = [], instantEject = false }) {
@ -77,7 +83,7 @@ export class ItemEjectorComponent extends Component {
} }
/** /**
* @param {Array<{pos: Vector, direction: enumDirection}>} slots The slots to eject on * @param {Array<{pos: Vector, direction: enumDirection, layer?: enumLayer}>} slots The slots to eject on
*/ */
setSlots(slots) { setSlots(slots) {
/** @type {Array<ItemEjectorSlot>} */ /** @type {Array<ItemEjectorSlot>} */
@ -89,19 +95,13 @@ export class ItemEjectorComponent extends Component {
direction: slot.direction, direction: slot.direction,
item: null, item: null,
progress: 0, progress: 0,
layer: slot.layer || enumLayer.regular,
cachedDestSlot: null, cachedDestSlot: null,
cachedTargetEntity: null, cachedTargetEntity: null,
}); });
} }
} }
/**
* Returns the amount of slots
*/
getNumSlots() {
return this.slots.length;
}
/** /**
* Returns where this slot ejects to * Returns where this slot ejects to
* @param {number} index * @param {number} index
@ -116,26 +116,17 @@ export class ItemEjectorComponent extends Component {
/** /**
* Returns whether any slot ejects to the given local tile * Returns whether any slot ejects to the given local tile
* @param {Vector} tile * @param {Vector} tile
* @param {enumLayer} layer
*/ */
anySlotEjectsToLocalTile(tile) { anySlotEjectsToLocalTile(tile, layer) {
for (let i = 0; i < this.slots.length; ++i) { for (let i = 0; i < this.slots.length; ++i) {
if (this.getSlotTargetLocalTile(i).equals(tile)) { if (this.getSlotTargetLocalTile(i).equals(tile) && this.slots[i].layer === layer) {
return true; return true;
} }
} }
return false; return false;
} }
/**
* Returns if slot # is currently ejecting
* @param {number} slotIndex
* @returns {boolean}
*/
isSlotEjecting(slotIndex) {
assert(slotIndex >= 0 && slotIndex < this.slots.length, "Invalid ejector slot: " + slotIndex);
return !!this.slots[slotIndex].item;
}
/** /**
* Returns if we can eject on a given slot * Returns if we can eject on a given slot
* @param {number} slotIndex * @param {number} slotIndex
@ -148,43 +139,18 @@ export class ItemEjectorComponent extends Component {
/** /**
* Returns the first free slot on this ejector or null if there is none * Returns the first free slot on this ejector or null if there is none
* @param {enumLayer} layer
* @returns {number?} * @returns {number?}
*/ */
getFirstFreeSlot() { getFirstFreeSlot(layer) {
for (let i = 0; i < this.slots.length; ++i) { for (let i = 0; i < this.slots.length; ++i) {
if (this.canEjectOnSlot(i)) { if (this.canEjectOnSlot(i) && this.slots[i].layer === layer) {
return i; return i;
} }
} }
return null; return null;
} }
/**
* Returns if any slot is ejecting
* @returns {boolean}
*/
isAnySlotEjecting() {
for (let i = 0; i < this.slots.length; ++i) {
if (this.slots[i].item) {
return true;
}
}
return false;
}
/**
* Returns if any slot is free
* @returns {boolean}
*/
hasAnySlotFree() {
for (let i = 0; i < this.slots.length; ++i) {
if (this.canEjectOnSlot(i)) {
return true;
}
}
return false;
}
/** /**
* Tries to eject a given item * Tries to eject a given item
* @param {number} slotIndex * @param {number} slotIndex

View File

@ -1,21 +1,25 @@
import { Component } from "../component"; import { Component } from "../component";
import { Vector } from "../../core/vector"; import { Vector, enumDirection } from "../../core/vector";
import { types } from "../../savegame/serialization"; import { types } from "../../savegame/serialization";
/** @enum {string} */ /** @enum {string} */
export const enumPinSlotType = { export const enumPinSlotType = {
energyEjector: "energyEjector", positiveEnergyEjector: "positiveEnergyEjector",
negativeEnergyEjector: "negativeEnergyEjector",
positiveEnergyAcceptor: "positiveEnergyAcceptor",
negativeEnergyAcceptor: "positiveEnergyAcceptor",
}; };
/** @typedef {{ /** @typedef {{
* pos: Vector, * pos: Vector,
* type: enumPinSlotType * type: enumPinSlotType,
* direction: enumDirection
* }} WirePinSlotDefinition */ * }} WirePinSlotDefinition */
/** @typedef {{ /** @typedef {{
* pos: Vector, * pos: Vector,
* type: enumPinSlotType, * type: enumPinSlotType,
* value: number * direction: enumDirection
* }} WirePinSlot */ * }} WirePinSlot */
export class WiredPinsComponent extends Component { export class WiredPinsComponent extends Component {
@ -29,7 +33,6 @@ export class WiredPinsComponent extends Component {
types.structured({ types.structured({
pos: types.vector, pos: types.vector,
type: types.enum(enumPinSlotType), type: types.enum(enumPinSlotType),
value: types.float,
}) })
), ),
}; };
@ -58,7 +61,7 @@ export class WiredPinsComponent extends Component {
this.slots.push({ this.slots.push({
pos: slotData.pos, pos: slotData.pos,
type: slotData.type, type: slotData.type,
value: 0.0, direction: slotData.direction,
}); });
} }
} }

View File

@ -23,7 +23,7 @@ import { GameHUD } from "./hud/hud";
import { KeyActionMapper } from "./key_action_mapper"; import { KeyActionMapper } from "./key_action_mapper";
import { GameLogic } from "./logic"; import { GameLogic } from "./logic";
import { MapView } from "./map_view"; import { MapView } from "./map_view";
import { GameRoot, enumEditMode } from "./root"; import { GameRoot, enumLayer } from "./root";
import { ShapeDefinitionManager } from "./shape_definition_manager"; import { ShapeDefinitionManager } from "./shape_definition_manager";
import { SoundProxy } from "./sound_proxy"; import { SoundProxy } from "./sound_proxy";
import { GameTime } from "./time/game_time"; import { GameTime } from "./time/game_time";
@ -393,26 +393,36 @@ export class GameCore {
root.map.drawBackground(params); root.map.drawBackground(params);
if (!this.root.camera.getIsMapOverlayActive()) { if (!this.root.camera.getIsMapOverlayActive()) {
systems.itemAcceptor.drawUnderlays(params); systems.itemAcceptor.drawUnderlays(params, enumLayer.regular);
systems.belt.draw(params); systems.belt.drawLayer(params, enumLayer.regular);
systems.itemEjector.draw(params); systems.itemEjector.drawLayer(params, enumLayer.regular);
systems.itemAcceptor.draw(params); systems.itemAcceptor.drawLayer(params, enumLayer.regular);
} }
root.map.drawForeground(params); root.map.drawForeground(params);
if (!this.root.camera.getIsMapOverlayActive()) { if (!this.root.camera.getIsMapOverlayActive()) {
systems.hub.draw(params); systems.hub.draw(params);
systems.energyGenerator.draw(params); systems.energyGenerator.draw(params);
systems.storage.draw(params); systems.storage.draw(params);
} }
/* wires:start */
root.hud.parts.wiresOverlay.draw(params); root.hud.parts.wiresOverlay.draw(params);
if (this.root.editMode === enumEditMode.wires) { if (this.root.currentLayer === enumLayer.wires) {
systems.wiredPins.drawWiresLayer(params); if (!this.root.camera.getIsMapOverlayActive()) {
systems.itemAcceptor.drawUnderlays(params, enumLayer.wires);
}
root.map.drawWiresLayer(params);
if (!this.root.camera.getIsMapOverlayActive()) {
systems.itemEjector.drawLayer(params, enumLayer.wires);
systems.itemAcceptor.drawLayer(params, enumLayer.wires);
systems.belt.drawLayer(params, enumLayer.wires);
systems.wiredPins.draw(params);
}
} }
/* wires:end */
if (G_IS_DEV) { if (G_IS_DEV) {
root.map.drawStaticEntityDebugOverlays(params); root.map.drawStaticEntityDebugOverlays(params);

View File

@ -1,9 +1,9 @@
/* typehints:start */ /* typehints:start */
import { GameRoot } from "./root";
import { DrawParameters } from "../core/draw_parameters"; import { DrawParameters } from "../core/draw_parameters";
import { Component } from "./component"; import { Component } from "./component";
/* typehints:end */ /* typehints:end */
import { GameRoot, enumLayer } from "./root";
import { globalConfig } from "../core/config"; import { globalConfig } from "../core/config";
import { enumDirectionToVector, enumDirectionToAngle } from "../core/vector"; import { enumDirectionToVector, enumDirectionToAngle } from "../core/vector";
import { BasicSerializableObject, types } from "../savegame/serialization"; import { BasicSerializableObject, types } from "../savegame/serialization";
@ -34,6 +34,11 @@ export class Entity extends BasicSerializableObject {
*/ */
this.registered = false; this.registered = false;
/**
* On which layer this entity is
*/
this.layer = enumLayer.regular;
/** /**
* Internal entity unique id, set by the @see EntityManager * Internal entity unique id, set by the @see EntityManager
*/ */
@ -72,6 +77,7 @@ export class Entity extends BasicSerializableObject {
return { return {
uid: types.uint, uid: types.uint,
components: types.keyValueMap(types.objData(gComponentRegistry)), components: types.keyValueMap(types.objData(gComponentRegistry)),
layer: types.enum(enumLayer),
}; };
} }
@ -83,6 +89,7 @@ export class Entity extends BasicSerializableObject {
for (const key in this.components) { for (const key in this.components) {
clone.components[key] = this.components[key].duplicateWithoutContents(); clone.components[key] = this.components[key].duplicateWithoutContents();
} }
clone.layer = this.layer;
return clone; return clone;
} }
@ -162,6 +169,9 @@ export class Entity extends BasicSerializableObject {
const ejectorSprite = Loader.getSprite("sprites/debug/ejector_slot.png"); const ejectorSprite = Loader.getSprite("sprites/debug/ejector_slot.png");
for (let i = 0; i < ejectorComp.slots.length; ++i) { for (let i = 0; i < ejectorComp.slots.length; ++i) {
const slot = ejectorComp.slots[i]; const slot = ejectorComp.slots[i];
if (slot.layer !== this.root.currentLayer) {
continue;
}
const slotTile = staticComp.localTileToWorld(slot.pos); const slotTile = staticComp.localTileToWorld(slot.pos);
const direction = staticComp.localDirectionToWorld(slot.direction); const direction = staticComp.localDirectionToWorld(slot.direction);
const directionVector = enumDirectionToVector[direction]; const directionVector = enumDirectionToVector[direction];
@ -184,6 +194,9 @@ export class Entity extends BasicSerializableObject {
const acceptorSprite = Loader.getSprite("sprites/debug/acceptor_slot.png"); const acceptorSprite = Loader.getSprite("sprites/debug/acceptor_slot.png");
for (let i = 0; i < acceptorComp.slots.length; ++i) { for (let i = 0; i < acceptorComp.slots.length; ++i) {
const slot = acceptorComp.slots[i]; const slot = acceptorComp.slots[i];
if (slot.layer !== this.root.currentLayer) {
continue;
}
const slotTile = staticComp.localTileToWorld(slot.pos); const slotTile = staticComp.localTileToWorld(slot.pos);
for (let k = 0; k < slot.directions.length; ++k) { for (let k = 0; k < slot.directions.length; ++k) {
const direction = staticComp.localDirectionToWorld(slot.directions[k]); const direction = staticComp.localDirectionToWorld(slot.directions[k]);

View File

@ -102,9 +102,7 @@ export class GameSystemManager {
add("staticMapEntities", StaticMapEntitySystem); add("staticMapEntities", StaticMapEntitySystem);
/* wires:start */
add("wiredPins", WiredPinsSystem); add("wiredPins", WiredPinsSystem);
/* wires:end */
// IMPORTANT: Must be after belt system since belt system can change the // IMPORTANT: Must be after belt system since belt system can change the
// orientation of an entity after it is placed -> the item acceptor cache // orientation of an entity after it is placed -> the item acceptor cache

View File

@ -1,9 +1,9 @@
/* typehints:start */ /* typehints:start */
import { Component } from "./component"; import { Component } from "./component";
import { GameRoot } from "./root";
import { Entity } from "./entity"; import { Entity } from "./entity";
/* typehints:end */ /* typehints:end */
import { GameRoot, enumLayer } from "./root";
import { GameSystem } from "./game_system"; import { GameSystem } from "./game_system";
import { arrayDelete, arrayDeleteValue } from "../core/utils"; import { arrayDelete, arrayDeleteValue } from "../core/utils";
import { DrawParameters } from "../core/draw_parameters"; import { DrawParameters } from "../core/draw_parameters";
@ -39,8 +39,9 @@ export class GameSystemWithFilter extends GameSystem {
* Calls a function for each matching entity on the screen, useful for drawing them * Calls a function for each matching entity on the screen, useful for drawing them
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @param {function} callback * @param {function} callback
* @param {enumLayer=} layerFilter Can be null for no filter
*/ */
forEachMatchingEntityOnScreen(parameters, callback) { forEachMatchingEntityOnScreen(parameters, callback, layerFilter = null) {
const cullRange = parameters.visibleRect.toTileCullRectangle(); const cullRange = parameters.visibleRect.toTileCullRectangle();
if (this.allEntities.length < 100) { if (this.allEntities.length < 100) {
// So, its much quicker to simply perform per-entity checking // So, its much quicker to simply perform per-entity checking
@ -48,9 +49,11 @@ export class GameSystemWithFilter extends GameSystem {
for (let i = 0; i < this.allEntities.length; ++i) { for (let i = 0; i < this.allEntities.length; ++i) {
const entity = this.allEntities[i]; const entity = this.allEntities[i];
if (cullRange.containsRect(entity.components.StaticMapEntity.getTileSpaceBounds())) { if (cullRange.containsRect(entity.components.StaticMapEntity.getTileSpaceBounds())) {
if (!layerFilter || entity.layer === layerFilter) {
callback(parameters, entity); callback(parameters, entity);
} }
} }
}
return; return;
} }
@ -91,10 +94,16 @@ export class GameSystemWithFilter extends GameSystem {
entityLoop: for (let i = 0; i < entities.length; ++i) { entityLoop: for (let i = 0; i < entities.length; ++i) {
const entity = entities[i]; const entity = entities[i];
// Avoid drawing non-layer contents
if (layerFilter && entity.layer !== layerFilter) {
continue;
}
// Avoid drawing twice // Avoid drawing twice
if (seenUids.has(entity.uid)) { if (seenUids.has(entity.uid)) {
continue; continue;
} }
seenUids.add(entity.uid); seenUids.add(entity.uid);
for (let i = 0; i < requiredComponents.length; ++i) { for (let i = 0; i < requiredComponents.length; ++i) {

View File

@ -40,6 +40,7 @@ import { HUDWiresOverlay } from "./parts/wires_overlay";
import { HUDChangesDebugger } from "./parts/debug_changes"; import { HUDChangesDebugger } from "./parts/debug_changes";
import { queryParamOptions } from "../../core/query_parameters"; import { queryParamOptions } from "../../core/query_parameters";
import { HUDSandboxController } from "./parts/sandbox_controller"; import { HUDSandboxController } from "./parts/sandbox_controller";
import { HUDWiresToolbar } from "./parts/wires_toolbar";
export class GameHUD { export class GameHUD {
/** /**
@ -56,6 +57,7 @@ export class GameHUD {
this.parts = { this.parts = {
processingOverlay: new HUDProcessingOverlay(this.root), processingOverlay: new HUDProcessingOverlay(this.root),
buildingsToolbar: new HUDBuildingsToolbar(this.root), buildingsToolbar: new HUDBuildingsToolbar(this.root),
wiresToolbar: new HUDWiresToolbar(this.root),
blueprintPlacer: new HUDBlueprintPlacer(this.root), blueprintPlacer: new HUDBlueprintPlacer(this.root),
buildingPlacer: new HUDBuildingPlacer(this.root), buildingPlacer: new HUDBuildingPlacer(this.root),
unlockNotification: new HUDUnlockNotification(this.root), unlockNotification: new HUDUnlockNotification(this.root),
@ -75,9 +77,7 @@ export class GameHUD {
screenshotExporter: new HUDScreenshotExporter(this.root), screenshotExporter: new HUDScreenshotExporter(this.root),
shapeViewer: new HUDShapeViewer(this.root), shapeViewer: new HUDShapeViewer(this.root),
/* wires:start */
wiresOverlay: new HUDWiresOverlay(this.root), wiresOverlay: new HUDWiresOverlay(this.root),
/* wires:end */
// Typing hints // Typing hints
/* typehints:start */ /* typehints:start */
@ -87,6 +87,7 @@ export class GameHUD {
}; };
this.signals = { this.signals = {
buildingSelectedForPlacement: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()),
selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()),
shapePinRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), shapePinRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()), shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()),
@ -139,7 +140,6 @@ export class GameHUD {
for (const key in this.parts) { for (const key in this.parts) {
this.parts[key].initialize(); this.parts[key].initialize();
} }
this.internalInitSignalConnections();
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this); this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this);
@ -205,14 +205,6 @@ export class GameHUD {
document.body.classList.toggle("uiHidden"); document.body.classList.toggle("uiHidden");
} }
/**
* Initializes connections between parts
*/
internalInitSignalConnections() {
const p = this.parts;
p.buildingsToolbar.sigBuildingSelected.add(p.buildingPlacer.startSelection, p.buildingPlacer);
}
/** /**
* Updates all parts * Updates all parts
*/ */

View File

@ -1,23 +1,26 @@
import { gMetaBuildingRegistry } from "../../../core/global_registries"; import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { Signal, STOP_PROPAGATION } from "../../../core/signal"; import { Signal, STOP_PROPAGATION } from "../../../core/signal";
import { TrackedState } from "../../../core/tracked_state";
import { makeDiv } from "../../../core/utils"; import { makeDiv } from "../../../core/utils";
import { KEYMAPPINGS } from "../../key_action_mapper"; import { KEYMAPPINGS } from "../../key_action_mapper";
import { MetaBuilding } from "../../meta_building"; import { MetaBuilding } from "../../meta_building";
import { BaseHUDPart } from "../base_hud_part";
import { GameRoot } from "../../root"; import { GameRoot } from "../../root";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
export class HUDBaseToolbar extends BaseHUDPart { export class HUDBaseToolbar extends BaseHUDPart {
/** /**
* @param {GameRoot} root * @param {GameRoot} root
* @param {Array<typeof MetaBuilding>} supportedBuildings * @param {object} param0
* @param {function} visibilityCondition * @param {Array<typeof MetaBuilding>} param0.supportedBuildings
* @param {function} param0.visibilityCondition
* @param {string} param0.htmlElementId
*/ */
constructor(root, supportedBuildings, visibilityCondition) { constructor(root, { supportedBuildings, visibilityCondition, htmlElementId }) {
super(root); super(root);
this.supportedBuildings = supportedBuildings; this.supportedBuildings = supportedBuildings;
this.visibilityCondition = visibilityCondition; this.visibilityCondition = visibilityCondition;
this.htmlElementId = htmlElementId;
/** @type {Object.<string, { /** @type {Object.<string, {
* metaBuilding: MetaBuilding, * metaBuilding: MetaBuilding,
@ -27,17 +30,6 @@ export class HUDBaseToolbar extends BaseHUDPart {
* index: number * index: number
* }>} */ * }>} */
this.buildingHandles = {}; this.buildingHandles = {};
this.sigBuildingSelected = new Signal();
this.trackedIsVisisible = new TrackedState(this.onVisibilityChanged, this);
}
/**
* Called when the visibility of the toolbar changed
* @param {boolean} visible
*/
onVisibilityChanged(visible) {
this.element.classList.toggle("visible", visible);
} }
/** /**
@ -45,7 +37,7 @@ export class HUDBaseToolbar extends BaseHUDPart {
* @param {HTMLElement} parent * @param {HTMLElement} parent
*/ */
createElements(parent) { createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_buildings_toolbar", ["ingame_buildingsToolbar"], ""); this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], "");
} }
initialize() { initialize() {
@ -80,6 +72,10 @@ export class HUDBaseToolbar extends BaseHUDPart {
this this
); );
this.domAttach = new DynamicDomAttach(this.root, this.element, {
timeToKeepSeconds: 0.12,
attachClass: "visible",
});
this.lastSelectedIndex = 0; this.lastSelectedIndex = 0;
actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this); actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this);
} }
@ -88,11 +84,10 @@ export class HUDBaseToolbar extends BaseHUDPart {
* Updates the toolbar * Updates the toolbar
*/ */
update() { update() {
this.trackedIsVisisible.set(this.visibilityCondition()); const visible = this.visibilityCondition();
this.domAttach.update(visible);
if (!this.trackedIsVisisible.get()) { if (visible) {
// Currently not active
} else {
for (const buildingId in this.buildingHandles) { for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId]; const handle = this.buildingHandles[buildingId];
const newStatus = handle.metaBuilding.getIsUnlocked(this.root); const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
@ -166,7 +161,7 @@ export class HUDBaseToolbar extends BaseHUDPart {
} }
this.root.soundProxy.playUiClick(); this.root.soundProxy.playUiClick();
this.sigBuildingSelected.dispatch(metaBuilding); this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding);
this.onSelectedPlacementBuildingChanged(metaBuilding); this.onSelectedPlacementBuildingChanged(metaBuilding);
} }
} }

View File

@ -11,6 +11,7 @@ import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach"; import { DynamicDomAttach } from "../dynamic_dom_attach";
import { Blueprint } from "../../blueprint"; import { Blueprint } from "../../blueprint";
import { SOUNDS } from "../../../platform/sound"; import { SOUNDS } from "../../../platform/sound";
import { enumLayer } from "../../root";
export class HUDBlueprintPlacer extends BaseHUDPart { export class HUDBlueprintPlacer extends BaseHUDPart {
createElements(parent) { createElements(parent) {
@ -26,7 +27,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
} }
initialize() { initialize() {
this.root.hud.signals.buildingsSelectedForCopy.add(this.onBuildingsSelected, this); this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
/** @type {TypedTrackedState<Blueprint?>} */ /** @type {TypedTrackedState<Blueprint?>} */
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this); this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
@ -43,6 +44,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
this.root.camera.movePreHandler.add(this.onMouseMove, this); this.root.camera.movePreHandler.add(this.onMouseMove, this);
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this); this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent); this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this); this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
@ -56,6 +58,24 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
} }
} }
/**
* Called when the layer was changed
* @param {enumLayer} layer
*/
onEditModeChanged(layer) {
// Check if the layer of the blueprint differs and thus we have to deselect it
const blueprint = this.currentBlueprint.get();
if (blueprint) {
if (blueprint.layer !== layer) {
this.currentBlueprint.set(null);
}
}
}
/**
* Called when the blueprint is now affordable or not
* @param {boolean} canAfford
*/
onCanAffordChanged(canAfford) { onCanAffordChanged(canAfford) {
this.costDisplayParent.classList.toggle("canAfford", canAfford); this.costDisplayParent.classList.toggle("canAfford", canAfford);
} }
@ -67,6 +87,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
} }
/** /**
* Called when the blueprint was changed
* @param {Blueprint} blueprint * @param {Blueprint} blueprint
*/ */
onBlueprintChanged(blueprint) { onBlueprintChanged(blueprint) {
@ -105,13 +126,12 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
const cost = blueprint.getCost(); const cost = blueprint.getCost();
this.root.hubGoals.takeShapeByKey(blueprintShape, cost); this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
this.root.soundProxy.playUi(SOUNDS.placeBuilding); this.root.soundProxy.playUi(SOUNDS.placeBuilding);
// This actually feels weird
// if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).pressed) {
// this.currentBlueprint.set(null);
// }
} }
} }
/**
* Mose move handler
*/
onMouseMove() { onMouseMove() {
// Prevent movement while blueprint is selected // Prevent movement while blueprint is selected
if (this.currentBlueprint.get()) { if (this.currentBlueprint.get()) {
@ -120,15 +140,19 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
} }
/** /**
* Called when an array of bulidings was selected
* @param {Array<number>} uids * @param {Array<number>} uids
*/ */
onBuildingsSelected(uids) { createBlueprintFromBuildings(uids) {
if (uids.length === 0) { if (uids.length === 0) {
return; return;
} }
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids)); this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
} }
/**
* Attempts to rotate the current blueprint
*/
rotateBlueprint() { rotateBlueprint() {
if (this.currentBlueprint.get()) { if (this.currentBlueprint.get()) {
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) { if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
@ -139,8 +163,17 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
} }
} }
/**
* Attempts to paste the last blueprint
*/
pasteBlueprint() { pasteBlueprint() {
if (this.lastBlueprintUsed !== null) { if (this.lastBlueprintUsed !== null) {
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
// Not compatible
this.root.soundProxy.playUiError();
return;
}
this.root.hud.signals.pasteBlueprintRequested.dispatch(); this.root.hud.signals.pasteBlueprintRequested.dispatch();
this.currentBlueprint.set(this.lastBlueprintUsed); this.currentBlueprint.set(this.lastBlueprintUsed);
} else { } else {

View File

@ -49,6 +49,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
// Bind to signals // Bind to signals
this.signals.variantChanged.add(this.rerenderVariants, this); this.signals.variantChanged.add(this.rerenderVariants, this);
this.root.hud.signals.buildingSelectedForPlacement.add(this.startSelection, this);
this.domAttach = new DynamicDomAttach(this.root, this.element, {}); this.domAttach = new DynamicDomAttach(this.root, this.element, {});
this.variantsAttach = new DynamicDomAttach(this.root, this.variantsElement, {}); this.variantsAttach = new DynamicDomAttach(this.root, this.variantsElement, {});
@ -389,7 +390,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const goodArrowSprite = Loader.getSprite("sprites/misc/slot_good_arrow.png"); const goodArrowSprite = Loader.getSprite("sprites/misc/slot_good_arrow.png");
const badArrowSprite = Loader.getSprite("sprites/misc/slot_bad_arrow.png"); const badArrowSprite = Loader.getSprite("sprites/misc/slot_bad_arrow.png");
// Just ignore this code ... // Just ignore the following code please ... thanks!
const offsetShift = 10; const offsetShift = 10;
@ -397,6 +398,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const slots = acceptorComp.slots; const slots = acceptorComp.slots;
for (let acceptorSlotIndex = 0; acceptorSlotIndex < slots.length; ++acceptorSlotIndex) { for (let acceptorSlotIndex = 0; acceptorSlotIndex < slots.length; ++acceptorSlotIndex) {
const slot = slots[acceptorSlotIndex]; const slot = slots[acceptorSlotIndex];
const acceptorSlotWsTile = staticComp.localTileToWorld(slot.pos); const acceptorSlotWsTile = staticComp.localTileToWorld(slot.pos);
const acceptorSlotWsPos = acceptorSlotWsTile.toWorldSpaceCenterOfTile(); const acceptorSlotWsPos = acceptorSlotWsTile.toWorldSpaceCenterOfTile();
@ -409,7 +411,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const worldDirection = staticComp.localDirectionToWorld(direction); const worldDirection = staticComp.localDirectionToWorld(direction);
const sourceTile = acceptorSlotWsTile.add(enumDirectionToVector[worldDirection]); const sourceTile = acceptorSlotWsTile.add(enumDirectionToVector[worldDirection]);
const sourceEntity = this.root.map.getTileContent(sourceTile); const sourceEntity = this.root.map.getTileContent(sourceTile, this.root.currentLayer);
let sprite = goodArrowSprite; let sprite = goodArrowSprite;
let alpha = 0.5; let alpha = 0.5;
@ -419,7 +421,13 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const sourceEjector = sourceEntity.components.ItemEjector; const sourceEjector = sourceEntity.components.ItemEjector;
const sourceStaticComp = sourceEntity.components.StaticMapEntity; const sourceStaticComp = sourceEntity.components.StaticMapEntity;
const ejectorAcceptLocalTile = sourceStaticComp.worldToLocalTile(acceptorSlotWsTile); const ejectorAcceptLocalTile = sourceStaticComp.worldToLocalTile(acceptorSlotWsTile);
if (sourceEjector && sourceEjector.anySlotEjectsToLocalTile(ejectorAcceptLocalTile)) { if (
sourceEjector &&
sourceEjector.anySlotEjectsToLocalTile(
ejectorAcceptLocalTile,
this.root.currentLayer
)
) {
sprite = goodArrowSprite; sprite = goodArrowSprite;
} }
alpha = 1.0; alpha = 1.0;
@ -443,7 +451,10 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
if (ejectorComp) { if (ejectorComp) {
const slots = ejectorComp.slots; const slots = ejectorComp.slots;
for (let ejectorSlotIndex = 0; ejectorSlotIndex < slots.length; ++ejectorSlotIndex) { for (let ejectorSlotIndex = 0; ejectorSlotIndex < slots.length; ++ejectorSlotIndex) {
const slot = ejectorComp.slots[ejectorSlotIndex]; const slot = slots[ejectorSlotIndex];
if (slot.layer !== this.root.currentLayer) {
continue;
}
const ejectorSlotWsTile = staticComp.localTileToWorld( const ejectorSlotWsTile = staticComp.localTileToWorld(
ejectorComp.getSlotTargetLocalTile(ejectorSlotIndex) ejectorComp.getSlotTargetLocalTile(ejectorSlotIndex)
@ -451,7 +462,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const ejectorSLotWsPos = ejectorSlotWsTile.toWorldSpaceCenterOfTile(); const ejectorSLotWsPos = ejectorSlotWsTile.toWorldSpaceCenterOfTile();
const ejectorSlotWsDirection = staticComp.localDirectionToWorld(slot.direction); const ejectorSlotWsDirection = staticComp.localDirectionToWorld(slot.direction);
const destEntity = this.root.map.getTileContent(ejectorSlotWsTile); const destEntity = this.root.map.getTileContent(ejectorSlotWsTile, this.root.currentLayer);
let sprite = goodArrowSprite; let sprite = goodArrowSprite;
let alpha = 0.5; let alpha = 0.5;
@ -463,7 +474,9 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
if (destAcceptor) { if (destAcceptor) {
const destLocalTile = destStaticComp.worldToLocalTile(ejectorSlotWsTile); const destLocalTile = destStaticComp.worldToLocalTile(ejectorSlotWsTile);
const destLocalDir = destStaticComp.worldDirectionToLocal(ejectorSlotWsDirection); const destLocalDir = destStaticComp.worldDirectionToLocal(ejectorSlotWsDirection);
if (destAcceptor.findMatchingSlot(destLocalTile, destLocalDir)) { if (
destAcceptor.findMatchingSlot(destLocalTile, destLocalDir, this.root.currentLayer)
) {
sprite = goodArrowSprite; sprite = goodArrowSprite;
} else { } else {
sprite = badArrowSprite; sprite = badArrowSprite;

View File

@ -12,7 +12,7 @@ import { BaseHUDPart } from "../base_hud_part";
import { SOUNDS } from "../../../platform/sound"; import { SOUNDS } from "../../../platform/sound";
import { MetaMinerBuilding, enumMinerVariants } from "../../buildings/miner"; import { MetaMinerBuilding, enumMinerVariants } from "../../buildings/miner";
import { enumHubGoalRewards } from "../../tutorial_goals"; import { enumHubGoalRewards } from "../../tutorial_goals";
import { enumEditMode } from "../../root"; import { enumLayer } from "../../root";
/** /**
* Contains all logic for the building placer - this doesn't include the rendering * Contains all logic for the building placer - this doesn't include the rendering
@ -125,12 +125,12 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
/** /**
* Called when the edit mode got changed * Called when the edit mode got changed
* @param {enumEditMode} editMode * @param {enumLayer} editMode
*/ */
onEditModeChanged(editMode) { onEditModeChanged(editMode) {
const metaBuilding = this.currentMetaBuilding.get(); const metaBuilding = this.currentMetaBuilding.get();
if (metaBuilding) { if (metaBuilding) {
if (metaBuilding.getEditLayer() !== editMode) { if (metaBuilding.getLayer() !== editMode) {
// This layer doesn't fit the edit mode anymore // This layer doesn't fit the edit mode anymore
this.currentMetaBuilding.set(null); this.currentMetaBuilding.set(null);
} }
@ -276,7 +276,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
const worldPos = this.root.camera.screenToWorld(mousePosition); const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace(); const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile); const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (contents) { if (contents) {
if (this.root.logic.tryDeleteBuilding(contents)) { if (this.root.logic.tryDeleteBuilding(contents)) {
this.root.soundProxy.playUi(SOUNDS.destroyBuilding); this.root.soundProxy.playUi(SOUNDS.destroyBuilding);
@ -302,7 +302,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
const worldPos = this.root.camera.screenToWorld(mousePosition); const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace(); const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile); const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (!contents) { if (!contents) {
const tileBelow = this.root.map.getLowerLayerContentXY(tile.x, tile.y); const tileBelow = this.root.map.getLowerLayerContentXY(tile.x, tile.y);
@ -322,6 +322,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
// Try to extract the building // Try to extract the building
const extracted = this.hack_reconstructMetaBuildingAndVariantFromBuilding(contents); const extracted = this.hack_reconstructMetaBuildingAndVariantFromBuilding(contents);
// If the building we are picking is the same as the one we have, clear the cursor. // If the building we are picking is the same as the one we have, clear the cursor.
if ( if (
!extracted || !extracted ||
@ -335,11 +336,6 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
this.currentMetaBuilding.set(extracted.metaBuilding); this.currentMetaBuilding.set(extracted.metaBuilding);
this.currentVariant.set(extracted.variant); this.currentVariant.set(extracted.variant);
this.currentBaseRotation = contents.components.StaticMapEntity.rotation; this.currentBaseRotation = contents.components.StaticMapEntity.rotation;
// Make sure we selected something, and also make sure it's not a special entity
// if (contents && !contents.components.Unremovable) {
// }
} }
/** /**
@ -760,7 +756,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
while (this.currentlyDeleting || this.currentMetaBuilding.get()) { while (this.currentlyDeleting || this.currentMetaBuilding.get()) {
if (this.currentlyDeleting) { if (this.currentlyDeleting) {
// Deletion // Deletion
const contents = this.root.map.getTileContentXY(x0, y0); const contents = this.root.map.getLayerContentXY(x0, y0, this.root.currentLayer);
if (contents && !contents.queuedForDestroy && !contents.destroyed) { if (contents && !contents.queuedForDestroy && !contents.destroyed) {
if (this.root.logic.tryDeleteBuilding(contents)) { if (this.root.logic.tryDeleteBuilding(contents)) {
anythingDeleted = true; anythingDeleted = true;

View File

@ -9,10 +9,10 @@ import { MetaSplitterBuilding } from "../../buildings/splitter";
import { MetaStackerBuilding } from "../../buildings/stacker"; import { MetaStackerBuilding } from "../../buildings/stacker";
import { MetaTrashBuilding } from "../../buildings/trash"; import { MetaTrashBuilding } from "../../buildings/trash";
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt"; import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
import { enumEditMode } from "../../root"; import { enumLayer } from "../../root";
import { HUDBaseToolbar } from "./base_toolbar"; import { HUDBaseToolbar } from "./base_toolbar";
const toolbarBuildings = [ const supportedBuildings = [
MetaBeltBaseBuilding, MetaBeltBaseBuilding,
MetaSplitterBuilding, MetaSplitterBuilding,
MetaUndergroundBeltBuilding, MetaUndergroundBeltBuilding,
@ -24,17 +24,16 @@ const toolbarBuildings = [
MetaPainterBuilding, MetaPainterBuilding,
MetaTrashBuilding, MetaTrashBuilding,
/* wires:start */
MetaEnergyGenerator, MetaEnergyGenerator,
/* wires:end */
]; ];
export class HUDBuildingsToolbar extends HUDBaseToolbar { export class HUDBuildingsToolbar extends HUDBaseToolbar {
constructor(root) { constructor(root) {
super( super(root, {
root, supportedBuildings,
toolbarBuildings, visibilityCondition: () =>
() => !this.root.camera.getIsMapOverlayActive() && this.root.editMode === enumEditMode.regular !this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === enumLayer.regular,
); htmlElementId: "ingame_HUD_buildings_toolbar",
});
} }
} }

View File

@ -8,7 +8,7 @@ import { THEME } from "../../theme";
import { globalConfig } from "../../../core/config"; import { globalConfig } from "../../../core/config";
import { T } from "../../../translations"; import { T } from "../../../translations";
import { enumItemType } from "../../base_item"; import { enumItemType } from "../../base_item";
import { enumEditMode } from "../../root"; import { enumLayer } from "../../root";
export class HUDColorBlindHelper extends BaseHUDPart { export class HUDColorBlindHelper extends BaseHUDPart {
createElements(parent) { createElements(parent) {
@ -41,14 +41,14 @@ export class HUDColorBlindHelper extends BaseHUDPart {
return null; return null;
} }
if (this.root.editMode !== enumEditMode.regular) { if (this.root.currentLayer !== enumLayer.regular) {
// Not in regular mode // Not in regular mode
return null; return null;
} }
const worldPos = this.root.camera.screenToWorld(mousePosition); const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace(); const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile); const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (contents && !contents.components.Miner) { if (contents && !contents.components.Miner) {
const beltComp = contents.components.Belt; const beltComp = contents.components.Belt;
@ -66,6 +66,9 @@ export class HUDColorBlindHelper extends BaseHUDPart {
if (ejectorComp) { if (ejectorComp) {
for (let i = 0; i < ejectorComp.slots.length; ++i) { for (let i = 0; i < ejectorComp.slots.length; ++i) {
const slot = ejectorComp.slots[i]; const slot = ejectorComp.slots[i];
if (slot.layer !== this.root.currentLayer) {
continue;
}
if (slot.item && slot.item.getItemType() === enumItemType.color) { if (slot.item && slot.item.getItemType() === enumItemType.color) {
return /** @type {ColorItem} */ (slot.item).color; return /** @type {ColorItem} */ (slot.item).color;
} }

View File

@ -36,7 +36,7 @@ export class HUDEntityDebugger extends BaseHUDPart {
this.mousePosElem.innerText = worldTile.x + " / " + worldTile.y; this.mousePosElem.innerText = worldTile.x + " / " + worldTile.y;
this.chunkPosElem.innerText = chunk.x + " / " + chunk.y; this.chunkPosElem.innerText = chunk.x + " / " + chunk.y;
const entity = this.root.map.getTileContent(worldTile); const entity = this.root.map.getTileContent(worldTile, this.root.currentLayer);
if (entity) { if (entity) {
removeAllChildren(this.entityInfoElem); removeAllChildren(this.entityInfoElem);
let html = "Entity"; let html = "Entity";

View File

@ -255,14 +255,12 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
condition: () => this.anythingSelectedOnMap, condition: () => this.anythingSelectedOnMap,
}, },
/* wires:start */
{ {
// Switch layers // Switch layers
label: T.ingame.keybindingsOverlay.switchLayers, label: T.ingame.keybindingsOverlay.switchLayers,
keys: [k.ingame.switchLayers], keys: [k.ingame.switchLayers],
condition: () => true, condition: () => true,
}, },
/* wires:end */
]; ];
if (!this.root.app.settings.getAllSettings().alwaysMultiplace) { if (!this.root.app.settings.getAllSettings().alwaysMultiplace) {

View File

@ -210,7 +210,7 @@ export class HUDMassSelector extends BaseHUDPart {
for (let x = realTileStart.x; x <= realTileEnd.x; ++x) { for (let x = realTileStart.x; x <= realTileEnd.x; ++x) {
for (let y = realTileStart.y; y <= realTileEnd.y; ++y) { for (let y = realTileStart.y; y <= realTileEnd.y; ++y) {
const contents = this.root.map.getTileContentXY(x, y); const contents = this.root.map.getLayerContentXY(x, y, this.root.currentLayer);
if (contents && this.root.logic.canDeleteBuilding(contents)) { if (contents && this.root.logic.canDeleteBuilding(contents)) {
this.selectedUids.add(contents.uid); this.selectedUids.add(contents.uid);
} }
@ -259,7 +259,7 @@ export class HUDMassSelector extends BaseHUDPart {
for (let x = realTileStart.x; x <= realTileEnd.x; ++x) { for (let x = realTileStart.x; x <= realTileEnd.x; ++x) {
for (let y = realTileStart.y; y <= realTileEnd.y; ++y) { for (let y = realTileStart.y; y <= realTileEnd.y; ++y) {
const contents = this.root.map.getTileContentXY(x, y); const contents = this.root.map.getLayerContentXY(x, y, this.root.currentLayer);
if (contents && this.root.logic.canDeleteBuilding(contents)) { if (contents && this.root.logic.canDeleteBuilding(contents)) {
const staticComp = contents.components.StaticMapEntity; const staticComp = contents.components.StaticMapEntity;
const bounds = staticComp.getTileSpaceBounds(); const bounds = staticComp.getTileSpaceBounds();

View File

@ -132,7 +132,7 @@ export class HUDSandboxController extends BaseHUDPart {
} }
}); });
this.visible = true; this.visible = !G_IS_DEV;
this.domAttach = new DynamicDomAttach(this.root, this.element); this.domAttach = new DynamicDomAttach(this.root, this.element);
} }

View File

@ -2,7 +2,7 @@ import { makeOffscreenBuffer } from "../../../core/buffer_utils";
import { globalConfig } from "../../../core/config"; import { globalConfig } from "../../../core/config";
import { DrawParameters } from "../../../core/draw_parameters"; import { DrawParameters } from "../../../core/draw_parameters";
import { KEYMAPPINGS } from "../../key_action_mapper"; import { KEYMAPPINGS } from "../../key_action_mapper";
import { enumEditMode } from "../../root"; import { enumLayer } from "../../root";
import { THEME } from "../../theme"; import { THEME } from "../../theme";
import { BaseHUDPart } from "../base_hud_part"; import { BaseHUDPart } from "../base_hud_part";
import { Loader } from "../../../core/loader"; import { Loader } from "../../../core/loader";
@ -26,12 +26,12 @@ export class HUDWiresOverlay extends BaseHUDPart {
* Switches between layers * Switches between layers
*/ */
switchLayers() { switchLayers() {
if (this.root.editMode === enumEditMode.regular) { if (this.root.currentLayer === enumLayer.regular) {
this.root.editMode = enumEditMode.wires; this.root.currentLayer = enumLayer.wires;
} else { } else {
this.root.editMode = enumEditMode.regular; this.root.currentLayer = enumLayer.regular;
} }
this.root.signals.editModeChanged.dispatch(this.root.editMode); this.root.signals.editModeChanged.dispatch(this.root.currentLayer);
} }
/** /**
@ -50,7 +50,7 @@ export class HUDWiresOverlay extends BaseHUDPart {
} }
update() { update() {
const desiredAlpha = this.root.editMode === enumEditMode.wires ? 1.0 : 0.0; const desiredAlpha = this.root.currentLayer === enumLayer.wires ? 1.0 : 0.0;
this.currentAlpha = lerp(this.currentAlpha, desiredAlpha, 0.08); this.currentAlpha = lerp(this.currentAlpha, desiredAlpha, 0.08);
} }
@ -63,6 +63,10 @@ export class HUDWiresOverlay extends BaseHUDPart {
return; return;
} }
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
if (!this.cachedPatternBackground) { if (!this.cachedPatternBackground) {
this.cachedPatternBackground = parameters.context.createPattern(this.tilePatternCanvas, "repeat"); this.cachedPatternBackground = parameters.context.createPattern(this.tilePatternCanvas, "repeat");
} }

View File

@ -0,0 +1,16 @@
import { MetaWireBaseBuilding } from "../../buildings/wire_base";
import { enumLayer } from "../../root";
import { HUDBaseToolbar } from "./base_toolbar";
const supportedBuildings = [MetaWireBaseBuilding];
export class HUDWiresToolbar extends HUDBaseToolbar {
constructor(root) {
super(root, {
supportedBuildings,
visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === enumLayer.wires,
htmlElementId: "ingame_HUD_wires_toolbar",
});
}
}

View File

@ -1,8 +1,12 @@
import { gItemRegistry } from "../core/global_registries"; import { gItemRegistry } from "../core/global_registries";
import { ShapeItem } from "./items/shape_item"; import { ShapeItem } from "./items/shape_item";
import { ColorItem } from "./items/color_item"; import { ColorItem } from "./items/color_item";
import { PositiveEnergyItem } from "./items/positive_energy_item";
import { NegativeEnergyItem } from "./items/negative_energy_item";
export function initItemRegistry() { export function initItemRegistry() {
gItemRegistry.register(ShapeItem); gItemRegistry.register(ShapeItem);
gItemRegistry.register(ColorItem); gItemRegistry.register(ColorItem);
gItemRegistry.register(PositiveEnergyItem);
gItemRegistry.register(NegativeEnergyItem);
} }

View File

@ -0,0 +1,68 @@
import { globalConfig } from "../../core/config";
import { smoothenDpi } from "../../core/dpi_manager";
import { DrawParameters } from "../../core/draw_parameters";
import { types } from "../../savegame/serialization";
import { BaseItem, enumItemType } from "../base_item";
export class NegativeEnergyItem extends BaseItem {
static getId() {
return "negative_energy";
}
static getSchema() {
return types.uint;
}
serialize() {
return 0;
}
deserialize(data) {}
getItemType() {
return enumItemType.negativeEnergy;
}
constructor() {
super();
this.bufferGenerator = null;
}
/**
* @param {number} x
* @param {number} y
* @param {number} size
* @param {DrawParameters} parameters
*/
draw(x, y, parameters, size = 12) {
if (!this.bufferGenerator) {
this.bufferGenerator = this.internalGenerateBuffer.bind(this);
}
const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel);
const key = size + "/" + dpi;
const canvas = parameters.root.buffers.getForKey(key, "", size, size, dpi, this.bufferGenerator);
parameters.context.drawImage(canvas, x - size / 2, y - size / 2, size, size);
}
/**
* @param {HTMLCanvasElement} canvas
* @param {CanvasRenderingContext2D} context
* @param {number} w
* @param {number} h
* @param {number} dpi
*/
internalGenerateBuffer(canvas, context, w, h, dpi) {
context.translate((w * dpi) / 2, (h * dpi) / 2);
context.scale((dpi * w) / 12, (dpi * h) / 12);
context.fillStyle = "#1d2725";
context.strokeStyle = "#eee";
context.lineWidth = 1;
context.beginCircle(0, 0, 5);
context.fill();
context.stroke();
}
}
export const POSITIVE_ENERGY_ITEM_SINGLETON = new NegativeEnergyItem();

View File

@ -0,0 +1,68 @@
import { globalConfig } from "../../core/config";
import { smoothenDpi } from "../../core/dpi_manager";
import { DrawParameters } from "../../core/draw_parameters";
import { types } from "../../savegame/serialization";
import { BaseItem, enumItemType } from "../base_item";
export class PositiveEnergyItem extends BaseItem {
static getId() {
return "positive_energy";
}
static getSchema() {
return types.uint;
}
serialize() {
return 0;
}
deserialize(data) {}
getItemType() {
return enumItemType.positiveEnergy;
}
constructor() {
super();
this.bufferGenerator = null;
}
/**
* @param {number} x
* @param {number} y
* @param {number} size
* @param {DrawParameters} parameters
*/
draw(x, y, parameters, size = 12) {
if (!this.bufferGenerator) {
this.bufferGenerator = this.internalGenerateBuffer.bind(this);
}
const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel);
const key = size + "/" + dpi;
const canvas = parameters.root.buffers.getForKey(key, "", size, size, dpi, this.bufferGenerator);
parameters.context.drawImage(canvas, x - size / 2, y - size / 2, size, size);
}
/**
* @param {HTMLCanvasElement} canvas
* @param {CanvasRenderingContext2D} context
* @param {number} w
* @param {number} h
* @param {number} dpi
*/
internalGenerateBuffer(canvas, context, w, h, dpi) {
context.translate((w * dpi) / 2, (h * dpi) / 2);
context.scale((dpi * w) / 12, (dpi * h) / 12);
context.fillStyle = "#e84a4a";
context.strokeStyle = "#eee";
context.lineWidth = 1;
context.beginCircle(0, 0, 5);
context.fill();
context.stroke();
}
}
export const POSITIVE_ENERGY_ITEM_SINGLETON = new PositiveEnergyItem();

View File

@ -25,9 +25,7 @@ export const KEYMAPPINGS = {
exportScreenshot: { keyCode: 114 }, // F3PS exportScreenshot: { keyCode: 114 }, // F3PS
toggleFPSInfo: { keyCode: 115 }, // F4 toggleFPSInfo: { keyCode: 115 }, // F4
/* wires:start */
switchLayers: { keyCode: key("Y") }, switchLayers: { keyCode: key("Y") },
/* wires:end */
}, },
navigation: { navigation: {
@ -55,10 +53,10 @@ export const KEYMAPPINGS = {
mixer: { keyCode: key("8") }, mixer: { keyCode: key("8") },
painter: { keyCode: key("9") }, painter: { keyCode: key("9") },
trash: { keyCode: key("0") }, trash: { keyCode: key("0") },
/* wires:start */
energy_generator: { keyCode: key("O") }, energy_generator: { keyCode: key("O") },
/* wires:end */
// Wires layer
wire: { keyCode: key("1") },
}, },
placement: { placement: {

View File

@ -1,4 +1,4 @@
import { GameRoot } from "./root"; import { GameRoot, enumLayer, arrayLayers } from "./root";
import { Entity } from "./entity"; import { Entity } from "./entity";
import { Vector, enumDirectionToVector, enumDirection } from "../core/vector"; import { Vector, enumDirectionToVector, enumDirection } from "../core/vector";
import { MetaBuilding } from "./meta_building"; import { MetaBuilding } from "./meta_building";
@ -63,16 +63,16 @@ export class GameLogic {
blueprintSpriteKey: "", blueprintSpriteKey: "",
}); });
const layer = building.getLayer();
const rect = checker.getTileSpaceBounds(); const rect = checker.getTileSpaceBounds();
for (let x = rect.x; x < rect.x + rect.w; ++x) { for (let x = rect.x; x < rect.x + rect.w; ++x) {
for (let y = rect.y; y < rect.y + rect.h; ++y) { for (let y = rect.y; y < rect.y + rect.h; ++y) {
const contents = this.root.map.getTileContentXY(x, y); const contents = this.root.map.getLayerContentXY(x, y, layer);
if (contents) { if (contents) {
if ( if (
!this.checkCanReplaceBuilding({ !this.checkCanReplaceBuilding({
original: contents, original: contents,
origin,
building, building,
rotation, rotation,
rotationVariant, rotationVariant,
@ -82,6 +82,25 @@ export class GameLogic {
return false; return false;
} }
} }
// Check for any pins which are in the way
if (layer === enumLayer.wires) {
const regularContents = this.root.map.getLayerContentXY(x, y, enumLayer.regular);
if (regularContents) {
const staticComp = regularContents.components.StaticMapEntity;
const pinComponent = regularContents.components.WiredPins;
if (pinComponent) {
const pins = pinComponent.slots;
for (let i = 0; i < pins.length; ++i) {
const pos = staticComp.localTileToWorld(pins[i].pos);
// Occupied by a pin
if (pos.x === x && pos.y === y) {
return false;
}
}
}
}
}
} }
} }
return true; return true;
@ -91,18 +110,22 @@ export class GameLogic {
* Checks if the given building can be replaced by another * Checks if the given building can be replaced by another
* @param {object} param0 * @param {object} param0
* @param {Entity} param0.original * @param {Entity} param0.original
* @param {Vector} param0.origin
* @param {number} param0.rotation * @param {number} param0.rotation
* @param {number} param0.rotationVariant * @param {number} param0.rotationVariant
* @param {MetaBuilding} param0.building * @param {MetaBuilding} param0.building
* @returns {boolean} * @returns {boolean}
*/ */
checkCanReplaceBuilding({ original, origin, building, rotation, rotationVariant }) { checkCanReplaceBuilding({ original, building, rotation, rotationVariant }) {
if (!original.components.ReplaceableMapEntity) { if (!original.components.ReplaceableMapEntity) {
// Can not get replaced at all // Can not get replaced at all
return false; return false;
} }
if (building.getLayer() !== original.layer) {
// Layer mismatch
return false;
}
const staticComp = original.components.StaticMapEntity; const staticComp = original.components.StaticMapEntity;
assert(staticComp, "Building is not static"); assert(staticComp, "Building is not static");
const beltComp = original.components.Belt; const beltComp = original.components.Belt;
@ -162,11 +185,12 @@ export class GameLogic {
blueprintSpriteKey: "", blueprintSpriteKey: "",
}); });
const rect = checker.getTileSpaceBounds(); const layer = building.getLayer();
const rect = checker.getTileSpaceBounds();
for (let x = rect.x; x < rect.x + rect.w; ++x) { for (let x = rect.x; x < rect.x + rect.w; ++x) {
for (let y = rect.y; y < rect.y + rect.h; ++y) { for (let y = rect.y; y < rect.y + rect.h; ++y) {
const contents = this.root.map.getTileContentXY(x, y); const contents = this.root.map.getLayerContentXY(x, y, layer);
if (contents) { if (contents) {
if (!this.tryDeleteBuilding(contents)) { if (!this.tryDeleteBuilding(contents)) {
logger.error("Building has replaceable component but is also unremovable"); logger.error("Building has replaceable component but is also unremovable");
@ -233,9 +257,10 @@ export class GameLogic {
/** /**
* Returns the acceptors and ejectors which affect the current tile * Returns the acceptors and ejectors which affect the current tile
* @param {Vector} tile * @param {Vector} tile
* @param {enumLayer} layer
* @returns {AcceptorsAndEjectorsAffectingTile} * @returns {AcceptorsAndEjectorsAffectingTile}
*/ */
getEjectorsAndAcceptorsAtTile(tile) { getEjectorsAndAcceptorsAtTile(tile, layer) {
/** @type {EjectorsAffectingTile} */ /** @type {EjectorsAffectingTile} */
let ejectors = []; let ejectors = [];
/** @type {AcceptorsAffectingTile} */ /** @type {AcceptorsAffectingTile} */
@ -247,13 +272,16 @@ export class GameLogic {
continue; continue;
} }
const entity = this.root.map.getTileContentXY(tile.x + dx, tile.y + dy); const entity = this.root.map.getLayerContentXY(tile.x + dx, tile.y + dy, layer);
if (entity) { if (entity) {
const staticComp = entity.components.StaticMapEntity; const staticComp = entity.components.StaticMapEntity;
const itemEjector = entity.components.ItemEjector; const itemEjector = entity.components.ItemEjector;
if (itemEjector) { if (itemEjector) {
for (let ejectorSlot = 0; ejectorSlot < itemEjector.slots.length; ++ejectorSlot) { for (let ejectorSlot = 0; ejectorSlot < itemEjector.slots.length; ++ejectorSlot) {
const slot = itemEjector.slots[ejectorSlot]; const slot = itemEjector.slots[ejectorSlot];
if (slot.layer !== layer) {
continue;
}
const wsTile = staticComp.localTileToWorld(slot.pos); const wsTile = staticComp.localTileToWorld(slot.pos);
const wsDirection = staticComp.localDirectionToWorld(slot.direction); const wsDirection = staticComp.localDirectionToWorld(slot.direction);
const targetTile = wsTile.add(enumDirectionToVector[wsDirection]); const targetTile = wsTile.add(enumDirectionToVector[wsDirection]);
@ -272,6 +300,10 @@ export class GameLogic {
if (itemAcceptor) { if (itemAcceptor) {
for (let acceptorSlot = 0; acceptorSlot < itemAcceptor.slots.length; ++acceptorSlot) { for (let acceptorSlot = 0; acceptorSlot < itemAcceptor.slots.length; ++acceptorSlot) {
const slot = itemAcceptor.slots[acceptorSlot]; const slot = itemAcceptor.slots[acceptorSlot];
if (slot.layer !== layer) {
continue;
}
const wsTile = staticComp.localTileToWorld(slot.pos); const wsTile = staticComp.localTileToWorld(slot.pos);
for (let k = 0; k < slot.directions.length; ++k) { for (let k = 0; k < slot.directions.length; ++k) {
const direction = slot.directions[k]; const direction = slot.directions[k];

View File

@ -1,7 +1,4 @@
/* typehints:start */ import { GameRoot, enumLayer } from "./root";
import { GameRoot } from "./root";
/* typehints:end */
import { globalConfig } from "../core/config"; import { globalConfig } from "../core/config";
import { Vector } from "../core/vector"; import { Vector } from "../core/vector";
import { Entity } from "./entity"; import { Entity } from "./entity";
@ -102,14 +99,15 @@ export class BaseMap extends BasicSerializableObject {
/** /**
* Returns the tile content of a given tile * Returns the tile content of a given tile
* @param {Vector} tile * @param {Vector} tile
* @param {enumLayer} layer
* @returns {Entity} Entity or null * @returns {Entity} Entity or null
*/ */
getTileContent(tile) { getTileContent(tile, layer) {
if (G_IS_DEV) { if (G_IS_DEV) {
this.internalCheckTile(tile); this.internalCheckTile(tile);
} }
const chunk = this.getChunkAtTileOrNull(tile.x, tile.y); const chunk = this.getChunkAtTileOrNull(tile.x, tile.y);
return chunk && chunk.getTileContentFromWorldCoords(tile.x, tile.y); return chunk && chunk.getLayerContentFromWorldCoords(tile.x, tile.y, layer);
} }
/** /**
@ -133,6 +131,29 @@ export class BaseMap extends BasicSerializableObject {
return chunk && chunk.getTileContentFromWorldCoords(x, y); return chunk && chunk.getTileContentFromWorldCoords(x, y);
} }
/**
* Returns the tile content of a given tile
* @param {number} x
* @param {number} y
* @param {enumLayer} layer
* @returns {Entity} Entity or null
*/
getLayerContentXY(x, y, layer) {
const chunk = this.getChunkAtTileOrNull(x, y);
return chunk && chunk.getLayerContentFromWorldCoords(x, y, layer);
}
/**
* Returns the tile contents of a given tile
* @param {number} x
* @param {number} y
* @returns {Array<Entity>} Entity or null
*/
getLayersContentsMultipleXY(x, y) {
const chunk = this.getChunkAtTileOrNull(x, y);
return chunk && chunk.getLayersContentsMultipleFromWorldCoords(x, y);
}
/** /**
* Checks if the tile is used * Checks if the tile is used
* @param {Vector} tile * @param {Vector} tile
@ -167,7 +188,12 @@ export class BaseMap extends BasicSerializableObject {
this.internalCheckTile(tile); this.internalCheckTile(tile);
} }
this.getOrCreateChunkAtTile(tile.x, tile.y).setTileContentFromWorldCords(tile.x, tile.y, entity); this.getOrCreateChunkAtTile(tile.x, tile.y).setLayerContentFromWorldCords(
tile.x,
tile.y,
entity,
entity.layer
);
const staticComponent = entity.components.StaticMapEntity; const staticComponent = entity.components.StaticMapEntity;
assert(staticComponent, "Can only place static map entities in tiles"); assert(staticComponent, "Can only place static map entities in tiles");
@ -185,7 +211,7 @@ export class BaseMap extends BasicSerializableObject {
for (let dy = 0; dy < rect.h; ++dy) { for (let dy = 0; dy < rect.h; ++dy) {
const x = rect.x + dx; const x = rect.x + dx;
const y = rect.y + dy; const y = rect.y + dy;
this.getOrCreateChunkAtTile(x, y).setTileContentFromWorldCords(x, y, entity); this.getOrCreateChunkAtTile(x, y).setLayerContentFromWorldCords(x, y, entity, entity.layer);
} }
} }
} }
@ -202,22 +228,11 @@ export class BaseMap extends BasicSerializableObject {
for (let dy = 0; dy < rect.h; ++dy) { for (let dy = 0; dy < rect.h; ++dy) {
const x = rect.x + dx; const x = rect.x + dx;
const y = rect.y + dy; const y = rect.y + dy;
this.getOrCreateChunkAtTile(x, y).setTileContentFromWorldCords(x, y, null); this.getOrCreateChunkAtTile(x, y).setLayerContentFromWorldCords(x, y, null, entity.layer);
} }
} }
} }
/**
* Resets the tiles content
* @param {Vector} tile
*/
clearTile(tile) {
if (G_IS_DEV) {
this.internalCheckTile(tile);
}
this.getOrCreateChunkAtTile(tile.x, tile.y).setTileContentFromWorldCords(tile.x, tile.y, null);
}
// Internal // Internal
/** /**

View File

@ -1,7 +1,4 @@
/* typehints:start */ import { GameRoot, enumLayer } from "./root";
import { GameRoot } from "./root";
/* typehints:end */
import { globalConfig } from "../core/config"; import { globalConfig } from "../core/config";
import { createLogger } from "../core/logging"; import { createLogger } from "../core/logging";
import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "../core/utils"; import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "../core/utils";
@ -37,6 +34,13 @@ export class MapChunk {
"map-chunk@" + this.x + "|" + this.y "map-chunk@" + this.x + "|" + this.y
); );
/** @type {Array<Array<?Entity>>} */
this.wireContents = make2DUndefinedArray(
globalConfig.mapChunkSize,
globalConfig.mapChunkSize,
"map-chunk-wires@" + this.x + "|" + this.y
);
/** @type {Array<Array<?BaseItem>>} */ /** @type {Array<Array<?BaseItem>>} */
this.lowerLayer = make2DUndefinedArray( this.lowerLayer = make2DUndefinedArray(
globalConfig.mapChunkSize, globalConfig.mapChunkSize,
@ -324,6 +328,53 @@ export class MapChunk {
return this.contents[localX][localY] || null; return this.contents[localX][localY] || null;
} }
/**
* Returns the contents of this chunk from the given world space coordinates
* @param {number} worldX
* @param {number} worldY
* @param {enumLayer} layer
* @returns {Entity=}
*/
getLayerContentFromWorldCoords(worldX, worldY, layer) {
const localX = worldX - this.tileX;
const localY = worldY - this.tileY;
assert(localX >= 0, "Local X is < 0");
assert(localY >= 0, "Local Y is < 0");
assert(localX < globalConfig.mapChunkSize, "Local X is >= chunk size");
assert(localY < globalConfig.mapChunkSize, "Local Y is >= chunk size");
if (layer === enumLayer.regular) {
return this.contents[localX][localY] || null;
} else {
return this.wireContents[localX][localY] || null;
}
}
/**
* Returns the contents of this chunk from the given world space coordinates
* @param {number} worldX
* @param {number} worldY
* @returns {Array<Entity>}
*/
getLayersContentsMultipleFromWorldCoords(worldX, worldY) {
const localX = worldX - this.tileX;
const localY = worldY - this.tileY;
assert(localX >= 0, "Local X is < 0");
assert(localY >= 0, "Local Y is < 0");
assert(localX < globalConfig.mapChunkSize, "Local X is >= chunk size");
assert(localY < globalConfig.mapChunkSize, "Local Y is >= chunk size");
const regularContent = this.contents[localX][localY];
const wireContent = this.wireContents[localX][localY];
const result = [];
if (regularContent) {
result.push(regularContent);
}
if (wireContent) {
result.push(wireContent);
}
return result;
}
/** /**
* Returns the chunks contents from the given local coordinates * Returns the chunks contents from the given local coordinates
* @param {number} localX * @param {number} localX
@ -344,22 +395,36 @@ export class MapChunk {
* @param {number} tileX * @param {number} tileX
* @param {number} tileY * @param {number} tileY
* @param {Entity=} contents * @param {Entity=} contents
* @param {enumLayer} layer
*/ */
setTileContentFromWorldCords(tileX, tileY, contents) { setLayerContentFromWorldCords(tileX, tileY, contents, layer) {
const localX = tileX - this.tileX; const localX = tileX - this.tileX;
const localY = tileY - this.tileY; const localY = tileY - this.tileY;
assert(localX >= 0, "Local X is < 0"); assert(localX >= 0, "Local X is < 0");
assert(localY >= 0, "Local Y is < 0"); assert(localY >= 0, "Local Y is < 0");
assert(localX < globalConfig.mapChunkSize, "Local X is >= chunk size"); assert(localX < globalConfig.mapChunkSize, "Local X is >= chunk size");
assert(localY < globalConfig.mapChunkSize, "Local Y is >= chunk size"); assert(localY < globalConfig.mapChunkSize, "Local Y is >= chunk size");
const oldContents = this.contents[localX][localY];
let oldContents;
if (layer === enumLayer.regular) {
oldContents = this.contents[localX][localY];
} else {
oldContents = this.wireContents[localX][localY];
}
assert(contents === null || !oldContents, "Tile already used: " + tileX + " / " + tileY); assert(contents === null || !oldContents, "Tile already used: " + tileX + " / " + tileY);
if (oldContents) { if (oldContents) {
// Remove from list // Remove from list
fastArrayDeleteValueIfContained(this.containedEntities, oldContents); fastArrayDeleteValueIfContained(this.containedEntities, oldContents);
} }
if (layer === enumLayer.regular) {
this.contents[localX][localY] = contents; this.contents[localX][localY] = contents;
} else {
this.wireContents[localX][localY] = contents;
}
if (contents) { if (contents) {
if (this.containedEntities.indexOf(contents) < 0) { if (this.containedEntities.indexOf(contents) < 0) {
this.containedEntities.push(contents); this.containedEntities.push(contents);

View File

@ -23,6 +23,7 @@ export class MapChunkView extends MapChunk {
this.boundInternalDrawBackgroundToContext = this.internalDrawBackgroundToContext.bind(this); this.boundInternalDrawBackgroundToContext = this.internalDrawBackgroundToContext.bind(this);
this.boundInternalDrawForegroundToContext = this.internalDrawForegroundToContext.bind(this); this.boundInternalDrawForegroundToContext = this.internalDrawForegroundToContext.bind(this);
this.boundInternalDrawWiresToContext = this.internalDrawWiresToContext.bind(this);
/** /**
* Whenever something changes, we increase this number - so we know we need to redraw * Whenever something changes, we increase this number - so we know we need to redraw
@ -99,6 +100,35 @@ export class MapChunkView extends MapChunk {
); );
} }
/**
* Draws the wires layer
* @param {DrawParameters} parameters
*/
drawWiresLayer(parameters) {
if (parameters.zoomLevel > globalConfig.mapChunkPrerenderMinZoom) {
this.internalDrawWireSystems(parameters);
return;
}
const dpi = smoothenDpi(parameters.zoomLevel);
const buffer = this.root.buffers.getForKey(
"" + dpi,
this.renderKey + "@wire",
chunkSizePixels,
chunkSizePixels,
dpi,
this.boundInternalDrawWiresToContext,
{ zoomLevel: parameters.zoomLevel }
);
parameters.context.drawImage(
buffer,
this.tileX * globalConfig.tileSize,
this.tileY * globalConfig.tileSize,
chunkSizePixels,
chunkSizePixels
);
}
/** /**
* *
* @param {HTMLCanvasElement} canvas * @param {HTMLCanvasElement} canvas
@ -181,6 +211,35 @@ export class MapChunkView extends MapChunk {
this.internalDrawForegroundSystems(parameters); this.internalDrawForegroundSystems(parameters);
} }
/**
*
* @param {HTMLCanvasElement} canvas
* @param {CanvasRenderingContext2D} context
* @param {number} w
* @param {number} h
* @param {number} dpi
*/
internalDrawWiresToContext(canvas, context, w, h, dpi, { zoomLevel }) {
context.scale(dpi, dpi);
const parameters = new DrawParameters({
context,
visibleRect: new Rectangle(
this.tileX * globalConfig.tileSize,
this.tileY * globalConfig.tileSize,
chunkSizePixels,
chunkSizePixels
),
desiredAtlasScale: "1",
zoomLevel,
root: this.root,
});
parameters.context.translate(
-this.tileX * globalConfig.tileSize,
-this.tileY * globalConfig.tileSize
);
this.internalDrawWireSystems(parameters);
}
/** /**
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
*/ */
@ -190,6 +249,16 @@ export class MapChunkView extends MapChunk {
systems.belt.drawChunk(parameters, this); systems.belt.drawChunk(parameters, this);
} }
/**
* @param {DrawParameters} parameters
*/
internalDrawWireSystems(parameters) {
const systems = this.root.systemMgr.systems;
systems.belt.drawWiresChunk(parameters, this);
systems.staticMapEntities.drawWiresChunk(parameters, this);
}
/** /**
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
*/ */

View File

@ -156,6 +156,38 @@ export class MapView extends BaseMap {
} }
} }
/**
* Draws the maps foreground
* @param {DrawParameters} parameters
*/
drawWiresLayer(parameters) {
const cullRange = parameters.visibleRect.toTileCullRectangle();
const top = cullRange.top();
const right = cullRange.right();
const bottom = cullRange.bottom();
const left = cullRange.left();
const border = 1;
const minY = top - border;
const maxY = bottom + border;
const minX = left - border;
const maxX = right + border - 1;
const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize);
const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize);
const chunkEndX = Math.ceil(maxX / globalConfig.mapChunkSize);
const chunkEndY = Math.ceil(maxY / globalConfig.mapChunkSize);
// Render y from top down for proper blending
for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) {
for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) {
const chunk = this.root.map.getChunk(chunkX, chunkY, true);
chunk.drawWiresLayer(parameters);
}
}
}
/** /**
* Draws the map background * Draws the map background
* @param {DrawParameters} parameters * @param {DrawParameters} parameters

View File

@ -4,7 +4,7 @@ import { Vector } from "../core/vector";
import { SOUNDS } from "../platform/sound"; import { SOUNDS } from "../platform/sound";
import { StaticMapEntityComponent } from "./components/static_map_entity"; import { StaticMapEntityComponent } from "./components/static_map_entity";
import { Entity } from "./entity"; import { Entity } from "./entity";
import { enumEditMode, GameRoot } from "./root"; import { enumLayer, GameRoot } from "./root";
export const defaultBuildingVariant = "default"; export const defaultBuildingVariant = "default";
@ -26,10 +26,10 @@ export class MetaBuilding {
/** /**
* Returns the edit layer of the building * Returns the edit layer of the building
* @returns {enumEditMode} * @returns {enumLayer}
*/ */
getEditLayer() { getLayer() {
return enumEditMode.regular; return enumLayer.regular;
} }
/** /**
@ -180,6 +180,7 @@ export class MetaBuilding {
*/ */
createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) { createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) {
const entity = new Entity(root); const entity = new Entity(root);
entity.layer = this.getLayer();
const blueprintSprite = this.getBlueprintSprite(rotationVariant, variant); const blueprintSprite = this.getBlueprintSprite(rotationVariant, variant);
entity.addComponent( entity.addComponent(
new StaticMapEntityComponent({ new StaticMapEntityComponent({

View File

@ -11,6 +11,7 @@ import { MetaTrashBuilding } from "./buildings/trash";
import { MetaUndergroundBeltBuilding } from "./buildings/underground_belt"; import { MetaUndergroundBeltBuilding } from "./buildings/underground_belt";
import { MetaHubBuilding } from "./buildings/hub"; import { MetaHubBuilding } from "./buildings/hub";
import { MetaEnergyGenerator } from "./buildings/energy_generator"; import { MetaEnergyGenerator } from "./buildings/energy_generator";
import { MetaWireBaseBuilding } from "./buildings/wire_base";
export function initMetaBuildingRegistry() { export function initMetaBuildingRegistry() {
gMetaBuildingRegistry.register(MetaSplitterBuilding); gMetaBuildingRegistry.register(MetaSplitterBuilding);
@ -25,4 +26,5 @@ export function initMetaBuildingRegistry() {
gMetaBuildingRegistry.register(MetaUndergroundBeltBuilding); gMetaBuildingRegistry.register(MetaUndergroundBeltBuilding);
gMetaBuildingRegistry.register(MetaHubBuilding); gMetaBuildingRegistry.register(MetaHubBuilding);
gMetaBuildingRegistry.register(MetaEnergyGenerator); gMetaBuildingRegistry.register(MetaEnergyGenerator);
gMetaBuildingRegistry.register(MetaWireBaseBuilding);
} }

View File

@ -32,11 +32,14 @@ import { KeyActionMapper } from "./key_action_mapper";
const logger = createLogger("game/root"); const logger = createLogger("game/root");
/** @enum {string} */ /** @enum {string} */
export const enumEditMode = { export const enumLayer = {
regular: "regular", regular: "regular",
wires: "wires", wires: "wires",
}; };
/** @type {Array<enumLayer>} */
export const arrayLayers = [enumLayer.regular, enumLayer.wires];
/** /**
* The game root is basically the whole game state at a given point, * The game root is basically the whole game state at a given point,
* combining all important classes. We don't have globals, but this * combining all important classes. We don't have globals, but this
@ -130,8 +133,8 @@ export class GameRoot {
/** @type {DynamicTickrate} */ /** @type {DynamicTickrate} */
this.dynamicTickrate = null; this.dynamicTickrate = null;
/** @type {enumEditMode} */ /** @type {enumLayer} */
this.editMode = enumEditMode.regular; this.currentLayer = enumLayer.regular;
this.signals = { this.signals = {
// Entities // Entities
@ -165,7 +168,7 @@ export class GameRoot {
bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()), bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()),
editModeChanged: /** @type {TypedSignal<[enumEditMode]>} */ (new Signal()), editModeChanged: /** @type {TypedSignal<[enumLayer]>} */ (new Signal()),
}; };
// RNG's // RNG's

View File

@ -13,6 +13,9 @@ import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter"; import { GameSystemWithFilter } from "../game_system_with_filter";
import { MapChunkView } from "../map_chunk_view"; import { MapChunkView } from "../map_chunk_view";
import { defaultBuildingVariant } from "../meta_building"; import { defaultBuildingVariant } from "../meta_building";
import { enumLayer } from "../root";
import { MetaWireBaseBuilding } from "../buildings/wire_base";
import { enumItemType } from "../base_item";
export const BELT_ANIM_COUNT = 28; export const BELT_ANIM_COUNT = 28;
@ -33,6 +36,15 @@ export class BeltSystem extends GameSystemWithFilter {
[enumDirection.right]: Loader.getSprite("sprites/belt/right_0.png"), [enumDirection.right]: Loader.getSprite("sprites/belt/right_0.png"),
}; };
/**
* @type {Object.<enumDirection, Array<AtlasSprite>>}
*/
this.wireSprites = {
[enumDirection.top]: Loader.getSprite("sprites/buildings/wire_top.png"),
[enumDirection.left]: Loader.getSprite("sprites/buildings/wire_left.png"),
[enumDirection.right]: Loader.getSprite("sprites/buildings/wire_right.png"),
};
/** /**
* @type {Object.<enumDirection, Array<AtlasSprite>>} * @type {Object.<enumDirection, Array<AtlasSprite>>}
*/ */
@ -120,7 +132,10 @@ export class BeltSystem extends GameSystemWithFilter {
return; return;
} }
const metaBelt = gMetaBuildingRegistry.findByClass(MetaBeltBaseBuilding); /* BIG HACK: We don't actually store the meta building */
const metaBelt = gMetaBuildingRegistry.findByClass(
entity.layer === enumLayer.regular ? MetaBeltBaseBuilding : MetaWireBaseBuilding
);
// Compute affected area // Compute affected area
const originalRect = staticComp.getTileSpaceBounds(); const originalRect = staticComp.getTileSpaceBounds();
@ -133,7 +148,7 @@ export class BeltSystem extends GameSystemWithFilter {
continue; continue;
} }
const targetEntity = this.root.map.getTileContentXY(x, y); const targetEntity = this.root.map.getLayerContentXY(x, y, entity.layer);
if (!targetEntity) { if (!targetEntity) {
// Empty tile // Empty tile
continue; continue;
@ -296,10 +311,14 @@ export class BeltSystem extends GameSystemWithFilter {
/** /**
* Draws all belt paths * Draws all belt paths
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @param {enumLayer} layer
*/ */
draw(parameters) { drawLayer(parameters, layer) {
for (let i = 0; i < this.beltPaths.length; ++i) { for (let i = 0; i < this.beltPaths.length; ++i) {
this.beltPaths[i].draw(parameters); const path = this.beltPaths[i];
if (path.layer === layer) {
path.draw(parameters);
}
} }
} }
@ -336,7 +355,7 @@ export class BeltSystem extends GameSystemWithFilter {
const followUpVector = enumDirectionToVector[followUpDirection]; const followUpVector = enumDirectionToVector[followUpDirection];
const followUpTile = staticComp.origin.add(followUpVector); const followUpTile = staticComp.origin.add(followUpVector);
const followUpEntity = this.root.map.getTileContent(followUpTile); const followUpEntity = this.root.map.getLayerContentXY(followUpTile.x, followUpTile.y, entity.layer);
// Check if theres a belt at the tile we point to // Check if theres a belt at the tile we point to
if (followUpEntity) { if (followUpEntity) {
@ -349,6 +368,12 @@ export class BeltSystem extends GameSystemWithFilter {
const acceptorSlots = followUpAcceptor.slots; const acceptorSlots = followUpAcceptor.slots;
for (let i = 0; i < acceptorSlots.length; ++i) { for (let i = 0; i < acceptorSlots.length; ++i) {
const slot = acceptorSlots[i]; const slot = acceptorSlots[i];
// Make sure the acceptor slot is on the same layer
if (slot.layer !== entity.layer) {
continue;
}
for (let k = 0; k < slot.directions.length; ++k) { for (let k = 0; k < slot.directions.length; ++k) {
const localDirection = followUpStatic.localDirectionToWorld(slot.directions[k]); const localDirection = followUpStatic.localDirectionToWorld(slot.directions[k]);
if (enumInvertedDirections[localDirection] === followUpDirection) { if (enumInvertedDirections[localDirection] === followUpDirection) {
@ -374,7 +399,7 @@ export class BeltSystem extends GameSystemWithFilter {
const supplyVector = enumDirectionToVector[supplyDirection]; const supplyVector = enumDirectionToVector[supplyDirection];
const supplyTile = staticComp.origin.add(supplyVector); const supplyTile = staticComp.origin.add(supplyVector);
const supplyEntity = this.root.map.getTileContent(supplyTile); const supplyEntity = this.root.map.getLayerContentXY(supplyTile.x, supplyTile.y, entity.layer);
// Check if theres a belt at the tile we point to // Check if theres a belt at the tile we point to
if (supplyEntity) { if (supplyEntity) {
@ -387,6 +412,11 @@ export class BeltSystem extends GameSystemWithFilter {
const ejectorSlots = supplyEjector.slots; const ejectorSlots = supplyEjector.slots;
for (let i = 0; i < ejectorSlots.length; ++i) { for (let i = 0; i < ejectorSlots.length; ++i) {
const slot = ejectorSlots[i]; const slot = ejectorSlots[i];
// Make sure the ejector slot is on the same layer
if (slot.layer !== entity.layer) {
continue;
}
const localDirection = supplyStatic.localDirectionToWorld(slot.direction); const localDirection = supplyStatic.localDirectionToWorld(slot.direction);
if (enumInvertedDirections[localDirection] === supplyDirection) { if (enumInvertedDirections[localDirection] === supplyDirection) {
return supplyEntity; return supplyEntity;
@ -510,6 +540,45 @@ export class BeltSystem extends GameSystemWithFilter {
1; 1;
} }
/**
* Draws a given chunk
* @param {DrawParameters} parameters
* @param {MapChunkView} chunk
*/
drawWiresChunk(parameters, chunk) {
if (parameters.zoomLevel < globalConfig.mapChunkOverviewMinZoom) {
return;
}
// Limit speed to avoid belts going backwards
const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10);
// SYNC with systems/item_acceptor.js:drawEntityUnderlays!
// 126 / 42 is the exact animation speed of the png animation
const animationIndex = Math.floor(
((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) *
globalConfig.itemSpacingOnBelts
);
const contents = chunk.wireContents;
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
const entity = contents[x][y];
if (entity && entity.components.Belt) {
const direction = entity.components.Belt.direction;
const sprite = this.wireSprites[direction];
entity.components.StaticMapEntity.drawSpriteOnFullEntityBounds(
parameters,
sprite,
0,
false
);
}
}
}
1;
}
/** /**
* Draws the belt path debug overlays * Draws the belt path debug overlays
* @param {DrawParameters} parameters * @param {DrawParameters} parameters

View File

@ -1,10 +1,11 @@
import { DrawParameters } from "../../core/draw_parameters"; import { DrawParameters } from "../../core/draw_parameters";
import { formatBigNumber } from "../../core/utils";
import { T } from "../../translations"; import { T } from "../../translations";
import { EnergyGeneratorComponent } from "../components/energy_generator"; import { EnergyGeneratorComponent, ENERGY_GENERATOR_EJECT_SLOT } from "../components/energy_generator";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter"; import { GameSystemWithFilter } from "../game_system_with_filter";
import { POSITIVE_ENERGY_ITEM_SINGLETON } from "../items/positive_energy_item";
import { ShapeDefinition } from "../shape_definition"; import { ShapeDefinition } from "../shape_definition";
import { formatBigNumber } from "../../core/utils";
export class EnergyGeneratorSystem extends GameSystemWithFilter { export class EnergyGeneratorSystem extends GameSystemWithFilter {
constructor(root) { constructor(root) {
@ -27,11 +28,18 @@ export class EnergyGeneratorSystem extends GameSystemWithFilter {
for (let i = 0; i < this.allEntities.length; ++i) { for (let i = 0; i < this.allEntities.length; ++i) {
const entity = this.allEntities[i]; const entity = this.allEntities[i];
const energyGenComp = entity.components.EnergyGenerator; const energyGenComp = entity.components.EnergyGenerator;
const ejectorComp = entity.components.ItemEjector;
if (!energyGenComp.requiredKey) { if (!energyGenComp.requiredKey) {
// Compute required key for this generator // Compute required key for this generator
energyGenComp.requiredKey = this.getShapeRequiredForGenerator(entity); energyGenComp.requiredKey = this.getShapeRequiredForGenerator(entity);
} }
if (energyGenComp.itemsInQueue > 0) {
if (ejectorComp.tryEject(ENERGY_GENERATOR_EJECT_SLOT, POSITIVE_ENERGY_ITEM_SINGLETON)) {
energyGenComp.itemsInQueue -= 1;
}
}
} }
} }

View File

@ -8,6 +8,7 @@ import { Loader } from "../../core/loader";
import { drawRotatedSprite } from "../../core/draw_utils"; import { drawRotatedSprite } from "../../core/draw_utils";
import { BELT_ANIM_COUNT } from "./belt"; import { BELT_ANIM_COUNT } from "./belt";
import { fastArrayDelete } from "../../core/utils"; import { fastArrayDelete } from "../../core/utils";
import { enumLayer } from "../root";
export class ItemAcceptorSystem extends GameSystemWithFilter { export class ItemAcceptorSystem extends GameSystemWithFilter {
constructor(root) { constructor(root) {
@ -49,19 +50,30 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
} }
} }
draw(parameters) { /**
this.forEachMatchingEntityOnScreen(parameters, this.drawEntity.bind(this)); * Draws the acceptor items
} * @param {DrawParameters} parameters
* @param {enumLayer} layer
drawUnderlays(parameters) { */
this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this)); drawLayer(parameters, layer) {
this.forEachMatchingEntityOnScreen(parameters, this.drawEntityRegularLayer.bind(this, layer));
} }
/** /**
* Draws the acceptor underlays
* @param {DrawParameters} parameters
* @param {enumLayer} layer
*/
drawUnderlays(parameters, layer) {
this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this, layer));
}
/**
* @param {enumLayer} layer
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @param {Entity} entity * @param {Entity} entity
*/ */
drawEntity(parameters, entity) { drawEntityRegularLayer(layer, parameters, entity) {
const staticComp = entity.components.StaticMapEntity; const staticComp = entity.components.StaticMapEntity;
const acceptorComp = entity.components.ItemAcceptor; const acceptorComp = entity.components.ItemAcceptor;
@ -75,8 +87,12 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
]; ];
const slotData = acceptorComp.slots[slotIndex]; const slotData = acceptorComp.slots[slotIndex];
const slotWorldPos = staticComp.applyRotationToVector(slotData.pos).add(staticComp.origin); if (slotData.layer !== layer) {
// Don't draw non-regular slots for now
continue;
}
const slotWorldPos = staticComp.applyRotationToVector(slotData.pos).add(staticComp.origin);
const fadeOutDirection = enumDirectionToVector[staticComp.localDirectionToWorld(direction)]; const fadeOutDirection = enumDirectionToVector[staticComp.localDirectionToWorld(direction)];
const finalTile = slotWorldPos.subScalars( const finalTile = slotWorldPos.subScalars(
fadeOutDirection.x * (animProgress / 2 - 0.5), fadeOutDirection.x * (animProgress / 2 - 0.5),
@ -91,10 +107,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
} }
/** /**
* @param {enumLayer} layer
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @param {Entity} entity * @param {Entity} entity
*/ */
drawEntityUnderlays(parameters, entity) { drawEntityUnderlays(layer, parameters, entity) {
const staticComp = entity.components.StaticMapEntity; const staticComp = entity.components.StaticMapEntity;
const acceptorComp = entity.components.ItemAcceptor; const acceptorComp = entity.components.ItemAcceptor;
@ -107,7 +124,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
const underlays = acceptorComp.beltUnderlays; const underlays = acceptorComp.beltUnderlays;
for (let i = 0; i < underlays.length; ++i) { for (let i = 0; i < underlays.length; ++i) {
const { pos, direction } = underlays[i]; const { pos, direction, layer: underlayLayer } = underlays[i];
if (underlayLayer !== layer) {
// Not our layer
continue;
}
const transformedPos = staticComp.localTileToWorld(pos); const transformedPos = staticComp.localTileToWorld(pos);
const angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)]; const angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)];

View File

@ -7,6 +7,7 @@ import { BaseItem } from "../base_item";
import { ItemEjectorComponent } from "../components/item_ejector"; import { ItemEjectorComponent } from "../components/item_ejector";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter"; import { GameSystemWithFilter } from "../game_system_with_filter";
import { enumLayer } from "../root";
const logger = createLogger("systems/ejector"); const logger = createLogger("systems/ejector");
@ -96,8 +97,10 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
for (let x = area.x; x < area.right(); ++x) { for (let x = area.x; x < area.right(); ++x) {
for (let y = area.y; y < area.bottom(); ++y) { for (let y = area.y; y < area.bottom(); ++y) {
const entity = this.root.map.getTileContentXY(x, y); const entities = this.root.map.getLayersContentsMultipleXY(x, y);
if (entity) { for (let i = 0; i < entities.length; ++i) {
const entity = entities[i];
// Recompute the entity in case its relevant for this system and it // Recompute the entity in case its relevant for this system and it
// hasn't already been computed // hasn't already been computed
if (!recomputedEntities.has(entity.uid) && entity.components.ItemEjector) { if (!recomputedEntities.has(entity.uid) && entity.components.ItemEjector) {
@ -134,11 +137,14 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
const ejectSlotTargetWsTile = ejectSlotWsTile.add(ejectSlotWsDirectionVector); const ejectSlotTargetWsTile = ejectSlotWsTile.add(ejectSlotWsDirectionVector);
// Try to find the given acceptor component to take the item // Try to find the given acceptor component to take the item
const targetEntity = this.root.map.getTileContent(ejectSlotTargetWsTile); // Since there can be cross layer dependencies, check on all layers
if (!targetEntity) { const targetEntities = this.root.map.getLayersContentsMultipleXY(
// No consumer for item ejectSlotTargetWsTile.x,
continue; ejectSlotTargetWsTile.y
} );
for (let i = 0; i < targetEntities.length; ++i) {
const targetEntity = targetEntities[i];
const targetAcceptorComp = targetEntity.components.ItemAcceptor; const targetAcceptorComp = targetEntity.components.ItemAcceptor;
const targetStaticComp = targetEntity.components.StaticMapEntity; const targetStaticComp = targetEntity.components.StaticMapEntity;
@ -149,7 +155,8 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
const matchingSlot = targetAcceptorComp.findMatchingSlot( const matchingSlot = targetAcceptorComp.findMatchingSlot(
targetStaticComp.worldToLocalTile(ejectSlotTargetWsTile), targetStaticComp.worldToLocalTile(ejectSlotTargetWsTile),
targetStaticComp.worldDirectionToLocal(ejectSlotWsDirection) targetStaticComp.worldDirectionToLocal(ejectSlotWsDirection),
ejectorSlot.layer
); );
if (!matchingSlot) { if (!matchingSlot) {
@ -163,8 +170,12 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
} else { } else {
ejectorComp.cachedConnectedSlots = [ejectorSlot]; ejectorComp.cachedConnectedSlots = [ejectorSlot];
} }
// A slot can always be connected to one other slot only
ejectorSlot.cachedTargetEntity = targetEntity; ejectorSlot.cachedTargetEntity = targetEntity;
ejectorSlot.cachedDestSlot = matchingSlot; ejectorSlot.cachedDestSlot = matchingSlot;
break;
}
} }
} }
@ -292,7 +303,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
const energyGeneratorComp = receiver.components.EnergyGenerator; const energyGeneratorComp = receiver.components.EnergyGenerator;
if (energyGeneratorComp) { if (energyGeneratorComp) {
if (energyGeneratorComp.tryTakeItem(item)) { if (energyGeneratorComp.tryTakeItem(item, slotIndex)) {
// Passed it over // Passed it over
return true; return true;
} }
@ -304,15 +315,21 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
return false; return false;
} }
draw(parameters) { /**
this.forEachMatchingEntityOnScreen(parameters, this.drawSingleEntity.bind(this)); * Draws the given layer
* @param {DrawParameters} parameters
* @param {enumLayer} layer
*/
drawLayer(parameters, layer) {
this.forEachMatchingEntityOnScreen(parameters, this.drawSingleEntity.bind(this, layer));
} }
/** /**
* @param {enumLayer} layer
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @param {Entity} entity * @param {Entity} entity
*/ */
drawSingleEntity(parameters, entity) { drawSingleEntity(layer, parameters, entity) {
const ejectorComp = entity.components.ItemEjector; const ejectorComp = entity.components.ItemEjector;
const staticComp = entity.components.StaticMapEntity; const staticComp = entity.components.StaticMapEntity;
@ -323,11 +340,17 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
for (let i = 0; i < ejectorComp.slots.length; ++i) { for (let i = 0; i < ejectorComp.slots.length; ++i) {
const slot = ejectorComp.slots[i]; const slot = ejectorComp.slots[i];
const ejectedItem = slot.item; const ejectedItem = slot.item;
if (!ejectedItem) { if (!ejectedItem) {
// No item // No item
continue; continue;
} }
if (slot.layer !== layer) {
// Not our layer
continue;
}
const realPosition = slot.pos.rotateFastMultipleOf90(staticComp.rotation); const realPosition = slot.pos.rotateFastMultipleOf90(staticComp.rotation);
const realDirection = Vector.transformDirectionFromMultipleOf90( const realDirection = Vector.transformDirectionFromMultipleOf90(
slot.direction, slot.direction,

View File

@ -6,6 +6,7 @@ import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter"; import { GameSystemWithFilter } from "../game_system_with_filter";
import { ColorItem } from "../items/color_item"; import { ColorItem } from "../items/color_item";
import { ShapeItem } from "../items/shape_item"; import { ShapeItem } from "../items/shape_item";
import { enumLayer } from "../root";
export class ItemProcessorSystem extends GameSystemWithFilter { export class ItemProcessorSystem extends GameSystemWithFilter {
constructor(root) { constructor(root) {
@ -48,11 +49,14 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
if (ejectorComp.canEjectOnSlot(preferredSlot)) { if (ejectorComp.canEjectOnSlot(preferredSlot)) {
slot = preferredSlot; slot = preferredSlot;
} else { } else {
slot = ejectorComp.getFirstFreeSlot(); /* FIXME: WIRES */
slot = ejectorComp.getFirstFreeSlot(enumLayer.regular);
} }
} else { } else {
/* FIXME: WIRES */
// We can eject on any slot // We can eject on any slot
slot = ejectorComp.getFirstFreeSlot(); slot = ejectorComp.getFirstFreeSlot(enumLayer.regular);
} }
if (slot !== null) { if (slot !== null) {

View File

@ -6,6 +6,7 @@ import { MinerComponent } from "../components/miner";
import { Entity } from "../entity"; import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter"; import { GameSystemWithFilter } from "../game_system_with_filter";
import { MapChunkView } from "../map_chunk_view"; import { MapChunkView } from "../map_chunk_view";
import { enumLayer } from "../root";
export class MinerSystem extends GameSystemWithFilter { export class MinerSystem extends GameSystemWithFilter {
constructor(root) { constructor(root) {
@ -74,7 +75,7 @@ export class MinerSystem extends GameSystemWithFilter {
const ejectingDirection = staticComp.localDirectionToWorld(ejectingSlot.direction); const ejectingDirection = staticComp.localDirectionToWorld(ejectingSlot.direction);
const targetTile = ejectingPos.add(enumDirectionToVector[ejectingDirection]); const targetTile = ejectingPos.add(enumDirectionToVector[ejectingDirection]);
const targetContents = this.root.map.getTileContent(targetTile); const targetContents = this.root.map.getTileContent(targetTile, enumLayer.regular);
// Check if we are connected to another miner and thus do not eject directly // Check if we are connected to another miner and thus do not eject directly
if (targetContents) { if (targetContents) {

View File

@ -4,6 +4,7 @@ import { globalConfig } from "../../core/config";
import { MapChunkView } from "../map_chunk_view"; import { MapChunkView } from "../map_chunk_view";
import { Loader } from "../../core/loader"; import { Loader } from "../../core/loader";
import { enumDirection } from "../../core/vector"; import { enumDirection } from "../../core/vector";
import { enumLayer } from "../root";
export class StaticMapEntitySystem extends GameSystem { export class StaticMapEntitySystem extends GameSystem {
constructor(root) { constructor(root) {
@ -40,7 +41,6 @@ export class StaticMapEntitySystem extends GameSystem {
continue; continue;
} }
drawnUids.add(entity.uid); drawnUids.add(entity.uid);
const staticComp = entity.components.StaticMapEntity; const staticComp = entity.components.StaticMapEntity;
if (drawOutlinesOnly) { if (drawOutlinesOnly) {
const rect = staticComp.getTileSpaceBounds(); const rect = staticComp.getTileSpaceBounds();
@ -68,4 +68,36 @@ export class StaticMapEntitySystem extends GameSystem {
} }
} }
} }
/**
* Draws the static wire entities
* @param {DrawParameters} parameters
* @param {MapChunkView} chunk
*/
drawWiresChunk(parameters, chunk) {
if (G_IS_DEV && globalConfig.debug.doNotRenderStatics) {
return;
}
const drawnUids = new Set();
const contents = chunk.wireContents;
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
const entity = contents[x][y];
if (entity) {
if (drawnUids.has(entity.uid)) {
continue;
}
drawnUids.add(entity.uid);
const staticComp = entity.components.StaticMapEntity;
const spriteKey = staticComp.spriteKey;
if (spriteKey) {
const sprite = Loader.getSprite(spriteKey);
staticComp.drawSpriteOnFullEntityBounds(parameters, sprite, 2, false);
}
}
}
}
}
} }

View File

@ -4,6 +4,7 @@ import { Entity } from "../entity";
import { DrawParameters } from "../../core/draw_parameters"; import { DrawParameters } from "../../core/draw_parameters";
import { formatBigNumber, lerp } from "../../core/utils"; import { formatBigNumber, lerp } from "../../core/utils";
import { Loader } from "../../core/loader"; import { Loader } from "../../core/loader";
import { enumLayer } from "../root";
export class StorageSystem extends GameSystemWithFilter { export class StorageSystem extends GameSystemWithFilter {
constructor(root) { constructor(root) {
@ -20,7 +21,9 @@ export class StorageSystem extends GameSystemWithFilter {
// Eject from storage // Eject from storage
if (storageComp.storedItem && storageComp.storedCount > 0) { if (storageComp.storedItem && storageComp.storedCount > 0) {
const ejectorComp = entity.components.ItemEjector; const ejectorComp = entity.components.ItemEjector;
const nextSlot = ejectorComp.getFirstFreeSlot();
/* FIXME: WIRES */
const nextSlot = ejectorComp.getFirstFreeSlot(enumLayer.regular);
if (nextSlot !== null) { if (nextSlot !== null) {
if (ejectorComp.tryEject(nextSlot, storageComp.storedItem)) { if (ejectorComp.tryEject(nextSlot, storageComp.storedItem)) {
storageComp.storedCount--; storageComp.storedCount--;

View File

@ -13,6 +13,7 @@ import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components
import { Entity } from "../entity"; import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter"; import { GameSystemWithFilter } from "../game_system_with_filter";
import { fastArrayDelete } from "../../core/utils"; import { fastArrayDelete } from "../../core/utils";
import { enumLayer } from "../root";
const logger = createLogger("tunnels"); const logger = createLogger("tunnels");
@ -95,7 +96,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
let matchingEntrance = null; let matchingEntrance = null;
for (let i = 0; i < range; ++i) { for (let i = 0; i < range; ++i) {
currentPos.addInplace(offset); currentPos.addInplace(offset);
const contents = this.root.map.getTileContent(currentPos); const contents = this.root.map.getTileContent(currentPos, entity.layer);
if (!contents) { if (!contents) {
continue; continue;
} }
@ -128,7 +129,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
for (let i = 0; i < matchingEntrance.range; ++i) { for (let i = 0; i < matchingEntrance.range; ++i) {
currentPos.addInplace(offset); currentPos.addInplace(offset);
const contents = this.root.map.getTileContent(currentPos); const contents = this.root.map.getTileContent(currentPos, entity.layer);
if (!contents) { if (!contents) {
allBeltsMatch = false; allBeltsMatch = false;
break; break;
@ -156,7 +157,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
// All belts between this are obsolete, so drop them // All belts between this are obsolete, so drop them
for (let i = 0; i < matchingEntrance.range; ++i) { for (let i = 0; i < matchingEntrance.range; ++i) {
currentPos.addInplace(offset); currentPos.addInplace(offset);
const contents = this.root.map.getTileContent(currentPos); const contents = this.root.map.getTileContent(currentPos, entity.layer);
assert(contents, "Invalid smart underground belt logic"); assert(contents, "Invalid smart underground belt logic");
this.root.logic.tryDeleteBuilding(contents); this.root.logic.tryDeleteBuilding(contents);
} }
@ -169,8 +170,8 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
const posBefore = currentPos.copy(); const posBefore = currentPos.copy();
currentPos.addInplace(offset); currentPos.addInplace(offset);
const entityBefore = this.root.map.getTileContent(posBefore); const entityBefore = this.root.map.getTileContent(posBefore, entity.layer);
const entityAfter = this.root.map.getTileContent(currentPos); const entityAfter = this.root.map.getTileContent(currentPos, entity.layer);
if (!entityBefore || !entityAfter) { if (!entityBefore || !entityAfter) {
continue; continue;
@ -233,10 +234,9 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
for (let x = area.x; x < area.right(); ++x) { for (let x = area.x; x < area.right(); ++x) {
for (let y = area.y; y < area.bottom(); ++y) { for (let y = area.y; y < area.bottom(); ++y) {
const entity = this.root.map.getTileContentXY(x, y); const entities = this.root.map.getLayersContentsMultipleXY(x, y);
if (!entity) { for (let i = 0; i < entities.length; ++i) {
continue; const entity = entities[i];
}
const undergroundComp = entity.components.UndergroundBelt; const undergroundComp = entity.components.UndergroundBelt;
if (!undergroundComp) { if (!undergroundComp) {
continue; continue;
@ -246,6 +246,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
} }
} }
} }
}
update() { update() {
if (this.areaToRecompute) { if (this.areaToRecompute) {
@ -297,7 +298,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
) { ) {
currentTile = currentTile.add(searchVector); currentTile = currentTile.add(searchVector);
const potentialReceiver = this.root.map.getTileContent(currentTile); const potentialReceiver = this.root.map.getTileContent(currentTile, enumLayer.regular);
if (!potentialReceiver) { if (!potentialReceiver) {
// Empty tile // Empty tile
continue; continue;
@ -393,7 +394,8 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
if (remainingTime <= 0) { if (remainingTime <= 0) {
const ejectorComp = entity.components.ItemEjector; const ejectorComp = entity.components.ItemEjector;
const nextSlotIndex = ejectorComp.getFirstFreeSlot();
const nextSlotIndex = ejectorComp.getFirstFreeSlot(entity.layer);
if (nextSlotIndex !== null) { if (nextSlotIndex !== null) {
if (ejectorComp.tryEject(nextSlotIndex, nextItem)) { if (ejectorComp.tryEject(nextSlotIndex, nextItem)) {
items.shift(); items.shift();

View File

@ -1,17 +1,22 @@
import { GameSystemWithFilter } from "../game_system_with_filter";
import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins";
import { DrawParameters } from "../../core/draw_parameters";
import { Entity } from "../entity";
import { THEME } from "../theme";
import { Loader } from "../../core/loader";
import { globalConfig } from "../../core/config"; import { globalConfig } from "../../core/config";
import { DrawParameters } from "../../core/draw_parameters";
import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins";
import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter";
import { MapChunkView } from "../map_chunk_view";
import { Loader } from "../../core/loader";
export class WiredPinsSystem extends GameSystemWithFilter { export class WiredPinsSystem extends GameSystemWithFilter {
constructor(root) { constructor(root) {
super(root, [WiredPinsComponent]); super(root, [WiredPinsComponent]);
this.pinSprites = { this.pinSprites = {
[enumPinSlotType.energyEjector]: [Loader.getSprite("sprites/wires/pin-energy-on.png")], [enumPinSlotType.positiveEnergyEjector]: Loader.getSprite(
"sprites/wires/pin-positive-energy.png"
),
[enumPinSlotType.negativeEnergyAcceptor]: Loader.getSprite(
"sprites/wires/pin-negative-energy.png"
),
}; };
} }
@ -19,25 +24,22 @@ export class WiredPinsSystem extends GameSystemWithFilter {
// TODO // TODO
} }
drawWiresLayer(parameters) { /**
this.forEachMatchingEntityOnScreen(parameters, this.drawEntityPins.bind(this)); * Draws the given layer
* @param {DrawParameters} parameters
*/
draw(parameters) {
this.forEachMatchingEntityOnScreen(parameters, this.drawSingleEntity.bind(this));
} }
/** /**
* * Draws a given chunk
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @param {Entity} entity * @param {Entity} entity
*/ */
drawEntityPins(parameters, entity) { drawSingleEntity(parameters, entity) {
const staticComp = entity.components.StaticMapEntity; const staticComp = entity.components.StaticMapEntity;
const slots = entity.components.WiredPins.slots;
if (!staticComp.shouldBeDrawn(parameters)) {
return;
}
const pinsComp = entity.components.WiredPins;
const slots = pinsComp.slots;
for (let i = 0; i < slots.length; ++i) { for (let i = 0; i < slots.length; ++i) {
const slot = slots[i]; const slot = slots[i];
@ -45,7 +47,7 @@ export class WiredPinsSystem extends GameSystemWithFilter {
const worldPos = tile.toWorldSpaceCenterOfTile(); const worldPos = tile.toWorldSpaceCenterOfTile();
this.pinSprites[slot.type][0].drawCachedCentered( this.pinSprites[slot.type].drawCachedCentered(
parameters, parameters,
worldPos.x, worldPos.x,
worldPos.y, worldPos.y,

View File

@ -441,6 +441,11 @@ buildings:
name: &belt Conveyor Belt name: &belt Conveyor Belt
description: Transports items, hold and drag to place multiple. description: Transports items, hold and drag to place multiple.
wire:
default:
name: &wire Wire
description: Allows to transport energy
miner: # Internal name for the Extractor miner: # Internal name for the Extractor
default: default:
name: &miner Extractor name: &miner Extractor
@ -801,6 +806,7 @@ keybindings:
energy_generator: *energy_generator energy_generator: *energy_generator
painter: *painter painter: *painter
trash: *trash trash: *trash
wire: *wire
pipette: Pipette pipette: Pipette
rotateWhilePlacing: Rotate rotateWhilePlacing: Rotate