First commit

This commit is contained in:
Carlo Ghisolfi 2026-10-04 19:17:16 +02:00
commit c2f76d4222
63 changed files with 11667 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*pycache*

BIN
assets/ARCO.ttf Normal file

Binary file not shown.

BIN
assets/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

43
assets/blue_arrive.svg Normal file
View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="49.999992mm"
height="50.000004mm"
viewBox="0 0 49.999992 50.000004"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-126.9132,-174.99535)">
<rect
style="fill:#e26465;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect131"
width="48.944542"
height="48.944538"
x="127.44092"
y="175.52307"
ry="0" />
<path
id="path146"
style="fill:#4f789a;fill-opacity:1;stroke:#3b4f63;stroke-width:0.793999;stroke-opacity:1"
transform="matrix(1.0541644,0,0,1.0541644,-110.60368,74.286918)"
d="m 250.53942,103.41605 3.48296,10.57748 11.13607,0.0439 a 1.5908266,1.5908266 71.999982 0 1 0.93386,2.87412 l -8.98348,6.58112 3.39951,10.60459 a 1.590828,1.590828 144.00001 0 1 -2.44488,1.77631 l -9.03506,-6.51012 -9.03507,6.51012 a 1.5908289,1.5908289 36.000002 0 1 -2.44488,-1.77631 l 3.39951,-10.60459 -8.98348,-6.58112 a 1.5908266,1.5908266 108.00002 0 1 0.93386,-2.87412 l 11.13607,-0.0439 3.48297,-10.57748 a 1.5908286,1.5908286 1.7041414e-5 0 1 3.02204,0 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/blue_pane.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

104
assets/blue_robot.svg Normal file
View file

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50.000008mm"
height="50mm"
viewBox="0 0 50.000008 50"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-127.36029,-5.8010774)">
<rect
style="fill:#e26465;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect96"
width="48.944542"
height="48.944538"
x="127.88802"
y="6.3288074"
ry="8.6410732" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect138"
width="32.757622"
height="6.6924181"
x="136.64062"
y="36.123081"
ry="1.7611626" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect132"
width="29.413462"
height="5"
x="138.3127"
y="36.96928"
ry="1.3157895" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect136"
width="12.416687"
height="12.768898"
x="136.71138"
y="19.479122"
ry="2.6417439" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect137"
width="6.5"
height="6.5"
x="139.65242"
y="22.50359"
ry="1.3447782" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect133"
width="12.416687"
height="12.768898"
x="156.16737"
y="19.479122"
ry="2.7397261" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect135"
width="6.5"
height="6.5"
x="159.12572"
y="22.613567"
ry="1.3447782" />
<path
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path152"
d="m 163.13239,6.8746271 a 10.772104,10.772104 0 0 1 -5.38605,9.3289159 10.772104,10.772104 0 0 1 -10.7721,0 10.772104,10.772104 0 0 1 -5.38605,-9.3289159 h 10.7721 z" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse155"
cx="133.69824"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse156"
cx="171.05814"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="51.000004mm"
height="51.000004mm"
viewBox="0 0 51.000004 51.000004"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="tiles_and_sprites.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
inkscape:zoom="0.37558051"
inkscape:cx="49.257083"
inkscape:cy="669.63007"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:export-bgcolor="#ffffff00"
showgrid="false">
<inkscape:page
x="0"
y="0"
width="51.000004"
height="51.000004"
id="page2"
margin="0"
bleed="0" />
</sodipodi:namedview>
<defs
id="defs1">
<linearGradient
id="linearGradient7"
inkscape:swatch="gradient">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-185.35863,-5.3288078)">
<rect
style="fill:#e26465;fill-opacity:1;stroke:#202a35;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
id="rect19"
width="48.944542"
height="48.944538"
x="186.35863"
y="6.3288074"
ry="8.6410732"
inkscape:export-filename="blue_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189" />
<rect
style="fill:#000000;fill-opacity:0.413953;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.484455"
id="rect20"
width="51"
height="51"
x="185.35863"
y="5.3288074"
ry="9.813427"
inkscape:export-filename="blue_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189"
rx="0" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect138"
width="32.757622"
height="6.6924181"
x="195.11122"
y="36.123081"
ry="1.7611626" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect132"
width="29.413462"
height="5"
x="196.78329"
y="36.96928"
ry="1.3157895" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect136"
width="12.416687"
height="12.768898"
x="195.18198"
y="19.479122"
ry="2.6417439" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect137"
width="6.5"
height="6.5"
x="198.12302"
y="22.50359"
ry="1.3447782" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect133"
width="12.416687"
height="12.768898"
x="214.63797"
y="19.479122"
ry="2.7397261" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect135"
width="6.5"
height="6.5"
x="217.59631"
y="22.613567"
ry="1.3447782" />
<path
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path152"
sodipodi:type="arc"
sodipodi:cx="210.83089"
sodipodi:cy="6.8746271"
sodipodi:rx="10.772104"
sodipodi:ry="10.772104"
sodipodi:start="0"
sodipodi:end="3.1415927"
sodipodi:arc-type="slice"
d="m 221.60299,6.8746271 a 10.772104,10.772104 0 0 1 -5.38605,9.3289159 10.772104,10.772104 0 0 1 -10.77211,0 10.772104,10.772104 0 0 1 -5.38605,-9.3289159 h 10.77211 z" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse155"
cx="192.16884"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse156"
cx="229.52873"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
assets/blue_text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
assets/bw_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
assets/bw_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

BIN
assets/completed_card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
assets/delete_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/delete_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

46
assets/floor.svg Normal file
View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50mm"
viewBox="0 0 50 50"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-5.5368996,-5.801076)">
<rect
style="fill:none;fill-opacity:1;stroke:none;stroke-width:1.07822;stroke-dasharray:none;stroke-opacity:1"
id="rect94"
width="50"
height="50"
x="6.0760098"
y="6.3401856"
ry="0" />
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect146"
width="48.944542"
height="48.944538"
x="6.0646296"
y="6.3288054"
ry="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/fw_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
assets/fw_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

BIN
assets/go_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
assets/go_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

43
assets/green_arrive.svg Normal file
View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="49.999992mm"
viewBox="0 0 50 49.999992"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-127.93943,-116.38636)">
<rect
style="fill:#f9c74f;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect149"
width="48.944542"
height="48.944538"
x="128.46716"
y="116.91409"
ry="0" />
<path
id="path149"
style="fill:#7fbe51;fill-opacity:1;stroke:#5a8639;stroke-width:0.793999;stroke-opacity:1"
transform="matrix(1.0541644,0,0,1.0541644,-109.57743,15.67794)"
d="m 250.53942,103.41605 3.48296,10.57748 11.13607,0.0439 a 1.5908266,1.5908266 71.999982 0 1 0.93386,2.87412 l -8.98348,6.58112 3.39951,10.60459 a 1.590828,1.590828 144.00001 0 1 -2.44488,1.77631 l -9.03506,-6.51012 -9.03507,6.51012 a 1.5908289,1.5908289 36.000002 0 1 -2.44488,-1.77631 l 3.39951,-10.60459 -8.98348,-6.58112 a 1.5908266,1.5908266 108.00002 0 1 0.93386,-2.87412 l 11.13607,-0.0439 3.48297,-10.57748 a 1.5908286,1.5908286 1.7041414e-5 0 1 3.02204,0 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/green_pane.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

104
assets/green_robot.svg Normal file
View file

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50.000008mm"
height="50.000004mm"
viewBox="0 0 50.000008 50.000004"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-127.40481,-61.09372)">
<rect
style="fill:#f9c74f;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect139"
width="48.944542"
height="48.944538"
x="127.93254"
y="61.621449"
ry="8.6410732" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect140"
width="32.757622"
height="6.6924181"
x="136.56062"
y="91.4384"
ry="1.7611626" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect141"
width="29.413462"
height="5"
x="138.2327"
y="92.284622"
ry="1.3157895" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect142"
width="12.416687"
height="12.768898"
x="136.64868"
y="74.056625"
ry="2.6417439" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect143"
width="6.5"
height="6.5"
x="139.58972"
y="77.0811"
ry="1.3447782" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect144"
width="12.416687"
height="12.768898"
x="156.16737"
y="74.056625"
ry="2.7397261" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect145"
width="6.5"
height="6.5"
x="159.04572"
y="77.016617"
ry="1.3447782" />
<path
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path151"
d="m 163.17692,62.151119 a 10.772104,10.772104 0 0 1 -5.38605,9.328916 10.772104,10.772104 0 0 1 -10.77211,0 10.772104,10.772104 0 0 1 -5.38605,-9.328916 h 10.77211 z" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse154"
cx="133.69824"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="path153"
cx="171.05814"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="51.000004mm"
height="51mm"
viewBox="0 0 51.000004 51"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="tiles_and_sprites.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
inkscape:zoom="0.37558051"
inkscape:cx="49.257083"
inkscape:cy="669.63007"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:export-bgcolor="#ffffff00"
showgrid="false">
<inkscape:page
x="0"
y="0"
width="51.000004"
height="51"
id="page2"
margin="0"
bleed="0" />
</sodipodi:namedview>
<defs
id="defs1">
<linearGradient
id="linearGradient7"
inkscape:swatch="gradient">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-185.34769,-60.565987)">
<rect
style="fill:#f9c74f;fill-opacity:1;stroke:#202a35;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
id="rect139"
width="48.944542"
height="48.944538"
x="186.40314"
y="61.621449"
ry="8.6410732"
inkscape:export-filename="green_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189" />
<rect
style="fill:#000000;fill-opacity:0.413953;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.484455"
id="rect18"
width="51"
height="51"
x="185.34769"
y="60.565987"
ry="9.813427"
inkscape:export-filename="blue_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189"
rx="0" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect140"
width="32.757622"
height="6.6924181"
x="195.03122"
y="91.4384"
ry="1.7611626" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect141"
width="29.413462"
height="5"
x="196.70329"
y="92.284622"
ry="1.3157895" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect142"
width="12.416687"
height="12.768898"
x="195.11928"
y="74.056625"
ry="2.6417439" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect143"
width="6.5"
height="6.5"
x="198.06032"
y="77.0811"
ry="1.3447782" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect144"
width="12.416687"
height="12.768898"
x="214.63797"
y="74.056625"
ry="2.7397261" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect145"
width="6.5"
height="6.5"
x="217.51631"
y="77.016617"
ry="1.3447782" />
<path
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path151"
sodipodi:type="arc"
sodipodi:cx="210.87541"
sodipodi:cy="62.151119"
sodipodi:rx="10.772104"
sodipodi:ry="10.772104"
sodipodi:start="0"
sodipodi:end="3.1415927"
sodipodi:arc-type="slice"
d="m 221.64752,62.151119 a 10.772104,10.772104 0 0 1 -5.38606,9.328916 10.772104,10.772104 0 0 1 -10.7721,0 10.772104,10.772104 0 0 1 -5.38605,-9.328916 h 10.7721 z" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse154"
cx="192.16884"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="path153"
cx="229.52873"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
assets/green_text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

4536
assets/gui.svg Normal file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 198 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 181 KiB

BIN
assets/locked.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/menu_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/menu_card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
assets/menu_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

62
assets/orange_door.svg Normal file
View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50.000004mm"
viewBox="0 0 50 50.000004"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-64.814606,-117.50717)">
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect123"
width="48.944538"
height="48.944542"
x="65.342339"
y="118.0349"
ry="0" />
<path
id="path123"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,118.5635 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path124"
style="fill:#f94144;stroke-width:0.509742"
d="m 76.582814,118.56338 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path125"
style="fill:#f8961e;fill-opacity:1;stroke-width:0.509742"
d="m 95.427254,118.5635 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path126"
style="fill:#f8961e;fill-opacity:1;stroke-width:0.509742"
d="m 76.582814,118.56338 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path127"
style="fill:#a56414;fill-opacity:1;stroke-width:0.509742"
d="m 100.04875,118.56326 -4.621346,2.02189 v 6.04416 l 9.240666,-4.04283 v -4.02322 z m 4.61932,4.89521 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 l 9.240666,-4.04282 z m 0,7.03143 -9.240666,4.04234 v 6.04464 l 9.240666,-4.04284 z m 0,6.91614 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="path128"
style="fill:#a56414;fill-opacity:1;stroke-width:0.509742"
d="m 81.20431,118.56313 -4.621346,2.0219 v 6.04416 l 9.240666,-4.04283 v -4.02323 z m 4.61932,4.89522 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 L 85.82363,150.482 Z m 0,7.03142 -9.240666,4.04235 v 6.04464 l 9.240666,-4.04284 z m 0,6.91615 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

48
assets/orange_press.svg Normal file
View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50.000004mm"
viewBox="0 0 50 50.000004"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-6.0760088,-117.50717)">
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect122"
width="48.944542"
height="48.944538"
x="6.6037388"
y="118.0349"
ry="0" />
<circle
style="fill:#f8961e;fill-opacity:1;stroke:none;stroke-width:0.913567;stroke-dasharray:none;stroke-opacity:1"
id="circle123"
cx="31.07601"
cy="142.50717"
r="21.640015" />
<path
id="path131"
style="fill:#a56414;fill-opacity:1;stroke:none;stroke-width:0.18323;stroke-dasharray:none;stroke-opacity:1"
d="m 26.804079,131.7742 v 24.37118 h 3.359806 v -8.72705 a 7.8228271,7.8228271 0 0 0 6.76655,-3.8954 7.8228271,7.8228271 0 0 0 0.01251,-7.83008 7.8228271,7.8228271 0 0 0 -6.779057,-3.91865 z m 3.359806,3.15337 a 4.6701503,4.6701503 0 0 1 4.037094,2.3388 4.6701503,4.6701503 0 0 1 -0.0075,4.67436 4.6701503,4.6701503 0 0 1 -4.02959,2.32482 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/panel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
assets/paused_card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
assets/play_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/play_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/quit_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/quit_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

62
assets/red_door.svg Normal file
View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50.000008mm"
viewBox="0 0 50 50.000008"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-64.814606,-61.093724)">
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect117"
width="48.944538"
height="48.944542"
x="65.342339"
y="61.621452"
ry="0" />
<path
id="path117"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,62.150048 h 9.240566 v 47.887592 h -9.240566 z" />
<path
id="path118"
style="fill:#f94144;stroke-width:0.509742"
d="M 76.582814,62.149927 H 85.82338 V 110.03752 H 76.582814 Z" />
<path
id="path119"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,62.150048 h 9.240566 v 47.887592 h -9.240566 z" />
<path
id="path120"
style="fill:#f94144;stroke-width:0.509742"
d="M 76.582814,62.149927 H 85.82338 V 110.03752 H 76.582814 Z" />
<path
id="path121"
style="fill:#ac2d2f;fill-opacity:1;stroke-width:0.509742"
d="M 100.04875,62.149806 95.427404,64.1717 v 6.044159 l 9.240666,-4.042831 v -4.023222 z m 4.61932,4.895213 -9.240666,4.042833 v 6.044159 l 9.240666,-4.042355 z m 0,7.031429 -9.240666,4.042832 v 6.044159 l 9.240666,-4.042353 z m 0,7.03143 -9.240666,4.042831 v 6.044638 l 9.240666,-4.042833 z m 0,6.916629 -9.240666,4.042354 v 6.044633 l 9.240666,-4.042827 z m 0,7.031429 -9.240666,4.042344 v 6.04464 l 9.240666,-4.04284 z m 0,6.916144 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="path122"
style="fill:#ac2d2f;fill-opacity:1;stroke-width:0.509742"
d="m 81.20431,62.149685 -4.621346,2.021894 v 6.044159 l 9.240666,-4.042831 v -4.023222 z m 4.61932,4.895213 -9.240666,4.042833 v 6.044159 l 9.240666,-4.042355 z m 0,7.031429 -9.240666,4.042832 v 6.044159 l 9.240666,-4.042353 z m 0,7.03143 -9.240666,4.042831 v 6.044638 l 9.240666,-4.042833 z m 0,6.916629 -9.240666,4.042354 v 6.044633 l 9.240666,-4.042827 z m 0,7.031429 -9.240666,4.042344 v 6.044641 l 9.240666,-4.04284 z m 0,6.916145 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

48
assets/red_press.svg Normal file
View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50.000004mm"
viewBox="0 0 50 50.000004"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-6.0760088,-61.093727)">
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect116"
width="48.944542"
height="48.944538"
x="6.6037388"
y="61.621456"
ry="0" />
<circle
style="fill:#f94144;fill-opacity:1;stroke:none;stroke-width:0.913567;stroke-dasharray:none;stroke-opacity:1"
id="circle117"
cx="31.07601"
cy="86.093727"
r="21.640015" />
<path
id="path130"
style="fill:#ac2d2f;fill-opacity:1;stroke:none;stroke-width:0.18323;stroke-dasharray:none;stroke-opacity:1"
d="m 26.804079,74.738089 v 24.371174 h 3.359806 v -8.72705 a 7.8228271,7.8228271 0 0 0 6.76655,-3.895397 7.8228271,7.8228271 0 0 0 0.01251,-7.830081 7.8228271,7.8228271 0 0 0 -6.779057,-3.918646 z m 3.359806,3.153368 a 4.6701503,4.6701503 0 0 1 4.037094,2.338798 4.6701503,4.6701503 0 0 1 -0.0075,4.674359 4.6701503,4.6701503 0 0 1 -4.02959,2.32482 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/resume_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/resume_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/retry_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
assets/retry_dark_btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/select_card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

62
assets/teal_door.svg Normal file
View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50.000004mm"
viewBox="0 0 50 50.000004"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-64.814606,-173.92063)">
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect93"
width="48.944538"
height="48.944542"
x="65.342339"
y="174.44835"
ry="0" />
<path
id="path114"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,174.97696 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path110"
style="fill:#f94144;stroke-width:0.509742"
d="m 76.582814,174.97684 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path115"
style="fill:#43aa8b;fill-opacity:1;stroke-width:0.509742"
d="m 95.427254,174.97696 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path111"
style="fill:#43aa8b;fill-opacity:1;stroke-width:0.509742"
d="m 76.582814,174.97684 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path116"
style="fill:#2b6e5a;fill-opacity:1;stroke-width:0.509742"
d="m 100.04875,174.97672 -4.621346,2.02189 v 6.04416 l 9.240666,-4.04283 v -4.02322 z m 4.61932,4.89521 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 l 9.240666,-4.04282 z m 0,7.03143 -9.240666,4.04234 v 6.04464 l 9.240666,-4.04284 z m 0,6.91614 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="rect99"
style="fill:#2b6e5a;fill-opacity:1;stroke-width:0.509742"
d="m 81.20431,174.97659 -4.621346,2.0219 v 6.04416 l 9.240666,-4.04283 v -4.02323 z m 4.61932,4.89522 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 l 9.240666,-4.04282 z m 0,7.03142 -9.240666,4.04235 v 6.04464 l 9.240666,-4.04284 z m 0,6.91615 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

48
assets/teal_press.svg Normal file
View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50.000004mm"
viewBox="0 0 50 50.000004"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-6.0760088,-173.92063)">
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect97"
width="48.944542"
height="48.944538"
x="6.6037388"
y="174.44835"
ry="0" />
<circle
style="fill:#43aa8b;fill-opacity:1;stroke:none;stroke-width:0.913567;stroke-dasharray:none;stroke-opacity:1"
id="path97"
cx="31.07601"
cy="198.92062"
r="21.640015" />
<path
id="rect128"
style="fill:#2b6e5a;fill-opacity:1;stroke:none;stroke-width:0.18323;stroke-dasharray:none;stroke-opacity:1"
d="m 26.804079,188.31218 v 24.37118 h 3.359806 v -8.72705 a 7.8228271,7.8228271 0 0 0 6.76655,-3.8954 7.8228271,7.8228271 0 0 0 0.01251,-7.83008 7.8228271,7.8228271 0 0 0 -6.779057,-3.91865 z m 3.359806,3.15337 a 4.6701503,4.6701503 0 0 1 4.037094,2.3388 4.6701503,4.6701503 0 0 1 -0.0075,4.67436 4.6701503,4.6701503 0 0 1 -4.02959,2.32482 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,759 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="tiles_and_sprites.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
inkscape:zoom="1.0623021"
inkscape:cx="844.86324"
inkscape:cy="221.68835"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:export-bgcolor="#ffffff00"
showgrid="false" />
<defs
id="defs1">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect151"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect149"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,4.8312155,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect146"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<linearGradient
id="linearGradient7"
inkscape:swatch="gradient">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#f94144;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-dasharray:none;stroke-opacity:1"
id="rect87"
width="21.310066"
height="21.310066"
x="0"
y="-32.053158" />
<rect
style="fill:#f3722c;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-dasharray:none;stroke-opacity:1"
id="rect88"
width="21.310066"
height="21.310066"
x="24.48016"
y="-32.053158" />
<rect
style="fill:#f8961e;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-dasharray:none;stroke-opacity:1"
id="rect89"
width="21.310066"
height="21.310066"
x="48.96032"
y="-32.053158" />
<rect
style="fill:#f9c74f;fill-opacity:1;stroke:none;stroke-width:0.794;stroke-dasharray:none;stroke-opacity:1"
id="rect90"
width="21.310066"
height="21.310066"
x="73.440483"
y="-32.053158" />
<rect
style="fill:#90be6d;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-dasharray:none;stroke-opacity:1"
id="rect91"
width="21.310066"
height="21.310066"
x="97.920647"
y="-32.053158" />
<rect
style="fill:#43aa8b;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-dasharray:none;stroke-opacity:1"
id="rect92"
width="21.310066"
height="21.310066"
x="122.40081"
y="-32.053158" />
<rect
style="fill:#577590;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-dasharray:none;stroke-opacity:1"
id="rect86"
width="21.310066"
height="21.310066"
x="146.88098"
y="-32.053158" />
<rect
style="fill:none;fill-opacity:1;stroke:none;stroke-width:1.07822;stroke-dasharray:none;stroke-opacity:1"
id="rect94"
width="50"
height="50"
x="6.0760098"
y="6.3401856"
ry="0" />
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect146"
width="48.944542"
height="48.944538"
x="6.6037378"
y="6.8679175"
ry="0"
inkscape:export-filename="floor.svg"
inkscape:export-xdpi="520.19"
inkscape:export-ydpi="520.19" />
<rect
style="fill:#f9c74f;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect149"
width="48.944542"
height="48.944538"
x="128.46716"
y="116.91409"
ry="0"
inkscape:export-filename="green_arrive.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<rect
style="fill:#e26465;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect131"
width="48.944542"
height="48.944538"
x="127.44092"
y="175.52307"
ry="0"
inkscape:export-filename="blue_arrive.svg"
inkscape:export-xdpi="520.19208"
inkscape:export-ydpi="520.19208" />
<rect
style="fill:#f9c74f;fill-opacity:1;stroke:#202a35;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
id="rect1"
width="48.944542"
height="48.944538"
x="127.93254"
y="61.621449"
ry="8.6410732"
inkscape:export-filename="green_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189" />
<rect
style="fill:#f9c74f;fill-opacity:1;stroke:#202a35;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
id="rect139"
width="48.944542"
height="48.944538"
x="186.40314"
y="61.621449"
ry="8.6410732"
inkscape:export-filename="green_robot_inactive.svg"
inkscape:export-xdpi="509.99213"
inkscape:export-ydpi="509.99213" />
<rect
style="fill:#e26465;fill-opacity:1;stroke:#202a35;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
id="rect2"
width="48.944542"
height="48.944538"
x="127.88802"
y="6.3288074"
ry="8.6410732"
inkscape:export-filename="blue_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189" />
<rect
style="fill:#e26465;fill-opacity:1;stroke:#202a35;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
id="rect19"
width="48.944542"
height="48.944538"
x="186.35863"
y="6.3288074"
ry="8.6410732"
inkscape:export-filename="blue_robot_inactive.png"
inkscape:export-xdpi="509.99213"
inkscape:export-ydpi="509.99213" />
<rect
style="fill:#000000;fill-opacity:0.413953;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.484455"
id="rect20"
width="51"
height="51"
x="185.35863"
y="5.3288074"
ry="9.813427"
inkscape:export-filename="blue_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189"
rx="0" />
<rect
style="fill:#000000;fill-opacity:0.413953;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.484455"
id="rect18"
width="51"
height="51"
x="185.34769"
y="60.565987"
ry="9.813427"
inkscape:export-filename="blue_robot.svg"
inkscape:export-xdpi="520.19189"
inkscape:export-ydpi="520.19189"
rx="0" />
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect116"
width="48.944542"
height="48.944538"
x="6.6037388"
y="61.621456"
ry="0"
inkscape:export-filename="red_press.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect122"
width="48.944542"
height="48.944538"
x="6.6037388"
y="118.0349"
ry="0"
inkscape:export-filename="orange_press.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<rect
style="fill:#ffdc89;fill-opacity:1;stroke:#2f3d47;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect97"
width="48.944542"
height="48.944538"
x="6.6037388"
y="174.44835"
ry="0"
inkscape:export-filename="teal_press.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect98"
width="48.944538"
height="48.944542"
x="65.342339"
y="6.3288054"
ry="0"
inkscape:export-filename="wall.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect117"
width="48.944538"
height="48.944542"
x="65.342339"
y="61.621452"
ry="0"
inkscape:export-filename="red_door.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect123"
width="48.944538"
height="48.944542"
x="65.342339"
y="118.0349"
ry="0"
inkscape:export-filename="orange_door.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect93"
width="48.944538"
height="48.944542"
x="65.342339"
y="174.44835"
ry="0"
inkscape:export-filename="teal_door.svg"
inkscape:export-xdpi="520.19202"
inkscape:export-ydpi="520.19202" />
<circle
style="fill:#f94144;fill-opacity:1;stroke:none;stroke-width:0.913567;stroke-dasharray:none;stroke-opacity:1"
id="circle117"
cx="31.07601"
cy="86.093727"
r="21.640015" />
<circle
style="fill:#f8961e;fill-opacity:1;stroke:none;stroke-width:0.913567;stroke-dasharray:none;stroke-opacity:1"
id="circle123"
cx="31.07601"
cy="142.50717"
r="21.640015" />
<circle
style="fill:#43aa8b;fill-opacity:1;stroke:none;stroke-width:0.913567;stroke-dasharray:none;stroke-opacity:1"
id="path97"
cx="31.07601"
cy="198.92062"
r="21.640015" />
<path
id="path117"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,62.150048 h 9.240566 v 47.887592 h -9.240566 z" />
<path
id="path123"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,118.5635 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path114"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,174.97696 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path118"
style="fill:#f94144;stroke-width:0.509742"
d="M 76.582814,62.149927 H 85.82338 V 110.03752 H 76.582814 Z" />
<path
id="path124"
style="fill:#f94144;stroke-width:0.509742"
d="m 76.582814,118.56338 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path110"
style="fill:#f94144;stroke-width:0.509742"
d="m 76.582814,174.97684 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path119"
style="fill:#f94144;stroke-width:0.509742"
d="m 95.427254,62.150048 h 9.240566 v 47.887592 h -9.240566 z" />
<path
id="path125"
style="fill:#f8961e;fill-opacity:1;stroke-width:0.509742"
d="m 95.427254,118.5635 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path115"
style="fill:#43aa8b;fill-opacity:1;stroke-width:0.509742"
d="m 95.427254,174.97696 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path120"
style="fill:#f94144;stroke-width:0.509742"
d="M 76.582814,62.149927 H 85.82338 V 110.03752 H 76.582814 Z" />
<path
id="path126"
style="fill:#f8961e;fill-opacity:1;stroke-width:0.509742"
d="m 76.582814,118.56338 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path111"
style="fill:#43aa8b;fill-opacity:1;stroke-width:0.509742"
d="m 76.582814,174.97684 h 9.240566 v 47.88759 h -9.240566 z" />
<path
id="path121"
style="fill:#ac2d2f;fill-opacity:1;stroke-width:0.509742"
d="M 100.04875,62.149806 95.427404,64.1717 v 6.044159 l 9.240666,-4.042831 v -4.023222 z m 4.61932,4.895213 -9.240666,4.042833 v 6.044159 l 9.240666,-4.042355 z m 0,7.031429 -9.240666,4.042832 v 6.044159 l 9.240666,-4.042353 z m 0,7.03143 -9.240666,4.042831 v 6.044638 l 9.240666,-4.042833 z m 0,6.916629 -9.240666,4.042354 v 6.044633 l 9.240666,-4.042827 z m 0,7.031429 -9.240666,4.042344 v 6.04464 l 9.240666,-4.04284 z m 0,6.916144 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="path127"
style="fill:#a56414;fill-opacity:1;stroke-width:0.509742"
d="m 100.04875,118.56326 -4.621346,2.02189 v 6.04416 l 9.240666,-4.04283 v -4.02322 z m 4.61932,4.89521 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 l 9.240666,-4.04282 z m 0,7.03143 -9.240666,4.04234 v 6.04464 l 9.240666,-4.04284 z m 0,6.91614 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="path116"
style="fill:#2b6e5a;fill-opacity:1;stroke-width:0.509742"
d="m 100.04875,174.97672 -4.621346,2.02189 v 6.04416 l 9.240666,-4.04283 v -4.02322 z m 4.61932,4.89521 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04235 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 l 9.240666,-4.04282 z m 0,7.03143 -9.240666,4.04234 v 6.04464 l 9.240666,-4.04284 z m 0,6.91614 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="path122"
style="fill:#ac2d2f;fill-opacity:1;stroke-width:0.509742"
d="m 81.20431,62.149685 -4.621346,2.021894 v 6.044159 l 9.240666,-4.042831 v -4.023222 z m 4.61932,4.895213 -9.240666,4.042833 v 6.044159 l 9.240666,-4.042355 z m 0,7.031429 -9.240666,4.042832 v 6.044159 l 9.240666,-4.042353 z m 0,7.03143 -9.240666,4.042831 v 6.044638 l 9.240666,-4.042833 z m 0,6.916629 -9.240666,4.042354 v 6.044633 l 9.240666,-4.042827 z m 0,7.031429 -9.240666,4.042344 v 6.044641 l 9.240666,-4.04284 z m 0,6.916145 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="path128"
style="fill:#a56414;fill-opacity:1;stroke-width:0.509742"
d="m 81.20431,118.56313 -4.621346,2.0219 v 6.04416 l 9.240666,-4.04283 v -4.02323 z m 4.61932,4.89522 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 L 85.82363,150.482 Z m 0,7.03142 -9.240666,4.04235 v 6.04464 l 9.240666,-4.04284 z m 0,6.91615 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="rect99"
style="fill:#2b6e5a;fill-opacity:1;stroke-width:0.509742"
d="m 81.20431,174.97659 -4.621346,2.0219 v 6.04416 l 9.240666,-4.04283 v -4.02323 z m 4.61932,4.89522 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04416 l 9.240666,-4.04236 z m 0,7.03143 -9.240666,4.04283 v 6.04464 l 9.240666,-4.04284 z m 0,6.91663 -9.240666,4.04235 v 6.04463 l 9.240666,-4.04282 z m 0,7.03142 -9.240666,4.04235 v 6.04464 l 9.240666,-4.04284 z m 0,6.91615 -9.240666,4.04236 v 4.0232 h 4.620126 l 4.62054,-2.0214 z" />
<path
id="path130"
style="fill:#ac2d2f;fill-opacity:1;stroke:none;stroke-width:0.18323;stroke-dasharray:none;stroke-opacity:1"
d="m 26.804079,74.738089 v 24.371174 h 3.359806 v -8.72705 a 7.8228271,7.8228271 0 0 0 6.76655,-3.895397 7.8228271,7.8228271 0 0 0 0.01251,-7.830081 7.8228271,7.8228271 0 0 0 -6.779057,-3.918646 z m 3.359806,3.153368 a 4.6701503,4.6701503 0 0 1 4.037094,2.338798 4.6701503,4.6701503 0 0 1 -0.0075,4.674359 4.6701503,4.6701503 0 0 1 -4.02959,2.32482 z" />
<path
id="path131"
style="fill:#a56414;fill-opacity:1;stroke:none;stroke-width:0.18323;stroke-dasharray:none;stroke-opacity:1"
d="m 26.804079,131.7742 v 24.37118 h 3.359806 v -8.72705 a 7.8228271,7.8228271 0 0 0 6.76655,-3.8954 7.8228271,7.8228271 0 0 0 0.01251,-7.83008 7.8228271,7.8228271 0 0 0 -6.779057,-3.91865 z m 3.359806,3.15337 a 4.6701503,4.6701503 0 0 1 4.037094,2.3388 4.6701503,4.6701503 0 0 1 -0.0075,4.67436 4.6701503,4.6701503 0 0 1 -4.02959,2.32482 z" />
<path
id="rect128"
style="fill:#2b6e5a;fill-opacity:1;stroke:none;stroke-width:0.18323;stroke-dasharray:none;stroke-opacity:1"
d="m 26.804079,188.31218 v 24.37118 h 3.359806 v -8.72705 a 7.8228271,7.8228271 0 0 0 6.76655,-3.8954 7.8228271,7.8228271 0 0 0 0.01251,-7.83008 7.8228271,7.8228271 0 0 0 -6.779057,-3.91865 z m 3.359806,3.15337 a 4.6701503,4.6701503 0 0 1 4.037094,2.3388 4.6701503,4.6701503 0 0 1 -0.0075,4.67436 4.6701503,4.6701503 0 0 1 -4.02959,2.32482 z" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect3"
width="32.757622"
height="6.6924181"
x="136.56062"
y="91.4384"
ry="1.7611626" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect140"
width="32.757622"
height="6.6924181"
x="195.03122"
y="91.4384"
ry="1.7611626" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect4"
width="32.757622"
height="6.6924181"
x="136.64062"
y="36.123081"
ry="1.7611626" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:1.1049;stroke-dasharray:none;stroke-opacity:1"
id="rect138"
width="32.757622"
height="6.6924181"
x="195.11122"
y="36.123081"
ry="1.7611626" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect5"
width="29.413462"
height="5"
x="138.2327"
y="92.284622"
ry="1.3157895" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect141"
width="29.413462"
height="5"
x="196.70329"
y="92.284622"
ry="1.3157895" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect6"
width="29.413462"
height="5"
x="138.3127"
y="36.96928"
ry="1.3157895" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.904968;stroke-dasharray:none;stroke-opacity:1"
id="rect132"
width="29.413462"
height="5"
x="196.78329"
y="36.96928"
ry="1.3157895" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect7"
width="12.416687"
height="12.768898"
x="136.64868"
y="74.056625"
ry="2.6417439" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect142"
width="12.416687"
height="12.768898"
x="195.11928"
y="74.056625"
ry="2.6417439" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect8"
width="12.416687"
height="12.768898"
x="136.71138"
y="19.479122"
ry="2.6417439" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect136"
width="12.416687"
height="12.768898"
x="195.18198"
y="19.479122"
ry="2.6417439" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect9"
width="6.5"
height="6.5"
x="139.58972"
y="77.0811"
ry="1.3447782" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect143"
width="6.5"
height="6.5"
x="198.06032"
y="77.0811"
ry="1.3447782" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect10"
width="6.5"
height="6.5"
x="139.65242"
y="22.50359"
ry="1.3447782" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect137"
width="6.5"
height="6.5"
x="198.12302"
y="22.50359"
ry="1.3447782" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect11"
width="12.416687"
height="12.768898"
x="156.16737"
y="74.056625"
ry="2.7397261" />
<rect
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect144"
width="12.416687"
height="12.768898"
x="214.63797"
y="74.056625"
ry="2.7397261" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect12"
width="12.416687"
height="12.768898"
x="156.16737"
y="19.479122"
ry="2.7397261" />
<rect
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="rect133"
width="12.416687"
height="12.768898"
x="214.63797"
y="19.479122"
ry="2.7397261" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect13"
width="6.5"
height="6.5"
x="159.04572"
y="77.016617"
ry="1.3447782" />
<rect
style="fill:#5a8639;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect145"
width="6.5"
height="6.5"
x="217.51631"
y="77.016617"
ry="1.3447782" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect14"
width="6.5"
height="6.5"
x="159.12572"
y="22.613567"
ry="1.3447782" />
<rect
style="fill:#3b4f63;fill-opacity:1;stroke:none;stroke-width:0.409877;stroke-dasharray:none;stroke-opacity:1"
id="rect135"
width="6.5"
height="6.5"
x="217.59631"
y="22.613567"
ry="1.3447782" />
<path
id="path149"
style="fill:#7fbe51;fill-opacity:1;stroke:#5a8639;stroke-width:0.793999;stroke-opacity:1"
inkscape:transform-center-y="-2.3624085"
transform="matrix(1.0541644,0,0,1.0541644,-109.57743,15.67794)"
d="m 250.53942,103.41605 3.48296,10.57748 11.13607,0.0439 a 1.5908266,1.5908266 71.999982 0 1 0.93386,2.87412 l -8.98348,6.58112 3.39951,10.60459 a 1.590828,1.590828 144.00001 0 1 -2.44488,1.77631 l -9.03506,-6.51012 -9.03507,6.51012 a 1.5908289,1.5908289 36.000002 0 1 -2.44488,-1.77631 l 3.39951,-10.60459 -8.98348,-6.58112 a 1.5908266,1.5908266 108.00002 0 1 0.93386,-2.87412 l 11.13607,-0.0439 3.48297,-10.57748 a 1.5908286,1.5908286 1.7041414e-5 0 1 3.02204,0 z"
inkscape:path-effect="#path-effect151"
inkscape:original-d="m 249.0284,98.827209 4.99398,15.166321 15.96725,0.0629 -12.8808,9.43621 4.87432,15.2052 -12.95475,-9.33442 -12.95476,9.33442 4.87432,-15.2052 -12.8808,-9.43621 15.96725,-0.0629 z"
inkscape:transform-center-x="1.2977838e-05" />
<path
id="path146"
style="fill:#4f789a;fill-opacity:1;stroke:#3b4f63;stroke-width:0.793999;stroke-opacity:1"
inkscape:transform-center-y="-2.3624085"
transform="matrix(1.0541644,0,0,1.0541644,-110.60368,74.286918)"
d="m 250.53942,103.41605 3.48296,10.57748 11.13607,0.0439 a 1.5908266,1.5908266 71.999982 0 1 0.93386,2.87412 l -8.98348,6.58112 3.39951,10.60459 a 1.590828,1.590828 144.00001 0 1 -2.44488,1.77631 l -9.03506,-6.51012 -9.03507,6.51012 a 1.5908289,1.5908289 36.000002 0 1 -2.44488,-1.77631 l 3.39951,-10.60459 -8.98348,-6.58112 a 1.5908266,1.5908266 108.00002 0 1 0.93386,-2.87412 l 11.13607,-0.0439 3.48297,-10.57748 a 1.5908286,1.5908286 1.7041414e-5 0 1 3.02204,0 z"
inkscape:path-effect="#path-effect149"
inkscape:original-d="m 249.0284,98.827209 4.99398,15.166321 15.96725,0.0629 -12.8808,9.43621 4.87432,15.2052 -12.95475,-9.33442 -12.95476,9.33442 4.87432,-15.2052 -12.8808,-9.43621 15.96725,-0.0629 z"
inkscape:transform-center-x="1.2977838e-05" />
<path
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path14"
sodipodi:type="arc"
sodipodi:cx="152.36029"
sodipodi:cy="6.8746271"
sodipodi:rx="10.772104"
sodipodi:ry="10.772104"
sodipodi:start="0"
sodipodi:end="3.1415927"
sodipodi:arc-type="slice"
d="m 163.13239,6.8746271 a 10.772104,10.772104 0 0 1 -5.38605,9.3289159 10.772104,10.772104 0 0 1 -10.7721,0 10.772104,10.772104 0 0 1 -5.38605,-9.3289159 h 10.7721 z" />
<path
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path152"
sodipodi:type="arc"
sodipodi:cx="210.83089"
sodipodi:cy="6.8746271"
sodipodi:rx="10.772104"
sodipodi:ry="10.772104"
sodipodi:start="0"
sodipodi:end="3.1415927"
sodipodi:arc-type="slice"
d="m 221.60299,6.8746271 a 10.772104,10.772104 0 0 1 -5.38605,9.3289159 10.772104,10.772104 0 0 1 -10.77211,0 10.772104,10.772104 0 0 1 -5.38605,-9.3289159 h 10.77211 z" />
<path
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path15"
sodipodi:type="arc"
sodipodi:cx="152.40482"
sodipodi:cy="62.151119"
sodipodi:rx="10.772104"
sodipodi:ry="10.772104"
sodipodi:start="0"
sodipodi:end="3.1415927"
sodipodi:arc-type="slice"
d="m 163.17692,62.151119 a 10.772104,10.772104 0 0 1 -5.38605,9.328916 10.772104,10.772104 0 0 1 -10.77211,0 10.772104,10.772104 0 0 1 -5.38605,-9.328916 h 10.77211 z" />
<path
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-dasharray:none;stroke-opacity:1"
id="path151"
sodipodi:type="arc"
sodipodi:cx="210.87541"
sodipodi:cy="62.151119"
sodipodi:rx="10.772104"
sodipodi:ry="10.772104"
sodipodi:start="0"
sodipodi:end="3.1415927"
sodipodi:arc-type="slice"
d="m 221.64752,62.151119 a 10.772104,10.772104 0 0 1 -5.38606,9.328916 10.772104,10.772104 0 0 1 -10.7721,0 10.772104,10.772104 0 0 1 -5.38605,-9.328916 h 10.7721 z" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse15"
cx="133.69824"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse155"
cx="192.16884"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse16"
cx="133.69824"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse154"
cx="192.16884"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse17"
cx="171.05814"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#4f789a;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse156"
cx="229.52873"
cy="49.03196"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="ellipse18"
cx="171.05814"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
<ellipse
style="fill:#7fbe51;fill-opacity:1;stroke:none;stroke-width:0.321662;stroke-dasharray:none;stroke-opacity:1"
id="path153"
cx="229.52873"
cy="104.57764"
rx="1.9423375"
ry="1.8339512" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/timer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
assets/unlocked.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

38
assets/wall.svg Normal file
View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50mm"
viewBox="0 0 50 50"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient7">
<stop
style="stop-color:#bcb776;stop-opacity:1;"
offset="0.26068801"
id="stop7" />
<stop
style="stop-color:#9a9147;stop-opacity:1;"
offset="1"
id="stop8" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-64.814606,-5.801076)">
<rect
style="fill:#273843;fill-opacity:1;stroke:#202a35;stroke-width:1.05546;stroke-dasharray:none;stroke-opacity:1"
id="rect98"
width="48.944538"
height="48.944542"
x="65.342339"
y="6.3288054"
ry="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 958 B

43
constants.py Normal file
View file

@ -0,0 +1,43 @@
# CONSTANTS
FPS = 60
SCALE_FACTOR = 1
# Tiles
TILE_SIZE = 32
# SCREEN AND PANEL
WIDTH = 1280
HEIGHT = 720
GAME_PANEL_W = 960
GAME_PANEL_H = 640
X_OFFSET = WIDTH/2 - GAME_PANEL_W / 2
Y_OFFSET = HEIGHT/2 - GAME_PANEL_H / 2
PANEL_WIDTH = 120
PANEL_HEIGHT = 120
PANEL_T_HEIGHT = 50
PANEL_T_WIDTH = 140
# WALL_COLOR = (50, 50, 50)
# FLOOR_COLOR = (200, 200, 200)
# RED_DOOR = (200, 0, 0)
# RED_PLATE = (100, 0, 0)
# BLUE_ARRIVE = (0, 0, 100)
# GREEN_ARRIVE = (0, 100, 0)
# BG_COLOR = (255, 0, 255)
# BUTTONS
MAX_BTN = 3
BTN_WIDTH = 232
BTN_HEIGHT = 82
# COLORS
BLUE = (43, 69, 104)
GREEN= (43, 104, 43)
RED = (93, 38, 38)
LIGHT = (100, 100, 100)
DARK = (64, 56, 43)
DARK_TEXT = (62,51,34)
WHITE = (255, 255, 255)

112
db_utils.py Normal file
View file

@ -0,0 +1,112 @@
import sqlite3
from pathlib import *
import json
def init_db():
conn = sqlite3.connect("progress.db")
cursor = conn.cursor()
for path in Path("./levels").glob("*.json"):
with open(path, "r") as file:
level = json.load(file)
level_id = level["id"]
# Initialize progress on levels not already in the table
cursor.execute(
"""
INSERT OR IGNORE INTO player_progress
(id, unlocked, completed, timer)
VALUES (?, 0, 0, 0)
""",
(level_id,)
)
# For end
# Set the unlocked property for the first level
cursor.execute(
"""
UPDATE player_progress
SET unlocked = TRUE
WHERE id = ?
""",
("001",)
)
conn.commit()
conn.close()
def get_levels():
levels = sorted(Path("./levels").glob("*.json"))
return levels
def reset_db():
conn = sqlite3.connect("progress.db")
cursor = conn.cursor()
cursor.execute(
"""
DELETE FROM player_progress
"""
)
conn.commit()
conn.close()
def get_progress():
conn = sqlite3.connect("progress.db")
cursor = conn.cursor()
# Set the completed property fand timer
cursor.execute(
"""
SELECT unlocked, timer FROM player_progress
ORDER BY id ASC
""",
)
result = cursor.fetchall()
conn.close()
return result
def save_progress(level_state):
conn = sqlite3.connect("progress.db")
cursor = conn.cursor()
level_id = level_state.level.id
# Set the completed property fand timer
cursor.execute(
"""
UPDATE player_progress
SET completed = TRUE, timer = ?
WHERE id = ?
""",
(level_state.final_time, level_id,)
)
unlock_level_id = None
next_level_number = level_state.level.level_number + 1
for path in Path("./levels").glob("*.json"):
if int(path.name.split("_")[0]) == next_level_number:
with open(path, "r") as file:
level = json.load(file)
unlock_level_id = level["id"]
break
if unlock_level_id is not None:
# Set the unlocked property for the next level
cursor.execute(
"""
UPDATE player_progress
SET unlocked = TRUE
WHERE id = ?
""",
(unlock_level_id,)
)
conn.commit()
conn.close()

100
gamestate.py Normal file
View file

@ -0,0 +1,100 @@
# libraries
from datetime import timedelta
# project modules
import db_utils as db
import db_utils
from new_gui import *
# -----------------------------------------------------
# Enum and Tables
# -----------------------------------------------------
class State(Enum):
MENU = 0
PLAY = 1
PAUSE = 2
SELECT = 3
COMPLETE = 4
# ------------------------------------------------------
# Class GameState
# - Represents the game state (playing, pause, menu...)
# - creates and keeps the different views
# ------------------------------------------------------
class GameState:
def __init__(self):
self.running = True
self.state = State.MENU
self.level_state = None
# Game time keeping
self.play_start = 0
self.paused_time = 0
self.pause_start = 0
self.elapsed = 0
# Views
self.start_menu = self.create_start_menu()
self.pause_menu = self.create_pause_menu()
self.select_menu = self.create_select_menu()
# It will get created at the end of each level
self.completed_menu = None
def update(self, ticks):
# update elapsed playing time
if self.state == State.PLAY:
self.elapsed = ticks - self.play_start - self.paused_time
# If the current level has been completed. This block of code is executed ONCE with the last check of the if
if self.level_state != None and self.level_state.completed == True and self.state != State.COMPLETE:
# save total time inside the level state
self.level_state.final_time = self.elapsed
self.state = State.COMPLETE
self.completed_menu = self.create_completed_menu()
self.save_progress()
self.select_menu = self.create_select_menu()
def save_progress(self):
# Save progress in db and unlock next level
db.save_progress(self.level_state)
# Functions that create the views
def create_pause_menu(self):
menu = MenuPage(MenuType.PAUSE)
menu.add_top_text("Don't worry, the clock isn't ticking!")
menu.add_button("playing", ButtonTypes.RESUME)
menu.add_button("select_level", ButtonTypes.MENU)
return menu
def create_start_menu(self):
menu = MenuPage(MenuType.START)
menu.add_button("select_level", ButtonTypes.PLAY)
menu.add_button("delete", ButtonTypes.DELETE)
menu.add_button("quit_game", ButtonTypes.QUIT)
return menu
def create_completed_menu(self):
# Text with the time formatted
timer = timedelta(milliseconds=self.level_state.final_time)
text = f"Timer: {str(timer).split(".")[0]}"
menu = MenuPage(MenuType.COMPLETED)
menu.add_top_text("Play the level again to beat your time!")
menu.add_bottom_text(text)
menu.add_button("retry", ButtonTypes.RETRY)
menu.add_button("select_level", ButtonTypes.MENU)
return menu
def create_select_menu(self):
level_paths = db_utils.get_levels()
progress = db_utils.get_progress()
menu = Menu(MenuType.SELECT)
# Adding buttons based on level files
for info in zip(level_paths, progress):
# print(f"Path: {info[0]}, Completato:{info[1][0]}, Tempo:{info[1][1]}")
time_text = str(timedelta(milliseconds=info[1][1])).split(".")[0]
text = f"{info[0].name.split('.')[0].split('_')[1]} - {time_text}"
menu.add_entry(text, (info[0],info[1][0]), EntryState.UNLOCKED if int(info[1][0]) == 1 else EntryState.LOCKED)
return menu

17
levels/00_tutorial.json Normal file
View file

@ -0,0 +1,17 @@
{
"id": "001",
"map": [
["#","#","#","#","#","#","#","#","#","#"],
["#","G",".",".",".","#",".",".",".","#"],
["#",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".","#",".",".",".","#"],
["#",".","b",".",".","R",".",".",".","#"],
["#",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".","#",".","g",".","#"],
["#",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".","#",".",".",".","#"],
["#","r",".",".",".","#",".",".","B","#"],
["#","#","#","#","#","#","#","#","#","#"]
]
}

25
levels/01_livello1.json Normal file
View file

@ -0,0 +1,25 @@
{
"id": "002",
"map":[
["#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#"],
["#","G",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".","b",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","R",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".","g",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".",".","#"],
["#","r",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","#",".",".","B","#"],
["#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#"]
]
}

4
levels/02_livello2.json Normal file
View file

@ -0,0 +1,4 @@
{
"id": "003",
"map": [[]]
}

4
levels/03_livello3.json Normal file
View file

@ -0,0 +1,4 @@
{
"id": "004",
"map": [[]]
}

4
levels/04_livello4.json Normal file
View file

@ -0,0 +1,4 @@
{
"id": "005",
"map": [[]]
}

365
levelstate.py Normal file
View file

@ -0,0 +1,365 @@
# libraries
import pygame
import numpy as np
import json
# project modules
from constants import *
from player import *
from new_gui import *
# -------------------------------------------------------------------------------
# Enum and Tables
# -------------------------------------------------------------------------------
class TileTypes(Enum):
FLOOR = 0
WALL = 1
RED_PLATE = 2
RED_DOOR = 3
ORANGE_PLATE = 4
ORANGE_DOOR = 5
TEAL_PLATE = 6
TEAL_DOOR = 7
BLUE_ARRIVE = 8
GREEN_ARRIVE = 9
TILE_FILES = {
TileTypes.FLOOR: "assets/floor.svg",
TileTypes.WALL : "assets/wall.svg",
TileTypes.RED_PLATE : "assets/red_press.svg",
TileTypes.RED_DOOR : "assets/red_door.svg",
TileTypes.ORANGE_PLATE : "assets/orange_press.svg",
TileTypes.ORANGE_DOOR : "assets/orange_door.svg",
TileTypes.TEAL_PLATE : "assets/teal_press.svg",
TileTypes.TEAL_DOOR : "assets/teal_door.svg",
TileTypes.BLUE_ARRIVE : "assets/blue_arrive.svg",
TileTypes.GREEN_ARRIVE : "assets/green_arrive.svg"
}
class GamePanel(Enum):
BLUE_PANE = 0
BLUE_TEXT = 1
GREEN_TEXT = 2
GREEN_PANE = 3
TIMER = 4
PANEL_FILES = {
GamePanel.BLUE_PANE: "assets/blue_pane.png",
GamePanel.BLUE_TEXT: "assets/blue_text.png",
GamePanel.GREEN_PANE: "assets/green_pane.png",
GamePanel.GREEN_TEXT: "assets/green_text.png",
GamePanel.TIMER: "assets/timer.png"
}
class Direction(Enum):
HORIZ = 0
VERT = 1
# -------------------------------------------------------------------------------
# Class Level
# - represents the static data of the current level being played
# -------------------------------------------------------------------------------
class Level:
def __init__(self, path):
# Saving the order number of the level
self.level_number = int(path.name.split("_")[0])
# Level data file loading
with open(path, "r") as file:
level_data = json.load(file)
self.map = np.array(level_data["map"])
self.id = level_data["id"]
# LOADING TILE IMAGES
target_size = (TILE_SIZE, TILE_SIZE)
self.floor_tile = self.load_tile(TileTypes.FLOOR ,target_size)
self.wall_tile = self.load_tile(TileTypes.WALL ,target_size)
self.red_press = self.load_tile(TileTypes.RED_PLATE ,target_size)
self.red_door = self.load_tile(TileTypes.RED_DOOR ,target_size)
self.orange_press = self.load_tile(TileTypes.ORANGE_PLATE ,target_size)
self.orange_door = self.load_tile(TileTypes.ORANGE_DOOR ,target_size)
self.teal_press = self.load_tile(TileTypes.TEAL_PLATE ,target_size)
self.teal_door = self.load_tile(TileTypes.TEAL_DOOR ,target_size)
self.blue_arrive = self.load_tile(TileTypes.BLUE_ARRIVE ,target_size)
self.green_arrive = self.load_tile(TileTypes.GREEN_ARRIVE ,target_size)
self.doors, self.plates = self.load_objs()
# For now this method does this with the map, in the future they will be encoded differently in the json
# maybe already in arrays to make everything easier
def load_objs(self):
doors = {}
plates = {}
for (row, col), character in np.ndenumerate(self.map):
if character in ('R'):
# Todo: choose type based on character
doors[character] = Door(col, row, TileTypes.RED_DOOR)
if character.lower() in plates:
plates[character.lower()].set_door(doors[character])
if character in ('r'):
# Todo: choose type based on character
plates[character] = PressurePlate(col, row, TileTypes.RED_PLATE)
if character.upper() in doors:
plates[character].set_door(doors[character.upper()])
#for (row, col), character in np.ndenumerate(self.map):
# if character == 'r':
# plates.append(PressurePlate(col, row, TileTypes.RED_PLATE))
return doors, plates
def load_tile(self, type, target_size):
return pygame.transform.smoothscale(pygame.image.load(TILE_FILES.get(type, TILE_FILES[TileTypes.FLOOR])).convert_alpha(), target_size)
def draw(self, screen, pressing):
for (row, col), character in np.ndenumerate(self.map):
# Convert grid coordinates to pixel coordinates
x = col * TILE_SIZE + X_OFFSET
y = row * TILE_SIZE + Y_OFFSET
# Create the rectangle boundary for the tile
rect = pygame.Rect(x, y, TILE_SIZE, TILE_SIZE)
# Draw the appropriate tile color
if character == '#':
screen.blit(self.wall_tile, rect)
# elif character == 'R' and pressing != "red":
# screen.blit(self.red_door, rect)
# elif character == 'r':
# screen.blit(self.red_press, rect)
elif character == 'B':
screen.blit(self.blue_arrive, rect)
elif character == 'G':
screen.blit(self.green_arrive, rect)
else:
screen.blit(self.floor_tile, rect)
for element in list(self.doors.values()) + list(self.plates.values()):
element.draw(screen)
# -------------------------------------------------------------------------------
# Class LevelState
# - represents the state of the current level being played
# - it manages all the gameplay logic and mechanics
# -------------------------------------------------------------------------------
class LevelState:
def __init__(self, level):
self.level = level
# Players setup
b_rows, b_cols = np.where(level.map == 'b')
g_rows, g_cols = np.where(level.map == 'g')
blue_y, blue_x = b_rows[0], b_cols[0]
green_y, green_x = g_rows[0], g_cols[0]
self.players = [Player(blue_x, blue_y, True, PlayerTypes.BLUE), Player(green_x, green_y, False, PlayerTypes.GREEN)]
self.curr_player_i = 0
self.player = self.players[self.curr_player_i]
# Sprite group for ease
self.all_sprites = pygame.sprite.Group()
self.all_sprites.add(self.players)
# state variables
self.pressing = "none"
self.blue_arrive = False
self.green_arrive = False
# Completion and final time
self.completed = False
self.final_time = 0
# GUI ELEMENTS
self.blue_pane = self.load_gui(GamePanel.BLUE_PANE)
self.green_pane = self.load_gui(GamePanel.GREEN_PANE)
self.blue_text = self.load_gui(GamePanel.BLUE_TEXT)
self.green_text = self.load_gui(GamePanel.GREEN_TEXT)
self.timer = self.load_gui(GamePanel.TIMER)
def load_gui(self, element):
return pygame.image.load(PANEL_FILES.get(element, None)).convert_alpha()
def change_player(self):
self.player.active = False
self.curr_player_i = 1 - self.curr_player_i
self.player = self.players[self.curr_player_i]
self.player.active = True
def try_move(self, dir, x, y, speed):
if dir == Direction.HORIZ:
next_x = x + speed
if (self.level.map[y, next_x] == '#' or
(self.level.map[y, next_x] == 'R' and self.pressing != "red") or
(next_x == self.players[1-self.curr_player_i].x and y == self.players[1-self.curr_player_i].y)):
return x
return next_x
else:
next_y = y + speed
if (self.level.map[next_y, x] == '#' or
(self.level.map[next_y, x] == 'R' and self.pressing != "red") or
(next_y == self.players[1-self.curr_player_i].y and x == self.players[1-self.curr_player_i].x)):
return y
return next_y
def update(self):
# to facilitate usage
p1 = self.players[0]
p2 = self.players[1]
# check for pressure on plates
# TODO: Add the other types of plates to press
if (self.level.map[p1.y, p1.x] == "r" and p1.powers[p1.current_power_i] == Powers.PRESS.value) or \
(self.level.map[p2.y, p2.x] == "r" and p2.powers[p2.current_power_i] == Powers.PRESS.value):
self.pressing = "red"
else:
self.pressing = "none"
for plate in self.level.plates.values():
if((p1.rect.x, p1.rect.y) == (plate.x, plate.y) and
p1.powers[p1.current_power_i] == Powers.PRESS.value) or ((p2.rect.x, p2.rect.y) == (plate.x, plate.y) and
p2.powers[p2.current_power_i] == Powers.PRESS.value):
plate.set_pressed(True)
else:
plate.set_pressed(False)
# check for arrival
self.blue_arrive = self.level.map[p1.y, p1.x] == "B"
self.green_arrive = self.level.map[p2.y, p2.x] == "G"
# Check completed condition
if(self.blue_arrive and self.green_arrive):
self.completed = True
def draw(self, screen):
self.level.draw(screen, self.pressing)
def draw_gui(self, screen, time, font):
y = Y_OFFSET
# Blue pane, then blue text box with the player's power
y = self._blit_panel(screen, self.blue_pane, y)
y = self._blit_panel(screen, self.blue_text, y, self.players[0].current_power, BLUE, font)
# Green pane, then green text box with the player's power
y = self._blit_panel(screen, self.green_pane, y)
y = self._blit_panel(screen, self.green_text, y, self.players[1].current_power, GREEN, font)
# Timer box with the elapsed seconds
self._blit_panel(screen, self.timer, y, str(time).split('.')[0], RED, font)
def _blit_panel(self, screen, image, y, text=None, color=None, font=None):
x = (X_OFFSET - image.get_width()) / 2
screen.blit(image, (x, y))
if text is not None:
label = TextArea(text, color)
label.place(x + image.get_width() / 2, y + image.get_height() / 2)
label.draw(screen, None, font, anchor="center")
return y + image.get_height()
# ---------------------------------------------------------------------
# Class MapElement
# ---------------------------------------------------------------------
# This is more of an abstract class that grants common method signature
# and behaviour.
# It inherits from Sprite so that I can add it to the group and
# it already has the draw method implemented
# ---------------------------------------------------------------------
class MapElement(pygame.sprite.Sprite):
def __init__(self, col, row, type):
super().__init__()
self.col = col
self.row = row
self.x = col * TILE_SIZE + X_OFFSET
self.y = row * TILE_SIZE + Y_OFFSET
self.image = self.load_image(type)
self.rect = self.image.get_rect()
self.rect.topleft = (self.x, self.y)
def load_image(self, type):
return pygame.transform.smoothscale(pygame.image.load(TILE_FILES.get(type, TILE_FILES[TileTypes.FLOOR])).convert_alpha(), (TILE_SIZE, TILE_SIZE))
def draw(self, screen):
screen.blit(self.image, self.rect)
# ----------------------------------------------------------------------
# Class PressurePlate
# ----------------------------------------------------------------------
class PressurePlate(MapElement):
def __init__(self, col, row, type):
super().__init__(col, row, type)
self.pressed = False
self.door = None
print("Plate created!")
# I should do the check if the value is boolean, but I do not want to
# (all of my methods do not have such checks, which is a bit ugh)
def set_door(self, door):
self.door = door
def set_pressed(self, value):
self.pressed = value
if self.door is None:
raise ValueError("Door is None")
self.door.set_open(self.pressed)
def is_pressed(self):
return self.pressed
# ----------------------------------------------------------------------
# Class Door
# ----------------------------------------------------------------------
class Door(MapElement):
def __init__(self, col, row, type):
super().__init__(col, row, type)
self.open = False
print("Door created")
def set_open(self, value):
self.open = value
def is_open(self):
return self.open
# I have to ovverride the sprite method, because I have to check if it is opened
def draw(self, screen):
if self.open == False:
super().draw(screen)
else:
pass
# ----------------------------------------------------------------------
# Class GrabbableObject
# ----------------------------------------------------------------------
# represents objects that can be grabbed and put in inventory
# they will be necessary to press certain types of pressure plates
# yet to be implemented
# ----------------------------------------------------------------------
class GrabbableObject(MapElement):
def __init__(self, col, row, type):
super().__init__(col, row, type)
self.grabbed = False
def grab(self):
self.grabbed = True
def release(self):
self.grabbed = False
def is_grabbed(self):
return self.grabbed
# I have to ovverride the sprite method, because I have to check if it is opened
def draw(self, screen):
if self.grabbed == False:
super().draw(screen)
else:
pass

201
main.py Normal file
View file

@ -0,0 +1,201 @@
from datetime import timedelta
import pygame
# project modules
from constants import *
from levelstate import Level
from levelstate import LevelState
from new_gui import *
import db_utils
from gamestate import *
from levelstate import Direction
# -----------------------------------------------------------------------------------
# Play state Loop
# -----------------------------------------------------------------------------------
def play(game_state, events):
# for ease of use
levelstate = game_state.level_state
player = levelstate.player
# Event polling
for event in events:
if event.type == pygame.QUIT:
game_state.running = False
elif event.type == pygame.KEYDOWN:
# Controls
if event.key == pygame.K_LCTRL:
player.change_power()
if event.key == pygame.K_LSHIFT:
levelstate.change_player()
player = levelstate.player
if event.key == pygame.K_ESCAPE:
game_state.state = State.PAUSE
game_state.pause_start = pygame.time.get_ticks()
# Movement
if event.key == pygame.K_a:
player.x = levelstate.try_move(Direction.HORIZ, player.x, player.y, -player.speed)
elif event.key == pygame.K_d:
player.x = levelstate.try_move(Direction.HORIZ, player.x, player.y, player.speed)
elif event.key == pygame.K_w:
player.y = levelstate.try_move(Direction.VERT, player.x, player.y, -player.speed)
elif event.key == pygame.K_s:
player.y = levelstate.try_move(Direction.VERT, player.x, player.y, player.speed)
# update level state
levelstate.update()
# update sprites
levelstate.all_sprites.update()
# bg
levelstate.draw(screen)
# Timer Text
time = timedelta(milliseconds=game_state.elapsed)
levelstate.draw_gui(screen, time, small_font)
# rendering of all the sprites
levelstate.all_sprites.draw(screen)
# -----------------------------------------------------------------------------------
# Pause state Loop
# -----------------------------------------------------------------------------------
def pause_menu(game_state, events, mouse):
# getting menu object
menu = game_state.pause_menu
# Display the menu
menu.draw(screen, mouse, title_font, small_font)
# Event polling handled by the menu
for event in events:
value = menu.handle_event(event, mouse)
# Actions based on what has been done in the interaction with the menu
if value == "playing":
game_state.state = State.PLAY
game_state.paused_time += pygame.time.get_ticks() - game_state.pause_start
game_state.pause_start = None
elif value == "select_level":
game_state.level_state = None
game_state.state = State.SELECT
elif value == "quit_game":
game_state.running = False
# -----------------------------------------------------------------------------------
# Menu state Loop
# -----------------------------------------------------------------------------------
def start_menu(game_state, events, mouse):
menu = game_state.start_menu
menu.draw(screen, mouse, title_font, small_font)
for event in events:
value = menu.handle_event(event, mouse)
if value == "quit_game":
game_state.running = False
elif value == "select_level":
game_state.state = State.SELECT
elif value == "delete":
db_utils.reset_db()
# -----------------------------------------------------------------------------------
# Select state Loop
# -----------------------------------------------------------------------------------
def select_level(game_state, events, mouse):
menu = game_state.select_menu
menu.draw(screen, mouse, title_font, small_font)
# Event polling
for event in events:
value = menu.handle_event(event, mouse)
if value == "quit_game":
game_state.running = False
elif value == "menu":
game_state.state = State.MENU
# The select level buttons have 2 values, the path and if the level is unlocked
# This is way there is the check for a tuple
elif value != None and isinstance(value, tuple):
completed = int(value[1])
level_path = value[0]
if completed == 1:
game_state.level_state = LevelState(Level(level_path))
game_state.state = State.PLAY
# Start timer
game_state.play_start = pygame.time.get_ticks()
game_state.paused_time = 0
game_state.elapsed = 0
break
# -----------------------------------------------------------------------------------
# Complete state Loop
# -----------------------------------------------------------------------------------
def completed_menu(game_state, events, mouse):
menu = game_state.completed_menu
menu.draw(screen, mouse, title_font, small_font)
for event in events:
value = menu.handle_event(event, mouse)
if value == "quit_game":
game_state.running = False
elif value == "select_level":
game_state.level_state = None
game_state.state = State.SELECT
elif value == "retry":
game_state.state = State.PLAY
game_state.level_state = LevelState(game_state.level_state.level)
# Start timer
game_state.play_start = pygame.time.get_ticks()
game_state.paused_time = 0
game_state.elapsed = 0
# -----------------------------------------------------------------------------------
# PYGAME SETUP
# -----------------------------------------------------------------------------------
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# Graphic assets
title_font = pygame.font.Font('assets/ARCO.ttf', 35)
small_font = pygame.font.Font('assets/ARCO.ttf', 20)
background = pygame.transform.scale_by(pygame.image.load('assets/background.png').convert_alpha(), SCALE_FACTOR)
# Db Init
db_utils.init_db()
# GameState setup
game_state = GameState()
# MAIN LOOP
while game_state.running:
screen.blit(background, (0, 0))
events = pygame.event.get()
mouse = pygame.mouse.get_pos()
if game_state.state == State.MENU:
start_menu(game_state, events, mouse)
elif game_state.state == State.PLAY:
play(game_state, events)
elif game_state.state == State.PAUSE:
pause_menu(game_state, events, mouse)
elif game_state.state == State.SELECT:
select_level(game_state, events, mouse)
elif game_state.state == State.COMPLETE:
completed_menu(game_state, events, mouse)
# update game_state
game_state.update(pygame.time.get_ticks())
pygame.display.flip()
clock.tick(FPS)
pygame.quit()

307
new_gui.py Normal file
View file

@ -0,0 +1,307 @@
# libraries
from enum import Enum
from functools import lru_cache
import pygame
# project modules
from constants import *
# NOTE_1
# Refactored using AI (Claude), did a great job, uses some obscure syntax
# still much better than the original which was becoming unusable
# I will use some of the stuff introduced by AI in this file to refactor all the other files
# NOTE_2
# The .get() function takes 2 values, the first is the field of the dictionary, the second
# is a default value to return if the key is not found
# -------------------------------------------------------------
# Enum and tables
# -------------------------------------------------------------
class ButtonTypes(Enum):
# The value doubles as the asset prefix: assets/<value>_btn.png
# and assets/<value>_dark_btn.png
PLAY = "play"
RESUME = "resume"
MENU = "menu"
DELETE = "delete"
QUIT = "quit"
RETRY = "retry"
FW = "fw"
BW = "bw"
GO = "go"
class MenuType(Enum):
PAUSE = 0
COMPLETED = 1
START = 2
SELECT = 3
class EntryState(Enum):
UNLOCKED = 0
LOCKED = 1
# Unscaled hitbox sizes (width, height); anything not listed uses the default
DEFAULT_HITBOX = (232, 82) # Defaults to a normal button
HITBOX_SIZES = {
ButtonTypes.FW: (105, 82),
ButtonTypes.BW: (105, 82),
ButtonTypes.GO: (83, 63),
}
CARD_FILES = {
MenuType.PAUSE: "assets/paused_card.png",
MenuType.COMPLETED: "assets/completed_card.png",
MenuType.START: "assets/menu_card.png",
MenuType.SELECT: "assets/select_card.png",
}
ICON_FILES = {
EntryState.LOCKED: "assets/locked.png",
EntryState.UNLOCKED: "assets/unlocked.png",
}
# Layout constants for SelectEntry
ENTRY_WIDTH = 500
ENTRY_PADDING = 20
ENTRY_ICON_X = 800
# --------------------------------------------------------------------------
# Helpers
# --------------------------------------------------------------------------
@lru_cache(maxsize=None)
def load_image(path, scale=1):
image = pygame.image.load(path).convert_alpha()
if scale != 1:
image = pygame.transform.scale_by(image, scale)
return image
# --------------------------------------------------------------------------
# Widgets
# --------------------------------------------------------------------------
class Widget:
# Anything a MenuPage can stack vertically.
# Note: this notation is called type hinting
rect: pygame.Rect
def place(self, centerx, y):
self.rect.centerx = centerx
self.rect.y = y
# This are just the interface for the methods implemented in the various widgets
def height(self, text_font):
return self.rect.height
def draw(self, screen, mouse, text_font):
raise NotImplementedError
class Button(Widget):
def __init__(self, value, kind=ButtonTypes.PLAY):
# value is a free-form field returned when the button is clicked
self.value = value
self.kind = kind
# f-strings from python 3.6 to embed variables
prefix = f"assets/{kind.value}"
self.image = load_image(f"{prefix}_btn.png", SCALE_FACTOR)
self.dark_image = load_image(f"{prefix}_dark_btn.png", SCALE_FACTOR)
width, height = HITBOX_SIZES.get(kind, DEFAULT_HITBOX)
self.rect = pygame.Rect(0, 0, int(width * SCALE_FACTOR), int(height * SCALE_FACTOR))
# text font is none because buttons have text in the image but the interface is the same for all widgets
def height(self, text_font=None):
return self.image.get_height() / 2
def clicked(self, mouse):
return self.rect.collidepoint(mouse)
def draw(self, screen, mouse, text_font=None):
image = self.dark_image if self.clicked(mouse) else self.image
# The image is always centred on the hitbox, so nothing to keep in sync
screen.blit(image, image.get_rect(center=self.rect.center))
class TextArea(Widget):
def __init__(self, text, color):
self.text = text
self.color = color
self.rect = pygame.Rect(0, 0, 0, 0)
def height(self, text_font):
return text_font.size(self.text)[1]
def draw(self, screen, mouse, text_font, anchor="midtop"):
# The anchor can be any rect attribute like midtop, topleft etc
surface = text_font.render(self.text, True, self.color)
position = getattr(self.rect, anchor)
screen.blit(surface, surface.get_rect(**{anchor: position}))
class SelectEntry(Widget):
# One row of the level-select menu: [go button] [label] ........ [lock icon]
def __init__(self, text, value, state):
self.value = value
self.btn = Button(value, ButtonTypes.GO)
self.label = TextArea(text, DARK)
self.icon = load_image(ICON_FILES[state])
self.icon_rect = self.icon.get_rect()
self.rect = pygame.Rect(0, 0, ENTRY_WIDTH, self.btn.rect.height)
def place(self, centerx, y):
super().place(centerx, y)
x = self.rect.x + ENTRY_PADDING
self.btn.rect.topleft = (x, self.rect.y)
self.label.rect.midleft = (x + self.btn.rect.width * 3, self.rect.centery)
self.icon_rect.topleft = (ENTRY_ICON_X, self.rect.y)
def clicked(self, mouse):
return self.btn.clicked(mouse)
def draw(self, screen, mouse, text_font):
self.btn.draw(screen, mouse)
self.label.draw(screen, mouse, text_font, anchor="center")
screen.blit(self.icon, self.icon_rect)
# --------------------------------------------------------------------------
# Menu page
# --------------------------------------------------------------------------
class MenuPage:
"""One card with optional top text, buttons, entries and bottom text,
stacked vertically and centred on screen."""
def __init__(self, kind):
self.top_text_area = None
self.bottom_text_area = None
self.buttons = []
self.entries = []
self.total_height = 0 # set by draw(), read by Menu
self.bg_image = load_image(CARD_FILES[kind], SCALE_FACTOR)
@property
def is_full(self):
return len(self.buttons) + len(self.entries) >= MAX_BTN
def add_button(self, value, kind):
self.buttons.append(Button(value, kind))
def add_entry(self, text, value, state):
self.entries.append(SelectEntry(text, value, state))
def add_top_text(self, text):
self.top_text_area = TextArea(text, DARK)
def add_bottom_text(self, text):
self.bottom_text_area = TextArea(text, DARK)
def _elements(self):
elements = []
if self.top_text_area:
elements.append(self.top_text_area)
elements.extend(self.buttons)
elements.extend(self.entries)
if self.bottom_text_area:
elements.append(self.bottom_text_area)
return elements
def draw(self, screen, mouse, btn_font, text_font):
# btn_font is unused now; kept so existing calls don't break
center_x, center_y = screen.get_rect().center
screen.blit(self.bg_image, self.bg_image.get_rect(center=(center_x, center_y)))
elements = self._elements()
spacing = BTN_HEIGHT * 0.5
heights = [e.height(text_font) for e in elements]
self.total_height = sum(heights) + spacing * max(len(elements) - 1, 0)
y = center_y - self.total_height / 2
for element, height in zip(elements, heights):
element.place(center_x, y)
element.draw(screen, mouse, text_font)
y += height + spacing
def handle_event(self, event, mouse):
if event.type == pygame.QUIT:
return "quit_game"
if event.type == pygame.MOUSEBUTTONDOWN:
for clickable in (*self.buttons, *self.entries):
if clickable.clicked(mouse):
return clickable.value
return None
# --------------------------------------------------------------------------
# Multi-page menu
# --------------------------------------------------------------------------
class Menu:
"""Paged menu: new pages are created automatically when one is full.
For now pages hold only buttons or entries, no top/bottom text."""
def __init__(self, menu_type):
self.menu_type = menu_type
self.pages = [MenuPage(menu_type)]
self.current_page_i = 0
self.prev_btn = Button(None, ButtonTypes.BW)
self.menu_btn = Button("menu", ButtonTypes.MENU)
self.next_btn = Button(None, ButtonTypes.FW)
self.nav_buttons = (self.prev_btn, self.menu_btn, self.next_btn)
@property
def page(self):
return self.pages[self.current_page_i]
def _page_with_room(self):
if self.pages[-1].is_full:
self.pages.append(MenuPage(self.menu_type))
return self.pages[-1]
def add_button(self, value, kind):
self._page_with_room().add_button(value, kind)
def add_entry(self, text, value, state):
self._page_with_room().add_entry(text, value, state)
def draw(self, screen, mouse, btn_font, text_font):
center_x, center_y = screen.get_rect().center
self.page.draw(screen, mouse, btn_font, text_font)
spacing = BTN_HEIGHT * 0.5
bottom_y = center_y + self.page.total_height / 2 + spacing
group_width = sum(b.rect.width for b in self.nav_buttons)
step = group_width / 2.5
# Left / middle / right, spaced `step` apart around the centre
for i, button in enumerate(self.nav_buttons):
button.place(center_x + (i - 1) * step, bottom_y)
button.draw(screen, mouse)
def handle_event(self, event, mouse):
if event.type == pygame.MOUSEBUTTONDOWN:
if self.prev_btn.clicked(mouse):
self.current_page_i = max(self.current_page_i - 1, 0)
return None
if self.next_btn.clicked(mouse):
self.current_page_i = min(self.current_page_i + 1, len(self.pages) - 1)
return None
if self.menu_btn.clicked(mouse):
return self.menu_btn.value
# Also handles pygame.QUIT and clicks on the page's own buttons
return self.page.handle_event(event, mouse)

66
player.py Normal file
View file

@ -0,0 +1,66 @@
# libraries
from enum import Enum
import pygame
# project modules
from constants import *
# ------------------------------------------------------------
# Class Player
# - represents the player object
# ------------------------------------------------------------
class PlayerTypes(Enum):
BLUE = "blue_robot"
GREEN = "green_robot"
class Powers(Enum):
PRESS = "press"
GRAB = "grab"
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, active, type=PlayerTypes.BLUE):
super().__init__()
# Attributes
self.speed = 1
self.width = 50
self.height = 50
self.x = x
self.y = y
self.active = active
# Yet to see if useful
self.direction = "up"
# Yet to find usage for grab
self.powers = [Powers.PRESS.value, Powers.GRAB.value]
self.current_power_i = 0
self.current_power = self.powers[self.current_power_i]
# Sprite image
self.active_sprite = pygame.image.load(f"assets/{type.value}.svg").convert_alpha()
self.inactive_sprite = pygame.image.load(f"assets/{type.value}_inactive.svg").convert_alpha()
self.image = pygame.transform.smoothscale(self.inactive_sprite, (TILE_SIZE, TILE_SIZE))
# Hitbox and position
self.rect = self.image.get_rect()
self.rect.topleft = (self.x*TILE_SIZE, self.y*TILE_SIZE)
def update(self):
self.image = pygame.transform.smoothscale(self.inactive_sprite, (TILE_SIZE, TILE_SIZE))
if self.active:
self.image = pygame.transform.smoothscale(self.active_sprite, (TILE_SIZE, TILE_SIZE))
# update rect position
self.rect.x = self.x * TILE_SIZE + X_OFFSET
self.rect.y = self.y * TILE_SIZE + Y_OFFSET
# Function to change current power
def change_power(self):
self.current_power_i += 1
if self.current_power_i >= len(self.powers):
self.current_power_i = 0
self.current_power = self.powers[self.current_power_i]

BIN
progress.db Normal file

Binary file not shown.