132 lines
3.6 KiB
C
132 lines
3.6 KiB
C
/**
|
|
* Copyright (c) 2025 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "entity.h"
|
|
#include "assert/assert.h"
|
|
#include "util/memory.h"
|
|
#include "world/world.h"
|
|
#include "world/tiledata.h"
|
|
#include "time.h"
|
|
|
|
entity_t ENTITIES[ENTITY_COUNT_MAX] = {0};
|
|
|
|
entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = {
|
|
{NULL}, // ENTITY_TYPE_NULL
|
|
{
|
|
.load = playerEntityLoad,
|
|
.update = playerEntityUpdate,
|
|
},
|
|
{
|
|
.load = npcLoad,
|
|
.update = npcUpdate,
|
|
.interact = npcInteract,
|
|
},
|
|
};
|
|
|
|
void entityLoad(entity_t *entity, const entity_t *source) {
|
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
|
assertNotNull(source, "Source entity pointer cannot be NULL");
|
|
assertTrue(source->type != ENTITY_TYPE_NULL, "Source entity type NULL");
|
|
assertTrue(source->type < ENTITY_TYPE_COUNT, "Source entity type bad");
|
|
assertNotNull(
|
|
ENTITY_CALLBACKS[source->type].load,
|
|
"Entity type has no i nit callback"
|
|
);
|
|
|
|
memoryZero(entity, sizeof(entity_t));
|
|
|
|
entity->type = source->type;
|
|
entity->x = source->x;
|
|
entity->y = source->y;
|
|
entity->dir = source->dir;
|
|
entity->id = source->id;
|
|
|
|
ENTITY_CALLBACKS[entity->type].load(entity, source);
|
|
}
|
|
|
|
void entityUpdate(entity_t *entity) {
|
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
|
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
|
|
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
|
|
assertNotNull(
|
|
ENTITY_CALLBACKS[entity->type].update,
|
|
"Entity type has no update callback"
|
|
);
|
|
|
|
ENTITY_CALLBACKS[entity->type].update(entity);
|
|
|
|
if(entity->subX > 0) {
|
|
entity->subX -= entity->moveSpeed;
|
|
} else if(entity->subX < 0) {
|
|
entity->subX += entity->moveSpeed;
|
|
}
|
|
|
|
if(entity->subY > 0) {
|
|
entity->subY -= entity->moveSpeed;
|
|
} else if(entity->subY < 0) {
|
|
entity->subY += entity->moveSpeed;
|
|
}
|
|
}
|
|
|
|
void entityMove(entity_t *entity, const uint8_t moveSpeed) {
|
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
|
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
|
|
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
|
|
assertFalse(
|
|
entityIsMoving(entity),
|
|
"Entity is already moving, cannot move again"
|
|
);
|
|
|
|
int8_t x = 0, y = 0;
|
|
directionGetCoordinates(entity->dir, &x, &y);
|
|
|
|
// entity in way?
|
|
entity_t *ent = entityGetAt(entity->x + x, entity->y + y);
|
|
if(ent != NULL) return;
|
|
|
|
entity->x += x;
|
|
entity->y += y;
|
|
entity->subX = TILE_WIDTH_HEIGHT * -x;
|
|
entity->subY = TILE_WIDTH_HEIGHT * -y;
|
|
entity->moveSpeed = moveSpeed;
|
|
}
|
|
|
|
void entityTurn(entity_t *entity, const direction_t dir) {
|
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
|
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
|
|
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
|
|
assertTrue(
|
|
dir >= DIRECTION_SOUTH && dir <= DIRECTION_NORTH, "Invalid direction"
|
|
);
|
|
assertFalse(
|
|
entityIsMoving(entity), "Entity is already moving, cannot turn"
|
|
);
|
|
|
|
entity->dir = dir;
|
|
}
|
|
|
|
bool_t entityIsMoving(const entity_t *entity) {
|
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
|
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
|
|
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
|
|
return entity->subX != 0 || entity->subY != 0;
|
|
}
|
|
|
|
entity_t * entityGetAt(
|
|
const uint32_t tileX,
|
|
const uint32_t tileY
|
|
) {
|
|
entity_t *entity = ENTITIES;
|
|
|
|
do {
|
|
if(entity->type == ENTITY_TYPE_NULL) continue;
|
|
if(entity->x == tileX && entity->y == tileY) return entity;
|
|
} while((entity++) < &ENTITIES[ENTITY_COUNT_MAX - 1]);
|
|
|
|
return NULL;
|
|
}
|