From 97929b55d360ed70e10184db36b38a4f774542ad Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Mon, 10 Aug 2026 11:28:45 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D1=80=D0=BE=D0=B2=D0=B5=D0=BD=D1=8C=204:?= =?UTF-8?q?=20=D0=B2=D1=82=D0=BE=D1=80=D0=BE=D0=B9=20=D1=82=D0=B0=D0=B9?= =?UTF-8?q?=D0=BB=D1=81=D0=B5=D1=82=20(=D0=B4=D0=B2=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D1=86)=20=E2=80=94=20=D0=B0=D1=81=D1=81=D0=B5=D1=82=D1=8B=20?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20(=D1=88=D0=B0=D0=B3=D0=B8=20A=20=D0=B8=20B?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Порт tbl_envir_ki[tbl_level_type[level]] (seg000:1108): оригинал под один и тот же набор id грузит РАЗНЫЙ .DAT — VDUNGEON или VPALACE. Упаковщик (toolchain/pop_pack_bg.py): - аргумент набора: `pop_pack_bg.py dungeon|palace`. Каскад каталогов — сначала свой набор, потом чужой фолбэком (в распакованном data/ res230/ 231/348 есть только в VDUNGEON, два десятка — только в VPALACE). - ОБА набора пакуются по одному объединению id, поэтому раскладка id -> (страница, idx) общая и заголовок один: коду достаточно подменить имена файлов. - PALACE_ENV_IDS: 78/80/82 (doortop_fram_bot), 81/83 (doortop_fram_top), 84 (полоска стены), 145 (stripe_id) — их рисует только палас, render_room про них не знает. - ENV_SHIFT 5 -> 4: с паласными кусками страница 2 переваливала за 16 КБ (16 996). Цена — 10 страниц EMM на набор вместо 5, при 215 свободных. - *tile.pal: 32 записи (env 0x50..0x5F + wall 0x60..0x6F) на набор. Полная kid.pal не трогается — Кид, страж, меч и зелья в других слотах. Движок: - pop_level_type() (tbl_level_type, SDLPoP data.h:840): дворцовые уровни 4, 5, 6, 10, 11, 14. Живёт в pop_level.c, потому что по типу расходятся не только атласы, но и ветки отрисовки seg008, кладка стены и модификатор пустой клетки от упавшей плиты (remove_loose, seg007:0EB8). - pop_bg_load(set): no-op при том же наборе, при смене выгружает старый (иначе текут 12 EMM-страниц) и правит 32 записи палитры в ОБЕ страницы дабл-буфера. Зовётся на старте и на границе уровня, не в кадре. - Путь к атласу склеивается на месте (bg_path): двадцать строк-имён в банке — лишние полкилобайта. Проверено в MAME: уровень 1 (подземелье) рисуется как прежде; уровень 4 (-DFIRST_LEVEL=4) — дворцовые арки, окна, пол, решётчатая дверь уровня, Кид не перекрашен. Стены пока чёрные: паласный wall_pattern — шаг C. tests-host: 5/5. Co-Authored-By: Claude Opus 5 --- applications/PoP/poc/res/bg/pal_env0.atl | Bin 0 -> 9272 bytes applications/PoP/poc/res/bg/pal_env1.atl | Bin 0 -> 1398 bytes applications/PoP/poc/res/bg/pal_env2.atl | Bin 0 -> 11935 bytes applications/PoP/poc/res/bg/pal_env3.atl | Bin 0 -> 1875 bytes applications/PoP/poc/res/bg/pal_env4.atl | Bin 0 -> 4280 bytes applications/PoP/poc/res/bg/pal_env5.atl | Bin 0 -> 13634 bytes applications/PoP/poc/res/bg/pal_env6.atl | Bin 0 -> 11601 bytes applications/PoP/poc/res/bg/pal_env7.atl | Bin 0 -> 4286 bytes applications/PoP/poc/res/bg/pal_env8.atl | Bin 0 -> 7454 bytes applications/PoP/poc/res/bg/pal_env9.atl | Bin 0 -> 4490 bytes applications/PoP/poc/res/bg/pal_fore.atl | Bin 0 -> 12308 bytes applications/PoP/poc/res/bg/pal_tile.pal | Bin 0 -> 128 bytes applications/PoP/poc/res/bg/pal_wall.atl | Bin 0 -> 5267 bytes applications/PoP/poc/res/bg/pop_bg_atlas.h | 38 ++++--- applications/PoP/poc/res/bg/pop_env0.atl | Bin 10578 -> 9272 bytes applications/PoP/poc/res/bg/pop_env1.atl | Bin 13481 -> 1398 bytes applications/PoP/poc/res/bg/pop_env2.atl | Bin 10798 -> 11704 bytes applications/PoP/poc/res/bg/pop_env3.atl | Bin 12937 -> 1885 bytes applications/PoP/poc/res/bg/pop_env4.atl | Bin 11283 -> 4296 bytes applications/PoP/poc/res/bg/pop_env5.atl | Bin 0 -> 12800 bytes applications/PoP/poc/res/bg/pop_env6.atl | Bin 0 -> 8005 bytes applications/PoP/poc/res/bg/pop_env7.atl | Bin 0 -> 5040 bytes applications/PoP/poc/res/bg/pop_env8.atl | Bin 0 -> 7444 bytes applications/PoP/poc/res/bg/pop_env9.atl | Bin 0 -> 4175 bytes applications/PoP/poc/res/bg/pop_tile.pal | Bin 0 -> 128 bytes applications/PoP/roomtest/Makefile | 17 ++- applications/PoP/roomtest/pop_bg.h | 2 +- applications/PoP/roomtest/pop_level.c | 13 +++ applications/PoP/roomtest/pop_level.h | 7 ++ applications/PoP/roomtest/pop_room.c | 86 +++++++++++--- applications/PoP/roomtest/pop_tile.c | 4 +- applications/PoP/roomtest/pop_tile.h | 10 +- applications/PoP/roomtest/roomtest.c | 14 ++- applications/PoP/toolchain/pop_pack_bg.py | 124 +++++++++++++++++---- 34 files changed, 250 insertions(+), 65 deletions(-) create mode 100644 applications/PoP/poc/res/bg/pal_env0.atl create mode 100644 applications/PoP/poc/res/bg/pal_env1.atl create mode 100644 applications/PoP/poc/res/bg/pal_env2.atl create mode 100644 applications/PoP/poc/res/bg/pal_env3.atl create mode 100644 applications/PoP/poc/res/bg/pal_env4.atl create mode 100644 applications/PoP/poc/res/bg/pal_env5.atl create mode 100644 applications/PoP/poc/res/bg/pal_env6.atl create mode 100644 applications/PoP/poc/res/bg/pal_env7.atl create mode 100644 applications/PoP/poc/res/bg/pal_env8.atl create mode 100644 applications/PoP/poc/res/bg/pal_env9.atl create mode 100644 applications/PoP/poc/res/bg/pal_fore.atl create mode 100644 applications/PoP/poc/res/bg/pal_tile.pal create mode 100644 applications/PoP/poc/res/bg/pal_wall.atl create mode 100644 applications/PoP/poc/res/bg/pop_env5.atl create mode 100644 applications/PoP/poc/res/bg/pop_env6.atl create mode 100644 applications/PoP/poc/res/bg/pop_env7.atl create mode 100644 applications/PoP/poc/res/bg/pop_env8.atl create mode 100644 applications/PoP/poc/res/bg/pop_env9.atl create mode 100644 applications/PoP/poc/res/bg/pop_tile.pal diff --git a/applications/PoP/poc/res/bg/pal_env0.atl b/applications/PoP/poc/res/bg/pal_env0.atl new file mode 100644 index 0000000000000000000000000000000000000000..5d57118f262811e2e7bc3334f754183b797ac427 GIT binary patch literal 9272 zcmeHNyRI8I5M9HCs{}#d!hnkiX_Zfkd$sdy zf4^5=fmM<~SkC5WklpSaB%SHVwMeGqQ?;Q7s`F(@~=Jil>IqjHnW>l-&nMBxAU|Ev4Y z&87FCdH=(-d;i09p14mt_aE?C1)BF?U=e8Ee}V5}p|$@79`6tk7dHE!_$asv6#I|c z8OsB#qdN2{FyT3<_dl(JUkE5r@SA$n2VOq^hToyD1m*J|y`y=H z!1KeMNFVh<;Q7sb(ia>HB8~Y619AUQe_i7W75q{EZf&gjabtYj@+-T^aDj58e;Yjb zCb%g}pS4R(6Y|(=Hbm15)2%|XdOr>Cd>v$6le*_W zIO)pX=F;k2ueW;F>vJ8jdRX?U-cc~+B<6*9o$4KP5zAZM=bDpi66I{(@?h#mn%>qy z$7$T?+nm{lHm7m>I_Nl4ZiaQo^@-w7XAn|1Ih{{Ae*YkCEOfF5=&$e(u`y|R+Et?oOn)>%`I_So)b;#<$bSd+GjEcLX7cxG;8W;$!XA=O=9p5 zfs(ih-wiIDO4{I8?b0cCbpWrz?c|+lnLSFPbiCH_*9Y+0i`#5;mc`(8pZz$;wO2iv zKY}06al5N`?0@#OJvuPImtF>kX;9)p;Q#4{v(sdr`+kuxN3TA{DP=?qDd zT0e?NFud^%eTwKI6N}x}hX5rIM@OG(BGA(}fgOFZu%}OfU401b>wkhAap2$q{Q2j| zg8&cUzmQ`;41AjKT|kfn%{e}6t_wi!rZCsOf#Z-tqD{?d3OQuLb{4u;e@!PuI zVth^fa-e_6pVzl-{{VOE-_(B;clW<({|G;fKkx6h{R2EbKinUicY6L%u3IfVzfTXf zXKl$wd0k#TJ=NDq?SVmUv%D^^{y`6(pOeo`j(yZ=C&9lrI1R4{O|kfvA3yx!m!0Z8 z&pF4lRM&6(#%whjHL%%O!K?=7Lwy>-ey)M?+wzRBVCQ+pEL%|nwVVP~O!25MH5lWB z>W)qRM?9!*+Rmv)qK-}QQ{aTM#SAB?J#GaWWD=k8Z|O__w&t^cV!!s@oe?_tTkOHjwp;WIHSDL&jswJa zv08OI&xEiiu#ja70_lA`pRu=Km%n1p_@Zi|K`QaTG0+6$j*Sq+U{L<75)hL3^GOYg z7DHCekRdu~hZeC4j?6`av5_%UTm=@nWEUnaGS2u(J;ue5O$j|P<8p3@fP=tXXhF@m gG~{TJdnG}Pc&nvrSZFC*&ka~K=QnO7h`ul3Px=fJp#T5? literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pal_env1.atl b/applications/PoP/poc/res/bg/pal_env1.atl new file mode 100644 index 0000000000000000000000000000000000000000..634d3987005977dd566b5581f88713ce58d4f193 GIT binary patch literal 1398 zcmcgqOKw6j3=HA|l@J?NT%kwk4N!=bAaQ?n(L010fASG|bWu?+Vn2^(9LMi^`TG0_ z@3(KX*zH32FaHzH2ll({Pe*#%IUGWLX*vG_{|V2qSNZ@q@J76C@F|_*7QNOOBMR!e zKgp!W_^h5Yh(K`C&HW*#X`Wg(Dj-`(gs!NgN1E_bfQvMclu+O22bUmjMR6P`z_;?L z4Ae*ra*+zt7Yb1r$QB^0xPGU*`Q{W)1`IGm{j9Bc9h|~3@N(mvJ;n|48WLm)5m}S? zzpOi9O{L7c@=JhmTMdC1MtgbZ`}i{U=G=@=EH8mPwj%rGYV`FHNS;5OZ4FL%mWPT% zx|f#6Ff631?b^2uL<~sN_i;!E_>^zA9rT?u-^a7`+Q0Yhn9tQS9>%XhWKeOd+D&(qQI~VWNqpsaGV}tSJ)ADhylCG-gbap zp?B~^Ql_mRQb~sbT_GX1M1G_w)09LjH`7laUYW-)_vZ9qXUCXtI~V&<|9C<5uidj_ zpg-?byHNk!t1h8_e^?zt{rhNg1@-Og3DWm(i2wbJ^j@Bm-q-W$2;@G#txlkxPpF?i z?<&-XCpe1@x$Nqc$}!%)VLI%VoXcwXD}u zE8i?PzEFO11Ju7AjkU1Jh4S?l#g1pYG6f&a7glL8pFdW;xLd64HQ%&uw=7#Y2t}t` zmNRo~qTmV`E>M|U*Vv5N4q!oS;IQHVCU!Rf)LqYJAY?NDoe$D5i`cHu?z$CD&p?_r zLTLx2*w#jx-F3hR&8P_MuB*(hAy4waqsB}xwGPkf%3PYdwNs!?4-Q6Kw>E@T{BCil z;x_zM+)h6g&*^9FXU3m<{v2NXQ{qRPKP7(j_$dC-{gYW=aLbY7FWNNHjBva5X`kZc zG~Lw$xw;J~)S~V?m?V{g%~MGpFpx)pfhLC3sgv z7Pl0)j69GHhs+#PQ-f!`w&>4I`;52^lm8tY<`w<-IKnaL!M+8w>fWu7SZWN8jv~l_ z4>Ftv83r4nCYWd2DNs4>7`Y{_={lD|Yg+@AQxLMJ&M{F`hsM012!#ygnEOoaa{(XLNK@J_vG{Lt|jOmWM_-9r%Ha zv*GDSsHY$FOeE_kQPu}^^i(K}H0q1!YGrX0mTo%QH02yOxiVRIrWY)Mt*l_;+6Cvh zxpUZm#Vd1Ur{H=GKdH8e#o;E@pbE-T4WM$Vx=ztn${0{cegi;Jaqr}`mkDQ=% z*&*4tJ<~4~=c;`?) xWGN3FoduGO0A*Z283!|wE<6I;PomlX5J+Fpb^R--wXdSeDV*~^JKE7<^%s*NH3$Fz literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pal_env3.atl b/applications/PoP/poc/res/bg/pal_env3.atl new file mode 100644 index 0000000000000000000000000000000000000000..11e3b6240f9d02094dfdd6faf19d352ae071d94d GIT binary patch literal 1875 zcmd^7OHKnZ4E0RrQ&m%Sh2$QCRmHOE1!$*;%*i+kS75=81;;6V$;1iiP=u;Vm54O+ z;%6szp4~rg?mN2vdZ*Q*D2U!974WX)4)|b}bKr;J8Stgz7Pzgs0e;q81N(+6;A_JM zXj(3T>y`^3)`}K%{9zrY`NPwsW8Y6YcKiR~VCqE3!CDb*c!qL=eE#*q!Z_ir#5>;q zH9n1mKiqSM*Bi2UZ|dLI<7-n=Hox&{EcPM(Z~T(xxki~ZCyGQVU8>yt{%j|5Ea|)% z<7CG)iLxd!^Fgh#dMh`$n4HHkoK;@-Y4*s68^kZ! zJ~s)j>#^y*YS#UTO9D%*)zq=*tWrqb+ zu|Sitr2hKvhcvE?A3wZ*YySTDPALutW6Jr5dALdK-wxd!_Mfl1Tg8@~2~NI~`BQV_(|HDYKE!iA*sbt2kC_LukYg zHc^r7lh{^Ouyy9HQMXoemXX&Mch54;=V(b6kv6$T-iV*kO8*=&a?mDC>vPIgBs@xG zAps&UXxJ*pmg8~K0BL64rXhdgoh&t)PfV?)%}3?ZncIK+4yn(0#%$j#pC8&jH9QJWdG%mmtI?_tl6Rd*X^?{O#U!w1lM z)Mw0IwfXdciXU!G#`iha3teLgDwCvp@)^Nh6X%#)d37~?pNd*5jq zDZYAwq&-);`>d9|+~l~Qd+6Ia*IKe%jdR%S8$wP_i)P=!zUFGzQuUwT#c%hY{>Vb^ zwSPLOWWbl-K8H3e!}LWXS9YM}%d|@pbp%up`K8pk4h0K<~vQV{=ivwY@J4=bl0aL1< zJqlA?aMsT~;zoH|Kk}1aIRaDmB);fTFv>$^d4Hk@NB!JC9AbT|p6bWh;V?NeemHG_ZR+oqJP8(2g`AaQamSZ9!GPNn?Cuue8WR`BB~m Y6~0Zu_o(o^qqIBlJxV+~ja-Y}FXV|iu>b%7 literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pal_env5.atl b/applications/PoP/poc/res/bg/pal_env5.atl new file mode 100644 index 0000000000000000000000000000000000000000..cf17816e927b25b0be2f8ec06383cf801a4b8063 GIT binary patch literal 13634 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 literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pal_tile.pal b/applications/PoP/poc/res/bg/pal_tile.pal new file mode 100644 index 0000000000000000000000000000000000000000..df429b204b053213dc0762b38a13ed9ffda63c8e GIT binary patch literal 128 zcmZQzU|_I`tYq-1T*weP^$Z?u}dE@B(8eI5W4UdSRaTVx%3uL4kUhyq4Uyz VhN-vygXxJtI$-7@hSFW{7y#UHH%0&e literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pal_wall.atl b/applications/PoP/poc/res/bg/pal_wall.atl new file mode 100644 index 0000000000000000000000000000000000000000..1c82e43a0edf336819d68b072f8a4b43dc15c115 GIT binary patch literal 5267 zcmdT`OKuZE5bY?59I(yDVPg?la|6T$B5?x{3)Ztj@^6m75m>O`C>(+X2jK!Nked4T zRDZ@ZcH%g6q^YX+s;aBse4LN(-@To=oyj)yj{9(rS_iS;2@#pL69PLlBZ(ebXC!V`o zx3+6#mc`cwU)_yp_HNZ#VTs00We5we*MW%AAxDTN#hJ)qs%SQwEFXvsuAE>zBLq$> zsEJ&{8JdvHj1VcTdnDOd!xhrkniCT!mmP0L=r0grkLQQV;u3GSl`6rW)q6D^z&n(bk= zt@x!wj8-6QHZn{k*+R$*O%2-1vJ87)Xu?&vXIpQ)4%qv-n>v#hxvMA&0em`xZ=41{ zsU{XzKC~$jeiULNz;P>S!faa+KI1WgpSD5;fAKPc;jBVoux6<4-@+?5QX#i8VV7+W zz}|L1t=4EyjeVh3In7n8c(9e5=*$62oH~h55!Sw@rF+*j6hPiThVgW)K{gxs5!{1p zrt~BtIKrek#8|`EH2L&#?|IS@AK)JJ%`|{Vxm9vV$LAmZ2+6B+Bt7)*_`&N7_u$ww z?A@Ow2jNh6d?`qL6p~sE?Kd=U_Z{kH5AI*Nar%33aIfz1`k3%U2Zdn>^!ah`D`&oM z?mm9lE(c`YoLXZNlH|mvc8Cr`a!N`ZT371j7w%G@&E0*E!-8Pa7#)_6=d1@$Ry@}o zK^ZF^PkS!h#Zfg2ir|JpcXH~=o$KB@PHH>W|Jp`IJ?3 literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pop_bg_atlas.h b/applications/PoP/poc/res/bg/pop_bg_atlas.h index 10e44d8..e62944c 100644 --- a/applications/PoP/poc/res/bg/pop_bg_atlas.h +++ b/applications/PoP/poc/res/bg/pop_bg_atlas.h @@ -2,32 +2,40 @@ * Сгенерировано toolchain/pop_pack_bg.py — НЕ править вручную. * * Прямая адресация (ноль remap-таблиц в W2): - * ENV фон id N -> atlas env_bg[N>>5], idx N&31 + * ENV фон id N -> atlas env_bg[N>>4], idx N&15 * WALL id N -> atlas wall, idx N * FORE id N -> atlas fore, idx N + * + * ДВА ТАЙЛСЕТА (порт tbl_envir_ki[tbl_level_type], seg000:1108): + * 0 = подземелье (pop_*), 1 = дворец (pal_*). Набор id и раскладка + * у них ОДНИ И ТЕ ЖЕ — меняются только файлы и 32 записи палитры + * (env 0x50..0x5F, wall 0x60..0x6F), см. *tile.pal. */ #ifndef POP_BG_ATLAS_H #define POP_BG_ATLAS_H -#define POP_ENV_SHIFT 5 -#define POP_ENV_MASK 31 -#define POP_ENV_PAGES 5 +#define POP_ENV_SHIFT 4 +#define POP_ENV_MASK 15 +#define POP_ENV_PAGES 10 +#define POP_TILESETS 2 -/* Палитра: env-слоты, wall-слоты (сприйт-пиксель i -> база+i). */ +/* Палитра: env-слоты, wall-слоты (спрайт-пиксель i -> база+i). */ #define POP_PAL_ENV 0x50 #define POP_PAL_WALL 0x60 -/* Имена файлов атласов (грузятся atlas_load). */ -static const char *const pop_env_atl[POP_ENV_PAGES] = { - "pop_env0.atl", - "pop_env1.atl", - "pop_env2.atl", - "pop_env3.atl", - "pop_env4.atl", +/* Имена файлов атласов по тайлсету (грузятся atlas_load). Таблицы + * видны только тому, кто попросил POP_BG_ATLAS_NAMES: иначе копия + * строк уедет в каждый включивший заголовок модуль. */ +#ifdef POP_BG_ATLAS_NAMES +static const char *const pop_env_atl[POP_TILESETS][POP_ENV_PAGES] = { + { "pop_env0.atl", "pop_env1.atl", "pop_env2.atl", "pop_env3.atl", "pop_env4.atl", "pop_env5.atl", "pop_env6.atl", "pop_env7.atl", "pop_env8.atl", "pop_env9.atl" }, + { "pal_env0.atl", "pal_env1.atl", "pal_env2.atl", "pal_env3.atl", "pal_env4.atl", "pal_env5.atl", "pal_env6.atl", "pal_env7.atl", "pal_env8.atl", "pal_env9.atl" }, }; -#define POP_WALL_ATL "pop_wall.atl" -#define POP_FORE_ATL "pop_fore.atl" -#define POP_POT_ATL "pop_pot.atl" /* chtab_1: зелья */ +static const char *const pop_wall_atl[POP_TILESETS] = { "pop_wall.atl", "pal_wall.atl" }; +static const char *const pop_fore_atl[POP_TILESETS] = { "pop_fore.atl", "pal_fore.atl" }; +static const char *const pop_tile_pal[POP_TILESETS] = { "pop_tile.pal", "pal_tile.pal" }; +#endif /* POP_BG_ATLAS_NAMES */ +#define POP_POT_ATL "pop_pot.atl" /* chtab_1: зелья, от набора не зависит */ #define POP_PAL_POT 0x40 #define POP_BG_PAL "pop_bg.pal" diff --git a/applications/PoP/poc/res/bg/pop_env0.atl b/applications/PoP/poc/res/bg/pop_env0.atl index 91f08be77b1b7d61edaeb029737ff38c43f2457f..5d57118f262811e2e7bc3334f754183b797ac427 100644 GIT binary patch delta 149 zcmcZ$O=qS-)=^TlQih`2fZ;1Q>N?JOeKuv*o z20u7vcF&F-1yOO5Z})a)b~n4q+x3U--`-rEo8_)sn(gu-j-nXfV{9&HcT&@%eM-#< z?blH4JX2fqf3wefW=`GAm=SHwdpX?iyhFTf2sQD)?fcARZ0z)SI*#Ml&-IiLl#C8H&Z5qoQjlBUh_<}77NJnRgjI^QDsA7+ zfeJounnfFfklFw$t&IaKC`4W~AT{$2UKGGf$?b9+w$TtE25KRc8fZ9Y62+MsXb{nH zg)l+^kr2f}{oo*~xW4l{fx|Hq)$ diff --git a/applications/PoP/poc/res/bg/pop_env1.atl b/applications/PoP/poc/res/bg/pop_env1.atl index ce903220da26f7f36e597899efcc1cf68d9f18b9..634d3987005977dd566b5581f88713ce58d4f193 100644 GIT binary patch literal 1398 zcmcgqOKw6j3=HA|l@J?NT%kwk4N!=bAaQ?n(L010fASG|bWu?+Vn2^(9LMi^`TG0_ z@3(KX*zH32FaHzH2ll({Pe*#%IUGWLX*vG_{|V2qSNZ@q@J76C@F|_*7QNOOBMR!e zKgp!W_^h5Yh(K`C&HW*#X`Wg(Dj-`(gs!NgN1E_bfQvMclu+O22bUmjMR6P`z_;?L z4Ae*ra*+zt7Yb1r$QB^0xPGU*`Q{W)1`IGm{j9Bc9h|~3@N(mvJ;n|48WLm)5m}S? zzpOi9O{L7c@=JhmTMdC1MtgbZ`}i{U=G=@=EH8mPwj%rGYV`FHNS;5OZ4FL%mWPT% zx|f#6Ff631?b^2uL<~sN_i;!E_>^zA9rT?u-^a7`+Q0Yhn9tQS98q_5Z;q4SuiX}Fc612DFC}52JA$!O2a^a6e&^|QF z2ziT?d5n~4k}~aPX7>M=luu_|f~7$3&iC!i><(wS%RRTRzPr3&+rNICJvy4r82e-P zGrLHz>D*T*&CZ%*bfQU2{S(eCHZ>tmFU&gLgrewYirf94nG zDF6M%`C}}$19!@-N?3)X%5S zs{@pOeO}$e^7yKvey*>oJ(S;HRWmH{dc=+xcdx}_;Q$~z2+0;AWsPWAB9=^uly79o z9Ug@z?2z?C(>Kj9jNE-QV9TKy{nIT+jjER5e8}IjWk2Dfem0Y?0mt7BT|4b=ySANn zcRkpgbWa$NY62mecJ;%nY1c4kr+!ZAglxlfq5Nr~MUY4UAnr4mc>?ztgZqqX?_0BR zTgSzLk?HQ^N+-kx6T^{-19*17mN=*!0_!%*xj(}x3ekvPZ*`9`XD`G3czR!^q7m-c za!l$il8z1bARZN&50QA~bW+ctjFjsPFV8f#lh0*HE~`rRrrujyny1NSF7+u32R5#b zTt(?1$7M(&Tz%79yu<@W;~rz-z?h}m!7UvR*Gzy*CV~?a#eqrSoFftcGEd>02@$*b)72GH_dRDA&GF^QPV);0i$t` zv2b9_fF0b@@o>!qxMU(YF;N_t1paYvG&~I*JIx&9O=zRF=7OF3GxB2(dvkiX=UO;) zroUFz^u)0$x3?>lr|Y>bH<#3C;O7-JLMq)ucGr(JV5sgkCweExCdcUZUrC>O9Lg`1 z=j^ec_kd@*v~3C^=4J#*y3ekAM{)#r2wSFf@37+fA_^g$<+)sl=#qiB*`1t*sMHqHxQ;#2Y?{VFK)qs)*0?)+FRa`}s!^E5BE?kQev?Bl#*>%sAS=`1*mH~P}eO{L)k~aD4|Dj3BL*< zk_Z=9tt~qSa@rdUqJgsGHJ9V{QDy&>JqTjt$0m%4iKd8!9|M2vA_}I*CMu#|zHC|| zU(tW=cb+3OST8WWy}qtMCfw^Yc933W`Z=Nn$^jKOIR>;qIiPSk7NT+7Hg0=2xUwK} zK;RX-&+OL7fxM%AJ!HEVzXQlqnRlQ3+1*3m;8i}gt>ni(%|qb>U2T$Ud(xJjabx*8 JBb`|8{tL-Vd}06q diff --git a/applications/PoP/poc/res/bg/pop_env2.atl b/applications/PoP/poc/res/bg/pop_env2.atl index 9773976404984193187426e80cbc9c205a5e9efd..584840507b1ba3db541e8864af8290191242929c 100644 GIT binary patch literal 11704 zcmeHM&2H2%5Oyg=Jy3O3iGs34AenI&&ogY^#l;5A!$C!UV zsc$fUc~%p?If;PA z#Hmnz>blMYK=u%l9Yo6(v9d-SnGh}C>s)y}3fJO=7-Tavjg&Lb&`7K)o7q2GbGA`a z6FQgqN7oz{BpPS4C`p`uFZ*`c)AntW8hlxU1viz-V(1aibICBg5gy@VHVboR;Ac|JCAH zG~9wa*e0KvJiTdZaU+x*$Yuwb7`z;MFvWfkey)A;u1x#nry0Hn|HzGRPJh0C@abIt zWqr!}Wb9+k{)>MV|H|zzd)be3Ts%V2#FW(3y*YCqq2b+{aEIZRcWY&)cD7+=?%Ddu zzG{rcW&%7oqqE7J;i=dY`CJ4``k8nbcsgV8oaLSc`t$u~;%4lh&e+5%Q2(@t@C%7N z&Of_H!~8S+L1TEIxaJ-5l3t}Cbf&C*9J$xuZp$@X1#JcsdrFjs;q^VcgjWb zISa{IRk7aGzI7l!O&)WpPg%II@pbemN*6gkLlWWUo8I9y9x)aV7zYPtI=VgF(Ft(N zM7U-coER1dCV?x31pj58!j;1N9sVRlG;xRy1AIjD_g8~VMGv5ph#Lm%ij5X>I+=cw zV`Ju{zo>8seoEeTfIlQ6gq)}B;a#;ji_d)XqP1ZgG03gi2lyzCEXAh`Z*{Q{@g5uT z0UPj!oqWk{->_b8`}fdE(EJ40(%1>{7PAE#n**;wXHd2pjNd79#Y&tD4ks+ww`@J| zS6iln?wdT^XGkL44s@!Z@rbc_z&JQC(}X?T(Ft(NM7U-coER1dCV@X}N5k9Dx!cS+ zep*_#)Le;m=#dY-?9J)z&b4sqOnJ_h=VAJ#d@U|Ry9Ycoq(f7%V!lO?WXJ4x?@6BEPvO9n9UT_@ zzKBA|T6xYE7+q?BZ}v%1lcmF4>9-{_yfEMP{dSZ5iA|}(m-Q+3k=_c5e-!`tfBmED za`ubCd72+X_Y`jed!9Ee-@ak-%PH13?3jnV&xZOT>+>;t@AR+P>2r<%(|@e15jtNx z_ICxY&OE&xu|G*Eh;6GRt z_uNJJ7_f_{%-P88=-4EY?GyMDG$D?65qThP{>FC92q<{U{_!R3u zkH<62?>~R}9P?Kv7d-#=WIV=tJe9fD_fOaFPsc~l|KyADHRfN=FWz7_y?=c9>@C*6 zzB+##>3_Wv{-3`U{@=elI{}XIVmKXAGqy`ZO4oBqyS%!-x@u@wDHXEBbDdJw$5QFK zqLEaJd?H0O0w9~Ea1GixJni_c9&TqIrN6#Xbgq0aWN+r1F7C20;2Q0sKpVV5E8I}B zYs1viY^XszJKjZI{|c&j7ZoS6-Qd(rkX%V6UUzG1p10E!xll{1kMK+)z z3(z40=#r^}u}k<}j}>xCU2aHUP)=A&83I{VA$Arryp8)Vu0Ihz4zDX8cF??A7V5Ubpe+vgAwGxtIP}N= z^n6&t`M0q%G0zK~oO(XcJ+Ech(V+VV1#e4FEsV$K)CBD+-^G^(FP?Mh8zLXyIKQ{5 zzR;gwoo!E>%_eQ}IGMdqu&>Px_cuM(cXE4_HMf{en-T)WcDR-sO-P?(GUl-0m=r5zOGo;B%Tz19%Z2Mo5{8_7HZUlo1D7 zA&m{IBj=>0BIk5R8oDAKIwM^=AuDuLD2-q@CuogMGF^U10>~QT)fzpeXTw{(SJJ>z zI7ox8Y2y2fFXeW#cgZCPKcq^DR|XX0^#b^xr_g+`xiBL**_o5tNBL- z74?Jj-G|jz$Uh#hY;g7Mt3UWx#m}lAalU8$q|7U&=Sb09u+|$3;F;09WZ@WYNDteP& z`2+*>5bsBwJ@-mT^wZIK=2t$*6a5q$V#5mX!@q}8T>dY~gs+6r?f6x(a2j=2%LoJL zIq6ZEgvYoFbq_Xf)lQ`f4s{@DKh(j4t!sI8W2YQ$GyFs60n_q7MOZrvT?KgC`e8aS zYdCmfde$S2Ll8?X-%#n)jNJCeoLuaH*CuD_wzgIqI!%6%z YemG%ZM)th%`-!9lh^9ypOIU;a4W|RVw*UYD diff --git a/applications/PoP/poc/res/bg/pop_env3.atl b/applications/PoP/poc/res/bg/pop_env3.atl index 5a30bf8d1e7a3419e34a0594276db848ec97eb19..754aabb50210c693cf771d6d3edcae1dd7b7452a 100644 GIT binary patch literal 1885 zcmd^7OHRWu5S=u?s!F78kfz6A$+8DPLWH)?g2QnXb}YC83r(^$Pe=@)Gz`aSOb!xdDFGTmzpQu7Ix% zm%zT|1#sJP0mRx+PseZ8<2=6`W&`{EY+%^^j{s9ALLQtG(cB2-4)WRUM`w%%6W$$1 z%fz9CPbYy(HA>(v}Jt*qd^Uv@*z8^6RDH@SiurPoh;qoH)lirHLcDx z%C$MyB&umzY9tgVm zJD`GkAn^V!8pgd-KJ6a)P{BN4JX1?)He#~B(pek2KK*L(fcM>>zg>mi($&A(Mf_2! Y$E^oi{l;qxUn_OoPyQ_Q%$#?>0B>!F*#H0l literal 12937 zcmeI2O>P`T6vx}LJyIfBN+KdVaU8~Yfx;?Ck=S^H!~x=Vk3Az9d&`0)$KVRAxds~~ zmRx}aD^9=yHShnv>Q!}hk3;NWMJ~l%Rqyw{>Z`kFGN*69{&L>je))c5zPYi{G{0}m zcToSZ`TP;;z3o?9sK28>)W2-ck5PZKBlT~e%wMAaeu`8$EZzzUELk*??V6A zPxm-7%rHqqm?pR+t2&w@tSP?ze zWht6g7_d~P(BxtdfHblRf=K0kpG^$|OWQs1V0-o>4AX<9k{G6snh1dAlaZ=E+f?@vxPebsQTP-slJtzq3&6%^<%`X>nubA@59 z&WS;#;G{rOa8jsovVuaDL!XSOA`AzGf90&gIg}guZD=crjR(&8zz}JFIcG{4~ej8G6j2t*xKeHnDPsQ z@fgBvQ9D|-!F|uSRN7#bQ>J^Ew&ra-gL}UR@c9{ph#Uv3RN(9=e>wb7p@&E@I1eo- zlsqYr9Vz!v2=?w_X_g6Vd1`g^sV{SwoC^wiF~V1u%is z-c=rQW`(5BiN`Swc*V0CiE6D8e((f$IFy`jQ^xd~pTcNOV4pJCa6v1{ap5C-XzEWh0yulk>sjF*~m{ zf0~c`XE5I*(me1}tC?5q}h@l1DtHGFs< zF?+U5=f~Vj{&>c*=b?hz%U!utkheK~Mk0EqVDEa$@6WJJh}1Xu9{uzd&v3TKc|YjI z&O?;Nww;G4i|ui4o@G}?8)=*6T8@1#ldVp~b2w?XB*vjYyI4GntvqL9WZmUvi(0-C zLOh%#Jg_6>&r0yDyrhvsM{UC`-Op&ES%Abdv3KkYy1*MB>a*VCJG@6_GIS5big%h# zRRr?7?rX(+BJjndSnJwhIQ_az|z z4}tG9hzGGWZ|pv{-|S9(CqMCZJl?VgMc$ez=`jX}BaA+lR~emdd}6OMK~+}$oG*6+ ze1s;CxzB_KjBg^e3^>qkXZpNA@|jmzx<&G~f)xtKGgq>g70KNXNOlvhI){d`kE(D6 zUAjUwSh0Kbqbum3APKIymtQ7Pt{Qt;=m?6e656Bx^tBm5LRvVxY`0mulykP#Oishr zIT9D_0dYt!8^SbwE_8>PJWU*}4LJ!OEMEY)EXS$xVXI1yUoLV z?o!4&bv86hSZB_}p06CHWNyJBr?#0Vu}I3Kc+yDS^t3L`4VQYRZameq=Ah}1xqr+R zUyrHuxZpZ$D0QHH)h7cGxtci`#PJ`?u6^lYN@dnOTbHr=L>3Z1Wh63H5SS+=3A&|0 zw+O^!DYGZ*GD|51$7!Y_hC<#S#(OXk&&F(4JoOkIm91u5EYammpw;*L^m7#OQ(QjU zg3+D!r>FEcHqwa+xSJ@ACygp(8k*&@-fbkKiK8p?=f$iDMRen%8;vvxLK-ic!{Wn2 zfRj!>1f0s{U0GZ;tYcY*lB99_ERXQ+J>Qw(UQ!$7^xZU%o5qjUU10ed=K1{}ISw;; zA4zS751Kc{`IKM%oz(&nI_WP@PR`B-7>Ekd%K=_2$c9RLaz#Hw%Z=3|$*+bKF3BUY z)@(g3iAOf@33?SAb1oWBD1|js&c@v=!U zySAS8!|YhwEiB4X`)uMz@%}xa-5`tFza=c>(sk-zYDTp{E1aqQo_oN>mVUNuPNHK7 nlci_`4neRixOCH19jQG`<1fbD5p!4#Jc}#h(ipi;)2{m$lJWw& diff --git a/applications/PoP/poc/res/bg/pop_env4.atl b/applications/PoP/poc/res/bg/pop_env4.atl index d426803a17cdb0e031eb0c7778fef8f25f3a806e..18bdd3e5e430375a5958babfe5b9b15036821194 100644 GIT binary patch literal 4296 zcmcJRO;X%25QR-aQegpM!3I{oLiQ=Das$SeouMk@$+5D?B1g+2_fX#JmgJT!85W5c zEUCYK{Udn_#^*1eK6d|q{6>n4i>@o@Ki&Pcwg0^6Z@K?|+23%!diQY0`N#W5nLmH% zFS-8}<}zN~UtRZ4^y9eit~+`Io{5mA8JX zf(?M$RmC-JeRo@_J5)G28F{^F7pN<0&$Qp%w<=FsCP)$EBBL8#(1J&bym7>^m?Moy z=ESQs#c$BSt5l0v^O~X@P9|*YRjnmX`B*_%_1#VT4!zHNOwEQxh*6piZQWsrtN|+e z5V^rKn$9?eQEHAW0+|afw}uxq-GRE~biIQbHNIKGV`h^%n@wN3MyuTsu|y4 zcFDTS(J*^o^``m}cOp^pBhX!O#K{F|(pnbbFqpm|g2f(Bz$k-#Lz2B9#txEhz-4x$ zDeQ@C?15D5LaKI$~iRqrcjb&@o)Rj z@8Zq<+ZS!EDfW+pGK0SI?VF{4f%e-9S8+gcI6!KluIa(r5)Ch+PV|u&K`Yi}STDcIq1n3@gP2l79GJs$d5^Ftpv10%bMuX+~D@>p5kpX$k3zw}RsRNtyc z{X9EdBXLta6(_a;-A*RnOva zNzMGsi&J8iwtt3`{&$V&Q)e=pfT;}gmPw=s;7dQVOmv~W6|R;nCtWz-fl=$kaf hXZDSjd61vwHK_77CEugU^NwtH=$OF-&Q zc)HB_KWAp{*dZyQC|9ay&i8%icjmUK+ttPQU!Qbu|M_a~lW{wK7n=p{`@(t zzkM*D!TQJH8Lod$W>c_#o*wMO`pa~J_O~BSab0{gMgNPBr$@lQK6-Qj>+eUW6Ieez zo}a)vIhj9$_08<;7}oVC=PzM>k$%DY>t_p$_xkh2W3az@LF-@V3(Wh&7f-R?@4h_7 z6()4j9d<+Q+0?*LjSr>{_RtvwCB3Aryu15bnLRCD(bjX^N)BWhTu@S*}g(Qmt84GYn_{>`l?La-nQ{ zmu!p`ExTis`&Mi=o&031JJ_|^Ew2ZbDYeE(657~WS>hu{ENUvN%}VL)D`LBw*r>2* zzy|@W4u)s3SZ39geK|3*meqyUPMd5XCA8*hvQ(JUYDUF|SvT$0W6yGgST5^K!abvV z#D^h8BWQ_xu+jsyq%A|3QE?BVH|xnqt8@CmWVl8vaAqnvGF3b=Bls`?0hN@`7(NUK z-9G*q4wt)6AAP@>q{D#_df)Hd(E9@^ss@6>c!T$Jr@SF=i{7?rt&Oa!hKb$V2%<@q zDNCeeW>QTUpLR*)h^eG&4_wid_exd_JLSLsYAJ}uqiZyY>YMm-g_Om*N;X7sY&4ND z7Bi~JWSEyWNvaW(LkJs9LnU&maM~S}cl#~}l#QNCf_cS>WG3oNTp5rJmr3r5oTOP+ ziOCV`rlD>?kGcc7S< z5Vr)SW69|_TnO1#jMT3zbwH}^{G6nsUx_dP1;Hn%Jtk{2Nq zz~pL4Rt2iG6-;#2o~ILKCPsHAy*v(pN-bE0b}U~Nk9cQ@gvl*lh4xU0MBeXR(13yw|V#M;jY6d^m58Lb;TnrXa#nnv(ekFAn%-Zxq&h{5YD0_ zcL30!p{GK7tU+={K$ zrJ>`56qXGp9?iam#fu`5@)Z;3*)`J+Y<4~tN^XJAsDb$yO`TNE5MMVlbCoL)^e#)` z?1XZE>=p%5LTj`pYe7(-nH1x^d)fW?)5UJjgRnWL`y0>YZmBOX?^cLkK5S2ovgLA{ zkY(G1D|^}zO}BdYh3V+zX*J_|UNyQ7vT^P5^Tp4a`mD%4x;H)S*0 zXWZn%$T}+u9g%OnFz148!dLC*e=79nRoO528%6n}_^RJ*HvQF=*u|OzExOPbz*XOm zM^Ebe=2HR9`rba@m_AOkU0#}CHuFXISbi+em}IW#Z7B&vm|d@{Jh9j7>ng9lkfHDo zY{6%2#tWPB%H!e-D-^EES6Pi;VJQjvmn`-U2@=n&E6PI<8~Kd=R#u^BI{8<&eOY*>{Ks2QOngVWBPVZhPwXUME8%IV>s-CED~ zGu-dCXcpQuTT4U jtUp&AZ6Ra^QkDR6Vy_g)xf`UQhZu|yf(*I7s%`xZ7R=cY diff --git a/applications/PoP/poc/res/bg/pop_env5.atl b/applications/PoP/poc/res/bg/pop_env5.atl new file mode 100644 index 0000000000000000000000000000000000000000..c55cb875d720a9242ea8d7363baa9647d4aeb468 GIT binary patch literal 12800 zcmeHNyN=vO5TpP>k^u>a3r~p;Q0PdxAi;lN?vlF~h}^(m=FE}*#JS2QK#OGTkH4GSw~rn*&9BdHp7Z#}cQ?BJ=gO{M zUO#(E`QiHZF^_*<-@f5-ym_g4f5Amw|MvaWJ05?2b^V0LkpKS5=C?oC{9j(bkUmCs z+q`YYVYs`yJ8`sacj``e!?@dbeK*+{0TVlQ_&ZhcnX4IVK3K+Wsi%U|E@yNnoKCggTY#qlR;u=e0cA|1S8O`Eh<7 zM}7jY>!;`PZ!;l@o%_eUDx6VI0>)j2N=dkKC06B zWqvq?_(uJVFz@<OWl4{EELA0==*KZLjQBh>I}elq-l z_SZ15%T@Y=>Sq|X`m=Q}@3A#LdnZ=bW>oY$q8?l2r~bU*A2qN)19ttM9?Ng^cEZ8~ zwfwR-kSlax)u!S5$5h`93v^zeDwkTcKQ>Xv>D5ZJ`2hYIRQye@+27I}`pbAtn!eAY z({$53Z_@1IY`%vV(kZ*S=Rk4SPXL-o{x}c-`a=1fU;xF70wW-CR7N~m%;Hta&Ceu- zDp!IsDQ;p(TmVUo-I;Bxo9vlKO@m)yhl`C%YbHEofXj!|$O$=c;LM>XQUbVyNWf`M ziwe>JqvWbwZj>4zWDOkqCE%LIO<=4u#^VZ5#61dO$vBM+uf|Z^Ak-Os4PXlUV?WaI zJV4sO{53!u1Yo0FC}ThyAL$BJvOxfx0$?1NE@e5uMem0Zz_Bk^@PyfD83=y?NC^QT zg(^q}Ye^Q7-^h2~EI@ zY&}l0!BvF3$gcZa1FYiIR5Df2AoJ3ctIB~x4zR~C6q+upo!3w%AbPLe4vB(1Pxb9#T+?RM)42Mjzh zB6<70Pz7nUm%1Tn&xF^FYzm!Dx{KSF*|H07vz#1R>GwY?v(>{sCj1< z4S9$C>j-*b4smm0Z=-#*{L1#Dbb0^w2J7gKR-_KSz2NXAqX2fpTp7aQcBgTU%nVzG z`ZQop$RHtVUZU0zIZ$%kGq;yWo*O8Ya~a7Z1t28%!J{##@Xk^|AV|7_AeppJrxT)c z1eYNs;oUq2qc%v>B$(yXq^#H+tS*Mm85K0xkT}U_WF>c`A{SDX1KE(XLNR84Ql^De zVuqhqpQE;67z*1v10o4)x<@ zl}5oA5MP03d_sDK&Xd41`#C)03qGkDb$+1GzxF?YIQt+U6Lw|%8Go4hkvtqT+;8U} z!7t-aD#E`k{yBG?75FB9Gk#O^K|Us^F>kIvE2vn16;6CbeP#ah@hXO@?_B-SzeWC| z`WgN`>o29S8h?V3Una1qf0#`Z?M>Im$-&KeC2o;2pk(aDzMb={B!sYcbPLd@^=6KKwV` zm_+yZ1RFSxfMyu+JNiDo@(C`Ec!(EQd_S|4`1g!(kJ}>mYAw*tL VT-j+{q?)s3p#x=Q#e%Jne*si$KcoNv literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pop_env6.atl b/applications/PoP/poc/res/bg/pop_env6.atl new file mode 100644 index 0000000000000000000000000000000000000000..ead77d9ce0f92ebed558dfd439b74ac927cd8ec5 GIT binary patch literal 8005 zcmeI1!EW3(5QgQ(y(NGHG)UnT!CrIhJ%{$zqoK;!6<{Q<)yL>V^bz_HJ@nYSI{*LA zkVA>uHHtXs!34Y{=lf?kqDV@+{`KzXA8&@IFMkh*7gtxqaCdchh5DawZf{WkcKzWR z^Yu(nd_?`nOVz)8cX*Hf%kK|wQ2%~=c#S&rm+C)%c=r~1l*901xIbUU^Z0(e zyHF0pt6}MviDew89u}OYaU37ET=ao>TKgkqcUStwe>C&5luNSMXphc8RRUOUDCCtQ zr`mg%;E%qg!$08Yn`s~%BKK;PPor#y z$83d1gc0Ho1O5KL}gmS$=Q zBJC217rQWy7^VleN@Ii`wGjZ%ry*TEeY$#*P8`Jq$kA(i&%P`lhU?+eXKgklbGAr$ zRw4-DBV^O`>GPvx({va<4)bYKjz^hzsk3*o$_3)5U4ipmL5aT;!MV}CAo!l3@Et+r zeS!Gth|JL_|7R| z4r>kpyzzkumaX!0Pcmsj&~SNTcoQjta|EC_BN+>UUw;#s%mvO%WSChz!iopAT7uvh zy;mN`8EflqX8Ffyw3ZwT-;3bmbFSCk=tq8gg5a3#bN;*?9YOKm5hUInBJ-Z0a-_FS zvU1+AwLlMvv}hVZJVN5$wnLEeg&}wzB79L7?t;@P)6BK1TH0{CNT+-yP`k!2vD+u=-1`-9gLex>&OZ9bl#!8{}CJn$*<{0!zZHlF?e^%?xW{-(kemp-&a zlVR2LJ+!jc?x}M|h%&OR?5b^B&UX{o=Rs`O#U5@#=l$M2;}9VBV3S{p9Gs>IpCgBW z?2%^_(ha|;<*&$g3S8jZb0qxfS@%zbSN?d$G4fVW{Bnc%g8-2&J{` xNT(l=Ruevb4g)n`RS^tY`-C)kF+BP?6f`JEf;D^X$63@$bFUdXgH=`){R;w2(I5Z- literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pop_env7.atl b/applications/PoP/poc/res/bg/pop_env7.atl new file mode 100644 index 0000000000000000000000000000000000000000..c8ac6659168afc040191175c7cc7b9de944a1d00 GIT binary patch literal 5040 zcmeHL%}yIJ5H=-Q0RpMY1rS79q#k;$#4(q?L9?5L`2Ov)d;Rs-U0oaB~vh}Z|ebZ7bO zRB;$xY%K~7lZ$ZDD}&SUB%kJnwmPc9RitorXUC3r5uV)RA-COdVkAr*Y1(~y>Z zIeTlk$L=Z-^>}?Qudx49`evGUNne-4Z_~W4_K(vcaQPkP`rblgso*6@--M^`zVrKB z@>=y3B4+Nl^Z9C3(4c4$yDjMDl458z^Ig+4d2q-`_^xD;k}?w4#MmTD>QM}Gg58VFmdeIZRuk)qP2_Tk{!%@zoAOdtVpBb?Ye`~(1+8Q=a_c!V^qG^G4_K}TYa+pM ze}s!wlIN=RkV8pyg4u~;wo0Otk3L^?pJuMO8Z%q^4ZNfK{OI%0?o(dT`5s?kIU1i< zHT{1iz5olmkX7IU1a`6L8@7jMwrQeMC%?dr_q{xU8Yvzo9)OAL@baj8NEG4` Xnl!;FCSu+KIGaVhc`A>?>|*f`O1v~} literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pop_env8.atl b/applications/PoP/poc/res/bg/pop_env8.atl new file mode 100644 index 0000000000000000000000000000000000000000..6e34d750c244c8aaf1b138600f2585cbb318be79 GIT binary patch literal 7444 zcmeHLOKuZE5bY>fNKvebu%kqdWs4(3;sV?N86Qz-&*C?O&@7_M%q(A@sNcUG47b!hmEa$M!U#uTs{rGadfc5j$3fC{w zMF;llZgL6hn{JBs&#uGu>83;d&8uz({NwC;0_&&QatiDB`T8E#Z+GiESide-x3I!< zpRQ8hdbTYvV}tmvE!ghbgvSSCwnO&YcF2ski2`4y`Eh54GKOmW54ccTFp9E^z6IAN z#~vkzT^{A=9ts`zkWji4D?w1~C*EVt>Fv6}q8sKQB0Wx4&B_>;)$8A!7g|p`$_7$GYpzk23Uj`iQL%oJy7Xb_*$fbyO`FNMXLOHv-{)uq zZEz1(exR1TWe77W?m<+uKWVf&=O35?*Ju^aOan)ziDza2?|UGilKL6K`+kxx@n<*; z_b$J7yX`bz4usHoKf9sx11XvYg2H%%_cT-9kgr9jt!o{lIMs-Wr?(bFlPXh|NXg8k zn$SKyC6NQBlJ0mQMN_^jSut$KfB$MJh{mfMIV5@?qvZ-Ii=8Ul5XG_4M8a6is3w!4 zUwTOL8ZbG8u+cPBBIgRbG^=O(oDC{k&m}>>Vn+%S{mi-1AZsp@d@2&jVcAPej@UL0 zbq%^s6Z@SWGePb73414yDCo1>Ez?x>UV<^)>ol&d=2o~Ywv{#+;&v2{n}xU~sD(AB z?QkJPH_TZ9P9|Twl4D$UTIYZJv9HyoV!!#Pw06N)qNSv(jj>jLIF&!mSk0+ zNn6207svB-rp(0X&ZLjW0Z^$0YtWA6QSpcuLnKUY@fx&;LL^f2yQ~|_gt+$g+m4-G zT69EMUVFWxnq=#A_dM&+3LQ>qr>=N~6|KNQbkTa73R0J}%MFyd1K}*Xat8nnKJ+wb z?<=&+?r9!G2f1xdP|3$>a+lIrt)@Q}fP1}N(HdlxZVww~*CQ3%<|MXNmxhiVQdl;a zcrg1O76(Nll`AGLvumaU*y4UHluUuosDb$!%{zNJL$t1ECY2Eg{w_-;c8)SXHbsGy P&>C%&wIJwUm=xm|6@ZOw literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pop_env9.atl b/applications/PoP/poc/res/bg/pop_env9.atl new file mode 100644 index 0000000000000000000000000000000000000000..3b57c9b6fb5c841328922a94fe38f37c00d8ae54 GIT binary patch literal 4175 zcmeHKOHKko5N*N&Ld>v&^=w(NaNz;G0Wd?DNeG_7rAOfodJqrdIk2n0Ro&G!EF^@) zj#}04z52G2*lb>(r|S0SQ?1scky1aCdII))TF=3L&FTv5`;)aVRXv9LxmwP^e#{rf zLWe80R;Rbkb?09w?&*H(*D4-Hk-O2ONB)l6$&ye+{-5pBkT5$CB*N= z__dm-%jI-}uaeb_=HW-dLMQ~6ERe#t80!MH5qdD9;taK#>lx$eyTjqo^?gJVPYWbE zQ8U-R>&n@+{@%Q9KTs>mA?y0M=S1dA8PwrzxvXW3(WWcd&a z6;PCQ37hc=oA931b^Ss4J?klB1JAM{Kf~H0CO&7)>`*}SjzvwO4m^t>;tqVS?!-5A znZk_J33Vv!Zk8>*VTc7MizjTxCv3ud7Oe~A_bjo2CuqEoi6X2$^o9gC7yO2fMNJ|7 z1^Jvi{DxySq~Y=+Y$yJAqRFM2aewPNMcAHqOj>`TyCbMCe?+Lqa9)IkY6Np=f*I6d pc<=nS7p3`7bJm5F323Vj&=tl?525e~1rS3Hq>up}gyv$$`UQzn_lW=i literal 0 HcmV?d00001 diff --git a/applications/PoP/poc/res/bg/pop_tile.pal b/applications/PoP/poc/res/bg/pop_tile.pal new file mode 100644 index 0000000000000000000000000000000000000000..e62c5734387a36849126ad4260bb9ae47cbd292b GIT binary patch literal 128 zcmZQzU|_IO;9>AFkYR{)F<>Z+bzzv=TFG$k*gl5;|Nk?rTD6KHG&Gc23) # не рисуются (отрисовка пропускает незагруженную страницу). Палитра — @@ -93,7 +100,7 @@ hdd: $(EXAMPLE).exe TC := $(PROJ_ROOT)/applications/PoP/toolchain $(BG_DATA): $(TC)/pop_pack_bg.py $(TC)/render_room.py - cd $(TC) && python3 pop_pack_bg.py + cd $(TC) && python3 pop_pack_bg.py dungeon && python3 pop_pack_bg.py palace $(GUARD_DATA): $(TC)/pop_pack_guard.py cd $(TC) && python3 pop_pack_guard.py diff --git a/applications/PoP/roomtest/pop_bg.h b/applications/PoP/roomtest/pop_bg.h index e7b4d40..c193ea0 100644 --- a/applications/PoP/roomtest/pop_bg.h +++ b/applications/PoP/roomtest/pop_bg.h @@ -34,7 +34,7 @@ /* Загрузить 7 атласов фона. Звать ДО initgraph (как poc.c — atlas_load * трогает W3; проверенный порядок). Палитру pop_bg.pal грузит ПРИЛОЖЕНИЕ * после initgraph (gfx_pal_fload). 0 — OK, -1 — ошибка. */ -int pop_bg_load(void) __banked; +int pop_bg_load(uint8_t set) __banked; /* 0 подземелье, 1 дворец */ /* Освободить EMM-страницы атласов. */ void pop_bg_free(void) __banked; diff --git a/applications/PoP/roomtest/pop_level.c b/applications/PoP/roomtest/pop_level.c index 23fdca6..39788bc 100644 --- a/applications/PoP/roomtest/pop_level.c +++ b/applications/PoP/roomtest/pop_level.c @@ -450,6 +450,19 @@ uint8_t pop_level_guard(uint8_t room, uint8_t *tile, int8_t *dir, return (uint8_t)(t < 30); } +/* tbl_level_type (SDLPoP data.h:840). Держим ЗДЕСЬ, а не в слое фона: + * тип уровня нужен не только атласам — по нему расходятся ветки отрисовки + * (seg008), кладка стены (wall_pattern) и модификатор пустой клетки от + * упавшей плиты (remove_loose, seg007:0EB8). */ +static const uint8_t LEVEL_TYPE[16] = { + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0 +}; + +uint8_t pop_level_type(void) +{ + return LEVEL_TYPE[pop_current_level & 15]; +} + uint8_t pop_level_start_room(void) { return start_byte(BP_START + 0); } uint8_t pop_level_start_pos(void) { return start_byte(BP_START + 1); } int8_t pop_level_start_dir(void) { return (int8_t)start_byte(BP_START + 2); } diff --git a/applications/PoP/roomtest/pop_level.h b/applications/PoP/roomtest/pop_level.h index be1c112..3656adf 100644 --- a/applications/PoP/roomtest/pop_level.h +++ b/applications/PoP/roomtest/pop_level.h @@ -135,6 +135,13 @@ uint8_t pop_guard_state_x(uint8_t room); uint8_t pop_level_guard(uint8_t room, uint8_t *tile, int8_t *dir, uint8_t *color, uint8_t *skill); +/* tbl_level_type (SDLPoP data.h:840) — какой тайлсет у уровня: + * 0 подземелье, 1 дворец. Дворцовые: 4, 5, 6, 10, 11, 14. Индекс — + * НОМЕР уровня; элемент 0 — демо-уровень. Оригинал по нему выбирает и + * .DAT окружения (tbl_envir_ki, seg000:1108), и десяток веток отрисовки + * в seg008, и графику стража (GUARD1/GUARD2). */ +uint8_t pop_level_type(void); + uint8_t pop_level_start_room(void); uint8_t pop_level_start_pos(void); int8_t pop_level_start_dir(void); diff --git a/applications/PoP/roomtest/pop_room.c b/applications/PoP/roomtest/pop_room.c index 59de686..f6cbc5b 100644 --- a/applications/PoP/roomtest/pop_room.c +++ b/applications/PoP/roomtest/pop_room.c @@ -8,6 +8,9 @@ * * Только DUNGEON-стиль (Фаза 1). */ +/* Имена файлов атласов обоих тайлсетов нужны только здесь; макрос обязан + * стоять ДО первого включения pop_bg_atlas.h (его тянет pop_tile.h). */ +#define POP_BG_ATLAS_NAMES #include #include #include @@ -22,34 +25,87 @@ #include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */ #include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев */ #include "pop_cdraw.h" /* pop_cd — габарит кадра Кида (y-порядок плиты) */ +#include +#include -static const char *const ENV_ATL[5] = { - /* Ресурсы разложены по каталогам образа (8.3, как в DSS): BG — фон, - * KID — персонаж, GUARD — стражи, LEVELS — уровни. Иначе корень диска - * зарастает десятками .atl. */ - "BG\\pop_env0.atl", "BG\\pop_env1.atl", "BG\\pop_env2.atl", - "BG\\pop_env3.atl", "BG\\pop_env4.atl" -}; +/* ---- Тайлсет: подземелье / дворец ----------------------------------- * + * Порт tbl_envir_ki[tbl_level_type[level]] (seg000:1108): оригинал под один + * и тот же набор id грузит РАЗНЫЙ .DAT — VDUNGEON или VPALACE. У нас так + * же: раскладка id -> (страница, idx) общая (упаковщик печёт оба набора по + * одному объединению id), меняются только файлы атласов и 32 записи + * палитры — env 0x50..0x5F и wall 0x60..0x6F. Кид, страж, меч и зелья + * живут в других слотах, поэтому общая kid.pal не трогается. */ +static uint8_t bg_set = 0xFF; /* какой набор сейчас загружен */ -int pop_bg_load(void) __banked +/* Ресурсы разложены по каталогам образа (8.3, как в DSS): BG — фон, KID — + * персонаж, GUARD — стражи, LEVELS — уровни. Иначе корень диска зарастает + * десятками .atl. Путь склеиваем на месте: держать по строке на каждый из + * двадцати атласов — лишние полкилобайта в банке. */ +static char bg_path_buf[20]; + +static const char *bg_path(const char *name) +{ + char *d = bg_path_buf; + *d++ = 'B'; *d++ = 'G'; *d++ = '\\'; + while (*name) *d++ = *name++; + *d = 0; + return bg_path_buf; +} + +/* 32 записи (env, затем wall) в ОБЕ палитры: у страниц дабл-буфера они + * раздельные. Буфер — на стеке: gfx_pal_load отдаёт указатель BIOS ($A4), + * а тот читает только #4000-#BFFF, то есть банковую rodata бы не увидел + * (те же грабли, что в pop_guard_set_palette). */ +static int bg_load_tile_pal(const char *name) +{ + uint8_t buf[64]; + int fd = open(bg_path(name), O_RDONLY); + if (fd < 0) return -1; + if (read(fd, buf, 64) != 64) { close(fd); return -1; } + gfx_pal_load(0, POP_PAL_ENV, 16, buf); + gfx_pal_load(1, POP_PAL_ENV, 16, buf); + if (read(fd, buf, 64) != 64) { close(fd); return -1; } + gfx_pal_load(0, POP_PAL_WALL, 16, buf); + gfx_pal_load(1, POP_PAL_WALL, 16, buf); + close(fd); + return 0; +} + +/* Загрузить набор set (0 подземелье, 1 дворец). Повторный вызов с тем же + * набором ничего не делает; со сменой — сначала выгружает старый, иначе + * EMM-страницы утекут (их по 12 на набор). */ +int pop_bg_load(uint8_t set) __banked { int i; - for (i = 0; i < 5; i++) - if (atlas_load(&pop_env[i], ENV_ATL[i]) != 0) return -1; - if (atlas_load(&pop_wall_at, "BG\\pop_wall.atl") != 0) return -1; - if (atlas_load(&pop_fore_at, "BG\\pop_fore.atl") != 0) return -1; - if (atlas_load(&pop_pot_at, "BG\\pop_pot.atl") != 0) return -1; - return 0; + if (set >= POP_TILESETS) return -1; + if (set == bg_set) return 0; + if (bg_set != 0xFF) { /* смена набора — освободить старый */ + for (i = 0; i < POP_ENV_PAGES; i++) atlas_free(&pop_env[i]); + atlas_free(&pop_wall_at); + atlas_free(&pop_fore_at); + } + for (i = 0; i < POP_ENV_PAGES; i++) + if (atlas_load(&pop_env[i], bg_path(pop_env_atl[set][i])) != 0) return -1; + if (atlas_load(&pop_wall_at, bg_path(pop_wall_atl[set])) != 0) return -1; + if (atlas_load(&pop_fore_at, bg_path(pop_fore_atl[set])) != 0) return -1; + if (bg_set == 0xFF && /* chtab_1 от набора не зависит */ + atlas_load(&pop_pot_at, bg_path(POP_POT_ATL)) != 0) return -1; + bg_set = set; + /* Палитра — ПОСЛЕ атласов: если атлас не загрузился, цвета остаются от + * прежнего набора и картинка хотя бы не разъезжается. */ + return bg_load_tile_pal(pop_tile_pal[set]); } void pop_bg_free(void) __banked { int i; - for (i = 0; i < 5; i++) + if (bg_set == 0xFF) return; + for (i = 0; i < POP_ENV_PAGES; i++) atlas_free(&pop_env[i]); atlas_free(&pop_wall_at); atlas_free(&pop_fore_at); atlas_free(&pop_pot_at); + bg_set = 0xFF; } static const uint8_t SPIKES_FRAM_RIGHT[10] = {0, 134, 135, 136, 137, 138, 137, 135, 134, 0}; diff --git a/applications/PoP/roomtest/pop_tile.c b/applications/PoP/roomtest/pop_tile.c index e040dbb..f4103e2 100644 --- a/applications/PoP/roomtest/pop_tile.c +++ b/applications/PoP/roomtest/pop_tile.c @@ -17,7 +17,7 @@ #include "_pop_draw.h" /* pop_heal_fast */ /* ---- Состояние (писучее, _DATA/W2 — видно из любого банка) ---------- */ -atlas_t pop_env[5], pop_wall_at, pop_fore_at, pop_pot_at; +atlas_t pop_env[POP_ENV_PAGES], pop_wall_at, pop_fore_at, pop_pot_at; const uint8_t *pop_t_fg, *pop_t_bg, *pop_t_lfg, *pop_t_lbg; const uint8_t *pop_t_below, *pop_t_above, *pop_t_abovemod; @@ -262,7 +262,7 @@ void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom) gfx_w0_unmap(); } -void pop_env_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_env[id >> 5], (uint8_t)(id & 31), x, yb); } +void pop_env_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_env[id >> POP_ENV_SHIFT], (uint8_t)(id & POP_ENV_MASK), x, yb); } void pop_wall_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_wall_at, id, x, yb); } void pop_fore_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_fore_at, id, x, yb); } void pop_pot_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_pot_at, id, x, yb); } diff --git a/applications/PoP/roomtest/pop_tile.h b/applications/PoP/roomtest/pop_tile.h index ca2304b..9af1d67 100644 --- a/applications/PoP/roomtest/pop_tile.h +++ b/applications/PoP/roomtest/pop_tile.h @@ -31,9 +31,13 @@ #include "pop_geom.h" /* pop_rnd_t — сид кладки комнаты */ /* ---- Атласы фона (прямая адресация id) ------------------------------ * - * env[id>>5] idx id&31 — chtab_6 environment; wall — chtab_7; fore — - * передний слой; pot — chtab_1 (зелья, меч-предмет). */ -extern atlas_t pop_env[5], pop_wall_at, pop_fore_at, pop_pot_at; + * env[id>>POP_ENV_SHIFT] idx id&POP_ENV_MASK — chtab_6 environment; + * wall — chtab_7; fore — передний слой; pot — chtab_1 (зелья, меч). + * Раскладка и число страниц — из pop_bg_atlas.h (генерит упаковщик). + * Тайлсетов ДВА (подземелье/дворец), но раскладка id у них общая: + * подменяются только файлы и 32 записи палитры (см. pop_bg_set_tileset). */ +#include "pop_bg_atlas.h" +extern atlas_t pop_env[POP_ENV_PAGES], pop_wall_at, pop_fore_at, pop_pot_at; /* ---- Текущая отрисованная комната ----------------------------------- * * fg — foretable-коды, bg — модификаторы; lfg/lbg — правый столбец ЛЕВОГО diff --git a/applications/PoP/roomtest/roomtest.c b/applications/PoP/roomtest/roomtest.c index 375e3b3..476ad6f 100644 --- a/applications/PoP/roomtest/roomtest.c +++ b/applications/PoP/roomtest/roomtest.c @@ -479,7 +479,11 @@ int main(void) uint8_t cheat_prev = 0, immo_prev = 0, sword_prev = 0, nlvl_prev = 0; uint8_t xdec_prev = 0, xinc_prev = 0; - if (pop_bg_load() != 0) { /* атласы — ДО initgraph (снимает DSS-страницу W0) */ + /* Набор фона — по типу СТАРТОВОГО уровня. Атласы грузятся ДО initgraph + * (тот снимает DSS-страницу W0); уровень к этому моменту ещё не прочитан, + * поэтому тип берём напрямую от номера. */ + pop_current_level = FIRST_LEVEL; + if (pop_bg_load(pop_level_type()) != 0) { puts("pop_bg_load failed"); return 1; } @@ -757,6 +761,14 @@ int main(void) * пределы, и персонаж просто не виден. */ pop_guard_free(); pop_guard_load(); + /* Тайлсет: подземелье <-> дворец (порт tbl_envir_ki, + * seg000:1108). Внутри — no-op, если тип не менялся; + * при смене выгружает старые атласы и правит 32 записи + * палитры. Только на границе уровня, не в кадре. */ + if (pop_bg_load(pop_level_type()) != 0) { + puts("bg set load failed"); + return 1; + } /* Всё состояние прошлого уровня сносит сам pop_start_level: * pop_trob_reset обнуляет room_seen (модификаторы комнат * перечитаются из НОВОЙ страницы), тайлы/стражи приезжают diff --git a/applications/PoP/toolchain/pop_pack_bg.py b/applications/PoP/toolchain/pop_pack_bg.py index e5cff0e..a37b138 100644 --- a/applications/PoP/toolchain/pop_pack_bg.py +++ b/applications/PoP/toolchain/pop_pack_bg.py @@ -129,7 +129,37 @@ CHOMPER_BLOOD_COLOR = VGA16_PAL_BASE + 12 # тот же mono-цвет 12 (seg0 # рисуется chtab_6 id 146). В статический render_room не попадает. TORCH_ENV_IDS = {146} -ENV_SHIFT = 5 # env фон: страница = id>>5, idx = id&31 +# ---- Два тайлсета: подземелье и дворец -------------------------------- +# Оригинал грузит РАЗНЫЙ .DAT под один и тот же набор id: +# tbl_envir_ki[tbl_level_type[level]] -> VDUNGEON / VPALACE (seg000:1108), +# то есть id спрайта от набора НЕ зависит — меняется только картинка и +# палитра (env 0x50..0x5F, wall 0x60..0x6F). Поэтому оба набора пакуются +# по ОДНОМУ И ТОМУ ЖЕ объединению id: раскладка id -> (страница, idx) +# остаётся одна, и коду достаточно подменить ИМЕНА файлов. +# +# Порядок каталогов — каскад: сначала «свой» набор, потом чужой как +# фолбэк (в распакованном data/ несколько id есть только в одном из них: +# res230/231/348 только в VDUNGEON, два десятка — только в VPALACE). +SETS = { + "dungeon": ("pop_", lambda: (R.VDUNGEON_DIR, R.VPALACE_DIR)), + "palace": ("pal_", lambda: (R.VPALACE_DIR, R.VDUNGEON_DIR)), +} +SRC_DIRS = None # ставит main() по выбранному набору + +# Спрайты, которые рисуются ТОЛЬКО на паласных уровнях (seg008): +# 78, 80, 82 doortop_fram_bot (низ верха двери, draw_tile_right) +# 81, 83 doortop_fram_top (draw_tile_topright) +# 84 полоска на стене (draw_tile_right, tiles_20_wall) +# 145 stripe_id соседнего тайла (draw_tile_right) +# render_room про них не знает (он рисует по подземельной ветке), поэтому +# добавляем явно — иначе при переключении набора в этих местах будет дыра. +PALACE_ENV_IDS = {78, 80, 81, 82, 83, 84, 145} + +ENV_SHIFT = 4 # env фон: страница = id>>SHIFT, idx = id&MASK. + # Было 5: паласный набор добавляет куски верха + # двери (78..84), и страница 2 переваливала за + # 16 КБ. При 4 обе раскладки укладываются, цена + # — 10 страниц EMM на набор вместо 5. ENV_MASK = (1 << ENV_SHIFT) - 1 # ---- .atl формат (== libbgi, но каталог не ограничен 19) -------------- @@ -194,7 +224,8 @@ NO_TRANSP_ENV_IDS = {36, 43, 73, 74, 96, 149} | LEVELDOOR_ENV_IDS def load_indexed(chtab, id, opaque=False, mono=None): - """PNG (mode P, 16 цветов) -> (w, h, bytes 8bpp). Каскад VDUNGEON->VPALACE. + """PNG (mode P, 16 цветов) -> (w, h, bytes 8bpp). Каскад по SRC_DIRS + (порядок задаёт выбранный тайлсет, см. SETS). Пиксель 0 -> 0xFF (прозрач); i -> base+i (env 0x50 / wall 0x60). opaque=True — пиксель 0 остаётся ЦВЕТОМ (base+0 = чёрный), а не ключом @@ -203,7 +234,7 @@ def load_indexed(chtab, id, opaque=False, mono=None): pal_base = 0x60 if chtab == R.CHTAB_WALL else 0x50 fname = f"res{base_res + id}.png" path = None - for d in (R.VDUNGEON_DIR, R.VPALACE_DIR): + for d in SRC_DIRS: p = os.path.join(d, fname) if os.path.exists(p): path = p @@ -306,11 +337,29 @@ def scale6to8(v): return (v * 255) // 63 +def read_pal16(res, d): + b = open(os.path.join(d, res), "rb").read() + return [(b[4 + i * 3], b[4 + i * 3 + 1], b[4 + i * 3 + 2]) for i in range(16)] + + +def build_tileset_palette(out_path): + """Палитра ТОЛЬКО тайлсета: 32 записи B,G,R,0 — env (16) затем wall (16). + Ею подменяются слоты 0x50..0x6F при смене типа уровня; полная игровая + палитра (kid.pal) при этом не трогается, потому что Кид, страж, меч и + зелья живут в других слотах (levels_plan §3). Порядок каталогов — + SRC_DIRS, то есть файл соответствует выбранному набору.""" + pal = bytearray(32 * 4) + src = read_pal16("res200.pal", SRC_DIRS[0]) + read_pal16("res360.pal", SRC_DIRS[0]) + for i, (r, g, b) in enumerate(src): + pal[i * 4:i * 4 + 4] = bytes((scale6to8(b), scale6to8(g), scale6to8(r), 0)) + with open(out_path, "wb") as f: + f.write(pal) + + def build_palette(out_path): """256-записная палитра B,G,R,0: env@0x50..0x5F, wall@0x60..0x6F.""" def read_pal(res, d): - b = open(os.path.join(d, res), "rb").read() - return [(b[4 + i * 3], b[4 + i * 3 + 1], b[4 + i * 3 + 2]) for i in range(16)] + return read_pal16(res, d) env = read_pal("res200.pal", R.VDUNGEON_DIR) wall = read_pal("res360.pal", R.VDUNGEON_DIR) @@ -334,7 +383,10 @@ def build_palette(out_path): # ---- 5. C-заголовок -------------------------------------------------- -def write_header(out_path, env_pages, wall_name, fore_name): +def write_header(out_path, env_pages): + """Заголовок ОДИН на оба тайлсета: раскладка id -> (страница, idx) у них + общая (пакуются по одному объединению id), различаются только имена + файлов и палитра. Поэтому здесь два массива имён и один индекс.""" lines = [ "/* pop_bg_atlas.h — раскладка атласов статического фона PoP.", " * Сгенерировано toolchain/pop_pack_bg.py — НЕ править вручную.", @@ -343,6 +395,11 @@ def write_header(out_path, env_pages, wall_name, fore_name): " * ENV фон id N -> atlas env_bg[N>>%d], idx N&%d" % (ENV_SHIFT, ENV_MASK), " * WALL id N -> atlas wall, idx N", " * FORE id N -> atlas fore, idx N", + " *", + " * ДВА ТАЙЛСЕТА (порт tbl_envir_ki[tbl_level_type], seg000:1108):", + " * 0 = подземелье (pop_*), 1 = дворец (pal_*). Набор id и раскладка", + " * у них ОДНИ И ТЕ ЖЕ — меняются только файлы и 32 записи палитры", + " * (env 0x50..0x5F, wall 0x60..0x6F), см. *tile.pal.", " */", "#ifndef POP_BG_ATLAS_H", "#define POP_BG_ATLAS_H", @@ -350,22 +407,32 @@ def write_header(out_path, env_pages, wall_name, fore_name): "#define POP_ENV_SHIFT %d" % ENV_SHIFT, "#define POP_ENV_MASK %d" % ENV_MASK, "#define POP_ENV_PAGES %d" % len(env_pages), + "#define POP_TILESETS 2", "", - "/* Палитра: env-слоты, wall-слоты (сприйт-пиксель i -> база+i). */", + "/* Палитра: env-слоты, wall-слоты (спрайт-пиксель i -> база+i). */", "#define POP_PAL_ENV 0x50", "#define POP_PAL_WALL 0x60", "", - "/* Имена файлов атласов (грузятся atlas_load). */", - "static const char *const pop_env_atl[POP_ENV_PAGES] = {", + "/* Имена файлов атласов по тайлсету (грузятся atlas_load). Таблицы", + " * видны только тому, кто попросил POP_BG_ATLAS_NAMES: иначе копия", + " * строк уедет в каждый включивший заголовок модуль. */", + "#ifdef POP_BG_ATLAS_NAMES", + "static const char *const pop_env_atl[POP_TILESETS][POP_ENV_PAGES] = {", ] - for pg in range(len(env_pages)): - nm = env_pages[pg] - lines.append(' %s,' % ('"%s"' % nm if nm else "0 /* пусто */")) + for prefix, _ in SETS.values(): + row = ", ".join(('"%s%s"' % (prefix, nm.split("_", 1)[1]) if nm else "0") + for nm in env_pages) + lines.append(" { %s }," % row) lines += [ "};", - '#define POP_WALL_ATL "%s"' % wall_name, - '#define POP_FORE_ATL "%s"' % fore_name, - '#define POP_POT_ATL "pop_pot.atl" /* chtab_1: зелья */', + 'static const char *const pop_wall_atl[POP_TILESETS] = { %s };' + % ", ".join('"%swall.atl"' % p for p, _ in SETS.values()), + 'static const char *const pop_fore_atl[POP_TILESETS] = { %s };' + % ", ".join('"%sfore.atl"' % p for p, _ in SETS.values()), + 'static const char *const pop_tile_pal[POP_TILESETS] = { %s };' + % ", ".join('"%stile.pal"' % p for p, _ in SETS.values()), + "#endif /* POP_BG_ATLAS_NAMES */", + '#define POP_POT_ATL "pop_pot.atl" /* chtab_1: зелья, от набора не зависит */', "#define POP_PAL_POT 0x%02X" % POT_PAL_BASE, '#define POP_BG_PAL "pop_bg.pal"', "", @@ -377,6 +444,14 @@ def write_header(out_path, env_pages, wall_name, fore_name): def main(): + global SRC_DIRS + set_name = sys.argv[1] if len(sys.argv) > 1 else "dungeon" + if set_name not in SETS: + die(f"набор '{set_name}': ожидался один из {', '.join(SETS)}") + prefix, dirs = SETS[set_name] + SRC_DIRS = dirs() + print(f"набор: {set_name} (источник {os.path.basename(SRC_DIRS[0])}, " + f"фолбэк {os.path.basename(SRC_DIRS[1])}), префикс {prefix}") os.makedirs(OUT_DIR, exist_ok=True) used = collect_used() env_ids = sorted(set(id for ch, id in used if ch != R.CHTAB_WALL) @@ -392,7 +467,8 @@ def main(): | CHOMPER_BLOOD_IDS # кровь (mono) | CHOMPER_BLOOD_FORE_IDS | OPENER_NOFLOOR_ENV_IDS # + opener без пола слева - | LEVELDOOR_ENV_IDS) # + дверь уровня (створка/лестница) + | LEVELDOOR_ENV_IDS # + дверь уровня (створка/лестница) + | PALACE_ENV_IDS) # + куски, что рисует только палас wall_ids = sorted(id for ch, id in used if ch == R.CHTAB_WALL) env_bg = [i for i in env_ids if i not in FORE_ENV_IDS] @@ -410,7 +486,7 @@ def main(): total_bytes = 0 for pg in range(max_pg + 1): if pg in pages: - nm = f"pop_env{pg}.atl" + nm = f"{prefix}env{pg}.atl" cnt, sz = pack_atlas(os.path.join(OUT_DIR, nm), pages[pg]) total_bytes += sz env_page_names.append(nm) @@ -421,18 +497,18 @@ def main(): # WALL -> idx=id wall_entries = {id: load_indexed(R.CHTAB_WALL, id) for id in wall_ids} - cnt, sz = pack_atlas(os.path.join(OUT_DIR, "pop_wall.atl"), wall_entries) + cnt, sz = pack_atlas(os.path.join(OUT_DIR, prefix + "wall.atl"), wall_entries) total_bytes += sz - print(f" pop_wall.atl: {len(wall_ids)} спрайтов, каталог {cnt}, {sz} Б") + print(f" {prefix}wall.atl: {len(wall_ids)} спрайтов, каталог {cnt}, {sz} Б") # FORE -> idx=id fore_entries = {id: load_indexed(R.CHTAB_ENV, id, False, CHOMPER_BLOOD_COLOR if id in CHOMPER_BLOOD_FORE_IDS else None) for id in env_fore} - cnt, sz = pack_atlas(os.path.join(OUT_DIR, "pop_fore.atl"), fore_entries) + cnt, sz = pack_atlas(os.path.join(OUT_DIR, prefix + "fore.atl"), fore_entries) total_bytes += sz - print(f" pop_fore.atl: {len(env_fore)} спрайтов, каталог {cnt}, {sz} Б") + print(f" {prefix}fore.atl: {len(env_fore)} спрайтов, каталог {cnt}, {sz} Б") # POTION (chtab_1) -> idx=id: склянки + кадры пузырька + маска # chtab_1 целиком (res151..res173 = id 1..23): пламя факелов, меч-предмет, @@ -452,13 +528,15 @@ def main(): pot_entries[id] = load_potion(id, opaque=True) else: pot_entries[id] = load_potion(id) + # chtab_1 (пламя/меч/зелья) от тайлсета НЕ зависит — пакуем один раз. cnt, sz = pack_atlas(os.path.join(OUT_DIR, "pop_pot.atl"), pot_entries) total_bytes += sz print(f" pop_pot.atl (chtab_1: факелы+зелья): {len(pot_entries)} спрайтов, каталог {cnt}, {sz} Б") + build_tileset_palette(os.path.join(OUT_DIR, prefix + "tile.pal")) + print(f" {prefix}tile.pal: 32 записи (env 0x50..0x5F + wall 0x60..0x6F)") build_palette(os.path.join(OUT_DIR, "pop_bg.pal")) - write_header(os.path.join(OUT_DIR, "pop_bg_atlas.h"), - env_page_names, "pop_wall.atl", "pop_fore.atl") + write_header(os.path.join(OUT_DIR, "pop_bg_atlas.h"), env_page_names) n_pages = sum(1 for n in env_page_names if n) + 2 print(f"ИТОГО: {len(env_bg)} env-фон + {len(wall_ids)} wall + "