#include "game/entities/entity.hpp" #include #include Entity::Entity(std::string name, TilePos tile, SDL_FRect pixel_rect) : name_(std::move(name)), tile_(tile), pixel_rect_(pixel_rect) {} void Entity::update(float delta_time) { if (anim_.has_value()) { anim_->tick(delta_time); } } void Entity::render() { // No-op de base. El dibuix real el fa `EntityManager::renderAll` (viu // a `entity_manager_loadlevel.cpp`, que sí depèn de `Surface`). Així // `entity.cpp` no arrossega el pipeline de render al smoke test // stand-alone. Les subclasses futures poden sobreescriure si volen // lògica pròpia (p.ex. render condicional segons estat). } void Entity::onPlayerContact(Player* /*player*/) { // No-op per defecte. } void Entity::notifyTilePainted(int /*col*/, int /*row*/) { // No-op per defecte; només `Sarcophagus` l'usa. } auto Entity::onWhipHit(WhipAttack* /*attack*/) -> bool { // No-op per defecte; les entitats no-whippables (Torch, Hole, Sarc, // Door, RollingRock...) retornen `false`. `Mummy` n'és l'override // efectiu. El caller usa el retorn per marcar `already_hit_` — // entitats que no han rebut dany NO bloquegen futurs frames del whip. return false; } void Entity::onJustSpawned() { // No-op per defecte. `DynamicHazard` override per disparar el seu // `triggerSpawnExit` (anima la fase EMERGING just després de néixer). } void Entity::onRemoved() { // No-op per defecte. `Sarcophagus` override per decrementar el // comptador `total_sarcs_` del manager. } auto Entity::shouldReceiveContact() const -> bool { // Default: l'entitat rep contacte si és sòlida (`collides_`) o si és // un trigger d'àrea (`triggers_on_overlap_`). `DynamicHazard` afegeix // el filtre de SPAWN — mentre està emergint, ignora contactes. return collides_ || triggers_on_overlap_; } auto Entity::getCollisionRect() const -> SDL_FRect { if (!collision_box_.has_value()) { return pixel_rect_; } return { .x = pixel_rect_.x + static_cast(collision_box_->offset_x), .y = pixel_rect_.y + static_cast(collision_box_->offset_y), .w = static_cast(collision_box_->width), .h = static_cast(collision_box_->height), }; } auto Entity::getFeetY() const -> float { // Decal de sòl: sentinel mínim per quedar al principi del Y-sort // ascendent de `GameScene` (stable_sort) i així pintar-se ABANS de // qualsevol actor. Sense passades de render extra. if (is_floor_decal_) { return std::numeric_limits::lowest(); } const auto RECT = getCollisionRect(); return RECT.y + RECT.h; }