feat(immunity): API setImmunity/isImmune i lectura del bloc immunity

This commit is contained in:
JailDesigner committed 2026-05-05 13:01:22 +02:00
1 parent 3985e66b94
commit 2e3816783f
3 files changed
+90

No files matched your search

+58
View File
@@ -8,6 +8,7 @@
#include <vector>
#include "core/rendering/sprite/animated_sprite.hpp"
#include "core/rendering/surface.hpp"
#include "external/fkyaml_node.hpp"
#include "game/map/map.hpp"
@@ -311,6 +312,25 @@ class Player : public AnimatedSprite {
// game over. Públic per a HUD i tests.
[[nodiscard]] auto getLivesRemaining() const -> int { return lives_remaining_; }
// Activa la immunitat per `duration_ms` ms. Mentre `isImmune()` és
// cert, `enterHurt` i `enterDying(GENERIC)` són no-op — els hazards no
// poden tocar el jugador. La caiguda per forats (`enterDying(HOLE)`)
// segueix funcionant: els forats no són dany convencional, són una
// sortida lògica del món. Idempotent: una segona crida reescriu el
// timer (no acumula). Visualment, el render alterna la paleta del
// sprite amb una paleta plana cada `immunity_config.blink_period_ms`
// ms. Si `duration_ms <= 0` és no-op (manera de cancel·lar
// explícitament la immunitat seria `setImmunity(0)` — equivalent al
// comportament natural quan el timer s'esgota).
void setImmunity(float duration_ms) {
if (duration_ms > 0.0F) { immunity_remaining_ms_ = duration_ms; }
}
// Cert mentre el jugador té immunitat activa. Comprovat per
// `enterHurt` i `enterDying` per filtrar els hazards. La causa HOLE
// ignora aquest gate (vegeu `enterDying`).
[[nodiscard]] auto isImmune() const -> bool { return immunity_remaining_ms_ > 0.0F; }
// Reset complet a l'estat inicial: posició a (x, y), velocitats a 0,
// estat GROUNDED, qualsevol flag de control reinicialitzat. Cridat
// per GameScene a la transició ROOM_OUTRO → ROOM_INTRO. Idempotent
@@ -664,6 +684,30 @@ class Player : public AnimatedSprite {
// l'animació) i `initial_lives` es manté al default (3).
static void readDeathBlock(const fkyaml::node& yaml);
// Configuració de la immunitat post-spawn llegida del bloc `immunity:`
// del YAML. `duration_ms` és el temps per defecte que dura cada
// immunitat (l'invoca `respawn`). `blink_period_ms` és el mig-cicle del
// parpadeig visual: cada `blink_period_ms` ms, el render alterna
// entre la paleta normal i la paleta `palette_key`. Si `duration_ms`
// és 0 (o el bloc manca) la immunitat queda desactivada i el
// comportament és l'antic.
struct ImmunityConfig {
float duration_ms{0.0F};
int blink_period_ms{0};
// Clau al Resource::Cache de la paleta plana usada al blink (basename
// del .pal a `data/player/`). Buida = no hi ha alternança visual,
// només la finestra lògica d'immunitat (que sense feedback visual
// pot ser confusa, però no és incorrecte).
std::string palette_key;
};
static ImmunityConfig immunity_config;
// Llig el bloc `immunity:` del YAML i n'omple `immunity_config`. Si
// hi ha `palette`, registra la paleta corresponent al Resource::Cache
// (path: `data/player/<palette_key>.pal`). Mateix patró que els altres
// readers — `loadFrom` el crida al final.
static void readImmunityBlock(const fkyaml::node& yaml);
// Activa l'estat ATTACKING en la direcció cardinal indicada (la
// direcció cap on mira el jugador) i publica `whip_spawn` al bus
// perquè el GameScene cree el `WhipAttack` corresponent. Posa el
@@ -743,6 +787,20 @@ class Player : public AnimatedSprite {
// LANDING_STUN i tot l'input queda bloquejat.
float landing_stun_remaining_ms_{0.0F};
// Temps restant d'immunitat (ms). Decreix cada frame al `tick`,
// independentment de l'estat — la immunitat és ortogonal al state
// machine. Mentre > 0, `enterHurt` i `enterDying(GENERIC)` són no-op.
// L'arma `setImmunity()` (cridada per `respawn` amb la durada del
// YAML), i el render alterna paleta cada `immunity_config.blink_period_ms`.
float immunity_remaining_ms_{0.0F};
// Còpia de la paleta normal del sprite (extreta de `surface_->getPalette()`
// al ctor). El render del blink l'usa per restaurar la paleta després
// d'aplicar la versió plana cada mig-cicle. Cachejada perquè la
// Surface pot ser compartida entre dos jugadors del mateix personatge
// i no és segur consultar-la entre swaps.
Palette normal_palette_{};
// Estat anterior del botó de salt per fer detecció de flanc (saltem
// només a la transició no-premut → premut, no mentre es manté). Es
// manté un per teclat i un per mando perquè poden conviure.