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
oid sha256:27c8d1eaa48beb7187e37244bd6ef7f43429be84ac88fffa96a4d72eb0e6565b
size 158809
oid sha256:7f04a2e96f79d013838dc95e0fcc9c2c2b3519cedc5d44602ecde29b85558239
size 174256

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:590751d33bdb2ffa0f3c7f533688f6f93c37940e1e906be7972c9d5757ab7f69
size 57790
oid sha256:b0e6ae46466addd1bcb55a8005bbfb58fdf9e66c7fbae5620b723bdb21943b1c
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},
"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":
{
"frame": {"x":570,"y":105,"w":13,"h":13},
"frame": {"x":603,"y":3,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -882,7 +906,7 @@
},
"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,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -1080,6 +1104,30 @@
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":16},
"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":
{
"frame": {"x":82,"y":72,"w":6,"h":6},
@ -1122,7 +1170,7 @@
},
"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,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":10,"h":10},
@ -1146,7 +1194,7 @@
},
"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,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":10,"h":10},
@ -1154,7 +1202,7 @@
},
"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,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":10,"h":10},
@ -1178,18 +1226,26 @@
},
"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,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"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,
"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}
}},
"meta": {
@ -1197,8 +1253,8 @@
"version": "1.0",
"image": "atlas0_10.png",
"format": "RGBA8888",
"size": {"w":616,"h":128},
"size": {"w":629,"h":128},
"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":
{
"frame": {"x":1880,"y":594,"w":77,"h":95},
"frame": {"x":1879,"y":594,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -18,7 +18,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -26,7 +26,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -34,7 +34,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -42,7 +42,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -50,7 +50,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -58,7 +58,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -66,7 +66,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -74,7 +74,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -90,7 +90,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -106,7 +106,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -114,7 +114,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -122,7 +122,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -130,7 +130,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -138,7 +138,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -146,7 +146,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -154,7 +154,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -162,7 +162,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -170,7 +170,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -178,7 +178,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -186,7 +186,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -194,7 +194,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -202,7 +202,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -210,7 +210,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -218,7 +218,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -242,7 +242,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -250,7 +250,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -258,7 +258,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -266,7 +266,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -274,7 +274,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -282,7 +282,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -290,7 +290,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -298,7 +298,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -330,7 +330,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -346,7 +346,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -386,7 +386,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -394,7 +394,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -402,7 +402,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -410,7 +410,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -418,7 +418,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -426,7 +426,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -434,7 +434,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -442,7 +442,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -450,7 +450,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -458,7 +458,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -466,7 +466,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -474,7 +474,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -482,7 +482,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -490,7 +490,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -498,7 +498,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -506,7 +506,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -514,7 +514,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -522,7 +522,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -530,7 +530,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -538,7 +538,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -546,7 +546,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -554,7 +554,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -562,7 +562,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -570,7 +570,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -578,7 +578,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -586,7 +586,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -594,7 +594,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -602,7 +602,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -610,7 +610,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -618,7 +618,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -626,7 +626,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -634,7 +634,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -642,7 +642,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -650,7 +650,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -658,7 +658,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -666,7 +666,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -690,7 +690,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":0,"w":79,"h":95},
@ -794,7 +794,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":142,"h":138},
@ -802,7 +802,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":2,"w":139,"h":138},
@ -842,7 +842,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":19,"w":138,"h":125},
@ -850,7 +850,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":32,"w":138,"h":112},
@ -858,7 +858,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":139,"h":112},
@ -866,15 +866,39 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":138,"h":112},
"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":
{
"frame": {"x":1235,"y":1298,"w":86,"h":86},
"frame": {"x":1078,"y":1339,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -882,7 +906,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -890,7 +914,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -938,7 +962,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":403,"y":1135,"w":136,"h":142},
"frame": {"x":402,"y":1135,"w":136,"h":142},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":142},
@ -1002,7 +1026,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":3,"w":141,"h":136},
@ -1010,7 +1034,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":3,"w":139,"h":136},
@ -1050,7 +1074,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":20,"w":137,"h":124},
@ -1058,7 +1082,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":33,"w":137,"h":111},
@ -1066,7 +1090,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
@ -1074,15 +1098,39 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
"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":
{
"frame": {"x":1963,"y":145,"w":38,"h":48},
"frame": {"x":2000,"y":1185,"w":38,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":38,"h":48},
@ -1090,7 +1138,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":38,"h":48},
@ -1098,7 +1146,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -1106,7 +1154,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":22,"h":22},
@ -1114,7 +1162,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":22,"h":22},
@ -1122,7 +1170,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":62,"h":62},
@ -1138,7 +1186,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":36,"h":24},
@ -1146,7 +1194,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":62,"h":62},
@ -1154,7 +1202,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":62,"h":72},
@ -1162,7 +1210,7 @@
},
"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,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":133,"h":66},
@ -1170,7 +1218,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":974,"y":1338,"w":20,"h":24},
"frame": {"x":1836,"y":827,"w":20,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -1184,12 +1232,20 @@
"spriteSourceSize": {"x":0,"y":0,"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,
"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}
}},
"meta": {
@ -1197,8 +1253,8 @@
"version": "1.0",
"image": "atlas0_75.png",
"format": "RGBA8888",
"size": {"w":2042,"h":1419},
"size": {"w":2042,"h":1428},
"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,
energy_generator;
energy_generator, wire;
@each $building in $buildings {
[data-icon="building_icons/#{$building}.png"] {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@ import { Loader } from "../core/loader";
import { createLogger } from "../core/logging";
import { Vector } from "../core/vector";
import { Entity } from "./entity";
import { GameRoot } from "./root";
import { GameRoot, enumLayer } from "./root";
import { findNiceIntegerValue } from "../core/utils";
import { blueprintShape } from "./upgrades";
import { globalConfig } from "../core/config";
@ -18,6 +18,17 @@ export class Blueprint {
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
* @param {GameRoot} root
@ -183,7 +194,7 @@ export class Blueprint {
rect.moveBy(tile.x, tile.y);
placementCheck: for (let x = rect.x; x < rect.right(); ++x) {
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) {
placeable = false;
break placementCheck;
@ -194,7 +205,7 @@ export class Blueprint {
if (placeable) {
for (let x = rect.x; x < rect.right(); ++x) {
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) {
assert(
contents.components.ReplaceableMapEntity,

View File

@ -9,7 +9,7 @@ import { ItemEjectorComponent } from "../components/item_ejector";
import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity";
import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { GameRoot, enumLayer } from "../root";
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 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 hasRightEjector = false;

View File

@ -2,11 +2,12 @@ import { enumDirection, Vector } from "../../core/vector";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { GameRoot, enumLayer } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
import { EnergyGeneratorComponent } from "../components/energy_generator";
import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins";
import { enumItemType } from "../base_item";
import { ItemEjectorComponent } from "../components/item_ejector";
export class MetaEnergyGenerator extends MetaBuilding {
constructor() {
@ -71,6 +72,25 @@ export class MetaEnergyGenerator extends MetaBuilding {
directions: [enumDirection.bottom],
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: [
{
pos: new Vector(0, 0),
type: enumPinSlotType.energyEjector,
type: enumPinSlotType.positiveEnergyEjector,
direction: enumDirection.top,
},
{
pos: new Vector(1, 0),
type: enumPinSlotType.energyEjector,
},
{
pos: new Vector(0, 1),
type: enumPinSlotType.energyEjector,
},
{
pos: new Vector(1, 1),
type: enumPinSlotType.energyEjector,
type: enumPinSlotType.negativeEnergyAcceptor,
direction: enumDirection.top,
},
],
})

View File

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

View File

@ -5,7 +5,7 @@ import { ItemEjectorComponent } from "../components/item_ejector";
import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt";
import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { GameRoot, enumLayer } from "../root";
import { globalConfig } from "../../core/config";
import { enumHubGoalRewards } from "../tutorial_goals";
import { formatItemsPerSecond } from "../../core/utils";
@ -152,7 +152,8 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding {
) {
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) {
const undergroundComp = contents.components.UndergroundBelt;
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 { 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 {
static getId() {
@ -12,7 +15,8 @@ export class EnergyGeneratorComponent extends Component {
static getSchema() {
return {
requiredKey: types.string,
requiredKey: types.nullable(types.string),
itemsInQueue: types.uint,
};
}
@ -35,20 +39,27 @@ export class EnergyGeneratorComponent extends Component {
/**
*
* @param {BaseItem} item
* @param {number} slot
*/
tryTakeItem(item) {
if (/** @type {ShapeItem} */ (item).definition.getHash() !== this.requiredKey) {
// Not our shape
return false;
}
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) {
// Not our shape
return false;
}
if (this.itemsInQueue >= maxQueueSize) {
// Queue is full
return false;
}
if (this.itemsInQueue >= maxQueueSize) {
// Queue is full
return false;
}
// Take item and put it into the queue
++this.itemsInQueue;
return true;
// Take item and put it into the queue
++this.itemsInQueue;
return true;
}
}
}

View File

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

View File

@ -4,12 +4,14 @@ import { Component } from "../component";
import { types } from "../../savegame/serialization";
import { gItemRegistry } from "../../core/global_registries";
import { Entity } from "../entity";
import { enumLayer } from "../root";
/**
* @typedef {{
* pos: Vector,
* direction: enumDirection,
* item: BaseItem,
* layer: enumLayer,
* progress: number?,
* cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot,
* cachedTargetEntity?: Entity
@ -32,6 +34,9 @@ export class ItemEjectorComponent extends Component {
direction: types.enum(enumDirection),
item: types.nullable(types.obj(gItemRegistry)),
progress: types.float,
// TODO: Migrate
layer: types.enum(enumLayer),
})
),
};
@ -44,6 +49,7 @@ export class ItemEjectorComponent extends Component {
slotsCopy.push({
pos: slot.pos.copy(),
direction: slot.direction,
layer: slot.layer,
});
}
@ -56,7 +62,7 @@ export class ItemEjectorComponent extends Component {
/**
*
* @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
*/
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) {
/** @type {Array<ItemEjectorSlot>} */
@ -89,19 +95,13 @@ export class ItemEjectorComponent extends Component {
direction: slot.direction,
item: null,
progress: 0,
layer: slot.layer || enumLayer.regular,
cachedDestSlot: null,
cachedTargetEntity: null,
});
}
}
/**
* Returns the amount of slots
*/
getNumSlots() {
return this.slots.length;
}
/**
* Returns where this slot ejects to
* @param {number} index
@ -116,26 +116,17 @@ export class ItemEjectorComponent extends Component {
/**
* Returns whether any slot ejects to the given local tile
* @param {Vector} tile
* @param {enumLayer} layer
*/
anySlotEjectsToLocalTile(tile) {
anySlotEjectsToLocalTile(tile, layer) {
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 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
* @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
* @param {enumLayer} layer
* @returns {number?}
*/
getFirstFreeSlot() {
getFirstFreeSlot(layer) {
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 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
* @param {number} slotIndex

View File

@ -1,21 +1,25 @@
import { Component } from "../component";
import { Vector } from "../../core/vector";
import { Vector, enumDirection } from "../../core/vector";
import { types } from "../../savegame/serialization";
/** @enum {string} */
export const enumPinSlotType = {
energyEjector: "energyEjector",
positiveEnergyEjector: "positiveEnergyEjector",
negativeEnergyEjector: "negativeEnergyEjector",
positiveEnergyAcceptor: "positiveEnergyAcceptor",
negativeEnergyAcceptor: "positiveEnergyAcceptor",
};
/** @typedef {{
* pos: Vector,
* type: enumPinSlotType
* type: enumPinSlotType,
* direction: enumDirection
* }} WirePinSlotDefinition */
/** @typedef {{
* pos: Vector,
* type: enumPinSlotType,
* value: number
* direction: enumDirection
* }} WirePinSlot */
export class WiredPinsComponent extends Component {
@ -29,7 +33,6 @@ export class WiredPinsComponent extends Component {
types.structured({
pos: types.vector,
type: types.enum(enumPinSlotType),
value: types.float,
})
),
};
@ -58,7 +61,7 @@ export class WiredPinsComponent extends Component {
this.slots.push({
pos: slotData.pos,
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 { GameLogic } from "./logic";
import { MapView } from "./map_view";
import { GameRoot, enumEditMode } from "./root";
import { GameRoot, enumLayer } from "./root";
import { ShapeDefinitionManager } from "./shape_definition_manager";
import { SoundProxy } from "./sound_proxy";
import { GameTime } from "./time/game_time";
@ -393,26 +393,36 @@ export class GameCore {
root.map.drawBackground(params);
if (!this.root.camera.getIsMapOverlayActive()) {
systems.itemAcceptor.drawUnderlays(params);
systems.belt.draw(params);
systems.itemEjector.draw(params);
systems.itemAcceptor.draw(params);
systems.itemAcceptor.drawUnderlays(params, enumLayer.regular);
systems.belt.drawLayer(params, enumLayer.regular);
systems.itemEjector.drawLayer(params, enumLayer.regular);
systems.itemAcceptor.drawLayer(params, enumLayer.regular);
}
root.map.drawForeground(params);
if (!this.root.camera.getIsMapOverlayActive()) {
systems.hub.draw(params);
systems.energyGenerator.draw(params);
systems.storage.draw(params);
}
/* wires:start */
root.hud.parts.wiresOverlay.draw(params);
if (this.root.editMode === enumEditMode.wires) {
systems.wiredPins.drawWiresLayer(params);
if (this.root.currentLayer === enumLayer.wires) {
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) {
root.map.drawStaticEntityDebugOverlays(params);

View File

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

View File

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

View File

@ -1,9 +1,9 @@
/* typehints:start */
import { Component } from "./component";
import { GameRoot } from "./root";
import { Entity } from "./entity";
/* typehints:end */
import { GameRoot, enumLayer } from "./root";
import { GameSystem } from "./game_system";
import { arrayDelete, arrayDeleteValue } from "../core/utils";
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
* @param {DrawParameters} parameters
* @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();
if (this.allEntities.length < 100) {
// So, its much quicker to simply perform per-entity checking
@ -48,7 +49,9 @@ export class GameSystemWithFilter extends GameSystem {
for (let i = 0; i < this.allEntities.length; ++i) {
const entity = this.allEntities[i];
if (cullRange.containsRect(entity.components.StaticMapEntity.getTileSpaceBounds())) {
callback(parameters, entity);
if (!layerFilter || entity.layer === layerFilter) {
callback(parameters, entity);
}
}
}
return;
@ -91,10 +94,16 @@ export class GameSystemWithFilter extends GameSystem {
entityLoop: for (let i = 0; i < entities.length; ++i) {
const entity = entities[i];
// Avoid drawing non-layer contents
if (layerFilter && entity.layer !== layerFilter) {
continue;
}
// Avoid drawing twice
if (seenUids.has(entity.uid)) {
continue;
}
seenUids.add(entity.uid);
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 { queryParamOptions } from "../../core/query_parameters";
import { HUDSandboxController } from "./parts/sandbox_controller";
import { HUDWiresToolbar } from "./parts/wires_toolbar";
export class GameHUD {
/**
@ -56,6 +57,7 @@ export class GameHUD {
this.parts = {
processingOverlay: new HUDProcessingOverlay(this.root),
buildingsToolbar: new HUDBuildingsToolbar(this.root),
wiresToolbar: new HUDWiresToolbar(this.root),
blueprintPlacer: new HUDBlueprintPlacer(this.root),
buildingPlacer: new HUDBuildingPlacer(this.root),
unlockNotification: new HUDUnlockNotification(this.root),
@ -75,9 +77,7 @@ export class GameHUD {
screenshotExporter: new HUDScreenshotExporter(this.root),
shapeViewer: new HUDShapeViewer(this.root),
/* wires:start */
wiresOverlay: new HUDWiresOverlay(this.root),
/* wires:end */
// Typing hints
/* typehints:start */
@ -87,6 +87,7 @@ export class GameHUD {
};
this.signals = {
buildingSelectedForPlacement: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()),
selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()),
shapePinRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()),
@ -139,7 +140,6 @@ export class GameHUD {
for (const key in this.parts) {
this.parts[key].initialize();
}
this.internalInitSignalConnections();
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this);
@ -205,14 +205,6 @@ export class GameHUD {
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
*/

View File

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

View File

@ -11,6 +11,7 @@ import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { Blueprint } from "../../blueprint";
import { SOUNDS } from "../../../platform/sound";
import { enumLayer } from "../../root";
export class HUDBlueprintPlacer extends BaseHUDPart {
createElements(parent) {
@ -26,7 +27,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
initialize() {
this.root.hud.signals.buildingsSelectedForCopy.add(this.onBuildingsSelected, this);
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
/** @type {TypedTrackedState<Blueprint?>} */
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.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
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) {
this.costDisplayParent.classList.toggle("canAfford", canAfford);
}
@ -67,6 +87,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
/**
* Called when the blueprint was changed
* @param {Blueprint} blueprint
*/
onBlueprintChanged(blueprint) {
@ -105,13 +126,12 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
const cost = blueprint.getCost();
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
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() {
// Prevent movement while blueprint is selected
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
*/
onBuildingsSelected(uids) {
createBlueprintFromBuildings(uids) {
if (uids.length === 0) {
return;
}
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
}
/**
* Attempts to rotate the current blueprint
*/
rotateBlueprint() {
if (this.currentBlueprint.get()) {
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() {
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.currentBlueprint.set(this.lastBlueprintUsed);
} else {

View File

@ -49,6 +49,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
// Bind to signals
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.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 badArrowSprite = Loader.getSprite("sprites/misc/slot_bad_arrow.png");
// Just ignore this code ...
// Just ignore the following code please ... thanks!
const offsetShift = 10;
@ -397,6 +398,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const slots = acceptorComp.slots;
for (let acceptorSlotIndex = 0; acceptorSlotIndex < slots.length; ++acceptorSlotIndex) {
const slot = slots[acceptorSlotIndex];
const acceptorSlotWsTile = staticComp.localTileToWorld(slot.pos);
const acceptorSlotWsPos = acceptorSlotWsTile.toWorldSpaceCenterOfTile();
@ -409,7 +411,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const worldDirection = staticComp.localDirectionToWorld(direction);
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 alpha = 0.5;
@ -419,7 +421,13 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const sourceEjector = sourceEntity.components.ItemEjector;
const sourceStaticComp = sourceEntity.components.StaticMapEntity;
const ejectorAcceptLocalTile = sourceStaticComp.worldToLocalTile(acceptorSlotWsTile);
if (sourceEjector && sourceEjector.anySlotEjectsToLocalTile(ejectorAcceptLocalTile)) {
if (
sourceEjector &&
sourceEjector.anySlotEjectsToLocalTile(
ejectorAcceptLocalTile,
this.root.currentLayer
)
) {
sprite = goodArrowSprite;
}
alpha = 1.0;
@ -443,7 +451,10 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
if (ejectorComp) {
const slots = ejectorComp.slots;
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(
ejectorComp.getSlotTargetLocalTile(ejectorSlotIndex)
@ -451,7 +462,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
const ejectorSLotWsPos = ejectorSlotWsTile.toWorldSpaceCenterOfTile();
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 alpha = 0.5;
@ -463,7 +474,9 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
if (destAcceptor) {
const destLocalTile = destStaticComp.worldToLocalTile(ejectorSlotWsTile);
const destLocalDir = destStaticComp.worldDirectionToLocal(ejectorSlotWsDirection);
if (destAcceptor.findMatchingSlot(destLocalTile, destLocalDir)) {
if (
destAcceptor.findMatchingSlot(destLocalTile, destLocalDir, this.root.currentLayer)
) {
sprite = goodArrowSprite;
} else {
sprite = badArrowSprite;

View File

@ -12,7 +12,7 @@ import { BaseHUDPart } from "../base_hud_part";
import { SOUNDS } from "../../../platform/sound";
import { MetaMinerBuilding, enumMinerVariants } from "../../buildings/miner";
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
@ -125,12 +125,12 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
/**
* Called when the edit mode got changed
* @param {enumEditMode} editMode
* @param {enumLayer} editMode
*/
onEditModeChanged(editMode) {
const metaBuilding = this.currentMetaBuilding.get();
if (metaBuilding) {
if (metaBuilding.getEditLayer() !== editMode) {
if (metaBuilding.getLayer() !== editMode) {
// This layer doesn't fit the edit mode anymore
this.currentMetaBuilding.set(null);
}
@ -276,7 +276,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (contents) {
if (this.root.logic.tryDeleteBuilding(contents)) {
this.root.soundProxy.playUi(SOUNDS.destroyBuilding);
@ -302,7 +302,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
const contents = this.root.map.getTileContent(tile, this.root.currentLayer);
if (!contents) {
const tileBelow = this.root.map.getLowerLayerContentXY(tile.x, tile.y);
@ -322,6 +322,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
// Try to extract the building
const extracted = this.hack_reconstructMetaBuildingAndVariantFromBuilding(contents);
// If the building we are picking is the same as the one we have, clear the cursor.
if (
!extracted ||
@ -335,11 +336,6 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
this.currentMetaBuilding.set(extracted.metaBuilding);
this.currentVariant.set(extracted.variant);
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()) {
if (this.currentlyDeleting) {
// 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 (this.root.logic.tryDeleteBuilding(contents)) {
anythingDeleted = true;

View File

@ -9,10 +9,10 @@ import { MetaSplitterBuilding } from "../../buildings/splitter";
import { MetaStackerBuilding } from "../../buildings/stacker";
import { MetaTrashBuilding } from "../../buildings/trash";
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
import { enumEditMode } from "../../root";
import { enumLayer } from "../../root";
import { HUDBaseToolbar } from "./base_toolbar";
const toolbarBuildings = [
const supportedBuildings = [
MetaBeltBaseBuilding,
MetaSplitterBuilding,
MetaUndergroundBeltBuilding,
@ -24,17 +24,16 @@ const toolbarBuildings = [
MetaPainterBuilding,
MetaTrashBuilding,
/* wires:start */
MetaEnergyGenerator,
/* wires:end */
];
export class HUDBuildingsToolbar extends HUDBaseToolbar {
constructor(root) {
super(
root,
toolbarBuildings,
() => !this.root.camera.getIsMapOverlayActive() && this.root.editMode === enumEditMode.regular
);
super(root, {
supportedBuildings,
visibilityCondition: () =>
!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 { T } from "../../../translations";
import { enumItemType } from "../../base_item";
import { enumEditMode } from "../../root";
import { enumLayer } from "../../root";
export class HUDColorBlindHelper extends BaseHUDPart {
createElements(parent) {
@ -41,14 +41,14 @@ export class HUDColorBlindHelper extends BaseHUDPart {
return null;
}
if (this.root.editMode !== enumEditMode.regular) {
if (this.root.currentLayer !== enumLayer.regular) {
// Not in regular mode
return null;
}
const worldPos = this.root.camera.screenToWorld(mousePosition);
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) {
const beltComp = contents.components.Belt;
@ -66,6 +66,9 @@ export class HUDColorBlindHelper extends BaseHUDPart {
if (ejectorComp) {
for (let i = 0; i < ejectorComp.slots.length; ++i) {
const slot = ejectorComp.slots[i];
if (slot.layer !== this.root.currentLayer) {
continue;
}
if (slot.item && slot.item.getItemType() === enumItemType.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.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) {
removeAllChildren(this.entityInfoElem);
let html = "Entity";

View File

@ -255,14 +255,12 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
condition: () => this.anythingSelectedOnMap,
},
/* wires:start */
{
// Switch layers
label: T.ingame.keybindingsOverlay.switchLayers,
keys: [k.ingame.switchLayers],
condition: () => true,
},
/* wires:end */
];
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 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)) {
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 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)) {
const staticComp = contents.components.StaticMapEntity;
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);
}

View File

@ -2,7 +2,7 @@ import { makeOffscreenBuffer } from "../../../core/buffer_utils";
import { globalConfig } from "../../../core/config";
import { DrawParameters } from "../../../core/draw_parameters";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { enumEditMode } from "../../root";
import { enumLayer } from "../../root";
import { THEME } from "../../theme";
import { BaseHUDPart } from "../base_hud_part";
import { Loader } from "../../../core/loader";
@ -26,12 +26,12 @@ export class HUDWiresOverlay extends BaseHUDPart {
* Switches between layers
*/
switchLayers() {
if (this.root.editMode === enumEditMode.regular) {
this.root.editMode = enumEditMode.wires;
if (this.root.currentLayer === enumLayer.regular) {
this.root.currentLayer = enumLayer.wires;
} 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() {
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);
}
@ -63,6 +63,10 @@ export class HUDWiresOverlay extends BaseHUDPart {
return;
}
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
if (!this.cachedPatternBackground) {
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 { ShapeItem } from "./items/shape_item";
import { ColorItem } from "./items/color_item";
import { PositiveEnergyItem } from "./items/positive_energy_item";
import { NegativeEnergyItem } from "./items/negative_energy_item";
export function initItemRegistry() {
gItemRegistry.register(ShapeItem);
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
toggleFPSInfo: { keyCode: 115 }, // F4
/* wires:start */
switchLayers: { keyCode: key("Y") },
/* wires:end */
},
navigation: {
@ -55,10 +53,10 @@ export const KEYMAPPINGS = {
mixer: { keyCode: key("8") },
painter: { keyCode: key("9") },
trash: { keyCode: key("0") },
/* wires:start */
energy_generator: { keyCode: key("O") },
/* wires:end */
// Wires layer
wire: { keyCode: key("1") },
},
placement: {

View File

@ -1,4 +1,4 @@
import { GameRoot } from "./root";
import { GameRoot, enumLayer, arrayLayers } from "./root";
import { Entity } from "./entity";
import { Vector, enumDirectionToVector, enumDirection } from "../core/vector";
import { MetaBuilding } from "./meta_building";
@ -63,16 +63,16 @@ export class GameLogic {
blueprintSpriteKey: "",
});
const layer = building.getLayer();
const rect = checker.getTileSpaceBounds();
for (let x = rect.x; x < rect.x + rect.w; ++x) {
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 (
!this.checkCanReplaceBuilding({
original: contents,
origin,
building,
rotation,
rotationVariant,
@ -82,6 +82,25 @@ export class GameLogic {
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;
@ -91,18 +110,22 @@ export class GameLogic {
* Checks if the given building can be replaced by another
* @param {object} param0
* @param {Entity} param0.original
* @param {Vector} param0.origin
* @param {number} param0.rotation
* @param {number} param0.rotationVariant
* @param {MetaBuilding} param0.building
* @returns {boolean}
*/
checkCanReplaceBuilding({ original, origin, building, rotation, rotationVariant }) {
checkCanReplaceBuilding({ original, building, rotation, rotationVariant }) {
if (!original.components.ReplaceableMapEntity) {
// Can not get replaced at all
return false;
}
if (building.getLayer() !== original.layer) {
// Layer mismatch
return false;
}
const staticComp = original.components.StaticMapEntity;
assert(staticComp, "Building is not static");
const beltComp = original.components.Belt;
@ -162,11 +185,12 @@ export class GameLogic {
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 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 (!this.tryDeleteBuilding(contents)) {
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
* @param {Vector} tile
* @param {enumLayer} layer
* @returns {AcceptorsAndEjectorsAffectingTile}
*/
getEjectorsAndAcceptorsAtTile(tile) {
getEjectorsAndAcceptorsAtTile(tile, layer) {
/** @type {EjectorsAffectingTile} */
let ejectors = [];
/** @type {AcceptorsAffectingTile} */
@ -247,13 +272,16 @@ export class GameLogic {
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) {
const staticComp = entity.components.StaticMapEntity;
const itemEjector = entity.components.ItemEjector;
if (itemEjector) {
for (let ejectorSlot = 0; ejectorSlot < itemEjector.slots.length; ++ejectorSlot) {
const slot = itemEjector.slots[ejectorSlot];
if (slot.layer !== layer) {
continue;
}
const wsTile = staticComp.localTileToWorld(slot.pos);
const wsDirection = staticComp.localDirectionToWorld(slot.direction);
const targetTile = wsTile.add(enumDirectionToVector[wsDirection]);
@ -272,6 +300,10 @@ export class GameLogic {
if (itemAcceptor) {
for (let acceptorSlot = 0; acceptorSlot < itemAcceptor.slots.length; ++acceptorSlot) {
const slot = itemAcceptor.slots[acceptorSlot];
if (slot.layer !== layer) {
continue;
}
const wsTile = staticComp.localTileToWorld(slot.pos);
for (let k = 0; k < slot.directions.length; ++k) {
const direction = slot.directions[k];

View File

@ -1,7 +1,4 @@
/* typehints:start */
import { GameRoot } from "./root";
/* typehints:end */
import { GameRoot, enumLayer } from "./root";
import { globalConfig } from "../core/config";
import { Vector } from "../core/vector";
import { Entity } from "./entity";
@ -102,14 +99,15 @@ export class BaseMap extends BasicSerializableObject {
/**
* Returns the tile content of a given tile
* @param {Vector} tile
* @param {enumLayer} layer
* @returns {Entity} Entity or null
*/
getTileContent(tile) {
getTileContent(tile, layer) {
if (G_IS_DEV) {
this.internalCheckTile(tile);
}
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);
}
/**
* 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
* @param {Vector} tile
@ -167,7 +188,12 @@ export class BaseMap extends BasicSerializableObject {
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;
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) {
const x = rect.x + dx;
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) {
const x = rect.x + dx;
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
/**

View File

@ -1,7 +1,4 @@
/* typehints:start */
import { GameRoot } from "./root";
/* typehints:end */
import { GameRoot, enumLayer } from "./root";
import { globalConfig } from "../core/config";
import { createLogger } from "../core/logging";
import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "../core/utils";
@ -37,6 +34,13 @@ export class MapChunk {
"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>>} */
this.lowerLayer = make2DUndefinedArray(
globalConfig.mapChunkSize,
@ -324,6 +328,53 @@ export class MapChunk {
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
* @param {number} localX
@ -344,22 +395,36 @@ export class MapChunk {
* @param {number} tileX
* @param {number} tileY
* @param {Entity=} contents
* @param {enumLayer} layer
*/
setTileContentFromWorldCords(tileX, tileY, contents) {
setLayerContentFromWorldCords(tileX, tileY, contents, layer) {
const localX = tileX - this.tileX;
const localY = tileY - 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 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);
if (oldContents) {
// Remove from list
fastArrayDeleteValueIfContained(this.containedEntities, oldContents);
}
this.contents[localX][localY] = contents;
if (layer === enumLayer.regular) {
this.contents[localX][localY] = contents;
} else {
this.wireContents[localX][localY] = contents;
}
if (contents) {
if (this.containedEntities.indexOf(contents) < 0) {
this.containedEntities.push(contents);

View File

@ -23,6 +23,7 @@ export class MapChunkView extends MapChunk {
this.boundInternalDrawBackgroundToContext = this.internalDrawBackgroundToContext.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
@ -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
@ -181,6 +211,35 @@ export class MapChunkView extends MapChunk {
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
*/
@ -190,6 +249,16 @@ export class MapChunkView extends MapChunk {
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
*/

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
* @param {DrawParameters} parameters

View File

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

View File

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

View File

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

View File

@ -13,6 +13,9 @@ import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter";
import { MapChunkView } from "../map_chunk_view";
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;
@ -33,6 +36,15 @@ export class BeltSystem extends GameSystemWithFilter {
[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>>}
*/
@ -120,7 +132,10 @@ export class BeltSystem extends GameSystemWithFilter {
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
const originalRect = staticComp.getTileSpaceBounds();
@ -133,7 +148,7 @@ export class BeltSystem extends GameSystemWithFilter {
continue;
}
const targetEntity = this.root.map.getTileContentXY(x, y);
const targetEntity = this.root.map.getLayerContentXY(x, y, entity.layer);
if (!targetEntity) {
// Empty tile
continue;
@ -296,10 +311,14 @@ export class BeltSystem extends GameSystemWithFilter {
/**
* Draws all belt paths
* @param {DrawParameters} parameters
* @param {enumLayer} layer
*/
draw(parameters) {
drawLayer(parameters, layer) {
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 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
if (followUpEntity) {
@ -349,6 +368,12 @@ export class BeltSystem extends GameSystemWithFilter {
const acceptorSlots = followUpAcceptor.slots;
for (let i = 0; i < acceptorSlots.length; ++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) {
const localDirection = followUpStatic.localDirectionToWorld(slot.directions[k]);
if (enumInvertedDirections[localDirection] === followUpDirection) {
@ -374,7 +399,7 @@ export class BeltSystem extends GameSystemWithFilter {
const supplyVector = enumDirectionToVector[supplyDirection];
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
if (supplyEntity) {
@ -387,6 +412,11 @@ export class BeltSystem extends GameSystemWithFilter {
const ejectorSlots = supplyEjector.slots;
for (let i = 0; i < ejectorSlots.length; ++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);
if (enumInvertedDirections[localDirection] === supplyDirection) {
return supplyEntity;
@ -510,6 +540,45 @@ export class BeltSystem extends GameSystemWithFilter {
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
* @param {DrawParameters} parameters

View File

@ -1,10 +1,11 @@
import { DrawParameters } from "../../core/draw_parameters";
import { formatBigNumber } from "../../core/utils";
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 { GameSystemWithFilter } from "../game_system_with_filter";
import { POSITIVE_ENERGY_ITEM_SINGLETON } from "../items/positive_energy_item";
import { ShapeDefinition } from "../shape_definition";
import { formatBigNumber } from "../../core/utils";
export class EnergyGeneratorSystem extends GameSystemWithFilter {
constructor(root) {
@ -27,11 +28,18 @@ export class EnergyGeneratorSystem extends GameSystemWithFilter {
for (let i = 0; i < this.allEntities.length; ++i) {
const entity = this.allEntities[i];
const energyGenComp = entity.components.EnergyGenerator;
const ejectorComp = entity.components.ItemEjector;
if (!energyGenComp.requiredKey) {
// Compute required key for this generator
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 { BELT_ANIM_COUNT } from "./belt";
import { fastArrayDelete } from "../../core/utils";
import { enumLayer } from "../root";
export class ItemAcceptorSystem extends GameSystemWithFilter {
constructor(root) {
@ -49,19 +50,30 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
}
}
draw(parameters) {
this.forEachMatchingEntityOnScreen(parameters, this.drawEntity.bind(this));
}
drawUnderlays(parameters) {
this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this));
/**
* Draws the acceptor items
* @param {DrawParameters} parameters
* @param {enumLayer} layer
*/
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 {Entity} entity
*/
drawEntity(parameters, entity) {
drawEntityRegularLayer(layer, parameters, entity) {
const staticComp = entity.components.StaticMapEntity;
const acceptorComp = entity.components.ItemAcceptor;
@ -75,8 +87,12 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
];
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 finalTile = slotWorldPos.subScalars(
fadeOutDirection.x * (animProgress / 2 - 0.5),
@ -91,10 +107,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
}
/**
* @param {enumLayer} layer
* @param {DrawParameters} parameters
* @param {Entity} entity
*/
drawEntityUnderlays(parameters, entity) {
drawEntityUnderlays(layer, parameters, entity) {
const staticComp = entity.components.StaticMapEntity;
const acceptorComp = entity.components.ItemAcceptor;
@ -107,7 +124,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
const underlays = acceptorComp.beltUnderlays;
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 angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)];

View File

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

View File

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

View File

@ -6,6 +6,7 @@ import { MinerComponent } from "../components/miner";
import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter";
import { MapChunkView } from "../map_chunk_view";
import { enumLayer } from "../root";
export class MinerSystem extends GameSystemWithFilter {
constructor(root) {
@ -74,7 +75,7 @@ export class MinerSystem extends GameSystemWithFilter {
const ejectingDirection = staticComp.localDirectionToWorld(ejectingSlot.direction);
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
if (targetContents) {

View File

@ -4,6 +4,7 @@ import { globalConfig } from "../../core/config";
import { MapChunkView } from "../map_chunk_view";
import { Loader } from "../../core/loader";
import { enumDirection } from "../../core/vector";
import { enumLayer } from "../root";
export class StaticMapEntitySystem extends GameSystem {
constructor(root) {
@ -40,7 +41,6 @@ export class StaticMapEntitySystem extends GameSystem {
continue;
}
drawnUids.add(entity.uid);
const staticComp = entity.components.StaticMapEntity;
if (drawOutlinesOnly) {
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 { formatBigNumber, lerp } from "../../core/utils";
import { Loader } from "../../core/loader";
import { enumLayer } from "../root";
export class StorageSystem extends GameSystemWithFilter {
constructor(root) {
@ -20,7 +21,9 @@ export class StorageSystem extends GameSystemWithFilter {
// Eject from storage
if (storageComp.storedItem && storageComp.storedCount > 0) {
const ejectorComp = entity.components.ItemEjector;
const nextSlot = ejectorComp.getFirstFreeSlot();
/* FIXME: WIRES */
const nextSlot = ejectorComp.getFirstFreeSlot(enumLayer.regular);
if (nextSlot !== null) {
if (ejectorComp.tryEject(nextSlot, storageComp.storedItem)) {
storageComp.storedCount--;

View File

@ -13,6 +13,7 @@ import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components
import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter";
import { fastArrayDelete } from "../../core/utils";
import { enumLayer } from "../root";
const logger = createLogger("tunnels");
@ -95,7 +96,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
let matchingEntrance = null;
for (let i = 0; i < range; ++i) {
currentPos.addInplace(offset);
const contents = this.root.map.getTileContent(currentPos);
const contents = this.root.map.getTileContent(currentPos, entity.layer);
if (!contents) {
continue;
}
@ -128,7 +129,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
for (let i = 0; i < matchingEntrance.range; ++i) {
currentPos.addInplace(offset);
const contents = this.root.map.getTileContent(currentPos);
const contents = this.root.map.getTileContent(currentPos, entity.layer);
if (!contents) {
allBeltsMatch = false;
break;
@ -156,7 +157,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
// All belts between this are obsolete, so drop them
for (let i = 0; i < matchingEntrance.range; ++i) {
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");
this.root.logic.tryDeleteBuilding(contents);
}
@ -169,8 +170,8 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
const posBefore = currentPos.copy();
currentPos.addInplace(offset);
const entityBefore = this.root.map.getTileContent(posBefore);
const entityAfter = this.root.map.getTileContent(currentPos);
const entityBefore = this.root.map.getTileContent(posBefore, entity.layer);
const entityAfter = this.root.map.getTileContent(currentPos, entity.layer);
if (!entityBefore || !entityAfter) {
continue;
@ -233,16 +234,16 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
for (let x = area.x; x < area.right(); ++x) {
for (let y = area.y; y < area.bottom(); ++y) {
const entity = this.root.map.getTileContentXY(x, y);
if (!entity) {
continue;
}
const undergroundComp = entity.components.UndergroundBelt;
if (!undergroundComp) {
continue;
}
const entities = this.root.map.getLayersContentsMultipleXY(x, y);
for (let i = 0; i < entities.length; ++i) {
const entity = entities[i];
const undergroundComp = entity.components.UndergroundBelt;
if (!undergroundComp) {
continue;
}
undergroundComp.cachedLinkedEntity = null;
undergroundComp.cachedLinkedEntity = null;
}
}
}
}
@ -297,7 +298,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
) {
currentTile = currentTile.add(searchVector);
const potentialReceiver = this.root.map.getTileContent(currentTile);
const potentialReceiver = this.root.map.getTileContent(currentTile, enumLayer.regular);
if (!potentialReceiver) {
// Empty tile
continue;
@ -393,7 +394,8 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
if (remainingTime <= 0) {
const ejectorComp = entity.components.ItemEjector;
const nextSlotIndex = ejectorComp.getFirstFreeSlot();
const nextSlotIndex = ejectorComp.getFirstFreeSlot(entity.layer);
if (nextSlotIndex !== null) {
if (ejectorComp.tryEject(nextSlotIndex, nextItem)) {
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 { 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 {
constructor(root) {
super(root, [WiredPinsComponent]);
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
}
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 {Entity} entity
*/
drawEntityPins(parameters, entity) {
drawSingleEntity(parameters, entity) {
const staticComp = entity.components.StaticMapEntity;
if (!staticComp.shouldBeDrawn(parameters)) {
return;
}
const pinsComp = entity.components.WiredPins;
const slots = pinsComp.slots;
const slots = entity.components.WiredPins.slots;
for (let i = 0; i < slots.length; ++i) {
const slot = slots[i];
@ -45,7 +47,7 @@ export class WiredPinsSystem extends GameSystemWithFilter {
const worldPos = tile.toWorldSpaceCenterOfTile();
this.pinSprites[slot.type][0].drawCachedCentered(
this.pinSprites[slot.type].drawCachedCentered(
parameters,
worldPos.x,
worldPos.y,

View File

@ -441,6 +441,11 @@ buildings:
name: &belt Conveyor Belt
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
default:
name: &miner Extractor
@ -801,6 +806,7 @@ keybindings:
energy_generator: *energy_generator
painter: *painter
trash: *trash
wire: *wire
pipette: Pipette
rotateWhilePlacing: Rotate