diff --git a/src/display/scene/overworld/sceneoverworld.c b/src/display/scene/overworld/sceneoverworld.c index 6dc283d..4069dbb 100644 --- a/src/display/scene/overworld/sceneoverworld.c +++ b/src/display/scene/overworld/sceneoverworld.c @@ -12,14 +12,15 @@ #include "display/scene/scenemanager.h" #include "display/mesh/quad.h" #include "asset/assetmanager.h" +#include "assert/assert.h" -camera_t SCENE_OVERWORLD_CAMERA; +sceneoverworld_t SCENE_OVERWORLD; asset_t *testAsset; ref_t testAssetRef; void sceneOverworldInit(void) { - cameraInit(&SCENE_OVERWORLD_CAMERA); - glm_vec3_copy((vec3){32.0f, 32.0f, 32.0f}, SCENE_OVERWORLD_CAMERA.lookat.position); + cameraInit(&SCENE_OVERWORLD.camera); + glm_vec3_copy((vec3){ 0.0f, 1.0f, 0.0f }, SCENE_OVERWORLD.camera.lookat.up); scene_t *scene = &SCENE_MANAGER_SCENES[SCENE_TYPE_OVERWORLD]; scene->flags |= SCENE_FLAG_ACTIVE | SCENE_FLAG_VISIBLE; @@ -31,24 +32,59 @@ void sceneOverworldUpdate(void) { } void sceneOverworldRender(void) { - cameraPushMatrix(&SCENE_OVERWORLD_CAMERA); + const float_t camOffset = 12.0f; + const float_t fbWidth = frameBufferGetWidth(FRAMEBUFFER_BOUND); + const float_t fbHeight = frameBufferGetHeight(FRAMEBUFFER_BOUND); + const float_t aspect = fbWidth / fbHeight; + const float_t pixelPerfectOffset = tanf( + (glm_rad(180) - SCENE_OVERWORLD.camera.perspective.fov) / 2.0f + ) * (fbHeight/ 2.0f); + + glm_vec3_copy((vec3){ + -100.0f, -100.0f, 0.0f + }, SCENE_OVERWORLD.camera.lookat.target); + glm_vec3_copy((vec3){ + SCENE_OVERWORLD.camera.lookat.target[0], + SCENE_OVERWORLD.camera.lookat.target[1] + camOffset, + SCENE_OVERWORLD.camera.lookat.target[2] + pixelPerfectOffset + }, SCENE_OVERWORLD.camera.lookat.position); + + cameraPushMatrix(&SCENE_OVERWORLD.camera); + + sceneOverworldRenderMap(&testMap); + + spriteBatchFlush(); + cameraPopMatrix(); +} + +void sceneOverworldRenderMap(const map_t *map) { + assertNotNull(map, "Map pointer cannot be NULL"); // Draw base layer // Draw entities + entity_t *start = &map->entities[0]; + entity_t *end = &map->entities[map->entityCount]; + while(start < end) { + // Render entity here. + sceneOverworldRenderEntity(start); + start++; + } // Draw overlay layer. - // renderTextDraw(0.0f, 0.0f, "Hello World", 0xFF, 0xFF, 0xFF); +} - // spriteBatchPush( - // &testAsset->paletteImage.texture, - // 0.0f, 0.0f, 12.0f, 12.0f, - // 0xFF, 0xFF, 0xFF, 0xFF, - // 0.0f, 0.0f, 1.0f, 1.0f - // ); - spriteBatchFlush(); +void sceneOverworldRenderEntity(const entity_t *entity) { + assertNotNull(entity, "Entity pointer cannot be NULL"); + assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type"); + assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type"); - cameraPopMatrix(); + // For now, just draw a placeholder quad. + spriteBatchPush( + &testAsset->paletteImage.texture, + entity->x, entity->y, entity->x + 32.0f, entity->y + 32.0f, + COLOR_WHITE, 0.0f, 0.0f, 0.125f, 0.125f + ); } void sceneOverworldDispose(void) { diff --git a/src/display/scene/overworld/sceneoverworld.h b/src/display/scene/overworld/sceneoverworld.h index e92c4dd..6a1c736 100644 --- a/src/display/scene/overworld/sceneoverworld.h +++ b/src/display/scene/overworld/sceneoverworld.h @@ -7,8 +7,13 @@ #pragma once #include "display/camera.h" +#include "rpg/world/map.h" -extern camera_t SCENE_OVERWORLD_CAMERA; +typedef struct { + camera_t camera; +} sceneoverworld_t; + +extern sceneoverworld_t SCENE_OVERWORLD; /** * Initialize the overworld scene. @@ -25,6 +30,20 @@ void sceneOverworldUpdate(void); */ void sceneOverworldRender(void); +/** + * Render a map in the overworld scene. + * + * @param map Pointer to the map to render. + */ +void sceneOverworldRenderMap(const map_t *map); + +/** + * Render an entity in the overworld scene. + * + * @param entity Pointer to the entity to render. + */ +void sceneOverworldRenderEntity(const entity_t *entity); + /** * Dispose of the overworld scene. */ diff --git a/src/engine/engine.c b/src/engine/engine.c index e44da0c..d252da4 100644 --- a/src/engine/engine.c +++ b/src/engine/engine.c @@ -41,6 +41,8 @@ errorret_t engineUpdate(void) { inputUpdate(); consoleUpdate(); assetManagerUpdate(); + + rpgUpdate(); errorChain(displayUpdate()); errorOk(); diff --git a/src/input/input.c b/src/input/input.c index f24ce56..06b002b 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -108,6 +108,13 @@ bool_t inputReleased(const inputaction_t action) { return !inputIsDown(action) && inputWasDown(action); } +float_t inputAxis(const inputaction_t neg, const inputaction_t pos) { + assertTrue(neg < INPUT_ACTION_COUNT, "Negative input action out of bounds"); + assertTrue(pos < INPUT_ACTION_COUNT, "Positive input action out of bounds"); + + return inputGetCurrentValue(pos) - inputGetCurrentValue(neg); +} + void inputBind(const inputbutton_t button, const char_t *action) { assertNotNull(action, "Input action is null"); assertStrLenMin(action, 1, "Input action is empty"); diff --git a/src/input/input.h b/src/input/input.h index 0920cf5..e66608b 100644 --- a/src/input/input.h +++ b/src/input/input.h @@ -80,6 +80,16 @@ bool_t inputPressed(const inputaction_t action); */ bool_t inputReleased(const inputaction_t action); +/** + * Gets the value of an input axis, defined by two actions (negative and + * positive). + * + * @param neg The action representing the negative direction of the axis. + * @param pos The action representing the positive direction of the axis. + * @return The current value of the axis (-1.0f to 1.0f). + */ +float_t inputAxis(const inputaction_t neg, const inputaction_t pos); + /** * Binds an input button to an action. Will first check if a matching action * exists, otherwise it will be treated as a command. @@ -87,4 +97,4 @@ bool_t inputReleased(const inputaction_t action); * @param button The input button to bind. * @param action The name of the input action or command to bind the button to. */ -void inputBind(const inputbutton_t data, const char_t *action); \ No newline at end of file +void inputBind(const inputbutton_t data, const char_t *action); diff --git a/src/rpg/CMakeLists.txt b/src/rpg/CMakeLists.txt index 7722d91..4178186 100644 --- a/src/rpg/CMakeLists.txt +++ b/src/rpg/CMakeLists.txt @@ -11,5 +11,4 @@ target_sources(${DUSK_TARGET_NAME} # Subdirs add_subdirectory(entity) -add_subdirectory(item) add_subdirectory(world) \ No newline at end of file diff --git a/src/rpg/entity/CMakeLists.txt b/src/rpg/entity/CMakeLists.txt index fe59ea9..f559893 100644 --- a/src/rpg/entity/CMakeLists.txt +++ b/src/rpg/entity/CMakeLists.txt @@ -6,8 +6,6 @@ # Sources target_sources(${DUSK_TARGET_NAME} PRIVATE - direction.c entity.c player.c - npc.c ) \ No newline at end of file diff --git a/src/rpg/entity/direction.c b/src/rpg/entity/direction.c deleted file mode 100644 index e4f0e5e..0000000 --- a/src/rpg/entity/direction.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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; - } -} \ No newline at end of file diff --git a/src/rpg/entity/direction.h b/src/rpg/entity/direction.h deleted file mode 100644 index 65d6f2e..0000000 --- a/src/rpg/entity/direction.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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 -); \ No newline at end of file diff --git a/src/rpg/entity/entity.c b/src/rpg/entity/entity.c index c8f6848..5ce21c5 100644 --- a/src/rpg/entity/entity.c +++ b/src/rpg/entity/entity.c @@ -8,116 +8,30 @@ #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, NULL }, // ENTITY_TYPE_NULL + { playerInit, playerUpdate }, // ENTITY_TYPE_PLAYER + { NULL, NULL }, // ENTITY_TYPE_NPC +}; -// 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) { +void entityInit(entity_t *entity, const entitytype_t type) { assertNotNull(entity, "Entity pointer cannot be NULL"); + assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type"); + assertTrue(type != ENTITY_TYPE_NULL, "Cannot have NULL entity type"); + assertNotNull(ENTITY_CALLBACKS[type].init, "Entity type has no init function"); + memoryZero(entity, sizeof(entity_t)); + entity->type = type; - // 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); + ENTITY_CALLBACKS[type].init(entity); } 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" - // ); + assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type"); + assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type"); + assertNotNull(ENTITY_CALLBACKS[entity->type].update, "enttype lacks update"); - // 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; -} + ENTITY_CALLBACKS[entity->type].update(entity); +} \ No newline at end of file diff --git a/src/rpg/entity/entity.h b/src/rpg/entity/entity.h index a9f04f0..adbd317 100644 --- a/src/rpg/entity/entity.h +++ b/src/rpg/entity/entity.h @@ -6,94 +6,51 @@ */ #pragma once -#include "direction.h" +// #include "direction.h" #include "rpg/entity/player.h" -#include "npc.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 +// #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 struct { + void (*init)(entity_t *entity); + void (*update)(entity_t *entity); +} entitycallback_t; typedef enum { - ENTITY_TYPE_NULL = 0, - ENTITY_TYPE_PLAYER = 1, - ENTITY_TYPE_NPC = 2, + ENTITY_TYPE_NULL, + ENTITY_TYPE_PLAYER, + ENTITY_TYPE_NPC, + + ENTITY_TYPE_COUNT } 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; +typedef struct entity_s { + // uint32_t id;// Completely unique ID for this entity. + float_t x, y; entitytype_t type; - direction_t dir; + // direction_t dir; union { - npc_t npc; - playerentity_t player; + player_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]; +extern entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT]; /** - * Loads an entity from the generated entity data. + * Initializes an entity structure. * - * @param entity Pointer to the entity to initialize. - * @param source Pointer to the source entity data. + * @param entity Pointer to the entity structure to initialize. + * @param type The type of the entity. */ -void entityInit(entity_t *entity); +void entityInit(entity_t *entity, const entitytype_t type); /** - * Updates the entity's state. + * Updates an entity. * - * @param entity Pointer to the entity to update. + * @param entity Pointer to the entity structure 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 -); \ No newline at end of file +void entityUpdate(entity_t *entity); \ No newline at end of file diff --git a/src/rpg/entity/npc.c b/src/rpg/entity/npc.c deleted file mode 100644 index cd94ac9..0000000 --- a/src/rpg/entity/npc.c +++ /dev/null @@ -1,45 +0,0 @@ -/** - * 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"); - } -} \ No newline at end of file diff --git a/src/rpg/entity/npc.h b/src/rpg/entity/npc.h deleted file mode 100644 index 3ed8136..0000000 --- a/src/rpg/entity/npc.h +++ /dev/null @@ -1,44 +0,0 @@ - -#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); \ No newline at end of file diff --git a/src/rpg/entity/player.c b/src/rpg/entity/player.c index f13135e..b829f66 100644 --- a/src/rpg/entity/player.c +++ b/src/rpg/entity/player.c @@ -7,81 +7,23 @@ #include "entity.h" #include "assert/assert.h" +#include "time/time.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 playerInit(entity_t *entity) { + assertNotNull(entity, "Entity pointer cannot be NULL"); } -void playerEntityLoad(entity_t *entity, const entity_t *source) { +void playerUpdate(entity_t *entity) { 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; - const uint8_t moveSpeed = 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); - // // } - // } + // testing only + float_t move = TIME.delta * 128.0f; // tiles per second + vec2 dir = { + inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT), + inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN) + }; + glm_vec2_normalize(dir); + entity->x += move * dir[0]; + entity->y -= move * dir[1]; } \ No newline at end of file diff --git a/src/rpg/entity/player.h b/src/rpg/entity/player.h index e5d9bdb..d0018a5 100644 --- a/src/rpg/entity/player.h +++ b/src/rpg/entity/player.h @@ -7,37 +7,23 @@ #pragma once #include "dusk.h" -#include "rpg/item/inventory.h" -#define PLAYER_SPEED_WALK 1 -#define PLAYER_SPEED_RUN 2 - -typedef struct _entity_t entity_t; +typedef struct entity_s entity_t; typedef struct { - uint32_t nothing; -} playerentity_t; - -#define PLAYER_ENTITY_ID (UINT32_MAX-1) - -extern inventory_t PLAYER_INVENTORY; + void *nothing; +} player_t; /** - * Initializes the player and all player-related entities. - */ -void playerInit(void); - -/** - * Loads the player entity. + * Initializes a player entity. * - * @param entity The entity to initialize. - * @param source The source entity to copy data from. + * @param entity Pointer to the entity structure to initialize. */ -void playerEntityLoad(entity_t *entity, const entity_t *source); +void playerInit(entity_t *entity); /** - * Updates the player entity. + * Updates a player entity. * - * @param entity The entity to update. + * @param entity Pointer to the entity structure to update. */ -void playerEntityUpdate(entity_t *entity); \ No newline at end of file +void playerUpdate(entity_t *entity); \ No newline at end of file diff --git a/src/rpg/item/CMakeLists.txt b/src/rpg/item/CMakeLists.txt deleted file mode 100644 index 19db837..0000000 --- a/src/rpg/item/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# 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 - inventory.c -) \ No newline at end of file diff --git a/src/rpg/item/inventory.c b/src/rpg/item/inventory.c deleted file mode 100644 index d123cf2..0000000 --- a/src/rpg/item/inventory.c +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "inventory.h" -#include "util/memory.h" -#include "assert/assert.h" - -void inventoryInit(inventory_t *inventory, const uint8_t size) { - assertNotNull(inventory, "inventory must not be NULL"); - assertTrue(size <= INVENTORY_SIZE_MAX, "size exceeding INVENTORY_SIZE_MAX"); - assertTrue(size > 0, "size must be greater than 0"); - - memoryZero(inventory, sizeof(inventory_t)); - inventory->size = size; -} - -uint8_t inventoryItemIndexByType( - const inventory_t *inventory, - const itemtype_t type -) { - assertNotNull(inventory, "inventory must not be NULL"); - assertTrue(type > ITEM_TYPE_NULL, "type must be greater than ITEM_TYPE_NULL"); - - uint8_t item = inventory->itemCount; - while(item--) { - if(inventory->items[item].type == type) return item; - } - return INVENTORY_SIZE_MAX; -} - -uint8_t inventoryItemCount( - const inventory_t *inventory, - const itemtype_t type -) { - assertNotNull(inventory, "inventory must not be NULL"); - assertTrue(type > ITEM_TYPE_NULL, "type must be greater than ITEM_TYPE_NULL"); - - const uint8_t index = inventoryItemIndexByType(inventory, type); - if(index == INVENTORY_SIZE_MAX) return 0; - return inventory->items[index].count; -} - -void inventoryItemSet( - inventory_t *inventory, - const itemtype_t type, - const uint8_t count -) { - assertNotNull(inventory, "inventory must not be NULL"); - assertTrue(type > ITEM_TYPE_NULL, "type must be greater than ITEM_TYPE_NULL"); - assertTrue(count > 0, "count must be greater than 0"); - - const uint8_t index = inventoryItemIndexByType(inventory, type); - - if(index == INVENTORY_SIZE_MAX) { - // Item does not exist, add it - assertTrue(inventory->itemCount < inventory->size, "inventory is full"); - inventory->items[inventory->itemCount].type = type; - inventory->items[inventory->itemCount].count = count; - inventory->itemCount++; - } else { - // Item exists, update the count - inventory->items[index].count = count; - } -} \ No newline at end of file diff --git a/src/rpg/item/inventory.h b/src/rpg/item/inventory.h deleted file mode 100644 index 3515b96..0000000 --- a/src/rpg/item/inventory.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "itemstack.h" - -#define INVENTORY_SIZE_MAX UINT8_MAX - -typedef struct { - itemstack_t items[INVENTORY_SIZE_MAX]; - uint8_t itemCount; - uint8_t size; -} inventory_t; - -/** - * Initializes an inventory with a specified size. - * - * @param inventory Pointer to the inventory to initialize. - * @param size The size of the inventory (maximum is INVENTORY_SIZE_MAX). - */ -void inventoryInit(inventory_t *inventory, const uint8_t size); - -/** - * Finds the index of the item of a specified type in the inventory. - * - * @param inventory Pointer to the inventory to search. - * @param type The type of item to find. - * @return The index of the item, or INVENTORY_SIZE_MAX if not found. - */ -uint8_t inventoryItemIndexByType( - const inventory_t *inventory, - const itemtype_t type -); - -/** - * Gets the count of items of a specified type in the inventory. - * - * @param inventory Pointer to the inventory to check. - * @param type The type of item to count. - * @return The count of items of the specified type. - */ -uint8_t inventoryItemCount( - const inventory_t *inventory, - const itemtype_t type -); - -/** - * Sets the count of items of a specified type in the inventory. - * If the item does not exist, it will be added. - * - * @param inventory Pointer to the inventory to modify. - * @param type The type of item to set. - * @param count The count of items to set. - */ -void inventoryItemSet( - inventory_t *inventory, - const itemtype_t type, - const uint8_t count -); \ No newline at end of file diff --git a/src/rpg/item/itemstack.h b/src/rpg/item/itemstack.h deleted file mode 100644 index b691d5d..0000000 --- a/src/rpg/item/itemstack.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "itemtype.h" - -typedef struct { - itemtype_t type; - uint8_t count; -} itemstack_t; \ No newline at end of file diff --git a/src/rpg/item/itemtype.h b/src/rpg/item/itemtype.h deleted file mode 100644 index 3f07403..0000000 --- a/src/rpg/item/itemtype.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 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 { - ITEM_TYPE_NULL = 0, - - // MEDICINE - ITEM_TYPE_POTION, - - // INGREDIENTS - ITEM_TYPE_ONION, - ITEM_TYPE_SWEET_POTATO, - ITEM_TYPE_CARROT, - - // COOKED FOOD - ITEM_TYPE_BAKED_SWEET_POTATO, -} itemtype_t; \ No newline at end of file diff --git a/src/rpg/rpg.c b/src/rpg/rpg.c index 31dd453..890afb5 100644 --- a/src/rpg/rpg.c +++ b/src/rpg/rpg.c @@ -6,8 +6,18 @@ */ #include "rpg.h" -#include "rpg/entity/player.h" + +#include "rpg/world/map.h" + +map_t testMap; void rpgInit() { - + mapInit(&testMap); + + entity_t *ent = mapEntityAdd(&testMap); + entityInit(ent, ENTITY_TYPE_PLAYER); +} + +void rpgUpdate() { + mapUpdate(&testMap); } \ No newline at end of file diff --git a/src/rpg/rpg.h b/src/rpg/rpg.h index 541ca58..9caf524 100644 --- a/src/rpg/rpg.h +++ b/src/rpg/rpg.h @@ -10,4 +10,9 @@ /** * Initializes the RPG subsystem. */ -void rpgInit(); \ No newline at end of file +void rpgInit(); + +/** + * Updates the RPG subsystem. + */ +void rpgUpdate(); \ No newline at end of file diff --git a/src/rpg/world/CMakeLists.txt b/src/rpg/world/CMakeLists.txt index 446cdbf..ea50569 100644 --- a/src/rpg/world/CMakeLists.txt +++ b/src/rpg/world/CMakeLists.txt @@ -1,11 +1,10 @@ # 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 - chunk.c - overworld.c + map.c ) \ No newline at end of file diff --git a/src/rpg/world/chunk.c b/src/rpg/world/chunk.c deleted file mode 100644 index 40cee7d..0000000 --- a/src/rpg/world/chunk.c +++ /dev/null @@ -1,321 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "chunk.h" -#include "util/memory.h" -#include "assert/assert.h" -#include "rpg/world/world.h" - -void renderChunkUpdated(chunk_t *chunk); - -chunkmap_t CHUNK_MAP; - -void chunkMapInit() { - memoryZero(&CHUNK_MAP, sizeof(chunkmap_t)); - - // Load default chunks, YX order. - uint16_t i = 0; - chunk_t *chunk; - for(uint8_t y = 0; y < CHUNK_MAP_HEIGHT; y++) { - for(uint8_t x = 0; x < CHUNK_MAP_WIDTH; x++) { - assertTrue(i < CHUNK_MAP_COUNT, "Chunk index out of bounds"); - - chunk = CHUNK_MAP.chunks + i; - CHUNK_MAP.chunkOrder[i] = chunk; - - chunkLoad(chunk, x, y); - assertTrue( - chunk->x == x && chunk->y == y, - "Chunk coordinates do not match expected values" - ); - - i++; - } - } -} - -void chunkMapShift(const int16_t x, const int16_t y) { - if(x == 0 && y == 0) assertUnreachable("ChunkMapShift called with no shift"); - - chunk_t *newChunkOrder[CHUNK_MAP_COUNT]; - chunk_t *unloadedChunks[CHUNK_MAP_COUNT]; - chunk_t *chunk; - uint8_t i, j; - uint16_t - /** New Map Coordinates */ - newX, newY, - newChunkX, newChunkY - ; - - // Calculate the new map coordinates - newX = CHUNK_MAP.topLeftX + x; - newY = CHUNK_MAP.topLeftY + y; - - // Zero the new chunk order - memoryZero(newChunkOrder, sizeof(newChunkOrder)); - - // For each chunk... - j = 0; - chunk = CHUNK_MAP.chunks; - do { - // Is this chunk still going to be within the map bounds? - if( - chunk->x < newX || chunk->y < newY || - chunk->x >= newX + CHUNK_MAP_WIDTH || - chunk->y >= newY + CHUNK_MAP_HEIGHT - ) { - // No, it's not, let's unload it and make it available for reuse. - chunkUnload(chunk); - assertTrue( - j < CHUNK_MAP_COUNT, - "Unloaded chunk index out of bounds" - ); - unloadedChunks[j++] = chunk; - chunk++; - continue; - } - - // Yes it is still valid, determine the new index that it will be at - i = (chunk->y - newY) * CHUNK_MAP_WIDTH + (chunk->x - newX); - assertTrue( - i < CHUNK_MAP_COUNT, - "Chunk index out of bounds after shifting" - ); - assertNull( - newChunkOrder[i], - "New chunk order index is already occupied" - ); - - // Set the new chunk order - newChunkOrder[i] = chunk; - chunk++; - } while(chunk < CHUNK_MAP.chunks + CHUNK_MAP_COUNT); - - // Now check the new chunk order list for missing chunks. - i = 0; - do { - assertTrue( - i < CHUNK_MAP_COUNT, - "New chunk order index out of bounds after shifting" - ); - - // Is this chunk loaded still? - chunk = newChunkOrder[i]; - if(chunk != NULL) { - i++; - continue; - } - - // Determine the new chunk coordinates. - newChunkX = i % CHUNK_MAP_WIDTH + newX; - newChunkY = i / CHUNK_MAP_WIDTH + newY; - assertTrue( - newChunkX >= newX && newChunkX < newX + CHUNK_MAP_WIDTH, - "New chunk X coordinate out of bounds after shifting" - ); - assertTrue( - newChunkY >= newY && newChunkY < newY + CHUNK_MAP_HEIGHT, - "New chunk Y coordinate out of bounds after shifting" - ); - - // Pop a chunk from the unloaded chunks list. - assertTrue(j > 0, "No unloaded chunks available to reuse"); - chunk = unloadedChunks[--j]; - assertNotNull(chunk, "Unloaded chunk pointer is null"); - - // Load the chunk at the new coordinates. - chunkLoad(chunk, newChunkX, newChunkY); - assertTrue( - chunk->x == newChunkX && chunk->y == newChunkY, - "Chunk coordinates do not match expected values after shifting" - ); - - // Set it in order. - newChunkOrder[i] = chunk; - i++; - } while(i < CHUNK_MAP_COUNT); - - // Update Absolutes. - CHUNK_MAP.topLeftX = newX; - CHUNK_MAP.topLeftY = newY; - - // Update the chunk order. - memoryCopy( - CHUNK_MAP.chunkOrder, - newChunkOrder, - sizeof(CHUNK_MAP.chunkOrder) - ); -} - -void chunkMapSetPosition(const uint16_t x, const uint16_t y) { - if(x == CHUNK_MAP.topLeftX && y == CHUNK_MAP.topLeftY) { - return; - } - - int16_t shiftX = x - CHUNK_MAP.topLeftX; - int16_t shiftY = y - CHUNK_MAP.topLeftY; - - // Are we shifting the entire map? - if( - shiftX >= CHUNK_MAP_WIDTH || shiftX < -CHUNK_MAP_WIDTH || - shiftY >= CHUNK_MAP_HEIGHT || shiftY < -CHUNK_MAP_HEIGHT - ) { - printf("Shifting chunk map to new position (%u, %u)\n", x, y); - } - - // Shift the chunk map by the specified offsets. - chunkMapShift(shiftX, shiftY); -} - -chunk_t * chunkGetChunkAt(const uint16_t chunkX, const uint16_t chunkY) { - assertTrue( - chunkX < WORLD_WIDTH && chunkY < WORLD_HEIGHT, - "Chunk coordinates out of bounds" - ); - - chunk_t *chunk = CHUNK_MAP.chunks; - do { - if(chunk->x == chunkX && chunk->y == chunkY) return chunk; - chunk++; - } while(chunk < CHUNK_MAP.chunks + CHUNK_MAP_COUNT); - return NULL; -} - -void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { - assertNotNull(chunk, "Chunk pointer is null"); - - // Zero out the chunk data. - memoryZero(chunk, sizeof(chunk_t)); - - // Set the chunk coordinates. - chunk->x = x; - chunk->y = y; - - // Only load data if the chunk is within bounds. - if(x >= WORLD_WIDTH || y >= WORLD_HEIGHT) { - memorySet(chunk->tilesBase, 0, sizeof(chunk->tilesBase)); - memorySet(chunk->tilesBaseOverlay, 0, sizeof(chunk->tilesBaseOverlay)); - return; - } - - // Is chunk data defined? - const chunkdata_t *chunkData = WORLD_CHUNKS[y * WORLD_WIDTH + x]; - if(chunkData == NULL) { - memorySet(chunk->tilesBase, 0, sizeof(chunk->tilesBase)); - memorySet(chunk->tilesBaseOverlay, 0, sizeof(chunk->tilesBaseOverlay)); - return; - } - - // Load tile data into chunk - // printf("Loading chunk at (%u, %u)\n", x, y); - memoryCopy( - chunk->tilesBase, - chunkData->layerBase, - sizeof(chunk->tilesBase) - ); - memoryCopy( - chunk->tilesBaseOverlay, - chunkData->layerBaseOverlay, - sizeof(chunk->tilesBaseOverlay) - ); - - // Load chunk entities - const entity_t *data; - entity_t *entity; - data = chunkData->entities; - while(data < chunkData->entities + CHUNK_ENTITY_COUNT_MAX) { - if(data->type == ENTITY_TYPE_NULL) break; - - // Store that this chunk owns this entity ID. - chunk->entityIDs[chunk->entityCount++] = data->id; - - // Check entity isn't loaded (still). - entity = ENTITIES; - do { - if(entity->type != ENTITY_TYPE_NULL && entity->id == data->id) break; - entity++; - } while(entity < ENTITIES + ENTITY_COUNT_MAX); - - if(entity != ENTITIES + ENTITY_COUNT_MAX) { - // Entity is already loaded, skip it. - printf("Entity ID %u already loaded, skipping...\n", data->id); - data++; - continue; - } - - // Find an empty entity slot. - entity = ENTITIES; - while(true) { - assertTrue( - entity < ENTITIES + ENTITY_COUNT_MAX, - "Out of available entities" - ); - - if(entity->type == ENTITY_TYPE_NULL) break; - entity++; - }; - - // Load this entity. - // entityLoad(entity, data); - data++; - } - - // Allow the rendering platform to know this chunk is loaded. - // renderChunkUpdated(chunk); -} - -void chunkUnload(chunk_t *chunk) { - uint8_t i; - entity_t *entity; - uint32_t id; - assertNotNull(chunk, "Chunk pointer is null"); - - // Iterate over each entity this chunk owns. - i = 0; - while(i < chunk->entityCount) { - id = chunk->entityIDs[i++]; - - // Now, do we need to unload this entity? - bool_t shouldUnload = false; - - // Now, find the entity loaded with this ID. It should be impossible for - // this entity to be unloaded (but may change in future). - entity = ENTITIES; - do { - if(entity->type != ENTITY_TYPE_NULL && entity->id == id) break; - entity++; - } while(entity < ENTITIES + ENTITY_COUNT_MAX); - - assertTrue( - entity < ENTITIES + ENTITY_COUNT_MAX, - "Entity ID not found in ENTITIES array, cannot unload" - ); - - // If the entity is still within our chunk bounds, it's getting unloaded - if( - floorf(entity->x) >= chunk->x * CHUNK_WIDTH * TILE_WIDTH_HEIGHT && - ceilf(entity->x) < (chunk->x + 1) * CHUNK_WIDTH * TILE_WIDTH_HEIGHT && - floorf(entity->y) >= chunk->y * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT && - ceilf(entity->y) < (chunk->y + 1) * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT - ) { - shouldUnload = true; - } else { - assertUnreachable( - "Entity has left its chunk bounds, we should not be unloading it but " - "I have yet to implement that properly. It will need to self-manage " - "its own unloading somehow, and also not be in a null chunk " - "when it does so." - ); - } - - // This entity is still in use, leave it loaded. - if(!shouldUnload) continue; - - // NULL the entity type, effectively unloading it. - entity->type = ENTITY_TYPE_NULL; - } -} \ No newline at end of file diff --git a/src/rpg/world/chunk.h b/src/rpg/world/chunk.h deleted file mode 100644 index 3b598aa..0000000 --- a/src/rpg/world/chunk.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "tile.h" -#include "display/display.h" - -#define CHUNK_WIDTH 8 -#define CHUNK_HEIGHT 8 -#define CHUNK_TILE_COUNT (CHUNK_WIDTH * CHUNK_HEIGHT) -#define CHUNK_ENTITY_COUNT_MAX 8 - -#define CHUNK_MAP_WIDTH (((DISPLAY_WIDTH / TILE_WIDTH_HEIGHT)/CHUNK_WIDTH)+2) -#define CHUNK_MAP_HEIGHT (((DISPLAY_HEIGHT / TILE_WIDTH_HEIGHT)/CHUNK_HEIGHT)+2) -#define CHUNK_MAP_COUNT (CHUNK_MAP_WIDTH * CHUNK_MAP_HEIGHT) - -typedef struct { - uint16_t x, y; - tile_t tilesBase[CHUNK_TILE_COUNT]; - tile_t tilesBaseOverlay[CHUNK_TILE_COUNT]; - uint32_t entityIDs[CHUNK_ENTITY_COUNT_MAX]; - uint8_t entityCount; -} chunk_t; - -typedef struct { - chunk_t chunks[CHUNK_MAP_COUNT]; - chunk_t *chunkOrder[CHUNK_MAP_COUNT]; - - uint16_t topLeftX; - uint16_t topLeftY; -} chunkmap_t; - -extern chunkmap_t CHUNK_MAP; - -/** - * Initializes the chunk map. - */ -void chunkMapInit(); - -/** - * Shifts the chunk map by the specified x and y offsets. - * - * @param x The x offset to shift the chunk map. - * @param y The y offset to shift the chunk map. - */ -void chunkMapShift(const int16_t x, const int16_t y); - -/** - * Sets the position of the chunk map to the specified coordinates. - * - * @param x The x coordinate of the top-left chunk. - * @param y The y coordinate of the top-left chunk. - */ -void chunkMapSetPosition(const uint16_t x, const uint16_t y); - -/** - * Gets the chunk at the specified chunk coordinates. - * - * @param chunkX The x coordinate of the chunk. - * @param chunkY The y coordinate of the chunk. - * @return A pointer to the chunk at the specified chunk coordinates, or NULL if - * no chunk exists at those coordinates. - */ -chunk_t * chunkGetChunkAt(const uint16_t chunkX, const uint16_t chunkY); - -/** - * Loads a chunk at the specified coordinates. - * - * @param chunk The chunk to load. - * @param x The x coordinate of the chunk. - * @param y The y coordinate of the chunk. - */ -void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y); - -/** - * Unloads a chunk (that is currently loaded). - * - * @param chunk The chunk to unload. - */ -void chunkUnload(chunk_t *chunk); \ No newline at end of file diff --git a/src/rpg/world/chunkdata.h b/src/rpg/world/chunkdata.h deleted file mode 100644 index 686558b..0000000 --- a/src/rpg/world/chunkdata.h +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "chunk.h" -#include "rpg/entity/entity.h" - -typedef struct { - uint8_t layerBase[CHUNK_TILE_COUNT]; - uint8_t layerBaseOverlay[CHUNK_TILE_COUNT]; - entity_t entities[CHUNK_ENTITY_COUNT_MAX]; -} chunkdata_t; \ No newline at end of file diff --git a/src/rpg/world/map.c b/src/rpg/world/map.c new file mode 100644 index 0000000..3c4182e --- /dev/null +++ b/src/rpg/world/map.c @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "map.h" +#include "util/memory.h" +#include "assert/assert.h" + +void mapInit(map_t *map) { + assertNotNull(map, "Map cannot be NULL"); + memoryZero(map, sizeof(map_t)); +} + +void mapUpdate(map_t *map) { + assertNotNull(map, "Map cannot be NULL"); + + entity_t *start = &map->entities[0]; + entity_t *end = &map->entities[map->entityCount]; + while(start < end) { + entityUpdate(start++); + } +} + +entity_t * mapEntityAdd(map_t *map) { + assertNotNull(map, "Map cannot be NULL"); + assertTrue(map->entityCount < MAP_ENTITY_COUNT_MAX, "Map entities full"); + + entity_t *entity = &map->entities[map->entityCount++]; + return entity; +} \ No newline at end of file diff --git a/src/rpg/world/map.h b/src/rpg/world/map.h new file mode 100644 index 0000000..c316011 --- /dev/null +++ b/src/rpg/world/map.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "rpg/entity/entity.h" + +#define MAP_ENTITY_COUNT_MAX 32 + +typedef struct { + entity_t entities[MAP_ENTITY_COUNT_MAX]; + uint8_t entityCount; +} map_t; + +extern map_t testMap; + +/** + * Initializes a map structure. + * + * @param map Pointer to the map structure to initialize. + */ +void mapInit(map_t *map); + +/** + * Updates the map and its entities. + * + * @param map Pointer to the map structure to update. + */ +void mapUpdate(map_t *map); + +/** + * Adds (but does not initialize) an entity on the map. + * + * @param map Pointer to the map structure. + * @return Pointer to the added entity. + */ +entity_t * mapEntityAdd(map_t *map); \ No newline at end of file diff --git a/src/rpg/world/overworld.c b/src/rpg/world/overworld.c deleted file mode 100644 index 6d6ae8e..0000000 --- a/src/rpg/world/overworld.c +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "overworld.h" -#include "chunk.h" -#include "display/display.h" -#include "assert/assert.h" -#include "rpg/entity/entity.h" - -uint32_t OVERWORLD_CAMERA_X; -uint32_t OVERWORLD_CAMERA_Y; -overworldcameratype_t OVERWORLD_CAMERA_TYPE; - -void overworldInit(void) { - playerInit(); - chunkMapInit(); - - OVERWORLD_CAMERA_X = 0; - OVERWORLD_CAMERA_Y = 0; - OVERWORLD_CAMERA_TYPE = OVERWORLD_CAMERA_TYPE_CENTERED_POSITION; -} - -void overworldUpdate() { - entity_t *entity; - - assertTrue( - OVERWORLD_CAMERA_X < OVERWORLD_CAMERA_LIMIT_X, - "Camera position limit (just because I haven't tested properly)" - ); - assertTrue( - OVERWORLD_CAMERA_Y < OVERWORLD_CAMERA_LIMIT_Y, - "Camera position limit (just because I haven't tested properly)" - ); - - entity = ENTITIES; - do { - entityUpdate(entity++); - } while(entity->type != ENTITY_TYPE_NULL); - - // Testing, follow player - entity = &ENTITIES[0]; // Player entity - assertTrue( - entity->type == ENTITY_TYPE_PLAYER, - "First entity must be player" - ); - OVERWORLD_CAMERA_X = entity->x * TILE_WIDTH_HEIGHT + entity->subX; - OVERWORLD_CAMERA_Y = entity->y * TILE_WIDTH_HEIGHT + entity->subY; - - uint16_t x, y; - uint16_t halfWidth, halfHeight; - halfWidth = ((CHUNK_MAP_WIDTH - 1) * CHUNK_WIDTH * TILE_WIDTH_HEIGHT) / 2; - halfHeight = ((CHUNK_MAP_HEIGHT - 1) * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT) / 2; - - // Calculate the chunk map position based on the camera position. - if(OVERWORLD_CAMERA_X < halfWidth) { - x = 0; - } else { - x = (OVERWORLD_CAMERA_X - halfWidth) / (CHUNK_WIDTH*TILE_WIDTH_HEIGHT); - } - - if(OVERWORLD_CAMERA_Y < halfHeight) { - y = 0; - } else { - y = (OVERWORLD_CAMERA_Y - halfHeight) / (CHUNK_HEIGHT*TILE_WIDTH_HEIGHT); - } - - chunkMapSetPosition(x, y); -} \ No newline at end of file diff --git a/src/rpg/world/overworld.h b/src/rpg/world/overworld.h deleted file mode 100644 index 10d7f5b..0000000 --- a/src/rpg/world/overworld.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * 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 { - OVERWORLD_CAMERA_TYPE_CENTERED_POSITION, -} overworldcameratype_t; - -extern uint32_t OVERWORLD_CAMERA_X; -extern uint32_t OVERWORLD_CAMERA_Y; -extern overworldcameratype_t OVERWORLD_CAMERA_TYPE; - -#define OVERWORLD_CAMERA_LIMIT_X (UINT32_MAX / 4) -#define OVERWORLD_CAMERA_LIMIT_Y (UINT32_MAX / 4) - -/** - * Initializes the overworld. - */ -void overworldInit(void); - -/** - * Updates the overworld. - */ -void overworldUpdate(void); \ No newline at end of file diff --git a/src/rpg/world/tile.h b/src/rpg/world/tile.h deleted file mode 100644 index 1e285ea..0000000 --- a/src/rpg/world/tile.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -#define TILE_WIDTH_HEIGHT 16 - -typedef uint8_t tile_t; - -typedef enum { - TILE_SOLID_NONE = 0, - TILE_SOLID_FULL = 1, - TILE_SOLID_TRIANGLE_TOP_RIGHT = 2, - TILE_SOLID_TRIANGLE_TOP_LEFT = 3, - TILE_SOLID_TRIANGLE_BOTTOM_RIGHT = 4, - TILE_SOLID_TRIANGLE_BOTTOM_LEFT = 5, -} tilesolidtype_t; - -typedef struct { - tilesolidtype_t solidType; -} tilemetadata_t; \ No newline at end of file diff --git a/src/rpg/world/world.h b/src/rpg/world/world.h deleted file mode 100644 index 64b837e..0000000 --- a/src/rpg/world/world.h +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/world/chunkdata.h" - -#define WORLD_WIDTH 1 -#define WORLD_HEIGHT 1 - -static const chunkdata_t *WORLD_CHUNKS[WORLD_HEIGHT * WORLD_WIDTH] = { - NULL -}; \ No newline at end of file