From 6305280e62ba192546bc7d0f216b35696c352a0e Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sun, 5 Apr 2026 22:47:12 +0200 Subject: [PATCH] ajustant el jugador --- CLAUDE.md | 28 +- config/assets.yaml | 28 +- data/player/player.aseprite | Bin 0 -> 837 bytes data/player/player.gif | Bin 145 -> 323 bytes data/player/player.yaml | 12 +- data/player/player2.gif | Bin 223 -> 0 bytes data/player/player2.yaml | 10 - data/room/03.yaml | 7 +- data/sound/jump.wav | Bin 0 -> 9814 bytes data/sound/jump1.wav | Bin 2310 -> 0 bytes data/sound/jump10.wav | Bin 2238 -> 0 bytes data/sound/jump11.wav | Bin 2134 -> 0 bytes data/sound/jump12.wav | Bin 2450 -> 0 bytes data/sound/jump13.wav | Bin 2658 -> 0 bytes data/sound/jump14.wav | Bin 2310 -> 0 bytes data/sound/jump15.wav | Bin 2414 -> 0 bytes data/sound/jump16.wav | Bin 2450 -> 0 bytes data/sound/jump17.wav | Bin 2450 -> 0 bytes data/sound/jump18.wav | Bin 2450 -> 0 bytes data/sound/jump19.wav | Bin 2342 -> 0 bytes data/sound/jump2.wav | Bin 2170 -> 0 bytes data/sound/jump20.wav | Bin 2274 -> 0 bytes data/sound/jump21.wav | Bin 2238 -> 0 bytes data/sound/jump22.wav | Bin 2274 -> 0 bytes data/sound/jump23.wav | Bin 2274 -> 0 bytes data/sound/jump3.wav | Bin 2450 -> 0 bytes data/sound/jump4.wav | Bin 2238 -> 0 bytes data/sound/jump5.wav | Bin 2310 -> 0 bytes data/sound/jump6.wav | Bin 2102 -> 0 bytes data/sound/jump7.wav | Bin 2206 -> 0 bytes data/sound/jump8.wav | Bin 2342 -> 0 bytes data/sound/jump9.wav | Bin 2414 -> 0 bytes data/sound/{jump24.wav => land.wav} | Bin source/core/rendering/screen.hpp | 8 +- source/core/resources/resource_cache.cpp | 217 ++++++++++++++-- source/core/resources/resource_cache.hpp | 27 +- source/core/resources/resource_types.hpp | 5 +- source/core/system/debug.cpp | 6 + source/core/system/debug.hpp | 2 + source/core/system/director.cpp | 16 +- source/game/editor/map_editor.cpp | 4 + source/game/entities/player.cpp | 313 +++++------------------ source/game/entities/player.hpp | 63 +---- source/game/gameplay/room_loader.cpp | 15 +- source/game/scenes/credits.cpp | 2 +- source/game/scenes/game_over.hpp | 12 +- source/game/scenes/title.cpp | 2 +- source/utils/color.hpp | 122 ++++----- source/utils/defines.hpp | 2 +- source/utils/utils.cpp | 33 ++- source/utils/utils.hpp | 3 +- 51 files changed, 487 insertions(+), 450 deletions(-) create mode 100644 data/player/player.aseprite delete mode 100644 data/player/player2.gif delete mode 100644 data/player/player2.yaml create mode 100644 data/sound/jump.wav delete mode 100644 data/sound/jump1.wav delete mode 100644 data/sound/jump10.wav delete mode 100644 data/sound/jump11.wav delete mode 100644 data/sound/jump12.wav delete mode 100644 data/sound/jump13.wav delete mode 100644 data/sound/jump14.wav delete mode 100644 data/sound/jump15.wav delete mode 100644 data/sound/jump16.wav delete mode 100644 data/sound/jump17.wav delete mode 100644 data/sound/jump18.wav delete mode 100644 data/sound/jump19.wav delete mode 100644 data/sound/jump2.wav delete mode 100644 data/sound/jump20.wav delete mode 100644 data/sound/jump21.wav delete mode 100644 data/sound/jump22.wav delete mode 100644 data/sound/jump23.wav delete mode 100644 data/sound/jump3.wav delete mode 100644 data/sound/jump4.wav delete mode 100644 data/sound/jump5.wav delete mode 100644 data/sound/jump6.wav delete mode 100644 data/sound/jump7.wav delete mode 100644 data/sound/jump8.wav delete mode 100644 data/sound/jump9.wav rename data/sound/{jump24.wav => land.wav} (100%) diff --git a/CLAUDE.md b/CLAUDE.md index 9d6005a..ce9a41b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,11 +18,37 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Estado del renombrado -Se han renombrado las referencias de `JailDoctor's Dilemma` → `Projecte 2026` y `jaildoctors_dilemma` → `projecte_2026` en código, configs, Makefile, CMake, LICENSE, Info.plist, scripts, locales, etc. Se han mantenido como placeholders: +Se han renombrado las referencias de `JailDoctor's Dilemma` → `Projecte 2026` y `jaildoctors_dilemma` → `projecte_2026` en código, configs, Makefile, CMake, LICENSE, Info.plist, scripts, locales, etc. Copyright actualizado a 2026. Se han mantenido como placeholders: - La clave de locale `jaildoctor:` en `data/locale/*.yaml` y su uso en `source/game/scenes/ending2.cpp` (es contenido de juego, pendiente de rediseño). - El publisher `jailgames` (carpeta de config de sistema: `~/.config/jailgames/projecte_2026`). - Los archivos `release/windows/jdd.rc` y `jdd.res` (solo bundlean el icono). +## Log de cambios realizados (sesiones de trabajo) + +### Eliminaciones +- **Clase `Stats` (persistencia CSV de muertes/visitas)** eliminada por completo: archivos `source/game/gameplay/stats.hpp/cpp`, entrada en CMakeLists, referencias en `Game` scene (`stats_`, `initStats()`, `addVisit/addDeath`), ficheros `stats.csv`/`stats_buffer.csv` en `config/assets.yaml`, patrón `*stats.txt` en `.gitignore`, campo `worst_nightmare` en `Options::Stats` + `Defaults::Stats::WORST_NIGHTMARE`, display de "worst nightmare" en `game_over.cpp`/`.hpp`, traducciones en locales, menciones en docs. +- **Mantenido:** `Options::stats.items` y `Options::stats.rooms` — son contadores de runtime del marcador/game_over, no tienen persistencia CSV. Coincidencia de nombre con la clase Stats eliminada. + +### Música +- Eliminadas las 10 pistas originales (14 MB) de `data/music/`. +- Copiadas 2 pistas de `../pollo/data/music/`: `574070_KUVO_Farewell_to_school.ogg` y `574071_EA_DTV.ogg` (7 MB total). +- `config/assets.yaml` reducido a esas 2 entradas. +- Las 10 llamadas `playMusic()` existentes (title/game/loading_*/ending*/game_over) remapeadas alternadamente a una de las 2 pistas. Mapeo concreto en esta misma documentación si hace falta consultarlo (ver git log del cambio). + +### Paleta +- Eliminadas las 23 paletas ZX Spectrum/otras de `data/palette/`. +- Traída `cpc.pal` de `../pollo/data/palettes/` (JASC-PAL, 28 entradas: CLEAR+27 colores CPC). +- `config/assets.yaml`: solo `cpc.pal`. +- `Defaults::Video::PALETTE_NAME = "cpc"`. +- Traída la clase `Color` de pollo a `source/utils/color.hpp` + `color.cpp` (enum `Color::Cpc` con 28 valores 0-27 + `Color::fromString()`). +- Struct RGB `Color` en `utils.hpp` **renombrada a `Rgb`** para evitar conflicto con la nueva clase. Propagado a `utils.cpp` (`colorAreEqual`), `screen.hpp`/`.cpp` (`clearRenderer`). +- Añadido `source/utils/color.cpp` a `CMakeLists.txt`. +- **Pendiente de revisar:** enum `PaletteColor` en `utils.hpp` sigue con los 16 índices antiguos (ZX Spectrum). Los índices 0-4 coinciden con CPC, pero 5+ mapean a colores diferentes (ej. `PaletteColor::BRIGHT_RED=5` ahora renderiza MAGENTA en CPC). `stringToColor()` también sin actualizar. `SPECTRUM_REFERENCE` en `palette_manager.cpp` sigue siendo la referencia ZX Spectrum de 16 colores. Falta decidir cómo migrar estos tres puntos cuando se vea el resultado visual. +- **`next()`/`previous()` en PaletteManager**: con una sola paleta hacen wrap al mismo índice (no crashean). El concepto de ciclar paletas queda desactivado de facto; posible futura reutilización para ciclar modos de ordenación. + +### Otros +- Añadidos `desktop.ini` y `Thumbs.db` al `.gitignore`. + --- ## Overview (legacy) diff --git a/config/assets.yaml b/config/assets.yaml index cf111c6..642a5eb 100644 --- a/config/assets.yaml +++ b/config/assets.yaml @@ -252,11 +252,9 @@ assets: player: BITMAP: - ${PREFIX}/data/player/player.gif - - ${PREFIX}/data/player/player2.gif - ${PREFIX}/data/player/player_game_over.gif ANIMATION: - ${PREFIX}/data/player/player.yaml - - ${PREFIX}/data/player/player2.yaml - ${PREFIX}/data/player/player_game_over.yaml # ITEMS @@ -276,30 +274,8 @@ assets: - ${PREFIX}/data/sound/item.wav - ${PREFIX}/data/sound/death.wav - ${PREFIX}/data/sound/notify.wav - - ${PREFIX}/data/sound/jump1.wav - - ${PREFIX}/data/sound/jump2.wav - - ${PREFIX}/data/sound/jump3.wav - - ${PREFIX}/data/sound/jump4.wav - - ${PREFIX}/data/sound/jump5.wav - - ${PREFIX}/data/sound/jump6.wav - - ${PREFIX}/data/sound/jump7.wav - - ${PREFIX}/data/sound/jump8.wav - - ${PREFIX}/data/sound/jump9.wav - - ${PREFIX}/data/sound/jump10.wav - - ${PREFIX}/data/sound/jump11.wav - - ${PREFIX}/data/sound/jump12.wav - - ${PREFIX}/data/sound/jump13.wav - - ${PREFIX}/data/sound/jump14.wav - - ${PREFIX}/data/sound/jump15.wav - - ${PREFIX}/data/sound/jump16.wav - - ${PREFIX}/data/sound/jump17.wav - - ${PREFIX}/data/sound/jump18.wav - - ${PREFIX}/data/sound/jump19.wav - - ${PREFIX}/data/sound/jump20.wav - - ${PREFIX}/data/sound/jump21.wav - - ${PREFIX}/data/sound/jump22.wav - - ${PREFIX}/data/sound/jump23.wav - - ${PREFIX}/data/sound/jump24.wav + - ${PREFIX}/data/sound/jump.wav + - ${PREFIX}/data/sound/land.wav # LOGO logo: diff --git a/data/player/player.aseprite b/data/player/player.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..c07ec96190f412ff6c03f04202cb19b4e60d0e6b GIT binary patch literal 837 zcmZ=|W?*=*l$C*lK>&yu85kH+fEWQ37#KlVO)Uumim)mG2_X0n)yM!2_KG>Crw(#47;rEJn7_Jq^#A{xGqoM(IWnwcauoVj z@upXCilefd)ZQZ9rT>qwvcGcm?3s7W>$#c!B>_$P^^p-Abf5skXG3V0As>SR57Wgh zv$_BOUo+)_LgtQariQf+3Y^7}_xcx1aR^f6_5E2P@-{^N^0bZbEMr#kGp!-T2J-xn zjOK@6ARkXC0sR0BrL3yYhyMT1@i-O3KN}KCJKppGLrK+5YA!I8-XE{CZC(FADDY&> zIs>LpxU2vL86qOsf$19<5j~Dv2OKz#x93*JG@gzE8H-6B^D3kdUzfb4 a-Ma76D%lru^{4NzTCr#48P;jlOeX;dN6tF{ literal 0 HcmV?d00001 diff --git a/data/player/player.gif b/data/player/player.gif index 51f56dbb6e36edbf824909cba88a4846fabe2511..3462b2d115ce5ca5b612240da67e89d6f0d3f3af 100644 GIT binary patch literal 323 zcmZ?wbh9u|)L;-`IKlu24Gawbfw+O8p@HH5e;|jU;XjA~3IWCbg9s4#4^#x?{0B>d zbN~fFNjb*I5DK~X zUX$nBwB3(4MC=VKzROS+bMD`@=LMB6xsT8PsZKO$j5TXvX=|#D>+CVFZ#CnY%o8R! zWopFqDbr?z%$}@1Pif)8MRS%fTQXznnwd*yGOSy@cH@?sjOjhmP4Ua@n} fE*@4T){`eson|rE-tW)G-um%8T_A_k& diff --git a/data/player/player.yaml b/data/player/player.yaml index d8fa865..76959a6 100644 --- a/data/player/player.yaml +++ b/data/player/player.yaml @@ -4,7 +4,17 @@ frameWidth: 8 frameHeight: 16 animations: + - name: stand + speed: 0 + loop: -1 + frames: [0] + - name: default - speed: 0.1333 + speed: 0.07 loop: 0 frames: [0, 1, 2, 3] + + - name: jump + speed: 0 + loop: -1 + frames: [4] diff --git a/data/player/player2.gif b/data/player/player2.gif deleted file mode 100644 index 4140a7558f6c423c6f316b88b49810f718b156ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 223 zcmZ?wbh9u|bYKu*XkY+=|Ns9h{^#~{4GDI33~)8lGhk)}iYoqO;p76+Iv^z=#SBb~ zTbdK6bFUOD2{!9~Q9Cb!$cQ@0%z0M)WOQeZqRx zgaf=R?Nv>)&P;kPUU_fHtsK2yrD41Hg?+uVsty}Q>?~}{J)J*miD>@yH`{mZdH?m; zrfbiieKOo$yo254d3(ll<(Wn|n?DA(?%dH<&UTbpOyw0v<<*rc#pc502~(<6OeHE- WL}i_-I$621@^=>N?5aQp25SJH4PLzf diff --git a/data/player/player2.yaml b/data/player/player2.yaml deleted file mode 100644 index 523b248..0000000 --- a/data/player/player2.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# player2 animation -tileSetFile: player2.gif -frameWidth: 8 -frameHeight: 16 - -animations: - - name: default - speed: 0.1333 - loop: 0 - frames: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/data/room/03.yaml b/data/room/03.yaml index dfbd896..f652322 100644 --- a/data/room/03.yaml +++ b/data/room/03.yaml @@ -1,9 +1,9 @@ # VOID MAIN room: - name_en: "VOID MAIN" name_ca: "VOID MAIN" + name_en: "VOID MAIN" bgColor: black - border: magenta + border: bright_black tileSetFile: standard.gif # Conexiones de la habitación (null = sin conexión) @@ -44,7 +44,7 @@ tilemap: enemies: - animation: code.yaml position: {x: 3, y: 2} - velocity: {x: 24.0, y: 0} + velocity: {x: 24, y: 0} boundaries: position1: {x: 3, y: 2} position2: {x: 27, y: 2} @@ -56,3 +56,4 @@ items: tile: 42 position: {x: 21, y: 13} counter: 1 + diff --git a/data/sound/jump.wav b/data/sound/jump.wav new file mode 100644 index 0000000000000000000000000000000000000000..9d0e2e9d2427524b6da5b57781d262ff13dd70e8 GIT binary patch literal 9814 zcmb`L$#Ub!5r#E4AN>eE`QW#3ggp_y_~3)*FltHELQ>p!5(Eg4;J&LxN?b&(?V}&k zSwK|*$V|1Yp7|Bhp}xwsvH(*5`p3^d|MSmBN5A~_-+zy1D}Vaq(b3UQ@bkC-9(lh% z9sS|xGFFNG1@=sK&u`!UgZ0o%#=ac?N_1Skd3d4wxAnvsxBaBGeti8#+%HR)r`-0$ zXv-w?WT#>$$26HQ#_fSR|2E0<&ePM~Co<<#d9TjT?dCICmae#_@Ew13)8|}IVx7Au z+7mx*(!tNUX0v`9WG}cp*oOQro7ptp84-R$)|EI6E9nNC@;i>%xqfHzpvwn3c<-Ec zVa{By-@ez&0pG)K;_T=(WNUk;59#Timd0N|e=^Z?h96A!*beYSqLaoJ_RKyo*sZ)* zHUU0Ywk*E`c*3}5@u~VpfO^F{EiCB3@R@S+&6j`K-;l>JpD4GJ_sK=)^W-X;de3y! z&=Xs{T%uj#)8snOx{P)1pYYp_%@QVr#AXW@Q->eOGRbH;+(y$F0?5+nRIf^kJFgr0iWBpgs&y696~H7kgBoFwtoc=q7IRKXwI~*(2>c)NPn1=Nho?2v7L&M;KqNj|z z_9HuR6q*Oll-7c)CH)X>4}TP8zWJuS_5PcN^MK02Ap zn1H@=lkKBmo}S#?)%lr*snPx8vx1VHNdY@NzeoX#pT`tBO9OjS@DbQWOvBt{6R-y- zE0|JwCYaRL%3NKXD|Bw&>;g8gTwew(?ymNaPtx$QUrYj1%1`befce^3*?7P%%;ol= z*}R&%3fOgTwL3gYxN~xes|&6AeDeUz7np%dr4*QHwsZ2yt4jqh&BbPaIQWK#aXA$S zCRG@(!Axq^%qFiiOZRTKd&TaoTr#d%!d`Cn4-Y=vxy4lCN-1tG?stL-?fa!v0?ecu zv%BqHu~8+RjB8e%thc+p5BH-=CYgvU0on-U38U3!r`V{PxlSmvL}Ln8p#6Tg+xE%= zNhPiMdb1S_wCR*G*GYx0okf6FRv~?zR4m)Ox!Y`|7L9xgkW^{(H9*5^HbB?bY;~`! z)=nvtx>jbn?s9#;GrL_Yv^0y^v_ffcx4M(Mb;`L+TB$NzuGW&Qd)0haqe6FnyH;pWF9aml znSEWYrN)h7E~AunrZ<{Qo26V8=PgcHwGW}QOf5$1b+%0@OCS0 z2K8b`G#T5CT2+C1M*v^L763(z?nr~aSqC6x^+yv)CT=qTHD>_8 z*T^;kV7SAv0zIoyuPL>9qp>98b~6C=_5gsdLCdIX3#&WSpkp@biZt4N4F)!NQnI>( z5eQt3Ms3s3!03R1RM#>Z3N-BAK!JhN1Rw>DhC`nWg(D@i(-**#YXt^I8yrdXTBf1p z^!fuyV7;l=?JlhQ>en<=Vk|3*0NU?Un|1$5p^}U|q?9 zb*WBh-EIf#jvefGI(oeg>k`cH0RF)|Eo5V!P6Z H%kBRGKUU^s literal 0 HcmV?d00001 diff --git a/data/sound/jump1.wav b/data/sound/jump1.wav deleted file mode 100644 index 490ce296c8c004a2f24efc4b9c4f2d58b8e069a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2310 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 F{{RSFMg0H( diff --git a/data/sound/jump11.wav b/data/sound/jump11.wav deleted file mode 100644 index a9a44a03260e51b347f534443857f44563cf028d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2134 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 cs8_%E4V=Oueuvu%H%2^BxXsO{F*_x)7 znjhu*fg+G1rji@^g{Xv}m?+V}xNuDyGjR0asjugDjMg;GrrEW3z9!+0T?^5owP6_}vpuxU$Qtr&#>gSrPLhY^ z%$=Ijw^v$fucX98ZAwmV4kIg%s$Qz6>aHH8xd)9T8p$*QXd=x4eG)wZDUqJuwChPv zZ{qe+DI|3dG6G0I)0?o~#7qowl8BY4QiHlaq)80g4lw%!u~gC}lN{Iu)@0%Yc>hNN z`xN4&kR~mNr>VZG-~Z%3qIdp)qGW@RclRn4fm=NwN2%#8{(R%R}IQ5@5{5YO3oop zqpX*va;t$VT~(_pHPSxLUJ+IkwiLF*iul9v!#uBf{4u&djeo#fJbJ7jV);rag!kM< z?o0eW|0j6iirLP+hVSD~@E7@7^9xfzJnwE~8qG$exdSSon~`CZ>Sy)#k!IwRA%jB_ z{2l$*tVXL$JFJ~lN7QanAbu2AM4FbO=`vbcLI}TVQ;niQG|478R*g~*$%o`~YPi}h zcgYfl=||mH-1E&%W>1#MY~~-# zx#mXmI)qaX~3*N;fs?*uxHL*^7EMio&N)V5TSLG}61^K+3 zASQ?gc~PdwKC-_yK-=Kh>KNo4?fk(+^Q7m7XD^(AD!oZhHnM|xS;Wq;bUvOhF}50A zU=WPvuk&ikgR$@zc!|&BS$rm63neh0Z{&W6<13&5o`kW`)iuzyI&4$eFO-*yy|cZA zxEGur^yQ>UXsS7vNUw6RS6M`2%v!?2TZi}~_xDXlgOWR$EC z)k32hhzN-aX$^1xKrBz?XFS(EZ^0%g(2wfd;V8I_B;yA4hW+duvm5b7Ics2PFcK#6 zg?t&?&C20C|&K{ovYZD9-bBc1l{HG*7>ca{zCsy+fdsk z%F~6uS-zL$WU8f7xzfMXzhCSTnR19sw7OdDq!6Ero#L2PW{r?pvK-6seO!z=a=h#> z(!@gB0-Mz#G;DuNbqa4U)GuS--G4BDxU@BY0Ci6VL zlx=4gbHNp`^TF&zRt%@%LGrhle9eSuP#9AYV{=A1UuieJozrXgu5Ej-twvVML0YvoaRj(#n+14`aU8`9(%U#xI)^j)%C(8+PpH*y`B1-Hc-^;9h)>mRbRca>X z^$a=DG1YNC@@nJ&bCS8;UEzLM@2_vv59oP(8!x38-ql0dD40oIwmZM1-_}>bZg>qo zfPd>kuY+6gAuD2ASs7ak`=BcuKsWLrT-KZQe$iRcdpjKLaMQYO#kD$Hr&$xN%UXl> zCQe7)*TGjvzYE*MXTs~d>$@lJik{RPe)V7T|0aGB1-K0ht$gdMXcTtzS%KPoUn~_z zDDEAFN7PVnj6^$5quPu^6VKvtl!zFQ411HM2{;yu$j0w@2cN=z=n@g)O?(wgu@IZ^ zDvrYuXcLldZZ6&60la|cDLZEo`wlL{C0L0^$>P_z2AAV6_!H*g+jtS{@C)37`S=+& z;$`Y~%di12VKMcS5_;Pu(yt|c1C5=y8O!l7d3hWQX!jk~(!8CzN(COngXBjES*Qu> zE)eTW+)vEI80b5tWa}cHBd_-0X=0zIGk+)kx8!3PVRghhhDY!up>@OyVD+T?iq4-U zO*QGi#zXYZi-eTXxhk>|7)OX-OV-Lscb?9lp!rnL?kW1>M$%RidVy>P&Q#+W`lfSa q?If+WgjCXdYJ$Fv$Y>giw1Rs1h&C#2~B diff --git a/data/sound/jump14.wav b/data/sound/jump14.wav deleted file mode 100644 index 82bbfdbbdbdc1760ec8367abaeedf13b616da6a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2310 zcmXw430PIf6~2$<$s*gkv)ubov;~(a3IZ-cq9Ou5Kmkoe)A$)A8dFL7mEb}o{Zuq+ zV_jkrw_s|;*d#XA1vO}l#uZeIRV#5t>k1MVl;z!XW;&04{mysa{B!;}=l*l zz#;ty59&W4HdcEpzc_!t%91WeOP9=0=8~gis`~YeBb7HprgvDX93yjNnoN;dGE=cx z%0??2qejpAu?nSkWEib@5BB)}$7QK`ro#V^OI7Q#74Pcsx)htCa%8FeSqkN-xNKz} zJXXy-Y^Iuf*c>%_bd2rDog>F7pNGj*maBZ3>iM0_lYfz`1eMYzQ)BF~<8|7p_ zX>{22HU3}v7m7mh#NFUF(1F2T4zChfA`>A2)@tS2Lb*VGfV1$4Y?eXFO2vHfp`0gs zD612f#Vhg^86#um58{xREoaH@va8%L56bD@?|3f{C=ck)Q@H5bBjUPYH}mzm`We>5 z9yo);x6u=HBRxQ)ojJ~@G>pB;K4jtMaPt_gr%~L+{fxeb59`7<@uPeqpUp?GDQp)1 zj2F{SX<^u+umFFWt=LASE(5?90&Jaa(?o$N zz$sX+ZPsq$4g5xI6}x1WY{YxmOYI{{_L5t~mm<-YY`fxn+n0p)3B3^R4o~eeqswCw zOwZ~M^ta4KW}V?S?&@A7!Wd@kGU|*%Qbwj2Wk#MyADu*VjXB0hHkrN4REvWqO26p`rA5urouDfWlfZ7a{6<@S<3vO#OqvN01op$*^E3bblGg3ECkUX$14 zYK1-#t3@~2O+Lm3Y!|I!mM9YMiJ4-j_)e@69}7zeQKeOC)ZWcr5HcsE!2HO3;0y{6 zWPR8HQb%_2e{s_oY7C({G>FG@kFF*3D>|Cb;K$fa7Qsd^H{*O7Tf$bd?QA{U%RW|P z4x7n*SZ@|dlE~8F^587rJl}p+q}AHq+@2ug zUc8U>=vL|)6iODu)Gj^|LBcN5M5@@JELV&XhUV1P`~1zvFPI09a?Wt3b}8)g8ZDyV zI!-!f8q1Am1~I4VrFs-ko3K(L9siBtR1RBtC12#Qp;+!~R{bX&zjrfX8lIbuCYVkO3 z7F$F)d=8VvYoZY!VFnJv@d}q=sp_OEv%mfB+c2KgO#Tz8~6r#aUd zRff;#gq6oR$v_VQzy9wKgX3=t$g#f1zJCQoPBTDxv;OoYr<>I zXXZa0)s8fMir(MMH9N6LcE!=`2sHW_ZIrQ7`YpXg-4!G08*~#nK(4ZO_6uny6X|R^ zlPzOA$r<9Q|8MC~niKYR*wDa?z{w&{Y-m~4(%0%{{iGe&N<^_();_;IUc`xIa-ocN z_jC^y@nW9%Ktx)GwO(u#MOcU#kPP`EUtEWa&;~6KAbiDrsD~I4D|B0kP1*xH?RL~S z?wfY!9qwa%q3==^PaqGtzmY(*shxBsNve+59(E$1qO(GM>lF*HzFZ?wBc2&EU)_bij)?;h2ER(%43enx{uET%h1+2va zYqE6#&*95B04X@&xjLtnumhez6O>{RZij6!5EJkv?5>_(SR&>KFE4MeyZ$fyKO^4} zUuRF}7wjOrrs~^7>@<-Qq?D{9E7(p|%VXp@p{knAbTg?UaWt1EtGn<9@uu-K zU8zl{PgQ?hCvBuwZ_uklu7-s8nSMht9=~lZZ=GpPwI<04G8vO_fqSmI4Cmq{yo|rG zxHS&5F&$Iznsw2dim&5ixDW5ZG)TZ`JO)Q#HT)UkF&6&;73wtagTB}k=Rq+L^*?qM zF2E+(057ZeEQJN&gWmX1eV5I!5&B^tTnj6}AMJPzF2RrRJy6uKLPZ3kAD)M5_!&-t zUG?M+_&an$AFP36@BnVXQ}|V}N5KmPoKzZ~t2*9;n{Zi0XlOwV9Pb!^fpbdjy^i&D lPzx5g)ti2XW@v;*DpS3R0C=H%=N0!H?!Z;${f~-8_%Dzcl*<4B diff --git a/data/sound/jump15.wav b/data/sound/jump15.wav deleted file mode 100644 index 53f3e2365f8d70f8835c0ed5a628a14f38d473ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2414 zcmXX|3s_ZE7CwhJ^0;u%*=wJBFDRL)nL1hulosX#MG-^+9l%iwHQ$a(Cg7;WXd((1 zL{kO`4YRK(6|&T5e0>m_PU&c1IzFZ`b9{~B<#G1fd-kQi_3gdS+H0Nvto^UG_IIYn z$HmR_SCr|mrHz}nWK~3nqA053p{ze9A0BupUP_3P5I-%&F4g$NxTN@LaVf#_IbqIQ z^M=O^j*c2UbjT1TYtE`U5fY_PY!QWGvv^OABC%CUfn1$(6pC$9bMLvWh21*^qFCD8 z?-WTXmaOkC-4^$koZU9JwW!<2DYlE! zZkyZw8&*lTmm6cd6sJTemOf57+$bfYOwQZI4yl*O+3oE{DD3ujBb3QeDt5}fBJsZT zs1_dzZ$*eAb%#2~XMxXc3$wJ_BJ7D_%fn3QMW>L(B-Zx2t;Jx*Xvl!!#vhHX#^*)@ zTm^>_Yj_&Z8h5~tQsZSKpVrV3G@XVRFBma$Ev5(PL3)wyg(gTO^GUj8nI+yk(R&yh zz(kkXq;JxaZ3AKF4(q}*C(edx#i z3NRltJ5oB{W*dleAI!Fu^xL@MYvlIMTWUF0wsXS`u-hL2zt;wkJ^AVK9ld09B;t&SSR}+LdJat&*CXrOUJPRSMp_itQaFMs+ZKz9^pM=^$dNC zBg;{0d}U;7TeMNK0#b|>Mg{qj>?ciRlkCl47zBSOKanV!LQjyJ!~=T5C3%8vq?Wu3 zl`=~!;S2IlQU(WLH>oEZ^a|ZS#1XRC`_JAxyNbGww;yhg7SZB{dQ%-?#+VLfWuGXu ziiUwWfc0hP#2GOKC*e8v9V?dinlE}|4OXK?_V8i$8C%EK@lpI$9)T$r{{ZyGJ+cp`@QM5hd&~m4CvU+P3_>rQ!P9s$PDU3##%fU` znmigkdIb&*bP+3Dw71!N)3LP7y5BkhvfxMRqG$EndOFD_9Kz@ZQbl4(8mWOZkVM`j zv&mn`T*!xD(udq2D!51p7$k;-K{N!AzNAV!s;#jUSem`hdk>V{W^_#H@Rc#-C~K5O z>6)u+IqcO_b|c@)NRD6f2Ny2=pd3n3^Ifyz!Hcc z(PT84MQ#&M2qKZ>9eJ*U<~MPjrfQ^A?dA;)U&|}*?OV8CGF%gc}(iHb6Sp8ruhUx&KYH4{vKrm`}=o!>Aonn`RD%jMbpLz$cY*iS~^ zfCXm0X<`>1X06^{kHdM1oJ*L&?@9))$|_6YLw-8y)xy zyCvDX$ATnE3%elktay`MXCBzWe9#mB&Hg3#LZsh+q%N3>UF?y>(a;a?u{+)R0EzQ| DHG|C_ diff --git a/data/sound/jump16.wav b/data/sound/jump16.wav deleted file mode 100644 index 7f66d15abe4111fc900db33e5f8840ba4ea8a316..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2450 zcmYjS33ye-6}~rl0SPY;-n+Bh_mbdJWeZDyEDs_QiivrU0uqAoHGC95goq_50*X}x zi>4%z1f&>bM@R?|kWwumCCDmk*n}2QK+2*Nv04J}-g9PpLO=WUyWh;5ZO%Ps=KN=d zMRIe?S{cSO{YT`CpEUKMwuWJtMvO7*QzE{PF+4_FBR^6wJVb0{aPE*uLGExL(fMPi zk53PG%gpH3BQ@0+H+JgSC&^1sou)Hr^whm{I*qjdeW~}kOwu+>dy=-9YMy%#_g}l- zx;M!(?rVC`oJRUA8qIVc-MlwUvOc=+eO)G5XOOh_|LM|*3zLt&wC`u{>7;+0_)OZH zb)O2;8YY{^$#*ZB`_R{{3F{~B%fdRFs6OOtpw8D@biFPxN0@ajwzU}If6gzGo=9p) zx|;Ma=H)%uQ1)tQap*0(#;#)Z?1+8SuC}+^gZKpgroGBOE^o`QGCZt<;i)%nsn*IL>(1Sf^^#BkDml+$c1< zscx#B4(V#WScg@HTB}#;i|VqvsJ>Ra^)B7n=w|efi^Lu9UGQax#)Upe-jnR`pcr9I zwnheL28)7k1gEhDY^nUKObZqSALiM-R_>QMcCr0D{{#P4wzP-K>GBQ_h-AB;Jzs1R zD@21hEN@CfB#UWcp;%|_u_E44-qhH%SSQ*PecgT0?PR8!4SI)8M2>zHP+g1;#$9Z} z2Hb(|jCRIOS{JDW6mOkAg!^!y&eMC;9u-kJs=w~1C#%Wo3w2s`)hXIGY@@_8&4XSm zVTIf!&m|g38FHiyu&(T^jLKPbrj>jHZxTUyO?vG1Vt}|TV&oKADLaU##7)ss3Yjk3 zi(JuH7Re=IrpWI07rR71 z`5QTpax-K|E)v_tNq&p}QjV2Zcnn3oTI>~9#1Vd#=ZWVYk4SKFF*NyIBcLT1&_WCh>1{$FXE3i5C6zqWK@C?48UR8tW zZn~=!m862I2n%tdny5D5T0DVAv4(K-rhZNP<78Y@LMz`DY1%o7FC?zuyZL)ojpdOY zI_VLS<;eH+#BgET$ zHSfrC__DyC0!6J$T6@iS(;saa-Rf*|(g}wJsz8;xGhG+&;ybETO@$Juz%m@A3e^tS z3V){@k}2+gz}FB~Y3ePUjk%bOy;LvN9aHcW9>d#s3uma8)y0_WFpxxKJE z<`7o5z(&{uJ0YKty95@&K#I5x)%;ST&*K+3nsDPmgiCl4TcUvru^bQJK|G}PtCO*( zVh1OTO-KlK4b~@~P0V1!*g^jV|0(&Ctd$4l*1)kq7s77|;rL~%%z9Mxqo`}eQR|8| zOuQsMGEk@&V|z-)J~?Y%C}BhGs2 zH+S#{oaByktKeN&pej@kNP#@af!EYj)e>SMiF(!#coVxoC)iH?ml3}M>R~Zqp%D(j z)RpJ)`GF0A*9pB_#8GkCQdR|>Zzk2p6gHm~ z^Vxha;dKsM#$M#*d<>t(|445{JwL=RG0lEt@g%L~^H?1_!)~$Zfq8-U-gNJ~<~;L8 z)A^?Id$aF#Fxu05&{kJRE25)d7*y#>eZtx2bcXhDU45f`uE+IY4BbO3HOVb@Yj7nB z4B&0|n%jtnaSBX^4X_$adS7O#nac5?r`os4w?^)f*Mi~dnEB>>D1$E1=g7x^3Q|D~NI*Pe1 z_H}!^vC2Uoc%eJx*Zdx?aF@C^`tU4#0j~R#Ta4qd13UsBK`k`r9RdpysUJ^=7wLw} zz=0oO0QI>jt!3~wR6zyYgsU(T3gHHP0}G%M7Q=kF2fcHqYkAD`6Q~?1k;*V?C^e({K!ylCRUG+f0%*WcMFyI?|W` diff --git a/data/sound/jump17.wav b/data/sound/jump17.wav deleted file mode 100644 index 6706f0c57759b0ffd28bac82287b760423263e46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2450 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 C4D6f$ diff --git a/data/sound/jump19.wav b/data/sound/jump19.wav deleted file mode 100644 index fb6a9666e79b5b56ed78dc8f2437fa00cb8dbc90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 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 diff --git a/data/sound/jump20.wav b/data/sound/jump20.wav deleted file mode 100644 index 4f4f8dadedcc6887005c4a0475afb697a46af3fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2274 zcmX|B2~<=^7X96Tg2>ucuYNb;62-yHjDkkRxFFFW;I4!qThoAyOC)ZiGm+$Aj&Th! z2KVJS8l6dus1uEQoFEya2ctuX$|fr6MB{QaMs2&_tD0(N&ir@&ulMeM^{VRJ`)X2Z za&lv!VZ51?@p|#B`CY>e!>|}uqwIus9$F25BitC1Iyv2;!_;xf<5MRmr-y2PjB7!0 z|AgKH2lS4Qi!+K`^IdCol}weXvf6Bl%2B>IM@QMp+2-f!C|lcFRna}tAEzf;a%!wtzqxJszB)dvux<3M<=ewljg_m_YOXQI*zC8< zuWxW-uob$&!cN;d<=fx4*RZ=RUA!%J+H345;W9LV2kJ~TLqv?Qi(z82IoE6k1v%m! z(IC8{9-c#`s1b8Tg|LV&;;3jAUByr_TD&C|i%*4Byd)NhjlvM!ML!q^g|;%AH8?yt zPoFT;J!XI)GHmYfF6N))_H~Z`MPsJ$_$H((#)385+5b+Ja%1@as zW(VjAKSPiRGvmx^-pWsl>jEKKr4+Y@{|c(J9- zlH_^SQ{c_>W?Ql>$JH@ag43~1pSN0ls}9jV8X-r@3bjT(p+~e#E|Kr51?mCaBSU%R zGxxZB1}a0phy-{2^}%=g*;X^RUP9&*Hb!kXbp^^oU<=Od%s*sXS| zSnPqha*8ZdW$G2`O}%7K=}@3n(o&kI&r&Zh$&+-H&d4h1lzH+g{X$I|4V7UsU(eel z*J@_lX_j}&L^(|QYQ?G^>Y0It8Q3MT$hO$FtkZ!`C613Adn3<9K4W2AI0ica`ok!e z&HirIo0ae#9Ap>RAT!70&}w=;=%jDm6-t3wQ>% z;5rO5!i)!a50mIs`a#vIby$H}GF>*y>+*Blj?pSgou*Ut0WGEn@_`&keW^rFlfRd- zatm#xLfxwejDtpI`-1kHBlbrev^Uu2IMz5)SU!tq6Ihx#&D;&uaFZ!k3-{p`_=^!d zpT7ee;4kns^yL%ydd-{z2E%)ND?h54+{_Pi4>!RD??D;g#4}+bT;dP;d48Aw21Wtn zzvHboY1AJlZt7aOp|>np6cmGdQQL6XiA|VsmOP>&GZQ=^3sR2jPf>TlilJdVx_FrW-t<_ITW0*kd?D5@Dvgt1A=)Bp9w4AHn&0?AIFm+8$RJj zcqw1a6CevlaF=HBzV2M)DSRpqf*2^_tN1p4ieJ&^^{^=3izTrxVew%P0-gqZ@2&DW z-5Kud)JW&mMHPX;*d3#BkF1nEG_ON&kmfE!hEoSRi`6(%4wnu1BTlD6xpFY zYo1?*WSGU4vnQOxSYFIqn48_<{$OW)+3iS-92Jrga?^U-I@>eNlkHA-XUMT~gW9CJ zdF|dr?2nV=BzXi6=x&Y13sghFWTnwK620W1(|8QeX-%KkcoAmeH2MRLq9odm8*npi zr0?()_MmPwk;YRa*5M_pqZ)Zm&hVS%x4h$)jde-pb;){w6>9)7Y`-mP>mEQAI%*8u&hbCbvMpC$DqJ$E07;e+* ztH$H_4StQQwf>6GiB3J&i@)F@+>d{v1+)?uqff7H{1q?aSq;1@IOshnk4`L diff --git a/data/sound/jump21.wav b/data/sound/jump21.wav deleted file mode 100644 index 5437264dacbc1df3cec24a08e61599e5b2147126..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2238 zcmXX{3s_Xg6~4O*@)p>=bLL)leND6+LELB#q8q1Wd zRi0A0UOlDiU0;STx<;;3W3iG_l~evK=BwSg`q`8EdASiSP%w!$XV~!_Pbi_n@A)@kz!<#(&@mG;@EW znOlucybpI61B^Ug!c%w-cXKcX@;CWr{!d=XPw+u}JpVgy;Qs@iA7wY#%}96T!$1sd zqN~*1>snj*HBjw z@5|5V&3dC@G0TmA7){I%F7U@Z!N@k|Lj~;QCzZ7DQrHKd^E#f%XYzV@1U0;oKLH1K z@nO7xZ{ZEl3e)&f{wp zjip}L6|c&x@?{w>SK)G;E9XcqnS6wIv07Hk1GJBp&_XJdE9F}%KTw89r!?fpG>?YJ zq4KbbU!aQ=p)l^CN_trik)YYN2HW?xwopr0k+Ih}*Tvl>pMSzD><8_s#&o0243DbP zPwD%h9`Zqyh#Yz0f;+59lS#EaM$>?-#vy!W6RB*0~5Gl&I^cjIx2 z%Sdl-6TD$eJ^=8PEkOuaERXM+NRwxX`j@^!0xB}l84~=%#8QNI5;%@=WG95%oq@F?Dz7%>l+{P(aBUWLhU3oJZbVg5pKIUFWJIP1?0dyM^1 z(6OKea)F%hp5dM-#)9-n9QwC+qH{}>>nl(0fcyOaG^ij_D zoSDX4qs+0>F#@JQu2EtvX65VzyUqT}kMM^q2p+IV7|2KQ8g_~Gf!E+`Xo3x_mK7@` zW8ecgr})|mb#Pam_ZS!rzWw+wd&J&>0=UH5m>=uGg6%!+GlS*@-M~id($TqNg2)hg z)(@@oFdx@=mV12X^ENfpG;g-ISus*gyT~TI-oCPz^ivET6<>*0)ESMzeprbWc!3(| zj%XHnltYAWOjS}v+h`I_!2T4iDqNz8+GMSF;I9Mk+ii{kt_iLdGdSu>eWI`^)=%e%o-pVW4zu0m8hF+#R%)j-!`h6A(msM}trXSZ2z(uHK zSJ-%#%eKHV=)s0CCk%#DYQHAvxq7PoU3+wJTyUrsq*>fgo)#-?S=u-)nlESf=Q#7Qv+XJZz=F$4QU2cDm)w4$Z30A2N^P{K5vrMfml}1sZ@E5P) z5WIxn<6<#e{0XPw4&081#2!(JTQLoju}L(F6IhEVo`^&osXEs}{84ec5kJE|3h!7< z$2fYCteQox7d=%tZ6u$d4mIAE1Yr(dG}j)H5CLJ2t6~vxIG8dmJYn z{dpR1)5BPbK2^U6?U1bhPWR!6Rycd>BXqC2ukkFC?bT1~$fBT3|5AUC6|iY+8B5dO z)(<+)JMzO8hjCk1ThY@+PoM8#9aZvg@`1b~uemR{{e;ImQ~e`OdyjeNduMw6q@TR) zZS+1bx`{eEN-Mnu-Xt7>4T{l?-coNTve03%UwkO0i$=VPF`|zckD1sLyWku#LzG}K zmWdT248w5{_Qwrky_kSmcvjR35?1BuinZdfcm?C|nz*PuLi9u@Hi&u=t@i4%cqCfI NebEnl;VJR8_&+8jg24a) diff --git a/data/sound/jump22.wav b/data/sound/jump22.wav deleted file mode 100644 index 5b0c89444b98c63c37e616440f5985dc9366d730..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2274 zcmXw330PIv5xyWn&=7gNGjrYpG$v|l6ciFcWO1zs5m$_&RuT1cjWsTTf?J|CBpPds zG*Y$hu@R%irA^{e5Dg%rf}o-h6t$_=C6z>ZzI*1}%(Lw`-@P;EKmW|Rvz$9RIWh6N zpJ9v}Fm~{ad5b#+8iwIzcpL8@XXBB#;bR0EDaom0f_a%dJaI&FYT}re*iOmFoDmh% zqjz+V$cPAIddA|6JdP4=MLm}oE86O9#jr$KaaJGeP1dozivFJ@@G6?oc$VH)FJ}B- zqIm6Ldi-M8_Task6=x;z+k^Mvw`b22H=eowT_>=PW;B+uc(y&~^?mN);lw@n@B3WG za@2T^_8V)0b;G)Cb@A@*UF>(xucsI(=C|L}zE{Y&kbU-I`*tV-zmQ*r*kz<_2jQ^I zS?pXcx6AEt670?>=L2jb`{NWWbX;(Z#YNavCdyYFgB+c(Kc15hUx z=mw23(u_nsQ2&h%QfK2eql@mS7wUPs%&M@0HENp`WWCIirc-q<&b?fp)`cuKE5JI$ zx?W$^F8x#=)CY94ex#dpqdu?C=})Y+R!^@;uWH{0-v@zKV29wr!GlAlh0KMu;0v$7 z6NhkS%dPTTxCAHVE%}MuFD1T-IdY2(mqTSI9E9uT0l5{AV?KV3b7Zbe!kH*!4|yBC zWj6i^d&(5K2sdIQy0I32#+A4eo6#oM;9gvUTQCBWVP4>>z;Ap@d|R8Q`)yZ>Yqz!C z8tOgVJ3@6+qt#HA;MLEoiYh2aWveVB)3`#HDTR_L+~{I_L?2O%j?kZ58?1pefL^c+ zt4x>Z9kh)mSmP`r7tPW$wW;0uJe84QS$c#Xrjzs#on$3hwHH8XZjQL8~T=NQiXcI?yqC@0P08Qb(vPA=r9#f8TWGoeMs@V zH&sv3dub=->Rf$`8cAroo~Yl}g;_zXf*fr-v>oA<=JnWh z(^c)RblZ&}<1&9;tyyi3r%}Weu=c4Psta|b`})2vR$r@9IztQi9*}yXy6JAZhAJtQ zhEcc<*Lm~@`YRpaOq=Ob`j{H%8eQTU+Dx1HPBqdIzDu=qk*am2F7PV!y5s-A{|MB= zXQ9VJn`K+aEZb@ufdi*IbDf<;KT#%bh|!Kkj-Nz3cqW2ik1UnPM2*OSd}u4X%S^FW zjKSYw6b{2LM5#E9H!&7Q!S7)&Ou=ld7th21OvhZ<2_s-0gkcii5=xM8!YSKTTTYvg z+k9qhFlM?Yxk}w9+(p(&D}y`qt~u2dWT(6Oj_#^n=1iZc6*@fa(cn-p-8?B+0ltu4R0^^%0k8jTqT1uG|r+e$k#$+S3 zb?4TZwsp3%&U?;g2RMIipJ<;YR*C(xT;{+=$P^pIUM#|+T%(iXikOI5I1+vfF0Myc zp7;LVMa0iA#2E4)99)e2nhmNoccEdPW0G(kVEc4V2y1)|=2t(|X z?X>}S1E#c^)@r1yzw4Wpf|j|~94pcYGi+`@cez<&-nN>oZDziC*xYZvW_7me%!}p{ zm8o{_#vjNshh6XLR{4Ek5ltC+yk>&7;slXxin;W##6oER;_ zU??C);_G6FSOHtO)AM1yC=mH@6z*~@{w-dBRK~7|9|iD@X%D@jPCOAEA%<(_fO^r) zQxp!X#V#?={=R)kyYzP5eItCE%q!;cmLn~j)OwX|Wm$RVdNalBZ$9NY-lMjuZRSRE zF3qN+>PyvPJ~lt(zP_hsb0xA=I{z<16si}gH8rZMDqW3N;q*GqSF_Y5bxz$>^=dii z?@eB`Nqwp+)OV^{RjJ)7U)@$Wc#3wZ^QxSgW$LghV0MlAyDDU!2Ro(yp-wQrRGn7G z)mhdRs)(5-Y@cDfn2|H=U#c$fQ^r1*c;_^GRWn+_mM2avV;g3f z75<`Aymys7N_ekI)jdD4gt0nxkvX-@uH&bQed?KC#V2|6WwtIeqmIA1hGTxuF`Cph F^$R>Vvz`C| diff --git a/data/sound/jump23.wav b/data/sound/jump23.wav deleted file mode 100644 index b79f2273b3174eb0a5ec568efe7e29fd0b719d66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2274 zcmXX`3wTXe7Cw1M(nuo7*=z4}Z|?X^I#n5u;wwdqc%_Vx#|`mrg9_>qGl|z29gon| zE0pp{sd}{(UlW5WCgf8@Jd@U|2qofKgytsq?6vmn8*|Th_TKB?YpuK2zyEbo`z0h? z3o(rJ9)tUgo1EP&(l87^!{7M#A-(wB-v~4!jl_QLG^aNE4NOSt=T1nA(CfsE>Ek+d zYV%IVHtpKBHO6LSXROv)`m03MU;Rxb>$#sApi=cJSq;>yBsEC6^*B(!0~+jCc(O)Q z8t_!@ouc=B9zMk9=krO{me2OBQ*@S;20U4Nzsl=YX$?728^%|WX&Up{X$|pdI?DH^ zXl$@b*YiLk5eQ&Mg-}6o4n6O2RwT=J84~nZ| zrdTU(aYLLDPlQW!6Rkvlv0fY!H9T7UL#z_L#b^;G;=~+LAPmt|^bsF5U{yR&OyNuT zmFSx2;?T0ti*$}eU6Ztwp& zHfrb@UBjywZ*(=@ruI}!KhjB6rot(h#;Xaci3(R^X)JA28`Nx?L5d93SM^j`ltpXR zdUZjaRUUt@|H{zKp+ng;_O@%7E8kJ%n8(($B%Z|s9nBrR#8|NtPC_>;!^#pX#2p}r zwGyo3{05)Mm-GK>4kqwC9;9pREYidRzMVJM6;^WMCH%Io@^x{FSMxIdkbAfgh5Q`9 z%d5G4-a&&YF)*kHc~<7rRBRwuf8)vSMqy}^5O4*)+bE{Qd;4^Hz(TPGYJplM^W}al#9peKT8{;o ztvTQd)Mng>53vgG>+|R1Qk+hIr@=IYO0gK%(K@oR9$RZRhEh5ytizEslA4mx3TaEd zsXN7zi`yo~~T&;}?;Ss(0Xs(z8Hi{#n0QSOpcml~{if};}DBwTxxx9dnfE-Y~nb@E?`4jKR zSMa@j66C^H{3tJmYcLX~!xgjE%n1KDJTcH6ILkZHn_WM-zN>myomM}oDRPorEtg4O zU(d%`m?sy?#wt_|$7GDxPbrm94?W++>)3-jksICElpJ&yZ{ZruM~fI8!UK37PoW0|HjEs%E9rPgRnYYRt?6GT6-`{6`pZOiPOYH03 zaxduq&%oi>-fm+L(O-lz5$ zhrKjMG5Y?mXy1EyALnQ#wbFPW>P2fPpIQgJ6Oh?Br?F3uZDP`5a``6iiEd(^hI_C= z6pGiN85FYftgT299Uu|vnG;U(yS$9uW%FT!R(?BP$!t~)0el(kfR^w+oYApKy26RD z7`}u9&=AJjZ;lN;n4 zn!h5sL%xtt8n7QUrxr3Skw@fH`9OQs$WyXdhUh#MvQ$2kk2LZ`{w&W(Ka_etD{D3K zySyu}%1g2lqE_8SDdkHYeMdi)+OJMtlb5B^*{bC&`B0y+PVe8=5do;=eU1I0Gr!dT Ncwa|&b;idU`ya6-trh?P diff --git a/data/sound/jump3.wav b/data/sound/jump3.wav deleted file mode 100644 index 9ad8648eb3fdc3575c5a97f87400369ca2c744e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2450 zcmX9<30PD|5`HrS0y;9|yguH{aC#tWR9KG?jYd2`0;?Dmyz}WQ`ssqkD|p0s!~+#& zL5;T}npMB`O5(M6#49XDO}veoxT`TCVewqhnOEJtHTb=+yQ}N$SM_)G2WcrO%fmD+ zJ2|UQPVV#=r>1EZ&8p2WN8*W93(}lgM%utZ9^9t&OX;6BFlA6U(ix*?=5$JG_jc!Y zi3thX*wNER_eL)s@FyhyomFyuwmuhBSrkr#>ju{cNK zENU{8iU^(S+jb*=Bj1ApJ-fLpiK$_^XVY!W?sTpOimP_T^madl0B0;IM_Pth;%#kg74{$PF5Zrh_ZE8H?j(1KzE|(Wv-n8&Tz4rwMbEGY zOfw>lR9%BCL3pJbWXF50TrYLDC@ zYsE9sOLbSRWeYi7PL-j`suE>_JfX@}cWYN`<1lyFa59-hdsDpG?tFJL8A2-PuQbZt z#Z6czR!JXGYIHC%Ssv@ghOo(eHSfgwv5#003*s@n4eQOmWLMcacAve)`XW_>l^D<7 zrP(yyHPUq}>|xjhHBJrm_3ZD~lu-R2-0dqNQvpPstRmttEC^#P{>Y zG>$%}4OuvE%MX$Ya)Ui*$LKXWgyfO?u3A@6Sa{fIIZSqa)%I1MImWzYy<=@7;zX{0 ztbe0guZrX{x!qiEX2}8a8+lT`GM|}W$WoahQ)N2zfq1;7tx-Qov=!CzsXPE*z!O;| z*K3=!F~J`O-*&!qt}x1sJWsL5Mk6S=TzXR@*(hbF*f{bD*~*TyscbdtL5I+%)PdQb z&6?33NQbdjtQT|91e%4o+DMPkadaUK;3}7VMs~YSx*FNJJ=N03a=~}PH`h1S_nBIt zhN(;yV@8^(qPsXEzm#h+$2IT(GGv;x3O_hRu*i~`@*&)Z#bRFleZCCmp$_l$OfgwZ z6_Z4fDpWDHXxn%8yY_gV%DZ|-da9_E-F7{5{eal*$p6f3B$|Y>Shf|hu#bF8{-72X z%$l)Zh>zT*wR96bhJV`uyGt0$#FO`@6X||>nI0#X$U?+lO8DUL9zn@LH~bg{Q+AR0YKFQHTp9ek104H}?~TRo?e0l>f&NeZl0Jv8+JU5!b}WtE z$Ft5RCFCUyXR~MtT}}3q7l@Y{5=tGkHN8OpO%IdHB%c=Hz773Rf1)QgNpF%7Iw15I z9Dw0<{pzM5Znj&>ER$diZ1Jt})yZmEAu7a5|0n(?vZ35AHj9pCD>Fg1mxc%zKbbep zzOo16Cm9aGZm1TIg*0o;a&bhAm7`>drP$)MN7$FLGWK7uGhzky@NUjbC*g^_jGy9r zU8h~|U`8!GnqSka^sD4|#8Elhqo34U(cZKH)}=t-s)u4do|7=@CW)jC>%-3Kcl2HQ zDLu}Sh0EfwT=AXuH8-Qpczk;ZI3d&oe}?QW=fVugG<%!V zWUlm?PtA_d8e*g&hnX4XK#?w@g&Y6rx_JV7z8&BC+aV7^YFsw`j`7kMYUCT;T>V{} z^sn?1eu$@$56SvQjJ%=U;vOD$XD4FF@R%f};@ckMMWHH|kG_h4;4{szln4r&yjULjh| bL%+rKdd0Xe!59JG8<1Lzvh^t2f>Hht5vIOJ diff --git a/data/sound/jump4.wav b/data/sound/jump4.wav deleted file mode 100644 index 6f938dfe47a58340f0d539e1bfcf5463cdcdb14c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2238 zcmXX{30M_J5}wB`*YmyU>Us0f1f$9B=PKZV#;93iJQfj=BY;YbW)(#tDzaWNUK_=8 z*SJQaL}gtyMk6s^f#4Zk5xj#&K{@2mXm&9HMc$k0o-NFN_4QPBRdr2O&EGZgQ6oki z_fwSQw~~gZWoCzVR20Rccqq$?Noev=yp)d0=%|E5CvBs~jEId&7?BuE^61I)(js3E z>)$V|S44y|Wpei9*%alTtd!OAu56H1#H(eEte|J5yhqf|D`{U#aurGKtCqBP<&Q6T z)eBp-tfx~|(oZn*A(z!;` zG|-7gTJXcneGz}fcU-Zq(`K=GK>1Qh6l26rkt;Tt8_fdwl}r&yVuksUxk4_L--}bC z*eo>LM61Y?o8>@rkat1_69J<@^o5%)@vT|AQ8zW%5-#i*Mpw>#g}}wqrGFi%Z#(eP1jXdkt~qiE#a1*unw#67XD&BF$mf9kY`1)SSNDCAlXlD5t~G%s1S{!nvl~XuFLCktVg_u)j!1l4r^vT zLgGS_slTh#e6I>VnVr>XafIK)3UfN4q3k!lsp1?T|=Ls+e;`nsF z9ZtY^a2raX77nv(?5VAT{gVG3|K3U;rLOIE+XHun`?7i2tdLjaaO020a62m(VQ zLbmX)`4}}*T>u;4CoRCCK{$NMzGjQH&ozKB=n2tqhF9=L!cqa0K{EvL?l1x_LIWIv zD=-db!5Y{{d0%CdY_n~Ozs>)M_)_Gy=CrOea*X#Z<18hV$sX5du4}SXK9-MUhI^uW zp3Ej>za%q^Nk*RBCf^guViKm{OqnLj@iH3t3`3<;-oP@vBrnJ+j~WmE00;a%(23yGn z@G;y9J)nhkfFqRu=VTw%F}dSFzma}9xEPnVWwnJM!&T;T(?(c5;@<0CA(zPUB0)?u z-Zi3SwEP0|aU*_=Wi&hX;8yG_B1Avx^v`sMyNOUSNJNU+Vy5^}mdlHtmpxAemIO}M zaJ{~`unXq$4g87f$L_*&SPWa>T{e%EKs{V%KU3#* zNQZTBgFR%Op+B5pcUYX7rp8&PTg!cJ`9xxGY%(GcK0adJu%7K^ z-C+n^p&Ih3?s{gj7|Oe=HQf5pyV<+Iwab;%I;_=?-nl`^QLKiKamsbfHO-uAPQ+v! z><)Jym4{?7`e3RNZ@ek{%QEA8BLSmvhuAFk8@r8qti&#&lL*7#VWipH-0!*Hvuki< zFzTJ12lNvCj=kBw&sJ=U(PnD7{3xGqTW5>mX?!sKhu*f2v&Zsu-b7d!tj4PXH2w;E zgD8%D1Y4n14PxurzgR9SU@bIPTZ4RqpLjNVu6HeS&1sw5b_=g!sXQXY93({UErMvy!gGilAhNbE@- z+c6xw;X=%&Z?X_y!yVjkv_*GPIx7Otl6|37wwm=yp3 diff --git a/data/sound/jump5.wav b/data/sound/jump5.wav deleted file mode 100644 index 81fd591e4022e0b2ba3ea979719072ad17d8b539..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2310 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 diff --git a/data/sound/jump7.wav b/data/sound/jump7.wav deleted file mode 100644 index fb703f27812cae818bf7ef0131aa3c651a9540bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2206 zcmX9;3sh7`674rI%m5<8d$0SwH-oE0<0q0RprVqJ(TFqiy1KVl}qsa_%LH|i#L3WTn z+9*xd2kAPF!huRJrN;lNza6a5%VT)jpcQg_a((8o>1?Js)ohlUr8qv4ucTS@1^OM` zWk0YJa0-^8C8(SoXX{xG>#X8NVJ+i}`E#j5lKpf)i`-qF8k!q=&h@|*g(u+#<*u^c zdC0j+->u(Neo-bH>y4*cpdO6h#oy__=`To#7D|Q^MUT?U$v5N-xlN904ccjZ6-b=?@8}=REn0OW$1vp+nkKjQDoH0{`JS1HW==t{z65k*Subd+}*pY1}Z@;7_nG2_sANV*Mzt$F0Oi zvubZ^ACmc^ez!;|sU+3pJJO#dlQMFaEL02B0gh3Q3ASlAUnH1F0vf|1wSPL8YU5>0k_~ha)3yrJ9&hyWTMEqUA199xtn}D z;6cDdKAtCgMtLrowdM?zf!2xY%r-O3Ms|&rux%`rCeQ-5nIR#4p&O*KDXa~epcqOZ zhDEcRa1Bg&2{pWiQwy~m3#<+tL{dqi^RP2PTc#x`GnMzr9AeXZ>G#yv>W|oqZCaRC zBskxWC6YHz-{T^sOj#P77u;ffWUV%<%-8N;+*2SG zcB4Y@HCiF!-tNFwPlw zj2r3`b%2tfSVisp#5}yH+)?_FIP!P$FEU+Sr3RC5@)%o4o%)m7f;rB``*2s>5AVd4 zI7&@cnL`PACtyeb;UPTBJ>UJp+veTEH}iDCh&$eE-f@r!73>H*W*#($!%(n`en-%7 zx(7<3NYwW%t)^RrjukQy5(Kw0d9BYSpYvTVcZt`QYW+|OHvoBtMJFzE|^lNmZ=|${x8PG_`dpwx*V5cgq?ValCP`{E(uPyrdp4C z4tj!KLq{E)hajn|^n>?5-XiZhZxZby=xTx6XgYvir03~# z_!S1x-n0dpVKPcX>#Uos*>Z{8mEH?PLemt`{cn!nqjI2o-Aj|ZjIMF za#6WYD9IEvGe_O6BH|*Q`mV@xCq98=m2@S~vBS|}lk9EY2i`Ls6&+uj)n+q#h>B?e zZE`odi+L#@4a4B6r^$1V{g>s_9J^&|NJ diff --git a/data/sound/jump8.wav b/data/sound/jump8.wav deleted file mode 100644 index dcec323ea7c7662db591e1e3f8f0605ddfc958cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 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 diff --git a/data/sound/jump9.wav b/data/sound/jump9.wav deleted file mode 100644 index be3119f3b78d6197eddd8828bfb3b667e8804ee5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2414 zcmXX{2~?Cv67D$|7+{c@zmI?B2L+?z9bFI5-58CEK@rdO*k}}Si6${B9t2Ur6McyX z8cjB$i5d|P6eT86@Y+?Q#w%e>%zBZBXFTG8IL_bIy*-%MuU~&%U0+r8QPqP}l9Mx? z2o3Kstas+5>2c8rAq%pi{0apgT9F+^qtuikLw#zRl9oImWk~YSD1}qgXJ&RvYMa=( zZToiZ(D?M}>2b=+PPt8PS8bbWJ5<}LdJu1y#j2Oq<85+_EU8~9sh7Rf3$jX83(A80 zQpMb&`YwfDTG^>^(ArK}rckj$Wq;0hD4jh@w*622UG*Bf>bbk*?t05XJ3)4-{92Yv z19{Og%PC8v&}N|(?w{R@V@hLEW2ePVCLfb^xExpe!VJGoy_@h69LKt|@7-72d+e2V zD%@hTxxutchjiPhZ4In}J5UXOu_jvUpcZb6YJn|=B~Ez76Zu?*qX_h!*e6D#F=(;O zmuFEGS{Sk@BqXX))NEgo&(rX44O_B)?0{CK_4K~uo#Ok%XD3a_33ih`@nT;E`IXc% zO@E|&yy3JpeN7*!hv+Tz_H+=9VO`l{cbKQAbC9z$>V)RJnEIlZ=q(mn7g!5Lp|}oL z;3s)rK9)~pn&=}M%Q)E|^+WL@R#eDJc}LdB6prX6kD$!)ElxM?4iQ{)EDXH^dcS0@>mtCW$S1KO<>84 z;r94Y5?LfoZx_+>RlGdrE(F>fet9~{#zHr+Q%8{`V}vpMuLdYwpe z0|O3q`CNx=|F)eDR0j43$^*?TEiC)gc@*=_e4{85Tjf@H6b?gs(MBv)vHSv6@Risk z(qyWvf$Pvxwvt$SWM|Y7jdo-@>Ka5ury7%uEiva~hT_S1hjvW+m-mR*rzhzxa4&p? zan?_NPyYu0h%4ByY$4miLWn^gF}I#YSJHHnOX>)vfhcE#GRFZ&2WSl?{vv;hOqSQt zH53mG;U6#%n#m^enz$@9aKSxsUpy8MM00orCdmo1pXe(t!9@t>V455x=h$=YAGtQU z8nJE+$8?DKfUcrd+HLJJv*@STEtX5xlJ)cu{hWQvE-CLTXc_IwMzS(;hMcB%=_Y!V zen&2nDB6lXbGtkzoK?<&%17LD?Rm8FzrwoAS`1qt*3``#^12)#hsf>bMzf1dlDhQC zB;JOvl!fx|Vz3AS!7s^6GEd})cGiy8P2qdPTWQ_33x?m2dc3!Eq}; zI-1NNKGubq)L>1>Yorq!!A8++CC?$<**G?ztRvINatnK&d4iy`(Q_IF&_E*pD=jWBYJ9I~1W)3UVj zsumy?&(7hSIEHqmx2T=9Aa9Ux+MKSS#neukksc~{e^(NNB$5m=n>gHY?vr6Zgtdcq zkXJXQ?i&9uzh${+`GFtgYXU0+@5}e(0+B0RW~g~W92EUTs@PV>^3T8LU}oi#0TY~&eSgHw#DMkzf>cdHydrs`J>70PE4SxL5$bed03kl#pC(w$7D ztLyK#H+h>R(@c5_&E#aP0M*$mHe z&zGcAae+Fo!Q_3i3!lal=>ob8Z^i5Jw>Z@^#&g#h za85=OQM!Mae_3Erpe1UGM!{%ER&}gI<-i~6XNuvJHwFWKgUis1cjt>?F06oMFo#d& z*OV*^Cc#|!p-gcMcN9dgjZQEI7@@vazI$%rPSl2JYxS@7edIj(pXZ4uPUUPYO`<6( zFK*EgHiCRWs Cache* { return Cache::cache; } // Constructor - Cache::Cache() - : loading_text_(Screen::get()->getText()) { + Cache::Cache(LoadingMode mode) + : loading_mode_(mode), loading_text_(Screen::get()->getText()) { load(); } @@ -59,18 +59,25 @@ namespace Resource { void Cache::load() { // Nota: el overlay de debug (RenderInfo) se inicializa después de esta carga, // por lo que updateZoomFactor() se llamará correctamente en RenderInfo::init(). - calculateTotal(); - Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); - std::cout << "\n** LOADING RESOURCES" << '\n'; - loadSounds(); - loadMusics(); - loadSurfaces(); - loadPalettes(); - loadTextFiles(); - loadAnimations(); - loadRooms(); - createText(); - std::cout << "\n** RESOURCES LOADED" << '\n'; + if (loading_mode_ == LoadingMode::EAGER) { + calculateTotal(); + Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); + std::cout << "\n** LOADING RESOURCES" << '\n'; + loadSounds(); + loadMusics(); + loadSurfaces(); + loadPalettes(); + loadTextFiles(); + loadAnimations(); + loadRooms(); + createText(); + std::cout << "\n** RESOURCES LOADED" << '\n'; + } else { + std::cout << "\n** LAZY LOADING MODE **\n"; + initLazyStubs(); + createText(); // Carga fuentes bajo demanda a través de los getters lazy + std::cout << "\n** RESOURCE STUBS READY" << '\n'; + } } // Recarga todos los recursos @@ -80,10 +87,13 @@ namespace Resource { } // Obtiene el sonido a partir de un nombre - auto Cache::getSound(const std::string& name) -> JA_Sound_t* { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getSound(const std::string& name) -> JA_Sound_t* { auto it = std::ranges::find_if(sounds_, [&name](const auto& s) -> bool { return s.name == name; }); if (it != sounds_.end()) { + if (loading_mode_ == LoadingMode::LAZY && it->sound == nullptr) { + loadSoundByName(name); + } return it->sound; } @@ -92,10 +102,13 @@ namespace Resource { } // Obtiene la música a partir de un nombre - auto Cache::getMusic(const std::string& name) -> JA_Music_t* { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getMusic(const std::string& name) -> JA_Music_t* { auto it = std::ranges::find_if(musics_, [&name](const auto& m) -> bool { return m.name == name; }); if (it != musics_.end()) { + if (loading_mode_ == LoadingMode::LAZY && it->music == nullptr) { + loadMusicByName(name); + } return it->music; } @@ -104,10 +117,13 @@ namespace Resource { } // Obtiene la surface a partir de un nombre - auto Cache::getSurface(const std::string& name) -> std::shared_ptr { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getSurface(const std::string& name) -> std::shared_ptr { auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) -> bool { return t.name == name; }); if (it != surfaces_.end()) { + if (loading_mode_ == LoadingMode::LAZY && it->surface == nullptr) { + loadSurfaceByName(name); + } return it->surface; } @@ -116,10 +132,13 @@ namespace Resource { } // Obtiene la paleta a partir de un nombre - auto Cache::getPalette(const std::string& name) -> Palette { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getPalette(const std::string& name) -> Palette { auto it = std::ranges::find_if(palettes_, [&name](const auto& t) -> bool { return t.name == name; }); if (it != palettes_.end()) { + if (loading_mode_ == LoadingMode::LAZY && !it->loaded) { + loadPaletteByName(name); + } return it->palette; } @@ -128,10 +147,13 @@ namespace Resource { } // Obtiene el fichero de texto a partir de un nombre - auto Cache::getTextFile(const std::string& name) -> std::shared_ptr { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getTextFile(const std::string& name) -> std::shared_ptr { auto it = std::ranges::find_if(text_files_, [&name](const auto& t) -> bool { return t.name == name; }); if (it != text_files_.end()) { + if (loading_mode_ == LoadingMode::LAZY && it->text_file == nullptr) { + loadTextFileByName(name); + } return it->text_file; } @@ -152,10 +174,13 @@ namespace Resource { } // Obtiene los datos de animación parseados a partir de un nombre - auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& { auto it = std::ranges::find_if(animations_, [&name](const auto& a) -> bool { return a.name == name; }); if (it != animations_.end()) { + if (loading_mode_ == LoadingMode::LAZY && it->yaml_data.empty()) { + loadAnimationByName(name); + } return *it; } @@ -164,10 +189,13 @@ namespace Resource { } // Obtiene la habitación a partir de un nombre - auto Cache::getRoom(const std::string& name) -> std::shared_ptr { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getRoom(const std::string& name) -> std::shared_ptr { auto it = std::ranges::find_if(rooms_, [&name](const auto& r) -> bool { return r.name == name; }); if (it != rooms_.end()) { + if (loading_mode_ == LoadingMode::LAZY && it->room == nullptr) { + loadRoomByName(name); + } return it->room; } @@ -205,6 +233,11 @@ namespace Resource { // Obtiene todas las habitaciones auto Cache::getRooms() -> std::vector& { + if (loading_mode_ == LoadingMode::LAZY) { + for (auto& r : rooms_) { + if (r.room == nullptr) { loadRoomByName(r.name); } + } + } return rooms_; } @@ -530,4 +563,144 @@ namespace Resource { checkEvents(); } + // --- Modo lazy: stubs y cargadores bajo demanda --------------------------- + + // Rellena los vectores de recursos con entradas name-only (sin contenido) + void Cache::initLazyStubs() { + sounds_.clear(); + musics_.clear(); + surfaces_.clear(); + palettes_.clear(); + text_files_.clear(); + animations_.clear(); + rooms_.clear(); + + for (const auto& l : List::get()->getListByType(List::Type::SOUND)) { + sounds_.emplace_back(SoundResource{.name = getFileName(l), .sound = nullptr}); + } + for (const auto& l : List::get()->getListByType(List::Type::MUSIC)) { + musics_.emplace_back(MusicResource{.name = getFileName(l), .music = nullptr}); + } + for (const auto& l : List::get()->getListByType(List::Type::BITMAP)) { + surfaces_.emplace_back(SurfaceResource{.name = getFileName(l), .surface = nullptr}); + } + for (const auto& l : List::get()->getListByType(List::Type::PALETTE)) { + palettes_.emplace_back(ResourcePalette{.name = getFileName(l)}); + } + for (const auto& l : List::get()->getListByType(List::Type::FONT)) { + text_files_.emplace_back(TextFileResource{.name = getFileName(l), .text_file = nullptr}); + } + for (const auto& l : List::get()->getListByType(List::Type::ANIMATION)) { + animations_.emplace_back(AnimationResource{.name = getFileName(l), .yaml_data = {}}); + } + for (const auto& l : List::get()->getListByType(List::Type::ROOM)) { + rooms_.emplace_back(RoomResource{.name = getFileName(l), .room = nullptr}); + } + } + + void Cache::loadSoundByName(const std::string& name) { + auto it = std::ranges::find_if(sounds_, [&name](const auto& s) { return s.name == name; }); + if (it == sounds_.end()) { return; } + auto path = List::get()->get(name); + try { + auto bytes = Helper::loadFile(path); + JA_Sound_t* sound = nullptr; + if (!bytes.empty()) { sound = JA_LoadSound(bytes.data(), static_cast(bytes.size())); } + if (sound == nullptr) { sound = JA_LoadSound(path.c_str()); } + if (sound == nullptr) { throw std::runtime_error("Failed to decode audio file"); } + it->sound = sound; + std::cout << "[lazy] Sound loaded: " << name << '\n'; + } catch (const std::exception& e) { + throwLoadError("SOUND", path, e); + } + } + + void Cache::loadMusicByName(const std::string& name) { + auto it = std::ranges::find_if(musics_, [&name](const auto& m) { return m.name == name; }); + if (it == musics_.end()) { return; } + auto path = List::get()->get(name); + try { + auto bytes = Helper::loadFile(path); + JA_Music_t* music = nullptr; + if (!bytes.empty()) { music = JA_LoadMusic(bytes.data(), static_cast(bytes.size())); } + if (music == nullptr) { music = JA_LoadMusic(path.c_str()); } + if (music == nullptr) { throw std::runtime_error("Failed to decode music file"); } + it->music = music; + std::cout << "[lazy] Music loaded: " << name << '\n'; + } catch (const std::exception& e) { + throwLoadError("MUSIC", path, e); + } + } + + void Cache::loadSurfaceByName(const std::string& name) { + auto it = std::ranges::find_if(surfaces_, [&name](const auto& s) { return s.name == name; }); + if (it == surfaces_.end()) { return; } + auto path = List::get()->get(name); + try { + it->surface = std::make_shared(path); + it->surface->setTransparentColor(0); + // Superficies con color transparente específico (replica el ajuste de loadSurfaces) + if (name == "loading_screen_color.gif" || name == "ending1.gif" || name == "ending2.gif" || + name == "ending3.gif" || name == "ending4.gif" || name == "ending5.gif") { + it->surface->setTransparentColor(); + } else if (name == "standard.gif") { + it->surface->setTransparentColor(16); + } + std::cout << "[lazy] Surface loaded: " << name << '\n'; + } catch (const std::exception& e) { + throwLoadError("BITMAP", path, e); + } + } + + void Cache::loadPaletteByName(const std::string& name) { + auto it = std::ranges::find_if(palettes_, [&name](const auto& p) { return p.name == name; }); + if (it == palettes_.end()) { return; } + auto path = List::get()->get(name); + try { + it->palette = readPalFile(path); + it->loaded = true; + std::cout << "[lazy] Palette loaded: " << name << '\n'; + } catch (const std::exception& e) { + throwLoadError("PALETTE", path, e); + } + } + + void Cache::loadTextFileByName(const std::string& name) { + auto it = std::ranges::find_if(text_files_, [&name](const auto& t) { return t.name == name; }); + if (it == text_files_.end()) { return; } + auto path = List::get()->get(name); + try { + it->text_file = Text::loadTextFile(path); + std::cout << "[lazy] TextFile loaded: " << name << '\n'; + } catch (const std::exception& e) { + throwLoadError("FONT", path, e); + } + } + + void Cache::loadAnimationByName(const std::string& name) { + auto it = std::ranges::find_if(animations_, [&name](const auto& a) { return a.name == name; }); + if (it == animations_.end()) { return; } + auto path = List::get()->get(name); + try { + auto bytes = Helper::loadFile(path); + if (bytes.empty()) { throw std::runtime_error("File is empty or could not be loaded"); } + it->yaml_data = bytes; + std::cout << "[lazy] Animation loaded: " << name << '\n'; + } catch (const std::exception& e) { + throwLoadError("ANIMATION", path, e); + } + } + + void Cache::loadRoomByName(const std::string& name) { + auto it = std::ranges::find_if(rooms_, [&name](const auto& r) { return r.name == name; }); + if (it == rooms_.end()) { return; } + auto path = List::get()->get(name); + try { + it->room = std::make_shared(Room::loadYAML(path)); + std::cout << "[lazy] Room loaded: " << name << '\n'; + } catch (const std::exception& e) { + throwLoadError("ROOM", path, e); + } + } + } // namespace Resource diff --git a/source/core/resources/resource_cache.hpp b/source/core/resources/resource_cache.hpp index d64f2e5..f8c1cfb 100644 --- a/source/core/resources/resource_cache.hpp +++ b/source/core/resources/resource_cache.hpp @@ -11,9 +11,14 @@ namespace Resource { class Cache { public: - static void init(); // Inicialización singleton - static void destroy(); // Destrucción singleton - static auto get() -> Cache*; // Acceso al singleton + enum class LoadingMode { + EAGER, // Carga todos los recursos en init() (comportamiento por defecto, producción) + LAZY // Sólo registra nombres; carga cada recurso la primera vez que se pide (desarrollo) + }; + + static void init(LoadingMode mode = LoadingMode::EAGER); // Inicialización singleton + static void destroy(); // Destrucción singleton + static auto get() -> Cache*; // Acceso al singleton auto getSound(const std::string& name) -> JA_Sound_t*; // Getters de recursos auto getMusic(const std::string& name) -> JA_Music_t*; @@ -57,6 +62,18 @@ namespace Resource { void loadRooms(); void createText(); + // Registro de stubs (modo lazy): sólo nombres, sin contenido + void initLazyStubs(); + + // Cargadores bajo demanda (modo lazy): cargan un recurso individual por nombre + void loadSoundByName(const std::string& name); + void loadMusicByName(const std::string& name); + void loadSurfaceByName(const std::string& name); + void loadPaletteByName(const std::string& name); + void loadTextFileByName(const std::string& name); + void loadAnimationByName(const std::string& name); + void loadRoomByName(const std::string& name); + // Métodos de limpieza void clear(); void clearSounds(); @@ -73,9 +90,11 @@ namespace Resource { [[noreturn]] static void throwLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e); // Constructor y destructor - Cache(); + explicit Cache(LoadingMode mode); ~Cache() = default; + LoadingMode loading_mode_ = LoadingMode::EAGER; + // Singleton instance static Cache* cache; diff --git a/source/core/resources/resource_types.hpp b/source/core/resources/resource_types.hpp index 58f8488..e9f4d53 100644 --- a/source/core/resources/resource_types.hpp +++ b/source/core/resources/resource_types.hpp @@ -33,8 +33,9 @@ struct SurfaceResource { // Estructura para almacenar objetos Palette y su nombre struct ResourcePalette { - std::string name; // Nombre de la surface - Palette palette{}; // Paleta + std::string name; // Nombre de la surface + Palette palette{}; // Paleta + bool loaded{false}; // Usado por el modo lazy para saber si ya se ha leído del disco }; // Estructura para almacenar ficheros TextFile y su nombre diff --git a/source/core/system/debug.cpp b/source/core/system/debug.cpp index 9d0b5fb..05b97ea 100644 --- a/source/core/system/debug.cpp +++ b/source/core/system/debug.cpp @@ -134,6 +134,7 @@ void Debug::loadFromFile() { spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y; spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP; initial_scene_ = SceneManager::Scene::GAME; + lazy_loading_ = false; std::ifstream file(debug_file_path_); if (!file.good()) { @@ -162,6 +163,9 @@ void Debug::loadFromFile() { if (yaml.contains("initial_scene")) { initial_scene_ = sceneFromString(yaml["initial_scene"].get_value()); } + if (yaml.contains("lazy_loading")) { + lazy_loading_ = yaml["lazy_loading"].get_value(); + } } catch (...) { // YAML inválido: resetear a defaults y sobreescribir spawn_settings_.room = Defaults::Game::Room::INITIAL; @@ -169,6 +173,7 @@ void Debug::loadFromFile() { spawn_settings_.spawn_y = Defaults::Game::Player::SPAWN_Y; spawn_settings_.flip = Defaults::Game::Player::SPAWN_FLIP; initial_scene_ = SceneManager::Scene::GAME; + lazy_loading_ = false; saveToFile(); } } @@ -184,6 +189,7 @@ void Debug::saveToFile() const { file << "spawn_y: " << (spawn_settings_.spawn_y / Tile::SIZE) << " # en tiles\n"; file << "spawn_flip: " << ((spawn_settings_.flip == Flip::RIGHT) ? "right" : "left") << "\n"; file << "initial_scene: " << sceneToString(initial_scene_) << "\n"; + file << "lazy_loading: " << (lazy_loading_ ? "true" : "false") << " # carga perezosa de recursos (dev)\n"; } #endif // _DEBUG \ No newline at end of file diff --git a/source/core/system/debug.hpp b/source/core/system/debug.hpp index 45a73e6..20be58a 100644 --- a/source/core/system/debug.hpp +++ b/source/core/system/debug.hpp @@ -47,6 +47,7 @@ class Debug { void setSpawnSettings(const SpawnSettings& s) { spawn_settings_ = s; } // Establece los valores de spawn [[nodiscard]] auto getInitialScene() const -> SceneManager::Scene { return initial_scene_; } // Obtiene la escena inicial de debug void setInitialScene(SceneManager::Scene s) { initial_scene_ = s; } // Establece la escena inicial de debug + [[nodiscard]] auto getLazyLoading() const -> bool { return lazy_loading_; } // Indica si el modo lazy de recursos está activo private: static Debug* debug; // [SINGLETON] Objeto privado @@ -64,6 +65,7 @@ class Debug { std::string debug_file_path_; // Ruta del archivo debug.yaml SpawnSettings spawn_settings_; // Configuración de spawn para debug SceneManager::Scene initial_scene_ = SceneManager::Scene::GAME; // Escena inicial en debug + bool lazy_loading_ = false; // Carga lazy de recursos (dev) }; #endif // _DEBUG \ No newline at end of file diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 66414f8..2d24f6c 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -160,8 +160,21 @@ Director::Director() { // Crea los objetos Screen::init(); +#ifdef _DEBUG + // En debug inicializamos Debug antes de Cache para leer el flag lazy_loading + Debug::init(); + Debug::get()->setDebugFile(Resource::List::get()->get("debug.yaml")); + Debug::get()->loadFromFile(); +#endif + // Initialize resources (works for both release and development) +#ifdef _DEBUG + Resource::Cache::init(Debug::get()->getLazyLoading() + ? Resource::Cache::LoadingMode::LAZY + : Resource::Cache::LoadingMode::EAGER); +#else Resource::Cache::init(); +#endif Notifier::init("", "8bithud"); RenderInfo::init(); Console::init("8bithud"); @@ -182,9 +195,6 @@ Director::Director() { Input::get()->applyGamepadBindingsFromOptions(); #ifdef _DEBUG - Debug::init(); - Debug::get()->setDebugFile(Resource::List::get()->get("debug.yaml")); - Debug::get()->loadFromFile(); SceneManager::current = Debug::get()->getInitialScene(); MapEditor::init(); #endif diff --git a/source/game/editor/map_editor.cpp b/source/game/editor/map_editor.cpp index 20d6015..5a35237 100644 --- a/source/game/editor/map_editor.cpp +++ b/source/game/editor/map_editor.cpp @@ -1131,6 +1131,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string& std::string val = toLower(value); if (property == "BGCOLOR") { + val = colorToString(stringToColor(val)); // Normaliza a nombre canónico (acepta nombres e índices) room_data_.bg_color = val; room_->setBgColor(val); autosave(); @@ -1138,6 +1139,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string& } if (property == "BORDER") { + val = colorToString(stringToColor(val)); room_data_.border_color = val; Screen::get()->setBorderColor(stringToColor(val)); autosave(); @@ -1145,6 +1147,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string& } if (property == "ITEMCOLOR1") { + val = colorToString(stringToColor(val)); room_data_.item_color1 = val; room_->setItemColors(room_data_.item_color1, room_data_.item_color2); autosave(); @@ -1152,6 +1155,7 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string& } if (property == "ITEMCOLOR2") { + val = colorToString(stringToColor(val)); room_data_.item_color2 = val; room_->setItemColors(room_data_.item_color1, room_data_.item_color2); autosave(); diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 1efa930..5350d90 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -76,11 +76,8 @@ void Player::move(float delta_time) { case State::ON_SLOPE: moveOnSlope(delta_time); break; - case State::JUMPING: - moveJumping(delta_time); - break; - case State::FALLING: - moveFalling(delta_time); + case State::ON_AIR: + moveOnAir(delta_time); break; } syncSpriteAndCollider(); // Actualiza la posición del sprite y las colisiones @@ -95,11 +92,8 @@ void Player::move(float delta_time) { case State::ON_SLOPE: Debug::get()->set("P.STATE", "ON_SLOPE"); break; - case State::JUMPING: - Debug::get()->set("P.STATE", "JUMPING"); - break; - case State::FALLING: - Debug::get()->set("P.STATE", "FALLING"); + case State::ON_AIR: + Debug::get()->set("P.STATE", "ON_AIR"); break; } #endif @@ -117,7 +111,8 @@ void Player::handleConveyorBelts() { void Player::handleShouldFall() { if (!isOnFloor() and (state_ == State::ON_GROUND || state_ == State::ON_SLOPE)) { - transitionToState(State::FALLING); + vy_ = 0.0F; + transitionToState(State::ON_AIR); } } @@ -128,37 +123,24 @@ void Player::transitionToState(State state) { switch (state) { case State::ON_GROUND: vy_ = 0; - handleDeathByFalling(); - resetSoundControllersOnLanding(); + if (previous_state_ == State::ON_AIR) { + Audio::get()->playSound(land_sound_, Audio::Group::GAME); + } current_slope_ = nullptr; break; case State::ON_SLOPE: vy_ = 0; - handleDeathByFalling(); - resetSoundControllersOnLanding(); + if (previous_state_ == State::ON_AIR) { + Audio::get()->playSound(land_sound_, Audio::Group::GAME); + } updateCurrentSlope(); if (current_slope_ == nullptr) { // Los pies no coinciden con ninguna rampa: tratar como suelo plano state_ = State::ON_GROUND; } break; - case State::JUMPING: - // Puede saltar desde ON_GROUND o ON_SLOPE - if (previous_state_ == State::ON_GROUND || previous_state_ == State::ON_SLOPE) { - vy_ = -MAX_VY; - last_grounded_position_ = y_; - updateVelocity(); - jump_sound_ctrl_.start(); - current_slope_ = nullptr; - } - break; - case State::FALLING: - fall_start_position_ = static_cast(y_); + case State::ON_AIR: last_grounded_position_ = static_cast(y_); - vy_ = MAX_VY; - vx_ = 0.0F; - jump_sound_ctrl_.reset(); - fall_sound_ctrl_.start(y_); current_slope_ = nullptr; break; } @@ -172,48 +154,48 @@ void Player::updateState(float delta_time) { case State::ON_SLOPE: updateOnSlope(delta_time); break; - case State::JUMPING: - updateJumping(delta_time); - break; - case State::FALLING: - updateFalling(delta_time); + case State::ON_AIR: + updateOnAir(delta_time); break; } } +// Inicia un salto desde ON_GROUND/ON_SLOPE: velocidad inicial hacia arriba + sonido + transición +void Player::startJump() { + vy_ = JUMP_VELOCITY; + last_grounded_position_ = y_; + Audio::get()->playSound(jump_sound_, Audio::Group::GAME); + transitionToState(State::ON_AIR); +} + // Actualización lógica del estado ON_GROUND void Player::updateOnGround(float delta_time) { (void)delta_time; // No usado en este método, pero se mantiene por consistencia handleConveyorBelts(); // Gestiona las cintas transportadoras - handleShouldFall(); // Verifica si debe caer (no tiene suelo) - // Verifica si el jugador quiere saltar - if (wanna_jump_) { transitionToState(State::JUMPING); } + // El salto tiene prioridad sobre la caída por falta de suelo + if (wanna_jump_) { + startJump(); + return; + } + handleShouldFall(); // Verifica si debe caer (no tiene suelo) } // Actualización lógica del estado ON_SLOPE void Player::updateOnSlope(float delta_time) { (void)delta_time; // No usado en este método, pero se mantiene por consistencia + if (wanna_jump_) { + startJump(); + return; + } handleShouldFall(); - // NOTA: No llamamos handleShouldFall() aquí porque moveOnSlope() ya maneja - // todas las condiciones de salida de la rampa (out of bounds, transición a superficie plana) - - // Verifica si el jugador quiere saltar - if (wanna_jump_) { transitionToState(State::JUMPING); } } -// Actualización lógica del estado JUMPING -void Player::updateJumping(float delta_time) { - auto_movement_ = false; // Desactiva el movimiento automático durante el salto - playJumpSound(delta_time); // Reproduce los sonidos de salto - handleJumpEnd(); // Verifica si el salto ha terminado (alcanzó la altura inicial) -} - -// Actualización lógica del estado FALLING -void Player::updateFalling(float delta_time) { - auto_movement_ = false; // Desactiva el movimiento automático durante la caída - playFallSound(delta_time); // Reproduce los sonidos de caída +// Actualización lógica del estado ON_AIR +void Player::updateOnAir(float delta_time) { + (void)delta_time; + auto_movement_ = false; // Desactiva el movimiento automático en el aire } // Movimiento físico del estado ON_GROUND @@ -256,7 +238,8 @@ void Player::moveOnSlope(float delta_time) { // Verificar rampa válida antes de comprobar velocidad: si no hay rampa siempre caer, // independientemente de si hay o no input (evita bloqueo con vx_=0 y slope null) if (current_slope_ == nullptr) { - transitionToState(State::FALLING); + vy_ = 0.0F; + transitionToState(State::ON_AIR); return; } @@ -320,7 +303,8 @@ void Player::moveOnSlope(float delta_time) { transitionToState(State::ON_GROUND); } else { // Sin soporte: empezar a caer - transitionToState(State::FALLING); + vy_ = 0.0F; + transitionToState(State::ON_AIR); } return; } @@ -332,69 +316,39 @@ void Player::moveOnSlope(float delta_time) { }*/ } -// Movimiento físico del estado JUMPING -void Player::moveJumping(float delta_time) { - // Movimiento horizontal +// Movimiento físico del estado ON_AIR +// El jugador puede moverse horizontalmente en el aire y la gravedad siempre actúa. +void Player::moveOnAir(float delta_time) { + // Movimiento horizontal libre según wanna_go_ (permite girar en el aire) + updateVelocity(); applyHorizontalMovement(delta_time); - // Movimiento vertical + // Gravedad applyGravity(delta_time); const float DISPLACEMENT_Y = vy_ * delta_time; - // Movimiento vertical hacia arriba + + // Subiendo: comprobar techo if (vy_ < 0.0F) { const SDL_FRect PROJECTION = getProjection(Direction::UP, DISPLACEMENT_Y); - - // Comprueba la colisión const int POS = room_->checkBottomSurfaces(PROJECTION); - - // Calcula la nueva posición if (POS == Collision::NONE) { - // Si no hay colisión y_ += DISPLACEMENT_Y; } else { - // Si hay colisión lo mueve hasta donde no colisiona -> FALLING + // Choque con techo: se pega por debajo y empieza a caer y_ = POS + 1; - transitionToState(State::FALLING); + vy_ = 0.0F; } + return; } - // Movimiento vertical hacia abajo - else if (vy_ > 0.0F) { - // Crea el rectangulo de proyección en el eje Y para ver si colisiona + + // Bajando: comprobar aterrizaje en superficies y rampas + if (vy_ > 0.0F) { const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT_Y); - - // JUMPING colisiona con rampas solo si vx_ == 0 - if (vx_ == 0.0F) { - handleLandingFromAir(DISPLACEMENT_Y, PROJECTION); - } else { - // Comprueba la colisión con las superficies y las cintas transportadoras (sin rampas) - // Extendemos 1px hacia arriba para detectar suelos traversados ligeramente al - // entrar horizontalmente (consecuencia del margen h=HEIGHT-1 en la proyección horizontal) - const SDL_FRect ADJ = {.x = PROJECTION.x, .y = PROJECTION.y - 1.0F, .w = PROJECTION.w, .h = PROJECTION.h + 1.0F}; - const float POS = std::max(room_->checkTopSurfaces(ADJ), room_->checkAutoSurfaces(ADJ)); - if (POS != Collision::NONE) { - // Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie - y_ = POS - HEIGHT; - transitionToState(State::ON_GROUND); - } else { - // Esta saltando con movimiento horizontal y no hay colisión con los muros - // Calcula la nueva posición (atraviesa rampas) - y_ += DISPLACEMENT_Y; - } - } + handleLandingFromAir(DISPLACEMENT_Y, PROJECTION); } } -// Movimiento físico del estado FALLING -void Player::moveFalling(float delta_time) { - // Crea el rectangulo de proyección en el eje Y para ver si colisiona - const float DISPLACEMENT = vy_ * delta_time; - const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT); - - // Comprueba aterrizaje en superficies y rampas - handleLandingFromAir(DISPLACEMENT, PROJECTION); -} - // Comprueba si está situado en alguno de los cuatro bordes de la habitación auto Player::handleBorders() -> Room::Border { if (x_ < PlayArea::LEFT) { @@ -410,10 +364,8 @@ auto Player::handleBorders() -> Room::Border { } if (y_ + HEIGHT > PlayArea::BOTTOM) { - // Si llega en estado terminal, muere y no cruza - const bool SHOULD_DIE = static_cast(y_) - last_grounded_position_ > MAX_FALLING_HEIGHT; - if (SHOULD_DIE) { markAsDead(); } - return is_alive_ ? Room::Border::BOTTOM : Room::Border::NONE; + // Restricción de muerte por altura de caída desactivada + return Room::Border::BOTTOM; } return Room::Border::NONE; @@ -454,9 +406,8 @@ void Player::switchBorders() { // Aplica gravedad al jugador void Player::applyGravity(float delta_time) { - // La gravedad solo se aplica cuando el jugador esta saltando - // Nunca mientras cae o esta de pie - if (state_ == State::JUMPING) { + // La gravedad solo se aplica cuando el jugador esta en el aire + if (state_ == State::ON_AIR) { vy_ += GRAVITY_FORCE * delta_time; vy_ = std::min(vy_, MAX_VY); } @@ -464,37 +415,13 @@ void Player::applyGravity(float delta_time) { // Establece la animación del jugador void Player::animate(float delta_time) { // NOLINT(readability-make-member-function-const) - if (vx_ != 0) { + if (state_ == State::ON_AIR) { + sprite_->setCurrentAnimation("jump"); + } else if (vx_ != 0) { + sprite_->setCurrentAnimation("default"); sprite_->update(delta_time); - } -} - -// Comprueba si ha finalizado el salto al alcanzar la altura de inicio -void Player::handleJumpEnd() { - // Si el jugador vuelve EXACTAMENTE a la altura inicial, debe CONTINUAR en JUMPING - // Solo cuando la SUPERA (desciende más allá) cambia a FALLING - if (state_ == State::JUMPING && vy_ > 0.0F && static_cast(y_) > last_grounded_position_) { - transitionToState(State::FALLING); - } -} - -// Calcula y reproduce el sonido de salto basado en tiempo transcurrido -void Player::playJumpSound(float delta_time) { // NOLINT(readability-convert-member-functions-to-static) - size_t sound_index; - if (jump_sound_ctrl_.shouldPlay(delta_time, sound_index)) { - if (sound_index < jumping_sound_.size()) { - Audio::get()->playSound(jumping_sound_[sound_index], Audio::Group::GAME); - } - } -} - -// Calcula y reproduce el sonido de caída basado en distancia vertical recorrida -void Player::playFallSound(float delta_time) { // NOLINT(readability-convert-member-functions-to-static) - size_t sound_index; - if (fall_sound_ctrl_.shouldPlay(delta_time, y_, sound_index)) { - if (sound_index < falling_sound_.size()) { - Audio::get()->playSound(falling_sound_[sound_index], Audio::Group::GAME); - } + } else { + sprite_->setCurrentAnimation("stand"); } } @@ -665,98 +592,10 @@ void Player::updateFeet() { .y = y_ + HEIGHT}; } -// Inicializa los sonidos de salto y caida +// Inicializa los sonidos de salto y aterrizaje void Player::initSounds() { // NOLINT(readability-convert-member-functions-to-static) - for (int i = 0; i < 24; ++i) { - std::string sound_file = "jump" + std::to_string(i + 1) + ".wav"; - jumping_sound_[i] = Resource::Cache::get()->getSound(sound_file); - - if (i >= 10) { // i+1 >= 11 - falling_sound_[i - 10] = Resource::Cache::get()->getSound(sound_file); - } - } -} - -// Implementación de JumpSoundController::start -void Player::JumpSoundController::start() { - current_index = 0; - elapsed_time = 0.0F; - active = true; -} - -// Implementación de JumpSoundController::reset -void Player::JumpSoundController::reset() { - active = false; - current_index = 0; - elapsed_time = 0.0F; -} - -// Implementación de JumpSoundController::shouldPlay -auto Player::JumpSoundController::shouldPlay(float delta_time, size_t& out_index) -> bool { - if (!active) { - return false; - } - - // Acumula el tiempo transcurrido durante el salto - elapsed_time += delta_time; - - // Calcula qué sonido debería estar sonando según el tiempo - size_t target_index = FIRST_SOUND + static_cast((elapsed_time / SECONDS_PER_SOUND)); - target_index = std::min(target_index, LAST_SOUND); - - // Reproduce si hemos avanzado a un nuevo sonido - if (target_index > current_index) { - current_index = target_index; - out_index = current_index; - return true; // NOLINT(readability-simplify-boolean-expr) - } - - return false; -} - -// Implementación de FallSoundController::start -void Player::FallSoundController::start(float start_y) { - current_index = 0; - distance_traveled = 0.0F; - last_y = start_y; - active = true; -} - -// Implementación de FallSoundController::reset -void Player::FallSoundController::reset() { - active = false; - current_index = 0; - distance_traveled = 0.0F; -} - -// Implementación de FallSoundController::shouldPlay -auto Player::FallSoundController::shouldPlay(float delta_time, float current_y, size_t& out_index) -> bool { - (void)delta_time; // No usado actualmente, pero recibido por consistencia - - if (!active) { - return false; - } - - // Acumula la distancia recorrida (solo hacia abajo) - if (current_y > last_y) { - distance_traveled += (current_y - last_y); - } - last_y = current_y; - - // Calcula qué sonido debería estar sonando según el intervalo - size_t target_index = FIRST_SOUND + static_cast((distance_traveled / PIXELS_PER_SOUND)); - - // El sonido a reproducir se limita a LAST_SOUND (13), pero el índice interno sigue creciendo - size_t sound_to_play = std::min(target_index, LAST_SOUND); - - // Reproduce si hemos avanzado a un nuevo índice (permite repetición de sonido 13) - if (target_index > current_index) { - current_index = target_index; // Guardamos el índice real (puede ser > LAST_SOUND) - out_index = sound_to_play; // Pero reproducimos LAST_SOUND cuando corresponde - return true; - } - - return false; + jump_sound_ = Resource::Cache::get()->getSound("jump.wav"); + land_sound_ = Resource::Cache::get()->getSound("land.wav"); } // Aplica los valores de spawn al jugador @@ -810,14 +649,6 @@ void Player::placeSprite() { sprite_->setPos(x_, y_); } -// Gestiona la muerta al ccaer desde muy alto -void Player::handleDeathByFalling() { - const int FALL_DISTANCE = static_cast(y_) - last_grounded_position_; - if (previous_state_ == State::FALLING && FALL_DISTANCE > MAX_FALLING_HEIGHT) { - markAsDead(); // Muere si cae más de 32 píxeles - } -} - // Calcula la velocidad en x void Player::updateVelocity() { if (auto_movement_) { @@ -900,12 +731,6 @@ auto Player::handleLandingFromAir(float displacement, const SDL_FRect& projectio return false; } -// Resetea los controladores de sonido al aterrizar -void Player::resetSoundControllersOnLanding() { - jump_sound_ctrl_.reset(); - fall_sound_ctrl_.reset(); -} - // Devuelve el rectangulo de proyeccion auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect { // NOLINT(readability-convert-member-functions-to-static) switch (direction) { diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index 7a6f95e..1ad4d6b 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -21,8 +21,7 @@ class Player { enum class State { ON_GROUND, // En suelo plano o conveyor belt ON_SLOPE, // En rampa/pendiente - JUMPING, - FALLING, + ON_AIR, // En el aire (saltando, cayendo o caminando al vacío) }; enum class Direction { @@ -34,10 +33,10 @@ class Player { }; // --- Constantes de física (públicas para permitir cálculos en structs) --- - static constexpr float HORIZONTAL_VELOCITY = 40.0F; // Velocidad horizontal en pixels/segundo (0.6 * 66.67fps) - static constexpr float MAX_VY = 80.0F; // Velocidad vertical máxima en pixels/segundo (1.2 * 66.67fps) - static constexpr float JUMP_VELOCITY = -80.0F; // Velocidad inicial del salto en pixels/segundo - static constexpr float GRAVITY_FORCE = 155.6F; // Fuerza de gravedad en pixels/segundo² (0.035 * 66.67²) + static constexpr float HORIZONTAL_VELOCITY = 60.0F; // Velocidad horizontal en pixels/segundo + static constexpr float MAX_VY = 160.0F; // Velocidad vertical máxima en pixels/segundo + static constexpr float JUMP_VELOCITY = -140.0F; // Velocidad inicial del salto en pixels/segundo + static constexpr float GRAVITY_FORCE = 360.0F; // Fuerza de gravedad en pixels/segundo² struct SpawnData { float x = 0; @@ -55,37 +54,6 @@ class Player { std::shared_ptr room = nullptr; }; - struct JumpSoundController { - // Duración del salto calculada automáticamente con física: t = 2 * v0 / g - static constexpr float JUMP_DURATION = (2.0F * MAX_VY) / GRAVITY_FORCE; - static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1) - static constexpr size_t LAST_SOUND = 17; // Último sonido a reproducir (índice 17) - static constexpr float SECONDS_PER_SOUND = JUMP_DURATION / (LAST_SOUND - FIRST_SOUND + 1); - - size_t current_index = 0; // Índice del sonido actual - float elapsed_time = 0.0F; // Tiempo transcurrido durante el salto - bool active = false; // Indica si el controlador está activo - - void start(); // Inicia el controlador - void reset(); // Resetea el controlador - auto shouldPlay(float delta_time, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido - }; - - struct FallSoundController { - static constexpr float PIXELS_PER_SOUND = 5.0F; // Intervalo de píxeles por sonido (configurable) - static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1) - static constexpr size_t LAST_SOUND = 13; // Último sonido a reproducir (índice 13) - - size_t current_index = 0; // Índice del sonido actual - float distance_traveled = 0.0F; // Distancia acumulada durante la caída - float last_y = 0.0F; // Última posición Y registrada - bool active = false; // Indica si el controlador está activo - - void start(float start_y); // Inicia el controlador - void reset(); // Resetea el controlador - auto shouldPlay(float delta_time, float current_y, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido - }; - // --- Constructor y Destructor --- explicit Player(const Data& player); ~Player() = default; @@ -155,12 +123,9 @@ class Player { int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo (hace doble función: tracking de caída + altura inicial del salto) // --- Variables de renderizado y sonido --- - Uint8 color_ = 0; // Color del jugador - std::array jumping_sound_{}; // Array con todos los sonidos del salto - std::array falling_sound_{}; // Array con todos los sonidos de la caída - JumpSoundController jump_sound_ctrl_; // Controlador de sonidos de salto - FallSoundController fall_sound_ctrl_; // Controlador de sonidos de caída - int fall_start_position_ = 0; // Posición Y al iniciar la caída + Uint8 color_ = 0; // Color del jugador + JA_Sound_t* jump_sound_ = nullptr; // Sonido al iniciar el salto + JA_Sound_t* land_sound_ = nullptr; // Sonido al aterrizar en el suelo void handleConveyorBelts(); void handleShouldFall(); @@ -169,14 +134,12 @@ class Player { // --- Métodos de actualización por estado --- void updateOnGround(float delta_time); // Actualización lógica estado ON_GROUND void updateOnSlope(float delta_time); // Actualización lógica estado ON_SLOPE - void updateJumping(float delta_time); // Actualización lógica estado JUMPING - void updateFalling(float delta_time); // Actualización lógica estado FALLING + void updateOnAir(float delta_time); // Actualización lógica estado ON_AIR // --- Métodos de movimiento por estado --- void moveOnGround(float delta_time); // Movimiento físico estado ON_GROUND void moveOnSlope(float delta_time); // Movimiento físico estado ON_SLOPE - void moveJumping(float delta_time); // Movimiento físico estado JUMPING - void moveFalling(float delta_time); // Movimiento físico estado FALLING + void moveOnAir(float delta_time); // Movimiento físico estado ON_AIR // --- Funciones de inicialización --- void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador @@ -188,6 +151,7 @@ class Player { // --- Funciones de gestión de estado --- void transitionToState(State state); // Cambia el estado del jugador + void startJump(); // Inicia el salto: velocidad inicial + sonido + transición a ON_AIR // --- Funciones de física --- void applyGravity(float delta_time); // Aplica gravedad al jugador @@ -197,7 +161,6 @@ class Player { auto getProjection(Direction direction, float displacement) -> SDL_FRect; // Devuelve el rectangulo de proyeccion void applyHorizontalMovement(float delta_time); // Aplica movimiento horizontal con colisión de muros auto handleLandingFromAir(float displacement, const SDL_FRect& projection) -> bool; // Detecta aterrizaje en superficies y rampas - void resetSoundControllersOnLanding(); // Resetea los controladores de sonido al aterrizar // --- Funciones de detección de superficies --- auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies @@ -216,11 +179,7 @@ class Player { // --- Funciones de finalización --- void animate(float delta_time); // Establece la animación del jugador auto handleBorders() -> Room::Border; // Comprueba si se halla en alguno de los cuatro bordes - void handleJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio auto handleKillingTiles() -> bool; // Comprueba que el jugador no toque ningun tile de los que matan - void playJumpSound(float delta_time); // Calcula y reproduce el sonido de salto - void playFallSound(float delta_time); // Calcula y reproduce el sonido de caer - void handleDeathByFalling(); // Gestiona la muerte al caer desde muy alto void updateVelocity(); // Calcula la velocidad en x void markAsDead(); // Marca al jugador como muerto }; \ No newline at end of file diff --git a/source/game/gameplay/room_loader.cpp b/source/game/gameplay/room_loader.cpp index 0410662..57454f5 100644 --- a/source/game/gameplay/room_loader.cpp +++ b/source/game/gameplay/room_loader.cpp @@ -21,6 +21,13 @@ auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string return value + ".yaml"; } +// Lee un nodo de color tolerando tanto string ("red", "bright_blue") como entero (índice de paleta) +static auto readColorNode(const fkyaml::node& node) -> std::string { + if (node.is_string()) { return node.get_value(); } + if (node.is_integer()) { return std::to_string(node.get_value()); } + return "black"; +} + // Convierte string de autoSurface a int auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int { // NOLINT(readability-convert-member-functions-to-static) if (node.is_integer()) { @@ -71,10 +78,10 @@ void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, con room.name = room_node["name"].get_value(); } if (room_node.contains("bgColor")) { - room.bg_color = room_node["bgColor"].get_value(); + room.bg_color = readColorNode(room_node["bgColor"]); } if (room_node.contains("border")) { - room.border_color = room_node["border"].get_value(); + room.border_color = readColorNode(room_node["border"]); } if (room_node.contains("tileSetFile")) { room.tile_set_file = room_node["tileSetFile"].get_value(); @@ -87,11 +94,11 @@ void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, con // Item colors room.item_color1 = room_node.contains("itemColor1") - ? room_node["itemColor1"].get_value_or("yellow") + ? readColorNode(room_node["itemColor1"]) : "yellow"; room.item_color2 = room_node.contains("itemColor2") - ? room_node["itemColor2"].get_value_or("magenta") + ? readColorNode(room_node["itemColor2"]) : "magenta"; // Dirección de la cinta transportadora (left/none/right) diff --git a/source/game/scenes/credits.cpp b/source/game/scenes/credits.cpp index 9f91539..aa38521 100644 --- a/source/game/scenes/credits.cpp +++ b/source/game/scenes/credits.cpp @@ -34,7 +34,7 @@ Credits::Credits() Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); // Cambia el color del borde fillTexture(); // Escribe el texto en la textura - Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica + Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica } // Comprueba el manejador de eventos diff --git a/source/game/scenes/game_over.hpp b/source/game/scenes/game_over.hpp index 24996f9..5e2191e 100644 --- a/source/game/scenes/game_over.hpp +++ b/source/game/scenes/game_over.hpp @@ -35,12 +35,12 @@ class GameOver { static constexpr float ENDING_DURATION = 1.12F; // Espera en negro antes de salir // --- Constantes de posición --- - static constexpr int TEXT_Y = 32; // Posición Y del texto principal - static constexpr int SPRITE_Y_OFFSET = 30; // Offset Y para sprites desde TEXT_Y - static constexpr int PLAYER_X_OFFSET = 10; // Offset X del jugador desde el centro - static constexpr int TV_X_OFFSET = 10; // Offset X del TV desde el centro - static constexpr int ITEMS_Y_OFFSET = 80; // Offset Y del texto de items desde TEXT_Y - static constexpr int ROOMS_Y_OFFSET = 90; // Offset Y del texto de rooms desde TEXT_Y + static constexpr int TEXT_Y = 32; // Posición Y del texto principal + static constexpr int SPRITE_Y_OFFSET = 30; // Offset Y para sprites desde TEXT_Y + static constexpr int PLAYER_X_OFFSET = 10; // Offset X del jugador desde el centro + static constexpr int TV_X_OFFSET = 10; // Offset X del TV desde el centro + static constexpr int ITEMS_Y_OFFSET = 80; // Offset Y del texto de items desde TEXT_Y + static constexpr int ROOMS_Y_OFFSET = 90; // Offset Y del texto de rooms desde TEXT_Y // --- Métodos --- void update(); // Actualiza el objeto diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index 4d2f804..9a5097a 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -47,7 +47,7 @@ Title::Title() initMarquee(); // Inicializa la marquesina createCheevosTexture(); // Crea y rellena la textura para mostrar los logros Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); // Cambia el color del borde - Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica + Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica } // Destructor diff --git a/source/utils/color.hpp b/source/utils/color.hpp index 23ee7e3..5bad808 100644 --- a/source/utils/color.hpp +++ b/source/utils/color.hpp @@ -17,75 +17,75 @@ * de 3 niveles de intensidad (0, 128, 255) para cada componente RGB. */ class Color { - public: - /** - * @enum Cpc - * @brief Índices de los colores de la paleta Amstrad CPC - * - * Los nombres corresponden a los colores oficiales documentados por Amstrad. - * El índice 0 está reservado para transparencia. - */ - enum class Cpc : Uint8 { - // Transparente (índice 0) - CLEAR = 0, // Nota: No usar "TRANSPARENT" - colisiona con macro de Windows + public: + /** + * @enum Cpc + * @brief Índices de los colores de la paleta Amstrad CPC + * + * Los nombres corresponden a los colores oficiales documentados por Amstrad. + * El índice 0 está reservado para transparencia. + */ + enum class Cpc : Uint8 { + // Transparente (índice 0) + CLEAR = 0, // Nota: No usar "TRANSPARENT" - colisiona con macro de Windows - // Negros y azules (R=0) - BLACK = 1, // 0, 0, 0 - BLUE = 2, // 0, 0, 128 - BRIGHT_BLUE = 3, // 0, 0, 255 + // Negros y azules (R=0) + BLACK = 1, // 0, 0, 0 + BLUE = 2, // 0, 0, 128 + BRIGHT_BLUE = 3, // 0, 0, 255 - // Rojos y magentas (G=0) - RED = 4, // 128, 0, 0 - MAGENTA = 5, // 128, 0, 128 - MAUVE = 6, // 128, 0, 255 - BRIGHT_RED = 7, // 255, 0, 0 - PURPLE = 8, // 255, 0, 128 - BRIGHT_MAGENTA = 9, // 255, 0, 255 + // Rojos y magentas (G=0) + RED = 4, // 128, 0, 0 + MAGENTA = 5, // 128, 0, 128 + MAUVE = 6, // 128, 0, 255 + BRIGHT_RED = 7, // 255, 0, 0 + PURPLE = 8, // 255, 0, 128 + BRIGHT_MAGENTA = 9, // 255, 0, 255 - // Verdes y cianes (R=0, G>0) - GREEN = 10, // 0, 128, 0 - CYAN = 11, // 0, 128, 128 - SKY_BLUE = 12, // 0, 128, 255 + // Verdes y cianes (R=0, G>0) + GREEN = 10, // 0, 128, 0 + CYAN = 11, // 0, 128, 128 + SKY_BLUE = 12, // 0, 128, 255 - // Amarillos y blancos medios (G=128) - YELLOW = 13, // 128, 128, 0 - WHITE = 14, // 128, 128, 128 - PASTEL_BLUE = 15, // 128, 128, 255 + // Amarillos y blancos medios (G=128) + YELLOW = 13, // 128, 128, 0 + WHITE = 14, // 128, 128, 128 + PASTEL_BLUE = 15, // 128, 128, 255 - // Naranjas y rosas (R=255, G=128) - ORANGE = 16, // 255, 128, 0 - PINK = 17, // 255, 128, 128 - PASTEL_MAGENTA = 18, // 255, 128, 255 + // Naranjas y rosas (R=255, G=128) + ORANGE = 16, // 255, 128, 0 + PINK = 17, // 255, 128, 128 + PASTEL_MAGENTA = 18, // 255, 128, 255 - // Verdes brillantes (G=255) - BRIGHT_GREEN = 19, // 0, 255, 0 - SEA_GREEN = 20, // 0, 255, 128 - BRIGHT_CYAN = 21, // 0, 255, 255 + // Verdes brillantes (G=255) + BRIGHT_GREEN = 19, // 0, 255, 0 + SEA_GREEN = 20, // 0, 255, 128 + BRIGHT_CYAN = 21, // 0, 255, 255 - // Limas y pasteles verdes (G=255) - LIME = 22, // 128, 255, 0 - PASTEL_GREEN = 23, // 128, 255, 128 - PASTEL_CYAN = 24, // 128, 255, 255 + // Limas y pasteles verdes (G=255) + LIME = 22, // 128, 255, 0 + PASTEL_GREEN = 23, // 128, 255, 128 + PASTEL_CYAN = 24, // 128, 255, 255 - // Amarillos brillantes y blancos (R=255, G=255) - BRIGHT_YELLOW = 25, // 255, 255, 0 - PASTEL_YELLOW = 26, // 255, 255, 128 - BRIGHT_WHITE = 27 // 255, 255, 255 - }; + // Amarillos brillantes y blancos (R=255, G=255) + BRIGHT_YELLOW = 25, // 255, 255, 0 + PASTEL_YELLOW = 26, // 255, 255, 128 + BRIGHT_WHITE = 27 // 255, 255, 255 + }; - /** - * @brief Obtiene el índice de paleta de un color CPC - * @param color Color del enum Cpc - * @return Índice de paleta (Uint8) - */ - static constexpr auto index(Cpc color) -> Uint8 { - return static_cast(color); - } + /** + * @brief Obtiene el índice de paleta de un color CPC + * @param color Color del enum Cpc + * @return Índice de paleta (Uint8) + */ + static constexpr auto index(Cpc color) -> Uint8 { + return static_cast(color); + } - /** - * @brief Convierte un nombre de color (string) a índice de paleta - * @param name Nombre del color en minúsculas (ej: "cyan", "bright_blue") - * @return Índice de paleta, o 1 (BLACK) si no se encuentra - */ - static auto fromString(const std::string& name) -> Uint8; + /** + * @brief Convierte un nombre de color (string) a índice de paleta + * @param name Nombre del color en minúsculas (ej: "cyan", "bright_blue") + * @return Índice de paleta, o 1 (BLACK) si no se encuentra + */ + static auto fromString(const std::string& name) -> Uint8; }; diff --git a/source/utils/defines.hpp b/source/utils/defines.hpp index 3cb9b26..e4b3dc6 100644 --- a/source/utils/defines.hpp +++ b/source/utils/defines.hpp @@ -6,7 +6,7 @@ namespace Texts { constexpr const char* WINDOW_CAPTION = "© 2026 Projecte 2026 — JailDesigner"; constexpr const char* COPYRIGHT = "@2026 JailDesigner"; - constexpr const char* VERSION = "1.13"; // Versión por defecto + constexpr const char* VERSION = "0.1"; // Versión por defecto } // namespace Texts // Tamaño de bloque diff --git a/source/utils/utils.cpp b/source/utils/utils.cpp index 4727e27..3c6263c 100644 --- a/source/utils/utils.cpp +++ b/source/utils/utils.cpp @@ -1,7 +1,8 @@ #include "utils/utils.hpp" -#include // Para find, transform -#include // Para tolower +#include // Para find, transform, ranges::all_of +#include // Para array +#include // Para tolower, isdigit #include // Para round, abs #include // Para abs #include // Para exception @@ -366,10 +367,36 @@ auto stringToColor(const std::string& str) -> Uint8 { auto it = PALETTE_MAP.find(str); if (it != PALETTE_MAP.end()) { return it->second; - } // Si no se encuentra el color, devolvemos negro por defecto + } + + // Fallback: si el string es numérico (p.ej. "4"), lo tratamos como índice de paleta + if (!str.empty() && std::ranges::all_of(str, [](char c) { return std::isdigit(static_cast(c)) != 0; })) { + const int IDX = safeStoi(str, 0); + if (IDX >= 0 && IDX <= 255) { + return static_cast(IDX); + } + } + + // Si no se encuentra el color, devolvemos negro por defecto return 0; } +// Inverso de stringToColor: devuelve el nombre canónico para un índice de paleta (o el propio número si no hay) +auto colorToString(Uint8 index) -> std::string { + static const std::array NAMES = { + "black", "bright_black", + "blue", "bright_blue", + "red", "bright_red", + "magenta", "bright_magenta", + "green", "bright_green", + "cyan", "bright_cyan", + "yellow", "bright_yellow", + "white", "bright_white"}; + if (index < NAMES.size()) { return NAMES[index]; } + if (index == 255) { return "transparent"; } + return std::to_string(index); +} + // Convierte una cadena a un entero de forma segura auto safeStoi(const std::string& value, int default_value) -> int { try { diff --git a/source/utils/utils.hpp b/source/utils/utils.hpp index 15b1373..5b684d7 100644 --- a/source/utils/utils.hpp +++ b/source/utils/utils.hpp @@ -92,7 +92,8 @@ auto toSDLRect(const SDL_FRect& frect) -> SDL_Rect; // Convierte SDL_FRect auto toSDLPoint(const SDL_FPoint& fpoint) -> SDL_Point; // Convierte SDL_FPoint a SDL_Point // CONVERSIONES DE STRING -auto stringToColor(const std::string& str) -> Uint8; // String a índice de paleta +auto stringToColor(const std::string& str) -> Uint8; // String a índice de paleta (acepta nombres o números) +auto colorToString(Uint8 index) -> std::string; // Índice de paleta a nombre canónico auto safeStoi(const std::string& value, int default_value = 0) -> int; // String a int seguro (sin excepciones) auto stringToBool(const std::string& str) -> bool; // String a bool (true/1/yes/on) auto boolToString(bool value) -> std::string; // Bool a string (1/0)