Add inventory.
This commit is contained in:
@@ -13,8 +13,8 @@ option(ENABLE_TESTS "Enable tests" ON)
|
|||||||
|
|
||||||
# Set target system
|
# Set target system
|
||||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||||
# set(DUSK_TARGET_SYSTEM "linux")
|
set(DUSK_TARGET_SYSTEM "linux")
|
||||||
set(DUSK_TARGET_SYSTEM "psp")
|
# set(DUSK_TARGET_SYSTEM "psp")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Prep cache
|
# Prep cache
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "rpg/world/chunk.h"
|
#include "rpg/overworld/chunk.h"
|
||||||
|
|
||||||
typedef struct assetcustom_s assetcustom_t;
|
typedef struct assetcustom_s assetcustom_t;
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "rpg/world/map.h"
|
#include "rpg/overworld/map.h"
|
||||||
#include "display/mesh/mesh.h"
|
#include "display/mesh/mesh.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "rpg/world/map.h"
|
#include "rpg/overworld/map.h"
|
||||||
|
|
||||||
int moduleMapLoad(lua_State *L) {
|
int moduleMapLoad(lua_State *L) {
|
||||||
assertNotNull(L, "Lua state cannot be NULL");
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
@@ -14,4 +14,4 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
# Subdirs
|
# Subdirs
|
||||||
add_subdirectory(cutscene)
|
add_subdirectory(cutscene)
|
||||||
add_subdirectory(entity)
|
add_subdirectory(entity)
|
||||||
add_subdirectory(world)
|
add_subdirectory(overworld)
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
#include "rpg/cutscene/cutscenemode.h"
|
#include "rpg/cutscene/cutscenemode.h"
|
||||||
#include "rpg/world/map.h"
|
#include "rpg/overworld/map.h"
|
||||||
|
|
||||||
entity_t ENTITIES[ENTITY_COUNT];
|
entity_t ENTITIES[ENTITY_COUNT];
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "rpg/world/worldpos.h"
|
#include "rpg/overworld/worldpos.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ENTITY_DIR_UP = ENTITY_DIR_NORTH,
|
ENTITY_DIR_UP = ENTITY_DIR_NORTH,
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "rpg/world/tile.h"
|
#include "rpg/overworld/tile.h"
|
||||||
#include "worldpos.h"
|
#include "worldpos.h"
|
||||||
#include "display/mesh/quad.h"
|
#include "display/mesh/quad.h"
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "rpg/world/chunk.h"
|
#include "rpg/overworld/chunk.h"
|
||||||
|
|
||||||
#define MAP_FILE_PATH_MAX 128
|
#define MAP_FILE_PATH_MAX 128
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "rpg.h"
|
#include "rpg.h"
|
||||||
#include "entity/entity.h"
|
#include "entity/entity.h"
|
||||||
#include "rpg/world/map.h"
|
#include "rpg/overworld/map.h"
|
||||||
#include "rpg/cutscene/cutscenesystem.h"
|
#include "rpg/cutscene/cutscenesystem.h"
|
||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
#include "rpgcamera.h"
|
#include "rpgcamera.h"
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "rpgcamera.h"
|
#include "rpgcamera.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "rpg/entity/entity.h"
|
#include "rpg/entity/entity.h"
|
||||||
#include "rpg/world/map.h"
|
#include "rpg/overworld/map.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
|
||||||
rpgcamera_t RPG_CAMERA;
|
rpgcamera_t RPG_CAMERA;
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "rpg/world/worldpos.h"
|
#include "rpg/overworld/worldpos.h"
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
13
archive/scene/CMakeLists.txt
Normal file
13
archive/scene/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_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
scenemanager.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(scene)
|
||||||
24
archive/scene/scene.h
Normal file
24
archive/scene/scene.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "display/color.h"
|
||||||
|
|
||||||
|
#define SCENE_FLAG_INITIALIZED (1 << 0)
|
||||||
|
|
||||||
|
typedef struct scenedata_s scenedata_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char_t *name;
|
||||||
|
errorret_t (*init)(scenedata_t *data);
|
||||||
|
void (*update)(scenedata_t *data);
|
||||||
|
void (*render)(scenedata_t *data);
|
||||||
|
void (*dispose)(scenedata_t *data);
|
||||||
|
uint8_t flags;
|
||||||
|
} scene_t;
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "rpg/entity/entity.h"
|
#include "rpg/entity/entity.h"
|
||||||
#include "rpg/world/map.h"
|
#include "rpg/overworld/map.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen.h"
|
||||||
#include "rpg/rpgcamera.h"
|
#include "rpg/rpgcamera.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
@@ -9,11 +9,4 @@
|
|||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
|
|
||||||
#include "scene/scene/scenetest.h"
|
#include "scene/scene/scenetest.h"
|
||||||
#include "scene/scene/scenemap.h"
|
#include "scene/scene/scenemap.h"
|
||||||
|
|
||||||
typedef struct scenedata_s {
|
|
||||||
union {
|
|
||||||
scenetest_t sceneTest;
|
|
||||||
scenemap_t sceneMap;
|
|
||||||
};
|
|
||||||
} scenedata_t;
|
|
||||||
@@ -15,7 +15,6 @@ typedef struct {
|
|||||||
scene_t *current;
|
scene_t *current;
|
||||||
scene_t *scenes[SCENE_MANAGER_SCENE_COUNT_MAX];
|
scene_t *scenes[SCENE_MANAGER_SCENE_COUNT_MAX];
|
||||||
uint8_t sceneCount;
|
uint8_t sceneCount;
|
||||||
scenedata_t sceneData;
|
|
||||||
} scenemanager_t;
|
} scenemanager_t;
|
||||||
|
|
||||||
extern scenemanager_t SCENE_MANAGER;
|
extern scenemanager_t SCENE_MANAGER;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
module('platform')
|
module('platform')
|
||||||
module('input')
|
module('input')
|
||||||
module('scene')
|
module('scene')
|
||||||
module('map')
|
|
||||||
|
|
||||||
-- Default Input bindings.
|
-- Default Input bindings.
|
||||||
if PLATFORM == "psp" then
|
if PLATFORM == "psp" then
|
||||||
@@ -39,4 +38,4 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
sceneSet('map')
|
sceneSet('map')
|
||||||
mapLoad('map/testmap/testmap.dmf')
|
-- mapLoad('map/testmap/testmap.dmf')
|
||||||
@@ -56,8 +56,9 @@ add_subdirectory(display)
|
|||||||
add_subdirectory(engine)
|
add_subdirectory(engine)
|
||||||
add_subdirectory(error)
|
add_subdirectory(error)
|
||||||
add_subdirectory(input)
|
add_subdirectory(input)
|
||||||
|
add_subdirectory(item)
|
||||||
add_subdirectory(locale)
|
add_subdirectory(locale)
|
||||||
add_subdirectory(rpg)
|
# add_subdirectory(rpg)
|
||||||
add_subdirectory(scene)
|
add_subdirectory(scene)
|
||||||
add_subdirectory(script)
|
add_subdirectory(script)
|
||||||
add_subdirectory(thread)
|
add_subdirectory(thread)
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
#include "type/assetpaletteimage.h"
|
#include "type/assetpaletteimage.h"
|
||||||
#include "type/assetalphaimage.h"
|
#include "type/assetalphaimage.h"
|
||||||
#include "type/assetlanguage.h"
|
#include "type/assetlanguage.h"
|
||||||
#include "type/assetmap.h"
|
|
||||||
#include "type/assetchunk.h"
|
|
||||||
#include "type/assetscript.h"
|
#include "type/assetscript.h"
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
@@ -20,8 +18,6 @@ typedef enum {
|
|||||||
ASSET_TYPE_PALETTE_IMAGE,
|
ASSET_TYPE_PALETTE_IMAGE,
|
||||||
ASSET_TYPE_ALPHA_IMAGE,
|
ASSET_TYPE_ALPHA_IMAGE,
|
||||||
ASSET_TYPE_LANGUAGE,
|
ASSET_TYPE_LANGUAGE,
|
||||||
ASSET_TYPE_MAP,
|
|
||||||
ASSET_TYPE_CHUNK,
|
|
||||||
ASSET_TYPE_SCRIPT,
|
ASSET_TYPE_SCRIPT,
|
||||||
|
|
||||||
ASSET_TYPE_COUNT,
|
ASSET_TYPE_COUNT,
|
||||||
@@ -72,19 +68,6 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
|||||||
.custom = assetLanguageHandler
|
.custom = assetLanguageHandler
|
||||||
},
|
},
|
||||||
|
|
||||||
[ASSET_TYPE_MAP] = {
|
|
||||||
.header = "DMF",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
|
||||||
.dataSize = sizeof(1),
|
|
||||||
.entire = assetMapLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_CHUNK] = {
|
|
||||||
.header = "DCF",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
|
||||||
.custom = assetChunkLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_SCRIPT] = {
|
[ASSET_TYPE_SCRIPT] = {
|
||||||
.header = "DSF",
|
.header = "DSF",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||||
|
|||||||
@@ -9,7 +9,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
assetalphaimage.c
|
assetalphaimage.c
|
||||||
assetpaletteimage.c
|
assetpaletteimage.c
|
||||||
assetlanguage.c
|
assetlanguage.c
|
||||||
assetmap.c
|
|
||||||
assetchunk.c
|
|
||||||
assetscript.c
|
assetscript.c
|
||||||
)
|
)
|
||||||
@@ -45,7 +45,7 @@ typedef color4b_t color_t;
|
|||||||
#define color4b(r, g, b, a) ((color4b_t){r, g, b, a})
|
#define color4b(r, g, b, a) ((color4b_t){r, g, b, a})
|
||||||
#define color(r, g, b, a) ((color_t){r, g, b, a})
|
#define color(r, g, b, a) ((color_t){r, g, b, a})
|
||||||
|
|
||||||
#define color_hex(hex) color( \
|
#define colorHex(hex) color( \
|
||||||
((hex >> 24) & 0xFF), \
|
((hex >> 24) & 0xFF), \
|
||||||
((hex >> 16) & 0xFF), \
|
((hex >> 16) & 0xFF), \
|
||||||
((hex >> 8) & 0xFF), \
|
((hex >> 8) & 0xFF), \
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "display/framebuffer.h"
|
#include "display/framebuffer.h"
|
||||||
#include "scene/scenemanager.h"
|
#include "scene/scene.h"
|
||||||
#include "display/spritebatch.h"
|
#include "display/spritebatch.h"
|
||||||
#include "display/mesh/quad.h"
|
#include "display/mesh/quad.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen.h"
|
||||||
@@ -120,7 +120,9 @@ errorret_t displayUpdate(void) {
|
|||||||
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
|
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
|
||||||
COLOR_CORNFLOWER_BLUE
|
COLOR_CORNFLOWER_BLUE
|
||||||
);
|
);
|
||||||
sceneManagerRender();
|
sceneRender();
|
||||||
|
|
||||||
|
// Render UI
|
||||||
uiRender();
|
uiRender();
|
||||||
|
|
||||||
// Finish up
|
// Finish up
|
||||||
|
|||||||
@@ -11,10 +11,10 @@
|
|||||||
#include "input/input.h"
|
#include "input/input.h"
|
||||||
#include "locale/localemanager.h"
|
#include "locale/localemanager.h"
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "scene/scenemanager.h"
|
#include "scene/scene.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "rpg/rpg.h"
|
// #include "rpg/rpg.h"
|
||||||
#include "script/scriptmanager.h"
|
#include "script/scriptmanager.h"
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
errorChain(scriptManagerInit());
|
errorChain(scriptManagerInit());
|
||||||
errorChain(displayInit());
|
errorChain(displayInit());
|
||||||
errorChain(uiInit());
|
errorChain(uiInit());
|
||||||
errorChain(rpgInit());
|
// errorChain(rpgInit());
|
||||||
errorChain(sceneManagerInit());
|
errorChain(sceneInit());
|
||||||
|
|
||||||
// Run the initial script.
|
// Run the initial script.
|
||||||
scriptcontext_t ctx;
|
scriptcontext_t ctx;
|
||||||
@@ -51,9 +51,9 @@ errorret_t engineUpdate(void) {
|
|||||||
timeUpdate();
|
timeUpdate();
|
||||||
inputUpdate();
|
inputUpdate();
|
||||||
|
|
||||||
errorChain(rpgUpdate());
|
// errorChain(rpgUpdate());
|
||||||
uiUpdate();
|
uiUpdate();
|
||||||
sceneManagerUpdate();
|
sceneUpdate();
|
||||||
errorChain(displayUpdate());
|
errorChain(displayUpdate());
|
||||||
|
|
||||||
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
|
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
|
||||||
@@ -67,8 +67,8 @@ void engineExit(void) {
|
|||||||
|
|
||||||
errorret_t engineDispose(void) {
|
errorret_t engineDispose(void) {
|
||||||
localeManagerDispose();
|
localeManagerDispose();
|
||||||
sceneManagerDispose();
|
// sceneManagerDispose();
|
||||||
rpgDispose();
|
// rpgDispose();
|
||||||
uiDispose();
|
uiDispose();
|
||||||
errorChain(displayDispose());
|
errorChain(displayDispose());
|
||||||
assetDispose();
|
assetDispose();
|
||||||
|
|||||||
11
src/item/CMakeLists.txt
Normal file
11
src/item/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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
|
||||||
|
item.c
|
||||||
|
inventory.c
|
||||||
|
)
|
||||||
165
src/item/inventory.c
Normal file
165
src/item/inventory.c
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 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,
|
||||||
|
inventorystack_t* storage,
|
||||||
|
uint8_t storageSize
|
||||||
|
) {
|
||||||
|
assertNotNull(inventory, "Inventory pointer is NULL.");
|
||||||
|
assertNotNull(storage, "Storage pointer is NULL.");
|
||||||
|
assertTrue(storageSize > 0, "Storage size must be greater than zero.");
|
||||||
|
|
||||||
|
inventory->storage = storage;
|
||||||
|
inventory->storageSize = storageSize;
|
||||||
|
|
||||||
|
// Zero item ids.
|
||||||
|
memoryZero(inventory->storage, sizeof(inventorystack_t) * storageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t inventoryItemExists(const inventory_t *inventory, const itemid_t item) {
|
||||||
|
assertNotNull(inventory, "Inventory pointer is NULL.");
|
||||||
|
assertNotNull(inventory->storage, "Storage pointer is NULL.");
|
||||||
|
assertTrue(inventory->storageSize > 0, "Storage too small.");
|
||||||
|
assertTrue(item != ITEM_ID_NULL, "Item ID cannot be ITEM_ID_NULL.");
|
||||||
|
|
||||||
|
inventorystack_t *stack = inventory->storage;
|
||||||
|
inventorystack_t *end = stack + inventory->storageSize;
|
||||||
|
do {
|
||||||
|
if(stack->item == ITEM_ID_NULL) break;
|
||||||
|
if(stack->item != item) continue;
|
||||||
|
assertTrue(stack->quantity > 0, "Item has quantity zero.");
|
||||||
|
return true;
|
||||||
|
} while(++stack < end);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inventorySet(
|
||||||
|
inventory_t *inventory,
|
||||||
|
const itemid_t item,
|
||||||
|
const uint8_t quantity
|
||||||
|
) {
|
||||||
|
assertNotNull(inventory, "Inventory pointer is NULL.");
|
||||||
|
assertNotNull(inventory->storage, "Storage pointer is NULL.");
|
||||||
|
assertTrue(inventory->storageSize > 0, "Storage too small.");
|
||||||
|
assertTrue(item != ITEM_ID_NULL, "Item ID cannot be ITEM_ID_NULL.");
|
||||||
|
|
||||||
|
// If quantity 0, remove.
|
||||||
|
if(quantity == 0) return inventoryRemove(inventory, item);
|
||||||
|
|
||||||
|
// Search for existing stack.
|
||||||
|
inventorystack_t *stack = inventory->storage;
|
||||||
|
inventorystack_t *end = stack + inventory->storageSize;
|
||||||
|
do {
|
||||||
|
// Not in inventory yet, add as new stack.
|
||||||
|
if(stack->item == ITEM_ID_NULL) {
|
||||||
|
stack->item = item;
|
||||||
|
stack->quantity = quantity;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not the stack we're looking for.
|
||||||
|
if(stack->item != item) continue;
|
||||||
|
|
||||||
|
// Update existing stack.
|
||||||
|
stack->quantity = quantity;
|
||||||
|
return;
|
||||||
|
} while(++stack < end);
|
||||||
|
|
||||||
|
// No space in the inventory.
|
||||||
|
assertUnreachable("Inventory is full, cannot set more items.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void inventoryAdd(
|
||||||
|
inventory_t *inventory,
|
||||||
|
const itemid_t item,
|
||||||
|
const uint8_t quantity
|
||||||
|
) {
|
||||||
|
uint8_t current = inventoryGetCount(inventory, item);
|
||||||
|
uint16_t newQuantity = (uint16_t)current + (uint16_t)quantity;
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
newQuantity <= UINT8_MAX,
|
||||||
|
"Cannot add item, would overflow maximum quantity."
|
||||||
|
);
|
||||||
|
|
||||||
|
inventorySet(inventory, item, (uint8_t)newQuantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inventoryRemove(inventory_t *inventory, const itemid_t item) {
|
||||||
|
assertNotNull(inventory, "Inventory pointer is NULL.");
|
||||||
|
assertNotNull(inventory->storage, "Storage pointer is NULL.");
|
||||||
|
assertTrue(inventory->storageSize > 0, "Storage too small.");
|
||||||
|
assertTrue(item != ITEM_ID_NULL, "Item ID cannot be ITEM_ID_NULL.");
|
||||||
|
|
||||||
|
inventorystack_t *stack = inventory->storage;
|
||||||
|
inventorystack_t *end = stack + inventory->storageSize;
|
||||||
|
|
||||||
|
// Search for existing stack.
|
||||||
|
do {
|
||||||
|
// End of inventory, item not present.
|
||||||
|
if(stack->item == ITEM_ID_NULL) break;
|
||||||
|
|
||||||
|
// Not matching stack.
|
||||||
|
if(stack->item != item) continue;
|
||||||
|
|
||||||
|
// Match found, shift everything else down
|
||||||
|
memoryMove(stack, stack + 1, end - (stack + 1));
|
||||||
|
|
||||||
|
// Clear last stack.
|
||||||
|
inventorystack_t *last = end - 1;
|
||||||
|
last->item = ITEM_ID_NULL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} while(++stack < end);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inventoryGetCount(const inventory_t *inventory, const itemid_t item) {
|
||||||
|
assertNotNull(inventory, "Inventory pointer is NULL.");
|
||||||
|
assertNotNull(inventory->storage, "Storage pointer is NULL.");
|
||||||
|
assertTrue(inventory->storageSize > 0, "Storage too small.");
|
||||||
|
assertTrue(item != ITEM_ID_NULL, "Item ID cannot be ITEM_ID_NULL.");
|
||||||
|
|
||||||
|
inventorystack_t *stack = inventory->storage;
|
||||||
|
inventorystack_t *end = stack + inventory->storageSize;
|
||||||
|
do {
|
||||||
|
// End of inventory, item not present.
|
||||||
|
if(stack->item == ITEM_ID_NULL) break;
|
||||||
|
|
||||||
|
// Not matching stack.
|
||||||
|
if(stack->item != item) continue;
|
||||||
|
|
||||||
|
// Match found, return quantity.
|
||||||
|
return stack->quantity;
|
||||||
|
} while(++stack < end);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t inventoryIsFull(const inventory_t *inventory) {
|
||||||
|
assertNotNull(inventory, "Inventory pointer is NULL.");
|
||||||
|
assertNotNull(inventory->storage, "Storage pointer is NULL.");
|
||||||
|
assertTrue(inventory->storageSize > 0, "Storage too small.");
|
||||||
|
|
||||||
|
inventorystack_t *stack = inventory->storage;
|
||||||
|
inventorystack_t *end = stack + inventory->storageSize;
|
||||||
|
do {
|
||||||
|
// Found empty stack, not full.
|
||||||
|
if(stack->item == ITEM_ID_NULL) return false;
|
||||||
|
} while(++stack < end);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t inventoryItemFull(const inventory_t *inventory, const itemid_t item) {
|
||||||
|
return inventoryGetCount(inventory, item) == ITEM_STACK_QUANTITY_MAX;
|
||||||
|
}
|
||||||
103
src/item/inventory.h
Normal file
103
src/item/inventory.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "item.h"
|
||||||
|
|
||||||
|
#define ITEM_STACK_QUANTITY_MAX UINT8_MAX
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
itemid_t item;
|
||||||
|
uint8_t quantity;
|
||||||
|
} inventorystack_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
inventorystack_t *storage;
|
||||||
|
uint8_t storageSize;
|
||||||
|
} inventory_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an inventory.
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to initialize.
|
||||||
|
* @param storage The storage array for the inventory.
|
||||||
|
* @param storageSize The size of the storage array.
|
||||||
|
*/
|
||||||
|
void inventoryInit(
|
||||||
|
inventory_t* inventory,
|
||||||
|
inventorystack_t* storage,
|
||||||
|
uint8_t storageSize
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a specific item exists in the inventory (and has quantity > 0).
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to check.
|
||||||
|
* @param item The item ID to check.
|
||||||
|
* @return true if the item exists, false otherwise.
|
||||||
|
*/
|
||||||
|
bool_t inventoryItemExists(const inventory_t *inventory, const itemid_t item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the quantity of a specific item in the inventory.
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to modify.
|
||||||
|
* @param item The item ID to set.
|
||||||
|
* @param quantity The quantity to set.
|
||||||
|
*/
|
||||||
|
void inventorySet(
|
||||||
|
inventory_t *inventory,
|
||||||
|
const itemid_t item,
|
||||||
|
const uint8_t quantity
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a specific quantity of an item to the inventory.
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to modify.
|
||||||
|
* @param item The item ID to add.
|
||||||
|
* @param quantity The quantity to add.
|
||||||
|
*/
|
||||||
|
void inventoryAdd(
|
||||||
|
inventory_t *inventory,
|
||||||
|
const itemid_t item,
|
||||||
|
const uint8_t quantity
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an item from the inventory.
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to modify.
|
||||||
|
* @param item The item ID to remove.
|
||||||
|
*/
|
||||||
|
void inventoryRemove(inventory_t *inventory, const itemid_t item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the count of a specific item in the inventory.
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to check.
|
||||||
|
* @param item The item ID to check.
|
||||||
|
* @return The count of the item in the inventory.
|
||||||
|
*/
|
||||||
|
uint8_t inventoryGetCount(const inventory_t *inventory, const itemid_t item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the inventory is full.
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to check.
|
||||||
|
* @return true if full, false otherwise.
|
||||||
|
*/
|
||||||
|
bool_t inventoryIsFull(const inventory_t *inventory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a specific item stack is full in the inventory.
|
||||||
|
*
|
||||||
|
* @param inventory The inventory to check.
|
||||||
|
* @param item The item ID to check.
|
||||||
|
* @return true if the item stack is full, false otherwise.
|
||||||
|
*/
|
||||||
|
bool_t inventoryItemFull(const inventory_t *inventory, const itemid_t item);
|
||||||
19
src/item/item.c
Normal file
19
src/item/item.c
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "item.h"
|
||||||
|
|
||||||
|
const item_t ITEMS[] = {
|
||||||
|
[ITEM_ID_NULL] = {
|
||||||
|
.type = ITEM_TYPE_NULL
|
||||||
|
},
|
||||||
|
|
||||||
|
// Potion
|
||||||
|
[ITEM_ID_POTION] = {
|
||||||
|
.type = ITEM_TYPE_MEDICINE
|
||||||
|
},
|
||||||
|
};
|
||||||
21
src/item/item.h
Normal file
21
src/item/item.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 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;
|
||||||
|
} item_t;
|
||||||
|
|
||||||
|
typedef uint8_t itemid_t;
|
||||||
|
|
||||||
|
#define ITEM_ID_NULL 0
|
||||||
|
#define ITEM_ID_POTION 1
|
||||||
|
#define ITEM_ID_POTATO 2
|
||||||
|
|
||||||
|
extern const item_t ITEMS[];
|
||||||
19
src/item/itemtype.h
Normal file
19
src/item/itemtype.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 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,
|
||||||
|
|
||||||
|
ITEM_TYPE_MEDICINE,
|
||||||
|
ITEM_TYPE_INGREDIENT,
|
||||||
|
ITEM_TYPE_KEYITEM,
|
||||||
|
|
||||||
|
ITEM_TYPE_COUNT
|
||||||
|
} itemtype_t;
|
||||||
@@ -6,8 +6,5 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
scenemanager.c
|
scene.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
|
||||||
add_subdirectory(scene)
|
|
||||||
84
src/scene/scene.c
Normal file
84
src/scene/scene.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) 2026 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
#include "scene.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
const scene_t SCENES[] = {
|
||||||
|
};
|
||||||
|
|
||||||
|
uint_fast8_t SCENE_CURRENT = 0xFF;
|
||||||
|
|
||||||
|
errorret_t sceneInit(void) {
|
||||||
|
// Initialize the scene subsystem here
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sceneUpdate(void) {
|
||||||
|
const scene_t *current = sceneGetCurrent();
|
||||||
|
if(current && current->update) {
|
||||||
|
current->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sceneRender(void) {
|
||||||
|
const scene_t *current = sceneGetCurrent();
|
||||||
|
|
||||||
|
if(current && current->render) {
|
||||||
|
current->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sceneDispose(void) {
|
||||||
|
const scene_t *current = sceneGetCurrent();
|
||||||
|
|
||||||
|
if(current && current->dispose) {
|
||||||
|
current->dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t sceneSet(const scene_t *scene) {
|
||||||
|
sceneDispose();
|
||||||
|
|
||||||
|
if(scene) {
|
||||||
|
SCENE_CURRENT = (uint_fast8_t)(scene - SCENES);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
SCENE_CURRENT < sizeof(SCENES) / sizeof(scene_t),
|
||||||
|
"Invalid scene index."
|
||||||
|
);
|
||||||
|
|
||||||
|
if(scene->init) {
|
||||||
|
errorret_t err = scene->init();
|
||||||
|
if(err.code != ERROR_OK) SCENE_CURRENT = 0xFF;
|
||||||
|
errorChain(err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SCENE_CURRENT = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
const scene_t* sceneGetCurrent(void) {
|
||||||
|
if(SCENE_CURRENT == 0xFF) return NULL;
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
SCENE_CURRENT < sizeof(SCENES) / sizeof(scene_t),
|
||||||
|
"Invalid current scene index."
|
||||||
|
);
|
||||||
|
|
||||||
|
return &SCENES[SCENE_CURRENT];
|
||||||
|
}
|
||||||
|
|
||||||
|
const scene_t* sceneGetByName(const char_t *name) {
|
||||||
|
for(uint_fast8_t i = 0; i < sizeof(SCENES) / sizeof(scene_t); i++) {
|
||||||
|
if(stringCompare(SCENES[i].name, name) == 0) {
|
||||||
|
return &SCENES[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -1,24 +1,63 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2025 Dominic Masters
|
* Copyright (c) 2026 Dominic Masters
|
||||||
*
|
*
|
||||||
* This software is released under the MIT License.
|
* This software is released under the MIT License.
|
||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "display/color.h"
|
|
||||||
|
|
||||||
#define SCENE_FLAG_INITIALIZED (1 << 0)
|
|
||||||
|
|
||||||
typedef struct scenedata_s scenedata_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char_t *name;
|
const char_t *name;
|
||||||
errorret_t (*init)(scenedata_t *data);
|
errorret_t (*init)(void);
|
||||||
void (*update)(scenedata_t *data);
|
void (*update)(void);
|
||||||
void (*render)(scenedata_t *data);
|
void (*render)(void);
|
||||||
void (*dispose)(scenedata_t *data);
|
void (*dispose)(void);
|
||||||
uint8_t flags;
|
} scene_t;
|
||||||
} scene_t;
|
|
||||||
|
extern const scene_t SCENES[];
|
||||||
|
extern uint_fast8_t SCENE_CURRENT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the scene subsystem.
|
||||||
|
*/
|
||||||
|
errorret_t sceneInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the current scene.
|
||||||
|
*/
|
||||||
|
void sceneUpdate(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the current scene.
|
||||||
|
*/
|
||||||
|
void sceneRender(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose of the scene subsystem.
|
||||||
|
*/
|
||||||
|
void sceneDispose(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current scene.
|
||||||
|
*
|
||||||
|
* @param sceneIndex The index of the scene to set.
|
||||||
|
* @return An error code indicating success or failure.
|
||||||
|
*/
|
||||||
|
errorret_t sceneSet(const scene_t *scene);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current scene.
|
||||||
|
*
|
||||||
|
* @return The current scene.
|
||||||
|
*/
|
||||||
|
const scene_t* sceneGetCurrent(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a scene by its name.
|
||||||
|
*
|
||||||
|
* @param name The name of the scene.
|
||||||
|
* @return The scene with the given name, or NULL if not found.
|
||||||
|
*/
|
||||||
|
const scene_t* sceneGetByName(const char_t *name);
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
#include "scene/scenemanager.h"
|
#include "scene/scene.h"
|
||||||
|
|
||||||
int moduleSceneSetScene(lua_State *L) {
|
int moduleSceneSetScene(lua_State *L) {
|
||||||
assertNotNull(L, "Lua state cannot be NULL");
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
@@ -20,13 +20,13 @@ int moduleSceneSetScene(lua_State *L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_t *scene = sceneManagerGetSceneByName(sceneName);
|
const scene_t *scene = sceneGetByName(sceneName);
|
||||||
if(scene == NULL) {
|
if(scene == NULL) {
|
||||||
luaL_error(L, "Scene '%s' not found", sceneName);
|
luaL_error(L, "Scene '%s' not found", sceneName);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t err = sceneManagerSetScene(scene);
|
errorret_t err = sceneSet(scene);
|
||||||
if(err.code != ERROR_OK) {
|
if(err.code != ERROR_OK) {
|
||||||
luaL_error(L, "Failed to set scene '%s'", sceneName);
|
luaL_error(L, "Failed to set scene '%s'", sceneName);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -10,14 +10,12 @@
|
|||||||
#include "script/module/moduleinput.h"
|
#include "script/module/moduleinput.h"
|
||||||
#include "script/module/moduleplatform.h"
|
#include "script/module/moduleplatform.h"
|
||||||
#include "script/module/modulescene.h"
|
#include "script/module/modulescene.h"
|
||||||
#include "script/module/modulemap.h"
|
|
||||||
|
|
||||||
const scriptmodule_t SCRIPT_MODULE_LIST[] = {
|
const scriptmodule_t SCRIPT_MODULE_LIST[] = {
|
||||||
{ .name = "system", .callback = moduleSystem },
|
{ .name = "system", .callback = moduleSystem },
|
||||||
{ .name = "input", .callback = moduleInput },
|
{ .name = "input", .callback = moduleInput },
|
||||||
{ .name = "platform", .callback = modulePlatform },
|
{ .name = "platform", .callback = modulePlatform },
|
||||||
{ .name = "scene", .callback = moduleScene },
|
{ .name = "scene", .callback = moduleScene },
|
||||||
{ .name = "map", .callback = moduleMapSystem },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCRIPT_MODULE_COUNT ( \
|
#define SCRIPT_MODULE_COUNT ( \
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ void timeInit(void) {
|
|||||||
TIME.dynamicTime = TIME_STEP;
|
TIME.dynamicTime = TIME_STEP;
|
||||||
TIME.dynamicDelta = TIME_STEP;
|
TIME.dynamicDelta = TIME_STEP;
|
||||||
TIME.dynamicUpdate = false;
|
TIME.dynamicUpdate = false;
|
||||||
|
TIME.lastNonDynamic = TIME.dynamicTime;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +45,9 @@ void timeUpdate(void) {
|
|||||||
assertTrue(TIME.dynamicDelta >= 0.0f, "Time delta is negative");
|
assertTrue(TIME.dynamicDelta >= 0.0f, "Time delta is negative");
|
||||||
|
|
||||||
// Is within 1ms of a full step?
|
// Is within 1ms of a full step?
|
||||||
if(TIME.dynamicTime - TIME.time >= TIME_STEP * 0.999f) {
|
if(TIME.dynamicTime - TIME.lastNonDynamic >= TIME_STEP * 0.999f) {
|
||||||
TIME.dynamicUpdate = false;
|
TIME.dynamicUpdate = false;
|
||||||
|
TIME.lastNonDynamic = TIME.dynamicTime;
|
||||||
TIME.delta = TIME_STEP;
|
TIME.delta = TIME_STEP;
|
||||||
TIME.time += TIME_STEP;
|
TIME.time += TIME_STEP;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ typedef struct {
|
|||||||
float_t time;
|
float_t time;
|
||||||
|
|
||||||
#if TIME_FIXED == 0
|
#if TIME_FIXED == 0
|
||||||
|
float_t lastNonDynamic;
|
||||||
bool_t dynamicUpdate;
|
bool_t dynamicUpdate;
|
||||||
float_t dynamicDelta;
|
float_t dynamicDelta;
|
||||||
float_t dynamicTime;
|
float_t dynamicTime;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "display/tileset/tileset_minogram.h"
|
#include "display/tileset/tileset_minogram.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen.h"
|
||||||
#include "ui/uitextbox.h"
|
// #include "ui/uitextbox.h"
|
||||||
|
|
||||||
ui_t UI;
|
ui_t UI;
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ void uiUpdate(void) {
|
|||||||
UI.camera.orthographic.top = 0;
|
UI.camera.orthographic.top = 0;
|
||||||
UI.camera.orthographic.bottom = SCREEN.height;
|
UI.camera.orthographic.bottom = SCREEN.height;
|
||||||
|
|
||||||
uiTextboxUpdate();
|
// uiTextboxUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiRender(void) {
|
void uiRender(void) {
|
||||||
@@ -42,7 +42,7 @@ void uiRender(void) {
|
|||||||
// Render UI elements here
|
// Render UI elements here
|
||||||
if(UI.fontTexture.width > 0) {
|
if(UI.fontTexture.width > 0) {
|
||||||
uiDebugRender(UI.fontTileset, &UI.fontTexture);
|
uiDebugRender(UI.fontTileset, &UI.fontTexture);
|
||||||
uiTextboxRender();
|
// uiTextboxRender();
|
||||||
}
|
}
|
||||||
cameraPopMatrix();
|
cameraPopMatrix();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "ui/uitext.h"
|
#include "ui/uitext.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen.h"
|
||||||
#include "display/spritebatch.h"
|
#include "display/spritebatch.h"
|
||||||
#include "rpg/entity/entity.h"
|
// #include "rpg/entity/entity.h"
|
||||||
|
|
||||||
bool_t UI_DEBUG_DRAW = true;
|
bool_t UI_DEBUG_DRAW = true;
|
||||||
|
|
||||||
@@ -67,32 +67,32 @@ void uiDebugRender(const tileset_t *tileset, texture_t *texture) {
|
|||||||
|
|
||||||
|
|
||||||
// Player position
|
// Player position
|
||||||
entity_t *player = NULL;
|
// entity_t *player = NULL;
|
||||||
for(uint8_t i = 0; i < ENTITY_COUNT; i++) {
|
// for(uint8_t i = 0; i < ENTITY_COUNT; i++) {
|
||||||
if(ENTITIES[i].type != ENTITY_TYPE_PLAYER) continue;
|
// if(ENTITIES[i].type != ENTITY_TYPE_PLAYER) continue;
|
||||||
player = &ENTITIES[i];
|
// player = &ENTITIES[i];
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
if(player == NULL) {
|
// if(player == NULL) {
|
||||||
snprintf(buffer, sizeof(buffer), "Player: N/A");
|
// snprintf(buffer, sizeof(buffer), "Player: N/A");
|
||||||
} else {
|
// } else {
|
||||||
snprintf(
|
// snprintf(
|
||||||
buffer,
|
// buffer,
|
||||||
sizeof(buffer),
|
// sizeof(buffer),
|
||||||
"%d,%d,%d/%d/%d",
|
// "%d,%d,%d/%d/%d",
|
||||||
player->position.x,
|
// player->position.x,
|
||||||
player->position.y,
|
// player->position.y,
|
||||||
player->position.z,
|
// player->position.z,
|
||||||
(int32_t)player->direction,
|
// (int32_t)player->direction,
|
||||||
(int32_t)player->animation
|
// (int32_t)player->animation
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
uiTextMeasure(buffer, tileset, &w, &h);
|
// uiTextMeasure(buffer, tileset, &w, &h);
|
||||||
uiTextDraw(
|
// uiTextDraw(
|
||||||
SCREEN.width - w, hOffset,
|
// SCREEN.width - w, hOffset,
|
||||||
buffer, COLOR_GREEN, tileset, texture
|
// buffer, COLOR_GREEN, tileset, texture
|
||||||
);
|
// );
|
||||||
hOffset += h;
|
// hOffset += h;
|
||||||
|
|
||||||
spriteBatchFlush();
|
spriteBatchFlush();
|
||||||
}
|
}
|
||||||
@@ -8,38 +8,38 @@
|
|||||||
#include "uitextbox.h"
|
#include "uitextbox.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "ui/uitext.h"
|
#include "ui/uitext.h"
|
||||||
#include "rpg/rpgtextbox.h"
|
// #include "rpg/rpgtextbox.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen.h"
|
||||||
#include "display/spritebatch.h"
|
#include "display/spritebatch.h"
|
||||||
#include "input/input.h"
|
#include "input/input.h"
|
||||||
|
|
||||||
void uiTextboxUpdate() {
|
// void uiTextboxUpdate() {
|
||||||
if(!rpgTextboxIsVisible()) return;
|
// if(!rpgTextboxIsVisible()) return;
|
||||||
|
|
||||||
if(inputPressed(INPUT_ACTION_ACCEPT)) {
|
// if(inputPressed(INPUT_ACTION_ACCEPT)) {
|
||||||
rpgTextboxHide();
|
// rpgTextboxHide();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
void uiTextboxRender() {
|
// void uiTextboxRender() {
|
||||||
if(!rpgTextboxIsVisible()) return;
|
// if(!rpgTextboxIsVisible()) return;
|
||||||
|
|
||||||
const char_t *text = RPG_TEXTBOX.text;
|
// const char_t *text = RPG_TEXTBOX.text;
|
||||||
int32_t textWidth, textHeight;
|
// int32_t textWidth, textHeight;
|
||||||
|
|
||||||
uiTextMeasure(text, UI.fontTileset, &textWidth, &textHeight);
|
// uiTextMeasure(text, UI.fontTileset, &textWidth, &textHeight);
|
||||||
|
|
||||||
float_t y = 0;
|
// float_t y = 0;
|
||||||
if(RPG_TEXTBOX.position == RPG_TEXTBOX_POS_BOTTOM) {
|
// if(RPG_TEXTBOX.position == RPG_TEXTBOX_POS_BOTTOM) {
|
||||||
y = SCREEN.height - (float_t)textHeight;
|
// y = SCREEN.height - (float_t)textHeight;
|
||||||
}
|
// }
|
||||||
|
|
||||||
spriteBatchPush(
|
// spriteBatchPush(
|
||||||
NULL,
|
// NULL,
|
||||||
0.0f, y,
|
// 0.0f, y,
|
||||||
(float_t)SCREEN.width, (float_t)(y + textHeight),
|
// (float_t)SCREEN.width, (float_t)(y + textHeight),
|
||||||
COLOR_BLACK,
|
// COLOR_BLACK,
|
||||||
0.0f, 0.0f, 1.0f, 1.0f
|
// 0.0f, 0.0f, 1.0f, 1.0f
|
||||||
);
|
// );
|
||||||
uiTextDraw(0, y, text, COLOR_RED, UI.fontTileset, &UI.fontTexture);
|
// uiTextDraw(0, y, text, COLOR_RED, UI.fontTileset, &UI.fontTexture);
|
||||||
}
|
// }
|
||||||
@@ -3,5 +3,8 @@
|
|||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
add_subdirectory(display)
|
||||||
|
# add_subdirectory(rpg)
|
||||||
|
add_subdirectory(item)
|
||||||
add_subdirectory(time)
|
add_subdirectory(time)
|
||||||
add_subdirectory(util)
|
add_subdirectory(util)
|
||||||
9
test/display/CMakeLists.txt
Normal file
9
test/display/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
include(dusktest)
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
dusktest(test_color.c)
|
||||||
98
test/display/test_color.c
Normal file
98
test/display/test_color.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dusktest.h"
|
||||||
|
#include "display/color.h"
|
||||||
|
|
||||||
|
static void test_color3f_create(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
color3f_t color = color3f(0.1f, 0.2f, 0.3f);
|
||||||
|
assert_float_equal(color.r, 0.1f, 0.0001f);
|
||||||
|
assert_float_equal(color.g, 0.2f, 0.0001f);
|
||||||
|
assert_float_equal(color.b, 0.3f, 0.0001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_color4f_create(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
color4f_t color = color4f(0.1f, 0.2f, 0.3f, 0.4f);
|
||||||
|
assert_float_equal(color.r, 0.1f, 0.0001f);
|
||||||
|
assert_float_equal(color.g, 0.2f, 0.0001f);
|
||||||
|
assert_float_equal(color.b, 0.3f, 0.0001f);
|
||||||
|
assert_float_equal(color.a, 0.4f, 0.0001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_color3b_create(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
color3b_t color = color3b(10, 20, 30);
|
||||||
|
assert_int_equal(color.r, 10);
|
||||||
|
assert_int_equal(color.g, 20);
|
||||||
|
assert_int_equal(color.b, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_color4b_create(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
color4b_t color = color4b(10, 20, 30, 40);
|
||||||
|
assert_int_equal(color.r, 10);
|
||||||
|
assert_int_equal(color.g, 20);
|
||||||
|
assert_int_equal(color.b, 30);
|
||||||
|
assert_int_equal(color.a, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_color_create(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
color_t color = color(10, 20, 30, 40);
|
||||||
|
assert_int_equal(color.r, 10);
|
||||||
|
assert_int_equal(color.g, 20);
|
||||||
|
assert_int_equal(color.b, 30);
|
||||||
|
assert_int_equal(color.a, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_colorHex_create(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
color_t color = colorHex(0x11223344);
|
||||||
|
assert_int_equal(color.r, 0x11);
|
||||||
|
assert_int_equal(color.g, 0x22);
|
||||||
|
assert_int_equal(color.b, 0x33);
|
||||||
|
assert_int_equal(color.a, 0x44);
|
||||||
|
|
||||||
|
color = colorHex(0xFF00FF00);
|
||||||
|
assert_int_equal(color.r, 0xFF);
|
||||||
|
assert_int_equal(color.g, 0x00);
|
||||||
|
assert_int_equal(color.b, 0xFF);
|
||||||
|
assert_int_equal(color.a, 0x00);
|
||||||
|
|
||||||
|
color_t comp = color(255, 0, 255, 0);
|
||||||
|
assert_int_equal(color.r, comp.r);
|
||||||
|
assert_int_equal(color.g, comp.g);
|
||||||
|
assert_int_equal(color.b, comp.b);
|
||||||
|
assert_int_equal(color.a, comp.a);
|
||||||
|
|
||||||
|
color = colorHex(0xFFFFFFFF);
|
||||||
|
assert_int_equal(color.r, COLOR_WHITE.r);
|
||||||
|
assert_int_equal(color.g, COLOR_WHITE.g);
|
||||||
|
assert_int_equal(color.b, COLOR_WHITE.b);
|
||||||
|
assert_int_equal(color.a, COLOR_WHITE.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(test_color3f_create),
|
||||||
|
cmocka_unit_test(test_color4f_create),
|
||||||
|
cmocka_unit_test(test_color3b_create),
|
||||||
|
cmocka_unit_test(test_color4b_create),
|
||||||
|
cmocka_unit_test(test_color_create),
|
||||||
|
cmocka_unit_test(test_colorHex_create),
|
||||||
|
};
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
||||||
9
test/item/CMakeLists.txt
Normal file
9
test/item/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
include(dusktest)
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
dusktest(test_inventory.c)
|
||||||
341
test/item/test_inventory.c
Normal file
341
test/item/test_inventory.c
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dusktest.h"
|
||||||
|
#include "item/inventory.h"
|
||||||
|
|
||||||
|
static void test_inventoryInit(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[5];
|
||||||
|
inventory_t inventory;
|
||||||
|
|
||||||
|
inventoryInit(&inventory, storage, 5);
|
||||||
|
|
||||||
|
// Should setup struct
|
||||||
|
assert_non_null(inventory.storage);
|
||||||
|
assert_int_equal(inventory.storageSize, 5);
|
||||||
|
|
||||||
|
// Should zero the item ids.
|
||||||
|
for(size_t i = 0; i < inventory.storageSize; i++) {
|
||||||
|
assert_int_equal(inventory.storage[i].item, ITEM_ID_NULL);
|
||||||
|
assert_int_equal(inventory.storage[i].quantity, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventoryInit(NULL, storage, 5));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
expect_assert_failure(inventoryInit(&inventory, NULL, 5));
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
expect_assert_failure(inventoryInit(&inventory, storage, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_inventoryItemExists(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[5];
|
||||||
|
inventory_t inventory;
|
||||||
|
inventoryInit(&inventory, storage, 5);
|
||||||
|
|
||||||
|
// Initially should not exist
|
||||||
|
assert_false(inventoryItemExists(&inventory, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Add item
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 3);
|
||||||
|
assert_true(inventoryItemExists(&inventory, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Remove item
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 0);
|
||||||
|
assert_false(inventoryItemExists(&inventory, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventoryItemExists(NULL, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
inventory.storage = NULL;
|
||||||
|
expect_assert_failure(inventoryItemExists(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storage = storage;
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
inventory.storageSize = 0;
|
||||||
|
expect_assert_failure(inventoryItemExists(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storageSize = 5;
|
||||||
|
|
||||||
|
// Should fail when given ITEM_ID_NULL
|
||||||
|
expect_assert_failure(inventoryItemExists(&inventory, ITEM_ID_NULL));
|
||||||
|
|
||||||
|
// Should fail if item has zero quantity somehow
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 3);
|
||||||
|
inventory.storage[0].quantity = 0;
|
||||||
|
expect_assert_failure(inventoryItemExists(&inventory, ITEM_ID_POTION));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_inventorySet(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[5];
|
||||||
|
inventory_t inventory;
|
||||||
|
inventoryInit(&inventory, storage, 5);
|
||||||
|
|
||||||
|
// Set item quantity
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 4);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[0].quantity, 4);
|
||||||
|
|
||||||
|
// Update item quantity
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 2);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[0].quantity, 2);
|
||||||
|
|
||||||
|
// Remove item by setting quantity to 0
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 0);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_NULL);
|
||||||
|
|
||||||
|
// Setting multiple items should not cause issues
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 1);
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTATO, 5);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[0].quantity, 1);
|
||||||
|
assert_int_equal(inventory.storage[1].item, ITEM_ID_POTATO);
|
||||||
|
assert_int_equal(inventory.storage[1].quantity, 5);
|
||||||
|
|
||||||
|
// Setting early item to 0 should shift others down
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 0);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_POTATO);
|
||||||
|
assert_int_equal(inventory.storage[0].quantity, 5);
|
||||||
|
assert_int_equal(inventory.storage[1].item, ITEM_ID_NULL);
|
||||||
|
|
||||||
|
// Setting non-existing item should add it
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 3);
|
||||||
|
assert_int_equal(inventory.storage[1].item, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[1].quantity, 3);
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventorySet(NULL, ITEM_ID_POTION, 3));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
inventory.storage = NULL;
|
||||||
|
expect_assert_failure(inventorySet(&inventory, ITEM_ID_POTION, 3));
|
||||||
|
inventory.storage = storage;
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
inventory.storageSize = 0;
|
||||||
|
expect_assert_failure(inventorySet(&inventory, ITEM_ID_POTION, 3));
|
||||||
|
inventory.storageSize = 5;
|
||||||
|
|
||||||
|
// Should fail when given ITEM_ID_NULL
|
||||||
|
expect_assert_failure(inventorySet(&inventory, ITEM_ID_NULL, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_inventoryAdd(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[5];
|
||||||
|
inventory_t inventory;
|
||||||
|
inventoryInit(&inventory, storage, 5);
|
||||||
|
|
||||||
|
// Add item quantity
|
||||||
|
inventoryAdd(&inventory, ITEM_ID_POTION, 4);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[0].quantity, 4);
|
||||||
|
|
||||||
|
// Add more to existing item
|
||||||
|
inventoryAdd(&inventory, ITEM_ID_POTION, 3);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[0].quantity, 7);
|
||||||
|
|
||||||
|
// Adding item that would overflow should assert
|
||||||
|
expect_assert_failure(inventoryAdd(&inventory, ITEM_ID_POTION, 250));
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventoryAdd(NULL, ITEM_ID_POTION, 3));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
inventory.storage = NULL;
|
||||||
|
expect_assert_failure(inventoryAdd(&inventory, ITEM_ID_POTION, 3));
|
||||||
|
inventory.storage = storage;
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
inventory.storageSize = 0;
|
||||||
|
expect_assert_failure(inventoryAdd(&inventory, ITEM_ID_POTION, 3));
|
||||||
|
inventory.storageSize = 5;
|
||||||
|
|
||||||
|
// Should fail when given ITEM_ID_NULL
|
||||||
|
expect_assert_failure(inventoryAdd(&inventory, ITEM_ID_NULL, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_inventoryRemove(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[5];
|
||||||
|
inventory_t inventory;
|
||||||
|
inventoryInit(&inventory, storage, 5);
|
||||||
|
|
||||||
|
// Add item and then remove it
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 5);
|
||||||
|
inventoryRemove(&inventory, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_NULL);
|
||||||
|
|
||||||
|
// Removing non-existing item should do nothing
|
||||||
|
inventoryRemove(&inventory, ITEM_ID_POTION);
|
||||||
|
assert_int_equal(inventory.storage[0].item, ITEM_ID_NULL);
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventoryRemove(NULL, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
inventory.storage = NULL;
|
||||||
|
expect_assert_failure(inventoryRemove(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storage = storage;
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
inventory.storageSize = 0;
|
||||||
|
expect_assert_failure(inventoryRemove(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storageSize = 5;
|
||||||
|
|
||||||
|
// Should fail when given ITEM_ID_NULL
|
||||||
|
expect_assert_failure(inventoryRemove(&inventory, ITEM_ID_NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_inventoryGetCount(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[5];
|
||||||
|
inventory_t inventory;
|
||||||
|
inventoryInit(&inventory, storage, 5);
|
||||||
|
|
||||||
|
// Initially should be zero
|
||||||
|
assert_int_equal(inventoryGetCount(&inventory, ITEM_ID_POTION), 0);
|
||||||
|
|
||||||
|
// Add item and check count
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 4);
|
||||||
|
assert_int_equal(inventoryGetCount(&inventory, ITEM_ID_POTION), 4);
|
||||||
|
|
||||||
|
// Update item quantity and check count
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 2);
|
||||||
|
assert_int_equal(inventoryGetCount(&inventory, ITEM_ID_POTION), 2);
|
||||||
|
|
||||||
|
// Remove item and check count
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 0);
|
||||||
|
assert_int_equal(inventoryGetCount(&inventory, ITEM_ID_POTION), 0);
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventoryGetCount(NULL, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
inventory.storage = NULL;
|
||||||
|
expect_assert_failure(inventoryGetCount(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storage = storage;
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
inventory.storageSize = 0;
|
||||||
|
expect_assert_failure(inventoryGetCount(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storageSize = 5;
|
||||||
|
|
||||||
|
// Should fail when given ITEM_ID_NULL
|
||||||
|
expect_assert_failure(inventoryGetCount(&inventory, ITEM_ID_NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_inventoryIsFull(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[2];
|
||||||
|
inventory_t inventory;
|
||||||
|
inventoryInit(&inventory, storage, 2);
|
||||||
|
|
||||||
|
// Initially should not be full
|
||||||
|
assert_false(inventoryIsFull(&inventory));
|
||||||
|
|
||||||
|
// Fill inventory
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 1);
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTATO, 1);
|
||||||
|
assert_true(inventoryIsFull(&inventory));
|
||||||
|
|
||||||
|
// Remove one item
|
||||||
|
inventoryRemove(&inventory, ITEM_ID_POTION);
|
||||||
|
assert_false(inventoryIsFull(&inventory));
|
||||||
|
|
||||||
|
// Add one item back
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 1);
|
||||||
|
assert_true(inventoryIsFull(&inventory));
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventoryIsFull(NULL));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
inventory.storage = NULL;
|
||||||
|
expect_assert_failure(inventoryIsFull(&inventory));
|
||||||
|
inventory.storage = storage;
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
inventory.storageSize = 0;
|
||||||
|
expect_assert_failure(inventoryIsFull(&inventory));
|
||||||
|
inventory.storageSize = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_inventoryItemFull(void **state) {
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
inventorystack_t storage[2];
|
||||||
|
inventory_t inventory;
|
||||||
|
inventoryInit(&inventory, storage, 2);
|
||||||
|
|
||||||
|
// Initially should not be full
|
||||||
|
assert_false(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Add some potions, but not too many.
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 100);
|
||||||
|
assert_false(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Fill with potions
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, ITEM_STACK_QUANTITY_MAX);
|
||||||
|
assert_true(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Add potatoes, should not affect potions
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTATO, 50);
|
||||||
|
assert_true(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
assert_false(inventoryItemFull(&inventory, ITEM_ID_POTATO));
|
||||||
|
|
||||||
|
// Remove some potions
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTION, 200);
|
||||||
|
assert_false(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Fill with potatoes
|
||||||
|
inventorySet(&inventory, ITEM_ID_POTATO, ITEM_STACK_QUANTITY_MAX);
|
||||||
|
assert_false(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
assert_true(inventoryItemFull(&inventory, ITEM_ID_POTATO));
|
||||||
|
|
||||||
|
// Should fail when given NULL inventory pointer
|
||||||
|
expect_assert_failure(inventoryItemFull(NULL, ITEM_ID_POTION));
|
||||||
|
|
||||||
|
// Should fail when given NULL storage pointer
|
||||||
|
inventory.storage = NULL;
|
||||||
|
expect_assert_failure(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storage = storage;
|
||||||
|
|
||||||
|
// Should fail when given zero storage size
|
||||||
|
inventory.storageSize = 0;
|
||||||
|
expect_assert_failure(inventoryItemFull(&inventory, ITEM_ID_POTION));
|
||||||
|
inventory.storageSize = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(test_inventoryInit),
|
||||||
|
cmocka_unit_test(test_inventoryItemExists),
|
||||||
|
cmocka_unit_test(test_inventorySet),
|
||||||
|
cmocka_unit_test(test_inventoryAdd),
|
||||||
|
cmocka_unit_test(test_inventoryRemove),
|
||||||
|
cmocka_unit_test(test_inventoryGetCount),
|
||||||
|
cmocka_unit_test(test_inventoryIsFull),
|
||||||
|
cmocka_unit_test(test_inventoryItemFull),
|
||||||
|
};
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
||||||
12
test/rpg/CMakeLists.txt
Normal file
12
test/rpg/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
include(dusktest)
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
dusktest(test_rpg.c)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(overworld)
|
||||||
10
test/rpg/overworld/CMakeLists.txt
Normal file
10
test/rpg/overworld/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
include(dusktest)
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
16
test/rpg/test_rpg.c
Normal file
16
test/rpg/test_rpg.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dusktest.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
// Add RPG tests here in the future
|
||||||
|
};
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
||||||
@@ -100,17 +100,17 @@ static void test_timeUpdate(void **state) {
|
|||||||
assert_float_equal(TIME.delta, TIME_STEP, 0.0001f);
|
assert_float_equal(TIME.delta, TIME_STEP, 0.0001f);
|
||||||
assert_float_equal(TIME.time, TIME_STEP * 4, 0.0001f);
|
assert_float_equal(TIME.time, TIME_STEP * 4, 0.0001f);
|
||||||
|
|
||||||
// Fifth test, despite a small time passing the game should be trying to catch
|
// Fifth test, despite a small time passing the game should not start
|
||||||
// and running extra ticks
|
// trying to run ahead
|
||||||
SDL_GETTICKS_TICKS = 104; // Simulate 4ms elapsed
|
SDL_GETTICKS_TICKS = 104; // Simulate 4ms elapsed
|
||||||
SDL_GETTICKS_CALLED = false;
|
SDL_GETTICKS_CALLED = false;
|
||||||
timeUpdate();
|
timeUpdate();
|
||||||
assert_true(SDL_GETTICKS_CALLED);
|
assert_true(SDL_GETTICKS_CALLED);
|
||||||
assert_false(TIME.dynamicUpdate);
|
assert_true(TIME.dynamicUpdate);
|
||||||
assert_float_equal(TIME.dynamicDelta, 0.004f, 0.0001f);
|
assert_float_equal(TIME.dynamicDelta, 0.004f, 0.0001f);
|
||||||
assert_float_equal(TIME.dynamicTime, TIME_STEP + 0.104f, 0.0001f);
|
assert_float_equal(TIME.dynamicTime, TIME_STEP + 0.104f, 0.0001f);
|
||||||
assert_float_equal(TIME.delta, TIME_STEP, 0.0001f);
|
assert_float_equal(TIME.delta, TIME_STEP, 0.0001f);
|
||||||
assert_float_equal(TIME.time, TIME_STEP * 5, 0.0001f);
|
assert_float_equal(TIME.time, TIME_STEP * 4, 0.0001f);
|
||||||
|
|
||||||
// Time can stand still if needed
|
// Time can stand still if needed
|
||||||
SDL_GETTICKS_CALLED = false;
|
SDL_GETTICKS_CALLED = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user