Quatre virtuals nous a `Entity` capten decisions que abans vivien al
manager com a discriminacions de tipus:
- `onWhipHit(WhipAttack*)` → bool. Default no-op/false. Override a
`Mummy` per entrar HURT si és whippable. WhipAttack::applyDamage
passa de `dynamic_cast<Mummy*>` + `isWhippable()` a una crida
polimòrfica neta. RollingRock no override → immune al látigo per
disseny, sense flag.
- `onJustSpawned()`. Default no-op. Override a `DynamicHazard` per
disparar `triggerSpawnExit()`. `spawnPendingActors` i `spawnActor`
passen de `dynamic_cast<DynamicHazard*>(observer)->triggerSpawnExit()`
a `observer->onJustSpawned()`.
- `onRemoved()`. Default no-op. Override a `Sarcophagus` per cridar
`entity_manager_->onSarcophagusRemoved()`. `removeEntity` passa de
`getName() == "sarcophagus"` a dispatch polimòrfic.
- `shouldReceiveContact()`. Default `collides() || triggersOnOverlap()`.
Override a `DynamicHazard` per excloure SPAWN. `checkPlayerCollisions`
passa de tres condicions inline per a sacs distints a una crida
unificada.
`whipDirToMummyDir` es mou de whip_attack.cpp a mummy.cpp — el mapping
viu on s'usa (dins de `Mummy::onWhipHit`).
`hitMummyIfApplicable` es renomena a `hitEntityIfApplicable`: ja no
discrimina tipus, aplica `entity->onWhipHit` i marca `already_hit_`
segons el retorn.
Comportament idèntic, tests verds. Aquest commit prepara el següent:
amb el polimorfisme madurat, el sac dual ja no aporta valor i podem
tornar a un únic `entities_`.
EntityManager guanya dues llistes lògiques:
- `map_entities_` — decoració, static_hazards (Hole, FloorTrap, WallTrap)
i interactables (Sarcophagus, Door). Persistents tota la sala.
- `actors_` — DynamicHazards (Mummy, RollingRock, futurs enemics).
Tipats com `unique_ptr<DynamicHazard>`, sense dynamic_cast.
`add()` enruta automàticament segons sigui DynamicHazard o no.
`update`, `notifyPlayerTilePainted`, `findFloorTriggerAt`, `removeEntity`,
`reload` i `renderAll` iteren el(s) sac(s) que toca.
`checkPlayerCollisions`: el filtre de SPAWN sobre el sac d'actors ja no
necessita dynamic_cast — `actor->isSpawning()` és directe. El filtre per
floor decals només toca map_entities_ (els decals viuen exclusivament
allà). Filtres per-jugador extrets a helpers per acotar complexitat.
API nova: `getMapEntities()` i `getActors()` exposen cada sac per
separat. `getEntities()` es manté com a concatenació per retro-compat
(editor, z-sort debug).
`GameScene::triggerHazardSpawnExit` itera `getActors()` directe — fora
dynamic_cast.
`GameScene::render` mergeja els tres orígens (map + actors + players)
en un sol vector temporal abans del stable_sort per `feet_y` — mateix
patró que ja s'usava amb players, ara amb una transformació més.
Comportament idèntic: les momies segueixen instanciant-se al
loadFromLevel. La preparació per al spawn diferit ve en el commit
següent.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hook només Debug que crida EntityManager::forceOpenDoor (nou helper
públic que delega a Door::open). El flux posterior — creuar la porta,
player_exited, level_complete, transició a OUTRO — funciona idèntic
al del joc real, perquè depèn de la Door, no del comptador de
sarcòfags. Útil per saltar la mecànica de pintat/sarcs durant proves
de progressió de sales.
Tecla configurable a data/input/keys.yaml > id: open_door
(per defecte Keypad 1). Mateixos gates que els salts [/]: ignora la
pulsació si la pausa està activa o l'editor obert. En Release la
ENTRADA del YAML segueix carregant-se però no té consumidor.