From 30bcc3459b397d4cdebde54b5136ab8e8daf02f7 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Thu, 20 Aug 2026 11:22:53 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D1=82=D0=BB=D0=B0=D1=81=20=D0=A2=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8:=20=D0=B7=D0=B0=D0=BF=D0=B5=D1=87=D1=91=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=BD=D0=B0=D0=B1=D0=BE=D1=80=20=D0=B2?= =?UTF-8?q?=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D1=81=D0=BF=D1=80=D0=B0=D0=B9?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=20=D1=81=D1=82=D1=80=D0=B0=D0=B6=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Оригинал кладёт спрайт дважды — прозрачным блитом в x и XOR-блиттером в x+1; пакетный блит так не умеет, поэтому результат запечён упаковщиком. Две половины, как и у оригинала: sk* — кадры вне боя (спрайты Кида), sf* — кадры 150..189 (SHADOW.DAT, тоже графика Кида). 251 спрайт, 32 EMM-страницы, палитра 16 цветов в 0xA0..0xAF. Закрывает BUG-SHADOW-SET: раньше тип 4 уходил в guard_names, и Тень в бою дралась серым стражем. Грабля: kid.pal заливает все 256 записей и затирает слоты Тени — палитра вынесена в pop_shadow_pal_apply рядом с pop_bg_pal_apply. Проверено в MAME на 6-м уровне: силуэт с контуром, как в оригинале. --- applications/PoP/docs/shadow_atlas_plan.md | 39 ++- applications/PoP/poc/res/shadow/sf0.atl | Bin 0 -> 9467 bytes applications/PoP/poc/res/shadow/sf1.atl | Bin 0 -> 10462 bytes applications/PoP/poc/res/shadow/sf2.atl | Bin 0 -> 8837 bytes applications/PoP/poc/res/shadow/sf3.atl | Bin 0 -> 1969 bytes applications/PoP/poc/res/shadow/sk0.atl | Bin 0 -> 7586 bytes applications/PoP/poc/res/shadow/sk1.atl | Bin 0 -> 8209 bytes applications/PoP/poc/res/shadow/sk10.atl | Bin 0 -> 5580 bytes applications/PoP/poc/res/shadow/sk11.atl | Bin 0 -> 6277 bytes applications/PoP/poc/res/shadow/sk12.atl | Bin 0 -> 6587 bytes applications/PoP/poc/res/shadow/sk13.atl | Bin 0 -> 9936 bytes applications/PoP/poc/res/shadow/sk14.atl | Bin 0 -> 6074 bytes applications/PoP/poc/res/shadow/sk15.atl | Bin 0 -> 5606 bytes applications/PoP/poc/res/shadow/sk16.atl | Bin 0 -> 3213 bytes applications/PoP/poc/res/shadow/sk17.atl | Bin 0 -> 7696 bytes applications/PoP/poc/res/shadow/sk18.atl | Bin 0 -> 5856 bytes applications/PoP/poc/res/shadow/sk19.atl | Bin 0 -> 6077 bytes applications/PoP/poc/res/shadow/sk2.atl | Bin 0 -> 8421 bytes applications/PoP/poc/res/shadow/sk20.atl | Bin 0 -> 6636 bytes applications/PoP/poc/res/shadow/sk21.atl | Bin 0 -> 7708 bytes applications/PoP/poc/res/shadow/sk22.atl | Bin 0 -> 10504 bytes applications/PoP/poc/res/shadow/sk23.atl | Bin 0 -> 10055 bytes applications/PoP/poc/res/shadow/sk24.atl | Bin 0 -> 6198 bytes applications/PoP/poc/res/shadow/sk25.atl | Bin 0 -> 6587 bytes applications/PoP/poc/res/shadow/sk26.atl | Bin 0 -> 5649 bytes applications/PoP/poc/res/shadow/sk27.atl | Bin 0 -> 968 bytes applications/PoP/poc/res/shadow/sk3.atl | Bin 0 -> 7287 bytes applications/PoP/poc/res/shadow/sk4.atl | Bin 0 -> 10075 bytes applications/PoP/poc/res/shadow/sk5.atl | Bin 0 -> 8092 bytes applications/PoP/poc/res/shadow/sk6.atl | Bin 0 -> 5732 bytes applications/PoP/poc/res/shadow/sk7.atl | Bin 0 -> 4330 bytes applications/PoP/poc/res/shadow/sk8.atl | Bin 0 -> 9386 bytes applications/PoP/poc/res/shadow/sk9.atl | Bin 0 -> 8118 bytes applications/PoP/roomtest/BUGS_OPEN.md | 23 ++ applications/PoP/roomtest/Makefile | 16 +- applications/PoP/roomtest/pop_cdraw.c | 31 +- applications/PoP/roomtest/pop_shadow.c | 88 ++++++ applications/PoP/roomtest/pop_shadow.h | 55 ++++ applications/PoP/roomtest/pop_shadow_atlas.h | 71 +++++ applications/PoP/roomtest/roomtest_cold.c | 5 + applications/PoP/toolchain/pop_pack_shadow.py | 292 ++++++++++++++++++ 41 files changed, 610 insertions(+), 10 deletions(-) create mode 100644 applications/PoP/poc/res/shadow/sf0.atl create mode 100644 applications/PoP/poc/res/shadow/sf1.atl create mode 100644 applications/PoP/poc/res/shadow/sf2.atl create mode 100644 applications/PoP/poc/res/shadow/sf3.atl create mode 100644 applications/PoP/poc/res/shadow/sk0.atl create mode 100644 applications/PoP/poc/res/shadow/sk1.atl create mode 100644 applications/PoP/poc/res/shadow/sk10.atl create mode 100644 applications/PoP/poc/res/shadow/sk11.atl create mode 100644 applications/PoP/poc/res/shadow/sk12.atl create mode 100644 applications/PoP/poc/res/shadow/sk13.atl create mode 100644 applications/PoP/poc/res/shadow/sk14.atl create mode 100644 applications/PoP/poc/res/shadow/sk15.atl create mode 100644 applications/PoP/poc/res/shadow/sk16.atl create mode 100644 applications/PoP/poc/res/shadow/sk17.atl create mode 100644 applications/PoP/poc/res/shadow/sk18.atl create mode 100644 applications/PoP/poc/res/shadow/sk19.atl create mode 100644 applications/PoP/poc/res/shadow/sk2.atl create mode 100644 applications/PoP/poc/res/shadow/sk20.atl create mode 100644 applications/PoP/poc/res/shadow/sk21.atl create mode 100644 applications/PoP/poc/res/shadow/sk22.atl create mode 100644 applications/PoP/poc/res/shadow/sk23.atl create mode 100644 applications/PoP/poc/res/shadow/sk24.atl create mode 100644 applications/PoP/poc/res/shadow/sk25.atl create mode 100644 applications/PoP/poc/res/shadow/sk26.atl create mode 100644 applications/PoP/poc/res/shadow/sk27.atl create mode 100644 applications/PoP/poc/res/shadow/sk3.atl create mode 100644 applications/PoP/poc/res/shadow/sk4.atl create mode 100644 applications/PoP/poc/res/shadow/sk5.atl create mode 100644 applications/PoP/poc/res/shadow/sk6.atl create mode 100644 applications/PoP/poc/res/shadow/sk7.atl create mode 100644 applications/PoP/poc/res/shadow/sk8.atl create mode 100644 applications/PoP/poc/res/shadow/sk9.atl create mode 100644 applications/PoP/roomtest/pop_shadow.c create mode 100644 applications/PoP/roomtest/pop_shadow.h create mode 100644 applications/PoP/roomtest/pop_shadow_atlas.h create mode 100644 applications/PoP/toolchain/pop_pack_shadow.py diff --git a/applications/PoP/docs/shadow_atlas_plan.md b/applications/PoP/docs/shadow_atlas_plan.md index c4a12a5..59d97fa 100644 --- a/applications/PoP/docs/shadow_atlas_plan.md +++ b/applications/PoP/docs/shadow_atlas_plan.md @@ -1,6 +1,7 @@ # Атлас Тени — разбор и план -Дата: 2026-08-20. Статус: **разбор сделан, код не писали.** +Дата: 2026-08-20. Статус: **СДЕЛАНО** (Ш0-Ш3), проверено на 6-м уровне; +уровни 4 и 12 ещё не прогонялись. Задача: сейчас Тень рисуется спрайтами Кида (вне боя) и спрайтами стража (в бою) как есть, поэтому от Кида она не отличается. В оригинале её вид @@ -225,3 +226,39 @@ XOR идёт по тому, что УЖЕ на экране, то есть ре `curr_guard_color` у не-стражей равен 0 (`seg002:183`). Ветку `pop_guard_set_palette` для типа 4 звать нельзя — она затрёт палитру Тени палитрой стража. + +--- + +# 8. Как сделали (2026-08-20) + +- `toolchain/pop_pack_shadow.py` — запекает обе половины, собирает + 16-цветную палитру гибридом (получилось 5 частых точно + 11 кластеров + хвоста), пишет `poc/res/shadow/sk0..27.atl`, `sf0..3.atl` и + `roomtest/pop_shadow_atlas.h`. Итог: **251 спрайт, 32 EMM-страницы, + 225 178 Б**. +- `roomtest/pop_shadow.c/.h` (банк 8) — загрузка. **Грузим один раз при + старте**, а не по уровням: страниц EMM с запасом, а забыть перезагрузку + на границе легко — ровно так и появился BUG-SHADOW-SET. +- `pop_cdraw.c` — одна ветка выбора атласа; заодно брызги урона теперь + берут атлас отдельным указателем (`spl`), потому что у оригинала они + всегда из «своего» chtab, а у Тени кадр может прийти из другой + половины набора. + +## Грабля, стоившая одного прогона + +Набор загрузился, силуэт нарисовался правильной формы — и **целиком +чёрный**. Причина: `gfx_pal_fload("KID\\kid.pal")` заливает ВСЕ 256 +записей палитры и затирает любые слоты, выставленные до него. Ровно та +же беда уже была с тайлсетом — сразу за этим вызовом стоит +`pop_bg_pal_apply`. Поэтому палитра Тени вынесена в отдельный +`pop_shadow_pal_apply()` и зовётся там же, а не внутри загрузки атласов. + +**Правило на будущее: любой новый набор палитровых слотов красится ПОСЛЕ +kid.pal, рядом с pop_bg_pal_apply.** + +## Что осталось + +- прогнать уровень 4 (рождение из зеркала) и 12 (бой — там работает + вторая половина набора, `sf*`); +- записать в `impl_diff.md` расхождение из §2 (кайма в один пиксель по + левым кромкам на НЕчёрном фоне). diff --git a/applications/PoP/poc/res/shadow/sf0.atl b/applications/PoP/poc/res/shadow/sf0.atl new file mode 100644 index 0000000000000000000000000000000000000000..313de95f48f0d08f8924b15af4aa6f56bb13e937 GIT binary patch literal 9467 zcmdT|OO6{i5N#tc>`hi##eiYJ8Q6>>Bra8moLZZ)yo$zrs?nL?HfM-`sVIEpTEBT_yeE+ ze0wkLr|&+!WBbqV@1_5@cXuDyW_dNeoGzEc1?7bQhZ)t=d_rZO4=4Pb&Ma@IH-Oc0 zuGOYCH|^S-&1va7tJ6978fX@$vjK!_K8p>hT`n*LHnz~D1=T<%eXz}^nTBLR2Zzam zXU!Hh?Ls#UA&gk0Q@oOk1SXz#PMlj&ErB$i7^U0dknM!RC($U@k~$itpBC*j3f`yt0%@MjGP-uI$LNp53;ct3VC!!6CDubI_qQvJgPqbd}fQfC?p4B5XHhP zIR%oqcz`J`By4)8?Bepn0>$kM@@eo3w=@2xg&B{8kEuT^^};^ZZZ{($6eV80GPK zdw61}C$AKa$27zC2LX~i`?c-}c0B(seQMZP76IUiKN!r?%m|P?IKXhbjF_KgW7k-y z?LBWmACsjv%8LO6rJ1Ci00Rw}8pu2o)Ig5M8o_HZU(Wo|K^kO1A}{B7l$Wtbk+_*e zKUB4kkemqu9pwAwAZFwB{!>YkQws!ScNo)bII7k!xA&N&+_Pw5eJ=W%j+H!!K3qOd zKTM6^7i!imdo{r7kg#jkY1U^3JL_r=ZipJ=ef5d8CtF&3T1Di_l*LkIrin;vEy|K1 z0RcI&QD;ac2uoWb=21w(W@g?D2ygrvLdK(M$ghqb=~qOsQXkEqWF93VD3CsSY&}mk zK+vTM$;ql37KUOHDMIT6d)XGCRL$M zwsI;OnDW7tqIe$V*Sj!*c&s9ui$>7L!n9_v!?diMxg<2RuyS zf?qmHzX;C)v$@p%-iyLsamj&ii?F@K!;&%A8avXKR77AS0C+7M%BzcDnHdQw099K# zBz7rWjR95()NuR_{?c^mau>}a>^yN$0W^&CR7OyeA(M2to9a_$%QRt$j)|luSU5D*}&9 z#D^TG|3bB^LaXss2D@UeO54wVxW1r4eJ}4_If7r!O@;ER zS)*Pv+mNo9`CWh>^RX-&YB0sPvxKm5xw2TO#KD!wuPIyc`}cWc6gQ^adwkFBj3PG{*Jkh#ik>ZUz$U6Ny}g! z+@6i|1^OBht+|ot){K0^JBn{lk=*Z||85sAJ;aX4{xOs!n%qU%i$4&JU6%{_?RcK; zCN_9eru*4n*(DFRr{M*y>Yd0XcXtp1Z^$#Sqs<(1a-Vhe0q^D9)^JPqYGdsN_w0~c z{5a%vlU;OwkRGECRDW!>JEHsl?UE!7t>0Mra?ok`x|DT%y#b7DEXDSJ`*KjQlqk+U ziXN4V#VW-N#8%JB;V4az`zr~48;MQ`oXP#Zz$5XLUN}rKh3l!T7c^D$Q1KmN_XQ+m zp+&rm!TRjJKrsBkND&A9vHJpc6SJN5Z0tbNQ!#56NN!Gg<>}ww}pFIpz?C39$)08I9as%ez81nQm z=&lQ)e~u@O@aXI4@&E&#ux>lkLkJ3PrBSm+1FLGbUp?%D=?Y6Ey#c~0iY~o6Aidd( z(El#dK++|kERQirrGGpuCOp!A#KQYvoV)466o=Zc-=My5Tvb;gM`ryXsrP17qn?RG z8n|X%C9~B%%-*)(ra>`s<)11|) zWmTF6r%7{Idfp J=RW<|{RKdNSTtV z)ez>V2zTl8^fHwty~^tL58r?H&8LUIzdRjozJB%UaQOX`n>W0E``O#qydFQlyW{oO zFK%yn{prg)x&C-_C-~pKdMD%b@aFLKVSBN%?lB!%d~g}Vj>m>1Vtc0w7BmQH1xu0dfFE`)_EDBQahz@}7~ zEWY0y-W+y`{_H?Ju)A}wSOCswH(k}B9CaMDK`5k4gDFTJ`j$!NDTd+H(#jGgp~WnX zDv>B*AQ4icD51kJ;tKpwtfRBS1xcbJmBUKD3=(-0EI&p>S&#}e6K$?X zYOWZJ#!y!|O3Mb}{ZMC$EEJOinW21?aS@MZh2j9jqo|CFOp1e}EZoFs8KO=i{Ztr3 zHLFB3o@|5lRC$`+&h`P9LAGTehfRNOdW3Ut+cH$!-L#KKM!4zhn|xsPy=@OA@9p9B zq3!<{+bL0qez+d(uFKcU<31`yhxS5Kn0EjoHo{zM#Sj%C%qv_1utAKwlQ_m@syz!h zisIdI8NPwghxl056|iMo&ZJ9Q0FanPcRebQwFfF(wZ>6D(kf}_DFCrh&x{N)!zzGS z2dO1j>{V8E(al+2Rm4JrSJ{9Q2~)uoZu_VVB42Sx>eWX@c7Q-2)e<{LwgAc3d=S_7 zB}|TtqDLSE%Ok0fkuH|d3q&;0jJV$ArSL?TFllC%DWGzeZXw??D)+FzLN2-TejxVH zWNdeJn&~=Y#}sgt6Opm6&wSXBBTsZ3N!DczXY^+)jZc~0OMM949qtZ;v8HP*U>UTd zatSnXnb?7pB?>lXOUDB^YDqVr9dgWe#a$4D%n_G&q?ow|GQOE+URic%G^l21d^}dU zIh`-*by;Z4P>q;txAc(4Ud^K~2otkXhykpF#z-Q>UX&$)B*O@zy7r+>N%M+C$BRr4 z6H@Y=pYf5(`}-t;LCs74D>@g&l=-N8n#kIH>_HI_X_TslQEEt)P#VGp!`zS|M5!5M z4uQ-FXB!J6XGhd_05c%UC@vuP^sQ@+LHsYjDKd4O$Q-QGrI}B2HB_R@{s1G7tlPuw zp4%5CO zkBu5p9l-&xaR^~rn4C{hK58QpMlqgO)=aP+F~N*XHAG@+qG-g-1nsK#W$IaDziaX_ zF)N7G-Ajqt%+^0S?gDbb<}^4Ex$$&8z}&%mccJY0kx&Y0LHN!pn&&n%g0A2!rEMAz zrp{E42r`5?EMNVRWaX)FCP%ncTtR|Q0rBEi0-~&2h-C$0xPh!EjZ^_N8#46QYFgpO zEKT3q_Ym}jFWq$Gje4N^)7wgF2sq3jgSkXHKJ*zIL)PWh!~9ToDn4y%;on~)BeVR zw)vuZ_maP2wvPU1+Pey|s7LbIpx9?37^t#aSdis?IcvMmQV6E{Op+1+x@8{c*VBOcFbt(oh;sK=P4Sx@~;_MUi{#UkMIGPk7{Klx>4H8f{BP z(Fh7=>0nrZPUwF|C0|R{x5df6yY0D>?6}On@)P3YG=CJ>bw=~EqjkKrCj#y`g!WB*;SV?IHOYbF-46o+K)tcNL@^4L{J`aU#$# zN)vOa!jdpMh=d6komzEocbR?m4?Y`yc;8lmoQ!yc&5D6 z_v{q|g8*|6V@&iP*TDu-4*+vz?}#EX^`B$|q5!kU#AVQAA2}V2UG#`JE^%f|?)MBN iTe3;v-H~!72x?y1!wMcT>4CTdn$cj|)D)@l*6|0Qqx%T} literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sf2.atl b/applications/PoP/poc/res/shadow/sf2.atl new file mode 100644 index 0000000000000000000000000000000000000000..1f0b6d41538f81225c2ed8af0233b46f9b72fb28 GIT binary patch literal 8837 zcmeHMOOE735UrlY2qZQv*dR3;sb^Nbnj>%nB+kK^aM`YQbyEX(LEM2AXE5)@CmoT_ zDtpn4SWHS?&dMbOA3uI|`0vx@@c7~G?r`|~?VCG(|9SiP!0(^mJjnOg zZ||l3ukZBx_4n_j{+A!_-xJ65c=&Lb|97e1qfxg5)py+{6)@W%U~YqsNH;)iRzL&P z>qw+On>AI6n|yD@w_lG=L4^n+=h@g7It3XK5v?R3C5n)zd7c)yfL7W*z4X($NEIcG zXz4kl*YEh7XJKc~v<{fLd-)A5=lLsfu_-;@5`q@ zCZSj$GRTGNiOnz2{}dq=XntbiAajaS>6AXEfJ|B`?s&Oe0)p8FN_Ag0+BMYWg3e(> zw)Qr-Otfq08prQcwu8|%w2F9$rS7?^Q6lISsTvY;6}8%wCkvYUHA?%ah?6=aA5GDaK6f^1>(nKHCIVAm}t z&p@`Mu@tyYQ<*sw8lueA0Ywu0H86#F97lj!q6!2V!Q7(RiIJI##Em>L8=~Z3YjjOj zn9USHrA93rFE|$(vmBv2W`~fCGXd+ifqT=P5ZebQ z$hLPL(y1nKzi1SH){Zr{dOi%B@?1-67T;U@An#hfL}i|IaZnOq;?U)wjVFP6-%KNi z@kRI2Fpj1kFwukPfxRrS454ynbb=gs85p%EVMvt0INpzvh#N+s8^$tk_fw zUuGYBlOG$o&*MTrpz6zA&cX@AjrgD`p$l5ggDo=4t z224ZxPvsnx=>J`(`j&8YDKEDMj}<^y13tIynFR)(`UOf^(FFOPk`5KPAFpm2Vec( zfcQTfG6W|t!cR>epGbt`l_Q@R2FGCCB|3@gKdNmw#$ppjE``IbXV4lnF*0FHV!Pcq zSWifg-X51Qkbp@9L^m-6q5wVtJ+l*&yoJcu#P#+BG$8~Mg#QflI1WdIMhrMLBGD%j z2jGjA5s_64N&W7pD0eIofle9Jaw`#ZEnWe}n0)G3(?}FI3<_#AYZU_#g{&P@=p;+M ztXgOZS#e9to(U}>E5bs#k>z^g_2y<8yUY0|0F7A2O*`g-ZGd>m?)&@0`@85wP4Fk;PV_&Y-SZ&(+spxdnD{0FSwb|NPE?^-6|@ly zeni*C%QS-w*y%8dOVPU$&%P?rl%b*c6m?96S&>>SgV$-xno^R0%bc!Ih148!Kspy8 zSPK&Ql&w(Em2CnFjU|iz<#-{eG+fJcm*;CurT#*Lubggaw2aK`1_q0{MZ>$cF#Zc= Cvtzsf literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sf3.atl b/applications/PoP/poc/res/shadow/sf3.atl new file mode 100644 index 0000000000000000000000000000000000000000..5c54e5a33d1d145261f854128ff1b40186944ac8 GIT binary patch literal 1969 zcmcJP%WcCj42EU&P;Zdj1LWQjxflMNxvrjmh>TMX1Fms(L7yQ&rHSvw( zyyIjfL{2c%9zs3>WLgWtG8d8a0O|;=VhIHk`Nldq*U*Osp{;@`oS9CdFv&Eeaty<5 z!5(t(e%Vn3xsZUsD8%_V!9|6xKe{=A_0U?);YElJ-|S_pa;9o%r8jycT_Z8 z;z~x(AG`BF5FCPy9zGk30nu3@{+9p% literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk0.atl b/applications/PoP/poc/res/shadow/sk0.atl new file mode 100644 index 0000000000000000000000000000000000000000..00d2e3526d6588b0e7b143fe4fe4c6fed2dec426 GIT binary patch literal 7586 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 literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk11.atl b/applications/PoP/poc/res/shadow/sk11.atl new file mode 100644 index 0000000000000000000000000000000000000000..c573db602d38b2ead23872b96e092b9b92b12d26 GIT binary patch literal 6277 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 R1#Vy zvgM))0b3OLI2_KK8ItD-F^RZ?zZnY?_Ym>`+@KO{Irqw z-+ta~`TqCQ(=(sH{_M-?PmTDtEwW z5d*|dP!W+1!!U>rry-Li-U5au8Wu=sjQ`%yOl*rxh%Nt32!iRG0yT#1u9erVuOTQ z9chH>GqoeuMCsUYT_@w`>*l6qOy^_MuaMd;;j-7f{;Mf_*KLD$s!}4 zgK`Ny9vU3v2=qce3?>;xVkFCkX(tP+zyirwv!6WZ<=P?tnbUCc{lGLaE7+`&E$ZG< zQ-=Ywo<%4@$-`l#m4oGu08QMo%w#P{69hph)dd2`Q%G4er_*8}M?jAt!$2XnrAcOa z+kNPYm`5J#0Z1wL-OuKE4CVH+Vardm>T<6UvxZWut)kL}F;-bxoODR=+!a$m1o=kx zTNI&X>-Y>TRT*2O9s98hhu}bL;nZGDsR3Ym@R@Nv7^|u(FGx@&8DQEK{zIZriJ>o4 zTUdyqfI&5`?Is8?!+E}H#n>BpA$j&*pPS}TTifTgYPES!eScufq;su{dRYbGBt_7* zD6m&nDKWu=Sqp+Gm}F@S`Y6i`6#gg|0G@0mz9!ijd9sC?eKXITDaT47|qk+gz zXa4gjhud9%a4+Fo`IqVAwCR4Wqd1eW_iBJ*ALbBtRUf4vg zAks-+EPU|Y?jBmle>p11Q1wo|!7?vW8UzQf-pav$i z=V~KK!jdF*B!9X3bNO7mlH(be^rFLw0cBjbWb%wankIpA=0FHWxOFJkujOi7Y0^JP u=hzF4D!(1h_SzIs#)>hRc?ObkIEb literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk15.atl b/applications/PoP/poc/res/shadow/sk15.atl new file mode 100644 index 0000000000000000000000000000000000000000..80217bb469876e404242527ff9177da6572c0d30 GIT binary patch literal 5606 zcmcInTdpHD5bZ$-frNyFM$w/V#fLH-L7>O0|$FjQ9-N{YJg)Om@=A2Ux+evpW zKUhlJu9wTMQ)TD3FTei$ZTJ7TYqxv*=1tfA@zrj}{>#_zp4eZ%d3w+Or|+iYsY0d-O!Jh!|C~OXsCVP|Ak*oJM@=7K?>S|jdQeF zlblj;Hjcg~cme4gbFOwYk#Rns=Xn?=Ep|NCnxhdHH#Vvt%`2yQSJOvy$6j7*o!O{Vr-w39io?~G_UQ;{$u$>UHn;CL+ik+GcTv%4M9wA1l`fakhK9%7G9 z^)9F;6uc15AQ&TrLyWNw0OWEY4T6A$17mMXKQ9sS^le&(z63ag&H0R{3@Drh3JVk? z#!Xrcb(ELoUH7yV=h)6lzY2jZ5NyDJn`n}`tfLJ*N0QfcDg;C<-^qpi<>e}^{E+T| zIG;^aU((5VVJd1;e~vF6GbDo-17jNiEStu{aRgYB#d$-c#Y;hfyI0u0c)A?|PA`H2 zQPgksuyAS3^62`e4i(KxA8O@v@nlxZBZa!l|e zQ8<~fc_PR?b?>`yY^C1-(Kd{>fwT=J>Gb^yn8*?SYQNo0Z1?i=_qhR1RbwtySag6= zJ0AO&xzr>TsyH3N$|$;L%5g|vCu$&y+TxD0Ob5D><%BU9C@Eo3=9B9_p5d%yOd`#gJ*sWgnOH*oIP)I!a|p)`h184#icJcK({shBZ>woJ6%D#y-&r!X z?>;=j98@-8N8ai!#)Z(}?d@~K7-DXeGD&cw>kyP#Lt(L1ji4tW<}p<~D{sVNaGR2K zJRSi@G~?nrsOlEXK#yz{MP8S4&1UH8HxTXQ(wy|O*iytu0M$i3#>Zp)Tf4gK8WT>|mpF3XZZ&EC&7=j}j>`|e}clJ91Z za^i7PJkE;E8{RxnI95wD`CgtkHV<89#>Uy`=D#8WcUu(!xdC(*Wq^%Mx1H95btr2% z;l`7rd^y^2a|(U1gNOK%8M?;itr-o`H($&aljH0OGNLp@jH9ZO#UJk4Ayvz>!ZiJQ zPN0V}auWjDOuc>gXwqM|hEz|aT@%`IRGF5VvsiTBeR?fhQs=?oVMamk;Y~xkIEwAtMgos+9JjE2 z>zIH{3~fOq#~XZLj^U4SP;Ppq8E>FkqIx=}*2TLU-LM5YIG7Y4HClgT|GWJRufu;e;;$gI8z>5wQw@C;F z%9d9;(4q6;HeoW9WLQ2hX)v)i;y7Xt!XmlBmM6n>s)~3ZTA8C~RA`qzWpL2SiGTi?HD3q9Uj86gy3A>QB<|kk& zxU#61j>q15f^D*Id7Fa69uM`V-;33!iWa zyeA3cX_=a+)OB|^^TM(JyBya|^L9c7Mf+G%S~Mxr;PaS`jw^5+w8egJK3401U1}5) z%EuMT-=eZE*m(zlxom}@)s1t+kT}(d#~lZuT^fu|7*gsmm$w*_)>M-+peR{H^2uD= zRBOsCBtyo;cF}A`S>;&oA;TJ)XJ&t@GLn{X)0#xym*Sa%+Wo$2S!gS=%`St6cJk!P zHsj4TC+3?=O3sL}aCLu7D_kq4ay;T@W11<$O-!Y6FwN^b(n{H%qf}nSc*v@K6fM*6 zj8rxYXBMR#IKZ%VPBpH$Uo5QE7O)wm{8>YhaVWD$Fn}q^#xxj3rfBM8Z2^uPK;9@I z6p6x@3o|>W3&*tba{Vh`Pe;|AWLmujOBn7m7LBxc|4&f^y%<0A8rfi!t!sgr{tIgO zAh>}k6Uu!y-P;5^^c;F^)dC z17ec~j|PRD@gHzNJKRWhWXT+Xz5Ztk_@KHrmJB9IshIwZLgQ{u5{?7N;@w=f{3HGs DJ%3bj literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk17.atl b/applications/PoP/poc/res/shadow/sk17.atl new file mode 100644 index 0000000000000000000000000000000000000000..86e63a6f439926bc96952166a7bc755ed0a4004e GIT binary patch literal 7696 zcmd5>OOD(&5S5XQ7Xc=VF%Vlz*Xs`tA9(-Y z`?qpG{&+9=zaH*B^FHm(@M&0I&Zcv&!T~JCag6I4y6)mQ&mqj~6gutz3SuKZTdl@u zAcfXp0A5(S{)!t-xqI2 z(q8~f+@ZPBv@Hz{CzalwfB$pwHbzYMoO><~IrWcp^1Q|;8b{35Y8$J%3n_vB+o^H3z_8H@7iHBb_kC)?k#JC*#V)|W=`lacS^19k5 zO$`vfXX+>vOsJq8G*+IaTLzj>fod6*JedSJnbLhfVM2}6CtA}JX2UU?7?gT|1qFbo4#Jr#hDw1b#uq%4=OP&3J6}-2 zP$f`j_=L)OZ%FVE7U+cw0pAj%5_pU$a97+-IsgGzO9(xQ%jGCp1&9XE7^e39@U6At zOvfPCXY5ogkaefL9cqR2=va5KIzW~mG--L!AEbc#iXtV1`EJB0Y`W8W?h}MhmsS%P)X_}uZcR@I?q-;vQA0rG@>^aPg(cO3l=?lbs7tK z5_O`a*eb=v={Cn>IA#ZihpK##t`gJk%2^N!o6fFxZo8X(lxIiGRqUw|U?NYnc^nRG zI0)(nO*Q~mREJKBX_L^wfV-AseUKzuzfVT+Tnx)F`?;$?B9cESk4GvX*h3YNm5lbg zEhw0?ypk#VuszQ!8SHCZ0|3d2!ZMInGL#C}0Dye^lT^v0iKCN~DnLciZA}Ky6|Zav zrYJWn86s>RrQh=U1-H2O;YtRNv9%KuEQY`xQn~ek%VPJZ^Hi*Nupu!kBSY9+taq>< zF)L9l5XjZ6D4U1*BF@Jvc%UOUWM>R1{V;qOPC}1iXIfo4Am)f9&!q{{6k#cC>!HpK zWxoD zVA_RYhS@BWFvfZ@E~(n6#jMu3+mhnDQf%Y%061?7c1hm_<|BlsZ6U@D>pRcX*RBpT zgfQEHIZD4QaAswpHl1YjI;No~;d@5Zl}zrMO=B0snQG=-`Q~vYB>LQP9)o*3yy(`Z zA1)t9CtjRJ&8)U2fbL8RsTEC8u%H7*scp2FKyXL%4sMQH&|VjW%?8qXGK(;5nJRSF zTt+p-Aa#@lRoUp|6^XssFwD8iH&e+JayWU`23hF}=H!=)9b55S{#-{2y2=aop##8$ zMhGX)S1*|YBpd0kMp&!DrXK=VXL;c)H&IxVG%~v0e+4sEV(Ahme6PH&pVL|W$>wgQ z#m#fQh*$9cIO~_osqZ9Ct%c?5%XPhf+3)=;W2@il3|6>ng5M0WRyC_1E$K|Fa8086 zgcTr6e2wN>Xgz8D2yZ)X`qmfx)5ZNVT|z-lWHiaCnTf_oXMTr;of_Hb?BusvnVm#~ z1AG_Oq$ixApn9~Wi5fq3G3nnI)CtOkvEs}fyzLpPt89@hgKcXnSGBpo(;r|m@3$Pq z*u3A|5rC05^S&qPI`UVAP8PXC#PI}*Iv{V{4W9>p^?!84yC zDJHqh;ZgZho78`i^+mSrx~YOI7-0Mt(-OjwaiVccve}=f&M7Q~*VEZrd$NcWYgU6= PK1WScQnjc$$=&)Nll2r? literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk18.atl b/applications/PoP/poc/res/shadow/sk18.atl new file mode 100644 index 0000000000000000000000000000000000000000..07498bab3e16679765b75245eeeae844628a008c GIT binary patch literal 5856 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 Kb+ty}2fP7GXg(GQJGvit35AthDRX4l& zkSGlt`(Oe);-gq>l3h(o``4ep{qn5)`svy|fB)o3*FF30#XXY z*mW#f1o5ln9BzEdB)1xL$5T_D0~@^x`#R``=Zz_!ITiNXoiYJpF8LIQGaME>bu#JL zj@lNE+&g#V*{k7lgbE#05xWgg01_NICe(|c(?LWOvQiL$pd2=micNH&Ji$j$G`4xw zg8{(O=P-J4;pvg~gp{#~L=rBFRxK#E9OQ-@g19#_bSXzkg9%$onP`E>s|S6YimbYnD~~ic2p%h($-WwtbCeP2E8wjpPF(J zHHE7?X4RWodW07@+u^CN3!4ne$|QaM8W0OhvRoORbHa zVO#2+AA^y>yHjbvrgKsNtO6w6Ov`YDCW#`%Xe!$2-Dt9VAra|N20tr!U*$6Jt&@?(5w)b4%9F#1vv+92T}d6*0Ta{N=gW7wxijxNUkDuB;b0 zeS47`drcU!XeR@2o7~`-%Jx}rn^$g=q`*2GQW z9vT4X3yyUPv49A1m4%$e7lFY`9Dk7-6!2p@qCm|ceTqLy1Aioy0BX5Rh1dx8wK7~G zHvoJP11zGRBY3&DVoC+!~1x;#`l>IOnhOz|fW^3E>K^R2A58b=YE54D;er$)@cIUFcKDR_nV77Kjt+>IOFGTad zMoJTD(%7;-;5wS%GE05a)dWf_lvCu*9*6@Z5Qi2#F3_Jy- z9?uJmadoE%)#J`<5YqS?BnwQeh_B|f1uud2jgS`b6Grhmg`hA01=C|g##xD7aeO-! z*20dmGa_j&%`fF5jeVX>4Jqe~A;zwl0%(EpHA)=JWtepmV$#`AcFs$-^s9%90)4D6 zhRF>m^FCH%-b5RwIdNj*xxPVTpp99{XxynCj4bpHrsaDaBPR8%O_TM8vo&)}OMJ^n z*Pmj|dXv?XW_uvM{9HG_b_x@{u)O!!0NHa2r(Fy#kb4*en7#ks%i65phs_>&d7l0Q DlqCo^ literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk20.atl b/applications/PoP/poc/res/shadow/sk20.atl new file mode 100644 index 0000000000000000000000000000000000000000..6b1e0f7bacffc45e74c6881f2519336419258458 GIT binary patch literal 6636 zcmc&&+l}Nl5S)WQY#1B6Sz zcsveEIO~|3fEmZ4&5YnjHb*O?W0q{qS0{cPA*SXz!jHujc%hNvj?~?F%xEVRl;`Ct zvW&1dz|!;6^YhdB%$d^QwK~T5Fbw4+9xo?G&DMeFNfz>2u!mAk9fD}Axet0=*VE|~ zA>2H`D0cv_E}O3;oR)H%Rboxng8=QuQit;v`%b;~C@ei5*O1L#)eM%e|{O+9d{Xn^oQXpkZs(*sy)5Zf7kd6+4iSM{*2IOEg@t~d06L&{`h zUi!DmWb@vt4N!67^=Ei*u*5t1_v^4w!F54|3c7+Y$4L*!L}xW3oUDgEtWian$cqyr zk%g=WreCHsMkHTZ4=cDyL`tRQG|C9|Kx=0kkemA?mDp4diJA)b6WQby^`Vr9Yz-AD z%jSw6TG?oQ=*de&?PWytuv?oi0Nlg|2G@gcltI}XCRq=hO@!O$u#p2SJA@Gy7fU%mKr}7c?M+G20GOB?iF%Yd^^!^)IxkNzGX=Osp^NJibE1a} zeXCSScKk?yE)ndF%~K59R2XW115`qMTQ(vumCfEv?tw}D zdG}UzHAK&*+UJII?NIvVpBd;1`lex)SE@ga+4o4+D*}$Nj7J=9G1nfwhe`3Ifjl^v zl<14j5ExuJgm(yHb)s`zEU2plqaa8RA$oaiO&HDvVML!FC5cKXg-{W3_)Ay!ou6_H zNf^=3VhnRydqFUafaoudQh#v`uS)c}j1O!v9uELYY?bI^QwBl$YF^5Sr2(gdHin;y zpDGY>i)=v~(jt4J37Ohd^B7MLq8=`|@-mI)$7!OIwSJBKukTfLdCtkaws?-1tgn1{ z3$lhTOCyYEg>7Y14GWAVnCTcnV9|qq$C(}gVG4LKu`v^x2!we?fl$2=Q4=cZ0*tc3 z^V0%dKo2_vad4`#5v!^PogY`8qe?k+QC&mjm=RQ}NNk!jKQBw@Aq3&_QzX}RdC66a z6Sd_+asu!odXO;`r=*Jf_W}=o>Vd-vq84onwn()^LqiR$bc#Wz$mHr8Kha`=!JmuL!3Mb zzb`I$1(nn^ddebEjquN};Vj@>gn|?#b@e050FECw>`rT=6s%bO8}bKmHi4&q=nh?w~*wC>^B^eO!@*H$5gWXF9B(tMsueWz(Y Hz2Er{GL={t literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk21.atl b/applications/PoP/poc/res/shadow/sk21.atl new file mode 100644 index 0000000000000000000000000000000000000000..d446b37db76abc39e80a553000cac3ffdcaddf46 GIT binary patch literal 7708 zcmcIoOO6~j3~d8mco86g;n;yOE5r6aN5~BVB#RtR_35te_Bh^VnPcQOmG?+WA|>_A z*l+|)>-R)b6d$FU-+%k{mlucszuX`0K0bSPIQ;wkt<-9H5NAmbvo^PN}CGhZ`taKGOhbY87a-Ei%LZcU_nXCe8%Jn zh|lM9+BjilngoCuD-e}{N$H*wR`R6OoF(cn{GFFDWu0Z2rfr*NqSB}H`PhK~nAX)c zMZ2zFI!sDSMhNf(+;vOGW2+OwOp@VFJ0O={AiNa{5l6VEDN7KyuQTT1YI-UlquL!X zo;@6k&3P;aEhwnnU~DSZgw8XMyA;CQs(qb`@`6Ewwlz3t=cq^R6drM$#%MsvP_wcH zSifJn?{B{{SKJW&EyE*odO7I{=>&W_KL}Ho5%drY?mwMC$&K{yEzuDkxI`4X9ZbRq z95H^MKg)@F7%40vxp;nyXoFeQmdIgP;13L*5hX}qNKK4YF(UtXe)r5Js^#~HYCXTB z7SUEx0F5?&H`a){1_yp$F1@%V=8JuYT?5mav?3Hj7Es1I-Zs+6sS8~WkLj;kAlahw zNC+usU_W|9WS{4^@G-#FvLQd*(U$5*{1yd%CE7i|sWxVYW{GwCm6&+*mHhr5q%_C! za=S?*kVwo1b7#+wW@~zz3MV_Z*||<*w&huik>qYu(J}ElYcEn*+_0@2uuSD2cbj%M z8!=Fd19!J+8~L1PMA~-kHf@!G92p@%V_UYO)R5NTPJ3DgmNmE?oCMp%T1O(-ALWsd zYORqd8yarimPKG)&I_=8NwILvHQw@&L7wG_{sgeH457I62kpR80 zCf;iL9;IuQwM{_ao+<>w!+c%kwhFOjQJY_*bI!Foo+Aq(Xp;CCZRjHbOZwubg%5AD zr#h-!Ri?gH&6RP2tA_8@z%U4grI(Ik4RLsz0YRk)vS6Qb^rwigSVMxCIQZjHKD zB1S@;e88B5tHFc`c1p`8N+4p}7!CJijudw~vN$t>`qKSz^!CbcGuHPdzKM5b$=_c5 zLQ5@*eFl-nAQ2$NJ!@YCQNq+%;Q`u?m&)xgv=*mdXsv0mtEkk|V9a0OtPt_toswfq z5{UQe;B987TvCzj1I(|-&7g3{9g()26=B2`ED5sUO`Y`L2nOY8B3hk%q%!6j_f1bJ za_U~Ot#2v`{i3o=z6`NnhPy_;vV&m28{5ollIEvx*pfr3!}M%5_LU*ZS{e{tYO#+b zPKKnlS5E663eFr@OzkN_)^ za3cWa{)bUSVVEzkEU#fm;5ck^xElNXAwmmMemQPN*M$YPusD|Z*wi4D zfMsmggW_@4GtMyT(NRSrjriEtSe4(pc3m0!cZYX}I`*xty1mkZC??k|u^62Vl?mFN zK|=&t%tBC&bND68)$eu%!5ev)?+hzhgkms^YXX!5kQC#WtdD8*~qwl{?c9= z)$7WKbj^!v?J#&9ouGq^3Owjk)zzitt>HI*6d*7MnMjfW$Zv`HSNs zv5T*PbY+6|4*^;j#PKz7Y9J!C!*LH$l;VQ8eIG!Gi(1tmJl_&DBCLT)Iu!X0GU%*F z&0&WOI%{y}#aVfP_l#E$(fAGzSi5;t<{YuwBGU G4)_n~nLpJ4 literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk22.atl b/applications/PoP/poc/res/shadow/sk22.atl new file mode 100644 index 0000000000000000000000000000000000000000..ae853daa24a2d5f1f970890c18c1a07ae277065f GIT binary patch literal 10504 zcmeHNv637$5FIBJ0TBrSc3qWyjxNG~z#mXW%m)z?kk2l)dsoL9zJPCA-h16Gsio1Z zvCoc}a?MEHPp?}ob!%qNKmYXO4__~z|9V>P-n@9REWdsA?uO4lzPWqN=P%#hzUA}x z?_TP8`u^1|`~TeBO8@KajpX$3Zh5m@%5^-J=B%-+wkO`SE!Fz-EO=TW%Wu7rPG+v7m>db(ZzWYrZ=VTEy?AK$X%SHVq_rQs?J)8L`a417T`+fB%I{s1QG24l4aH{Og)$1AMd@W_Toi+B?d1WbosIIBjTlECz z`nal$mr>eJyj@rsqJ)oXR-&S zH3$0lND%zvXqh%1zoVM3D%Kp%!8HbkkPJ8I)l8#ZMupd^PTijaomz~|?Z2v(`epnu zIu+13JOibf*0qQLCbbttv)~aofXAsFA0zRs=S6X@HD4=D<6)&wYf#RB&>y=p6#zG% z21{l>PSt5sY?U;Q597{~9-LwlL9C z!wN}SGtI$OEP~|JPHBS%HtMpXGeSVpto#&`z9lwUU?>VMtqzw9xmVEKLU0fIB}jC( zpX3-FX|W$j(heEhBpIbiavgE4RDo9!FHm1G#Nu$g+%9jIG{=wblqKC` z=nn2}=+$-Luq(4O<|{!0$Tq2=CwJe*d-Ds(E=EhTzmqLtV*d8~OYc=+EG0Hih^Pcn zOJI38Bnl?@WsU+G3@txvf`19aywM6*L-Tt+BqsPZ_`Wzj~DHlLAd!$KC(E85%37k#RoFy$*%*&~(>j6H>Q6lV!Q^=Qhf z+S4k$e73r|69ukvEXyHylP)Oz1)aLH*MDZ?x|7!@mzs=PgG@* zr(Tk)UWtV7cl&+!sO+?F8QbL=r4&&;z>mZjYdOqt8&L$FbBXs*&p3`3D1sy`B;{4q zC^C^iQCV65+hNU~-3w`yp|U6y&9UY=TXqdFIjf2h5I&RhU}RmfqEZXX1`04z8CpYd zs}6Zf>ipg}7?eq-qShmVI#B6{_(n>bz3+|MnsRKAb^^tPvfX+>6d=PU&tyQ^{>|d9 zXZvQ?97oXmZsgcSJvd%oEw@Xfx?V*{-VB&DCz#~;1e4h3m|6;2jCO*2Lb&TY26j_% zREuVRUV#*W@w(6@1Fm_OTci&46dDN4wCM}n8U{k??BuB{ zP`ibb);sRhma35*c(gVBN%MHTO}~uk)nS4)F`~COPkK8J>dgon^{SPEo7cRkTGd;1xqGpHZSDo& z*&SaYq>#url1;_^#*4y}50v+8Q{|Uc2nUcxO@^Xed_~A9mMH|R0SK-#-Wz=y`Xm}y zZzOpkTyU3XovQI5-dz#{nk=c0VTHmP)fOl$+&v^bEr7_}LKP$s1h}cng1J0wsGFTB zh(f^zJhlrgZYIh|!l6Suy)5@Rvn&~U&w+p$@LDhj113NmkT4Ua#I~G!2+ntZJ_79e z!Hfgo<{7_v_FVp7S0k{yE&=PeNZtF)3PTP1sB8*lvVh246nIqlxFlewX1nFL{+8^h z$kvLn9aj$mo*d?5i;)b_^3#+PwHUq2#c`k%Z@(Y4b0gu^vH#nHCT3lDY7mh9`WB5^ zT53x~NmIh`=3Fo%yeCk1G*ncA#RnwS-HTRYQ(b~r;aH`MswvMnrLlrTC{*kfA3Oqq vD%-%`)vyM`m0oSM+z6mhT7Zi8^~b|Eob={s34R4_w8R^GV?*yE@WRBuxA)DT literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk23.atl b/applications/PoP/poc/res/shadow/sk23.atl new file mode 100644 index 0000000000000000000000000000000000000000..450828b1871ef8b57b166024c64bcc424e096e2b GIT binary patch literal 10055 zcmds+O^zfr5QTFj7O-If3&f&?)brCL&59*UZh*v^BXFmzWU{7d8aNSGA$c$U9N~0! zwMGNdkeaSchd)1u?Qo>4=Eont|Mt`A-@hKF)2nCCrs?lbPPe@O{MpS5-oN|&wcP*u z@>cFYef{Q!_OHGaZ)D{&31}4Gi?zq~m#5AnjGQ7h>#NBq9Zl_`W z*4AfSZ&ul7j}ojD->)m$q5O*LXOX%$ey&)0ORLbhNJ0RUlH5532fhmN^lF z<#5B&UPdkCm1!b)f(aX0&mLOM&zNLkbr<8#54pj2z01+q2TVFluAN2bsxQH3lLd~Eu{LkV*o)7?#`F0r=|l3HOn zcpy_e8gR0{1A8$MlI&5eUEyp&-cF(*+%fG)0%k3)NRe%s?3~Jz?0kd+VYvpB=0pdMDITNBRcA8# zteuV_d2cqc1E^9*5OZ%xxfg?bV1v43QnAC%jFb*jtI?x)buCAm>!bF~rmna0!P9=z z55Q%){a@zj!BF4ZRPuc!*D6;w?rs|^d&pox<>E0k%O;(O>6YS5G+G3LlYq3`C0EO5 zX?x_ut@YewOb2)zZj}iHULPE8H7oLP6$6rP?YpX2O{Nj_PqMV8F;sX@A%X|!q{D6O z_AIlF54SN@DpwA-X;N}$e2%JkNTV{?54VBfp{IN>kDP580Wx^czXC8G(3KsE+ zLPYq(T=Qxqq~Bl@Wn;3NBzoTiAyyf>{$!15+JP0y#?@Mvg>Ihvn_L_{?co{BeP z=gPDU`>8XR5w5d@Z8o;wL>UMY1_+hvUvfnO&K&-l^NBYN1LMb6nvG9{%&;F%nUWMq zgh!m7PMI(iQGFi~Z0(oVd6h;cVx96PZT$CA%!CoPGX#wMskzG?Ng`C?$uxc^HBT~P z2UD$yPn~?{crFz#>P;xS1GuX;$W`Qi_H${;xK(E;<13=nDT#p@6_yV8 zy~d%QnYk-?n!=@<-J?uxc&oBIO9>K;vVN{3X@iphtF-W>fWZXgo%3#K!S~mYp^}`e z=#=?^o6WVW+2N`(G0>op8@S7;6IwNYD5^+f*spCV*YXq+I%IHln2f1sh&3HNaa&01 z?xPcH?~=+DEfz4QN}wbQ(~-Jj{B)czsSawz;I3@RP-{&GPoyw2ZBGpt849z+KX!5L A=Kufz literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk24.atl b/applications/PoP/poc/res/shadow/sk24.atl new file mode 100644 index 0000000000000000000000000000000000000000..258ba9322a9c1ae84007c202ba520df978c376ef GIT binary patch literal 6198 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 jkWernG>UOC=6R$a1Z|^^G{@XY2H2?G4 zn+MK+zj^ zYTePLunH8f$Odh6JbJ(&!N}=(1EdS(fdE}?uLZsG_Jtv0HRN0Ns;f-1#B9T`Ga_bN z=e6NPY9bCtDeHeZ393Tq|(O_8&A%5kT9fI z`&_NAqHxI9wErK4Y+Y&h-KQ?AU#tQJxk^-4wF4%jmF>(&r1y1LMEeD7*y-(pU$YxI zu|#jNE9z`8#*+;fnv;;-FaVCZO4}3ELZc1b1T2k#y3T_h< zL=#@tt1a;T;daz*->$raL1};gWe?+28+7LP4O_j*_E`0pk8QO{-|>^gnSBk1H@|+|{g`syT0Uw3H<|{V913LoU+#&)TwiD8XM!OtPV)e7<$(BTZZAKn)q^f1A zP(+V(?$s)TFs{mX9rjr5Jx_vGq){RxSEeteJ&-t|nRNhPdeQ|4C~tFHF~HIQOqlwY@PTk{KY!p(0YhLkpe_wAm>Var8~~n6*V+ ze8^z~s$zm%hA(9;M|3Wh_A8Q5O`7Zxh5W!4!IHb~?jQ1F>5R=9&Pd4ouUbe0r&_DCbU(-~4D z5udQH>?^pLTRO}!-aXcjo)X)Nrbg8&VJ$-xq7m=Xd`{Vq1n^`Ar8uDMAwC?0t)+mQ zuoy5k&E&LJD@^u)|Cm+6e>ZFk5;MGPFA7#~wC2#tm)Q)GW&{R2G`_(7HbKD83wE}I zBQyXUp{yT977`RPV9yNRlYO2mA)KH6gT&~C%jIOL{{=yAVjDgAaDL>Zx&ph9RBF$B z!m&B*9mWyW14o?UwqeZiA=FBFrm*Dq@~nfvi$U Ma5d%oCWFo1-C*+m`g!+RV Zls~I03Qgk2qny}d->qvAHtn%I_61^UwKo6& literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk3.atl b/applications/PoP/poc/res/shadow/sk3.atl new file mode 100644 index 0000000000000000000000000000000000000000..e2a92c1aef621cd224cccedd3703d19330173d55 GIT binary patch literal 7287 zcmd5>%ZeN~6fJK;AP|US8|<++gTdfkmR{x$0@>%=>e*f0(=%S>SF+DO|4=#S+1MGLO zwrzWac|hC5+8u$R9rPy$$F99V4SHzjbFMfJ7`h-9L3ekn+Sn0l2Zo7u*FGdnN*omS zaNo8M#{i|&w%sUfp69j=Y@`YxiCQpelIF`GI-J{i4wF*Vae7=J%SK)41KeY@hJ{HW3D+PLO7NBWO-PR)BQC=#e zHiUHD1v$e#uxI<++%$WZrN~N{S2Po*Q5C}W3ga~Bwk(8HLjmmxo%1^A_ApE+FN21R zm>!{`3K9ajQOId9FMmV>OMY2OQLBTZ<0MY7#9T zsFm+o20o#+S>#Zp!5!!cgF9i+-p;%(Qy1rcxQ{;1fEe>0S+yBSuaDFlhLO@EDd>Sj z7IfRZYf9)@-)hy14i6|_=bC4hwe!~+Lg4PcHa{S!T(uPg!tzuxr}8=15ai-Rb!&Q7 zw7fQT-DtZGGl%=NG%;fbRVLkY2h<;vi&P$ts457mMfo`~xBw6@nh^AuYXXMu$cwY- zK*WH-+#Izk@PoS4i^6zbOCzg`M%gQWQ;A`zgc8e`OC*YO66-LY(qi!$N>Kzegi$dF zv&FxhofAC>q{%bqYJr&eQL*>pHD~!lEm_UBG z-A@3FhJz~pgePp=vf!j(NDP`5q;xvzeZHQkfPC5As<9Z&aCKm?SP+Bf*48F>D-Ojn>5!z*E!fJl)J6ufne(9lTStsO+_olUpKc+ zJn!~->ehwU;7c4CXtRhFHFzxsiWfphF6&BmaZ9qjY999n`A{(4R~k$zTcZ6@>&=XC zW_7$Ay7UcAB7qMsbgH%{ga-%IYVu7sGV`7t- z>)hp3!iJLKASWWIx#Qn*_nj|x|DXY`R(UnH(e#DPL0O0Zi2hC5p@ z+9k7Z7_ksl42NvNpX@uwlxVMz&^3djLFDqh30F9QQ~7WgubPifv)T2Z=r$2mr8nzi zG7M!z^S7!D_86anyhlO|oUB;K4~w?nC}yH)o*iL3M7UUNd45P{wIZB1b~MWn@*6^M z?~Z`L*Ae$B&yjv)@MNJ=Trk`Ynu)`^_D_Y(6#nLeGbk^E5wYCTpz5T_-dr?HOA8UkO_T|0&nM>8`EW z!MJYNPBQQd&P{3CLCwv1!DvC`ObA@=jP7MhKx$1aR9@vWmSd9@@Dp6~`vb4ntcqxr z#6UUoJA~%6lN&~Q3SRV83R~6m@FQUKn?q!XB1##ODk$f!4fQ0+Rsjy8&T2!;KM=G@ QW(+SS{7n=uNS?(01vt@WlmGw# literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk4.atl b/applications/PoP/poc/res/shadow/sk4.atl new file mode 100644 index 0000000000000000000000000000000000000000..358078e538ef9a1ea9045b4ccbd3083bbd85aa61 GIT binary patch literal 10075 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 Q>hca8yS<<|=WP}J4^cU|OaK4? literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk7.atl b/applications/PoP/poc/res/shadow/sk7.atl new file mode 100644 index 0000000000000000000000000000000000000000..65d80bba0f17de74b5459079cbaa593dbab38797 GIT binary patch literal 4330 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 ArvLx| literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/shadow/sk9.atl b/applications/PoP/poc/res/shadow/sk9.atl new file mode 100644 index 0000000000000000000000000000000000000000..a69cacfdb4a165bb22cc9422236050640fc46072 GIT binary patch literal 8118 zcmc&(OOD(&5S14J62J(IECK|!0o!AH;f0YLAvXw+8|5TyiQSSW>YmGFm38i+yjMjQ zi)yiF5X1?AX_2f~AAahQ(){|%&p&d*4N^Qn0h!DrI59vo{g!oTD z%TP_rS56ee{H}TewyY;{Ki$;E9=T;4-rM4L-Ce~&H=sF~N1VxE6V^R?Z+SBv%=&d? zrdXgJkxAje4Q0zz5LN1fld!9#B!sBTI_l3%T1t+@qoWlfhMIclu-f*+;ZRcmjd(<* zpChReIbAeR{=#u(!w@zlgyd{xoVH&JjYklnh|*8aS~s=fc&v;F;a~<9q*0oFZ$axA zGL=Tj*c5GcQ8<}B6l%m4D}pFVUzlP&o#t8DOT)C`8(AQ?Cb9>{ou)(S#Z53=UX&qh z!nod^g*8xs%r1khibAmRbJgt|ESD6Ln%3&`956!W`B)O! zf$#m-41va~bn{NEjy17*tAeq$M5VvMBd@!UT>&*~4ec8L_#ES?6S}JPsuuPW_Yf1V z>Msqv86>hYzI9WmVmpv8yTv&fT>3{CM343W!8B^ILTcP zWTqHclbJ1s$YbFixvXW*q=u%OQMB&Q59tLFV@qbxT^Nx>1u_E((HFT2ugkg{9B~Pq z37Y|>{YVk+nhLb4si{Z5zS5<`&IQFOz*P!=pkGY=W)j^P@B2}{Fvu|5uzbeKOI}fL z)}EBy46}%KZvP8=UZ}`|v2E@T&1x8F6R1jY(8-3nfgkU|rhNlgQ+NkXn`! zq}qp@&@yDR!#v6$H!%4Y)#4i1Q-0*`-=`x$qUE;i_su0pV=_X@EONcKOTg-hw;+EF z5>G~=nxybt-n%xQBx8|V$dH91Kix=ZcSF<*kxzT#4?=xLY-xES-d!8zsgVko#8u@3 z722G+EC}Izx!fxVWIRm|sg6Mw45}CHKeJnn#^E?m)0zETMqJa`uL*+LMsDaA2HVG? zsymH+B>hyl6$bJ)wjd=ilqB%SlZb_`5gi+6d=Hc;`d$Oli1-ms`x%rpSYhD@2C3kp zlrX3;Y&w%JG)QKY@)K%IbvEgj{jAaq!e*|76-im`PFgAACYQ$6vOv$@%?JPOfDOjL-H;D%ae=o! zh$z(~6%cJ|0Q3uY^4}6sN8(8IvUhZEK~9kxM-BQ=z$HmjTE;In*YE(boA1CQPDS$j ZfRLS73_CF$*W%6F?&fj}c%_}W>u*twIhOzc literal 0 HcmV?d00001 diff --git a/applications/PoP/roomtest/BUGS_OPEN.md b/applications/PoP/roomtest/BUGS_OPEN.md index a764b2f..1369e5b 100644 --- a/applications/PoP/roomtest/BUGS_OPEN.md +++ b/applications/PoP/roomtest/BUGS_OPEN.md @@ -24,6 +24,7 @@ | [GRAB-KBD-TIMING](#grab-kbd-timing) | зацеп в падении срабатывает менее стабильно, чем в оригинале | **после всех уровней** | открыт: подозрение на клавиатурный модуль, не на физику | | [GUARD-ENTRY-DEATH](#guard-entry-death) | вход в комнату вплотную к стражу = мгновенная смерть (не портирован `bump_into_opponent`) | порт | **фикс есть, ждёт проверки в MAME** | | [BUG-SHADOW-SET](#bug-shadow-set) | Тень на 12-м уровне дерётся спрайтами СТРАЖА: SHADOW.DAT у нас нет вовсе | порт | открыт, разбор готов | +| [BUG-CORPSE-AIR](#bug-corpse-air) | труп Кида висит в воздухе, когда убившая его плита улетела вниз | физика | открыт | | [LOOSE-ROOM-CHANGE](#loose-room-change) | расшатанная плита не доваливается, если Кид ушёл в соседнюю комнату | порт | закрыт 2026-08-13, кроме [LOOSE-SEAM-ANIM](#loose-seam-anim) | | [JUMP-FLOOR-LEGS](#jump-floor-legs) | в прыжке с пола ноги Кида рисуются ПОВЕРХ кромки пола, а должны за ней | окклюзия | **корень найден и починен, ждёт проверки в MAME** | | [MOB-CLIP-RIGHT](#mob-clip-right) | окна и узор кладки рисуются ПОВЕРХ падающих плит | окклюзия | открыт: корень найден 2026-08-13 | @@ -870,3 +871,25 @@ Makefile правила нет. **Оговорка.** `pop_guard_set_palette` для типа 4 звать НЕЛЬЗЯ — она затрёт палитру Тени палитрой стража (`curr_guard_color` у не-стражей = 0, `seg002:183`). + +### BUG-CORPSE-AIR. Труп висит в воздухе после падения плиты + +**Симптом** (найдено пользователем 2026-08-20, ур. 12 к. 15, старт с +`POS=15`): Кид встал на проваливающийся пол (0,6), плита обрушилась и +убила его, но ТЕЛО осталось лежать на уровне исчезнувшего пола, а плита +улетела дальше вниз. Труп висит в пустоте. + +**Где смотреть.** Кадр смерти — `actions_5_bumped` (см. seq в +`kid_data`), а гравитация в `check_action` (seg006:05CD) для действия 5 +включается только на кадрах приседа: у оригинала есть отдельные фиксы +`FIX_DEAD_FLOATING_IN_AIR` (кадры 177..185) именно про этот случай — +значит **в оригинале 1989 года труп в воздухе тоже висит**, и SDLPoP +чинит это опциональным фиксом, по умолчанию выключенным. + +**Отсюда вопрос к решению**, а не сразу правка: чинить ли вообще. Если +чинить — портировать `fix_dead_floating_in_air` и записать как +осознанное расхождение в `../docs/impl_diff.md` (мы уже отказались от +двух других опциональных фиксов SDLPoP в `bump_into_opponent`). + +**Приоритет низкий:** ситуация возникает только когда труп остаётся на +проваливающемся полу, играбельности не мешает. diff --git a/applications/PoP/roomtest/Makefile b/applications/PoP/roomtest/Makefile index 93af3ee..d81074e 100644 --- a/applications/PoP/roomtest/Makefile +++ b/applications/PoP/roomtest/Makefile @@ -35,7 +35,7 @@ MEMORY ?= huge # small-раскладка + банки кода в W # ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том # же ALLOCS — иначе сравниваются не правки, а уровни оптимизации. ALLOCS ?= 3000 -EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c $(PROF_FLAGS) +EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c --bank 8=pop_shadow.c $(PROF_FLAGS) # Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по # умолчанию, пока идёт работа с производительностью; make PROF=0 выключает. # Каждая фаза кадра красит бордюр в свой цвет, высота полосы на скриншоте @@ -112,8 +112,16 @@ VIZIER_DIR := $(CURDIR)/../poc/res/vizier VIZIER_DATA := $(VIZIER_DIR)/g0.atl $(VIZIER_DIR)/g1.atl $(VIZIER_DIR)/g2.atl \ $(VIZIER_DIR)/g3.atl $(VIZIER_DIR)/g4.atl +# ТЕНЬ — свой набор, запечённый упаковщиком (наложение спрайта на себя со +# сдвигом; наш блит так не умеет, см. ../docs/shadow_atlas_plan.md). Две +# половины в одном наборе: sk* — кадры вне боя (спрайты Кида), sf* — кадры +# 150..189 (SHADOW.DAT, это тоже графика Кида, а не стража). +SHADOW_DIR := $(CURDIR)/../poc/res/shadow +SHADOW_DATA := $(foreach n,0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27,$(SHADOW_DIR)/sk$(n).atl) \ + $(foreach n,0 1 2 3,$(SHADOW_DIR)/sf$(n).atl) + EXTRA_DATA := $(BG_DATA) $(KID_DATA) $(KID_BIN) $(GUARD_DATA) $(SKEL_DATA) \ - $(VIZIER_DATA) $(LVL_DATA) + $(VIZIER_DATA) $(SHADOW_DATA) $(LVL_DATA) include $(PROJ_ROOT)/app.mk # Образ HDD для MAME: ресурсы раскладываются ПО КАТАЛОГАМ (8.3, как в DSS), @@ -130,6 +138,7 @@ hdd: $(EXAMPLE).exe $(foreach f,$(GUARD_DATA),GUARD:$(f)) \ $(foreach f,$(SKEL_DATA),SKEL:$(f)) \ $(foreach f,$(VIZIER_DATA),VIZIER:$(f)) \ + $(foreach f,$(SHADOW_DATA),SHADOW:$(f)) \ $(foreach f,$(LVL_DATA),LEVELS:$(f)) TC := $(PROJ_ROOT)/applications/PoP/toolchain @@ -144,6 +153,9 @@ $(SKEL_DATA): $(TC)/pop_pack_guard.py $(VIZIER_DATA): $(TC)/pop_pack_guard.py cd $(TC) && python3 pop_pack_guard.py VIZIER +$(SHADOW_DATA) pop_shadow_atlas.h: $(TC)/pop_pack_shadow.py $(TC)/pop_pack_bg.py $(TC)/pop_pack_kid.py + cd $(TC) && python3 pop_pack_shadow.py + $(KID_DATA): $(TC)/pop_pack_kid.py $(TC)/pop_pack_bg.py cd $(TC) && python3 pop_pack_kid.py kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py diff --git a/applications/PoP/roomtest/pop_cdraw.c b/applications/PoP/roomtest/pop_cdraw.c index d24823b..fcdbcb4 100644 --- a/applications/PoP/roomtest/pop_cdraw.c +++ b/applications/PoP/roomtest/pop_cdraw.c @@ -23,6 +23,7 @@ #include "_pop_kdraw.h" #include "pop_vflip.h" /* зеркальные страницы атласов (зелье инверсии) */ /* меч + блит по id — сосед по банку 4 */ /* атласы/кадр Кида, pop_sword_draw, окна Char */ #include "pop_cdraw.h" +#include "pop_shadow.h" /* запечённый набор Тени */ #include "pop_pace.h" /* pop_beam_sample — счёт кадров по лучу */ #include "pop_state.h" /* ВРЕМЕННО: зонды pop_dbg_b* */ #include "pop_bg.h" /* POP_YOFF, pop_fore_over_char, pop_fore_set_clip */ @@ -527,6 +528,10 @@ void pop_char_draw(uint8_t who) __banked const pop_char_t *ch; const kframe *fr; const atlas_t *pages; + /* Атлас БРЫЗГ отдельно от кадра: у оригинала они всегда из «своего» + * chtab (Кид — chtab_2 image 218, прочие — chtab_5 image 1, + * seg006:2019), а у Тени кадр может прийти из другой половины набора. */ + const atlas_t *spl; const uint8_t *img; uint8_t npages, page, idx, dp, flip, hurt, lskip; uint8_t w, h, vis_w; @@ -549,19 +554,31 @@ void pop_char_draw(uint8_t who) __banked if (who == POP_CH_KID) { pop_loadkid(); ch = &Kid; fr = &kid_frame; pages = kidp; npages = kid_npages; + spl = kidp; hurt = pop_kid_hurt; } else { pop_loadshad(); ch = &Guard; fr = &pop_gframe; pages = gp; npages = g_ok ? GUARD_PAGES : 0; + spl = gp; hurt = pop_guard_hurt; if (Guard.charid == 0) return; /* соперника на сцене нет */ - /* ТЕНЬ (ур. 4) — это зеркальный Кид: вне боевых кадров 150..189 она - * ходит по таблице КИДА (seg006:0532), а `image` из неё индексирует - * спрайты Кида, а не стража. Набор атласов обязан идти за таблицей — - * условие берём из того же места, что load_frame, чтобы они не - * разъехались. */ - if (!pop_frame_tbl_is_guard(Guard.charid, Guard.frame)) { + /* Набор атласов обязан идти за ТАБЛИЦЕЙ КАДРОВ — условие берём из + * того же места, что load_frame (seg006:0532), чтобы они не + * разъехались: вне боевых кадров 150..189 Тень ходит по таблице + * КИДА, и `image` из неё индексирует спрайты Кида. */ + if (Guard.charid == CHARID_1_SHADOW && pop_shadow_kid_n) { + /* У Тени СВОЙ запечённый набор (pop_shadow.h): её вид даёт + * наложение спрайта на себя со сдвигом, а пакетный блит так не + * умеет. Обе половины лежат в нём же, поэтому подмены на kidp + * здесь уже не нужно. */ + if (pop_frame_tbl_is_guard(Guard.charid, Guard.frame)) { + pages = pop_shadow_fgt; npages = pop_shadow_fgt_n; + } else { + pages = pop_shadow_kid; npages = pop_shadow_kid_n; + } + spl = pop_shadow_fgt; /* брызги — из половины chtab_5 */ + } else if (!pop_frame_tbl_is_guard(Guard.charid, Guard.frame)) { pages = kidp; npages = kid_npages; } } @@ -741,7 +758,7 @@ void pop_char_draw(uint8_t who) __banked /* по нему считается футпринт */ } pop_dbg_m15(); /* ЗАМЕР: снимок прямоугольника сделан */ - if (hurt) cd_splash(s, who, pages, fp_x, obj_y); + if (hurt) cd_splash(s, who, spl, fp_x, obj_y); /* add_sword_to_objtable (seg006:1798): клинок отдельным спрайтом поверх * персонажа — со своим прямоугольником heal. */ { diff --git a/applications/PoP/roomtest/pop_shadow.c b/applications/PoP/roomtest/pop_shadow.c new file mode 100644 index 0000000..34e3b3d --- /dev/null +++ b/applications/PoP/roomtest/pop_shadow.c @@ -0,0 +1,88 @@ +/* + * pop_shadow.c — загрузка запечённого набора спрайтов Тени. Зачем набор + * отдельный и почему половин две — в шапке pop_shadow.h. + * + * Код ХОЛОДНЫЙ (раз на уровень), поэтому живёт в банке 8 вместе с прочей + * загрузкой. Сами atlas_t — в W2: их читает отрисовка из банка 4, а + * данные видны из любого банка. + */ + +#include +#include +#include +#include "pop_shadow.h" +#include "pop_shadow_atlas.h" + +atlas_t pop_shadow_kid[POP_SHADOW_KID_PAGES]; +atlas_t pop_shadow_fgt[POP_SHADOW_FGT_PAGES]; +uint8_t pop_shadow_kid_n, pop_shadow_fgt_n; + +/* ГРУЗИМ ОДИН РАЗ НА ЗАПУСК, а не по уровням. + * + * Тень бывает на ЧЕТЫРЁХ уровнях: 4 — рождается прыжком сквозь зеркало + * (jump_through_mirror, seg003:0811, ставит Char.charid = charid_1_shadow + * прямо из Кида), 5 — крадёт зелье, 6 — прыгает через пропасть, 12 — + * дерётся. Читается как три, потому что таблиц init_shad_N всего три + * (5/6/12): четвёртой нет — на 4-м Тень копируется с Кида, а не поднимается + * из таблицы. Так вот, напрашивается + * грузить набор только там, как это сделано с перевёрнутыми наборами + * (pop_vflip_load_all зовётся лишь на POP_UPSIDE_LEVEL). Решение + * пользователя — грузить сразу, и оно правильное по двум причинам: + * страниц EMM с запасом (32 из ~215 свободных), а вот забыть перезагрузку + * на границе уровня легко — ровно так и появился BUG-SHADOW-SET. Разовая + * загрузка убирает целый класс ошибок и заодно не тормозит переход между + * уровнями на 32 файла. */ +int pop_shadow_load(void) __banked +{ + uint8_t i; + if (pop_shadow_kid_n || pop_shadow_fgt_n) return 0; /* уже загружен */ + + for (i = 0; i < POP_SHADOW_KID_PAGES; i++) { + if (atlas_load(&pop_shadow_kid[i], pop_shadow_kid_atl[i]) != 0) { + pop_shadow_free(); + return -1; + } + pop_shadow_kid_n = (uint8_t)(i + 1); + } + for (i = 0; i < POP_SHADOW_FGT_PAGES; i++) { + if (atlas_load(&pop_shadow_fgt[i], pop_shadow_fgt_atl[i]) != 0) { + pop_shadow_free(); + return -1; + } + pop_shadow_fgt_n = (uint8_t)(i + 1); + } + + pop_shadow_pal_apply(); + return 0; +} + +/* ПАЛИТРА ОТДЕЛЬНО ОТ ЗАГРУЗКИ, и это не косметика. + * + * `gfx_pal_fload("KID\\kid.pal")` заливает ВСЕ 256 записей — это единая + * игровая палитра, — и затирает любые слоты, выставленные до него. Ровно + * та же беда уже была с тайлсетом: сразу за ним стоит pop_bg_pal_apply, + * который возвращает цвета env/wall. Наши 0xA0..0xAF из той же оперы, и + * в первом заходе я на это наступил: набор грузился, силуэт рисовался + * правильной формы, но ЦЕЛИКОМ ЧЁРНЫЙ (поймано пользователем на 6-м + * уровне). Поэтому вызов живёт рядом с pop_bg_pal_apply, а не внутри + * загрузки атласов. + * + * Обе страницы дабл-буфера: у них свои палитры. Через буфер в W2 — + * gfx_pal_load отдаёт указатель BIOS ($A4), а тот читает только + * #4000-#BFFF и банковую rodata не увидит. */ +void pop_shadow_pal_apply(void) __banked +{ + uint8_t buf[64], k; + if (!pop_shadow_kid_n) return; /* набора нет — нечего красить */ + for (k = 0; k < 64; k++) buf[k] = pop_shadow_pal[k]; + gfx_pal_load(0, POP_SHADOW_PAL_BASE, 16, buf); + gfx_pal_load(1, POP_SHADOW_PAL_BASE, 16, buf); +} + +void pop_shadow_free(void) __banked +{ + uint8_t i; + for (i = 0; i < pop_shadow_kid_n; i++) atlas_free(&pop_shadow_kid[i]); + for (i = 0; i < pop_shadow_fgt_n; i++) atlas_free(&pop_shadow_fgt[i]); + pop_shadow_kid_n = pop_shadow_fgt_n = 0; +} diff --git a/applications/PoP/roomtest/pop_shadow.h b/applications/PoP/roomtest/pop_shadow.h new file mode 100644 index 0000000..7463e2f --- /dev/null +++ b/applications/PoP/roomtest/pop_shadow.h @@ -0,0 +1,55 @@ +/* + * pop_shadow.h — запечённый набор спрайтов ТЕНИ. + * + * Оригинал спрайтов Тени не хранит: он кладёт обычный спрайт дважды — в x + * прозрачным блитом и в x+1 «блиттером XOR» (draw_objtable_item, + * seg008.c:1600). Пакетный блит так не умеет, поэтому результат запечён + * заранее (toolchain/pop_pack_shadow.py); разбор и замеры — + * ../docs/shadow_atlas_plan.md. + * + * ПОЛОВИН ДВЕ, и это не наша выдумка. Набор спрайтов у оригинала выбирает + * не персонаж, а поле `sword` САМОГО КАДРА (load_frame_to_obj, + * seg008.c:1752: chtab_base жёстко = chtab_2, плюс `sword >> 6`). У всех + * кадров таблицы Кида эти биты нулевые, у всех кадров таблицы стража — + * 0xC0. Тень берёт таблицу стража для кадров 150..189 (seg006.c:533), + * значит идёт через chtab_5 — а chtab_5 на 12-м уровне грузится из + * SHADOW.DAT (tbl_guard_type[12] == 4), и это графика КИДА в боевых позах. + * Отсюда: + * + * pop_shadow_kid[] — кадры вне боя (запечены из спрайтов Кида); + * pop_shadow_fgt[] — кадры 150..189 (запечены из SHADOW.DAT). + * + * Какая половина нужна, отрисовка уже знает — тем же условием, что + * выбирает таблицу кадров (pop_frame_tbl_is_guard). + * + * СПРАЙТ ТЕНИ НА ПИКСЕЛЬ ШИРЕ исходного: второй проход оригинала кладётся + * в x+1, суммарный след занимает [x, x+w]. Рисовать по тем же + * координатам, что и Кида — сдвиг уже внутри спрайта. + */ +#ifndef POP_SHADOW_H +#define POP_SHADOW_H + +#include +#include + +extern atlas_t pop_shadow_kid[]; /* половина «вне боя» */ +extern atlas_t pop_shadow_fgt[]; /* половина «в бою» (SHADOW.DAT) */ +/* Сколько страниц реально загружено; 0 = набора нет (уровень без Тени + * или загрузка не удалась) — отрисовка тогда идёт прежним путём. */ +extern uint8_t pop_shadow_kid_n, pop_shadow_fgt_n; + +/* Загрузить набор. Звать ОДИН РАЗ при старте: набор не зависит от + * уровня, а перезагрузка на границе — лишний повод её забыть (почему + * именно так — в шапке pop_shadow.c). Повторный вызов — no-op. + * Возврат: 0 — OK, -1 — ошибка загрузки. */ +int pop_shadow_load(void) __banked; + +/* Залить 16 слотов палитры Тени. ЗВАТЬ ПОСЛЕ ЛЮБОЙ заливки общей + * палитры (gfx_pal_fload kid.pal): та кладёт все 256 записей и затирает + * наши — см. развёрнуто в pop_shadow.c. Рядом с pop_bg_pal_apply. */ +void pop_shadow_pal_apply(void) __banked; + +/* Освободить страницы; звать на выходе из программы. */ +void pop_shadow_free(void) __banked; + +#endif diff --git a/applications/PoP/roomtest/pop_shadow_atlas.h b/applications/PoP/roomtest/pop_shadow_atlas.h new file mode 100644 index 0000000..7c46fe7 --- /dev/null +++ b/applications/PoP/roomtest/pop_shadow_atlas.h @@ -0,0 +1,71 @@ +/* pop_shadow_atlas.h — раскладка атласа ТЕНИ. + * СГЕНЕРЕНО toolchain/pop_pack_shadow.py — НЕ править вручную. + * + * Две половины, потому что и у оригинала их две (см. шапку + * упаковщика): кадры вне боя адресуют chtab_2 (спрайты Кида), + * кадры 150..189 — chtab_5, а он на 12-м уровне это SHADOW.DAT. + * Какая половина нужна, приложение уже знает — тем же условием, + * что выбирает таблицу кадров (pop_frame_tbl_is_guard). + * + * Спрайт Тени НА ОДИН ПИКСЕЛЬ ШИРЕ исходного: второй проход + * оригинала кладётся в x+1, и суммарный след занимает [x, x+w]. + * Рисовать по тем же координатам, что и Кида — сдвиг уже внутри. + */ +#ifndef POP_SHADOW_ATLAS_H +#define POP_SHADOW_ATLAS_H + +#include + +#define POP_SHADOW_SHIFT 3 +#define POP_SHADOW_MASK 7 +#define POP_SHADOW_PAL_BASE 0xA0 /* слоты Sprinter под Тень */ + +/* Половина «вне боя» — кадры Кида (chtab_2). */ +#define POP_SHADOW_KID_PAGES 28 +/* Половина «в бою» — SHADOW.DAT (chtab_5, кадры 150..189). */ +#define POP_SHADOW_FGT_PAGES 4 + +static const char *const pop_shadow_kid_atl[POP_SHADOW_KID_PAGES] = { + "SHADOW\\sk0.atl", + "SHADOW\\sk1.atl", + "SHADOW\\sk2.atl", + "SHADOW\\sk3.atl", + "SHADOW\\sk4.atl", + "SHADOW\\sk5.atl", + "SHADOW\\sk6.atl", + "SHADOW\\sk7.atl", + "SHADOW\\sk8.atl", + "SHADOW\\sk9.atl", + "SHADOW\\sk10.atl", + "SHADOW\\sk11.atl", + "SHADOW\\sk12.atl", + "SHADOW\\sk13.atl", + "SHADOW\\sk14.atl", + "SHADOW\\sk15.atl", + "SHADOW\\sk16.atl", + "SHADOW\\sk17.atl", + "SHADOW\\sk18.atl", + "SHADOW\\sk19.atl", + "SHADOW\\sk20.atl", + "SHADOW\\sk21.atl", + "SHADOW\\sk22.atl", + "SHADOW\\sk23.atl", + "SHADOW\\sk24.atl", + "SHADOW\\sk25.atl", + "SHADOW\\sk26.atl", + "SHADOW\\sk27.atl", +}; + +static const char *const pop_shadow_fgt_atl[POP_SHADOW_FGT_PAGES] = { + "SHADOW\\sf0.atl", + "SHADOW\\sf1.atl", + "SHADOW\\sf2.atl", + "SHADOW\\sf3.atl", +}; + +/* 16 цветов, запись 4 байта (B, G, R, 0) — формат gfx_pal_load. */ +static const uint8_t pop_shadow_pal[64] = { + 0x00,0x00,0x00,0x00,0xD8,0xFC,0xFC,0x00,0x6C,0x80,0xDC,0x00,0x78,0x44,0x24,0x00,0xA0,0xB8,0xD8,0x00,0xB5,0x7C,0x21,0x00,0x00,0x90,0xB8,0x00,0x5D,0x6D,0xAB,0x00,0x0C,0xF0,0x6C,0x00,0xCC,0x38,0x05,0x00,0x38,0xCC,0xC0,0x00,0x58,0xDB,0xA7,0x00,0xBB,0x9F,0x54,0x00,0x5D,0x18,0x60,0x00,0x37,0xD7,0x37,0x00,0x2F,0x17,0xD2,0x00, +}; + +#endif diff --git a/applications/PoP/roomtest/roomtest_cold.c b/applications/PoP/roomtest/roomtest_cold.c index d3f7c08..774fe5e 100644 --- a/applications/PoP/roomtest/roomtest_cold.c +++ b/applications/PoP/roomtest/roomtest_cold.c @@ -23,6 +23,7 @@ #include /* gfx_copy_page */ #include "pop_tune.h" #include "pop_ctrl.h" /* pop_ctrl_init/close — ввод поднимает и закрывает boot */ +#include "pop_shadow.h" /* запечённый набор Тени */ #include "pop_vflip.h" /* сброс зеркальных страниц на смене уровня */ #include "pop_cheat.h" /* pop_cheats — режим разработки включает pop_boot */ #include "pop_pace.h" /* pop_speed_mode — режим скорости в отладочной метке */ @@ -749,6 +750,7 @@ int pop_boot(void) __banked } pop_sword_load(); /* меч в руке (без него кадры 229+ без клинка) */ pop_guard_load(); /* атласы стража (GUARD\\g0..g4) */ + pop_shadow_load(); /* запечённый набор Тени — один раз на запуск */ if (pop_kid_load(28) != 0) { /* ВСЕ страницы: бег+стоп+разворот+присед+прыжок */ puts("kid atlas load failed"); return -1; @@ -771,6 +773,8 @@ int pop_boot(void) __banked * дворцовых уровнях без этого рисуется дворцовая геометрия подземельными * красками (сине-серое вместо песочного). */ pop_bg_pal_apply(); + /* ...и палитру Тени: kid.pal затёр и её 16 слотов (pop_shadow.c). */ + pop_shadow_pal_apply(); /* Фон комнаты рисуется в ОБЕ графические страницы: у каждой своя * ОЗУ-копия/видео-ОЗУ, а heal берёт чистый фон из ОЗУ-копии ТОЙ @@ -853,6 +857,7 @@ void pop_shutdown(void) __banked closegraph(); pop_bg_free(); pop_kid_free(); + pop_shadow_free(); pop_guard_free(); pop_kid_data_free(); pop_level_free(); diff --git a/applications/PoP/toolchain/pop_pack_shadow.py b/applications/PoP/toolchain/pop_pack_shadow.py new file mode 100644 index 0000000..aac74fb --- /dev/null +++ b/applications/PoP/toolchain/pop_pack_shadow.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 +""" +pop_pack_shadow.py — упаковщик спрайтов ТЕНИ. + +ЗАЧЕМ ОТДЕЛЬНЫЙ НАБОР. Оригинал не хранит спрайтов Тени вовсе: он кладёт +обычный спрайт ДВАЖДЫ — в x обычным прозрачным блитом, и в x+1 «блиттером +XOR» (draw_objtable_item, seg008.c:1600). Наш пакетный блит так не умеет, +поэтому результат запекается заранее, здесь. + +ЧТО ИМЕННО ДЕЛАЕТ ОРИГИНАЛ (проверено по исходнику, не по памяти): + + * `blitters_2_or` — НЕ побитовое ИЛИ. В SDLPoP это обычный блит с + colour key = индекс 0 (method_6_blit_img_to_scr, seg009.c:3306), то + есть один в один наш прозрачный блит. + * `blitters_3_xor` работает по 24-битному RGB, а не по индексам палитры + (blit_xor, seg009.c:3190: конвертация в 24 бита, затем `*p_dest ^= + *p_src` побайтно). Прозрачности у него нет — XOR'ится весь + прямоугольник, но прозрачный пиксель это чёрный 0x000000, а XOR с + нулём ничего не меняет. + +Отсюда своя палитра: XOR двух цветов игровой палитры даёт цвет, которого в +ней нет. + +ЕДИНСТВЕННОЕ РАСХОЖДЕНИЕ. XOR считается по тому, что УЖЕ на экране, то +есть зависит от фона. Разбор по пикселям: от фона зависит только кайма в +один пиксель по ЛЕВЫМ кромкам силуэта (там, где спрайт прозрачен в x, но +непрозрачен в x−1). На чёрном фоне `фон XOR цвет == цвет`, и запечка +точна; Тень почти всегда на чёрном. Мы печём именно этот случай. + +ДВА НАБОРА В ОДНОМ АТЛАСЕ. Набор спрайтов у оригинала выбирает НЕ +персонаж, а поле `sword` самого кадра: load_frame_to_obj (seg008.c:1752) +держит chtab_base жёстко равным chtab_2 и прибавляет `sword >> 6`. У всех +кадров frame_table_kid эти биты нулевые, у всех кадров frame_tbl_guard — +0xC0. Тень берёт таблицу стража для кадров 150..189 (seg006.c:533), то +есть идёт через chtab_5, а chtab_5 на 12-м уровне грузится из SHADOW.DAT +(tbl_guard_type[12] == 4, seg000.c:1117) — и это графика КИДА в боевых +позах, а не стража. Поэтому печём обе половины: + + KID — data/KID/res(401+id).png, id 0..218 -> sk0..skN.atl + SHADOW — data/SHADOW/res(751+id).png, id 0..31 -> sf0..sfM.atl + +Выход: poc/res/shadow/sk*.atl + sf*.atl + pop_shadow_atlas.h (палитра +внутри заголовка — 16 записей, её заливает приложение через gfx_pal_load). +""" +import os +import sys +from PIL import Image + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +import pop_pack_bg as B +from pop_pack_kid import transpose_cols + +DATA = os.path.join(HERE, "..", "SDLPoP", "data") +OUT_DIR = os.path.join(HERE, "..", "poc", "res", "shadow") +PAL_BASE = 0xA0 # слоты Sprinter под Тень: 0xA0..0xAF +NCOL = 16 # столько цветов в палитре Тени +SHIFT = 3 # sk[id>>3], idx id&7 — как у Kid (кадры крупные) +MASK = (1 << SHIFT) - 1 + +# Половины набора: (каталог, база ресурса, префикс выходных файлов). +# Off-by-one тот же, что у Kid и стража: images[0] = res(база+1), значит +# frame.image = N -> res(база+1+N) (см. pop_pack_kid.load_kid). +HALVES = (("KID", 400, "sk"), + ("SHADOW", 750, "sf")) + + +def frames(dirname, base): + """Все кадры половины: [(id, w, h, [[rgb|None]...])] — уже после + наложения XOR, в честном RGB.""" + out = [] + id = 0 + while True: + path = os.path.join(DATA, dirname, f"res{base + 1 + id}.png") + if not os.path.exists(path): + break + im = Image.open(path) + if im.mode != "P": + B.die(f"{path}: mode {im.mode}, ожидался P") + pal = im.getpalette()[:NCOL * 3] + rgb = [tuple(pal[i * 3:i * 3 + 3]) for i in range(NCOL)] + w, h = im.size + px = im.load() + grid = [] + for y in range(h): + # Ширина на один больше: второй проход кладётся в x+1, и + # суммарный след занимает [x, x+w]. + row = [None] * (w + 1) + for x in range(w): # проход 1: обычный блит + i = px[x, y] + if i: + row[x] = rgb[i] + for x in range(w): # проход 2: XOR в x+1 + i = px[x, y] + if not i: + continue # чёрный: XOR — не операция + s = rgb[i] + t = x + 1 + row[t] = s if row[t] is None else tuple(a ^ b for a, b in zip(row[t], s)) + grid.append(row) + out.append((id, w + 1, h, grid)) + id += 1 + return out + + +def histogram(halves): + h = {} + for _, fr in halves: + for _, _, _, grid in fr: + for row in grid: + for c in row: + if c is not None: + h[c] = h.get(c, 0) + 1 + return h + + +def _d2(a, b): + return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2 + + +def _kmeans(pts, k, init): + """Взвешенный Ллойд по СПИСКУ ЦВЕТОВ с весами (их полсотни, не пиксели).""" + cent = list(init) + for _ in range(80): + groups = [[] for _ in cent] + for c, n in pts: + groups[min(range(len(cent)), key=lambda j: _d2(c, cent[j]))].append((c, n)) + new = [] + for j, g in enumerate(groups): + if not g: + new.append(cent[j]) + continue + w = sum(n for _, n in g) + new.append(tuple(int(round(sum(c[i] * n for c, n in g) / w)) for i in range(3))) + if new == cent: + break + cent = new + return cent + + +def build_palette(hist): + """16 цветов ГИБРИДОМ: часть слотов — самые частые цвета ТОЧНО, остаток + — взвешенные кластеры хвоста. + + Почему не «просто самые частые»: тогда редкие цвета уезжают в далёкий + ближайший, и грубых промахов (сдвиг >90 по евклиду в RGB при максимуме + 441) получается впятеро больше — 381 пиксель против 76 на все 251 + кадр (замер 2026-08-20). Почему не чистый k-means: он двигает вообще + все цвета, включая массовые. + + Разделение слотов подбираем перебором по критерию «сначала минимум + грубых промахов, потом заметных, потом худшая ошибка».""" + items = sorted(hist.items(), key=lambda kv: -kv[1]) + + def stats(pal): + bad = worst = mid = big = 0 + for c, n in items: + e = min(_d2(c, p) for p in pal) ** 0.5 + if e > 0: + bad += n + worst = max(worst, e) + if e >= 90: + big += n + elif e >= 40: + mid += n + return bad, mid, big, worst + + best = None + for m in range(1, NCOL): # m слотов под хвост + keep = [c for c, _ in items[:NCOL - m]] + rest = [(c, n) for c, n in items[NCOL - m:]] + if not rest: + continue + pal = keep + _kmeans(rest, m, [c for c, _ in rest[:m]]) + bad, mid, big, worst = stats(pal) + score = (big, mid, worst) + if best is None or score < best[0]: + best = (score, m, pal, (bad, mid, big, worst)) + _, m, pal, st = best + # Чёрный обязан быть ТОЧНЫМ и лежать в слоте 0: это XOR-погашенная + # середина силуэта, больше половины всех пикселей Тени. + j = min(range(len(pal)), key=lambda i: _d2((0, 0, 0), pal[i])) + pal[j] = (0, 0, 0) + pal[0], pal[j] = pal[j], pal[0] + bad, mid, big, worst = st + tot = sum(hist.values()) + print(f" палитра: {NCOL - m} частых точно + {m} кластеров хвоста; " + f"из {len(items)} цветов изменено {bad} px из {tot} " + f"({100.0 * bad / tot:.2f} %), заметно {mid}, сильно {big}, худшая {worst:.0f}") + return pal + + +def encode(grid, w, h, pal): + """RGB-сетка -> байты атласа: нет пикселя -> 0xFF, цвет -> PAL_BASE + k. + Чёрный — НАСТОЯЩИЙ цвет Тени (слот 0), а не прозрачность.""" + row = bytearray() + for y in range(h): + for x in range(w): + c = grid[y][x] + if c is None: + row.append(0xFF) + else: + row.append(PAL_BASE + min(range(len(pal)), key=lambda k: _d2(c, pal[k]))) + return transpose_cols(w, h, bytes(row)) + + +def write_header(path, counts, pal): + vals = [] + for (r, g, b) in pal: + vals += [b, g, r, 0] # формат gfx_pal_load: B, G, R, 0 + lines = [ + "/* pop_shadow_atlas.h — раскладка атласа ТЕНИ.", + " * СГЕНЕРЕНО toolchain/pop_pack_shadow.py — НЕ править вручную.", + " *", + " * Две половины, потому что и у оригинала их две (см. шапку", + " * упаковщика): кадры вне боя адресуют chtab_2 (спрайты Кида),", + " * кадры 150..189 — chtab_5, а он на 12-м уровне это SHADOW.DAT.", + " * Какая половина нужна, приложение уже знает — тем же условием,", + " * что выбирает таблицу кадров (pop_frame_tbl_is_guard).", + " *", + " * Спрайт Тени НА ОДИН ПИКСЕЛЬ ШИРЕ исходного: второй проход", + " * оригинала кладётся в x+1, и суммарный след занимает [x, x+w].", + " * Рисовать по тем же координатам, что и Кида — сдвиг уже внутри.", + " */", + "#ifndef POP_SHADOW_ATLAS_H", + "#define POP_SHADOW_ATLAS_H", + "", + "#include ", + "", + "#define POP_SHADOW_SHIFT %d" % SHIFT, + "#define POP_SHADOW_MASK %d" % MASK, + "#define POP_SHADOW_PAL_BASE 0x%02X /* слоты Sprinter под Тень */" % PAL_BASE, + "", + "/* Половина «вне боя» — кадры Кида (chtab_2). */", + "#define POP_SHADOW_KID_PAGES %d" % counts["sk"], + "/* Половина «в бою» — SHADOW.DAT (chtab_5, кадры 150..189). */", + "#define POP_SHADOW_FGT_PAGES %d" % counts["sf"], + "", + "static const char *const pop_shadow_kid_atl[POP_SHADOW_KID_PAGES] = {", + ] + lines += [' "SHADOW\\\\sk%d.atl",' % i for i in range(counts["sk"])] + lines += [ + "};", + "", + "static const char *const pop_shadow_fgt_atl[POP_SHADOW_FGT_PAGES] = {", + ] + lines += [' "SHADOW\\\\sf%d.atl",' % i for i in range(counts["sf"])] + lines += [ + "};", + "", + "/* 16 цветов, запись 4 байта (B, G, R, 0) — формат gfx_pal_load. */", + "static const uint8_t pop_shadow_pal[64] = {", + " " + ",".join("0x%02X" % v for v in vals) + ",", + "};", + "", + "#endif", + "", + ] + with open(path, "w") as f: + f.write("\n".join(lines)) + print(f" pop_shadow_atlas.h -> {path}") + + +def main(): + os.makedirs(OUT_DIR, exist_ok=True) + halves = [(prefix, frames(d, base)) for d, base, prefix in HALVES] + for (d, base, prefix), (_, fr) in zip(HALVES, halves): + if not fr: + B.die(f"нет спрайтов в data/{d} (SHADOW.DAT распакован?)") + print(f" {d}: {len(fr)} кадров") + pal = build_palette(histogram(halves)) + + counts, total, nspr = {}, 0, 0 + for prefix, fr in halves: + pages = {} + for id, w, h, grid in fr: + pages.setdefault(id >> SHIFT, {})[id & MASK] = (w, h, encode(grid, w, h, pal)) + nspr += 1 + npg = max(pages) + 1 + counts[prefix] = npg + for pg in range(npg): + nm = f"{prefix}{pg}.atl" + cnt, sz = B.pack_atlas(os.path.join(OUT_DIR, nm), pages.get(pg, {})) + total += sz + print(f" {prefix}*.atl: {len(fr)} спрайтов, {npg} EMM-страниц") + write_header(os.path.join(HERE, "..", "roomtest", "pop_shadow_atlas.h"), counts, pal) + print(f"ИТОГО: {nspr} спрайтов Тени, " + f"{counts['sk'] + counts['sf']} EMM-страниц, {total} Б -> {OUT_DIR}") + + +if __name__ == "__main__": + main()