diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d9b0f42..7bc94a3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -59,7 +59,7 @@ add_subdirectory(event) add_subdirectory(input) add_subdirectory(item) add_subdirectory(locale) -# add_subdirectory(rpg) +add_subdirectory(map) add_subdirectory(scene) add_subdirectory(script) add_subdirectory(story) diff --git a/src/engine/engine.c b/src/engine/engine.c index 2640480..8eb4840 100644 --- a/src/engine/engine.c +++ b/src/engine/engine.c @@ -14,7 +14,7 @@ #include "scene/scene.h" #include "asset/asset.h" #include "ui/ui.h" -// #include "rpg/rpg.h" +#include "map/map.h" #include "script/scriptmanager.h" #include "debug/debug.h" #include "item/backpack.h" @@ -35,7 +35,7 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) { errorChain(scriptManagerInit()); errorChain(displayInit()); errorChain(uiInit()); - // errorChain(rpgInit()); + errorChain(mapInit()); errorChain(sceneInit()); backpackInit(); @@ -53,9 +53,9 @@ errorret_t engineUpdate(void) { timeUpdate(); inputUpdate(); - // errorChain(rpgUpdate()); uiUpdate(); errorChain(sceneUpdate()); + mapUpdate(); errorChain(displayUpdate()); if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false; @@ -69,6 +69,7 @@ void engineExit(void) { errorret_t engineDispose(void) { sceneDispose(); + mapDispose(); localeManagerDispose(); uiDispose(); errorChain(displayDispose()); diff --git a/src/overworld/CMakeLists.txt b/src/map/CMakeLists.txt similarity index 81% rename from src/overworld/CMakeLists.txt rename to src/map/CMakeLists.txt index d962e9a..914f254 100644 --- a/src/overworld/CMakeLists.txt +++ b/src/map/CMakeLists.txt @@ -1,11 +1,13 @@ # Copyright (c) 2025 Dominic Masters -# +# # This software is released under the MIT License. # https://opensource.org/licenses/MIT # Sources target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + mapchunk.c map.c - mapentity.c + worldpos.c + maptile.c ) \ No newline at end of file diff --git a/src/map/map.c b/src/map/map.c new file mode 100644 index 0000000..3769e91 --- /dev/null +++ b/src/map/map.c @@ -0,0 +1,271 @@ +/** + * 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" +#include "asset/asset.h" +// #include "entity/entity.h" +#include "util/string.h" +#include "time/time.h" + +map_t MAP; + +errorret_t mapInit() { + memoryZero(&MAP, sizeof(map_t)); + errorOk(); +} + +bool_t mapIsLoaded() { + return MAP.filePath[0] != '\0'; +} + +errorret_t mapLoad(const char_t *path, const chunkpos_t position) { + assertStrLenMin(path, 1, "Map file path cannot be empty"); + assertStrLenMax(path, MAP_FILE_PATH_MAX - 1, "Map file path too long"); + + if(stringCompare(MAP.filePath, path) == 0) { + // Same map, no need to reload + errorOk(); + } + + chunkindex_t i; + + // Unload all loaded chunks + if(mapIsLoaded()) { + for(i = 0; i < MAP_CHUNK_COUNT; i++) { + mapChunkUnload(&MAP.chunks[i]); + } + } + + // Store the map file path + stringCopy(MAP.filePath, path, MAP_FILE_PATH_MAX); + + // Determine directory path (it is dirname) + stringCopy(MAP.dirPath, path, MAP_FILE_PATH_MAX); + char_t *last = stringFindLastChar(MAP.dirPath, '/'); + if(last == NULL) errorThrow("Invalid map file path"); + + // Store filename, sans extension + stringCopy(MAP.fileName, last + 1, MAP_FILE_PATH_MAX); + *last = '\0'; // Terminate to get directory path + + last = stringFindLastChar(MAP.fileName, '.'); + if(last == NULL) errorThrow("Map file name has no extension"); + *last = '\0'; // Terminate to remove extension + + // Reset map position + MAP.chunkPosition = position; + + // Perform "initial load" + i = 0; + for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) { + for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) { + for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) { + mapchunk_t *chunk = &MAP.chunks[i]; + chunk->position.x = x + position.x; + chunk->position.y = y + position.y; + chunk->position.z = z + position.z; + MAP.chunkOrder[i] = chunk; + errorChain(mapChunkLoad(chunk)); + i++; + } + } + } + + // Execute map script. + // char_t scriptPath[MAP_FILE_PATH_MAX + 16]; + // stringFormat( + // scriptPath, sizeof(scriptPath), "%s/%s.dsf", + // MAP.dirPath, MAP.fileName + // ); + // if(assetFileExists(scriptPath)) { + // scriptcontext_t ctx; + // errorChain(scriptContextInit(&ctx)); + // errorChain(scriptContextExecFile(&ctx, scriptPath)); + // scriptContextDispose(&ctx); + // } + + errorOk(); +} + +errorret_t mapPositionSet(const chunkpos_t newPos) { + if(!mapIsLoaded()) errorThrow("No map loaded"); + + const chunkpos_t curPos = MAP.chunkPosition; + if(mapChunkPositionIsEqual(curPos, newPos)) { + errorOk(); + } + + // Determine which chunks remain loaded + chunkindex_t chunksRemaining[MAP_CHUNK_COUNT] = {0}; + chunkindex_t chunksFreed[MAP_CHUNK_COUNT] = {0}; + + uint32_t remainingCount = 0; + uint32_t freedCount = 0; + + for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) { + // Will this chunk remain loaded? + mapchunk_t *chunk = &MAP.chunks[i]; + if( + chunk->position.x >= newPos.x && + chunk->position.x < newPos.x + MAP_CHUNK_WIDTH && + + chunk->position.y >= newPos.y && + chunk->position.y < newPos.y + MAP_CHUNK_HEIGHT && + + chunk->position.z >= newPos.z && + chunk->position.z < newPos.z + MAP_CHUNK_DEPTH + ) { + // Stays loaded + chunksRemaining[remainingCount++] = i; + continue; + } + + // Not remaining loaded + chunksFreed[freedCount++] = i; + } + + // Unload the freed chunks + for(chunkindex_t i = 0; i < freedCount; i++) { + mapchunk_t *chunk = &MAP.chunks[chunksFreed[i]]; + mapChunkUnload(chunk); + } + + // This can probably be optimized later, for now we check each chunk and see + // if it needs loading or not, and update the chunk order + chunkindex_t orderIndex = 0; + for(chunkunit_t zOff = 0; zOff < MAP_CHUNK_DEPTH; zOff++) { + for(chunkunit_t yOff = 0; yOff < MAP_CHUNK_HEIGHT; yOff++) { + for(chunkunit_t xOff = 0; xOff < MAP_CHUNK_WIDTH; xOff++) { + const chunkpos_t newChunkPos = { + newPos.x + xOff, newPos.y + yOff, newPos.z + zOff + }; + + // Is this chunk already loaded (was not unloaded earlier)? + chunkindex_t chunkIndex = -1; + for(chunkindex_t i = 0; i < remainingCount; i++) { + mapchunk_t *chunk = &MAP.chunks[chunksRemaining[i]]; + if(!mapChunkPositionIsEqual(chunk->position, newChunkPos)) continue; + chunkIndex = chunksRemaining[i]; + break; + } + + // Need to load this chunk + if(chunkIndex == -1) { + // Find a freed chunk to reuse + chunkIndex = chunksFreed[--freedCount]; + mapchunk_t *chunk = &MAP.chunks[chunkIndex]; + chunk->position = newChunkPos; + errorChain(mapChunkLoad(chunk)); + } + + MAP.chunkOrder[orderIndex++] = &MAP.chunks[chunkIndex]; + } + } + } + + // Update map position + MAP.chunkPosition = newPos; + + errorOk(); +} + +void mapUpdate() { + #if TIME_FIXED == 0 + if(!TIME.dynamicUpdate) return; + #endif +} + +void mapDispose() { + for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) { + mapChunkUnload(&MAP.chunks[i]); + } +} + +void mapChunkUnload(mapchunk_t* chunk) { + // for(uint8_t i = 0; i < CHUNK_ENTITY_COUNT_MAX; i++) { + // if(chunk->entities[i] == 0xFF) break; + // entity_t *entity = &ENTITIES[chunk->entities[i]]; + // entity->type = ENTITY_TYPE_NULL; + // } + + for(uint8_t i = 0; i < chunk->meshCount; i++) { + if(chunk->meshes[i].vertexCount == 0) continue; + meshDispose(&chunk->meshes[i]); + } +} + +errorret_t mapChunkLoad(mapchunk_t* chunk) { + if(!mapIsLoaded()) errorThrow("No map loaded"); + + char_t buffer[64]; + + // TODO: Can probably move this to asset load logic? + chunk->meshCount = 0; + memoryZero(chunk->meshes, sizeof(chunk->meshes)); + memorySet(chunk->entities, 0xFF, sizeof(chunk->entities)); + + // Get chunk filepath. + snprintf(buffer, sizeof(buffer), "%s/chunks/%d_%d_%d.dcf", + MAP.dirPath, + chunk->position.x, + chunk->position.y, + chunk->position.z + ); + + // Chunk available? + if(!assetFileExists(buffer)) { + memoryZero(chunk->tiles, sizeof(chunk->tiles)); + errorOk(); + } + + // Load. + errorChain(assetLoad(buffer, chunk)); + errorOk(); +} + +chunkindex_t mapGetChunkIndexAt(const chunkpos_t position) { + if(!mapIsLoaded()) return -1; + + chunkpos_t relPos = { + position.x - MAP.chunkPosition.x, + position.y - MAP.chunkPosition.y, + position.z - MAP.chunkPosition.z + }; + + if( + relPos.x < 0 || relPos.y < 0 || relPos.z < 0 || + relPos.x >= MAP_CHUNK_WIDTH || + relPos.y >= MAP_CHUNK_HEIGHT || + relPos.z >= MAP_CHUNK_DEPTH + ) { + return -1; + } + + return chunkPosToIndex(&relPos); +} + +mapchunk_t* mapGetChunk(const uint8_t index) { + if(index >= MAP_CHUNK_COUNT) return NULL; + if(!mapIsLoaded()) return NULL; + return MAP.chunkOrder[index]; +} + +maptile_t mapGetTile(const worldpos_t position) { + if(!mapIsLoaded()) return TILE_SHAPE_NULL; + + chunkpos_t chunkPos; + worldPosToChunkPos(&position, &chunkPos); + chunkindex_t chunkIndex = mapGetChunkIndexAt(chunkPos); + if(chunkIndex == -1) return TILE_SHAPE_NULL; + + mapchunk_t *chunk = mapGetChunk(chunkIndex); + assertNotNull(chunk, "Chunk pointer cannot be NULL"); + chunktileindex_t tileIndex = worldPosToChunkTileIndex(&position); + return chunk->tiles[tileIndex]; +} \ No newline at end of file diff --git a/src/map/map.h b/src/map/map.h new file mode 100644 index 0000000..339c364 --- /dev/null +++ b/src/map/map.h @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "mapchunk.h" + +#define MAP_FILE_PATH_MAX 128 + +typedef struct map_s { + char_t filePath[MAP_FILE_PATH_MAX]; + char_t dirPath[MAP_FILE_PATH_MAX]; + char_t fileName[MAP_FILE_PATH_MAX]; + + mapchunk_t chunks[MAP_CHUNK_COUNT]; + mapchunk_t *chunkOrder[MAP_CHUNK_COUNT]; + chunkpos_t chunkPosition; +} map_t; + +extern map_t MAP; + +/** + * Initializes the map. + * + * @return An error code. + */ +errorret_t mapInit(); + +/** + * Checks if a map is loaded. + * + * @return true if a map is loaded, false otherwise. + */ +bool_t mapIsLoaded(); + +/** + * Loads a map from the given file path. + * + * @param path The file path. + * @param position The initial chunk position. + * @return An error code. + */ +errorret_t mapLoad(const char_t *path, const chunkpos_t position); + +/** + * Updates the map. + */ +void mapUpdate(); + +/** + * Disposes of the map. + */ +void mapDispose(); + +/** + * Sets the map position and updates chunks accordingly. + * + * @param newPos The new chunk position. + * @return An error code. + */ +errorret_t mapPositionSet(const chunkpos_t newPos); + +/** + * Unloads a chunk. + * + * @param chunk The chunk to unload. + */ +void mapChunkUnload(mapchunk_t* chunk); + +/** + * Loads a chunk. + * + * @param chunk The chunk to load. + * @return An error code. + */ +errorret_t mapChunkLoad(mapchunk_t* chunk); + +/** + * Gets the index of a chunk, within the world, at the given position. + * + * @param position The chunk position. + * @return The index of the chunk, or -1 if out of bounds. + */ +chunkindex_t mapGetChunkIndexAt(const chunkpos_t position); + +/** + * Gets a chunk by its index. + * + * @param chunkIndex The index of the chunk. + * @return A pointer to the chunk. + */ +mapchunk_t * mapGetChunk(const uint8_t chunkIndex); + +/** + * Gets the tile at the given world position. + * + * @param position The world position. + * @return The tile at that position, or TILE_NULL if the chunk is unloaded. + */ +maptile_t mapGetTile(const worldpos_t position); \ No newline at end of file diff --git a/src/map/mapchunk.c b/src/map/mapchunk.c new file mode 100644 index 0000000..20f004b --- /dev/null +++ b/src/map/mapchunk.c @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "mapchunk.h" + +uint32_t mapChunkGetTileindex(const chunkpos_t position) { + return ( + (position.z * CHUNK_WIDTH * CHUNK_HEIGHT) + + (position.y * CHUNK_WIDTH) + + position.x + ); +} + +bool_t mapChunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b) { + return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); +} \ No newline at end of file diff --git a/src/map/mapchunk.h b/src/map/mapchunk.h new file mode 100644 index 0000000..0fd53b1 --- /dev/null +++ b/src/map/mapchunk.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "maptile.h" +#include "worldpos.h" +#include "display/mesh/quad.h" + +typedef struct chunk_s { + chunkpos_t position; + maptile_t tiles[CHUNK_TILE_COUNT]; + + uint8_t meshCount; + meshvertex_t vertices[CHUNK_VERTEX_COUNT_MAX]; + mesh_t meshes[CHUNK_MESH_COUNT_MAX]; + uint8_t entities[CHUNK_ENTITY_COUNT_MAX]; +} mapchunk_t; + +/** + * Gets the tile index for a tile position within a chunk. + * + * @param position The position within the chunk. + * @return The tile index within the chunk. + */ +uint32_t mapChunkGetTileindex(const chunkpos_t position); + +/** + * Checks if two chunk positions are equal. + * + * @param a The first chunk position. + * @param b The second chunk position. + * @return true if equal, false otherwise. + */ +bool_t mapChunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b); \ No newline at end of file diff --git a/src/map/maptile.c b/src/map/maptile.c new file mode 100644 index 0000000..15280a8 --- /dev/null +++ b/src/map/maptile.c @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "maptile.h" + +bool_t mapTileIsWalkable(const maptile_t tile) { + switch(tile) { + case TILE_SHAPE_NULL: + return false; + + default: + return true; + } +} + +bool_t mapTileIsRamp(const maptile_t tile) { + switch(tile) { + case TILE_SHAPE_RAMP_NORTH: + case TILE_SHAPE_RAMP_SOUTH: + case TILE_SHAPE_RAMP_EAST: + case TILE_SHAPE_RAMP_WEST: + case TILE_SHAPE_RAMP_NORTHEAST: + case TILE_SHAPE_RAMP_NORTHWEST: + case TILE_SHAPE_RAMP_SOUTHEAST: + case TILE_SHAPE_RAMP_SOUTHWEST: + return true; + + default: + return false; + } +} \ No newline at end of file diff --git a/src/map/maptile.h b/src/map/maptile.h new file mode 100644 index 0000000..a18ece5 --- /dev/null +++ b/src/map/maptile.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "duskdefs.h" +// #include "rpg/entity/entitydir.h" + +typedef uint8_t maptile_t; + +/** + * Returns whether or not the given tile is walkable. + * + * @param tile The tile to check. + * @return bool_t True if walkable, false if not. + */ +bool_t mapTileIsWalkable(const maptile_t tile); + +/** + * Returns whether or not the given tile is a ramp tile. + * + * @param tile The tile to check. + * @return bool_t True if ramp, false if not. + */ +bool_t mapTileIsRamp(const maptile_t tile); \ No newline at end of file diff --git a/src/map/worldpos.c b/src/map/worldpos.c new file mode 100644 index 0000000..3cdd710 --- /dev/null +++ b/src/map/worldpos.c @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "worldpos.h" +#include "assert/assert.h" + +bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b) { + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out) { + assertNotNull(chunkPos, "Chunk position pointer cannot be NULL"); + assertNotNull(out, "Output world position pointer cannot be NULL"); + + out->x = (worldunit_t)(chunkPos->x * CHUNK_WIDTH); + out->y = (worldunit_t)(chunkPos->y * CHUNK_HEIGHT); + out->z = (worldunit_t)(chunkPos->z * CHUNK_DEPTH); +} + +void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out) { + assertNotNull(worldPos, "World position pointer cannot be NULL"); + assertNotNull(out, "Output chunk position pointer cannot be NULL"); + + if(worldPos->x < 0) { + out->x = (chunkunit_t)((worldPos->x - (CHUNK_WIDTH - 1)) / CHUNK_WIDTH); + } else { + out->x = (chunkunit_t)(worldPos->x / CHUNK_WIDTH); + } + + if(worldPos->y < 0) { + out->y = (chunkunit_t)((worldPos->y - (CHUNK_HEIGHT - 1)) / CHUNK_HEIGHT); + } else { + out->y = (chunkunit_t)(worldPos->y / CHUNK_HEIGHT); + } + + if(worldPos->z < 0) { + out->z = (chunkunit_t)((worldPos->z - (CHUNK_DEPTH - 1)) / CHUNK_DEPTH); + } else { + out->z = (chunkunit_t)(worldPos->z / CHUNK_DEPTH); + } +} + +chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos) { + assertNotNull(worldPos, "World position pointer cannot be NULL"); + + uint8_t localX, localY, localZ; + if(worldPos->x < 0) { + localX = (uint8_t)( + (CHUNK_WIDTH - 1) - ((-worldPos->x - 1) % CHUNK_WIDTH) + ); + } else { + localX = (uint8_t)(worldPos->x % CHUNK_WIDTH); + } + + if(worldPos->y < 0) { + localY = (uint8_t)( + (CHUNK_HEIGHT - 1) - ((-worldPos->y - 1) % CHUNK_HEIGHT) + ); + } else { + localY = (uint8_t)(worldPos->y % CHUNK_HEIGHT); + } + + if(worldPos->z < 0) { + localZ = (uint8_t)( + (CHUNK_DEPTH - 1) - ((-worldPos->z - 1) % CHUNK_DEPTH) + ); + } else { + localZ = (uint8_t)(worldPos->z % CHUNK_DEPTH); + } + + chunktileindex_t chunkTileIndex = (chunktileindex_t)( + (localZ * CHUNK_WIDTH * CHUNK_HEIGHT) + + (localY * CHUNK_WIDTH) + + localX + ); + assertTrue( + chunkTileIndex < CHUNK_TILE_COUNT, + "Calculated chunk tile index is out of bounds" + ); + return chunkTileIndex; +} + +chunkindex_t chunkPosToIndex(const chunkpos_t* pos) { + assertNotNull(pos, "Chunk position pointer cannot be NULL"); + + chunkindex_t chunkIndex = (chunkindex_t)( + (pos->z * MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT) + + (pos->y * MAP_CHUNK_WIDTH) + + pos->x + ); + + return chunkIndex; +} \ No newline at end of file diff --git a/src/map/worldpos.h b/src/map/worldpos.h new file mode 100644 index 0000000..a9432e4 --- /dev/null +++ b/src/map/worldpos.h @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" +#include "duskdefs.h" + +#define CHUNK_TILE_COUNT (CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_DEPTH) + +#define MAP_CHUNK_WIDTH 3 +#define MAP_CHUNK_HEIGHT 3 +#define MAP_CHUNK_DEPTH 3 +#define MAP_CHUNK_COUNT (MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT * MAP_CHUNK_DEPTH) + +typedef int16_t worldunit_t; +typedef int16_t chunkunit_t; +typedef int16_t chunkindex_t; +typedef uint32_t chunktileindex_t; + +typedef int32_t worldunits_t; +typedef int32_t chunkunits_t; + +typedef struct worldpos_s { + worldunit_t x, y, z; +} worldpos_t; + +typedef struct chunkpos_t { + chunkunit_t x, y, z; +} chunkpos_t; + +/** + * Compares two world positions for equality. + * + * @param a The first world position. + * @param b The second world position. + * @return true if equal, false otherwise. + */ +bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b); + +/** + * Converts a world position to a chunk position. + * + * @param worldPos The world position. + * @param out The output chunk position. + */ +void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out); + +/** + * Converts a chunk position to a world position. + * + * @param worldPos The world position. + * @param out The output chunk position. + */ +void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out); + +/** + * Converts a position in world-space to an index inside a chunk that the tile + * resides in. + * + * @param worldPos The world position. + * @return The tile index within the chunk. + */ +chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos); + +/** + * Converts a chunk position to a world position. + * + * @param worldPos The world position. + * @param out The output chunk position. + */ +chunkindex_t chunkPosToIndex(const chunkpos_t* pos); \ No newline at end of file diff --git a/src/overworld/map.c b/src/overworld/map.c deleted file mode 100644 index 2d39c21..0000000 --- a/src/overworld/map.c +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "map.h" -#include "util/memory.h" -#include "util/string.h" -#include "assert/assert.h" - -map_t MAP; - -void mapInit(void) { - memoryZero(&MAP, sizeof(map_t)); -} - -mapentity_t * mapEntityAdd(const mapentitytype_t type) { - assertTrue(type != MAP_ENTITY_TYPE_NULL, "Type cannot be NULL"); - assertTrue(type < MAP_ENTITY_TYPE_COUNT, "Type is out of range"); - - // Find any available entity. - mapentity_t *start = &MAP.entities[0]; - mapentity_t *end = &MAP.entities[MAP_ENTITY_COUNT_MAX]; - do { - if(start->type != MAP_ENTITY_TYPE_NULL) continue; - mapEntityInit(start, type); - return start; - } while(start->type != MAP_ENTITY_TYPE_NULL && ++start < end); - - return NULL; -} - -void mapEntityRemove(mapentity_t *ent) { - assertNotNull(ent, "Ent cannot be NULL"); - assertTrue(ent->type != MAP_ENTITY_TYPE_NULL, "Ent is already NULL"); - assertTrue( - ent >= &MAP.entities[0] && ent < &MAP.entities[MAP_ENTITY_COUNT_MAX], - "Ent is out of range" - ); - - ent->type = MAP_ENTITY_TYPE_NULL; -} - -mapentity_t * mapEntityGetByName(const char_t *name) { - assertNotNull(name, "Name cannot be NULL"); - assertStrLenMax(name, MAP_ENTITY_NAME_MAX_LENGTH, "Name is too long"); - - // Search for the entity by name. - mapentity_t *start = &MAP.entities[0]; - mapentity_t *end = &MAP.entities[MAP_ENTITY_COUNT_MAX]; - do { - if(start->type == MAP_ENTITY_TYPE_NULL) continue; - if(stringCompare(start->name, name) == 0) { - return start; - } - } while(++start < end); - - return NULL; -} \ No newline at end of file diff --git a/src/overworld/map.h b/src/overworld/map.h deleted file mode 100644 index 45fa00e..0000000 --- a/src/overworld/map.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "mapentity.h" - -#define MAP_ENTITY_COUNT_MAX 32 - -typedef struct { - mapentity_t entities[MAP_ENTITY_COUNT_MAX]; -} map_t; - -extern map_t MAP; - -/** - * Initialize the overworld map. - */ -void mapInit(void); \ No newline at end of file diff --git a/src/overworld/mapentity.c b/src/overworld/mapentity.c deleted file mode 100644 index 5206b61..0000000 --- a/src/overworld/mapentity.c +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "mapentity.h" -#include "util/memory.h" -#include "util/string.h" - -void mapEntityInit(mapentity_t *ent, const mapentitytype_t type) { - memoryZero(ent, sizeof(mapentity_t)); - ent->type = type; -} - -void mapEntitySetName(mapentity_t *ent, const char_t *name) { - assertNotNull(ent, "Ent cannot be NULL"); - assertNotNull(name, "Name cannot be NULL"); - assertStrLenMax(name, MAP_ENTITY_NAME_MAX_LENGTH, "Name is too long"); - - stringCopy(ent->name, name, MAP_ENTITY_NAME_MAX_LENGTH); -} \ No newline at end of file diff --git a/src/overworld/mapentity.h b/src/overworld/mapentity.h deleted file mode 100644 index e5ad150..0000000 --- a/src/overworld/mapentity.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -#define MAP_ENTITY_NAME_MAX_LENGTH 16 -#define MAP_ENTITY_SCRIPT_MAX_LENGTH 64 - -typedef enum { - MAP_ENTITY_DIR_NORTH = 0, - MAP_ENTITY_DIR_EAST = 1, - MAP_ENTITY_DIR_SOUTH = 2, - MAP_ENTITY_DIR_WEST = 3, - - MAP_ENTITY_DIR_COUNT = 4, - - MAP_ENTITY_DIR_UP = MAP_ENTITY_DIR_NORTH, - MAP_ENTITY_DIR_RIGHT = MAP_ENTITY_DIR_EAST, - MAP_ENTITY_DIR_DOWN = MAP_ENTITY_DIR_SOUTH, - MAP_ENTITY_DIR_LEFT = MAP_ENTITY_DIR_WEST -} mapentitydir_t; - -typedef enum { - MAP_ENTITY_TYPE_NULL, - - MAP_ENTITY_TYPE_NPC, - - MAP_ENTITY_TYPE_COUNT -} mapentitytype_t; - -typedef struct { - char_t name[MAP_ENTITY_NAME_MAX_LENGTH]; - - // Position within the map - uint16_t x, y; - uint8_t layer; - - // Rendering properties - mapentitydir_t dir; - mapentitytype_t type; - - // Script to execute on interaction - char_t script[MAP_ENTITY_SCRIPT_MAX_LENGTH]; -} mapentity_t; - -/** - * Initialize a map entity to default values. - * - * @param ent The entity to initialize. - * @param type The type of the entity. - */ -void mapEntityInit(mapentity_t *ent, const mapentitytype_t type); \ No newline at end of file diff --git a/src/scene/scene.c b/src/scene/scene.c index 434eeb3..d5a64c5 100644 --- a/src/scene/scene.c +++ b/src/scene/scene.c @@ -22,6 +22,12 @@ errorret_t sceneInit(void) { } errorret_t sceneUpdate(void) { + #if TIME_FIXED == 0 + if(!TIME.dynamicUpdate) { + errorOk(); + } + #endif + lua_getglobal(SCENE.scriptContext.luaState, "sceneUpdate"); if(!lua_isfunction(SCENE.scriptContext.luaState, -1)) { lua_pop(SCENE.scriptContext.luaState, 1);