From 6c7f2034f771b6d0675514910e0f25873887569e Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Wed, 4 Mar 2026 21:27:52 -0800 Subject: [PATCH 01/33] [FEATURE] Implement a custom splash screen #308 Implement a custom splash screen in SkyLockAssault using Godot 4.5, displayed at game startup before transitioning to the main menu. Include fade-in, pause, and fade-out effects for a smooth introduction, replacing the default Godot splash. For web exports, integrate with the existing custom HTML shell (custom_shell.html) to handle initial loading visuals consistently. --- custom_shell.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/custom_shell.html b/custom_shell.html index 0d8c9282..c9fd933a 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -105,6 +105,23 @@ height: 50px; transform: translate(-50%, -50%); } + /*LOGO*/ + .logo-container { + display: flex; + flex-direction: column; /* Stack them vertically */ + align-items: center; + gap: 20px; /* Space between the two logos */ + margin-bottom: 30px; + } + .splash-img { + max-width: 40%; /* Godot logo size */ + height: auto; + } + .custom-logo { + max-width: 150px; /* Your logo size */ + height: auto; + filter: invert(1); /* Turns your black logo white for visibility */ + } @@ -113,6 +130,7 @@
+ Loading...
From d3a63872145ddfff2fe83570173dc9305f961ec5 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Wed, 4 Mar 2026 22:42:20 -0800 Subject: [PATCH 02/33] Revert "[FEATURE] Implement a custom splash screen #308" This reverts commit 6c7f2034f771b6d0675514910e0f25873887569e. --- custom_shell.html | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index c9fd933a..0d8c9282 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -105,23 +105,6 @@ height: 50px; transform: translate(-50%, -50%); } - /*LOGO*/ - .logo-container { - display: flex; - flex-direction: column; /* Stack them vertically */ - align-items: center; - gap: 20px; /* Space between the two logos */ - margin-bottom: 30px; - } - .splash-img { - max-width: 40%; /* Godot logo size */ - height: auto; - } - .custom-logo { - max-width: 150px; /* Your logo size */ - height: auto; - filter: invert(1); /* Turns your black logo white for visibility */ - } @@ -130,7 +113,6 @@
- Loading...
From 339116c470db1b87ca89369b54e2965267b4e39c Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Wed, 4 Mar 2026 23:49:18 -0800 Subject: [PATCH 03/33] Add logo assets and update project/export Add multiple branding assets (SVG, PNG, JPG) and their Godot import metadata under assets/ (godot_logo_bg_removed, ikostan_logo, ikostan_logo_bg_removed, logo_large_monochrome_light, logo_vertical_monochrome_light). Update export_presets.cfg to include assets/* in the export bundle. Update project.godot with a project description and boot splash settings (background color and boot splash image uid) while keeping the existing icon and main scene. --- assets/godot_logo_bg_removed.png | Bin 0 -> 25697 bytes assets/godot_logo_bg_removed.png.import | 40 ++++++++++++++++ assets/ikostan_logo.jpg | Bin 0 -> 107331 bytes assets/ikostan_logo.jpg.import | 40 ++++++++++++++++ assets/ikostan_logo_bg_removed.png | Bin 0 -> 81217 bytes assets/ikostan_logo_bg_removed.png.import | 40 ++++++++++++++++ assets/logo_large_monochrome_light.svg | 1 + assets/logo_large_monochrome_light.svg.import | 43 ++++++++++++++++++ assets/logo_vertical_monochrome_light.png | Bin 0 -> 28491 bytes .../logo_vertical_monochrome_light.png.import | 40 ++++++++++++++++ export_presets.cfg | 2 +- project.godot | 3 ++ 12 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 assets/godot_logo_bg_removed.png create mode 100644 assets/godot_logo_bg_removed.png.import create mode 100644 assets/ikostan_logo.jpg create mode 100644 assets/ikostan_logo.jpg.import create mode 100644 assets/ikostan_logo_bg_removed.png create mode 100644 assets/ikostan_logo_bg_removed.png.import create mode 100644 assets/logo_large_monochrome_light.svg create mode 100644 assets/logo_large_monochrome_light.svg.import create mode 100644 assets/logo_vertical_monochrome_light.png create mode 100644 assets/logo_vertical_monochrome_light.png.import diff --git a/assets/godot_logo_bg_removed.png b/assets/godot_logo_bg_removed.png new file mode 100644 index 0000000000000000000000000000000000000000..9b22a44bf4dfad0eb4cb785c91d11dd75721770b GIT binary patch literal 25697 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 literal 0 HcmV?d00001 diff --git a/assets/godot_logo_bg_removed.png.import b/assets/godot_logo_bg_removed.png.import new file mode 100644 index 00000000..6ffde562 --- /dev/null +++ b/assets/godot_logo_bg_removed.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cs3bksakdbt0u" +path="res://.godot/imported/godot_logo_bg_removed.png-caadf3749ad830a08d0cf4bc77bc06ca.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/godot_logo_bg_removed.png" +dest_files=["res://.godot/imported/godot_logo_bg_removed.png-caadf3749ad830a08d0cf4bc77bc06ca.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/ikostan_logo.jpg b/assets/ikostan_logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..319023f14586b104d59983aae8535f94471e2c15 GIT binary patch literal 107331 zcmeFZc~n#9_dfb&Ac4qiR6rmoD5=&8f=r4@P(g4Y4%HT|sHot8$RH{dP9R!aiy%U) zbs)z&fbGXpD~gpu9El@I#flXX6f__rGDJv7!rkYbVEg@i*Inzk?!ABBb}bPJ$vN-4 z-@TvxJkLIZj|ZPKY-jJ-upXiC@CnEqA;dt|G&-6`Lud+oHx2$i4!&l>_Z#*w5qv=> zh(F-J#T#O`tWMdMv@Xca&quWW^QFs@e0Q$jyg6!Hs;`evTx|TjiL)aoi^Yq4*82H{ z#>`!?-gkrFtjQbvrf!{>GAm?F>=OT_Y1=j=q{VOZ7p3@luZa~+oRhFRe(stS@n-?z z(21W-4qFpDXVbdPiJu3=e>T}~$;`P+x2#_lKWFZzDGMXF$E@3!u<6t7UQ^d3Y!(Hq zo;h`%*OIifDDSzOKU+L^TWt8Ja~7^!Jnyp|OO}MDZQV3qyd-eqtcb}8Q~fs0Tq{Zm zUpjxWX!5#*&{=5_qNELLmQ38_wPkhKQt`s6o3@0`-{d!W_UEg`YkU{XUA!}VvDZZZ z6raz%7cW`+*~YLnNlOxwKc72yoByIvuT*j9#u(qJerv>^&z?Ou)qitr>^kwH*jbDH z!saJci;IqbWov+`zb+Gtf9bluyu>2QHTOe9IGd%qN z--`b)w_>mf*+zthhawuRF^vfL!Fn_kzWaaoAMqyt@7@7^d+-XfGiUB+*fMB#h;Bz? z*wF@WARb(&8TH=exr9GxbOzIm#WuI#41*V3utjtlgF$C9%*>cf_-O|G95L<8?8kVE zSi={tW{*wePRYtYZtfm(?&^p|f4=kZS(B7)!5KNq!O>~lcu)RE6ClF<0|J9)&YB$> zHYYq{@sdxMF8l2BsF=0u*2l(e*qEHMEp_{jooUityT97=^*4JD6cm2<{lP;&9RBgd z$y29`OV0fC+xfB!7t1gGe)-z<8#k*Jw{G8gQ2X$&M|F??e)9Z9bIZ$D>ejZ`UEMvs zn)iMES{-p;G{pF@WYnGg*L}ev(CADigUKfDi$>p0+_)XnY>YR{UbK+CI&t{eDOu*+ zko@E4u3EVJEP6L$P12v7ksiL!$8{06M&8-~*^OoYKf1FIH}=ncJwcWX8f+fJ4hfKP z>s)&;OxKH^Sf29Fm|+}5X}0-&=R1xLqCL^Z@(YaOx|g~ff!EW@blo7*45I7ZxN3dv zzJ?MSAK?~u>Bi`0QQ_&%;>O0#S%ucJ=!37hPIi}CF`FKpDmJq8uErf#h0xskxWkpM zgGf4v#$*LYz8pk#cwlqmJFI06D}c-8qC>9IZm#nS6{GO^9yw3lb(8hmx9KTujjL;d zyxwqd)}67jOX z8t*(Z2(7PV(xoBm22SYv@L?8xVa@vctZhMG4kFQCs`a7$ZeD}P9WKSNDezRvz_US= zweaAi-pX6;KC5s#e8@Z-k(OiGrqO2N$izI30fxVdpj@NGj_H?Qt6@*6}Wu_uc599YGYz}v8RW=v`RZGDeO z71;})HoAKdZ68D~g6E>chpT>iwq4#jwcrwOp%L4Us{}iZsVc@aO=q1U2iO;jYC}2cyK`8-!_OimakK^ zMrnzU``WkchnTE|PY<$|;AWgik#IP18Ma4ly&^9SBEfUvFrgV*)-E*jeX@O4g#TX& z+Cj8`Xy> zIwQZJ-^jK5X!&gUOXC`8(QMYN_@0=AfcE;*I@dy{#jrKA7wl;_z+T2{Gl+n`99x_a zg*GhhHHK-$$S!Yl238X{cG1OevAg=)BU1B{A4$hNwEpD2px;#_O3oOr(K|U9*mXK5 zIuYu#MYuT9BRzAn{+gsEFX84OIwTg0X(HMA9=)JxH;oF-F`}|HErZB!&QF}4r|&Rj z^G((^_bnBf{=eSi&D1(^>?Pcfg1!4yu^rRpyngy_?XMX-b=!%tjR+44ufmA z5ZV=bsND=Z29cBH!@o33dnyN!@Kc57J6yG&h;zyK$jbuWt2iIo->}0!&-VW-y5_xs zJt6h)&wn{)-0pPUy|Ls!>KUaiRqgF-xGtJnWteWiYI6W)GoTnm>mXuiLNiv1PA?bZ zD)Ed}HoRi(eP+bcKNGar4_?TUW4Y_fmD}~b0qO_Rh>XnWGZqd_syHsH7N)IoLK*A; zG5kJTO_`=zKM92lq8&!wEpdt!&YryT z2cxXE2e&9eIMahsSJ&lw5}Sb5$k$}(*0*Eez9p6TCGY-ZY+Kv8BLyu&_&WJ z+4h9Wy|my7ryHJhlt0}UKKwXDlt>&S_(m^}yp`0;6X{E)hEK9Bv*go~G9q8a(ZX*< zAJ?DH(wET693Qsz80bQ~CYe!^-f$oT4fyza31`=aPPJ+ickd?X?NO7~ih2V=_TBE0E-+0nJRGvs^9 zwQaZ12^Z(&$9Zi>RclWERq=`JU0Ci;4cF--&n=zBdb>D2tTRfi%`1lULoO1m)?xGT z%6z-j;I7_56o^0F5ZFS*23p|L$lEiBR!SW1cwg!4A4L0*&v!HS=#43;5Op-ZDSaul z|H#8~5b0V272*^#G@gy?ccbx*eORZ=SjpP5Q8!Whtnv7$2^lw8*~1GSXApZV@kF#N zGTCs+HR1G{&5%!iD87;63qfx)o9&@umLWJ)HAfb-@>%uUSBqA3clJ;2w(U~lzU=80 z#$o!e`F@ZP5q|$_bXdZ~Xbs2Ap>bKcTK<$D;HKI*4)Hxw0tV5HUbI#xyQiWRyvBTl ztjII^`_NiU`*=qUrqs3z&4YTC<$?#0T)79*4x{|VY!BlSq(l7i*f4Eo9N+xQiE8by zIHaT7S6p_(Z;lCI4kB64ee%#OnnWys2!HYTO~rX7)}!sxOB}+d%Zj!7R+@!!yks0C zo;rxAqBy#6PK%f>W-gdBoo6hstE-bmA>j?n*gI zQQYH;3LTU$u*tXWejRtNEw30p!LYLEp*^SZTBcNQg*eA<>1=xR``E&)nMoEdzw?^l zYLQ2uuR}@s7Gv~GHRRrBsugafTL$En z9f^F0my4cVgA>Ey7G+C3;g#;IZWvTEb|u3JII_S$6=$1HE-JL#$`8CI#rf!Jb$Tps z9~y)9r|-3VI-)nV`@$ev=r_6eHC9apI{LI;<4c`<4szl9+VWi>Uo6ahtQY7WB8Zh( z_Mh^|o4?}UOuIOUnzVMm*@xc}5F7Cck+gm3oB`P&if$9(W`V}aDqO|f>lLg!jJ7&9 zi5YwS(qf5SDg#9H(}tgxC3O95neg4#8M1q@*Bj|YmoKcBTd96ZGNZQ~Ot^_1dd)cS zg?xl@?Z*{~HOZo1pP;1<0X1>7mx0a2A0i%Sx@g}+O*L#ZU$kk~AYulT1jl_e|ExwY z2=V)(683s3I%x=QrCps8c+0aFH{(xBgh-%Gmt(bqs8neABsq5woes{Fsn4QM9tF#b zAzyJlLM6 z>IQU)S{1`9IVZVI$XOzV3sZOh>uQ1^8dk3;5B63(uZM8kdxGcH2O&iOKDLA{64fBu z1Bt_}aF6XBMojmRtjV(;XN0vIxlZ zSx1{?-F#?avV@k}RCU6aSV0}HZZBZPFvxXt04K5ovV?&yiswem$tqYTdk*`({edZR z@r6gKp^ax)=Xkf*X#_P{>E_9nxHI_ivMWvH@E-(}2*8*@LU?(U~L zbK98x$#1c1(!lWB#yLXvs^)I)X!u2k1F5~vmWDV-7c?Pfzd&#bO}DAI9;;X9Vy9=b ztmn5jHhsgNy3bd)vc95T!?Adu2>{I&H{H=DOJ1{HP|_hJF%@T2ahjDGZWcVM%`hLK z;Y1R3LW)2^XHp#PArdoZS>I_q$a|=w|Fqq`RiNzlrSX~X_%y%#zva#{^}n(d&2`kk zSuL*%XRoprI_l-RYZ5MEnZbHLkPPRgyF~T?SXn7?c>v24L(9L;D{fOdC@%78se`Dj z@fiAqC^@W5s)kPb0KjllDm?qp5ZQw>VU-aa1iFMD#V=s1=;A}Btc|cQhU3t6E7K*BM2Qfw0feOD@4cl z9!7^OEyXdc&MgCmdr?*o;{P_IyYyh`gUFTFEVP2VAAa(v;f2(4x$uUON(@GWS+wo~8nt_R!iZyfL$3QvYt& zxq@%?D)AgK-Co$V7LsKRh2Hii1rMm=f+Q}Lm6*uLMNdd%M_erx?Ej}9|iZP?ig{XOMfsQV%G}E#oyk=2)dHF%D8O`zM zw$g3o=_wqm+Q=p2S;@H>apS!&mST6YKfHq3E&Pwa&M7E|+y|hAY;i*hYM~SbE@pf3 zBD-)4zPEULU1Tut^%$hVA9yb`d~O%&a-IZ9I7d+)g_83AD1O{!%p{tw(9hm#cQ(5O zY4qs>Lrto?Rw>Ha)(O8MkZoiDPUpRwtrN$&IXFO%6F%-YdoDydeS+^$pb(`?<}-)7IGpw%`zD!bK6MNLctV^V`7snGHGW<~99I;S)7uF} zJ9UB}vXxH@Ip70TCS+PpdY91`<>1@ZwZt}hB^LdyXcn4ZcgurXdW-;V=n4Qk2y4`- z)Hdg}--iSA0N3DV^YWD*y*jKYvk=O2$F6M?AoE>7qp>H^H4^&CjNlU5C51z^DH6=z zgf+#DU-;_c#a|Dx53nLj9C3Ho<8GPbh?Y$Q|jxp<=q-kJb%g~;D zz%zT%n(ykf)8XQ#4|EA_*ltdiM|ok`#N`_JETGBuais7A8U5zjgmKXMQq)b9W7 zXv^A`7CY^G{M^-GEV5ll&t}>1{JYh<7+>`KPl1hrsbZ9jU$oF*D_;Mq^K?;^KqW+N zqLsCGyPyZ3M57LCx@v|M7|N^4U8W>X4zz#g{C+yv~UBm6VA zb^n=}og0+c`y%^c-51j@VEFGd8uvqU#lG#@`0XI_-hRnB1#9OF6u>S2xjGY^LFs=vf(Jxa=q&scd)fBVn$tnV>{Wj zL=o8rHRlU&0^=hbzSi2p(e>nd39U#y!@#G7YXm<4z(QLz8iP$gl**P@aFlJ;&X%&C zw|x31nJZ$CE9yK22JDf<`F|7}Pyauc*Yp`I_-=fsg5?{q$vq-bCbjuoCx9X14NOhO zdwmF$6Y`?Td~2OZW;)uDRQ=yI(^A?M^0Ta`U7h`cZnH%;<#nanJ`*t)E|QVGRklQZ z5W9-)PkE2;$LZOH4Vt>Uvvp=>XMVZ7b0hS-WM}(v#Q$0o{?z!&$6_~}(MD}<@<|gV z#I^h<%S*?OGLWELa8_hVMsc6zx z%w1?P6f;!ld|=Js)=}V$cX}+J=;@(8BBJ{u%MIC~2pb|F!k!a5DHTv#Ya$Nlrkdsz z)GWI$0MxfqLM4eSy}bQ+(mu^{Bi6zwo|m3z;7_r%jJfD-%z(UrCb5NZt@dlb`~z!l z2!yhnd8~vsH}|Pg2FTdFY^@fJ3fs9+iWaU}rw;~l6HSM_lcYoeXNkAW76W>|^ zJf!4@0L5mtegOLraHcm2ye6@Qa5qbuTmC|Rj{x(5>BojCqIO7ey~4vf@aHShK}aS&d}eBCo)_KlPbq=%ZVGoy2jK1|6G$9UnbeFk4y2$g2h7IX~A5aXI3QlsA1Hna4%a z`O~~`Mmw>{;&uFKZGEW&kHtcQn&8sLZyjC~Bm*@0pZQEtd3sf2$#n`mjTU*P|I%1e zXv;;r_6Il$)IB(|4V_J!|#IoyIIevC?=T~j^(xT@Jaj4 z7R|44@5>GLA@x|AP{szH=lf>k!GATD8uMwZ^hf0WC`% z&ie9RmG*rLrZXPnPc1xfIWju3ZS!;#Bwjm-Rb13*Fj`R6OWdB-=H|R^IEB-bg?5(jm2fYQ zaErxn^AzxsZA4mONPq2wmgznUl={DG?&8uGNJcCv*HHY${QXHm&1V6`(6bJ(&yt-P z*>y@Si0&!E%I&+-MyztT*={mHQK*OSJ8DDq+rKt$(Y3$)(O_wydcKGYQ|lrpMYo#z zgb`n#{;sw&-N;;P8{}E%Z2V)mP&Bc;KH}IV7T32XC z94tgDGDCADIR#e~+7}WVpL!r&+r^Aw!=bUGuFIK<=Ur>pNbHtv*?AuY*awN@@Y0{< z-<{PRU1 zknH5fyRW(12;Ji~sdqE3p3&<xfaD`bmnoT- z6ac`YsJdcr3vgeRIMhP0CuGZ`Yh9qnWI*M-ViCYKPm)+z)s<`enzdr4grH><7e z?QY~+%-f^ELkM2BcELS9^GK?QNM$6S^Do44XHnI+2}=DgrfZ?CV?a%yBCx9r19 zey%KQ@6X;J=EAp_7+luMcaiALSXV)TF!k;zmGRDmunCRJj2=JfGqFYSPk`bQerkjk zzzx5(CnhcPgg(xf>YitdB&$}eLDQ1YTAP7P^l9Ts`_nZyw~d9HKI zhKB}03I2d!1m{A85j!=8nQKiZ(BolDdkoGHkIK&QGfFlT;=hoXcfb6ZU{5!fO-esE zn7Omf?9X_tJ=!C*fxlBpgLpqv01(jc!#80s2aGbH+Whp-8ZcdhcU}1@Byf(Y=Q^CJ zXfOT#+g^vyWS4DT78v6E93XA+>8nJJ6ftf_6hIRg9YQQp;fMMwb<{_`)Vkqgx+cq7 zu4PwJgy4r?u)GG;fdprLk3frg$oI*s%#4pOpKqA-ILDjqDT^8wKFMw>gM>-+>~Z5S zw%1*}DmuFM#US$a{gusA2g{XO+Hc`;dl*l7H^km|Zf4vh;@*se z*SX{3Tlicg#34&Z4a-URxxT0It^4}b^{zm}DPJBQMyVPvYyOm7Z!==^#P-XUZ&GbD z`>Q;(=wz5*6Z|#SQhHtA(aS%eRSD_hVN%R>(PtPrLbzgCSi- zw~ri8A?(FZHjTuQ85L3>KfaH zHj8uVEqzc*+7rn(iF}JlvI7TDOeKU9j_OlpHZ+?r4dJ}!LaPbF+vKt!A?z9jY(IRk za-O;>I5>`WAXSf@LT>9;W+wE!2~yEJ**_T|4ee$nM}|G=(_8S(NnQ2BCBqvy2F%Dc zE-in}wRKZ|naP9jG3jG~3jCtqR~?Z9jyWr`+jk+|xZKdZxYI_Vbs9E)C^o9G;o8hO zA#;e9LaQQk!dmWV`-v$lG6Vqa&KL{r_>G^+)y7#TT&gi=@uCf{cLDGtuY8FAA`c<4 zh9$UIcJ_*&?RcPd|M2hlw7dPGx+qmH~TRi|fWlLGCBL&4#m!%_1&&-VX@ z@&6nYE(uHKT+jG3ujiHrwpioZ>ts(HQ|9e2;!8yqSH?@I;3?y}xoOx?$44#$ksFx9 z3E6=zT@O{vLfCMTj1o}`S}|a7OiE-F$0XK1E$_p+o(q%0$|270Z4I_*mKx&t`4QcT zIoqboj6|8AJ7gV@Hz;1j(JJ{g_JTw2n{{HkiXNNOQyb7p$kAk@ ziTJdNuY8m%(qBnz&%F%-cEv|%?%;1#2g{O0u*$RmW9uNQQuM3nYiYGm=lzR+fn+q_ z^MuFJr+nstKUtmcmv`fu!W(=wA&mVt^HgEvA`csC^*I}L zKktM#1}Bu;H>I$~%|fK;OV(`0b`KRxqQ7W6br}Ti-OPZAtsO5n8IO}`7F>4&r2!(MoU9@ot&^bv*4gy9ci! z68zZRuh~&n>}>WznF6{J##g-P9-t!s4gI% zkh4Rs;283Sq(ov>%6S2A-pF-?R@kb&UB`QeH+YoI^p}a?6z*eiy#)=t6?yGKdtgPF zJtmZFy`v9EK-=#|$6(5hBJ;f}CcF>3yF4OSwaDXluJZ3XdvKR{}$ zkHGXo><6+A9K%AgCD+QGXK@^8^^zBvNp2!H~@2t*g<{7Zkwhp1Wh4a5;zL~b(G9v&U zoB*l2vZNUqd>?0P>kR%UKHKX$JNn%4hp?JvmP`KE&eKFb{n2-OM8XpuZ;sT}>Xw@^ z_FSvNj&SItdOI&Cc6yphT!vt233zp~rKJxKc{}h&Mk68023eRg!j{z?{WdT6G7bdG zM;T*49jD<&g{>a4c3LZ&A zR-snD4-qlLdhx{@+fpk*h4RxTmgi_XYujZ}Y?7A=9bQoIOe*3}DQxH+7%%_?A}Cb8 zugBFff*PM&`aR%nB3uiuiPEBDtsKH~G2HL%W4wgWq0f~ujib8te>(j-tk;lSs~-@H zfs5Fj8H`PiKz{N*`C`a8rOd?o=~x6Ad0BtxZ0huJ6TDwmm0wDjA%(qiqLU$qBswpMu16*vIF}hd3oMT>4kzlmh|LBYB zPgC%X^Oyeyb}8nXGfMZoE2_AY$1191@4)D~O1x$gnt5SQLc6}ick!~n2m+1;HW;#4 z%?5r?blfl0r`{2+7#dIM(I~4JDvM@k6F>-pcZd%&Wvn4S01EQV=g~k3&;+~na$l~) zo=2o{WzmtU%i1`($iK9-6-2yMmNs?IOkGLP5C|bXM@Q@b+)l<>N5#8(om#M)#?pLo zQ4dzM@e8v+!y&j5{I!*Zt%jGUHBjMc<6&LqnD4V?#x-f$#W|AGAuv1*gy=C(geQ*&1sbIoQ|&@x#PtHF+WYUKENM$xB(4 zzRGy4#FsEGuMO<-haq=^}=G*(h_PHJ^Bc%O)@N$@^U7f^oHiumT>^j@9%5g5iu zx%$VE4f^Okk!?b9k@n#SgCA%G{Z?kI)uL0>u^|`N!o9N}i$Vv;r3Q-E{6n*_gfcc! zxtJg;2|3fQqOPtNtZo!*hG$RV`;3%utX9;`|MEgKE}nU$>hR7u;5h$Kml}f-wQ8N} zQ{uxG9tB&NsI6~Lvwj~6{^p8%G1gPt-YK*jDnrSHTIh?)Mld@w>kaq#{_~4d#ss{H zd?1xA9k>`WbL~5fc9V5`+>fKE4#q(me7+ykl%U&-I~#|D2hDoVy1FN(RxyH3)G-q# zWbU2O#;6nA5~I7V@~@4b;pVMiUQ!0APbULaRwp{PKqgR)!gV$;MP3W~I^<7p;tf!; zfs7@yKi_LZ@%k|}1hw@PkOOnv*Uhp4wGPGkntYR?syMy}VCmM#d5P`D8I_e?LK1ng z14x@DLcplUH;g3HM0fZS$q(V&~s*h)OtVq`AzcCQrjQ^zO zXz*`Bb!Vad?soH>e%J~~uHEd38#Z2(MiDV{$gzf%k*-?L%({)UT4I=Qb;+{3m8?P{ z)+V2YKG1%`wx=_W5(-_o&_WVK)0dDo$h|`l|3vAE^d18rxmoWKe8s1kygNC)9S=8G zC+7-WWu?!l5Xx5t&R%&xUTqYKObiW|^d0eiA&}^z^Lf!&d%a$#VpMx8pw~B5TWf7Z z^Gmh^#5k}4fa6YnGR39|Gc2)lj1H57-^ee!`g_+CT4Oe)ed5wvxC)>;ZMkFfDd-Ew zzjRUbfT`%FqEE@&)0zf$*HtlrxSDahDPJ=W(^VBcL?F&(l|5=jj8k;GWsHj%apbYt zi=3@3Iu2X0Q>OD2!1@h)ns3bfN;0|^XXL#j4-Fpy6qR@_*y&4^oK}A zp+2{-Kys^w?uxfd0|pdaNxJUXozc-M*cS?)(y@_A@;Zpc`oOj)QjwJXy+BEFZhjK* z1uWIshYG$k)y=;dXKtFEB+yIio+Ui|+2=uZjo>mHzV zRLG;OEKu}8jrRBVeac$-Srou`@#$AF0OvA7kvOwYaBvX)9H_w=FBfL-FznQ2#0B2G zQj@4Wi#+cd8uckeFa=3Jn>ex0@JYDhHet8WbkDJ_CfUeCJH`eyA_Mb>Vi z6;|3ZiFMV~-I$qGNAyJ|Ozz>Zpg|)F%NXzkS*IROT|4g-csDD@qFXYuyh&d$CcovetuCba*Gxwfla zG$nO;yUL$1tJN9P4Se&8vzqq)eIKWNSv=#Iz%_0>k*0jc<;gdT00)mYCBvo-MCKt2fy8b`s~-CSY!k#4 zhwWbKJdjlnDs&2+-&tFlaV`5s;8n%Shv=T)(^cCvj(}|zR8Av5-Gexy)>$)cy&xwc zygEV|A7n-|ORbnRh$3$!QQ1ZGpOcz|=6|~UrynDF8>$;WAYSjAC4F-Vs5LT$da*_apM&_; zwVHS&=bvUKE7|OB{XUagT*$HbqN+Y~jPTX7Z!0_d%|B!0sMe1z?Bm_ls^X5H$EFS< zGw(PeN5Tcc+JuBo*~!RPbmLcVo{iFrt0N=tf@4kepN-=l)ip#x3)mpjA zAbyF>ziYDvJkWd5VTnt*;S{LkCu5`{`|rw@8>3&1LGLo<>K^=-B*#9O4|W$1VUXHW zg=w_Gawp5RZ~JO-{RiQVHY&F27-l~nZNG0u*pOy!SQ=eoOmVXAHo&SHD^2F*LoXc` zf*(QeE!zJYuHcui3jUNV3ot|DLw$;Zj1zEj#|US>h!)(=xl-e!_(gDvb%QXbz%Q5~*Cz0h3!gi*Lh{79Ap?K?*C);O! zp4xYxEqr2e;Bx)SEaB|W<4dD&Hrgv`i^?Mrv zT2$UN_9+CN1O*dqFKMez2x@iWB{N3!=pR3!TB?mlbBtWa+n;w7hkUwmT`QGSbDk#VbP*msWIK%k-B18%@vY&vrsrVb(2YPA zx8HzrDP}l^T3prHfc}ZA9V?DDWkxFxTW5=tXbP?J10XJQ{CbJ&j}l8uwHyu?$S~yX zj0AHxx%Cq!bjAl6#|Xn=sf75}Gxs{ujUyXx5GlY)7J>~J9gX?s0WQKsJI*@f{{2N&lVFewE zHbj_lBPn&0HrW7= zByTKtVL``3Rb1ft?su6hvD@m}ZeOzL3ccuar8)?5T8S?hjjhdt6NQ}RDq24S_VXk- zOU!o!UiEa58&ZY{cDn_kiF=1F{vxIOFQZhVphIKk{$vRbHkY14VM4p(o^IXV z#+~>N6VF~~4L2Q{t!ri!^>PD~l6zbQ!?lM|Cd<3tfok)zA||}wlpyFHnH@}}VZM*u z`P?8=RJ-N=2wgsX-3N}F>~&m#Tw$hb+Z65kE--eSy_B9?=GcYzvIT@;5h_8Uq_?fsK1Ph<+@-%QtK+?0g?W>>G4$M) zJrIwit0VbqIE~OkKqZWunzQKqrs(Ll&D@bhrk6sJdY&%U541_I6ku%RJ$Sk4e#R^Vev(2#k*(EML7k3M8}ri$MJT!LCR1j zw#%EOsU#xZ-K~QW*IcU)HWojV3{e|ok6cFf0iOm0>RWw1)(0?Cf+LIJSdS+m{h1L% zVmICOM9x5$LW8SEW}SR?i*mye(wPaA*%kH@9um;{h&c`VF_u)-leaRAV4EhO?}w&! zXb%e_m(b?Xvtx-mzKe94kjCs=hgxK7Fx*(kbpy%*LOO8t z*k#P-72hYPK{Eh`l5g26W2kh|rya)E@UfOp`{uR)Qu2w_7rzW- zx>d4O*aUj~7oXJ0nW;=Z z>eJFxbb3&%r`8y3#j>8XvF=6I0-@UT_dY^G9`g`^DT6ux@8$BgRroDJO$;IRZ7B{l z2zpz>4NG!N*{by)Bv$&xDTxmxBd~7`wb1dghXKh}6MRl+zF+}ZOt>dYQ~RJ^j)6vs zNm20$Ca?{dgv+p|Fr8*c6eCBfhFV$B*a5);NI1PO$TGgH zM3<))GGeA%VtKvLalw8ct^M;oFfTNuNXjf@4*#pKzKdcq#)+!ai=d^uDw$%@0DxJS zmah7MBX=~OGTV)OT}KsNf@ZM!QTDjeuL>)2apl zm(366ZEAc+xR>wor{)y=mO$7trU?MAU{^T9U^t07LL>zMX(-JGH!dMlNLcBZ1<5_w zbRNt-crlLOCy03Kq{Aido^t3^e4VH@Iv&!!AkozIy@L-?<GhC&w*~=s@Mua^9;U=D zMR5v0ee>uU*21+jP0C4vEXC`G=6nd>L88&uG1OXTXfVD4og;%kb<~Ed3D8&(9%tI{ z{QM5$JQbCpJAkmRGgp1rR>u~|c=wEBB`*5t^rB;e$Vj7nvx;&1%6$|d`~zc|i;(cxco$SOF31udsF-_6yyYY2R+CrB*3#1Yp-CbfO7SKH zZ3`|J%i0YM!$_0ShZJ_?tBx-Z>PKFIu@+N$1zu^0R3~0FLBm@J*q6wi1S5|WbP4q8 zWFN$hR|j_FZ0mbZ{@l~~@DTQ!GO~I{wRgR4fZ+ShO@7MfWg`QH!3zY+(g;+zs(V`B zkOqaoQT!u^2IReHf<;2!RU-#=`zIGZ+LUXKSRDqFhd4Z#YT(w z8_K?y?K8d)7kz)#R4B(%$eZ#2Um3uf{T znWPeyhS#LfxWi2cp~bcNvMpspi?J}bnIKWviH1Kxg3If|Ss&^kNS)o3GRdc`w!2wl zh%;e&!OMZ`c|Gm@Fx0bEjk%_-i*h zoQC5u(QjqfwRXQLgrR5Cx z0g{9|N)2g&5tMSq41w@0NC@Js$r4Ptku{M}DVPfnumOXj+{A2}@jVOMPuReuMef4%XXO9(PgHfU9>;X_uC1rfCWd_|HSr`mZ~8FHR?(eHFage0b0v@53Hzn1WC&C zs{>2~blzg=VU8^^CWtuzPk%TZ=LWd3!PFTh!M_2Zw z)TC2KgHR>8G48?BRCK+3vN4!2R+c`H*qXgfgqa1x`-Gc#7}$3sd?%C& zX>qmLjW8*L2J%l8{$)yWa8GZqy0I6hB^E6ZD1c$3ZIy%mtC&v|8M1^)1IvE|_Z#>` zDwoB}Z2>frFw}C)+-=~Bke8O1ZzQs)r5mm8)!S(pG(0eKVjiSX$OR9wBpxZa1#8+x ztZ640(Shs(7ZY@a;F(@xzkPWATPzyJ`7+}I6(8MlX$>N|B6dK7{OurWB&OO@(G#Bz zFyFiDUr2z6=Z=P0b;@3qNPtlw?+yg6^(jL6Rin+5p)ATus*&a|JNGi3iCpOTlfQ;6PdDaV^aMI&GIx-Z($x?mDu?QuU*(YdSjoyeBjEKk1brz0nNR# zcVxJz28_AtKyk(lf6kiJT^lUR>C>_n@Y35ilpLhem>a~Ab@k^s4PV>Tc zWnc!Zwi{Q291|`&IcjO8fP0P7d+h#mysD~p8W0UXO+5Y_J*Mibs!+cY@6hH$I+l%9rg@Fbjo5Uy1VBq`O zE0`F$bb+A%ZhP!eG2@zTGMGE316~;(-g@mrBWv6|!d4w}Q45FEw#irqv55prSu7S|M_-jrRj0Syct1IV zFuBNDpe#;9LW@=(VhWdqW!zpCHA&= zw2QVb+uosjy3H)YqN1Y_6favCd|{MU(l-PvrU5U*RlY!HU&0m$-Dp(X?Offy~Vr}6_ z7<2bUH$8F++J(e$tEF@7#Y9j-sCtjSf(1DMsx;U($w3IHgkr|$+hdNdkuu@g9X_#l zkM`sY#ON_)C2Q}dUy7pSsyJvpIopOez?_GXbVnv4SMD!Gv@EEOzmk-qg z<|%2&MW}c#6VPrAak{A8&h#`;7zX%Fbcg3+|M5VH!<6BhzSMHsCuJ}plL`2dQxXn4f^_w}72BbY6!b&eBH z!}PZ_4s<$j#QPp;m6bNBez=N0Qoz&=uZZt!=9bG6d{0gng9Vu!_@pTFk=c8aY(~$~ zG#CPONv4qpPWbf0D8?(g^n;S;fA2l8Vh^pZbyRdh3S!#6S3phA)9Ql`(>HuxRiDwi zgPNGPd;q;*+34M1W_@96vruTxwQR10dX)mX6IRD+p@ilA8k#SH>EXh31Y!j+7|puz4z?|J@6{C{0vt9YCtg zPyYqu$xx)+Tv>NMYB*I|+Ix}1rZCDUUZG*_AjWgYA>Z!AT*WH@J%X&3_jnQMT9!DY zod&Fi?-U-l8`1P2fIdj`jvGbU1_|;P4j%Z?M8f0LlL2-+bjn~JqZBX_*~Yj9r^VDm zvce1PeE-uJU)9T{XD@Gu2oOG8w0&+Dq*I}p*`=u$<$GQ`C>`#zR*-HVvUj#R*}Fz% zK@6*M$!lk>l(vEboDC~z{WP`1fWg2YVZ)`3PKhiALhtF(cnuVlz@U71O29ER7ZUfh zSH?c$bQrxE;y8rnv|-S%6g7g!t%UA#B~qz%LLtfh12kO=kl{cEd*_33inhJH6ov-C zj@N_&)zCk%Jsnr1#|rKNW_%CO(WzXn(equCai=dTSzuEhfwqKh z708KoIIAzAFG#L;&?kd+aFsf+xt8}xVphWfVymEN{)Z_>Vxo~t8|~j0S(n$vweYw& zE5-6VnxitZ-3Yed8IXi&?x&y(oos>0HmV@eYM)TWirH~h2Tw=3-y2!?E^cAH`)h&j zMRv32iKxsOLNMZS$Yyv^QZfbi@}i+n&l1}citNs2hiO3SebSzhW*j3us?M8-MUf8* z$@jV%OfciHfPqWdazP37&P>uj2Mu9X@NNBkXbO*eB_Hi-1Lxt*5AF=kFpov3Julh_ zki|a883X<&0!?dn?=ip}IGkOn^e~DrKeBXFRb!fatg%y_2gj(6JDmATW4zpsQKToQ z-ySaUXmJe{D1C=}uB)m9YcnYq6AVOvH!m^`(UcC6XB?<{6j+(}RN>I6!BqfQEl4xw z1If3S8{w%pFFowu3VoTR`tc-W_zIblzcD)jh(t`RGUs+Oib2Zd4JV`x2Ig7u0%nS(G~7)vE^{) zoY4F`f7sLxqF*3Kpz8RBb3&`z)ze}jBzH}MCgD_;^2*o&Vbo+@(uhV(IXU9*7appzv$>G|an zT`u7=&xee7yP>mKr02I?!N{D*69*--;}6J{$d5iJm}vwr1F6{Www~4niz2&|y#buICmhRpt3~(| z0=?9yug`X;JcD0pr7qT3BnXXXMKM&~xA7e0-6-@P^q%M8hi{%x-$ zu6UNTUMo(9Cnq!;KKOKRyNLAAmH#Cw=_+c5=lS7k+t|9EMFP{r4b)Hk>$1ZMI#rbQ zq1!i&;5Vaijyb5bd9aUCUw90HMc{&rpv+lD(EhEn+K(pJ=`|+rjM)%v4>Zv~9>4#d zT+1@0SLzEz#hDC?CS6@>G5e-*9^W@7suamKKp7~42w%5gj{)WZegi#2bcD)FEvRSm4E67xr2lyJ&}0IPN`7z&PxYAjFjD~3S`CHf zB;7*C4q$r}E?0C$iI|!4uhVLVLbc7c5NAcQebiH`f~2s?}TR?RdZPoGJ> zmlRpM>q|vJ9XzIh@5?JMBn(5K=UVUs2|^xy5Fq#;!#DpoW8fc# z`$;D9zXtyK9Kx+=@81Myq#chtPJ2vEq^rag}%tY6y_# zI7@EveWhu?)MvVXcnIe%$y%G|gUGX8^Ok^UB@SaHjzfpaiZLeRS0JQ_p<2o{O~%qJ zm^ihvXa&*E%}y$+nH4tuBSvdn5TOhFYcL;3hT9>#U+?T|2J6u2V?VfVUGN}Lq#9?c zKL0A*W}cqDM7KZ!-{BrlHegZTsJ05M3!S_79&EjdyN}@gm0vzk1YCzMugBNLZoY?1 zb7q{GUCGi8X&dPO$0BQWdxw(5*eJ`d?|OCQ)xjh1DA%w5{e6Elmu``-NE35LZfK0n zkT>OAt(m6gsh>zU5JSI3(!=xpo*2tGOs-S4-(Q{Dggzosz^bnMsG_Z}Z$Kqwvw8D! z4$j?8)7e+w44u zCbth+FgS*9bi5vT=xMm$o3GB@e(%Ef2a)Lsi))(G6>m8Vg1~AJ6#{l;JyZ>ez;3G+ zuptL$o1PMxi$Bi)P*+fVMW{CbcAd5p49~=-n&#GsdvW|$IP~C8@+l8Wa;A5dySvGc zmTM^lNf8QB;H|zdtH2TrqYLu0Y~d9mFo{iO6guamw)eu58|cD*=azgO;g-r*nT$05 zaD}i?c^)Y`d0me2M7c{Va(V3k&`ul6?p8c+6Mgbg#fAQJ74?D2=k@P2hezi55KlcM>k46_po!e`g%+Z3hdk$j6iZ=23@dW~FS6b|5UTzE zA3tL-2-D&gS*9*Ui=<@Bm{GU1iF?~um2R{kNwSO?v`VIulrYmR(IRzIC>f@ zWXU#`>;^Mt#_xH~8Qu5i`}^nK>lS9tyq4$l@q8>QzKgjiu$!>Sh?AzAPSkrvx^T-1 zjl7{efD0dk3C1gNQgwQJ0DVGNbzh@BFcX~>*$7EYNkk_m#xEGmrO?3m<8)os<#;Kj z3*-S;8Jvd`SNcRn!s^CW$TX#E98j2Xk?pTT@l0N)j3=OEs>B+LN1n^yFF7)$!kc#6 zVv!;J+rgtNPG_q2b_{-o-bj5}+ zA4-WgFYDaG2Rt*f4b@P`5amg!pF%JIQAtR9!RD7?ZftL42Q7U7Z`u0Q^-@TlygnTuL@h*7FtiPGi z#|D%c__Mey>6)>cmZmW<;^;rQBXC3V;WTuw<*lw391J}+J~q~4{E%;DRbQ>*#hXH7 zb?i=4lDB>dg<%Ut-MT+m&h?mpG4`kZqR8&Xr?bewNKvn1IcvsSG36?TNiSc~wQv+6 zLXl90vU(Rp)3JxPq!1<fyR?%qyL%$|E*4;8!=!lKVso-e2E6YQ2V z!LFqQ%tO+U893CfrbM{)^c>cbA3L9*`_lI|+_-h9IaBooZBbr^-!$3>VXo`SJGv=#TcXgY>y%G16IQFym32$yh9#?qS zz6rbgh&d+7aN9B|HIyOfv8Ez_gD!Xk^Nht*893uNRzZ2r-^t4YJZf8k1u7cL_!OHu zE@BTpIAAYpG@^(U?&(e*Dto={8_Q`*GikVK9_sDY=2U^?(O3*?#Yia&^tQ<5m0Xy2 z#JVzi@1;)@)rfaFd`>B7o%w3WE?o-(%nh$Op9Y|5s-{vB{fgnfa`B*YFnmfm;O82K zd<^q4X2^Mt$mIk=;7`{aVC93^HExw0H?}}5^d<&B>y)0+T^=yd22k9bEx~eCVpkOH zgjhy^&IRQzPlwZ$yK7JM2DK_r>ZW!}6`X9UNz5EG=Q}bkpsiEr0j_gX9Y{p~&ptC( zb@+xNiz8LN(59=;2QRHITA>~qQD+y>a+%#1=~~9_;XvE9Ak?!$3@D<0u9_L;$4mHz zH6GYV!w}P_g1g+nON3z!Fs2|BIdezR<$R4+AtdnA{kzG6j!u~PCZMuiCG@Df-TPuP zJRY$JG4EXfD$kJy(#crmdQ!FItACb@OC#lN6JP*1HWH&rqJkE1m3A75;oMahW@_4{ z9Yz7)Yq^gRWx1R-xd_qjq(oEtB_5M7J8B?@Z;$mdlERu*iT&HXR34EorKImJT!ZQZ zh38{qL&*XegVBoF*FLhaI1Sgu z;;bP9vmTXGnsRTXJzN;AU@!$^_t5hK&*#!`9ykR2(pCEpjv`^~qJbf4z*q}&&^7=p z*!hYY6li!@ZRj|H@3rPIj_ z4@AEk2DZ3urv+iYb!4GwM-}e{vT(O~yxbjT9$KU|KzwLNr-_(o?8cXuo`njYQt@-1 z%LOkWx=x{K?5;j*myh!f+w=bc249C1ufKk8r1ek^c~eAnHd9rUdY@|lV@_VrQTeyx zuIloD>?4eqtyDQpa9|AQF=O+7$Wgwq#{xR^g7~k!j|xS{qa&uh`!SK2+Qjg@kFG5= zK3vuGaTnWZ)^rjvHWCa)asKYUO~*RxPU)yeuPml3dQGK!FpzUq=xy3t;0F`WApuFc z0WnjY?0%rKLsVEw*6(B&p}4@+Y-7TOP$MC68^YL3;X9c38D|hc6O8|0JC%SW&A$%R zB)ShzLyVoX$84YN=fw8P9*LzM9%Z!rI+je*C=CsyYnOl*85g z4B&4?#=$#5=$p7y3qqmN6{D$r)yv z@K7{a4XyZ9ZzjAnUMQBbBWmTXDo#e;M$C)!aZyL;jU5U%WCb@e3Vr1j|EC2v@+t@% zMoBm>#0&vIB=~J)XiyKMHt-Y2w$(%weuuL7^)wSMB~v}YF&tEfwi!@or>O6K#GtKH z*yt(!xneKMYhQp*D|myQLd$RLWnqj0_=*7BeQe`@BJ2rBt-uk}%X(`O5?88VCW=2m zGr#EBQJAR!!wbJLZLk~DL$!KSxddR3|M71)s^f9X+YjJ13^_55jP+u#0(DY3M(b8J zCo0*<Q@GvYaPO?-Z z=}P=twGlT}LyfCQ7A0+b;A{x4rm8I)knnXUH zX9)3Bnh_CBDjFkP;bCJ>>r*eX|z=v@C1rN9*JvIbm^vPj%Ng!6f z^PSCwPy8+ZUd=F4v)bEY>yM#uUo;Pko+yiM6bxXAoxHx`SncJhy2$xk2-r}_?`i1eM7qma&jQcj$&w>lidECZoiu!{p25+LHj;oq^8e(WzE~YfP zIAQe-zHSWc6nVhnyeW~mx-NO?-#=CE-^M8%LucfJ9z&y4>(?-0dZb{!L+9@5)qXz{NTfOmGg-LXrmK!o(BvGo{89~z25{eIuKKA% z_3XA`(QTTR4yxgguCj0PlF@*iZVex<>JQh4(1X!Fvhw-X~(HwzZ0!atpztj(SjvBgJ-oQ}|)u*z^J2-DS z$uGd=tPW0-!#}kplSvQeQ=gG>_JnGThEucvWETEelD9;uF6l=ZYcfl}`nk7$XBCjX zF+u6YraMF3NjhpZig$1l0x*joeSfBY1%iDAfeH%OvECV7M%WH9^?l8#r7f(3M{T38 zm&y_nE9TRVQtlWr9WkW#)@5|75q6?+58$IUB{|i-P1$(p{(3O@XfUSGs$48^@9%WE zfv$X5rs(QX{_7}LW2iCK+bC$Dv5aM;)tDi3hrz@=*9_Sk%%l!r--{eM`Qk9;4)@F$ zOZ3F0Bgbi1Eat9KI`&|biAda5eN5?r&M%cr3j{1;^GvIInJosU-4kTIYg`BHD@!8K z7p^v%eBn-9{f8y$7vuo6EuAj~oI6kgqDGe}w7Un6B9QA1QTvCF%HZQex9ZXfKy?9! z6O#|Ej6enR7sbRt>Py>6dp)KSa*ao7^y+u* zQL3V+for}@>S6J+&ht6%`)e~8q5QR><8v{UnJxiyw5dd5?nqOwSP?#UBf&FNiE>?q z9QO-x@*V0>P(y>j349{_Pk?eY*T)7_S7joOc;yonJ@Li=Sw(i#`E@`XK$C5J76uRv zxTLI_kuS1bDDD&{wLfsD8C@;H+ks-*Y^8=418KZ*cY7~Z!fYRYNLbcGUiT<;U}u*2tIW`p*K}mFfRISi5!?<^yO1hZ&J?S(5)kM zWvXVnw^{lz)|Z^Gfy?gsF?;}6W_svY#b+#R!|iSuxfu!wgB&?q77CJ25nSViJvxXn ziP+OdSN1a``egI2XvtncfRF>C!~905UTF_3R1V;qVA^a~GngN!#5Q?l9Y7NPSD!hH zVol^!0n2V;R0y_O#vHORSpx@CZcJ*1;@FWn#&b%$YQmiUJv2r~z3K5@ZHj+~0(=4b zfDi|V+&Kl*6N<;6v0pi6v%_KmnYwy@fd<$bhwk;*Xt2Mnc)jo;7mvL zRqE;%Fdb_(N^hYgilDmYY7$CDZiP;Ckbfm^#e=;ezrq z)??mp{8ne4P`G5}p)(o!aB%2;s{xW{3fh%C-+T6k(w}R<3cJ+OL z_6oDeL~vIPoGy6LaF&1=8y3XPz}%_OOIba-@NZIFL_Vy4uv-)&2J9ZufE>gZjp=T@ zHB8QXaF1E;8j9?;jCz?nz&B0hWC8nRO!qA@x!I3P?$`9QmWMPNz?kb^8B6J@K_aFu zL-7`p{bvYB0Gq$S+>5QQ61f^OOK>OxRb}rpd`tv=kSzz5;m$wxH)vV>=miE6rD`h}Lor=)i=>fy_P!y7Q&L7>CJOWpA%QtHW zMzdeXAcr?n-mt3%?74&-^7UYo?+hwAulMn2ySp@!oqo+x`>Q#&K^+7#w(W}13*u#w0H z32*YE40jvAG94iNE;16!1G<5R369YV4l|5p5WTYmJl@A!|7W!ky~6HpXHElQ+wf*D z*`SCd=FY@4z`7fXj|6i1hlTqbF;)t&7Z!&MP_l-FW|ux`=ACAC$XfNwLgU3YMvZIh zb4eZD&>(qwV3?6UdWQcK1uNMx@{G&dX+4hYe#J7xIxsrQzEz{G8@2{14RHt#eBRRr zcufUdaUZSY;em(;1U~>AUF+MK-YA_=Qr!!*DtxG7`pZAsX;OAd5!f^r0_7s>Asg2dVW`q)W#X{vB>6#x(8EF-2Dc!rT^J>v%2Qn?xl}2Q< z3fn$E8UR3{D7N=A+kL4}z8Ly^Ix1H?bD!}5#zeEUN1-1F?f zqj8Y$vgZ#&k3!-50zy|X)|O39PlBvk!s(@zMK5s*mN^3XvLgmLhW~OLdUu_rTCYN@ zhiogQ$%WHV5GR0C8D-vJC57tWa@0^AzH#@SFCXophb2YK8AZZJkwF_IkM^B1RKisy zCN#1|(E`dU#v~YNH4fdyMXnva>5)iwKDSiR*VnDDvH)ip5 zr{Jtqp`(4Q&@@j^6+@NYW-N?NZR>7U>~=}VRK8jSs+#(VyYn4Do0~yc0sIlHSu^_K za{sr45k=xJ4)-K|eWOsk0G^Jw2^j5{1QxBA3Db(z9gqDdNYav+-}!)8sKS6pWtWJS zzLVDoM$Uz3Czg$%BTuvg#7;rN>Pb~_LRuFNbad}I>1TTh>o4%d{R zpX-&OVrL#%oz;kv&HhkQ5LkqYUN$J5vms7l0pk;_(1mmu+1VSV)`79p`AtqRiBZy( zSHSE#%Fv%#%Hv{G!LdsHv%WsuJm{$gkSf^ieYZQ<#H)Wg9lye~izn|2)jl=^W^^&S zEW@7p>WfVPRFrxk_xVp5VN6b`jZuSr6U9@c2yn^9$WJxt2A$Hzsy3*SjIh>D8%>Z? z!q-bqnzwbkEK&0UbwOlbJp0CAH$O)_$kjYd_MoL8`e?+W{yV3ql|$NSu%U`|OTp8J zT<=KK9u{{`TVgcG2dt|S&ju>=20i{EAU!FU5>ydjDz0bX7PPvmXT|xP2$MSYPPyYC zciOWjZNs-+U9k2Q7=(XZ9Foy8iRMH&NK_P8;R)W=C5;ryT|s@%B`xUU+rL4U#ZsnE!_GMD^l638Bn7)|xf zrv}1gmF`u?()IH{pX!tl@LTb@eWlHpN1RXVMeQC%+!SA_g7^X2`Cl;`tixFuJ6#md6*H&UZG6h>Z{8o|?Q)}O6J@gVwC{KC^cqzTE9NYw z&JzU7kM$jbu$$XFy@KghvJXl3nE7*Q5)#B|7V63V8a^p=o>P(7W|DdwCNQ%hnessR za!<+iC#K+cceH>;c}VV{6Nc~gj!)+N)=n8Fr$OCAMDLRf#50CBzT|DM+fdcdXPdw> z82mZT6n_KZl%=A_#?skZwj?KEr`r+3*2a;_p>NI!W`Rs-V|O&Y^bO!h2cJD@bUt;T zysBr2fA8Sg8#%ojFFy;lOVnz2biW?pZ^X&#fAD0EL;A>?@ystaJG?sRCKB&3Uxu$v zXUc24jlmxLK>q-L^J_+f{meU;40r;nh03=kmb(pMoY5oG9`N~wbq)?E8-KbBIUs23 z<08L(pYPZc7F2AnU|0|g;*L{!ja1fK(Sq4t$cfVHl-) zRW&-kGs;@VbJRV|ui?AM&U7dkfpncF<^)QQHgnau*vy;NpxsgXxGEJb`7g$hFmuAZ zLcvz;BBFk0ER(|omv&HwVTh~>X4-I4J^C6LkRY~rOMQZ9lHO5?L!Ogy$dll{Ov+q` zUM?zb)ISYvtpP&=(0_p=mOkJ$#za9@JP)ZJ7Avv|yH~N)UHiJ*=<3bJKu(5)g=^=O zWxKL|Mo(JQj}T1GmB8dTPOW^I`u^;$(=3t;`WhY9=YSZ)zce}S8n9cc0I@cBR-ASF zc$iym<)Z7kKL{aXq6AXbI?5d*cIp1Y zW$L+)$VO5kuy%+E*GwEHBsrM+)EfL&aD49xX6A`eq!bExslvhm=+<|Ap79TNX_@i;QHf3PEm!Y+`g3rS<+v6x@W)$-3 zJZGMuze5@ew+3El9+F2&IsJf9A*pXjEfy-P&aV0f_D5FzNE&vVBcY;Ko_xW~p^4%S4`xQGfFsKZ1E_}J}N#em#WFp+1 zv~u?L-s&_T=-s@d?sQyK3)v`#>|BW?&Nf!Ptd4UC|`TL>0Y`;l41+d9ai zZF3nT3|fiI2OB_;jUBzJ*==}M8rFMYb0Y445qv1FK{u-hTt%tY(cV?lS;x$~AoK%~ z8OH}q=pZ;_KIgT<^U@@rwrt34foDw<0VjG!zwDa+Thmz1DxI@>O}f?!@I5QI{6B9W zd-^J|-l><7%h=Y`kO};&&`A_dfFiPzbyrf#`$Zf+_@`sGh`;QKeO9Cg9|G3`l{ojc za=_dRi4SGqmbTyWP^Vv3*37ud;^NwdzP|QDS3B?jIQKDW3$N{DHsx#s%lWtA^Nr_t zMh7hqFWuHE4O{7Z^NWPj?)wrNg?sP4J{DB4rOUq7Z~Z1uEm!Q|mHqQ)!99o_Wc5oQ zjt7AZ;Fxyl>GkPSG?qt0H%tVOJp?c!)#ddOsA7~^2zg*T1v&tzM~`O&eEDR zGu*7Yay#S+cia^0V1L-IIqT&22c8uwO)AVQFFh#!dvT(F?M4}&+g67P8?XnUxgn0E z-%%S)Uw1Ki56c*bnl9=dA18(im6xV|f~9?jhGw#gMe!035}#)z3d#4^vXkYtPGuyq zrQU=0N(Hx_Mn3W~k>l+tx9-rE!XTf~fj8=edT^D*SL);#bjhjt5a<*Bg%Ih18q8hp zx6Q%)EXWH5CM{HvkI~^C^5iO_Ww4DBRIr2hGC6RdL$LFSkW{-%Be{);&-+e5H1EwZhqNuHw@u;`>60gttA4%cGoB@+21H0(p_bJOF*%bNKWjdjN&9Rf!Mi z9~YDRd0LC8?5V_ zR>K5iJo=)KqBv)3D1>}ysi2kPDwKkO^&ubcU*@zFtgz7f>rdt-$$V`0Y0^$~?&OKu z(Q$kxJ}9*(tflpK_gC>uiX)XIzgYX98dBjF!vTtCtIte~!yUs)dWWaE1nQf6^vZaOxd1@_#I_lr3qS*yy1Uyee=)5i8NYM)r_-dx6V zW)6!R&2zFJ_4uWj?W$#P{;F(>b00XftAC$@|1fDht>VDCBHJ5K&aHiVOgsUn*A|9n zGrxjjJ5Snj|JOBY8r1$($}R&BR$x8f)vxbIBSuKo6s`QNwX=F|%?X~@xoPR8x>W`H z4c}jCSvWL>UM6q>%qkxW-}sZ3B~Hf#&}Ew;gvjmnme`aL0YeNSj(Bt9 zpL3fU!Kfe6jmj(BiXl#fEv%!14_MBxhG!h@KR#7|OAdp*`LktWv&mLhyD!~N84*!^ zyCqT&d`jA}_Hbbw%os3o#J`RxEBrr>JS1KLBY75;=BWB@>%Y4oS}of5`6Ijw!C)H% z3s}l(gu(c_i`}&>$l%1WcRHA}*m!*9B|(t$)wHu65)Yr5|0f5CplNT82CAc*VX-o+ zEWGGDxfx*Z`bHil3xv-&2YgRRYF!pU@niYovR=+1;U18P{RP=ehQ2ikxN!B-9P#&v zWU$~tZzHp@1vX}NV_GLzOY;=PWos^JTa4-5j!%n?A-pPi-ieCewqj!0_&{F)@R^=k zcXG;b8-Z6Vkz;yOHOI{Pmb{LSuFg526r0)N1`cCv^s}p^mONUY88?bpb(@-}$i_@( zmhLyThm_*I0nu@J=$vIwefRBxP;j}PgE2#wDDNAP1FPZz!vszs1aZ0xDx;U_W!40N zp*ZEuP+nX4zyMqTgCEo|A6giqsjo$TVg>PsKTOaOd7V?^7US=W`yGU`On zCS@gnjmXqPB1VyPlsRbvV@6_?LbHRMKK$Wm+50Qs2Cs#9n}2wqc>rrD)}y4rLKv%Q+WtJrZN&zEs^is}&l3hZ%6nQ^&i2D)%m!ZmpSAqe zGDWGb1+f%Cb}99z%j=GZe^EdTL6-X~md1#J0viE^5pakN9Q9RjGc00o3N1uX$bBA`yiHv(t~5}}Ub`52 ziEm0&TYaDLqqaJkV#`>Q>Hk6AEjtb)t!N*W<#Wlkq*fBl_4GHVq8f0cThWnqPe6r6 zwXlu~=J_gGEYWNl%ry-;ZExT4EzcE549MOH|7>gU+}1kAJI_~__P*c z0@Z(JHAW^g5E>f};3w)QE+ZZ`*S{k6`o>h}%NmeTd;TRvpP+ABnV(L-;9xVxqw%rU z&n@+;8c=Nh7(geZqkBgW)x8TIEUe?Ca|gvzn0-1Wdp$)#|9C8v16(iRj3HWi@*H=b zynkS}-J-a}jO}+t@9NBKA2Y3P5YzPtl4^}F7y11WUG^94b}{dq0qn~U^UK7Lkzc2? z7Sf(SE_g=bd8au}?#+*nN4q}WN9iwJ$2;wIJxf0S`StYXBxK~}sY+8JD2DI;`?;>? z;Ww3Wn}Y7fG*!>5%Nhqh3_1@H8HjL!3M0u*K!4QOZ;<8jiFS9sHLJ?D>ePyt` zPbqaCFIB8e)IxFukpg2PbKV;wU0?|3|)pNGSyl3cAIb(8PI_ zNgxoVYJLQXCUPYbi&B7%FlH%W?4zu5w8lZm5i9yF_vO=?FQ{@5r`o975g4umZ^j&2 z(P+n-bIFZ8AdPiDpc_diM#B7!mH;*LEdCyMjL`Y3|5Xih?X{z^fGm-RAJ8Vbh5S_- zlUZ709{(1LAQp=TL@qR{O>MiMfedbB@f&2Nk|>UPSgUb$gNr?$@K1zq&>H`5&gr1@ z;AgP?(9EllhR5O4P9hQE_tdotd*1C}yl@=)=$wskFTkK0jV?mv4gb?w9W|M_(f_yO zJG?gTV@^8mTb?d^RCT{aHjIM?WM0aVpY&!<&TfH3vBSq`#zD)ZYC+gV1k^R_6S{Kz znU?q0s3Us%;NY@V7m{*a=OhJ6_F3`h;LyhJNsCP?!^@*ci@& zZoBp@*7xJ?>nXLpGa4Id;&D(f3!WfhLC6X{Lcf=JEsKIhO={@rax&GO`nrd$`i#I? zoP-BqM(-M1PXDt9$9^_2mwZQ&{orGOmbYawVP0*3+Fn;0Cj6mcyc~jcKyfiwC~Y}eq*ZFOJeTE&6ib9IJEOT9kPABSL{Zy6 z?2}POmf_P-{H17V0}~B^Zw!>5XI+rxkJ`0qXpQq=>_BHFuxQXoL~H(G6c(+LhhP@; zW7z^Kt5EA%x^U^y^9K*#71od+yR|Uyj!;Ei`}%opr@yv<&jP7MUX$=KB`7d`N3pPG z^M?R$8+d-yxoJrhcd1uu1xk~dsJjfI8vfH*1+z%a{~ojoiwZt|*PUbj;%6WMV{rO}d-q-?Hhyq{6FAY*s!9<)olCa-ziZ&W()303 zZE+w!Q#lwUedZCChtImpmR|Fx4OHFo62I{w<*AJmLliPL-Gh{%Xp@!4WSb->e>p#V z`QJB)9a?H;@#tyv|17p&^Q!Yz_q^L_t5Dmd3E*Ii#UjDFy8jfyY*u7g_v;3BRQK5E z(NJtI0^eV1+_mJJXcXT`RW;)NOe_%q_6a%(o}yp3DF+ZG=6V~5WFSR((Xc-Vp}-^(Q{l>^<{X(k*AV zl;-<1aevd-cG_TNV>M!8h1Mg4-|hB9aDFH#io3}1X#@9B*pOuj9XeR3PtyjfYQ*+b zI5zxQJ56k#?Yq+umTTa*Xx7d0qj}edLdpQ@X54WrY#5iaz6bz^!__g!P)qx9K2!@d z#WUo=C~{mudFw&+!KgkbCK}4?dQ@1>4#V$g4KFH4X{QpU+m_NzwxO>C-HQlTe`(O$ zmowpa@1FZYkD!R)WZYL$J=CvwrG|dOof4-p{_fF;{9(CHQM_7EzWUR!T*rs>414^p zxn3DHak)cn&{1Y4A-|1G8lZ{5uy&Ujgs>&7O0M_nAxc28h!k?wI_Q(si0L9aVO&KV z2l$_=e@v+Gz$4C1C}BW@w*tdW-8m6V_f`j)$_Z7IWyoUGX_Q5XYl=bi_BNt3V=UCf z0!dJvM-!~;;2S?X#zmrZbr7qiGV^{@8C;7$i8-{IQAC@$P{Qy*zUgI2L^(jl4)?Q1 z)e$iJwPl&kzKI+TV@jU|4to$0bM6O(x_-jj?zr15v$nBEgvJ^ZT<(vVu^)$=66}nc zdM*qcc>DJVJ@FviiStvW5h;NAg79r3*@exwF~%<8S%`@)s@NyQ99cN*5g5m9HOATc z$e3p#&LUDZH%V`+Wa)d7(nWw-b$}8>^*fa;AMioG({gFpr$a=$bU)gDi ztl#Ah9PUVpBe|3U>=eS=kJg*l7lyr|rXK{8AM%%AoT?sm zn)uWiZd0ZGq0)~QgV4ch4m3kcul4dz)c59`%Cd3T8&})LEVl`};}9oUe~R+G)J`@S z1wj@=%z+NO7DA7XJfS5aB;a=Y#!fGWm)+L~nSN6(Zk=kRwKLnYWsI9y(jE7|N?A+M zXG-{ejQ&%J#Te1eGNA?58xbq>&rR}dYhcariier*?}x}gWTE78808&B@=UN?B4mTYYRG+nOFpkycyScb9OSOV zPT)57!Kb~X|;NEuvpo{LyE4%c9swKRq7YbvL0pZmU_H~%RV5LTdCnXWS~!{gWtic4NS6n>=pMvG;@nV6 zWN(MFdC$>B8e%8s|(FL%wVy2Uqg6iwnU&eB(@)+)I7&(36>lUBTLvD%(iyl9# zFgwkbbcTe719_mYW58w-KBZfD@p?o0>seoOhEsod`AfWYIXAZ{XnAEP`HkhZW9qO! z!k6?uvlaI`--oiylUDIk(EMG@y}7ljq3ZQE@AJGLGjek`P}==%p8{U zNZnZdm+-c~_}}eIC*MhbsYoYvCiw+v@|tsGfQuy{p|#iUw{88LRJVU>!l^Xxr?dqP z9~(O-EH$eu=(|npD?ZF@t`(U&-)32z+9(O&`*E5g^bolAVMmyNd0?EYVzE2`=JBc} zBz@0}p`lJ-sU2CEa?|7*oT#M$|2^k@^?b)NGJNPM3xm{G-R~Djlyu&9AyHHCw@e+n zOq=9TPWo1aTu!?}Zec>(OK2rE@Zfa!AbD61?-HV(J?OHZ{{8!S=iD|J6P|=>y6$II zvy0F+T1g~*744zqu_ytG@m#&n;*I?;MiDvyh`$&n;CH1H8MOdNWu0^#luT(cd%?<% zsx04E(JNQF4!F>P4huX^0w|M^B`c^bDDH5ZMQ~3^W^xW7m*@L~B@qT*f^cn&4?c~5 z2=u}@5>M6&s7?n7+ZYZCPBGXYOr$9Z@0&3Dp5iW%J>0;9pt&3iGi3fL0kVd+scq>L==Urxx#!Dp(#P*bdhcs@q^9|606x28O%cpTVN@*e z;7hGi6xS4|;nQJJCbv88ym7Pk!|nE`!BZn{9H^dW>Gw}x*L2a4bFe%d3TZed|HuO( z@}JY!eS=u|@uiMGzKZUmtwwfskdeR27rA@AM$4hhr8^Rmv<=ciMiz12%BVB6Mq2|K((R`6UcBeg&Z*9a-evT+yCDpR9{X4 zX=A?xPRid9#{M1+i=HbmJ@%R*q704uByfL?!?x7-kQ0dUa0&WtIUR+H)XP(G3DEfD zV_+tPjy{pisBDv%+B+pCo1(SVvNkW{<-UId{rz(U`7mqEqS{gh&V8hHmQ^tM&2_5~ zN#Yxtk(0~a>?;K(Y{i5cD$D(eRYE`mNxG9b$goq?WJY`jHW*_i(tFm=JJr*cRv_rALeK6e_FiwjF~Q3%!luvQgV4 z*iL>AR#Jq4v5s|Mdw-j(Rr!r)eHNI`EgB9Gi^TfeRumE+e?i?1nTaKJs!MQ`R>^xd z9P{*!9v*h1Q>v90MMxoyz^)?7XR=0DY8j2|}$;+ba>}|_tgp4ASFy)o5 zmisE?$SG1+wAhp_!UtNHaP{sOZFp&NfHEvuWg_Ba#O{{}H~pXKFXRnz{|QBoJpJB_ zs$j#(e^w_UEwU~3b-KfqAAEzJFY5PgOqd%qXXA+Tz1^ateg3rO97&l(`&iAwT}sbvyHL;ADo}h zirIJf=jc9q_J-jVq#9@6Lix@}J;W@3QWc84|3*rei#4I_oRWU~XV_j&d7K52xx9yS zHh!+g}-7oyxtxqREVCnd0od8RJaL4 zXs_L4o-t4Sk+k-LrPylX0)=Gn`zu?`Jtdl63Yryf8k->2+dC+lBa1grY(o2%~~xDs8K%4;it0xzn*MJaAW)Ev+@U@*ZU{HQpxm?_!Qw zU0)USg^8txP@-ZQBO$AHt4Zn{Q>`}WAO*~P34#!y4jP7;(s zZQA#8Org7U*?Sa5k!u}DXf!Vn>{k$P2!6yM7ye6PA>;k`?@G)1v8blK`AQ+1!`nL5 z$Tp}3Q?reU(88-y9lfgoJst0XCcsY;0HZG&QV0qsd|oMgLr{MCyUVBJ0{5c0Z2g!O z#y$ie!Z^ZrkAupWrqnZ!AH%>8s<@IUoB>=Ev*c;n!l)2wgfm>wSp@FQt_U3v9KwmE z0)oszF5+FVuv4k2KBt`Tqr6Jo#uWho6&rbLAkh51->S>P-yB9#nDE;Gsh8iUHyP~U zo^LaFso*7URo6=6Wg=@ZeU-|3lByKsl~6!Up78cuiDCGQ=h_TY8uYuXkT*>2;jO+O ztWL@nn%V~2B&jE~I8*auBY<8VN6|ihpmKfglb)*6o%_z`@TmpocKiNL0LI)u(Gb{W zdv5Q8#^>)m6I(`L)UnpF7dl_Fe)@Rp62(#&Jt{LU&;fL$(*s8%PB~~r9*<}6Qm~1_ zio1oPxKOwYF49TR8E_;bI%SG%pFn2*EtM%MUp8x}BMJR{PSH58 zDI)|jnqR@+I^WMv2c(+{mUyVK=&hqufusy5Gvtgav+8a*5DqVd*hWY_inPe_6J*H< z_gBm&RkepQ;T{|dB-V!!BO6eq$fsBCJ9q)}u9-eFH6s;uJ;7Z0|G@0@P~NuBINWqh z4Rz{?LIa)(tWir~ADDlkFMG@kUr9KNniQFY!f~27bdLIrA7TLGyMtZ=Cj-oqC+fPI z_kVz3t7%3eI5Id8Qij+AgO>ud*g3uegAa&(E}z6nm+&EYL1jVcC9t+P%vnQuKn9jG z4j^c>DqDeRyK@Q{j10`;;TnGpyBNFR^;F!AeN+x}$R^zpaR9;`LRpPohYCy>2T+li}Q5^(?ivoYpILxzTG>RvPG3wQ1tYMQ>hTaDg8aC;Kx$m zE25o3TgHea&Uee0-is#-Zz{f2W!>!6D>eH0?ZDRW`;Sdgu^R3T62>(BXNR z%(jm>{7Y$hnRh$gLif^-`lOq>tmKL8s|R@ z-@$qAIV|Opxz46Cy?=e3-8^4jq5YlzXp32{(08Nf6AJ5?#0=A{?HM4@;OD|(hO$WwlZo1)%}(9&4avK?;h1`m7O=@>+a4qn~j>px|0WuIO5A*<iTQH zFzYvDeeI?-x3Fw|RLsq99|18?|8Vd$9o4u~fUr#cu03Q-GqF&aiV*m}v&=jLp<#o* znt2U97mV`)lGz=SAZ{VJieU_bCFrt_nlZ;G2Y7d=>-_l=RinX1D3m!pxG&AZE6(X) zS1@(rv}wr$+%Zz25sZlp#<{Fg2062?lr$+wF*o$m@#X)Ftn`r207tRm>cdGRLP)HWDD52_oYVVlz-||3N~&H)I|ou3%dE)CtV#E# z*+?*#XfNp<%H^jI55NzY<7d*Ci5Mn=nq(|GY0D_`EFvGo95}9Pc66%R7=iraxOwG2 zeSSj|hkY?^$_kd3nXWqoizYz|0BZX~D)uyBjUp#T{vs;E2kx^+4xeKEFEj=oQ?Wu- zJ@i#kHifIeExCHbDDvnM@V?zbmmy&Z2(ovOf)2>8tgy`Nn%9*cS6lhfV4h!kqI}1b zeCv?%9c~vD|I`u&&ppE_i_SW|yqE`0yBo%3?%8n3aD(Tgwqw3#|1zRipO&xj6xX(g z+^(26inO)&)yH5tR)tLmSkV5FzjhQoYImMlv1sH>;}sftGk=i!C4S$d`yo#+)KDai zg9r8fX=OA~`vHu_gXyWAZ}&!A%jj^PT4{6MM0~Vn6=2=t!oHeaq5aDbnLEFBwP>m0 zqV_1Vd&K)INhW7-VubJeX*vplvzl;K!40Y)X6E^uBeUCMY%-~)r%U?06d%gX<>!(y*yej*d&dtTUqapq}~5ib9`yh{BPAoX64M+S6(@7E1HsG^UCLVA*)g0 z9FlQ3xZIOEr5$A7H~Y_gcU^2Fyb)Ks-z=$SOGI;inWDvNq_;^Ck-T1;d6iZF_8v$d z;OOUPBGVHVzvT@HX;m@EQYhtnMYWsVn-(w=kYJ{^*q7|qTX3pirZD?O;IbE&R*%aS zul9WEdRzXuWW?mLwu7yLk=^sk8oDaae?Md#%^$J+j6_7a-5fr;q_T~BJi(~_1}j#9cJEX;Qwr32!r#|f4zm4QmMeneNAAe%Y(|l< z{Vzoy2G8*xGyksf>f!2^|9EgQtJOsBu~6nd*Us)6wdKz3FEz`81_iXGkDr;kT-pD^ zmkXQKGrOg|YPCX;4amfrr(E*oh(*V@Ru@IsC9SqLvW+m!QPk!4Yev?g^z}&r~G-qY6(Z!d~R)**P6d&g`83v6a{-z4E zA+N0N%q}={s#xSlYnOj#Gp{i-8fl(89gh&UC-=bxtWjFu8%63+T8&_9TuUF07;}>>o|vI#zBFnEE#MVZ|wi-$}i z;+9oOx{(&jwm&NR_cy2t+~p%0ONAvNVMhhr{>mbNfE4mQQGg4#rqT}gs&is;K#GT} zv0|c5L+E@Ga@oR|=7l$?S zcDiiFS$@u%ji>g6@H!(n@&mq4y9xybadS%N+%r6}(z4sKYi`$#eOG9Xwa4?XHONb# z?=p&TxZ`X2#b^evh(q{x{~$S9w)kq*p6sL@nXfs6-}WoYMa(-8omtqrXm?NIiQTik zdU8&0@~@e5V}FQznm`2HlkJ}5;ov~#>u8q|2QYggnWpHYMj-aGH-8>|Ec`eZ+2Tu%Pf86Fbve;e9Z&`WX^TZaxUp`{J+}j z-wowniy0CN!XI&tl>UJ>I(fN~HnZ?Zh>S_;vmgSb@NN0u{u77S&a-p<5q8?IuH#8Z zAwybJ%W@8Zg$#@Ad+C#eYg=t=?`Mv@z6^o@Prup$!cZbB-=kn|&+UZ!D`zk2W&aGl zHM@52*}GdL^FPe38=M$jQn47I!ZC(P(0%mEQckCrVit$o6QcP400-DUs_*9CtOJ?v z9-RA^PKpM+36^I9<io7`rL|O9K-8_6SwHT52Q!D8n^OJP=m|f7MYvK5V+r_?oR>>+7W@iGJ%A?VCQV4jLS|mfW})SYl-HLuTP+&22HTF zv>c&{@!5EudH;YditdCSymy8R_rYKLpqxW-)-eAkJNB@g3P3-~j}Ghe^+wH1vbGkjFoGAo{@m(|VTi_9AKa(g)CvcPezw}E9iij3=cEs*3Pvap`R^=+v$N0GuE@GV!el~!&=y+bcW zw-Xw6(K_mu!}0ga(v0~^(G$mPA~$$u#ouIFb$V6-S?#2p*2s>`GQQO1wr%BxK3IWZ zd~qQ{Hqf8_RcvKW5qAKlz4_sbN1qS$38 zzGUBryh&Af7H}lsXJ22Erc%$Z0?zs@>4*nG$tr3GEXj6lJ;PO^Sc373wGe4h{qGll z7_X-0uMC0D@$c3;p^%gdUenw-S5Ycc3rSjJSVi*xkl??PCTEIbkl{@Y%X4P(8r_a` zo?|3^>~k}DXM16F)0S2k8O(i8X8<#@7qHN$MUr}c7wqOi;jL1ofQzF%%;s-08^5 zG^XAUs-d_uo(9+XT&iCGn0LM83D8y^*6w89+Q$3`z9Gd1_%C6_Vrc~BM-l{(xZ0N~ zqWb}K-iS?Em%8K8y3+!SsR!rd1D)Amz=nGLXfBPDGZ=R+E72bil+q8mhpKAsB(QV{;91=rH-gbs%Q-{QP)N_s&82y@Su( zC1>{E*55Z?DoUmDZk_Qr(^N{UkapnGV*WF4u(W6K z{b(j&Kk8zdp@KTNsKy|M>^v}eN2qJNzJSNM=s#sIF2qIy31+(AkVCozFyl0psJ(|$ zovocVWr}1zx6Jxr#EZp##y)f7{Y%PI3m|kCk_FT=O88GPs-HU^q%lU+uEEvF+(w1O zM5aR92?noNvWz4Bn0UFT`n8`RX8M7cs+qom&h?VkJ-&^NBGt3{^6F#m@T%}a$WL)v6^op26aJPTL|9^hP{&;zSZ`9Ybfip%HC4zLVeNv zoLTxN`BTW0i_GfxDhHW8T(W>R$>;I$;Md<;P9CO(q_uAv&wr9H7zj!0&#tRumLB@z z<}EPKq52R_SXxMH`1HHbF%4%GJ{qJK=h4DsaW5F?gVq?( z83qe4)oIajiVEb0zLcDa*iV}lHUv{o&Fm+8FYDV@KZncuS4xnE>Mr4`=&dt`v-ia69!E9S5^VGZ4NR*N%?mdITS;Ib zVyjo*6E?`zxVozmcLu^b0_62k8^Y{MbOA_rP)2wVB%W}&hO0MDpBBVr<0mng@M7d= zbiA*L>=mLO6O*HlUizd)#4R2P*QPZA&I180PH;#qL_PCsVVM#UJ#Lg zbg)eUH))z0+o-=?nOjdHnLbfJ9jOoocj}(}@nXJOpIB#AU!Pwe^L6SRn)y>&%M3gD zFtvB(t$|(P|6=*fV2XYfb#VCYpQM7jXfg$1EApXHsNgixH8QU_%L_P73LC-<*xtb+ zYKVA9cF+-3mr*=qNX6frWmVaEQ21+1eUhYhgZw)FPo^jd8BVJX5M;TFy3sodHF~0K z4p(`!Iovw)z_Mc{83!*`&%Mq&HYoMYl4gw@dy$_nO7DjL#X?hXPh#~<`o&`5n48f5 zN7kFiL%F~I`}g_%@qU~h?;h2d`+mKy>v~?##oynp2E;LFgqqC7 zRXVKAmF;b%l4Mn>t&Q~BUr6CM!;ma10`uJr*?ern>he1g*hC3>9p*1NR~0>1O! z#mnoq+R$G^)9o&iuRh@zS#wYu^X}VDKoNuKrFEe)x?f?6a+1&>Lt{8~X5iiS z2l&UMu)E1n1bd{958foD6Jjg+c8^gS_J37qzJ`y;mw^&#sv+x}RKo@01fk(lFmh?| zdo9`m%Q}v**K)>Kz~$TF!6>?o#-YONfY20nrX*LRC++5(a2Izd-Y%9Hu9~JS`cvvE zq}*0U2ZF#XtmL(`k0l=dTYNXUl63eS>;AN*Q4BK@4W+1p zJf*$;#JhYToI>(~Byr;mZEu zZXYsjK5g!c5G-VVjRAGF+TOB8o(pB@AnF2bE7&vmCUxJ7HB7>B|tVQr^_~!*U;GL~)hG*$Tx-B8GZIQ=yqd*Z_kQ8or|HY;KIg*fL-QI#?eH`te0zI zmcSK#YUh41(n|p=7l>Na`0BD51yB={&$LIAIz$v=Y@FTsE&bpfpFC{DhF#iBTkL(D zIk@QBt(AmA+B&0InhMYnLgxhO0~cWXxfb1=DxK*6Hc6o<(cR#0;zHzG(8bl%u zteZ7U`t?h-*?%(Cu>>m1jur#04yOOW?c1!|f)J>{jSVu96sY^8)^CQUYRmPOM5`T- zvcY0t3!H~^Gxg^fH^P=82E8urs_oxJzhotW1(wvGl~(ijIy?5)2r0*(V7Jz9Vwm0{ zC9649wda|&j3hL^bDN5$-RZ!`2^9T8DGvh(QIzqqB}NlgAOO1AU&* za4d!gZ+#v5la%Re31i^TfQ8CA%o5exs-VLs>D7~ekJft|4iJTld^862>?A(rso0J@ zc+_j{7{I5T==}=s@Q{0#rz}v+W(y8P@%V+jNv&<)pI9h<7>nGSS!qx;sh75`VG)Ni zEUXcbqil)4;q>%M1EcehKVsetH)lyw+cHnVZ=VMi zHV&2T575)z@#qp2YGZjS^H`8l(>%uK!-W{f(Bd6LDrkY}U0yl~Bp ze?$-Z=abHIcF{Q*!l$Qyh|?(+H2h5IW*gE06vEUUIE8y*<7}xCH#{uYT zTwsIS)*8nc&N_CJeA2^KXRqSiluN?Ts^i*ZQ2lVAgMzp$mYrS(YO8eo0vdoP!BXRT zO;x2jf@wX^a-3E&N`Wb?g{2PE764>hj@jxY1AdBG5d|g>5E=-+BG}QlgaE;9F%>0; z=qM=eN-LvMD5XjP?Ib%fSi$xh>Y&H-r1N18kBttA?qh$cIQYHpi&`-{UC>=z#HhSsK7*vdl3K_uGeqnIk z

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

K`4u*Z^Oz~g!J4G#oW)>s-625DD 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 literal 0 HcmV?d00001 diff --git a/assets/ikostan_logo.jpg.import b/assets/ikostan_logo.jpg.import new file mode 100644 index 00000000..a231f3b3 --- /dev/null +++ b/assets/ikostan_logo.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b2ti7wqvn4apd" +path="res://.godot/imported/ikostan_logo.jpg-a946f4d1402ce4b446871347ed0d40a5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ikostan_logo.jpg" +dest_files=["res://.godot/imported/ikostan_logo.jpg-a946f4d1402ce4b446871347ed0d40a5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/ikostan_logo_bg_removed.png b/assets/ikostan_logo_bg_removed.png new file mode 100644 index 0000000000000000000000000000000000000000..e9e0c53efb67989585cb446a059befc88146b7af GIT binary patch literal 81217 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 literal 0 HcmV?d00001 diff --git a/assets/ikostan_logo_bg_removed.png.import b/assets/ikostan_logo_bg_removed.png.import new file mode 100644 index 00000000..904f24b7 --- /dev/null +++ b/assets/ikostan_logo_bg_removed.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7jpd8lq6kokg" +path="res://.godot/imported/ikostan_logo_bg_removed.png-ec2a705d4cc66e2dca57040f0f45ffef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ikostan_logo_bg_removed.png" +dest_files=["res://.godot/imported/ikostan_logo_bg_removed.png-ec2a705d4cc66e2dca57040f0f45ffef.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/logo_large_monochrome_light.svg b/assets/logo_large_monochrome_light.svg new file mode 100644 index 00000000..b4b6258e --- /dev/null +++ b/assets/logo_large_monochrome_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/logo_large_monochrome_light.svg.import b/assets/logo_large_monochrome_light.svg.import new file mode 100644 index 00000000..398db69e --- /dev/null +++ b/assets/logo_large_monochrome_light.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bfh57t5b6qudy" +path="res://.godot/imported/logo_large_monochrome_light.svg-9ee2e492857843b63d1cd337f7e9c284.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/logo_large_monochrome_light.svg" +dest_files=["res://.godot/imported/logo_large_monochrome_light.svg-9ee2e492857843b63d1cd337f7e9c284.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/assets/logo_vertical_monochrome_light.png b/assets/logo_vertical_monochrome_light.png new file mode 100644 index 0000000000000000000000000000000000000000..a51e208ac48a8fee4a59708d991720007f03c928 GIT binary patch literal 28491 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 Date: Wed, 4 Mar 2026 23:58:18 -0800 Subject: [PATCH 04/33] Update custom_shell.html --- custom_shell.html | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index 0d8c9282..ec6a579e 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -48,7 +48,7 @@ left: 0; width: 100%; height: 100%; - background-color: black; + background-color: #2e2e2e; display: flex; flex-direction: column; align-items: center; @@ -56,8 +56,8 @@ z-index: 20; } #loading img { - max-width: 50%; - max-height: 50%; + max-width: 80%; + max-height: 80%; } #progress-bar { width: 50%; @@ -69,11 +69,12 @@ #progress { width: 0%; height: 100%; - background-color: #0f0; + background-color: black; } #status { - color: white; + color: black; margin-top: 10px; + font-size: 40px; } /* Retry button style (visible override) */ #retry-button { From 691e7b25164ebd73df8b83f1d8c278c5eec4d7ed Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 00:01:50 -0800 Subject: [PATCH 05/33] Update custom_shell.html --- custom_shell.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_shell.html b/custom_shell.html index ec6a579e..b9f2496f 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -61,7 +61,7 @@ } #progress-bar { width: 50%; - height: 20px; + height: 40px; background-color: #333; margin-top: 20px; border: 1px solid #555; From bd1bd82b6d56a9a86912bffbc8159f604b21cba4 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 00:08:57 -0800 Subject: [PATCH 06/33] Update custom_shell.html --- custom_shell.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index b9f2496f..6c6df8b3 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -56,12 +56,12 @@ z-index: 20; } #loading img { - max-width: 80%; - max-height: 80%; + max-width: 50%; + max-height: 50%; } #progress-bar { width: 50%; - height: 40px; + height: 30px; background-color: #333; margin-top: 20px; border: 1px solid #555; @@ -74,7 +74,7 @@ #status { color: black; margin-top: 10px; - font-size: 40px; + font-size: 30px; } /* Retry button style (visible override) */ #retry-button { From 482c8746c07126857d906867550d7451ac56362e Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 18:22:05 -0800 Subject: [PATCH 07/33] Refine loading UI and export settings Adjust loading screen visuals in custom_shell.html: set background to #3d3d3d, increase loading image max size to 60%, reduce progress bar top margin to 10px, and raise status font-size to 40px. Clear include_filter in export_presets.cfg (was "assets/*") to avoid a restrictive export filter. Update project.godot boot_splash/bg_color to Color(0.23921569...) to match the updated shell background. --- custom_shell.html | 10 +++++----- export_presets.cfg | 2 +- project.godot | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index 6c6df8b3..b14ee0a7 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -48,7 +48,7 @@ left: 0; width: 100%; height: 100%; - background-color: #2e2e2e; + background-color: #3d3d3d; display: flex; flex-direction: column; align-items: center; @@ -56,14 +56,14 @@ z-index: 20; } #loading img { - max-width: 50%; - max-height: 50%; + max-width: 60%; + max-height: 60%; } #progress-bar { width: 50%; height: 30px; background-color: #333; - margin-top: 20px; + margin-top: 10px; border: 1px solid #555; } #progress { @@ -74,7 +74,7 @@ #status { color: black; margin-top: 10px; - font-size: 30px; + font-size: 40px; } /* Retry button style (visible override) */ #retry-button { diff --git a/export_presets.cfg b/export_presets.cfg index daf75a1c..a3cd65ca 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -7,7 +7,7 @@ advanced_options=true dedicated_server=false custom_features="" export_filter="all_resources" -include_filter="assets/*" +include_filter="" exclude_filter="" export_path="export/web/index.html" patches=PackedStringArray() diff --git a/project.godot b/project.godot index 25dd2424..bf5ec404 100644 --- a/project.godot +++ b/project.godot @@ -14,7 +14,7 @@ config/name="SkyLockAssault" config/description="Combat top-down airplane game with fuel management, multiple weapons, multi-level, and adjustable difficulty. Made with Godot." run/main_scene="uid://brpckgp7j86jp" config/features=PackedStringArray("4.5", "GL Compatibility") -boot_splash/bg_color=Color(0.18000486, 0.18000486, 0.18000486, 1) +boot_splash/bg_color=Color(0.23921569, 0.23921569, 0.23921569, 1) boot_splash/image="uid://b7jpd8lq6kokg" config/icon="res://icon.svg" From ff47fb8543a184ede0cd9c0b2fdabb8c18820cca Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 18:33:18 -0800 Subject: [PATCH 08/33] [DOCUMENTATION] Milestone #12 README.md update #317 Perform a comprehensive review of Milestone 10 upon its completion, and update the project's README.md file to reflect the delivered content. This ensures the documentation accurately captures the progress in this Godot 4.5 learning project on Windows 10 64-bit, highlighting new features, refactors, and improvements for better readability and onboarding. --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 001cbeae..f605d75f 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ You can play this game on [Itch.io](https://ikostan.itch.io/sky-lock-assault) 7. [Signing Setup for GitHub Desktop](/files/docs/Signing_Setup_GitHub_Desktop.md) 8. BOTS: - [Dependabot](https://docs.github.com/en/code-security/dependabot) + - [Coderabbitai](https://github.com/coderabbitai) - [Snyk](https://docs.snyk.io/) - [Sourcery AI](https://docs.sourcery.ai/) - [CodeRabbit AI](https://github.com/coderabbitai) @@ -207,6 +208,27 @@ these GPL requirements, a separate license is available upon request. - Version tagging in CI/CD – Issue #285. - Dynamic speed bar color changes (partially merged in PR #275/#288, but full threshold logic ongoing) – Issue #286. + - Improve input mappings with conflict handling and unbound warnings: + - Conflict detection + confirmation dialog when assigning already-used inputs. + - Per-device tracking, last-used device persistence, and device-aware remap prompts. + - HUD warnings for unbound critical controls during gameplay. + - Support opening key-mapping menu directly from other menus. + - Expanded tests for input remap and settings behaviors. + - Ensure menu navigation bindings & legacy input migration: + - Guaranteed binding of core navigation actions (ui_accept, ui_up, etc.). + - Initial focus management for gameplay/options menus and restored focus flows. + - Improved keyboard/gamepad input label generation and legacy config migration. + - Updated default gamepad throttle mappings to match expectations. + - Expanded test coverage around menu navigation and input handling. + - Enable keyboard & d-pad navigation for audio settings and key mappings: + - Full keyboard + gamepad navigation support for audio settings. + - Focus highlighting on volume rows and unified accept action for slider/toggle. + - Better modifier key handling (Ctrl/Shift/Alt/Meta) in remapping UI. + - Refined conflict handling in key remapping logic and focus restoration + from audio → main menu. + - CI/tooling version bumps and asset import config additions. + +--- - **Planned (Milestone 9: Expansions and Polish)**: - Mobile exports (Android/iOS) with touch controls and From c13d3761342edf1f016ed10eb684b4057baf837a Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 18:34:18 -0800 Subject: [PATCH 09/33] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f605d75f..cbf8ba25 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,8 @@ these GPL requirements, a separate license is available upon request. but full threshold logic ongoing) – Issue #286. - Improve input mappings with conflict handling and unbound warnings: - Conflict detection + confirmation dialog when assigning already-used inputs. - - Per-device tracking, last-used device persistence, and device-aware remap prompts. + - Per-device tracking, last-used device persistence, and device-aware + remap prompts. - HUD warnings for unbound critical controls during gameplay. - Support opening key-mapping menu directly from other menus. - Expanded tests for input remap and settings behaviors. From db52c1003c714b1b83acfb334931ab38861284a1 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 19:14:40 -0800 Subject: [PATCH 10/33] Update README.md --- README.md | 54 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index cbf8ba25..a720c530 100644 --- a/README.md +++ b/README.md @@ -231,25 +231,47 @@ these GPL requirements, a separate license is available upon request. --- -- **Planned (Milestone 9: Expansions and Polish)**: - - Mobile exports (Android/iOS) with touch controls and - optimizations – Issues #35, #41, #43. - - Multiplayer (co-op/competitive) using Godot's High-Level Multiplayer API, - with security/testing – Issues #34, #36, #42. - - AI enemies with pathfinding (NavigationServer) and behavior - trees – Issues #40, #44. - - Refactor fuel/speed dictionaries to dedicated StatManager class – Issue #276. - - Add signals for fuel, speed, and weapons in player.gd – Issues #278, #279, #280. - - Convert hard-coded fuel elements to Godot Resources – Issue #281. - - Multi-level progression with scenes – Issue #21. - - Optimize performance (e.g., web-specific) – Issues #27, #37. - - Asset management/polish, bug fixes, feedback - guides – Issues #29, #31, #33, #38, #86, #90. - - Audio enhancements (e.g., refactor duplicated SFX volume logic) – Issue #267. - - Particle effects for explosions/weapons. +## Milestones + +## Input & Navigation Improvements (Milestone 12) + +Milestone 12 focused on making the game more navigable and responsive +to user input devices: + +### Input Remapping +- Conflict detection dialog when assigning existing bindings +- Per-device last input selection persists between sessions +- Critical control warnings if actions are unbound +- Remap menu accessible from all relevant UI paths + +### Menu Navigation +- Keyboard + gamepad (D-Pad) support for all menu flows +- Guaranteed core navigation actions remain bound +- Focus restoration when leaving submenus (Audio → Options → Main) +- Modifier key respect (Ctrl/Shift/Alt/Meta) in remapping UI + +### Audio Settings Controls +- Use keyboard/gamepad accept action for sliders and toggles +- Focus highlighting for better visual feedback +- Unified UI interactions without relying on the mouse + +### Godot Resource Migration +- Replaced hard-coded globals with a `GameSettingsResource` +- Easier inspector-based editing and persistence +- Safer loading with fallback on corrupted configs + +### Known Limitations + +* Some complex menu flows may still rely on mouse until additional + focus neighbors are defined. +* Modifier-aware remapping requires explicit key+modifier press for + unique bindings. + Track progress via [Milestones](https://github.com/ikostan/SkyLockAssault/milestones). +--- + ### Known Issues - Harmless console warning on desktop fullscreen From 8058b1894a9e6c2f529afd6f08e11533499d8a7b Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 19:16:49 -0800 Subject: [PATCH 11/33] suggestion: A fixed 40px font size for the status text may cause layout issues on smaller screens. Using a fixed 40px font size for #status can cause the loading text to overflow or look cramped on smaller viewports. Consider using responsive units (e.g., rem, vw, clamp) or constraining the text container width to keep the layout usable across screen sizes. --- custom_shell.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_shell.html b/custom_shell.html index b14ee0a7..cbb211aa 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -74,7 +74,7 @@ #status { color: black; margin-top: 10px; - font-size: 40px; + font-size: clamp(1.5rem, 4vw, 2.5rem); } /* Retry button style (visible override) */ #retry-button { From bf6480d536d8ea2d5b592ac52b9ec6214a286969 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 19:17:40 -0800 Subject: [PATCH 12/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a720c530..5bdf4a62 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ You can play this game on [Itch.io](https://ikostan.itch.io/sky-lock-assault) 7. [Signing Setup for GitHub Desktop](/files/docs/Signing_Setup_GitHub_Desktop.md) 8. BOTS: - [Dependabot](https://docs.github.com/en/code-security/dependabot) - - [Coderabbitai](https://github.com/coderabbitai) + - [Coderabbit AI](https://github.com/coderabbitai) - [Snyk](https://docs.snyk.io/) - [Sourcery AI](https://docs.sourcery.ai/) - [CodeRabbit AI](https://github.com/coderabbitai) From 54e0448447c73204c3a11a0ff3c1812771119af7 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 20:11:19 -0800 Subject: [PATCH 13/33] Add splash screen and threaded loader Add a new SplashScreen scene (Control) with logo, ProgressBar and Label, plus a splash_screen.gd script that performs threaded resource loading using ResourceLoader.load_threaded_request. The script smooths progress, enforces a minimum display time (longer on Web), handles load failures with a fallback path, and transitions to the loaded scene when ready. Update project.godot to set the new splash scene as the main_scene and include the script UID file. --- project.godot | 2 +- scenes/splash_screen.tscn | 70 ++++++++++++++++++++ scripts/splash_screen.gd | 122 +++++++++++++++++++++++++++++++++++ scripts/splash_screen.gd.uid | 1 + 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 scenes/splash_screen.tscn create mode 100644 scripts/splash_screen.gd create mode 100644 scripts/splash_screen.gd.uid diff --git a/project.godot b/project.godot index bf5ec404..97a410e1 100644 --- a/project.godot +++ b/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="SkyLockAssault" config/description="Combat top-down airplane game with fuel management, multiple weapons, multi-level, and adjustable difficulty. Made with Godot." -run/main_scene="uid://brpckgp7j86jp" +run/main_scene="uid://di3kdwlspwjbt" config/features=PackedStringArray("4.5", "GL Compatibility") boot_splash/bg_color=Color(0.23921569, 0.23921569, 0.23921569, 1) boot_splash/image="uid://b7jpd8lq6kokg" diff --git a/scenes/splash_screen.tscn b/scenes/splash_screen.tscn new file mode 100644 index 00000000..1c5c552e --- /dev/null +++ b/scenes/splash_screen.tscn @@ -0,0 +1,70 @@ +[gd_scene load_steps=5 format=3 uid="uid://di3kdwlspwjbt"] + +[ext_resource type="Script" uid="uid://dm26g1kkq7f3w" path="res://scripts/splash_screen.gd" id="1_hsxvm"] +[ext_resource type="Texture2D" uid="uid://b7jpd8lq6kokg" path="res://assets/ikostan_logo_bg_removed.png" id="1_n4g2v"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hsxvm"] +bg_color = Color(0.25929382, 0.25929365, 0.2592937, 1) +corner_radius_top_left = 20 +corner_radius_top_right = 20 +corner_radius_bottom_right = 20 +corner_radius_bottom_left = 20 +shadow_size = 1 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4gp4q"] +bg_color = Color(0, 0, 0, 1) +corner_radius_top_left = 20 +corner_radius_top_right = 20 +corner_radius_bottom_right = 20 +corner_radius_bottom_left = 20 + +[node name="SplashScreen" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_hsxvm") + +[node name="IkostanLogoBgRemoved" type="Sprite2D" parent="."] +position = Vector2(630, 287) +scale = Vector2(0.5, 0.5) +texture = ExtResource("1_n4g2v") + +[node name="ProgressBar" type="ProgressBar" parent="."] +layout_mode = 1 +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +offset_left = -350.0 +offset_top = -220.0 +offset_right = 350.0 +offset_bottom = -193.0 +grow_horizontal = 2 +grow_vertical = 0 +size_flags_vertical = 6 +theme_override_colors/font_color = Color(0, 0, 0, 1) +theme_override_styles/background = SubResource("StyleBoxFlat_hsxvm") +theme_override_styles/fill = SubResource("StyleBoxFlat_4gp4q") + +[node name="Label" type="Label" parent="."] +layout_mode = 1 +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +offset_left = -35.0 +offset_top = -170.0 +offset_right = 35.0 +offset_bottom = -147.0 +grow_horizontal = 2 +grow_vertical = 0 +size_flags_horizontal = 4 +size_flags_vertical = 6 +theme_override_colors/font_color = Color(0, 0, 0, 1) +theme_override_font_sizes/font_size = 25 +text = "Loading: " diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd new file mode 100644 index 00000000..34acfc0b --- /dev/null +++ b/scripts/splash_screen.gd @@ -0,0 +1,122 @@ +## Copyright (C) 2025 Egor Kostan +## SPDX-License-Identifier: GPL-3.0-or-later +## Splashing Screen Script: splashing_screen.gd +## +## Manages background splashing of the next scene with smooth progress bar. +## Uses Godot's ResourceLoader for threaded splashing. +## Transitions to the loaded scene upon completion. +## +## :vartype progress_bar: ProgressBar +## :vartype label: Label +## :vartype loader_progress: float + +extends Control + +var loader_progress: float = 0.0 # Current smoothed progress value. +var min_load_time: float = 1.0 # Minimum splashing time in seconds for visibility (adjust as needed). +var load_start_time: float = 0.0 # Timestamp when splashing starts. +var is_scene_loaded: bool = false # Flag to track if the scene is fully loaded. +var scene: PackedScene = null # Holder for the loaded scene. +var load_failed: bool = false # Flag if splashing request failed. +var transitioning: bool = false # Flag to prevent multiple scene changes. +var label_text: String = "Loading: " + +@onready var progress_bar: ProgressBar = $ProgressBar # Progress bar UI element. +@onready var label: Label = $Label # Label for displaying loading status. + + +# Starts threaded loading of the next scene from Globals. +func _ready() -> void: + load_start_time = Time.get_ticks_msec() / 1000.0 + + # Give more breathing room on Web (threaded progress unreliable per Godot 4.5). + if OS.has_feature("web"): + min_load_time = 3.0 + + if Globals.next_scene == "": + Globals.log_message("Next scene path is empty!", Globals.LogLevel.ERROR) + load_failed = true + return + + # Start background loading with sub-threads to fix 50% quirk. + var err: int = ResourceLoader.load_threaded_request(Globals.next_scene, "", true) + if err != OK: + Globals.log_message("Failed to start splashing screen: " + str(err), Globals.LogLevel.ERROR) + load_failed = true + else: + Globals.log_message("Splashing screen started successfully.", Globals.LogLevel.DEBUG) + + +# Polls loading status and updates UI. Changes scene when loaded. +# Eliminated fake_progress; relies on real ResourceLoader progress. +func _process(_delta: float) -> void: + var elapsed_time: float = (Time.get_ticks_msec() / 1000.0) - load_start_time + + var real_progress: float = 0.0 + if is_scene_loaded: + real_progress = 100.0 # Force 100% if already loaded (ignores post-load status). + elif load_failed: + real_progress = 0.0 # Keep at 0 if failed early. + else: + # Only poll if not done. + var progress_array: Array = [] + var status: int = ResourceLoader.load_threaded_get_status( + Globals.next_scene, progress_array + ) + + if status == ResourceLoader.THREAD_LOAD_IN_PROGRESS: + if progress_array.size() > 0: + real_progress = progress_array[0] * 100.0 # Convert to percentage. + else: + Globals.log_message( + "Progress array empty during IN_PROGRESS.", Globals.LogLevel.WARNING + ) + + elif status == ResourceLoader.THREAD_LOAD_LOADED: + real_progress = 100.0 + if not is_scene_loaded: + is_scene_loaded = true + scene = ResourceLoader.load_threaded_get(Globals.next_scene) + Globals.log_message("Scene loaded successfully.", Globals.LogLevel.DEBUG) + + elif ( + status == ResourceLoader.THREAD_LOAD_FAILED + or status == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE + ): + Globals.log_message("Loading failed or invalid.", Globals.LogLevel.ERROR) + load_failed = true + + # Use real progress only (eliminates fake_progress process). + # Sub-threads + Web min_load_time fix 50% quirk and give breathing room. + var display_progress: float = real_progress + if load_failed: + display_progress = 100.0 # Force end on failure. + + # Smooth progress with lerp. + loader_progress = lerp(loader_progress, display_progress, 0.01) + # Update UI. + progress_bar.value = loader_progress + label.text = label_text + str(int(loader_progress)) + "%" + + # Proceed only when both loaded (or failed fallback) and minimum time elapsed. + if (is_scene_loaded or load_failed) and elapsed_time >= min_load_time and not transitioning: + transitioning = true # Lock to prevent re-entry. + + # Optional delay at 100%. + await get_tree().create_timer(1.5).timeout + + var target_path: String = Globals.next_scene # Cache the path. + Globals.next_scene = "" # Reset to avoid stale values. + + if target_path == "": + Globals.log_message( + "Empty next_scene - returning to main menu.", Globals.LogLevel.ERROR + ) + get_tree().change_scene_to_file("res://scenes/main_menu.tscn") + elif load_failed: + # Fallback to direct load on failure + Globals.log_message("Fallback: Loading scene directly.", Globals.LogLevel.WARNING) + get_tree().change_scene_to_file(target_path) + else: + # Change scene. + get_tree().change_scene_to_packed(scene) diff --git a/scripts/splash_screen.gd.uid b/scripts/splash_screen.gd.uid new file mode 100644 index 00000000..30058701 --- /dev/null +++ b/scripts/splash_screen.gd.uid @@ -0,0 +1 @@ +uid://dm26g1kkq7f3w From 93a81992e8f66000953ae4fdbe284b64ec318abd Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 20:17:07 -0800 Subject: [PATCH 14/33] Update splash_screen.gd --- scripts/splash_screen.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd index 34acfc0b..ba74a610 100644 --- a/scripts/splash_screen.gd +++ b/scripts/splash_screen.gd @@ -22,7 +22,7 @@ var transitioning: bool = false # Flag to prevent multiple scene changes. var label_text: String = "Loading: " @onready var progress_bar: ProgressBar = $ProgressBar # Progress bar UI element. -@onready var label: Label = $Label # Label for displaying loading status. +@onready var label: Label = $Label # Label for displaying loading status. # Starts threaded loading of the next scene from Globals. From 92324d3530dbb3d65e21da3a0cecdb99a2470748 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 20:18:49 -0800 Subject: [PATCH 15/33] Update splash_screen.gd --- scripts/splash_screen.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd index ba74a610..1bf0a84e 100644 --- a/scripts/splash_screen.gd +++ b/scripts/splash_screen.gd @@ -13,7 +13,7 @@ extends Control var loader_progress: float = 0.0 # Current smoothed progress value. -var min_load_time: float = 1.0 # Minimum splashing time in seconds for visibility (adjust as needed). +var min_load_time: float = 1.0 # Minimum splashing time in seconds for visibility. var load_start_time: float = 0.0 # Timestamp when splashing starts. var is_scene_loaded: bool = false # Flag to track if the scene is fully loaded. var scene: PackedScene = null # Holder for the loaded scene. From fbd937838f86705c53d8728d298b1a98ac04f3be Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 20:25:58 -0800 Subject: [PATCH 16/33] Update splash_screen.tscn --- scenes/splash_screen.tscn | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/scenes/splash_screen.tscn b/scenes/splash_screen.tscn index 1c5c552e..bbf0ef6d 100644 --- a/scenes/splash_screen.tscn +++ b/scenes/splash_screen.tscn @@ -27,8 +27,21 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_hsxvm") -[node name="IkostanLogoBgRemoved" type="Sprite2D" parent="."] -position = Vector2(630, 287) +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -20.0 +offset_top = -20.0 +offset_right = 20.0 +offset_bottom = 20.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="IkostanLogoBgRemoved" type="Sprite2D" parent="VBoxContainer"] scale = Vector2(0.5, 0.5) texture = ExtResource("1_n4g2v") @@ -57,10 +70,10 @@ anchor_left = 0.5 anchor_top = 1.0 anchor_right = 0.5 anchor_bottom = 1.0 -offset_left = -35.0 +offset_left = -54.5 offset_top = -170.0 -offset_right = 35.0 -offset_bottom = -147.0 +offset_right = 54.5 +offset_bottom = -135.0 grow_horizontal = 2 grow_vertical = 0 size_flags_horizontal = 4 From 29402152c547755302aaf024d2c94bb014fc172d Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Thu, 5 Mar 2026 20:26:31 -0800 Subject: [PATCH 17/33] Update scripts/splash_screen.gd Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- scripts/splash_screen.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd index 1bf0a84e..2d1f8bf2 100644 --- a/scripts/splash_screen.gd +++ b/scripts/splash_screen.gd @@ -1,6 +1,6 @@ ## Copyright (C) 2025 Egor Kostan ## SPDX-License-Identifier: GPL-3.0-or-later -## Splashing Screen Script: splashing_screen.gd +## Splash Screen Script: splash_screen.gd ## ## Manages background splashing of the next scene with smooth progress bar. ## Uses Godot's ResourceLoader for threaded splashing. From c1c7f5b1bb23c51b8c648dd4010c96475a825bb3 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Thu, 5 Mar 2026 20:30:29 -0800 Subject: [PATCH 18/33] Update scripts/splash_screen.gd Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- scripts/splash_screen.gd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd index 2d1f8bf2..aba3b40a 100644 --- a/scripts/splash_screen.gd +++ b/scripts/splash_screen.gd @@ -101,6 +101,9 @@ func _process(_delta: float) -> void: # Proceed only when both loaded (or failed fallback) and minimum time elapsed. if (is_scene_loaded or load_failed) and elapsed_time >= min_load_time and not transitioning: transitioning = true # Lock to prevent re-entry. + loader_progress = 100.0 + progress_bar.value = 100.0 + label.text = label_text + "100%" # Optional delay at 100%. await get_tree().create_timer(1.5).timeout From 70422a36508dad7a24f2720778b91ff616997af8 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 20:35:11 -0800 Subject: [PATCH 19/33] Update splash_screen.tscn --- scenes/splash_screen.tscn | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/scenes/splash_screen.tscn b/scenes/splash_screen.tscn index bbf0ef6d..5bc2b6b9 100644 --- a/scenes/splash_screen.tscn +++ b/scenes/splash_screen.tscn @@ -28,36 +28,28 @@ grow_vertical = 2 script = ExtResource("1_hsxvm") [node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -20.0 -offset_top = -20.0 -offset_right = 20.0 -offset_bottom = 20.0 -grow_horizontal = 2 -grow_vertical = 2 +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 [node name="IkostanLogoBgRemoved" type="Sprite2D" parent="VBoxContainer"] +position = Vector2(661, 341) scale = Vector2(0.5, 0.5) texture = ExtResource("1_n4g2v") [node name="ProgressBar" type="ProgressBar" parent="."] layout_mode = 1 -anchors_preset = 7 +anchors_preset = 8 anchor_left = 0.5 -anchor_top = 1.0 +anchor_top = 0.5 anchor_right = 0.5 -anchor_bottom = 1.0 +anchor_bottom = 0.5 offset_left = -350.0 -offset_top = -220.0 +offset_top = 130.0 offset_right = 350.0 -offset_bottom = -193.0 +offset_bottom = 160.0 grow_horizontal = 2 -grow_vertical = 0 +grow_vertical = 2 size_flags_vertical = 6 theme_override_colors/font_color = Color(0, 0, 0, 1) theme_override_styles/background = SubResource("StyleBoxFlat_hsxvm") From 0575e74165082d83bbc4bfdc00afe4e3f0eb94fa Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Thu, 5 Mar 2026 20:44:16 -0800 Subject: [PATCH 20/33] Playwright tests fixes --- tests/audio_flow_test.py | 3 ++- tests/back_flow_test.py | 3 ++- tests/difficulty_flow_test.py | 3 ++- tests/load_main_menu_test.py | 2 ++ tests/navigation_to_audio_test.py | 3 ++- tests/no_error_logs_test.py | 2 ++ tests/reset_audio_flow_test.py | 3 ++- tests/validate_clean_load_test.py | 2 ++ tests/volume_sliders_mutes_test.py | 3 ++- 9 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/audio_flow_test.py b/tests/audio_flow_test.py index f7e4eb85..95f77595 100644 --- a/tests/audio_flow_test.py +++ b/tests/audio_flow_test.py @@ -65,7 +65,8 @@ def on_console(msg) -> None: cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) - page.wait_for_timeout(3000) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) # Verify canvas diff --git a/tests/back_flow_test.py b/tests/back_flow_test.py index caeace90..56ef7056 100644 --- a/tests/back_flow_test.py +++ b/tests/back_flow_test.py @@ -62,7 +62,8 @@ def on_console(msg) -> None: cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) - page.wait_for_timeout(3000) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) # Verify canvas diff --git a/tests/difficulty_flow_test.py b/tests/difficulty_flow_test.py index b1044983..347c3299 100644 --- a/tests/difficulty_flow_test.py +++ b/tests/difficulty_flow_test.py @@ -70,8 +70,9 @@ def on_console(msg: Any) -> None: cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=3000) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) # Wait for Godot engine init (ensures 'godot' object is defined) - page.wait_for_timeout(3000) page.wait_for_function("() => window.godotInitialized", timeout=3000) # Verify canvas and title to ensure game is initialized diff --git a/tests/load_main_menu_test.py b/tests/load_main_menu_test.py index fa5700a1..ceb98777 100644 --- a/tests/load_main_menu_test.py +++ b/tests/load_main_menu_test.py @@ -69,6 +69,8 @@ def on_console(msg) -> None: cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) # Wait for Godot engine init (ensures 'godot' object is defined) page.wait_for_function("() => window.godotInitialized", timeout=5000) diff --git a/tests/navigation_to_audio_test.py b/tests/navigation_to_audio_test.py index ee732cca..18708d91 100644 --- a/tests/navigation_to_audio_test.py +++ b/tests/navigation_to_audio_test.py @@ -62,7 +62,8 @@ def on_console(msg) -> None: cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) - page.wait_for_timeout(3000) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) # Verify canvas diff --git a/tests/no_error_logs_test.py b/tests/no_error_logs_test.py index 1af4104d..70557c73 100644 --- a/tests/no_error_logs_test.py +++ b/tests/no_error_logs_test.py @@ -65,6 +65,8 @@ def on_page_error(exc) -> None: wait_until="networkidle", timeout=DEFAULT_TIMEOUT, ) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) # Wait for the custom Godot initialization flag page.wait_for_function("() => window.godotInitialized", timeout=DEFAULT_TIMEOUT) diff --git a/tests/reset_audio_flow_test.py b/tests/reset_audio_flow_test.py index c4db4cdb..70dda6c1 100644 --- a/tests/reset_audio_flow_test.py +++ b/tests/reset_audio_flow_test.py @@ -62,7 +62,8 @@ def on_console(msg) -> None: cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) - page.wait_for_timeout(3000) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) # Verify canvas diff --git a/tests/validate_clean_load_test.py b/tests/validate_clean_load_test.py index 939e5bc9..43360d5d 100644 --- a/tests/validate_clean_load_test.py +++ b/tests/validate_clean_load_test.py @@ -45,6 +45,8 @@ def on_console(msg) -> None: page.goto( "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 ) + # 1.5. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) # 2. Wait for the engine's ready signal page.wait_for_function("() => window.godotInitialized", timeout=5000) diff --git a/tests/volume_sliders_mutes_test.py b/tests/volume_sliders_mutes_test.py index 88f17212..ca5c3679 100644 --- a/tests/volume_sliders_mutes_test.py +++ b/tests/volume_sliders_mutes_test.py @@ -62,7 +62,8 @@ def on_console(msg) -> None: cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) - page.wait_for_timeout(3000) + # 1. Wait for the engine to actually start the splash scene + page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) # Verify canvas From 135d295af28809030eaa36d56fb323c906c4d1fe Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 04:45:04 +0000 Subject: [PATCH 21/33] style: format code with Black and isort This commit fixes the style issues introduced in 0575e74 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/458 --- tests/audio_flow_test.py | 149 +++++++++++------ tests/back_flow_test.py | 134 +++++++++------ tests/difficulty_flow_test.py | 159 +++++++++++------- tests/load_main_menu_test.py | 35 ++-- tests/navigation_to_audio_test.py | 110 ++++++++----- tests/reset_audio_flow_test.py | 252 ++++++++++++++++++++--------- tests/volume_sliders_mutes_test.py | 207 ++++++++++++++++-------- 7 files changed, 703 insertions(+), 343 deletions(-) diff --git a/tests/audio_flow_test.py b/tests/audio_flow_test.py index 95f77595..8e18156e 100644 --- a/tests/audio_flow_test.py +++ b/tests/audio_flow_test.py @@ -25,9 +25,10 @@ v8_coverage_audio_flow_test.json, artifacts/test_audio_failure_*.png/txt """ +import json import os import time -import json + import pytest from playwright.sync_api import Page @@ -62,9 +63,13 @@ def on_console(msg) -> None: # Start CDP session for V8 JS coverage (workaround for Python Playwright lacking native coverage API) cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") - cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) - page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) + page.goto( + "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 + ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) @@ -77,69 +82,90 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Open options - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) # page.click("#options-button", force=True) - page.wait_for_function('window.optionsPressed !== undefined', timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings - page.wait_for_selector('#advanced-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-button", state="visible", timeout=2500) # page.click("#advanced-button", force=True) - page.wait_for_function('window.advancedPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedPressed !== undefined", timeout=2500) page.evaluate("window.advancedPressed([])") - page.wait_for_function('window.changeLogLevel !== undefined', timeout=2500) + page.wait_for_function("window.changeLogLevel !== undefined", timeout=2500) advanced_display: str = page.evaluate( - "window.getComputedStyle(document.getElementById('log-level-select')).display") - assert advanced_display == 'block', "Advanced menu not loaded (selected log level not displayed)" + "window.getComputedStyle(document.getElementById('log-level-select')).display" + ) + assert ( + advanced_display == "block" + ), "Advanced menu not loaded (selected log level not displayed)" # Set log level DEBUG pre_change_log_count = len(logs) page.evaluate("window.changeLogLevel([0])") page.wait_for_timeout(1000) new_logs = logs[pre_change_log_count:] - assert any("log level changed to: debug" in log["text"].lower() for log in new_logs) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + assert any( + "log level changed to: debug" in log["text"].lower() for log in new_logs + ) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" # Go back to Options menu - page.wait_for_selector('#advanced-back-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-back-button", state="visible", timeout=2500) # page.click("#advanced-back-button", force=True) - page.wait_for_function('window.advancedBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedBackPressed !== undefined", timeout=2500) page.evaluate("window.advancedBackPressed([])") # Open audio pre_change_log_count = len(logs) - page.wait_for_selector('#audio-button', state='visible', timeout=2500) + page.wait_for_selector("#audio-button", state="visible", timeout=2500) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([])") page.wait_for_timeout(1500) - assert page.evaluate("window.getComputedStyle(document.getElementById('master-slider')).display") == 'block' + assert ( + page.evaluate( + "window.getComputedStyle(document.getElementById('master-slider')).display" + ) + == "block" + ) new_logs = logs[pre_change_log_count:] assert any("audio button pressed" in log["text"].lower() for log in new_logs) # Get initial values initial_sfx: str = page.evaluate("document.getElementById('sfx-slider').value") - initial_weapon: str = page.evaluate("document.getElementById('weapon-slider').value") - initial_music: str = page.evaluate("document.getElementById('music-slider').value") - initial_rotors: str = page.evaluate("document.getElementById('rotors-slider').value") + initial_weapon: str = page.evaluate( + "document.getElementById('weapon-slider').value" + ) + initial_music: str = page.evaluate( + "document.getElementById('music-slider').value" + ) + initial_rotors: str = page.evaluate( + "document.getElementById('rotors-slider').value" + ) # WARN-01: Master muted → attempt sub-volume adjust (SFX) pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteMaster !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteMaster !== undefined", timeout=2500) page.evaluate("window.toggleMuteMaster([0])") # Mute page.wait_for_timeout(1500) new_logs = logs[pre_change_log_count:] assert any("master is muted" in log["text"].lower() for log in new_logs) # Change SFX Volume when Master is muted pre_change_log_count = len(logs) - page.wait_for_function('window.changeSfxVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeSfxVolume !== undefined", timeout=2500) page.evaluate("window.changeSfxVolume([0])") page.wait_for_timeout(1500) - assert page.evaluate( - "document.getElementById('sfx-slider').value") == initial_sfx, "SFX value changed unexpectedly" + assert ( + page.evaluate("document.getElementById('sfx-slider').value") == initial_sfx + ), "SFX value changed unexpectedly" new_logs = logs[pre_change_log_count:] - assert any("master muted, cannot adjust sub-volume" in log["text"].lower() for log in new_logs) or any( - "warning dialog" in log["text"].lower() for log in new_logs) + assert any( + "master muted, cannot adjust sub-volume" in log["text"].lower() + for log in new_logs + ) or any("warning dialog" in log["text"].lower() for log in new_logs) # Additional: Master muted → attempt sub-volume adjust (Music) # Attempt to change music while Master is still muted @@ -150,76 +176,93 @@ def on_console(msg) -> None: # slider.dispatchEvent(new Event('change')); # """) pre_change_log_count = len(logs) - page.wait_for_function('window.changeMusicVolume !== undefined', timeout=1500) + page.wait_for_function("window.changeMusicVolume !== undefined", timeout=1500) page.evaluate("window.changeMusicVolume([0.3])") page.wait_for_timeout(1500) - assert page.evaluate( - "document.getElementById('music-slider').value") == initial_music, "Music value changed unexpectedly under Master mute" + assert ( + page.evaluate("document.getElementById('music-slider').value") + == initial_music + ), "Music value changed unexpectedly under Master mute" new_logs = logs[pre_change_log_count:] - assert any("master muted, cannot adjust sub-volume" in log["text"].lower() for log in new_logs) or any( - "warning dialog" in log["text"].lower() for log in new_logs) + assert any( + "master muted, cannot adjust sub-volume" in log["text"].lower() + for log in new_logs + ) or any("warning dialog" in log["text"].lower() for log in new_logs) # Additional: Master muted → attempt sub-volume adjust (Rotors) # Assuming Rotors is affected by Master mute (as a deeper sub-volume) pre_change_log_count = len(logs) - page.wait_for_function('window.changeRotorsVolume !== undefined', timeout=1500) + page.wait_for_function("window.changeRotorsVolume !== undefined", timeout=1500) page.evaluate("window.changeRotorsVolume([0.4])") page.wait_for_timeout(1500) - assert page.evaluate( - "document.getElementById('rotors-slider').value") == initial_rotors, "Rotors value changed unexpectedly under Master mute" + assert ( + page.evaluate("document.getElementById('rotors-slider').value") + == initial_rotors + ), "Rotors value changed unexpectedly under Master mute" new_logs = logs[pre_change_log_count:] - assert any("master muted, cannot adjust sub-volume" in log["text"].lower() for log in new_logs) or any( - "warning dialog" in log["text"].lower() for log in new_logs) + assert any( + "master muted, cannot adjust sub-volume" in log["text"].lower() + for log in new_logs + ) or any("warning dialog" in log["text"].lower() for log in new_logs) # Unmute Master for next tests - page.wait_for_function('window.toggleMuteMaster !== undefined', timeout=1500) + page.wait_for_function("window.toggleMuteMaster !== undefined", timeout=1500) page.evaluate("window.toggleMuteMaster([1])") page.wait_for_timeout(1500) # WARN-02: SFX muted → attempt weapon adjust - page.wait_for_function('window.toggleMuteSfx !== undefined', timeout=1500) + page.wait_for_function("window.toggleMuteSfx !== undefined", timeout=1500) page.evaluate("window.toggleMuteSfx([0])") # Mute page.wait_for_timeout(1500) pre_change_log_count = len(logs) - page.wait_for_function('window.changeWeaponVolume !== undefined', timeout=1500) + page.wait_for_function("window.changeWeaponVolume !== undefined", timeout=1500) page.evaluate("window.changeWeaponVolume([0])") page.wait_for_timeout(1500) - assert page.evaluate( - "document.getElementById('weapon-slider').value") == initial_weapon, "Weapon value changed unexpectedly" + assert ( + page.evaluate("document.getElementById('weapon-slider').value") + == initial_weapon + ), "Weapon value changed unexpectedly" new_logs = logs[pre_change_log_count:] - assert any("sfx muted, cannot adjust" in log["text"].lower() for log in new_logs) or any( - "warning dialog" in log["text"].lower() for log in new_logs) + assert any( + "sfx muted, cannot adjust" in log["text"].lower() for log in new_logs + ) or any("warning dialog" in log["text"].lower() for log in new_logs) # Additional: SFX muted → attempt rotors adjust (assuming Rotors under SFX) pre_change_log_count = len(logs) - page.wait_for_function('window.changeRotorsVolume !== undefined', timeout=1500) + page.wait_for_function("window.changeRotorsVolume !== undefined", timeout=1500) page.evaluate("window.changeRotorsVolume([0.5])") page.wait_for_timeout(1500) - assert page.evaluate( - "document.getElementById('rotors-slider').value") == initial_rotors, "Rotors value changed unexpectedly under SFX mute" + assert ( + page.evaluate("document.getElementById('rotors-slider').value") + == initial_rotors + ), "Rotors value changed unexpectedly under SFX mute" new_logs = logs[pre_change_log_count:] - assert any("sfx muted, cannot adjust" in log["text"].lower() for log in new_logs) or any( - "warning dialog" in log["text"].lower() for log in new_logs) + assert any( + "sfx muted, cannot adjust" in log["text"].lower() for log in new_logs + ) or any("warning dialog" in log["text"].lower() for log in new_logs) # Unmute SFX - page.wait_for_function('window.toggleMuteSfx !== undefined', timeout=1500) + page.wait_for_function("window.toggleMuteSfx !== undefined", timeout=1500) page.evaluate("window.toggleMuteSfx([1])") page.wait_for_timeout(1500) # WARN-03: Master unmuted → adjust sub-volume (Music) # Capture logs before the change to isolate new ones (good for debugging in Godot tests) pre_change_log_count = len(logs) - page.wait_for_function('window.changeMusicVolume !== undefined', timeout=1500) + page.wait_for_function("window.changeMusicVolume !== undefined", timeout=1500) page.evaluate("window.changeMusicVolume([0.6])") page.wait_for_timeout(1500) # Verify the value changed (as expected, no mute constraint) - assert page.evaluate("document.getElementById('music-slider').value") == '0.6', "Music value not changed" + assert ( + page.evaluate("document.getElementById('music-slider').value") == "0.6" + ), "Music value not changed" # Check only new logs for no warnings (stronger assertion, catches unrelated warnings) new_logs = logs[pre_change_log_count:] assert not any( - "warning" in log["text"].lower() for log in new_logs), "Unexpected warning after music volume change" + "warning" in log["text"].lower() for log in new_logs + ), "Unexpected warning after music volume change" except Exception as e: print(f"Test: 'test_audio_flow' failed: {str(e)}") @@ -236,7 +279,7 @@ def on_console(msg) -> None: finally: if cdp_session: # Stop V8 coverage and save to file (even on failure) - coverage = cdp_session.send("Profiler.takePreciseCoverage")['result'] + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") with open("v8_coverage_audio_flow_test.json", "w") as f: diff --git a/tests/back_flow_test.py b/tests/back_flow_test.py index 56ef7056..ef26f0e1 100644 --- a/tests/back_flow_test.py +++ b/tests/back_flow_test.py @@ -25,9 +25,10 @@ v8_coverage_back_flow_test.json, artifacts/test_back_failure_*.png/txt """ +import json import os import time -import json + from playwright.sync_api import Page @@ -59,9 +60,13 @@ def on_console(msg) -> None: # Start CDP session for V8 JS coverage (workaround for Python Playwright lacking native coverage API) cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") - cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) - page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) + page.goto( + "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 + ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) @@ -74,66 +79,88 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Navigate to options menu - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) # page.click("#options-button", force=True, timeout=2500) - page.wait_for_function('window.optionsPressed !== undefined', timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings - page.wait_for_selector('#advanced-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-button", state="visible", timeout=2500) # page.click("#advanced-button", force=True) - page.wait_for_function('window.advancedPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedPressed !== undefined", timeout=2500) page.evaluate("window.advancedPressed([])") - page.wait_for_function('window.changeLogLevel !== undefined', timeout=2500) + page.wait_for_function("window.changeLogLevel !== undefined", timeout=2500) advanced_display: str = page.evaluate( - "window.getComputedStyle(document.getElementById('log-level-select')).display") - assert advanced_display == 'block', "Advanced menu not loaded (selected log level not displayed)" + "window.getComputedStyle(document.getElementById('log-level-select')).display" + ) + assert ( + advanced_display == "block" + ), "Advanced menu not loaded (selected log level not displayed)" # Set log level DEBUG pre_change_log_count = len(logs) page.evaluate("window.changeLogLevel([0])") page.wait_for_timeout(1000) new_logs = logs[pre_change_log_count:] - assert any("log level changed to: debug" in log["text"].lower() for log in new_logs) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + assert any( + "log level changed to: debug" in log["text"].lower() for log in new_logs + ) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" # Go back to Options menu - page.wait_for_selector('#advanced-back-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-back-button", state="visible", timeout=2500) # page.click("#advanced-back-button", force=True) - page.wait_for_function('window.advancedBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedBackPressed !== undefined", timeout=2500) page.evaluate("window.advancedBackPressed([])") # Navigate to audio sub-menu - page.wait_for_selector('#audio-button', state='visible', timeout=2500) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + page.wait_for_selector("#audio-button", state="visible", timeout=2500) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" pre_change_log_count = len(logs) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([])") page.wait_for_timeout(5000) # Wait for audio scene load and JS eval - audio_display: str = page.evaluate("window.getComputedStyle(document.getElementById('master-slider')).display") - assert audio_display == 'block', "Audio menu not loaded (master-slider not displayed)" + audio_display: str = page.evaluate( + "window.getComputedStyle(document.getElementById('master-slider')).display" + ) + assert ( + audio_display == "block" + ), "Audio menu not loaded (master-slider not displayed)" new_logs = logs[pre_change_log_count:] - assert any("audio button pressed." in log["text"].lower() for log in new_logs), "Audio navigation log not found" + assert any( + "audio button pressed." in log["text"].lower() for log in new_logs + ), "Audio navigation log not found" # BACK-01: Back returns to parent menu # Preconditions: In Audio Settings # Steps: Press Back # Expected: Options menu visible pre_change_log_count = len(logs) - page.wait_for_function('window.audioBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") page.wait_for_timeout(2500) - options_display: str = page.evaluate("window.getComputedStyle(document.getElementById('gameplay-button')).display") - assert options_display == 'block', "Did not return to options menu" - audio_display_after: str = page.evaluate("window.getComputedStyle(document.getElementById('master-slider')).display") - assert audio_display_after == 'none', "Audio menu still visible after back" + options_display: str = page.evaluate( + "window.getComputedStyle(document.getElementById('gameplay-button')).display" + ) + assert options_display == "block", "Did not return to options menu" + audio_display_after: str = page.evaluate( + "window.getComputedStyle(document.getElementById('master-slider')).display" + ) + assert audio_display_after == "none", "Audio menu still visible after back" new_logs = logs[pre_change_log_count:] - assert any("back (audio_back_button) button pressed in audio" in log["text"].lower() for log in new_logs), "Back log not found" + assert any( + "back (audio_back_button) button pressed in audio" in log["text"].lower() + for log in new_logs + ), "Back log not found" # Re-enter audio for next tests - page.wait_for_selector('#audio-button', state='visible', timeout=2500) + page.wait_for_selector("#audio-button", state="visible", timeout=2500) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) @@ -141,27 +168,32 @@ def on_console(msg) -> None: # Preconditions: No modification # Steps: Press Back # Expected: Back to Options; no state mutation - initial_master: str = page.evaluate("document.getElementById('master-slider').value") - page.wait_for_function('window.audioBackPressed !== undefined', timeout=2500) + initial_master: str = page.evaluate( + "document.getElementById('master-slider').value" + ) + page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") - page.wait_for_selector('#audio-button', state='visible', timeout=2500) + page.wait_for_selector("#audio-button", state="visible", timeout=2500) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) - assert page.evaluate("document.getElementById('master-slider').value") == initial_master, "State mutated without changes" + assert ( + page.evaluate("document.getElementById('master-slider').value") + == initial_master + ), "State mutated without changes" # Re-enter audio page.reload() page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) # Navigate to options menu - page.wait_for_selector('#options-button', state='visible', timeout=5000) + page.wait_for_selector("#options-button", state="visible", timeout=5000) page.click("#options-button", force=True) # Navigate to audio menu - page.wait_for_selector('#audio-button', state='visible', timeout=5000) + page.wait_for_selector("#audio-button", state="visible", timeout=5000) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) @@ -169,17 +201,19 @@ def on_console(msg) -> None: # Preconditions: Sliders adjusted but not Reset # Steps: Press Back # Expected: Return; previous changes persist until Reset - page.wait_for_function('window.changeMusicVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeMusicVolume !== undefined", timeout=2500) page.evaluate("window.changeMusicVolume([0.4])") page.wait_for_timeout(1500) - page.wait_for_function('window.audioBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") - page.wait_for_selector('#audio-button', state='visible', timeout=2500) + page.wait_for_selector("#audio-button", state="visible", timeout=2500) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) - assert page.evaluate("document.getElementById('music-slider').value") == '0.4', "Changes did not persist after back" + assert ( + page.evaluate("document.getElementById('music-slider').value") == "0.4" + ), "Changes did not persist after back" # BACK-04: Back from mid-interaction # Preconditions: Slider being dragged @@ -187,30 +221,36 @@ def on_console(msg) -> None: # Expected: Navigation ok, no JS exceptions # Simulate mid-drag by setting value without full change event, then back pre_change_log_count = len(logs) - page.evaluate(""" + page.evaluate( + """ const slider = document.getElementById('sfx-slider'); slider.value = 0.6; slider.dispatchEvent(new Event('input')); // Mid-drag - """) + """ + ) page.wait_for_timeout(500) - page.wait_for_function('window.audioBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") page.wait_for_timeout(2000) new_logs = logs[pre_change_log_count:] - assert not any("error" in log["text"].lower() for log in new_logs), "JS exceptions during back mid-interaction" + assert not any( + "error" in log["text"].lower() for log in new_logs + ), "JS exceptions during back mid-interaction" except Exception as e: print(f"Test suite failed: {str(e)}") os.makedirs("artifacts", exist_ok=True) timestamp: int = int(time.time()) page.screenshot(path=f"artifacts/test_back_failure_screenshot_{timestamp}.png") - with open(f"artifacts/test_back_failure_console_logs_{timestamp}.txt", "w") as f: + with open( + f"artifacts/test_back_failure_console_logs_{timestamp}.txt", "w" + ) as f: for log in logs: f.write(f"[{log['type']}] {log['text']}\n") raise finally: if cdp_session: - coverage = cdp_session.send("Profiler.takePreciseCoverage")['result'] + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") with open("v8_coverage_back_flow_test.json", "w") as f: diff --git a/tests/difficulty_flow_test.py b/tests/difficulty_flow_test.py index 347c3299..cf29b9c8 100644 --- a/tests/difficulty_flow_test.py +++ b/tests/difficulty_flow_test.py @@ -1,4 +1,3 @@ - # Copyright (C) 2025 Egor Kostan # SPDX-License-Identifier: GPL-3.0-or-later # tests/difficulty_flow_test.py @@ -32,10 +31,11 @@ v8_coverage_difficulty_flow_test.json, artifacts/test_difficulty_failure_*.png/txt """ +import json import os import time -import json from typing import Any, Dict, List, Optional + from playwright.sync_api import Page @@ -67,9 +67,13 @@ def on_console(msg: Any) -> None: # Start CDP session for V8 JS coverage (workaround for Python Playwright lacking native coverage API) cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") - cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) - page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=3000) + page.goto( + "http://localhost:8080/index.html", wait_until="networkidle", timeout=3000 + ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) # Wait for Godot engine init (ensures 'godot' object is defined) @@ -83,81 +87,102 @@ def on_console(msg: Any) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Check element present - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('options-button') !== null") # Check invisible (opacity 0) - opacity: str = page.evaluate("window.getComputedStyle(document.getElementById('options-button')).opacity") - assert opacity == '0', f"Expected opacity 0, got {opacity}" + opacity: str = page.evaluate( + "window.getComputedStyle(document.getElementById('options-button')).opacity" + ) + assert opacity == "0", f"Expected opacity 0, got {opacity}" # Check pointer-events none pointer_events: str = page.evaluate( - "window.getComputedStyle(document.getElementById('options-button')).pointerEvents") - assert pointer_events == 'none', f"Expected pointer-events none, got {pointer_events}" + "window.getComputedStyle(document.getElementById('options-button')).pointerEvents" + ) + assert ( + pointer_events == "none" + ), f"Expected pointer-events none, got {pointer_events}" # Wait main menu (function check for ID) - page.wait_for_function("() => document.getElementById('options-button') !== null", - timeout=5000) # Longer for stalls + page.wait_for_function( + "() => document.getElementById('options-button') !== null", timeout=5000 + ) # Longer for stalls # Open options - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) # page.click("#options-button", force=True) - page.wait_for_function('window.optionsPressed !== undefined', timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings - page.wait_for_selector('#advanced-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-button", state="visible", timeout=2500) # page.click("#advanced-button", force=True) - page.wait_for_function('window.advancedPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedPressed !== undefined", timeout=2500) page.evaluate("window.advancedPressed([])") - page.wait_for_function('window.changeLogLevel !== undefined', timeout=2500) + page.wait_for_function("window.changeLogLevel !== undefined", timeout=2500) advanced_display: str = page.evaluate( - "window.getComputedStyle(document.getElementById('log-level-select')).display") - assert advanced_display == 'block', "Advanced menu not loaded (selected log level not displayed)" + "window.getComputedStyle(document.getElementById('log-level-select')).display" + ) + assert ( + advanced_display == "block" + ), "Advanced menu not loaded (selected log level not displayed)" # Set log level DEBUG pre_change_log_count: int = len(logs) page.evaluate("window.changeLogLevel([0])") page.wait_for_timeout(1000) new_logs: List[Dict[str, str]] = logs[pre_change_log_count:] - assert any("log level changed to: debug" in log["text"].lower() for log in new_logs) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" - assert any("Log level changed to: DEBUG" in log["text"] for log in new_logs), "Failed to set log level to DEBUG" assert any( - "log level changed to: debug" in log["text"].lower() for log in new_logs), "Failed to set log level to DEBUG" + "log level changed to: debug" in log["text"].lower() for log in new_logs + ) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" assert any( - "settings saved" in log["text"].lower() for log in new_logs), "Failed to save the settings" + "Log level changed to: DEBUG" in log["text"] for log in new_logs + ), "Failed to set log level to DEBUG" + assert any( + "log level changed to: debug" in log["text"].lower() for log in new_logs + ), "Failed to set log level to DEBUG" + assert any( + "settings saved" in log["text"].lower() for log in new_logs + ), "Failed to save the settings" # Go back to Options menu - page.wait_for_selector('#advanced-back-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-back-button", state="visible", timeout=2500) # page.click("#advanced-back-button", force=True) - page.wait_for_function('window.advancedBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedBackPressed !== undefined", timeout=2500) page.evaluate("window.advancedBackPressed([])") # Go to Gameplay Settings - page.wait_for_selector('#gameplay-button', state='visible', timeout=2500) + page.wait_for_selector("#gameplay-button", state="visible", timeout=2500) # page.click("#advanced-back-button", force=True) - page.wait_for_function('window.gameplayPressed !== undefined', timeout=2500) + page.wait_for_function("window.gameplayPressed !== undefined", timeout=2500) page.evaluate("window.gameplayPressed([])") # Assert gameplay settings overlay is shown and options overlay is hidden - page.wait_for_selector('#difficulty-slider', state='visible', timeout=2500) - page.wait_for_selector('#options-back-button', state='hidden', timeout=2500) + page.wait_for_selector("#difficulty-slider", state="visible", timeout=2500) + page.wait_for_selector("#options-back-button", state="hidden", timeout=2500) # Set difficulty to 2.0 - directly call the exposed callback (bypasses event for reliability in automation) pre_change_log_count = len(logs) - page.wait_for_function('window.changeDifficulty !== undefined', timeout=2500) + page.wait_for_function("window.changeDifficulty !== undefined", timeout=2500) page.evaluate("window.changeDifficulty([2.0])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] assert any( - "difficulty changed to: 2.0" in log["text"].lower() for log in new_logs), "Failed to set difficulty to 2.0" + "difficulty changed to: 2.0" in log["text"].lower() for log in new_logs + ), "Failed to set difficulty to 2.0" assert any( - "settings saved" in log["text"].lower() for log in new_logs), "Failed to save the settings" + "settings saved" in log["text"].lower() for log in new_logs + ), "Failed to save the settings" # Reset gameplay settings back to defaults via the gameplay reset action pre_reset_log_count: int = len(logs) - page.wait_for_function('window.gameplayResetPressed !== undefined', timeout=2500) + page.wait_for_function( + "window.gameplayResetPressed !== undefined", timeout=2500 + ) page.evaluate("window.gameplayResetPressed([])") page.wait_for_timeout(2500) reset_logs: List[Dict[str, str]] = logs[pre_reset_log_count:] @@ -174,49 +199,62 @@ def on_console(msg: Any) -> None: # Back to Main menu pre_change_log_count = len(logs) - page.wait_for_function('window.gameplayBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.gameplayBackPressed !== undefined", timeout=2500) page.evaluate("window.gameplayBackPressed([])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("back button pressed." in log["text"].lower() for log in new_logs), "Back button not found" + assert any( + "back button pressed." in log["text"].lower() for log in new_logs + ), "Back button not found" # After gameplayBackPressed([]), the options overlay should be visible again # and gameplay-specific elements should be hidden. # Options overlay visible - page.wait_for_selector('#options-back-button', state='visible', timeout=2500) + page.wait_for_selector("#options-back-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('options-back-button') !== null") # Gameplay UI hidden - page.wait_for_selector('#difficulty-slider', state='hidden', timeout=2500) - assert page.evaluate("document.getElementById('difficulty-slider') === null || document.getElementById('difficulty-slider').offsetParent === null") + page.wait_for_selector("#difficulty-slider", state="hidden", timeout=2500) + assert page.evaluate( + "document.getElementById('difficulty-slider') === null || document.getElementById('difficulty-slider').offsetParent === null" + ) # Check element present - page.wait_for_selector('#options-back-button', state='visible', timeout=2500) + page.wait_for_selector("#options-back-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('options-back-button') !== null") page.evaluate("window.optionsBackPressed([])") # After optionsBackPressed([]), we should be back on the main menu: # main-menu elements visible and options elements hidden. - page.wait_for_selector('#start-button', state='visible', timeout=2500) + page.wait_for_selector("#start-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('start-button') !== null") - page.wait_for_selector('#options-back-button', state='hidden', timeout=2500) - assert page.evaluate("document.getElementById('options-back-button') === null || document.getElementById('options-back-button').offsetParent === null") + page.wait_for_selector("#options-back-button", state="hidden", timeout=2500) + assert page.evaluate( + "document.getElementById('options-back-button') === null || document.getElementById('options-back-button').offsetParent === null" + ) # Start game - page.wait_for_selector('#start-button', state='visible', timeout=2500) + page.wait_for_selector("#start-button", state="visible", timeout=2500) pre_change_log_count = len(logs) pre_poll_log_count: int = len(logs) page.click("#start-button", force=True) - page.wait_for_timeout(5000) # Sometimes it takes longer time to pass the loading screen + page.wait_for_timeout( + 5000 + ) # Sometimes it takes longer time to pass the loading screen new_logs = logs[pre_change_log_count:] assert any( - "start game menu button pressed." in log["text"].lower() for log in new_logs), "Start Game button not found" + "start game menu button pressed." in log["text"].lower() for log in new_logs + ), "Start Game button not found" assert any( - "initializing main scene..." in log["text"].lower() for log in new_logs), "Game scene not found" + "initializing main scene..." in log["text"].lower() for log in new_logs + ), "Game scene not found" # Poll for loading start log to confirm transition to loading screen start_time: float = time.time() while time.time() - start_time < 30: - if any("loading started successfully." in log["text"].lower() for log in logs[pre_poll_log_count:]): + if any( + "loading started successfully." in log["text"].lower() + for log in logs[pre_poll_log_count:] + ): break time.sleep(0.5) else: @@ -225,7 +263,10 @@ def on_console(msg: Any) -> None: # Poll for scene loaded log from loading_screen.gd start_time = time.time() while time.time() - start_time < 30: - if any("scene loaded successfully." in log["text"].lower() for log in logs[pre_poll_log_count:]): + if any( + "scene loaded successfully." in log["text"].lower() + for log in logs[pre_poll_log_count:] + ): break time.sleep(0.5) else: @@ -241,17 +282,23 @@ def on_console(msg: Any) -> None: page.wait_for_timeout(3000) new_logs = logs[pre_change_log_count:] # Verify scaled cooldown in logs (fire_rate 0.15 * 2.0 = 0.3) - assert any("firing with scaled cooldown: 0.3" in log["text"].lower() for log in - new_logs), "Scaled cooldown not found in logs" + assert any( + "firing with scaled cooldown: 0.3" in log["text"].lower() + for log in new_logs + ), "Scaled cooldown not found in logs" except Exception as e: print(f"Test: 'test_difficulty_flow' failed: {str(e)}") os.makedirs("artifacts", exist_ok=True) # Artifact on failure timestamp: int = int(time.time()) - page.screenshot(path=f"artifacts/test_difficulty_failure_screenshot_{timestamp}.png") + page.screenshot( + path=f"artifacts/test_difficulty_failure_screenshot_{timestamp}.png" + ) - log_file: str = f"artifacts/test_difficulty_failure_console_logs_{timestamp}.txt" + log_file: str = ( + f"artifacts/test_difficulty_failure_console_logs_{timestamp}.txt" + ) with open(log_file, "w") as f: for log in logs: f.write(f"[{log['type']}] {log['text']}\n") @@ -260,12 +307,16 @@ def on_console(msg: Any) -> None: with open(f"artifacts/test_difficulty_failure_html_{timestamp}.html", "w") as f: f.write(page.content()) - print(f"Failure logs: artifacts/test_difficulty_failure_console_logs_{timestamp}.txt. Error: {e}") + print( + f"Failure logs: artifacts/test_difficulty_failure_console_logs_{timestamp}.txt. Error: {e}" + ) raise finally: if cdp_session: # Stop V8 coverage and save to file (even on failure) - coverage: Dict[str, Any] = cdp_session.send("Profiler.takePreciseCoverage")['result'] + coverage: Dict[str, Any] = cdp_session.send("Profiler.takePreciseCoverage")[ + "result" + ] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") with open("v8_coverage_difficulty_flow_test.json", "w") as f: diff --git a/tests/load_main_menu_test.py b/tests/load_main_menu_test.py index ceb98777..08e82d99 100644 --- a/tests/load_main_menu_test.py +++ b/tests/load_main_menu_test.py @@ -33,9 +33,10 @@ v8_coverage_load_main_menu_test.json, artifacts/test_load_main_menu_failure_*.png/txt """ +import json import os import time -import json + from playwright.sync_api import Page @@ -66,9 +67,13 @@ def on_console(msg) -> None: # Start CDP session for V8 JS coverage (workaround for Python Playwright lacking native coverage API) cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") - cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) - page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) + page.goto( + "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 + ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) # Wait for Godot engine init (ensures 'godot' object is defined) @@ -84,11 +89,11 @@ def on_console(msg) -> None: # Since the DOM overlays are now central to the web flow, # consider also asserting that the main-menu overlay elements are present # and visible (similar to navigation_to_audio_test): - page.wait_for_selector('#start-button', state='visible', timeout=2500) + page.wait_for_selector("#start-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('start-button') !== null") - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('options-button') !== null") - page.wait_for_selector('#quit-button', state='visible', timeout=2500) + page.wait_for_selector("#quit-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('quit-button') !== null") except Exception as e: @@ -96,22 +101,30 @@ def on_console(msg) -> None: os.makedirs("artifacts", exist_ok=True) # Artifact on failure timestamp = int(time.time()) - page.screenshot(path=f"artifacts/test_load_main_menu_failure_screenshot_{timestamp}.png") + page.screenshot( + path=f"artifacts/test_load_main_menu_failure_screenshot_{timestamp}.png" + ) - log_file: str = f"artifacts/test_load_main_menu_failure_console_logs_{timestamp}.txt" + log_file: str = ( + f"artifacts/test_load_main_menu_failure_console_logs_{timestamp}.txt" + ) with open(log_file, "w") as f: for log in logs: f.write(f"[{log['type']}] {log['text']}\n") print(f"Console logs saved to {log_file}") - with open(f"artifacts/test_load_main_menu_failure_html_{timestamp}.html", "w") as f: + with open( + f"artifacts/test_load_main_menu_failure_html_{timestamp}.html", "w" + ) as f: f.write(page.content()) - print(f"Failure logs: artifacts/test_load_main_menu_failure_console_logs_{timestamp}.txt. Error: {e}") + print( + f"Failure logs: artifacts/test_load_main_menu_failure_console_logs_{timestamp}.txt. Error: {e}" + ) raise finally: if cdp_session: - coverage = cdp_session.send("Profiler.takePreciseCoverage")['result'] + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") with open("v8_coverage_load_main_menu_test.json", "w") as f: diff --git a/tests/navigation_to_audio_test.py b/tests/navigation_to_audio_test.py index 18708d91..4d71e823 100644 --- a/tests/navigation_to_audio_test.py +++ b/tests/navigation_to_audio_test.py @@ -25,9 +25,10 @@ v8_coverage_navigation_to_audio_test.json, artifacts/test_navigation_failure_*.png/txt """ +import json import os import time -import json + from playwright.sync_api import Page @@ -59,9 +60,13 @@ def on_console(msg) -> None: # Start CDP session for V8 JS coverage (workaround for Python Playwright lacking native coverage API) cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") - cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) - page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) + page.goto( + "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 + ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) @@ -74,33 +79,42 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # NAV-01: Verify main menu overlays exist and are configured - page.wait_for_selector('#start-button', state='visible', timeout=2500) + page.wait_for_selector("#start-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('start-button') !== null") - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('options-button') !== null") - page.wait_for_selector('#quit-button', state='visible', timeout=2500) + page.wait_for_selector("#quit-button", state="visible", timeout=2500) assert page.evaluate("document.getElementById('quit-button') !== null") - opacity: str = page.evaluate("window.getComputedStyle(document.getElementById('options-button')).opacity") - assert opacity == '0', f"Expected opacity 0, got {opacity}" - pointer_events: str = page.evaluate("window.getComputedStyle(document.getElementById('options-button')).pointerEvents") - assert pointer_events == 'none', f"Expected pointer-events none, got {pointer_events}" + opacity: str = page.evaluate( + "window.getComputedStyle(document.getElementById('options-button')).opacity" + ) + assert opacity == "0", f"Expected opacity 0, got {opacity}" + pointer_events: str = page.evaluate( + "window.getComputedStyle(document.getElementById('options-button')).pointerEvents" + ) + assert ( + pointer_events == "none" + ), f"Expected pointer-events none, got {pointer_events}" # NAV-02: Navigate to options menu # Open options - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) # page.click("#options-button", force=True) - page.wait_for_function('window.optionsPressed !== undefined', timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings - page.wait_for_selector('#advanced-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-button", state="visible", timeout=2500) # page.click("#advanced-button", force=True) - page.wait_for_function('window.advancedPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedPressed !== undefined", timeout=2500) page.evaluate("window.advancedPressed([])") - page.wait_for_function('window.changeLogLevel !== undefined', timeout=2500) + page.wait_for_function("window.changeLogLevel !== undefined", timeout=2500) advanced_display: str = page.evaluate( - "window.getComputedStyle(document.getElementById('log-level-select')).display") - assert advanced_display == 'block', "Advanced menu not loaded (selected log level not displayed)" + "window.getComputedStyle(document.getElementById('log-level-select')).display" + ) + assert ( + advanced_display == "block" + ), "Advanced menu not loaded (selected log level not displayed)" # NAV-03: Set log level to DEBUG # Set log level DEBUG @@ -108,22 +122,28 @@ def on_console(msg) -> None: page.evaluate("window.changeLogLevel([0])") page.wait_for_timeout(1000) new_logs = logs[pre_change_log_count:] - assert any("log level changed to: debug" in log["text"].lower() for log in new_logs) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + assert any( + "log level changed to: debug" in log["text"].lower() for log in new_logs + ) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" # Go back to Options menu - page.wait_for_selector('#advanced-back-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-back-button", state="visible", timeout=2500) # page.click("#advanced-back-button", force=True) - page.wait_for_function('window.advancedBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedBackPressed !== undefined", timeout=2500) page.evaluate("window.advancedBackPressed([])") # NAV-04: Navigate to audio sub-menu - page.wait_for_selector('#audio-button', state='visible', timeout=2500) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + page.wait_for_selector("#audio-button", state="visible", timeout=2500) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" # Open audio # page.click("#audio-button", force=True, timeout=1500) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) # Wait for audio scene load and JS eval @@ -131,44 +151,62 @@ def on_console(msg) -> None: gameplay_button_display_in_audio: str = page.evaluate( "window.getComputedStyle(document.getElementById('gameplay-button')).display" ) - assert gameplay_button_display_in_audio == 'none', "Gameplay button should be hidden while audio menu is open" + assert ( + gameplay_button_display_in_audio == "none" + ), "Gameplay button should be hidden while audio menu is open" - audio_display: str = page.evaluate("window.getComputedStyle(document.getElementById('master-slider')).display") - assert audio_display == 'block', "Audio menu not loaded (master-slider not displayed)" - assert any("audio button pressed." in log["text"].lower() for log in logs), "Audio navigation log not found" + audio_display: str = page.evaluate( + "window.getComputedStyle(document.getElementById('master-slider')).display" + ) + assert ( + audio_display == "block" + ), "Audio menu not loaded (master-slider not displayed)" + assert any( + "audio button pressed." in log["text"].lower() for log in logs + ), "Audio navigation log not found" # Navigate back from audio menu - page.wait_for_selector('#audio-back-button', state='visible', timeout=2500) + page.wait_for_selector("#audio-back-button", state="visible", timeout=2500) # page.click("#audio-back-button", force=True, timeout=1500) - page.wait_for_function('window.audioBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") - page.wait_for_timeout(2000) # Wait for audio overlay to hide and main/options overlays to re-show + page.wait_for_timeout( + 2000 + ) # Wait for audio overlay to hide and main/options overlays to re-show # Assert audio overlay is hidden again audio_display_after_back: str = page.evaluate( "window.getComputedStyle(document.getElementById('master-slider')).display" ) - assert audio_display_after_back == 'none', "Audio menu still visible after navigating back from audio menu" + assert ( + audio_display_after_back == "none" + ), "Audio menu still visible after navigating back from audio menu" # Assert main/options overlays are restored options_overlay_display: str = page.evaluate( "window.getComputedStyle(document.getElementById('gameplay-button')).display" ) - assert options_overlay_display == 'block', "Options overlay not restored after exiting audio menu" + assert ( + options_overlay_display == "block" + ), "Options overlay not restored after exiting audio menu" except Exception as e: print(f"Test suite failed: {str(e)}") os.makedirs("artifacts", exist_ok=True) timestamp: int = int(time.time()) - page.screenshot(path=f"artifacts/test_navigation_failure_screenshot_{timestamp}.png") - with open(f"artifacts/test_navigation_failure_console_logs_{timestamp}.txt", "w") as f: + page.screenshot( + path=f"artifacts/test_navigation_failure_screenshot_{timestamp}.png" + ) + with open( + f"artifacts/test_navigation_failure_console_logs_{timestamp}.txt", "w" + ) as f: for log in logs: f.write(f"[{log['type']}] {log['text']}\n") raise finally: if cdp_session: # Stop V8 coverage and save to file (even on failure) - coverage = cdp_session.send("Profiler.takePreciseCoverage")['result'] + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") with open("v8_coverage_navigation_to_audio_test.json", "w") as f: diff --git a/tests/reset_audio_flow_test.py b/tests/reset_audio_flow_test.py index 70dda6c1..f8a10fd9 100644 --- a/tests/reset_audio_flow_test.py +++ b/tests/reset_audio_flow_test.py @@ -25,9 +25,10 @@ v8_coverage_reset_flow_test.json, artifacts/test_reset_failure_*.png/txt """ +import json import os import time -import json + from playwright.sync_api import Page @@ -59,9 +60,13 @@ def on_console(msg) -> None: # Start CDP session for V8 JS coverage (workaround for Python Playwright lacking native coverage API) cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") - cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) - page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) + page.goto( + "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 + ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) @@ -74,182 +79,261 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Open options - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) # page.click("#options-button", force=True) - page.wait_for_function('window.optionsPressed !== undefined', timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings - page.wait_for_selector('#advanced-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-button", state="visible", timeout=2500) # page.click("#advanced-button", force=True) - page.wait_for_function('window.advancedPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedPressed !== undefined", timeout=2500) page.evaluate("window.advancedPressed([])") - page.wait_for_function('window.changeLogLevel !== undefined', timeout=2500) + page.wait_for_function("window.changeLogLevel !== undefined", timeout=2500) advanced_display: str = page.evaluate( - "window.getComputedStyle(document.getElementById('log-level-select')).display") - assert advanced_display == 'block', "Advanced menu not loaded (selected log level not displayed)" + "window.getComputedStyle(document.getElementById('log-level-select')).display" + ) + assert ( + advanced_display == "block" + ), "Advanced menu not loaded (selected log level not displayed)" # Set log level DEBUG pre_change_log_count = len(logs) page.evaluate("window.changeLogLevel([0])") page.wait_for_timeout(1000) new_logs = logs[pre_change_log_count:] - assert any("log level changed to: debug" in log["text"].lower() for log in new_logs) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + assert any( + "log level changed to: debug" in log["text"].lower() for log in new_logs + ) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" # Go back to Options menu - page.wait_for_selector('#advanced-back-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-back-button", state="visible", timeout=2500) # page.click("#advanced-back-button", force=True) - page.wait_for_function('window.advancedBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedBackPressed !== undefined", timeout=2500) page.evaluate("window.advancedBackPressed([])") # Navigate to audio sub-menu - page.wait_for_selector('#audio-button', state='visible', timeout=2500) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + page.wait_for_selector("#audio-button", state="visible", timeout=2500) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" pre_change_log_count = len(logs) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([])") page.wait_for_timeout(5000) # Wait for audio scene load and JS eval - audio_display: str = page.evaluate("window.getComputedStyle(document.getElementById('master-slider')).display") - assert audio_display == 'block', "Audio menu not loaded (master-slider not displayed)" + audio_display: str = page.evaluate( + "window.getComputedStyle(document.getElementById('master-slider')).display" + ) + assert ( + audio_display == "block" + ), "Audio menu not loaded (master-slider not displayed)" new_logs = logs[pre_change_log_count:] - assert any("audio button pressed." in log["text"].lower() for log in new_logs), "Audio navigation log not found" + assert any( + "audio button pressed." in log["text"].lower() for log in new_logs + ), "Audio navigation log not found" # RESET-01: Reset all buses to defaults # Preconditions: Sliders moved, some mutes active # Steps: 1) Adjust multiple sliders 2) Toggle some mutes 3) Press Reset # Expected: Every slider back to 1.0, all mutes off - page.wait_for_function('window.changeMasterVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeMasterVolume !== undefined", timeout=2500) page.evaluate("window.changeMasterVolume([0.5])") - page.wait_for_function('window.changeMusicVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeMusicVolume !== undefined", timeout=2500) page.evaluate("window.changeMusicVolume([0.3])") - page.wait_for_function('window.changeSfxVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeSfxVolume !== undefined", timeout=2500) page.evaluate("window.changeSfxVolume([0.7])") - page.wait_for_function('window.toggleMuteMusic !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteMusic !== undefined", timeout=2500) page.evaluate("window.toggleMuteMusic([0])") - page.wait_for_function('window.toggleMuteMaster !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteMaster !== undefined", timeout=2500) page.evaluate("window.toggleMuteMaster([0])") page.wait_for_timeout(2500) pre_change_log_count = len(logs) - page.wait_for_function('window.audioResetPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioResetPressed !== undefined", timeout=2500) page.evaluate("window.audioResetPressed([])") page.wait_for_timeout(2500) - assert float(page.evaluate("document.getElementById('master-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('music-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('sfx-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('weapon-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('rotors-slider').value")) == 1.0 + assert ( + float(page.evaluate("document.getElementById('master-slider').value")) + == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('music-slider').value")) == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('sfx-slider').value")) == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('weapon-slider').value")) + == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('rotors-slider').value")) + == 1.0 + ) assert page.evaluate("document.getElementById('mute-master').checked") assert page.evaluate("document.getElementById('mute-music').checked") assert page.evaluate("document.getElementById('mute-sfx').checked") assert page.evaluate("document.getElementById('mute-weapon').checked") assert page.evaluate("document.getElementById('mute-rotors').checked") new_logs = logs[pre_change_log_count:] - assert any("audio reset pressed" in log["text"].lower() for log in new_logs), "Reset log not found" - assert any("audio volumes reset to defaults" in log["text"].lower() for log in new_logs), "Reset log not found" + assert any( + "audio reset pressed" in log["text"].lower() for log in new_logs + ), "Reset log not found" + assert any( + "audio volumes reset to defaults" in log["text"].lower() for log in new_logs + ), "Reset log not found" # RESET-02: Reset does not duplicate sliders already default # Preconditions: All at defaults # Steps: Press Reset # Expected: No change, UI stable pre_reset_logs = len(logs) - page.wait_for_function('window.audioResetPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioResetPressed !== undefined", timeout=2500) page.evaluate("window.audioResetPressed([])") page.wait_for_timeout(1500) - assert float(page.evaluate("document.getElementById('master-slider').value")) == 1.0, "Value changed unexpectedly" + assert ( + float(page.evaluate("document.getElementById('master-slider').value")) + == 1.0 + ), "Value changed unexpectedly" new_logs = logs[pre_reset_logs:] - assert not any("error" in log["text"].lower() for log in new_logs), "Unexpected error after reset on defaults" + assert not any( + "error" in log["text"].lower() for log in new_logs + ), "Unexpected error after reset on defaults" # RESET-03: Reset after incomplete changes # Preconditions: Only Master & Rotors changed # Steps: Press Reset # Expected: All buses at defaults - page.wait_for_function('window.changeMasterVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeMasterVolume !== undefined", timeout=2500) page.evaluate("window.changeMasterVolume([0.4])") - page.wait_for_function('window.changeRotorsVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeRotorsVolume !== undefined", timeout=2500) page.evaluate("window.changeRotorsVolume([0.6])") page.wait_for_timeout(1500) pre_change_log_count = len(logs) - page.wait_for_function('window.audioResetPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioResetPressed !== undefined", timeout=2500) page.evaluate("window.audioResetPressed([])") page.wait_for_timeout(1500) - assert float(page.evaluate("document.getElementById('master-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('rotors-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('music-slider').value")) == 1.0 # Unchanged remains default + assert ( + float(page.evaluate("document.getElementById('master-slider').value")) + == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('rotors-slider').value")) + == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('music-slider').value")) == 1.0 + ) # Unchanged remains default new_logs = logs[pre_change_log_count:] - assert any("audio reset pressed" in log["text"].lower() for log in new_logs), "Reset log not found" - assert any("audio volumes reset to defaults" in log["text"].lower() for log in new_logs), "Reset log not found" + assert any( + "audio reset pressed" in log["text"].lower() for log in new_logs + ), "Reset log not found" + assert any( + "audio volumes reset to defaults" in log["text"].lower() for log in new_logs + ), "Reset log not found" # RESET-04: Reset persists after Back navigation # Preconditions: Modified then Reset # Steps: Back → Re-enter Audio # Expected: Defaults remain - page.wait_for_function('window.changeSfxVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeSfxVolume !== undefined", timeout=2500) page.evaluate("window.changeSfxVolume([0.2])") pre_change_log_count = len(logs) - page.wait_for_function('window.audioResetPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioResetPressed !== undefined", timeout=2500) page.evaluate("window.audioResetPressed([])") page.wait_for_timeout(1500) new_logs = logs[pre_change_log_count:] - assert any("audio reset pressed" in log["text"].lower() for log in new_logs), "Reset log not found" - assert any("audio volumes reset to defaults" in log["text"].lower() for log in new_logs), "Reset log not found" + assert any( + "audio reset pressed" in log["text"].lower() for log in new_logs + ), "Reset log not found" + assert any( + "audio volumes reset to defaults" in log["text"].lower() for log in new_logs + ), "Reset log not found" page.evaluate("window.audioBackPressed([])") - page.wait_for_selector('#audio-button', state='visible', timeout=2500) + page.wait_for_selector("#audio-button", state="visible", timeout=2500) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) - assert float(page.evaluate("document.getElementById('sfx-slider').value")) == 1.0, "Reset not persisted after back" + assert ( + float(page.evaluate("document.getElementById('sfx-slider').value")) == 1.0 + ), "Reset not persisted after back" # RESET-05: Rapid Reset clicks # Preconditions: Controls modified # Steps: Click Reset quickly 3× # Expected: UI stays stable with defaults, no JS errors - page.wait_for_function('window.changeMasterVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeMasterVolume !== undefined", timeout=2500) page.evaluate("window.changeMasterVolume([0.5])") page.wait_for_timeout(500) pre_change_log_count = len(logs) for _ in range(3): - page.wait_for_function('window.audioResetPressed !== undefined', timeout=2500) + page.wait_for_function( + "window.audioResetPressed !== undefined", timeout=2500 + ) page.evaluate("window.audioResetPressed([])") page.wait_for_timeout(300) # Rapid - assert float(page.evaluate("document.getElementById('master-slider').value")) == 1.0 + assert ( + float(page.evaluate("document.getElementById('master-slider').value")) + == 1.0 + ) new_logs = logs[pre_change_log_count:] - assert not any("error" in log["text"].lower() for log in new_logs), "JS errors during rapid reset" + assert not any( + "error" in log["text"].lower() for log in new_logs + ), "JS errors during rapid reset" # STATE-01: Reset button state persists in config # Preconditions: After Reset + Save # Steps: Reload game/settings # Expected: Defaults retained for all sliders and mutes pre_change_log_count = len(logs) - page.wait_for_function('window.audioResetPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioResetPressed !== undefined", timeout=2500) page.evaluate("window.audioResetPressed([])") page.wait_for_timeout(1500) new_logs = logs[pre_change_log_count:] - assert any("audio reset pressed" in log["text"].lower() for log in new_logs), "Reset log not found" - assert any("audio volumes reset to defaults" in log["text"].lower() for log in new_logs), "Reset log not found" + assert any( + "audio reset pressed" in log["text"].lower() for log in new_logs + ), "Reset log not found" + assert any( + "audio volumes reset to defaults" in log["text"].lower() for log in new_logs + ), "Reset log not found" # Reload and validate persisted defaults for all audio controls page.reload() page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) - page.wait_for_selector('#options-button', state='visible', timeout=5000) - page.wait_for_function('window.optionsPressed !== undefined', timeout=5000) + page.wait_for_selector("#options-button", state="visible", timeout=5000) + page.wait_for_function("window.optionsPressed !== undefined", timeout=5000) # page.click("#options-button", force=True) page.evaluate("window.optionsPressed([])") - page.wait_for_selector('#audio-button', state='visible', timeout=5000) + page.wait_for_selector("#audio-button", state="visible", timeout=5000) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([])") page.wait_for_timeout(5000) # Sliders should all be at default volume (mirroring RESET-01 expectations) - assert float(page.evaluate("document.getElementById('master-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('music-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('sfx-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('weapon-slider').value")) == 1.0 - assert float(page.evaluate("document.getElementById('rotors-slider').value")) == 1.0 + assert ( + float(page.evaluate("document.getElementById('master-slider').value")) + == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('music-slider').value")) == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('sfx-slider').value")) == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('weapon-slider').value")) + == 1.0 + ) + assert ( + float(page.evaluate("document.getElementById('rotors-slider').value")) + == 1.0 + ) # Mutes should retain their default checked state after reload assert page.evaluate("document.getElementById('mute-master').checked") @@ -263,44 +347,54 @@ def on_console(msg) -> None: # Steps: Navigate other menus # Expected: Other menus unaffected # Navigate back to options menu to access difficulty-slider - page.wait_for_function('window.audioBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") page.wait_for_timeout(2000) # Cache the initial difficulty value to avoid depending on a hardcoded default - initial_difficulty_value = float(page.evaluate("document.getElementById('difficulty-slider').value")) + initial_difficulty_value = float( + page.evaluate("document.getElementById('difficulty-slider').value") + ) pre_change_log_count = len(logs) assert initial_difficulty_value == 1.0, "Unexpected initial difficulty default" # Navigate back to audio menu to test reset isolation - page.wait_for_selector('#audio-button', state='visible', timeout=2500) + page.wait_for_selector("#audio-button", state="visible", timeout=2500) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([])") page.wait_for_timeout(5000) - page.wait_for_function('window.audioResetPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioResetPressed !== undefined", timeout=2500) page.evaluate("window.audioResetPressed([])") page.wait_for_timeout(1500) new_logs = logs[pre_change_log_count:] - assert any("audio reset pressed" in log["text"].lower() for log in new_logs), "Reset log not found" - assert any("audio volumes reset to defaults" in log["text"].lower() for log in new_logs), "Reset log not found" - page.wait_for_function('window.audioBackPressed !== undefined', timeout=2500) + assert any( + "audio reset pressed" in log["text"].lower() for log in new_logs + ), "Reset log not found" + assert any( + "audio volumes reset to defaults" in log["text"].lower() for log in new_logs + ), "Reset log not found" + page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") page.wait_for_timeout(2000) # Later, after audio reset and navigating back to the difficulty menu, # assert the difficulty slider has not changed from its initial value. - assert float(page.evaluate( - "document.getElementById('difficulty-slider').value")) == initial_difficulty_value, "Difficulty reset unexpectedly" + assert ( + float(page.evaluate("document.getElementById('difficulty-slider').value")) + == initial_difficulty_value + ), "Difficulty reset unexpectedly" except Exception as e: print(f"Test suite failed: {str(e)}") os.makedirs("artifacts", exist_ok=True) timestamp: int = int(time.time()) page.screenshot(path=f"artifacts/test_reset_failure_screenshot_{timestamp}.png") - with open(f"artifacts/test_reset_failure_console_logs_{timestamp}.txt", "w") as f: + with open( + f"artifacts/test_reset_failure_console_logs_{timestamp}.txt", "w" + ) as f: for log in logs: f.write(f"[{log['type']}] {log['text']}\n") raise finally: if cdp_session: - coverage = cdp_session.send("Profiler.takePreciseCoverage")['result'] + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") with open("v8_coverage_reset_flow_test.json", "w") as f: diff --git a/tests/volume_sliders_mutes_test.py b/tests/volume_sliders_mutes_test.py index ca5c3679..ac18bd46 100644 --- a/tests/volume_sliders_mutes_test.py +++ b/tests/volume_sliders_mutes_test.py @@ -25,9 +25,10 @@ v8_coverage_volume_sliders_mutes_test.json, artifacts/test_volume_failure_*.png/txt """ +import json import os import time -import json + from playwright.sync_api import Page @@ -59,9 +60,13 @@ def on_console(msg) -> None: # Start CDP session for V8 JS coverage (workaround for Python Playwright lacking native coverage API) cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") - cdp_session.send("Profiler.startPreciseCoverage", {"callCount": True, "detailed": True}) + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) - page.goto("http://localhost:8080/index.html", wait_until="networkidle", timeout=5000) + page.goto( + "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 + ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) page.wait_for_function("() => window.godotInitialized", timeout=5000) @@ -74,33 +79,40 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Open options - page.wait_for_selector('#options-button', state='visible', timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=2500) # page.click("#options-button", force=True) - page.wait_for_function('window.optionsPressed !== undefined', timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings - page.wait_for_selector('#advanced-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-button", state="visible", timeout=2500) # page.click("#advanced-button", force=True) - page.wait_for_function('window.advancedPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedPressed !== undefined", timeout=2500) page.evaluate("window.advancedPressed([])") - page.wait_for_function('window.changeLogLevel !== undefined', timeout=2500) + page.wait_for_function("window.changeLogLevel !== undefined", timeout=2500) advanced_display: str = page.evaluate( - "window.getComputedStyle(document.getElementById('log-level-select')).display") - assert advanced_display == 'block', "Advanced menu not loaded (selected log level not displayed)" + "window.getComputedStyle(document.getElementById('log-level-select')).display" + ) + assert ( + advanced_display == "block" + ), "Advanced menu not loaded (selected log level not displayed)" # Set log level DEBUG pre_change_log_count = len(logs) page.evaluate("window.changeLogLevel([0])") page.wait_for_timeout(1000) new_logs = logs[pre_change_log_count:] - assert any("log level changed to: debug" in log["text"].lower() for log in new_logs) - assert page.evaluate("document.getElementById('audio-button') !== null"), "Audio button not found/displayed" + assert any( + "log level changed to: debug" in log["text"].lower() for log in new_logs + ) + assert page.evaluate( + "document.getElementById('audio-button') !== null" + ), "Audio button not found/displayed" # Go back to Options menu - page.wait_for_selector('#advanced-back-button', state='visible', timeout=2500) + page.wait_for_selector("#advanced-back-button", state="visible", timeout=2500) # page.click("#advanced-back-button", force=True) - page.wait_for_function('window.advancedBackPressed !== undefined', timeout=2500) + page.wait_for_function("window.advancedBackPressed !== undefined", timeout=2500) page.evaluate("window.advancedBackPressed([])") # Navigate to audio sub-menu (use coordinates for Godot-rendered button) @@ -110,180 +122,249 @@ def on_console(msg) -> None: # Open audio pre_change_log_count = len(logs) # page.click("#audio-button", force=True) - page.wait_for_function('window.audioPressed !== undefined', timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([])") page.wait_for_timeout(5000) # Wait for audio scene load - audio_display: str = page.evaluate("window.getComputedStyle(document.getElementById('master-slider')).display") - assert audio_display == 'block', "Audio menu not loaded (master-slider not displayed)" + audio_display: str = page.evaluate( + "window.getComputedStyle(document.getElementById('master-slider')).display" + ) + assert ( + audio_display == "block" + ), "Audio menu not loaded (master-slider not displayed)" new_logs = logs[pre_change_log_count:] - assert any("audio button pressed" in log["text"].lower() for log in new_logs), "Audio navigation log not found" + assert any( + "audio button pressed" in log["text"].lower() for log in new_logs + ), "Audio navigation log not found" # VOL-01: Adjust Master volume slider pre_change_log_count = len(logs) - page.wait_for_function('window.changeMasterVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeMasterVolume !== undefined", timeout=2500) page.evaluate("window.changeMasterVolume([0.5])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("master volume changed to: 0.5" in log["text"].lower() for log in new_logs), "Master volume change log not found" + assert any( + "master volume changed to: 0.5" in log["text"].lower() for log in new_logs + ), "Master volume change log not found" value = page.evaluate("document.getElementById('master-slider').value") - assert value == '0.5', f"Master slider value not set to 0.5, got {value}" + assert value == "0.5", f"Master slider value not set to 0.5, got {value}" # VOL-02: Mute / unmute Master # MUTE pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteMaster !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteMaster !== undefined", timeout=2500) page.evaluate("window.toggleMuteMaster([0])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("master is muted" in log["text"].lower() for log in new_logs), "Master mute log not found" + assert any( + "master is muted" in log["text"].lower() for log in new_logs + ), "Master mute log not found" checked = page.evaluate("document.getElementById('mute-master').checked") assert not checked, "Master mute not toggled to muted" # UNMUTE pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteMaster !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteMaster !== undefined", timeout=2500) page.evaluate("window.toggleMuteMaster([1])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("applied loaded master volume to audioserver: 0.5" in log["text"].lower() for log in new_logs), "Master mute log not found" + assert any( + "applied loaded master volume to audioserver: 0.5" in log["text"].lower() + for log in new_logs + ), "Master mute log not found" checked = page.evaluate("document.getElementById('mute-master').checked") assert checked, "Master mute not toggled to unmuted" - assert any("master mute button toggled to: true" in log["text"].lower() for log in new_logs), "Master unmute log not found" + assert any( + "master mute button toggled to: true" in log["text"].lower() + for log in new_logs + ), "Master unmute log not found" # VOL-03: Adjust Music volume slider pre_change_log_count = len(logs) - page.wait_for_function('window.changeMusicVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeMusicVolume !== undefined", timeout=2500) page.evaluate("window.changeMusicVolume([0.3])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] value = page.evaluate("document.getElementById('music-slider').value") - assert value == '0.3', f"Music slider value not set to 0.3, got {value}" - assert any("music volume changed to: 0.3" in log["text"].lower() for log in new_logs), "Music volume change log not found" + assert value == "0.3", f"Music slider value not set to 0.3, got {value}" + assert any( + "music volume changed to: 0.3" in log["text"].lower() for log in new_logs + ), "Music volume change log not found" # VOL-04: Mute / unmute Music # MUTE pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteMusic !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteMusic !== undefined", timeout=2500) page.evaluate("window.toggleMuteMusic([0])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("music is muted" in log["text"].lower() for log in new_logs), "Music mute log not found" + assert any( + "music is muted" in log["text"].lower() for log in new_logs + ), "Music mute log not found" checked = page.evaluate("document.getElementById('mute-music').checked") assert not checked, "Music mute not toggled to muted" # UNMUTE pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteMusic !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteMusic !== undefined", timeout=2500) page.evaluate("window.toggleMuteMusic([1])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("applied loaded music volume to audioserver: 0.3" in log["text"].lower() for log in new_logs), "Music unmute log not found" + assert any( + "applied loaded music volume to audioserver: 0.3" in log["text"].lower() + for log in new_logs + ), "Music unmute log not found" checked = page.evaluate("document.getElementById('mute-music').checked") assert checked, "Music mute not toggled to unmuted" - assert any("music mute button toggled to: true" in log["text"].lower() for log in new_logs), "Music unmute log not found" + assert any( + "music mute button toggled to: true" in log["text"].lower() + for log in new_logs + ), "Music unmute log not found" # VOL-05: Adjust SFX volume slider pre_change_log_count = len(logs) - page.wait_for_function('window.changeSfxVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeSfxVolume !== undefined", timeout=2500) page.evaluate("window.changeSfxVolume([0.8])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] value = page.evaluate("document.getElementById('sfx-slider').value") - assert value == '0.8', f"SFX slider value not set to 0.8, got {value}" - assert any("sfx volume level changed: 0.8" in log["text"].lower() for log in new_logs), "SFX volume change log not found" - assert any("sfx volume level in audiomanager: 0.8" in log["text"].lower() for log in new_logs), "SFX volume change log not found" - assert any("saved volumes to config" in log["text"].lower() for log in new_logs), "SFX volume change log not found" + assert value == "0.8", f"SFX slider value not set to 0.8, got {value}" + assert any( + "sfx volume level changed: 0.8" in log["text"].lower() for log in new_logs + ), "SFX volume change log not found" + assert any( + "sfx volume level in audiomanager: 0.8" in log["text"].lower() + for log in new_logs + ), "SFX volume change log not found" + assert any( + "saved volumes to config" in log["text"].lower() for log in new_logs + ), "SFX volume change log not found" # VOL-06: Mute / unmute SFX # MUTE pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteSfx !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteSfx !== undefined", timeout=2500) page.evaluate("window.toggleMuteSfx([0])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("sfx is muted" in log["text"].lower() for log in new_logs), "SFX mute log not found" + assert any( + "sfx is muted" in log["text"].lower() for log in new_logs + ), "SFX mute log not found" checked = page.evaluate("document.getElementById('mute-sfx').checked") assert not checked, "SFX mute not toggled to muted" # UNMUTE pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteSfx !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteSfx !== undefined", timeout=2500) page.evaluate("window.toggleMuteSfx([1])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("applied loaded sfx volume to audioserver: 0.8" in log["text"].lower() for log in new_logs), "SFX unmute log not found" + assert any( + "applied loaded sfx volume to audioserver: 0.8" in log["text"].lower() + for log in new_logs + ), "SFX unmute log not found" checked = page.evaluate("document.getElementById('mute-sfx').checked") assert checked, "SFX mute not toggled to unmuted" - assert any("sfx mute button toggled to: true" in log["text"].lower() for log in new_logs), "SFX unmute log not found" + assert any( + "sfx mute button toggled to: true" in log["text"].lower() + for log in new_logs + ), "SFX unmute log not found" # VOL-07: Adjust Weapon volume slider pre_change_log_count = len(logs) - page.wait_for_function('window.changeWeaponVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeWeaponVolume !== undefined", timeout=2500) page.evaluate("window.changeWeaponVolume([0.2])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] value = page.evaluate("document.getElementById('weapon-slider').value") - assert value == '0.2', f"Weapon slider value not set to 0.2, got {value}" - assert any("weapon volume level changed: 0.2" in log["text"].lower() for log in new_logs), "Weapon volume change log not found" + assert value == "0.2", f"Weapon slider value not set to 0.2, got {value}" + assert any( + "weapon volume level changed: 0.2" in log["text"].lower() + for log in new_logs + ), "Weapon volume change log not found" # VOL-08: Mute / unmute Weapon pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteWeapon !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteWeapon !== undefined", timeout=2500) page.evaluate("window.toggleMuteWeapon([0])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("weapon is muted" in log["text"].lower() for log in new_logs), "Weapon mute log not found" + assert any( + "weapon is muted" in log["text"].lower() for log in new_logs + ), "Weapon mute log not found" checked = page.evaluate("document.getElementById('mute-weapon').checked") assert not checked, "Weapon mute not toggled to muted" pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteWeapon !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteWeapon !== undefined", timeout=2500) page.evaluate("window.toggleMuteWeapon([1])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("applied loaded sfx_weapon volume to audioserver: 0.2" in log["text"].lower() for log in new_logs), "Weapon unmute log not found" + assert any( + "applied loaded sfx_weapon volume to audioserver: 0.2" + in log["text"].lower() + for log in new_logs + ), "Weapon unmute log not found" checked = page.evaluate("document.getElementById('mute-weapon').checked") assert checked, "Weapon mute not toggled to unmuted" - assert any("weapon mute button toggled to: true" in log["text"].lower() for log in new_logs), "Weapon unmute log not found" + assert any( + "weapon mute button toggled to: true" in log["text"].lower() + for log in new_logs + ), "Weapon unmute log not found" # VOL-09: Adjust Rotors volume slider pre_change_log_count = len(logs) - page.wait_for_function('window.changeRotorsVolume !== undefined', timeout=2500) + page.wait_for_function("window.changeRotorsVolume !== undefined", timeout=2500) page.evaluate("window.changeRotorsVolume([0.9])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] value = page.evaluate("document.getElementById('rotors-slider').value") - assert value == '0.9', f"Rotors slider value not set to 0.9, got {value}" - assert any("rotors volume level changed: 0.9" in log["text"].lower() for log in new_logs), "Rotors volume change log not found" + assert value == "0.9", f"Rotors slider value not set to 0.9, got {value}" + assert any( + "rotors volume level changed: 0.9" in log["text"].lower() + for log in new_logs + ), "Rotors volume change log not found" # VOL-10: Mute / unmute Rotors pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteRotors !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteRotors !== undefined", timeout=2500) page.evaluate("window.toggleMuteRotors([0])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("rotors is muted" in log["text"].lower() for log in new_logs), "Rotors mute log not found" + assert any( + "rotors is muted" in log["text"].lower() for log in new_logs + ), "Rotors mute log not found" checked = page.evaluate("document.getElementById('mute-rotors').checked") assert not checked, "Rotors mute not toggled to muted" pre_change_log_count = len(logs) - page.wait_for_function('window.toggleMuteRotors !== undefined', timeout=2500) + page.wait_for_function("window.toggleMuteRotors !== undefined", timeout=2500) page.evaluate("window.toggleMuteRotors([1])") page.wait_for_timeout(2500) new_logs = logs[pre_change_log_count:] - assert any("applied loaded sfx_rotors volume to audioserver: 0.9" in log["text"].lower() for log in new_logs), "Rotors unmute log not found" + assert any( + "applied loaded sfx_rotors volume to audioserver: 0.9" + in log["text"].lower() + for log in new_logs + ), "Rotors unmute log not found" checked = page.evaluate("document.getElementById('mute-rotors').checked") assert checked, "Rotors mute not toggled to unmuted" - assert any("rotors mute button toggled to: true" in log["text"].lower() for log in new_logs), "Rotors unmute log not found" + assert any( + "rotors mute button toggled to: true" in log["text"].lower() + for log in new_logs + ), "Rotors unmute log not found" except Exception as e: print(f"Test suite failed: {str(e)}") os.makedirs("artifacts", exist_ok=True) timestamp: int = int(time.time()) - page.screenshot(path=f"artifacts/test_volume_failure_screenshot_{timestamp}.png") - with open(f"artifacts/test_volume_failure_console_logs_{timestamp}.txt", "w") as f: + page.screenshot( + path=f"artifacts/test_volume_failure_screenshot_{timestamp}.png" + ) + with open( + f"artifacts/test_volume_failure_console_logs_{timestamp}.txt", "w" + ) as f: for log in logs: f.write(f"[{log['type']}] {log['text']}\n") raise finally: if cdp_session: # Stop V8 coverage and save to file (even on failure) - coverage = cdp_session.send("Profiler.takePreciseCoverage")['result'] + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") with open("v8_coverage_volume_sliders_mutes_test.json", "w") as f: From d14707e50d6893f20d8b6b9f73cd09ed374b98ff Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Fri, 6 Mar 2026 21:02:21 -0800 Subject: [PATCH 22/33] Resolve a startup target instead of treating cold starts as load failures. Because project.godot now boots straight into this scene, Globals.next_scene is still empty on a cold launch (scripts/globals.gd Line 32). The only helper that populates it, Globals.load_scene_with_loading(), runs later during in-app navigation (scripts/globals.gd Lines 280-290). So this branch fires on every startup, logs an error, and skips threaded loading of the initial menu entirely. --- scripts/splash_screen.gd | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd index aba3b40a..d4ad42ec 100644 --- a/scripts/splash_screen.gd +++ b/scripts/splash_screen.gd @@ -12,6 +12,9 @@ extends Control +const DEFAULT_STARTUP_SCENE := "res://scenes/main_menu.tscn" + +var resolved_next_scene: String = "" var loader_progress: float = 0.0 # Current smoothed progress value. var min_load_time: float = 1.0 # Minimum splashing time in seconds for visibility. var load_start_time: float = 0.0 # Timestamp when splashing starts. @@ -33,13 +36,19 @@ func _ready() -> void: if OS.has_feature("web"): min_load_time = 3.0 - if Globals.next_scene == "": - Globals.log_message("Next scene path is empty!", Globals.LogLevel.ERROR) - load_failed = true - return + #if Globals.next_scene == "": + # Globals.log_message("Next scene path is empty!", Globals.LogLevel.ERROR) + # load_failed = true + # return + + # Resolve a startup target instead of treating cold starts as load failures. + resolved_next_scene = ( + Globals.next_scene if Globals.next_scene != "" else DEFAULT_STARTUP_SCENE + ) # Start background loading with sub-threads to fix 50% quirk. - var err: int = ResourceLoader.load_threaded_request(Globals.next_scene, "", true) + # var err: int = ResourceLoader.load_threaded_request(Globals.next_scene, "", true) + var err: int = ResourceLoader.load_threaded_request(resolved_next_scene, "", true) if err != OK: Globals.log_message("Failed to start splashing screen: " + str(err), Globals.LogLevel.ERROR) load_failed = true From f1e104c468d1b16b2dea1fb5075b536d29393e6b Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 6 Mar 2026 21:03:31 -0800 Subject: [PATCH 23/33] Update README.md Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bdf4a62..6ac3b81a 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ to user input devices: ### Known Limitations -* Some complex menu flows may still rely on mouse until additional +* Some complex menu flows may still rely on the mouse until additional focus neighbors are defined. * Modifier-aware remapping requires explicit key+modifier press for unique bindings. From a1d7a76bf34b6127b46dc50f81cdaf53c9c484ca Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Fri, 6 Mar 2026 21:06:37 -0800 Subject: [PATCH 24/33] issue: Avoid duplicate CodeRabbit entries and inconsistent naming in the bots list. Coderabbit AI and CodeRabbit AI both link to https://github.com/coderabbitai. Keep only one entry and standardize on a single name for this bot. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 6ac3b81a..ab6652b1 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,6 @@ You can play this game on [Itch.io](https://ikostan.itch.io/sky-lock-assault) 7. [Signing Setup for GitHub Desktop](/files/docs/Signing_Setup_GitHub_Desktop.md) 8. BOTS: - [Dependabot](https://docs.github.com/en/code-security/dependabot) - - [Coderabbit AI](https://github.com/coderabbitai) - [Snyk](https://docs.snyk.io/) - [Sourcery AI](https://docs.sourcery.ai/) - [CodeRabbit AI](https://github.com/coderabbitai) From 100c866ed6d7723ad0950436459ad79ad3e85754 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Fri, 6 Mar 2026 21:09:00 -0800 Subject: [PATCH 25/33] Update splash_screen.gd --- scripts/splash_screen.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd index d4ad42ec..04e92986 100644 --- a/scripts/splash_screen.gd +++ b/scripts/splash_screen.gd @@ -40,7 +40,7 @@ func _ready() -> void: # Globals.log_message("Next scene path is empty!", Globals.LogLevel.ERROR) # load_failed = true # return - + # Resolve a startup target instead of treating cold starts as load failures. resolved_next_scene = ( Globals.next_scene if Globals.next_scene != "" else DEFAULT_STARTUP_SCENE From e196fa92cfc254bd66b85ae4e351263454bbbfbf Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Fri, 6 Mar 2026 22:55:35 -0800 Subject: [PATCH 26/33] New HTML page --- assets/gears.svg | 157 ++++++++++++++++++++++++++++++++++++++++ assets/gears.svg.import | 43 +++++++++++ custom_shell.html | 89 ++++++++++++++++------- 3 files changed, 261 insertions(+), 28 deletions(-) create mode 100644 assets/gears.svg create mode 100644 assets/gears.svg.import diff --git a/assets/gears.svg b/assets/gears.svg new file mode 100644 index 00000000..19a12907 --- /dev/null +++ b/assets/gears.svg @@ -0,0 +1,157 @@ + + + + +Created by potrace 1.15, written by Peter Selinger 2001-2017 + + + + + + + + + + + + + + diff --git a/assets/gears.svg.import b/assets/gears.svg.import new file mode 100644 index 00000000..43ff4e25 --- /dev/null +++ b/assets/gears.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cm16bsb57nind" +path="res://.godot/imported/gears.svg-1ead9a7dc40c4307289978dee7a08f79.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/gears.svg" +dest_files=["res://.godot/imported/gears.svg-1ead9a7dc40c4307289978dee7a08f79.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/custom_shell.html b/custom_shell.html index cbb211aa..592b5deb 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -54,27 +54,7 @@ align-items: center; justify-content: center; z-index: 20; - } - #loading img { - max-width: 60%; - max-height: 60%; - } - #progress-bar { - width: 50%; - height: 30px; - background-color: #333; - margin-top: 10px; - border: 1px solid #555; - } - #progress { - width: 0%; - height: 100%; - background-color: black; - } - #status { - color: black; - margin-top: 10px; - font-size: clamp(1.5rem, 4vw, 2.5rem); + padding: 5px; } /* Retry button style (visible override) */ #retry-button { @@ -106,6 +86,33 @@ height: 50px; transform: translate(-50%, -50%); } + + /* Rotation Definitions */ + + /* This is the fix: it forces the origin to the center of each individual group */ + .gear-group { + transform-box: fill-box; + transform-origin: center; + animation-iteration-count: infinite; + animation-timing-function: linear; + } + + /* Directions: CW, CCW, CW, CCW, CW */ + .g1 { animation-name: spin-cw; animation-duration: 9.5s; } + .g2 { animation-name: spin-ccw; animation-duration: 16.5s; } + .g3 { animation-name: spin-cw; animation-duration: 9.5s; } + .g4 { animation-name: spin-ccw; animation-duration: 6s; } + .g5 { animation-name: spin-cw; animation-duration: 3s; } + + @keyframes spin-cw { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } + } + + @keyframes spin-ccw { + from { transform: rotate(0deg); } + to { transform: rotate(-360deg); } + } @@ -114,13 +121,39 @@

From a17b86c0f3f24bf958f475742a96f1746c36e80b Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 7 Mar 2026 22:15:05 -0800 Subject: [PATCH 27/33] Playwright tests fixes --- tests/audio_flow_test.py | 4 ++-- tests/back_flow_test.py | 4 ++-- tests/difficulty_flow_test.py | 2 +- tests/load_main_menu_test.py | 6 +++--- tests/navigation_to_audio_test.py | 6 +++--- tests/reset_audio_flow_test.py | 4 ++-- tests/volume_sliders_mutes_test.py | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/audio_flow_test.py b/tests/audio_flow_test.py index 8e18156e..bd8f2df7 100644 --- a/tests/audio_flow_test.py +++ b/tests/audio_flow_test.py @@ -82,9 +82,9 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Open options - page.wait_for_selector("#options-button", state="visible", timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=4500) # page.click("#options-button", force=True) - page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=4500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings diff --git a/tests/back_flow_test.py b/tests/back_flow_test.py index ef26f0e1..9ef210a6 100644 --- a/tests/back_flow_test.py +++ b/tests/back_flow_test.py @@ -79,9 +79,9 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Navigate to options menu - page.wait_for_selector("#options-button", state="visible", timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=4500) # page.click("#options-button", force=True, timeout=2500) - page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=4500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings diff --git a/tests/difficulty_flow_test.py b/tests/difficulty_flow_test.py index cf29b9c8..7c5725d5 100644 --- a/tests/difficulty_flow_test.py +++ b/tests/difficulty_flow_test.py @@ -87,7 +87,7 @@ def on_console(msg: Any) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Check element present - page.wait_for_selector("#options-button", state="visible", timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=4500) assert page.evaluate("document.getElementById('options-button') !== null") # Check invisible (opacity 0) diff --git a/tests/load_main_menu_test.py b/tests/load_main_menu_test.py index 08e82d99..e9c8b462 100644 --- a/tests/load_main_menu_test.py +++ b/tests/load_main_menu_test.py @@ -89,11 +89,11 @@ def on_console(msg) -> None: # Since the DOM overlays are now central to the web flow, # consider also asserting that the main-menu overlay elements are present # and visible (similar to navigation_to_audio_test): - page.wait_for_selector("#start-button", state="visible", timeout=2500) + page.wait_for_selector("#start-button", state="visible", timeout=4500) assert page.evaluate("document.getElementById('start-button') !== null") - page.wait_for_selector("#options-button", state="visible", timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=4500) assert page.evaluate("document.getElementById('options-button') !== null") - page.wait_for_selector("#quit-button", state="visible", timeout=2500) + page.wait_for_selector("#quit-button", state="visible", timeout=4500) assert page.evaluate("document.getElementById('quit-button') !== null") except Exception as e: diff --git a/tests/navigation_to_audio_test.py b/tests/navigation_to_audio_test.py index 4d71e823..ad6b0ee9 100644 --- a/tests/navigation_to_audio_test.py +++ b/tests/navigation_to_audio_test.py @@ -79,11 +79,11 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # NAV-01: Verify main menu overlays exist and are configured - page.wait_for_selector("#start-button", state="visible", timeout=2500) + page.wait_for_selector("#start-button", state="visible", timeout=4500) assert page.evaluate("document.getElementById('start-button') !== null") - page.wait_for_selector("#options-button", state="visible", timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=4500) assert page.evaluate("document.getElementById('options-button') !== null") - page.wait_for_selector("#quit-button", state="visible", timeout=2500) + page.wait_for_selector("#quit-button", state="visible", timeout=4500) assert page.evaluate("document.getElementById('quit-button') !== null") opacity: str = page.evaluate( "window.getComputedStyle(document.getElementById('options-button')).opacity" diff --git a/tests/reset_audio_flow_test.py b/tests/reset_audio_flow_test.py index f8a10fd9..dae14c5a 100644 --- a/tests/reset_audio_flow_test.py +++ b/tests/reset_audio_flow_test.py @@ -79,9 +79,9 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Open options - page.wait_for_selector("#options-button", state="visible", timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=4500) # page.click("#options-button", force=True) - page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=4500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings diff --git a/tests/volume_sliders_mutes_test.py b/tests/volume_sliders_mutes_test.py index ac18bd46..4cb013a3 100644 --- a/tests/volume_sliders_mutes_test.py +++ b/tests/volume_sliders_mutes_test.py @@ -79,9 +79,9 @@ def on_console(msg) -> None: assert "SkyLockAssault" in page.title(), "Title not found" # Open options - page.wait_for_selector("#options-button", state="visible", timeout=2500) + page.wait_for_selector("#options-button", state="visible", timeout=4500) # page.click("#options-button", force=True) - page.wait_for_function("window.optionsPressed !== undefined", timeout=2500) + page.wait_for_function("window.optionsPressed !== undefined", timeout=4500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings From bed6c2fb93132ffcbbb6d4cc64ca50b63dc540d1 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 7 Mar 2026 22:21:25 -0800 Subject: [PATCH 28/33] Update difficulty_flow_test.py --- tests/difficulty_flow_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/difficulty_flow_test.py b/tests/difficulty_flow_test.py index 7c5725d5..d7dea2b9 100644 --- a/tests/difficulty_flow_test.py +++ b/tests/difficulty_flow_test.py @@ -72,12 +72,12 @@ def on_console(msg: Any) -> None: ) page.goto( - "http://localhost:8080/index.html", wait_until="networkidle", timeout=3000 + "http://localhost:8080/index.html", wait_until="networkidle", timeout=5000 ) # 1. Wait for the engine to actually start the splash scene page.wait_for_timeout(5000) # Wait for Godot engine init (ensures 'godot' object is defined) - page.wait_for_function("() => window.godotInitialized", timeout=3000) + page.wait_for_function("() => window.godotInitialized", timeout=5000) # Verify canvas and title to ensure game is initialized canvas = page.locator("canvas") From 038439c8f1c3e43333c215347be74b92611285db Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 7 Mar 2026 22:31:29 -0800 Subject: [PATCH 29/33] Update back_flow_test.py --- tests/back_flow_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/back_flow_test.py b/tests/back_flow_test.py index 9ef210a6..53b6dfc1 100644 --- a/tests/back_flow_test.py +++ b/tests/back_flow_test.py @@ -189,11 +189,13 @@ def on_console(msg) -> None: page.wait_for_function("() => window.godotInitialized", timeout=5000) # Navigate to options menu page.wait_for_selector("#options-button", state="visible", timeout=5000) - page.click("#options-button", force=True) + # page.click("#options-button", force=True) + page.wait_for_function("window.optionsPressed !== undefined", timeout=4500) + page.evaluate("window.optionsPressed([])") # Navigate to audio menu page.wait_for_selector("#audio-button", state="visible", timeout=5000) # page.click("#audio-button", force=True) - page.wait_for_function("window.audioPressed !== undefined", timeout=2500) + page.wait_for_function("window.audioPressed !== undefined", timeout=4500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) From face01a88916a30c5ef57f09e50112ac8ffa6569 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 7 Mar 2026 22:59:13 -0800 Subject: [PATCH 30/33] Update custom_shell.html --- custom_shell.html | 48 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index 592b5deb..2a951fce 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -56,19 +56,6 @@ z-index: 20; padding: 5px; } - /* Retry button style (visible override) */ - #retry-button { - opacity: 1; /* Visible */ - pointer-events: auto; /* Clickable */ - color: white; /* Text color */ - background-color: #f00; /* Red button for error theme */ - border: 1px solid #fff; - padding: 10px 20px; - font-size: 18px; - cursor: pointer; - margin-top: 20px; - display: none; /* Hidden initially */ - } #audio-back-button { display: none; top: 80%; @@ -202,37 +189,22 @@ var engine = new Engine($GODOT_CONFIG); // Official placeholder for config // Start Godot engine (async for stability) - engine.startGame({ - onProgress: function(current, total) { - var percentage = total > 0 ? Math.round((current / total) * 100) : 0; - document.getElementById('progress').style.width = percentage + '%'; - document.getElementById('progress-bar').setAttribute('aria-valuenow', percentage); - document.getElementById('status').innerText = 'Loading: ' + percentage + '%'; - } - }).then(() => { + engine.startGame().then(() => { console.log("Godot engine started successfully!"); - // Hide the loading UI and set aria-hidden to prevent screen readers from announcing stale content + + // Hide the loading UI var loadingDiv = document.getElementById('loading'); - loadingDiv.style.display = 'none'; - loadingDiv.setAttribute('aria-hidden', 'true'); - window.godotInitialized = true; // Signal for Playwright waits + if (loadingDiv) { + loadingDiv.style.display = 'none'; + loadingDiv.setAttribute('aria-hidden', 'true'); + } + window.godotInitialized = true; }).catch(err => { console.error("Error starting Godot:", err); - // Update UI to persistent error state with retry - document.getElementById('status').innerText = 'Error loading game: ' + (err.message || 'Unknown error. Please try again or refresh the page.'); - document.getElementById('progress').style.backgroundColor = 'red'; // Visual failure indicator - document.getElementById('progress-bar').setAttribute('aria-valuenow', '0'); // Reset ARIA for error state - document.getElementById('progress-bar').style.display = 'none'; // Hide progress bar on error - document.getElementById('retry-button').style.display = 'block'; // Show retry button - // window.godotInitialized remains false implicitly - // No aria-hidden here since error state should remain visible/accessible for recovery + // Fallback if engine fails to boot + alert('Error loading SkyLockAssault. Please refresh.'); }); - // Retry button handler (reloads page to reset everything) - document.getElementById('retry-button').onclick = () => { - location.reload(); - }; - // Hook buttons/sliders to exposed Godot functions document.getElementById('controls-button').onclick = () => window.controlsPressed([]); document.getElementById('audio-button').onclick = () => window.audioPressed([]); From 284b2c4220a6e535f8e0c3a22d9149512f8382fb Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sat, 7 Mar 2026 23:03:56 -0800 Subject: [PATCH 31/33] Create old_custom_shell.html --- old_custom_shell.html | 233 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 old_custom_shell.html diff --git a/old_custom_shell.html b/old_custom_shell.html new file mode 100644 index 00000000..0d8c9282 --- /dev/null +++ b/old_custom_shell.html @@ -0,0 +1,233 @@ + + + + + + SkyLockAssault (DEBUG) + + + + + + + +
+ Loading... + +
+
+
+

Loading...

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1603e5f83e6f3785886016d9e83c61d7734ebb4c Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sun, 8 Mar 2026 21:53:00 -0700 Subject: [PATCH 32/33] Update splash_screen.gd --- scripts/splash_screen.gd | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/scripts/splash_screen.gd b/scripts/splash_screen.gd index 04e92986..9e96c055 100644 --- a/scripts/splash_screen.gd +++ b/scripts/splash_screen.gd @@ -28,34 +28,6 @@ var label_text: String = "Loading: " @onready var label: Label = $Label # Label for displaying loading status. -# Starts threaded loading of the next scene from Globals. -func _ready() -> void: - load_start_time = Time.get_ticks_msec() / 1000.0 - - # Give more breathing room on Web (threaded progress unreliable per Godot 4.5). - if OS.has_feature("web"): - min_load_time = 3.0 - - #if Globals.next_scene == "": - # Globals.log_message("Next scene path is empty!", Globals.LogLevel.ERROR) - # load_failed = true - # return - - # Resolve a startup target instead of treating cold starts as load failures. - resolved_next_scene = ( - Globals.next_scene if Globals.next_scene != "" else DEFAULT_STARTUP_SCENE - ) - - # Start background loading with sub-threads to fix 50% quirk. - # var err: int = ResourceLoader.load_threaded_request(Globals.next_scene, "", true) - var err: int = ResourceLoader.load_threaded_request(resolved_next_scene, "", true) - if err != OK: - Globals.log_message("Failed to start splashing screen: " + str(err), Globals.LogLevel.ERROR) - load_failed = true - else: - Globals.log_message("Splashing screen started successfully.", Globals.LogLevel.DEBUG) - - # Polls loading status and updates UI. Changes scene when loaded. # Eliminated fake_progress; relies on real ResourceLoader progress. func _process(_delta: float) -> void: From d4dd13f09b19c54b6f956a476bb3f4177f5f3729 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sun, 8 Mar 2026 22:00:26 -0700 Subject: [PATCH 33/33] Update back_flow_test.py --- tests/back_flow_test.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/back_flow_test.py b/tests/back_flow_test.py index 53b6dfc1..5cb05162 100644 --- a/tests/back_flow_test.py +++ b/tests/back_flow_test.py @@ -80,13 +80,11 @@ def on_console(msg) -> None: # Navigate to options menu page.wait_for_selector("#options-button", state="visible", timeout=4500) - # page.click("#options-button", force=True, timeout=2500) page.wait_for_function("window.optionsPressed !== undefined", timeout=4500) page.evaluate("window.optionsPressed([])") # Go to Advanced settings page.wait_for_selector("#advanced-button", state="visible", timeout=2500) - # page.click("#advanced-button", force=True) page.wait_for_function("window.advancedPressed !== undefined", timeout=2500) page.evaluate("window.advancedPressed([])") page.wait_for_function("window.changeLogLevel !== undefined", timeout=2500) @@ -111,7 +109,6 @@ def on_console(msg) -> None: # Go back to Options menu page.wait_for_selector("#advanced-back-button", state="visible", timeout=2500) - # page.click("#advanced-back-button", force=True) page.wait_for_function("window.advancedBackPressed !== undefined", timeout=2500) page.evaluate("window.advancedBackPressed([])") # Navigate to audio sub-menu @@ -120,7 +117,6 @@ def on_console(msg) -> None: "document.getElementById('audio-button') !== null" ), "Audio button not found/displayed" pre_change_log_count = len(logs) - # page.click("#audio-button", force=True) page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([])") page.wait_for_timeout(5000) # Wait for audio scene load and JS eval @@ -159,7 +155,6 @@ def on_console(msg) -> None: # Re-enter audio for next tests page.wait_for_selector("#audio-button", state="visible", timeout=2500) - # page.click("#audio-button", force=True) page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) @@ -174,7 +169,6 @@ def on_console(msg) -> None: page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") page.wait_for_selector("#audio-button", state="visible", timeout=2500) - # page.click("#audio-button", force=True) page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) @@ -189,12 +183,10 @@ def on_console(msg) -> None: page.wait_for_function("() => window.godotInitialized", timeout=5000) # Navigate to options menu page.wait_for_selector("#options-button", state="visible", timeout=5000) - # page.click("#options-button", force=True) page.wait_for_function("window.optionsPressed !== undefined", timeout=4500) page.evaluate("window.optionsPressed([])") # Navigate to audio menu page.wait_for_selector("#audio-button", state="visible", timeout=5000) - # page.click("#audio-button", force=True) page.wait_for_function("window.audioPressed !== undefined", timeout=4500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000) @@ -209,7 +201,6 @@ def on_console(msg) -> None: page.wait_for_function("window.audioBackPressed !== undefined", timeout=2500) page.evaluate("window.audioBackPressed([])") page.wait_for_selector("#audio-button", state="visible", timeout=2500) - # page.click("#audio-button", force=True) page.wait_for_function("window.audioPressed !== undefined", timeout=2500) page.evaluate("window.audioPressed([0])") page.wait_for_timeout(5000)