Add inventory.
This commit is contained in:
1 parent
024ace1078
commit
af5bf987c8
91 files changed
+1105
-136
No files matched your search
+2
-2
@@ -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
|
||||||
|
|||||||
File renamed without changes.
@@ -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;
|
||||||
|
|
||||||
File renamed without changes.
@@ -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)
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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];
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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,
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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"
|
||||||
|
|
||||||
File renamed without changes.
@@ -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
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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"
|
||||||
File renamed without changes.
@@ -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 {
|
||||||
File renamed without changes.
File renamed without changes.
@@ -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)
|
||||||
@@ -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;
|
||||||
File renamed without changes.
@@ -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"
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -10,10 +10,3 @@
|
|||||||
|
|
||||||
#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;
|
|
||||||
File renamed without changes.
@@ -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;
|
||||||
File renamed without changes.
+1
-2
@@ -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')
|
||||||
+2
-1
@@ -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
|
||||||
)
|
)
|
||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+8
-8
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -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
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -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[];
|
||||||
@@ -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)
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
+51
-12
@@ -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 ( \
|
||||||
|
|||||||
+3
-1
@@ -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;
|
||||||
|
|||||||
+3
-3
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-27
@@ -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();
|
||||||
}
|
}
|
||||||
+25
-25
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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