# Entities Source: `src/dusk/rpg/entity/` --- ## Storage Entities live in a single fixed global array: ```c entity_t ENTITIES[ENTITY_COUNT]; // ENTITY_COUNT = 64 ``` A slot is "empty" when `entity->type == ENTITY_TYPE_NULL`. Never allocate entity memory dynamically — always find a free slot with `entityGetAvailable()`, which returns its index (`0xFF` if none free). --- ## `entity_t` structure ```c typedef struct entity_s { uint8_t id; // index in ENTITIES[] entitytype_t type; // ENTITY_TYPE_NULL / PLAYER / NPC entitytypedata_t data; // union: player_t | npc_t entitydir_t direction; // facing direction (N/S/E/W) fixed_t position[3]; // current sub-tile position (x, y, z) fixed_t lastPosition[3]; // position before last move (for interpolation) entityanim_t animation; // IDLE / TURN / WALK fixed_t animTime; // countdown timer for current animation entityinteract_t interact; // optional interact component } entity_t; ``` --- ## Type system Entity types are defined in `entitytype.h` using the enum+integer-typedef pattern: ```c typedef enum { ENTITY_TYPE_NULL, ENTITY_TYPE_PLAYER, ENTITY_TYPE_NPC, ENTITY_TYPE_COUNT } entitytype_enum_t; typedef uint8_t entitytype_t; ``` Each type has a `entitycallback_t` entry in the `ENTITY_CALLBACKS[ENTITY_TYPE_COUNT]` static table: ```c typedef struct { void (*init)(entity_t *entity); void (*movement)(entity_t *entity); bool_t (*interact)(entity_t *player, entity_t *entity); } entitycallback_t; ``` Callbacks not applicable to a type are `NULL`; `entityUpdate()` guards against this before calling. Type-specific data sits in `entitytypedata_t` (a union of `player_t` and `npc_t`). Currently both are stubs (`void *nothing`). --- ## Direction (`entitydir.h`) ```c ENTITY_DIR_NORTH / EAST / SOUTH / WEST ``` Aliases: `UP = NORTH`, `DOWN = SOUTH`, `LEFT = WEST`, `RIGHT = EAST`. Utilities: - `entityDirGetOpposite(dir)` — returns the opposite direction. - `entityDirGetRelative(dir, &relX, &relY)` — fills in the ±1 XY delta for that direction. - `assertValidEntityDir(dir, msg)` — assertion macro. --- ## Animation (`entityanim.h`) ```c ENTITY_ANIM_IDLE // standing still ENTITY_ANIM_TURN // turning to a new direction (ENTITY_ANIM_TURN_DURATION = FIXED(0.06)) ENTITY_ANIM_WALK // mid-step (ENTITY_ANIM_WALK_DURATION = FIXED(0.1)) ``` `entityAnimUpdate(entity)` decrements `animTime` each frame and transitions back to `IDLE` when it reaches zero. `entityCanWalk(entity)` / `entityCanTurn(entity)` both return true only when `animation == ENTITY_ANIM_IDLE`. The renderer interpolates between `lastPosition` and `position` using `animTime / WALK_DURATION` to produce smooth motion even at low frame rates. --- ## Movement `entityWalk(entity, direction)`: 1. Converts `entity->position` to a `worldpos_t` (truncates fractional part). 2. Applies the directional delta to get `newPos`. 3. Checks the current and target tiles for ramp raise/fall logic (see [world.md](world.md)). 4. Checks `ENTITIES[]` for another entity occupying `newPos` — blocks if found. 5. On success: copies `position` to `lastPosition`, updates `position` to `newPos` (via `worldPosToFixed`), sets `animation = ENTITY_ANIM_WALK`. `entityTurn(entity, direction)`: sets `direction` and starts a brief turn animation. --- ## Interaction (`entityinteract.h`) The `entityinteract_t` component is embedded in every entity. It is optional — set `type = ENTITY_INTERACT_NULL` for non-interactable entities. ```c typedef enum { ENTITY_INTERACT_NULL, ENTITY_INTERACT_CUTSCENE, // plays a cutscene_t * ENTITY_INTERACT_PRINT, // prints a short message[32] } entityinteracttype_t; ``` `entityInteractWith(player, target)` dispatches: 1. If the interact component's `type != NULL`, handles it (starts the cutscene or prints the message). 2. Otherwise falls back to `ENTITY_CALLBACKS[type].interact` if set. --- ## Player (`player.h` / `player.c`) `playerInit()` is called via `ENTITY_CALLBACKS[ENTITY_TYPE_PLAYER].init`. `playerInput(entity)` is the movement callback. It reads `PLAYER_INPUT_DIR_MAP[]` — a static table mapping input actions (`INPUT_ACTION_UP/DOWN/LEFT/RIGHT`) to entity directions — and calls `entityWalk` or `entityTurn` accordingly. The player entity is normally `ENTITIES[0]` but there is no hardcoded assumption about its index beyond being initialized with `ENTITY_TYPE_PLAYER`. --- ## NPC (`npc.h` / `npc.c`) `npcInit()`, `npcMovement()`, and `npcInteract()` provide the NPC type callbacks. Currently stubs; movement does nothing, interact returns false.