Made a big mess of the codebase
This commit is contained in:
13
src/rpg/entity/CMakeLists.txt
Normal file
13
src/rpg/entity/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
direction.c
|
||||
entity.c
|
||||
player.c
|
||||
npc.c
|
||||
)
|
||||
53
src/rpg/entity/direction.c
Normal file
53
src/rpg/entity/direction.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "direction.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
float_t directionToAngle(const direction_t dir) {
|
||||
switch(dir) {
|
||||
case DIRECTION_NORTH: return (M_PI_2);
|
||||
case DIRECTION_SOUTH: return -(M_PI_2);
|
||||
case DIRECTION_EAST: return 0;
|
||||
case DIRECTION_WEST: return (M_PI);
|
||||
default: return 0; // Should never happen
|
||||
}
|
||||
}
|
||||
|
||||
void directionGetCoordinates(
|
||||
const direction_t dir,
|
||||
int8_t *x, int8_t *y
|
||||
) {
|
||||
assertNotNull(x, "X coordinate pointer cannot be NULL");
|
||||
assertNotNull(y, "Y coordinate pointer cannot be NULL");
|
||||
|
||||
switch(dir) {
|
||||
case DIRECTION_NORTH:
|
||||
*x = 0;
|
||||
*y = -1;
|
||||
break;
|
||||
|
||||
case DIRECTION_SOUTH:
|
||||
*x = 0;
|
||||
*y = 1;
|
||||
break;
|
||||
|
||||
case DIRECTION_EAST:
|
||||
*x = 1;
|
||||
*y = 0;
|
||||
break;
|
||||
|
||||
case DIRECTION_WEST:
|
||||
*x = -1;
|
||||
*y = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid direction");
|
||||
break;
|
||||
}
|
||||
}
|
||||
41
src/rpg/entity/direction.h
Normal file
41
src/rpg/entity/direction.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef enum {
|
||||
DIRECTION_SOUTH = 0,
|
||||
DIRECTION_EAST = 1,
|
||||
DIRECTION_WEST = 2,
|
||||
DIRECTION_NORTH = 3,
|
||||
|
||||
DIRECTION_UP = DIRECTION_NORTH,
|
||||
DIRECTION_DOWN = DIRECTION_SOUTH,
|
||||
DIRECTION_LEFT = DIRECTION_WEST,
|
||||
DIRECTION_RIGHT = DIRECTION_EAST,
|
||||
} direction_t;
|
||||
|
||||
/**
|
||||
* Converts a direction to an angle in float_t format.
|
||||
*
|
||||
* @param dir The direction to convert.
|
||||
* @return The angle corresponding to the direction.
|
||||
*/
|
||||
float_t directionToAngle(const direction_t dir);
|
||||
|
||||
/**
|
||||
* Gets the relative coordinates for a given direction.
|
||||
*
|
||||
* @param dir The direction to get coordinates for.
|
||||
* @param x Pointer to store the x coordinate.
|
||||
* @param y Pointer to store the y coordinate.
|
||||
*/
|
||||
void directionGetCoordinates(
|
||||
const direction_t dir,
|
||||
int8_t *x, int8_t *y
|
||||
);
|
||||
123
src/rpg/entity/entity.c
Normal file
123
src/rpg/entity/entity.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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 entityInit(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
memoryZero(entity, sizeof(entity_t));
|
||||
|
||||
// entity->type = ENTITY_TYPE_NULL;
|
||||
// entity->x = 0;
|
||||
// entity->y = 0;
|
||||
// entity->dir = DIRECTION_SOUTH;
|
||||
// entity->id = 0;
|
||||
|
||||
// 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 int32_t tileX,
|
||||
const int32_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;
|
||||
}
|
||||
99
src/rpg/entity/entity.h
Normal file
99
src/rpg/entity/entity.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "direction.h"
|
||||
#include "player.h"
|
||||
#include "npc.h"
|
||||
|
||||
#define ENTITY_COUNT_MAX 32
|
||||
#define ENTITY_TURN_DURATION 0.075f // Duration for turning in seconds
|
||||
#define ENTITY_MOVE_DURATION 0.1f // Duration for moving 1 tile, in seconds.
|
||||
#define ENTITY_PLAYER_INDEX 0
|
||||
|
||||
typedef enum {
|
||||
ENTITY_TYPE_NULL = 0,
|
||||
ENTITY_TYPE_PLAYER = 1,
|
||||
ENTITY_TYPE_NPC = 2,
|
||||
} entitytype_t;
|
||||
#define ENTITY_TYPE_COUNT 3
|
||||
|
||||
typedef struct _entity_t {
|
||||
uint32_t id;// Completely unique ID for this entity.
|
||||
int32_t x, y;
|
||||
int8_t subX, subY;
|
||||
uint8_t moveSpeed;
|
||||
|
||||
entitytype_t type;
|
||||
direction_t dir;
|
||||
|
||||
union {
|
||||
npc_t npc;
|
||||
playerentity_t player;
|
||||
};
|
||||
} entity_t;
|
||||
|
||||
// typedef struct {
|
||||
// void (*load) (entity_t *entity, const entity_t *source);
|
||||
// void (*update) (entity_t *entity);
|
||||
// void (*interact)(entity_t *player, entity_t *self);
|
||||
// } entitycallback_t;
|
||||
|
||||
extern entity_t ENTITIES[ENTITY_COUNT_MAX];
|
||||
// extern entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT];
|
||||
|
||||
/**
|
||||
* Loads an entity from the generated entity data.
|
||||
*
|
||||
* @param entity Pointer to the entity to initialize.
|
||||
* @param source Pointer to the source entity data.
|
||||
*/
|
||||
void entityInit(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Updates the entity's state.
|
||||
*
|
||||
* @param entity Pointer to the entity to update.
|
||||
*/
|
||||
void entityUpdate(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Moves the entity by the specified x and y offsets.
|
||||
*
|
||||
* @param entity Pointer to the entity to move.
|
||||
* @param moveSpeed The speed at which to move the entity.
|
||||
*/
|
||||
void entityMove(entity_t *entity, const uint8_t moveSpeed);
|
||||
|
||||
/**
|
||||
* Turns the entity to face the specified direction.
|
||||
*
|
||||
* @param entity Pointer to the entity to turn.
|
||||
* @param dir The direction to turn the entity to.
|
||||
*/
|
||||
void entityTurn(entity_t *entity, const direction_t dir);
|
||||
|
||||
/**
|
||||
* Returns whether or not an entity is currently moving.
|
||||
*
|
||||
* @param entity Pointer to the entity to check.
|
||||
* @return True if the entity is moving, false otherwise.
|
||||
*/
|
||||
bool_t entityIsMoving(const entity_t *entity);
|
||||
|
||||
/**
|
||||
* Gets the entity at the specified tile coordinates.
|
||||
*
|
||||
* @param tileX The x coordinate of the tile to get the entity from.
|
||||
* @param tileY The y coordinate of the tile to get the entity from.
|
||||
* @return Pointer to the entity at the specified coordinates, or NULL if no
|
||||
* entity exists there.
|
||||
*/
|
||||
entity_t *entityGetAt(
|
||||
const int32_t tileX,
|
||||
const int32_t tileY
|
||||
);
|
||||
45
src/rpg/entity/npc.c
Normal file
45
src/rpg/entity/npc.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity.h"
|
||||
// #include "ui/uitextbox.h"
|
||||
// #include "locale/language.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void npcLoad(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_NPC, "Source entity type must be NPC");
|
||||
|
||||
entity->npc = source->npc;
|
||||
}
|
||||
|
||||
void npcUpdate(entity_t *entity) {
|
||||
}
|
||||
|
||||
void npcInteract(entity_t *player, entity_t *self) {
|
||||
assertTrue(self->type == ENTITY_TYPE_NPC, "Entity must be of type NPC");
|
||||
|
||||
switch(self->npc.interactType) {
|
||||
case NPC_INTERACT_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case NPC_INTERACT_TYPE_TEXT:
|
||||
// uiTextboxSetText(languageGet(self->npc.text));
|
||||
break;
|
||||
|
||||
case NPC_INTERACT_TYPE_CONVO:
|
||||
break;
|
||||
|
||||
case NPC_INTERACT_TYPE_EVENT:
|
||||
// eventSetActive(self->npc.eventData);
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unknown NPC interaction type");
|
||||
}
|
||||
}
|
||||
44
src/rpg/entity/npc.h
Normal file
44
src/rpg/entity/npc.h
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct _entity_t entity_t;
|
||||
|
||||
typedef enum {
|
||||
NPC_INTERACT_TYPE_NONE = 0,
|
||||
NPC_INTERACT_TYPE_TEXT = 1,
|
||||
NPC_INTERACT_TYPE_CONVO = 2,
|
||||
NPC_INTERACT_TYPE_EVENT = 3,
|
||||
} npcinteracttype_t;
|
||||
|
||||
typedef struct {
|
||||
npcinteracttype_t interactType;
|
||||
|
||||
union {
|
||||
const char_t* text;
|
||||
// const eventdata_t *eventData;
|
||||
};
|
||||
} npc_t;
|
||||
|
||||
/**
|
||||
* Initializes the NPC entity.
|
||||
*
|
||||
* @param entity The entity to initialize.
|
||||
* @param source The source entity to copy data from.
|
||||
*/
|
||||
void npcLoad(entity_t *entity, const entity_t *source);
|
||||
|
||||
/**
|
||||
* Updates the NPC entity.
|
||||
*
|
||||
* @param entity The entity to update.
|
||||
*/
|
||||
void npcUpdate(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Handles interaction between the player and the NPC.
|
||||
*
|
||||
* @param player The player entity interacting with the NPC.
|
||||
* @param self The NPC entity being interacted with.
|
||||
*/
|
||||
void npcInteract(entity_t *player, entity_t *self);
|
||||
86
src/rpg/entity/player.c
Normal file
86
src/rpg/entity/player.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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 "input/input.h"
|
||||
// #include "display/render.h"
|
||||
// #include "world/world.h"
|
||||
|
||||
// #include "ui/uitextbox.h"
|
||||
|
||||
inventory_t PLAYER_INVENTORY;
|
||||
|
||||
void playerInit() {
|
||||
entity_t *ent = &ENTITIES[ENTITY_PLAYER_INDEX];
|
||||
entityInit(ent);
|
||||
inventoryInit(&PLAYER_INVENTORY, INVENTORY_SIZE_MAX);
|
||||
}
|
||||
|
||||
void playerEntityLoad(entity_t *entity, const entity_t *source) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
assertNotNull(source, "Source entity pointer cannot be NULL");
|
||||
assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity type must be PLAYER");
|
||||
assertTrue(source->type == entity->type, "Source/Entity type mismatch");
|
||||
}
|
||||
|
||||
void playerEntityUpdate(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity type must be PLAYER");
|
||||
|
||||
// TODO: make this just a method somewhere.
|
||||
// if(UI_TEXTBOX.visible) return;
|
||||
if(entityIsMoving(entity)) return;
|
||||
|
||||
const uint8_t moveSpeed = inputIsDown(INPUT_BIND_CANCEL) ? PLAYER_SPEED_RUN : PLAYER_SPEED_WALK;
|
||||
|
||||
if(inputIsDown(INPUT_BIND_UP)) {
|
||||
if(entity->dir != DIRECTION_NORTH) {
|
||||
entityTurn(entity, DIRECTION_NORTH);
|
||||
return;
|
||||
}
|
||||
entityMove(entity, moveSpeed);
|
||||
return;
|
||||
|
||||
} else if(inputIsDown(INPUT_BIND_DOWN)) {
|
||||
if(entity->dir != DIRECTION_SOUTH) {
|
||||
entityTurn(entity, DIRECTION_SOUTH);
|
||||
return;
|
||||
}
|
||||
|
||||
entityMove(entity, moveSpeed);
|
||||
return;
|
||||
} else if(inputIsDown(INPUT_BIND_LEFT)) {
|
||||
if(entity->dir != DIRECTION_WEST) {
|
||||
entityTurn(entity, DIRECTION_WEST);
|
||||
return;
|
||||
}
|
||||
entityMove(entity, moveSpeed);
|
||||
return;
|
||||
|
||||
} else if(inputIsDown(INPUT_BIND_RIGHT)) {
|
||||
if(entity->dir != DIRECTION_EAST) {
|
||||
entityTurn(entity, DIRECTION_EAST);
|
||||
return;
|
||||
}
|
||||
|
||||
entityMove(entity, moveSpeed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Interact
|
||||
if(inputPressed(INPUT_BIND_ACTION)) {
|
||||
int8_t x, y;
|
||||
directionGetCoordinates(entity->dir, &x, &y);
|
||||
entity_t *ent = entityGetAt(entity->x + x, entity->y + y);
|
||||
|
||||
// if(ent != NULL && ENTITY_CALLBACKS[ent->type].interact != NULL) {
|
||||
// assertTrue(ent->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
|
||||
// ENTITY_CALLBACKS[ent->type].interact(entity, ent);
|
||||
// }
|
||||
}
|
||||
}
|
||||
43
src/rpg/entity/player.h
Normal file
43
src/rpg/entity/player.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "item/inventory.h"
|
||||
|
||||
#define PLAYER_SPEED_WALK 1
|
||||
#define PLAYER_SPEED_RUN 2
|
||||
|
||||
typedef struct _entity_t entity_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t nothing;
|
||||
} playerentity_t;
|
||||
|
||||
#define PLAYER_ENTITY_ID (UINT32_MAX-1)
|
||||
|
||||
extern inventory_t PLAYER_INVENTORY;
|
||||
|
||||
/**
|
||||
* Initializes the player and all player-related entities.
|
||||
*/
|
||||
void playerInit(void);
|
||||
|
||||
/**
|
||||
* Loads the player entity.
|
||||
*
|
||||
* @param entity The entity to initialize.
|
||||
* @param source The source entity to copy data from.
|
||||
*/
|
||||
void playerEntityLoad(entity_t *entity, const entity_t *source);
|
||||
|
||||
/**
|
||||
* Updates the player entity.
|
||||
*
|
||||
* @param entity The entity to update.
|
||||
*/
|
||||
void playerEntityUpdate(entity_t *entity);
|
||||
Reference in New Issue
Block a user