fix(hazard): aterrar damunt d'un Hole salta el LANDING_STUN

This commit is contained in:
JailDesigner committed 2026-04-30 13:53:26 +02:00
1 parent 4da50571eb
commit 3e5217066f
5 files changed
+80 -5

No files matched your search

+32 -5
View File
@@ -17,6 +17,8 @@
#include "core/resources/resource_cache.hpp"
#include "core/resources/resource_helper.hpp"
#include "external/fkyaml_node.hpp"
#include "game/entities/entity.hpp"
#include "game/entities/entity_manager.hpp"
#include "game/entities/event_bus.hpp"
#include "game/options.hpp"
#include "utils/defaults.hpp"
@@ -923,6 +925,28 @@ auto Player::integrateJump(float delta_time) -> bool {
return false;
}
if (jump_z_ <= 0.0F) {
// Aterratge sobre decal-trigger (Hole, futurs pinchos plans...):
// saltem el LANDING_STUN i transicionem directament a la caiguda
// pel forat. Sense aquesta detecció, l'aterratge entraria a
// LANDING_STUN (~200 ms flotant sobre el forat) i només quan
// tornés a GROUNDED `Hole::onPlayerContact` ho dispararia. La
// hit-box (8×8 centrada al sprite) és la mateixa que `Hole`
// usa al seu re-check; coherent. Si el manager no s'ha
// injectat (tests stand-alone), el camí d'aterratge segueix sent
// el habitual.
if (entity_manager_ != nullptr) {
const Entity* trigger = entity_manager_->findFloorTriggerAt(getHitBox());
if (trigger != nullptr) {
const auto BOX = trigger->getCollisionRect();
const float CENTER_X = BOX.x + (BOX.w * 0.5F);
const float CENTER_Y = BOX.y + (BOX.h * 0.5F);
const float FLOOR_Y = BOX.y + BOX.h;
enterHoleFall(CENTER_X, CENTER_Y, FLOOR_Y);
// No retornem `true`: no és un aterratge "normal" i
// `applyMovement` no ha de cridar `resolveLandingOverlap`.
return false;
}
}
jump_z_ = 0.0F;
jump_vz_ = 0.0F;
state_ = State::LANDING_STUN;
@@ -1455,11 +1479,14 @@ void Player::disable() {
}
void Player::enterHoleFall(float center_x, float center_y, float floor_y) {
// Defensa: només transicionem des de GROUNDED. Saltadors, AIRBORNE,
// HURT, DYING, etc. no han de caure pel forat (entre altres coses,
// perquè `checkPlayerCollisions` ja filtra airborne via altura, però
// afegim el gat ací per coherència amb la resta de transicions).
if (state_ != State::GROUNDED) { return; }
// Cap guard de state ací: la responsabilitat la té el caller perquè
// hi ha dos callers vàlids amb states distints:
// - `Hole::onPlayerContact` (state GROUNDED, el jugador camina i
// trepitja el tile del forat).
// - `Player::integrateJump` (state AIRBORNE, en aterrar damunt
// d'un decal-trigger en lloc d'entrar a LANDING_STUN).
// Posar `if (state_ != GROUNDED) return` ací bloquejaria el segon
// cas i obligaria a hacks tipus "forçar GROUNDED abans de cridar".
// Snap del centre de la hit-box a la coordenada central del forat.
// Resolem `pos = center - (hit_offset + hit_size/2)` per a cada eix: