From c0ab9155a38bd9a312bc34088e9e545f9066148f Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Sat, 22 Aug 2026 10:32:59 -0600 Subject: [PATCH] Add wall art decals to Wolfenstein levels - Add new `wallArt` level data array with per-cell decal frames - Integrate wall art rendering into WolfensteinView using same texture sampling as walls - Add Wall Art tool to WolfensteinEditor with dynamic dropdown from JSON registry - Create wolfenstein-wallart.json frame registry for easy decal management - Add validation ensuring wall art sits on actual wall cells - Support wall art in save/load system with backward compatibility - Alert idle enemies when shot, even outside vision cone --- assets/gamedata/wolfenstein/level-e1m1.json | 34 ++++++++- assets/images/wolfenstein/wall-art.png | Bin 0 -> 10818 bytes assets/images/wolfenstein/wall-art.psd | Bin 0 -> 47205 bytes data/wolfenstein-artwork.json | 3 +- data/wolfenstein-wallart.json | 7 ++ src/games/wolfenstein/WolfensteinEditor.js | 73 +++++++++++++++++++- src/games/wolfenstein/WolfensteinLogic.js | 35 ++++++++-- src/games/wolfenstein/WolfensteinView.js | 46 +++++++++--- src/games/wolfenstein/sprites.md | 46 ++++++++++++ 9 files changed, 224 insertions(+), 20 deletions(-) create mode 100644 assets/images/wolfenstein/wall-art.png create mode 100644 assets/images/wolfenstein/wall-art.psd create mode 100644 data/wolfenstein-wallart.json diff --git a/assets/gamedata/wolfenstein/level-e1m1.json b/assets/gamedata/wolfenstein/level-e1m1.json index 204b801..c610450 100644 --- a/assets/gamedata/wolfenstein/level-e1m1.json +++ b/assets/gamedata/wolfenstein/level-e1m1.json @@ -512,5 +512,37 @@ "y": 18.5, "radius": 0.6 }, - "briefing": [] + "briefing": [], + "wallArt": [ + { + "x": 11, + "y": 2, + "frame": 0 + }, + { + "x": 11, + "y": 4, + "frame": 0 + }, + { + "x": 11, + "y": 6, + "frame": 0 + }, + { + "x": 11, + "y": 8, + "frame": 0 + }, + { + "x": 7, + "y": 14, + "frame": 1 + }, + { + "x": 1, + "y": 15, + "frame": 1 + } + ] } diff --git a/assets/images/wolfenstein/wall-art.png b/assets/images/wolfenstein/wall-art.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e56c7fb3eed5b34ec521a0dd42b6cae5077f18 GIT binary patch literal 10818 zcmeIXcUM!}_dUE5nt}o%MHImTB1O6)Jzi9#*U$+lO^Se_Ne`l82Z2a0S9+)dijUJ8J-Hz2G>)gd=Mo{j1@Ie*d0T^!58|*(F#c8(&I?%s zf&#^#kJ-mZls!mzulTPucKGvm?^nZ6PU-z_Cm-y}1kAK&U{8~tvpCVZG8;C$v3$_7 z5*-?HXoveW>|cRS*$fqzlr%LmG1x_`i>{0}Y`pHyZrWTLrS-2)Hqmp3V<-9IR~ICGP%|>KNrk4?)~WwB zk5`T?I3_HUG(6qhg1QY%S5mV3uz~qw4*AfR!-DZ;pA>KD44hwR=${K{>wh7E9N6Sb zzZ&$L#i=PISYns)cgMHm2o96vfDD730PzcY7v_=IwVdAGyx9N#1YF{R4ks%my4XP! z8Ak3mlzW$>74f2V8eLG})+C;uKeqG^v5?U+dp`I8LQ5Ab>k;kiF(&?q{w!Vbu0(~p z61?Docgme(F!$^%W$fpF5GPmfYX-q{O(kN=2MVrgby*F@!+Cp8e|r4*^YhBOi%BD8 z_516o{%uJ=h?y^S)JC|$;98@P5P`a2zkown^uPUbH_d-?7aZ%O(PJHJ8*?wig$Is zZk*wivwQR4aD)ZgnnBob|CSZ$m7Xm_9WqaSZ`aUokt5kvyD?~h?s}U% z7YB!XUvHvg#oHNLA}ag=`j+lsL~wWWHR902#OSlnb5(D}c$5Smc+-riIeB3oi^5zS zc0HLIz48+2CiBxK?#DZk_9wonMx74{+rGs{R#lP|+u2K-4>P94qexkyWqVmg zMi%siy-OKA3;F7~KG~UBK3W&I)S{x2qD<{#9Xj^H+}z~j-6ERwyN+K?`u|prB|6t@ z@TYuxS2CXzqju_jYgF`3A*LWW6+8c*si`u$-mj0ke2^>|45}9%1H81%P{S`?JhQ-b zz2=7#A7`^}uXuT_KhZhI&}HLjq{Y}~j|m;?csBT*0y>5Bps01tli;=Gm9@t%FZo$5 z#C7hYA1A6~=naSb?Us6hT4@+WsPf9jKB=6qx{?~Paj?}Vw;O%Xu#ei!3iHEkauplc z{cAJBvq^Z4C{0?Lzoc4edxP1L=1x&bEsa{SsH0%nAQ;1`CR_F78|K3np{joo0pPJ> zaANR3d48l^6*cf_ZJFWLBy>&?%po4L2ur(|_4I|YJivTlpgGxtC=BFfU;BeIL!t9| zF3#sJUwO;Q4dLe)%k-ShSl&&_;ch>=Q&??dDz!*5e9>{R~&I_NoOJYg%Fy0yaH)qe_m%*{|g{^c=pjEyadD%E4d*Uh+fdp9M zmW&&jRRZ!O)Fg0vJi@9W<(+BTP90WKaQEF!3n>|yT12WzvOD2@`!0u~x=T=;VL8~etn$PhNu+lTzNKQcXIHmTtj!siH#4tSZTp>B{* zaH?13S2-H4V^a|&1CAJ$F&k%s?Fvuv(?Vko@Q#@?`pT@lW!uT}ZIJ6>>nU2SE?VE* z4)yYpILjV|=NT@)&1szs;hG|m1>qxajxItxXvIoKMvr7IBb;EoMabtVnUfK53 zX$bzPGHXDzAhU3il8mcR+}!KPU>?-fI2Y&3zDbPH{(d9gkAxLf!{fNqbuF${I+u;5 zUN{`B#$4{5P*K*a6fL*^qjgpq%-w|orxBa7VVw4YOI~B6#j}J{a#I0!YQpL7?|!@8 zmUv$G2bG3U5Kxj5Jz|umaHECR8@K)|e{3-a)%phuaaggt_{p733ENu?1p<#Yhiica zxky0u#NTxKsgC7M^zK^txT|V4@unH3$Wv|rJ@2LeTOGh}MJsdt_R)PT4SLl8 z$-N_`J%o;fuTk?w_g4C_O@p!x*4M5M>Q^DK;t~=R9r)o#zhVf& zWd-sacJ_Eg63=Rcw0(XsX2e$PyfTTKBm?s7OnbC)u);kF$Y|_$8IRpuy^u2N7>7my zeoe7s?YpeYYzoE9$lnhKP^Ew9APu;5>?|`H;1-IWZ(pC%cAV+Vl3T$AT6Jd~T5T

#{ULO2f9@&FEW`3||D7vD zc~a5^_HNIK00H2rNa0Lg^$dqt$wW8qz9HqCH~2@zWj$ilU-%HcS87V`@jsh1=JUSo zd30F+C&N?*KbZR$b;i$DZmixxKUST$7lIcQ0ON}JRY$>$;EoYrUJjdCt*f%#W`52rT^jW2@z%MiAAF6Ta0J3ph0pGf3cl=^%cH1RmV!=!D+rzz%~Lx?jQzp z!+0VDQSFctB{WWMz@S)va$jWUcUup6Q!M(5bL4t#*3R_U`g{`yIYoM9@!;QaGe!7q z0S|*&lWaLo=zCejJvJ~F`aJ^jc>+631}R%K<{>}P;&Ndd01$AtaAdk{a*19B&WTK7 z==vvtttHDCa<|PnWXa;no;;;o4ntuqH?4HM7FJ$dTXB2X;OOCm;?dboZirqUw+kGk zi^c5Pd3ANaC;oT7p>;k5yR{!91MVbazb2{_HS*PS;{oI2d%Iy?)K#v$c%vN6TbMFw z;~88I)K;B|+zsnrr*caT7DJW1dYz)#CW0ke5 zx%oN$JkUDCb!|fD!0+ywNGU4yDix%OfKXLC%;Tpw55$<Cx}XR2b1 zFySiW)bM>ATW=*Zf!Xd!_hW3iE-Cp8m%l1vkOJvi>p$4&b9aHvk?P0KR3%@h7PCYv zwm;kIggWg|$DwC=%R?ms1W^;m?t8qIRTuzgFC7h7C%3PWbN-#e#9|rUl-b8sA|G>wk*;JB*cY6KYDokw@F(+}5@aYdp5@2;21P3Q|Q;4`z#@3)9wEZhR*+or&62 z$5!SQAmDG;g}Jbcrm`cZtB+hc&KW}M3djU zmr0Ns*T8&!H&26+?LMW@M{mck1wKhR-kn_3IJCwJ(-O%eLcRoA>!iP5dA|VB7Vfj` zfzDl0m6c$^Sx};2eU+cT@9Dgwpq$*Si^=kS@X3B{wmZW*+RJO6ZDS&N3H&ZN3f&yt z{`dqh9zkPH)I-=<))I`)PS=Y<_q)Xi>nsFjR75_%g^gEex zW9gb|f)k)rj++;z?!uhIBIms_}Vu9Z;4k~p5=&Wm4c4*Rz-nz*&hnl+66y4wJ%o-8t8W`JzlYdp3pn#}cur^3HyI zB)Mbkn>AlNyR+UU9xId_kb<&5RYG!`@d>qYe}!%dL4FR!o`K$+lE^$O9o zQbZw;={l1#V*5dvk*oh%?@VtvQ09~;lj~zPtM@(VAz}Aue0FMqPc-56H=`fz4fR{8 z-5yR!NZk2WLm3tz67n5Br!6yD7e9f|e)bp3JOvHX?KtpNP*9xC-o|9SdEZpjw1UI? z#A=uP?c2CPKe;DiC1pM&6(=VwEQ}<#ojA!FS^gMglcMiZsvP!+h=>ZWCF<1U*3jkG zrY8s8N9!zhR@a=?VEID`J2QXw!IHygOnI$#>#M7=av;T<$u~0D6uj;=bHGyF4J(tQ zbbei69QtQc4x$p;IC}iwiB&kC=NZ3l<5!U(Ym*=*?z*8w{?|Rw&Cs||rBhgfYGtSB zTBkBZy6esui-7pnMu6oka~D&V&2)hyU4AHW2$ad%YkO?!CHbH8Kx~~hq`|KpU1noY z*CACgJpyC_?Ky_5qXdCj^#5==R0rF0`O}x?SH?%=De0a$@AAB-B+Go5UxY*OCp`@B z%1rfku>2C@Hhe{}$t{_5hKp!3J%Ed^p0OGmHsg(0>X2a512$ZVvOZV6HGDd3MRM{g z1RvX);qGXT*spJDbh_~B=O%iuGF{roGa>N}(Wc`Y{Xvb);e)Mc@No%6Eer{7NfG=~ z*od=vHZ}lKuiRy_m);v0T8LUcmogH~-qFO6ez|KOGXk%D4YzY#0RPwqQPx+`o7_))HN1Xdu+%E~N@ zH*#9X70$&E{1+k*`!37AxmGD@yv6wF+S=Jd*BA0Ti1@nAxJq=qNOX!I?Vw<1Q{}J| z_N;fs=TiLrh9M2TTC#n>R%W>q@T>mxkwHqNf$Ao_4=sHSX+y|hYHo*>DcD3JV$vNf+;*b@0iqh+`IrKP%568mUK$+(jTKFTg&2!;N#_yH6m}g*qI;y3Sblyk#T@VQCp?&KofOM)fC=rsT(6M=s;ne!P zzw-G(LPkeSlXSvFMKah+2QG+r#7-!a-OCIzl+76&OdHaumgpcfwzKja8!>qz;w;LP zM@%tro5qh1orrd*soDL`0%WFEzIfp$H7m81f3qLubq+!}}?Yg*x*4d;I`fg5A}q=bgEl7A*(A9oyN3wjH=}qhRj^HyIyz`e#q1IjYmheuy7djLP|>NlI>`9G}f2Y zI5cs*8o>tGws=uCx90&qFkRO3EYmR2^FlTlbHjYIqm#3WZ59pduW{_UtssTkE0--Vl*KnB zjCzu`H_Oj9n%NOZ@d-bR66LPt?JamQZ7hoa^3m0O{L32O5mxu@)e|1>-^To!x?~@g z$7Q?;ow#Jf-JRNgOU**@VL>D{cF&!9(ZOw`zp%g1Fm*dopIGT+><@eJprYL0PCj&K zxDC_qC;%S0wIE`vLuEl8$6xe1jb)lxn5Sdjo->&_C>5+VPJmbB%A!n6)S5(u{_ns` zioL8X&N){j#;F~O?V^I0g`F;N@QA*)Ic((keUdiv`M-bE3IdNU9!HJ#=Ubb`N%v4i zLHz%@4*e6y+Bktlp(kFF>59}#Gd@nc;ZYaniS@bqPejVP=Mk}~h;aS7fnuFxj%A$b z`^kW~NV>-4`?F*9goU9pW1c(xw`4BZQ<4nj;IVjji@^c;dZX?n;iuBz@_PGf&aetz zU_tH0t_}b#_fC_RnH%9Fa&7D@WnF4&*4|M6?2{|XxoxcfVxKl-Ln#;KzV5knJWpnO zq}H>w_z1VC<}Y!spE3+(PqMsDgzM~B8r^U2BUbDgE8lrF`5 zN{P2tD<2onSWiFX2Tx>l*cB1$$&=_PX>fmTro?n`rD{+g6@J9!KI}FfX~2UcvV!TK z^S~vmAjt6DiEnyobXPbmk0p*nG|~(axpu3xq=X+g=`T$ywLwU62|Bua=s1Rq=x~EW zcchrlSyb%DE>sXO(`9nrxl>G+@7#T+R{sayJ-P9S60Cg8K^uA@!$cL8c zA+ukbP|YeEXpngIUl*~fw#I$R1uLAW8~zgt;C(`Z{02QaTFm)NUAWE!nPm>R%-6Wr zgl%}(eO_drpTIVi4$}OdZ_IQjGc6%Ul|u&I;9pMAq9$S3!AVl8-`@WRMo6vUX7Z^x zl`zfVaOs@NReD*+j)q@?<`nG*k>$Dn$?}B0=cVJOS(@iRm072gK*bP9HrirH2b*wk zgsC+k74Ah=Vp~t({0kUGJ2PVu5&JPd32M#h6ZNZY$N04|0jqRm>Ckc1wqAHGZDo)5VBxsC(@rUccu z`-G%SF0v(-Ls9m@#%!QLt;U%y`b(LsT;kb9kF+U$XIMs~+R(sO7M>tpWw6e3-i)F7+Gx73Ec$`Dv%?KTYnD3VU35N6ytVc)54aG2?-h zC*Bllhql^hr97P{q4=Paylbef?K?wgoHUNzddd6#>;?8a9*CB2rS>y7ybLv* zW2wXYH%_cCK|9a>T)svrBn!*4eCQq9liuv{3U5T(HLXCE?NF z@0d+By%5D>@gW(|c=43kV#o|-M&G;-CafI(T9}c*23&{so_D{vd^v@1cw?9`DLBC5 z!UO4)-y$eP2;yJ5cQU>CphWfr;v!pKE4}NFrn;gjyd(3h+z4f(%sTSd=;b@`;rKsl zK(ay<#bw{rehJvRSI&dqHkb0MU;6D(3-B=;yMuwG^%}1OJ)?i}5J#&OuRf##rtzPK z;C%Ehhpl()e1jK6Sh)b#nWlLg{n0}GZXG#@haiw2Z#eS3&*GZb>rSg#&r)iXa=wMq zDsuh=((qSQ`V*%{M{hCsL+9{AtoKy>AT=>uOKFUW%8I6AC0xeULy`- zx!BnX>+l!hw;;)^*PA_Grn3c1uM7O2n(zBt)^33e z)cs~h4UW8P+FQA9bZEI11eMOl9G|gljY2-c*)lE8t~;gbO&n>p7Ji)p)1_;xNGfo^ z;QuWhS4NVhhxl?e@T1xOh<82BImObm8&yNWaLmx2^q%7AT9?{9m93W5JdDVu+{J|0D-_qGdjuwxp0rQbF#|&Me zo{-MPS&fjP#OJRG$c{9l_>>YQ`_u`c6rI|I3Ing1{3Q7=hYlCkN?9l9FTb0c_#I;AqQu%@s3(z2yWNXVk6cZ3n% zc0(Rg{t6-ZWhDIzaIx|yeh~4mPuTrp*=g0Ry-euDMA~gpeWNxD(!{ZgTrX)8>i$kP zKYYYU!!+4FZOd_?@s+n)x;UH>a`0n)e&(R8yN1i(abCz?tBP87u(6yCDZ@(7DULZ8 z8=^++NWm3#DD=$A2(0?=p8xKurQ}?SQi>pG_+u}A3LOtK2Z_EskmiHov7{jl%aC1` z^%A20%)V;jb@D@6vn2cn<9QFG-#)&!*3$OahK7a%hc;+h^^wyaf2Wmy%7b?~hZ~v$ zPg`UQV1nhOVTtkMej|SZ4SSYJlm^deajr`HRaF_trS|{WxZLRp^gC6eT3wzQ78b^! zFKywvP3}Uu<1Esqd}Eu7Z+`;-ypF|efIwxiIu}vR>FIGl&$|k|mkEp6VZ+q5v|wOl z9t$fboBY|>DKNDj9tpT?WxW!>Uump=#W8u|vg2%k`8?BG`rqq+5%^yO{uhD&Md1JE f2y7Q`;2`l=oa*KKO78#tZT(v&H!J^fdHnwX_U@qb literal 0 HcmV?d00001 diff --git a/assets/images/wolfenstein/wall-art.psd b/assets/images/wolfenstein/wall-art.psd new file mode 100644 index 0000000000000000000000000000000000000000..297c7bb2dd310ec7e692e24150f0e0b25bea2509 GIT binary patch literal 47205 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%0D}R(SF37)&*|Tb_^)0} zDU0cAX)Bbwy>BnV#d_ZT~*1;lWl-P^tvR+I945#l!vsgFOi(s@~OdaxW^SQzn zt4qCzUF*dZtmj*fi^W7}SH4iUUQ8=_2*T&uT_o=by@-tK#Wb|=E%b$QHv*F7@UMy{_w?KOtuB&b73_Wvlr2hy_hgKJgcw)QxeY~9N7yAHhETTgBV3<{P~Eb z>_sEb-dKDs>;^DF0#D>+FPy4{Zv{Bu1wLo<5vaKb*fEU6HfQ!&Crg|N151 zmw;aaehK&`;Fo}30)7ejCE%BUUjlv!{HqdhQR49*T*yf@e@uzZeRF?wW~`#f`*o^| zlG1lSe|&dQ(Iol|6@b;Pb{*fbh~`coqOMU?JkuchX4T4u28RBQVrVJ0R)2#~#0ebD zeyWqA3pX*0Wao|@qXYu_5+$bTkvn!GOfmgn0Y~%-RxzhlkGUA*Ij6H;C=!Z9V)79R z1;RR~^PG#JA5(FpFJpans^KpT)xhn)^vnJ^>W*urb7Y-_Y$dr2WZdfMcRE4VQ}1z{ zO$QfXHS-=vZ^HEU=&FAZ0qdy$3#pL|-kGyI(QGzzVp%BQoF)X-QWKj z%D*m)mHz;D|43>C_qLpP)aBNrEADvori5;#^?meKY5p^~w<6rs)?1I> to patch into rather than a hardcoded list, + // since new decal frames are meant to be added to that JSON alone, no + // code changes. Each option's id is `${WALLART_PREFIX}${frame}` so + // applyTool can recover which frame is selected without a second lookup. + { id: 'wallart', label: 'Wall Art', options: [] }, { id: 'door', label: 'Door', options: [ { id: 'door', label: 'Normal' }, ] }, @@ -134,6 +143,13 @@ export default class WolfensteinEditor extends Phaser.Scene { this.refreshLoadOptions(); }).catch(() => {}); + this.wallArtFrames = []; + fetch('data/wolfenstein-wallart.json').then((r) => r.json()) + .then((d) => { + this.wallArtFrames = d.frames ?? []; + this.refreshWallArtOptions(); + }).catch(() => {}); + this.buildToolbar(); this.buildLoadPanel(); this.buildMinimap(); @@ -153,7 +169,7 @@ export default class WolfensteinEditor extends Phaser.Scene { campaignId: null, missionIndex: 0, width: W, height: H, cellSize: 64, walls, playerStart: { x: 1.5, y: 1.5, angle: 0 }, - doors: [], enemies: [], items: [], + doors: [], enemies: [], items: [], wallArt: [], exit: { x: W - 1.5, y: H - 1.5, radius: 0.6 }, briefing: [], }; @@ -317,6 +333,7 @@ export default class WolfensteinEditor extends Phaser.Scene { doors: this.level.doors.filter((d) => d.x < w - 1 && d.y < h - 1), enemies: this.level.enemies.filter((e) => e.x < w - 1 && e.y < h - 1), items: this.level.items.filter((it) => it.x < w - 1 && it.y < h - 1), + wallArt: (this.level.wallArt ?? []).filter((wa) => wa.x < w - 1 && wa.y < h - 1), playerStart: this.level.playerStart && this.level.playerStart.x < w - 1 && this.level.playerStart.y < h - 1 ? this.level.playerStart : null, exit: this.level.exit && this.level.exit.x < w - 1 && this.level.exit.y < h - 1 ? this.level.exit : null, }; @@ -378,6 +395,13 @@ export default class WolfensteinEditor extends Phaser.Scene { this.loadSelect.innerHTML = opts; } + /** Patches the Wall Art category's