item
Some checks failed
Build Dusk / run-tests (push) Failing after 1m31s
Build Dusk / build-linux (push) Failing after 1m8s
Build Dusk / build-psp (push) Failing after 1m32s

This commit is contained in:
2026-01-25 15:01:25 -06:00
parent e1d7b7308f
commit f71c271c97
17 changed files with 480 additions and 51 deletions

View File

@@ -18,11 +18,6 @@ errorret_t assetInit(void) {
// Engine may have been provided the launch path
if(ENGINE.argc > 0) {
// This first arg is the executable, so on most platforms it is say
// "/path/file" or "C:\Path\file.exe". On PSP this would be something
// like "ms0:/PSP/GAME/DUSK/EBOOT.PBP" or if we are debugging it is
// "host0:/Dusk.prx"
// Get the directory of the executable
char_t buffer[FILENAME_MAX];
stringCopy(buffer, ENGINE.argv[0], FILENAME_MAX);
@@ -55,11 +50,15 @@ errorret_t assetInit(void) {
// Default system path, intended to be overridden by the platform
stringCopy(ASSET.systemPath, ".", FILENAME_MAX);
// PSP specific time.
// PSP specific asset loading.
#if PSP
assertTrue(ENGINE.argc >= 1, "PSP requires launch argument.");
// PSP is given either host0:/Dusk.prx (debugging) OR the PBP file.
// PSP is given either the prx OR the PBP file.
// In the format of "ms0:/PSP/GAME/DUSK/EBOOT.PBP" or "host0:/Dusk.prx"
// IF the file is the PBP file, we are loading directly on the PSP itself.
// IF the file is the .prx then we are debugging and fopen will return
// relative filepaths correctly, e.g. host0:/dusk.dsk will be on host.
if(
stringEndsWithCaseInsensitive(ENGINE.argv[0], ".pbp") ||
ASSET_PBP_READ_PBP_FROM_HOST
@@ -143,7 +142,6 @@ errorret_t assetInit(void) {
}
#endif
// Open zip file
char_t searchPath[FILENAME_MAX];
const char_t **path = ASSET_SEARCH_PATHS;

View File

@@ -56,6 +56,7 @@ typedef struct {
char_t systemPath[FILENAME_MAX];
uint8_t assetCount;
// PSP specific information.
#if PSP
FILE *pbpFile;
assetpbp_t pbpHeader;

View File

@@ -17,6 +17,7 @@
// #include "rpg/rpg.h"
#include "script/scriptmanager.h"
#include "debug/debug.h"
#include "item/backpack.h"
engine_t ENGINE;
@@ -38,6 +39,8 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
// errorChain(rpgInit());
errorChain(sceneInit());
backpackInit();
// Run the initial script.
scriptcontext_t ctx;
errorChain(scriptContextInit(&ctx));

View File

@@ -24,44 +24,6 @@ void inputInit(void) {
}
INPUT.deadzone = 0.2f;
// Setup Default Binds
// #if INPUT_SDL2 == 1
// #if INPUT_KEYBOARD == 1
// inputBind(inputButtonGetByName("up"), INPUT_ACTION_UP);
// inputBind(inputButtonGetByName("down"), INPUT_ACTION_DOWN);
// inputBind(inputButtonGetByName("left"), INPUT_ACTION_LEFT);
// inputBind(inputButtonGetByName("right"), INPUT_ACTION_RIGHT);
// inputBind(inputButtonGetByName("w"), INPUT_ACTION_UP);
// inputBind(inputButtonGetByName("s"), INPUT_ACTION_DOWN);
// inputBind(inputButtonGetByName("a"), INPUT_ACTION_LEFT);
// inputBind(inputButtonGetByName("d"), INPUT_ACTION_RIGHT);
// inputBind(inputButtonGetByName("enter"), INPUT_ACTION_ACCEPT);
// inputBind(inputButtonGetByName("escape"), INPUT_ACTION_RAGEQUIT);
// inputBind(inputButtonGetByName("space"), INPUT_ACTION_ACCEPT);
// inputBind(inputButtonGetByName("backspace"), INPUT_ACTION_CANCEL);
// inputBind(inputButtonGetByName("e"), INPUT_ACTION_ACCEPT);
// inputBind(inputButtonGetByName("q"), INPUT_ACTION_CANCEL);
// #endif
// #if INPUT_GAMEPAD == 1
// #if PSP
// INPUT.deadzone = 0.2890625f;// Taken from the PSP firmware
// inputBind(inputButtonGetByName("up"), INPUT_ACTION_UP);
// inputBind(inputButtonGetByName("down"), INPUT_ACTION_DOWN);
// inputBind(inputButtonGetByName("left"), INPUT_ACTION_LEFT);
// inputBind(inputButtonGetByName("right"), INPUT_ACTION_RIGHT);
// inputBind(inputButtonGetByName("circle"), INPUT_ACTION_CANCEL);
// inputBind(inputButtonGetByName("cross"), INPUT_ACTION_ACCEPT);
// inputBind(inputButtonGetByName("lstick_negative_y"), INPUT_ACTION_UP);
// inputBind(inputButtonGetByName("lstick_positive_y"), INPUT_ACTION_DOWN);
// inputBind(inputButtonGetByName("lstick_negative_x"), INPUT_ACTION_LEFT);
// inputBind(inputButtonGetByName("lstick_positive_x"), INPUT_ACTION_RIGHT);
// inputBind(inputButtonGetByName("select"), INPUT_ACTION_RAGEQUIT);
// #endif
// #endif
// #endif
}
void inputUpdate(void) {

View File

@@ -3,9 +3,29 @@
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
include(cmake/modules/csvtoenum.cmake)
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
item.c
inventory.c
)
backpack.c
)
# Generate itemtype_t enum from CSV
set(ITEM_CSV "${CMAKE_CURRENT_LIST_DIR}/itemtypes.csv")
set(ITEM_HEADER "${CMAKE_CURRENT_LIST_DIR}/itemtypes2.h")
csvtoenum(${ITEM_CSV} ${ITEM_HEADER} itemtype_t id ITEM_TYPE_)
add_custom_command(
OUTPUT ${OUTPUT_FULL_PATH}
COMMAND ${CMAKE_COMMAND}
-DENV_FILE=${INPUT_FULL_PATH}
-DOUT_HEADER=${OUTPUT_FULL_PATH}
-P ${CMAKE_SOURCE_DIR}/cmake/modules/envtoh.cmake
DEPENDS ${INPUT_FULL_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules/envtoh.cmake
COMMENT "Generating ${OUTPUT_NAME_RELATIVE}"
)
add_custom_target(${OUTPUT_NAME_RELATIVE}_header DEPENDS ${OUTPUT_FULL_PATH})
add_dependencies(${DUSK_LIBRARY_TARGET_NAME} ${OUTPUT_NAME_RELATIVE}_header)

15
src/item/backpack.c Normal file
View File

@@ -0,0 +1,15 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "backpack.h"
inventorystack_t BACKPACK_STORAGE[BACKPACK_STORAGE_SIZE_MAX];
inventory_t BACKPACK;
void backpackInit() {
inventoryInit(&BACKPACK, BACKPACK_STORAGE, BACKPACK_STORAGE_SIZE_MAX);
}

View File

@@ -6,4 +6,14 @@
*/
#pragma once
#include "inventory.h"
#include "inventory.h"
#define BACKPACK_STORAGE_SIZE_MAX 20
extern inventorystack_t BACKPACK_STORAGE[BACKPACK_STORAGE_SIZE_MAX];
extern inventory_t BACKPACK;
/**
* Initializes the backpack inventory for the player.
*/
void backpackInit();

4
src/item/item.csv Normal file
View File

@@ -0,0 +1,4 @@
id,type,
POTION,MEDICINE,
POTATO,FOOD,
APPLE,FOOD,
1 id type
2 POTION MEDICINE
3 POTATO FOOD
4 APPLE FOOD

View File

@@ -0,0 +1,259 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/scriptcontext.h"
#include "item/inventory.h"
#include "item/backpack.h"
int moduleInventoryItemExists(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Expect inventory pointer and item ID
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventoryItemExists: Expected inventory pointer as first argument");
return 0;
}
if(!lua_isinteger(L, 2)) {
luaL_error(L, "inventoryItemExists: Expected item ID as second argument");
return 0;
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
itemid_t item = (itemid_t)lua_tointeger(L, 2);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
// Error if item is ITEM_ID_NULL
if(item == ITEM_ID_NULL) {
luaL_error(L, "inventoryItemExists: Item ID cannot be ITEM_ID_NULL");
return 0;
}
bool_t hasItem = inventoryItemExists(inventory, item);
lua_pushboolean(L, hasItem);
return 1;
}
int moduleInventorySet(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Requires inventory pointer, item ID and quantity (uint8_t)
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventorySet: Expected inventory pointer as first argument");
return 0;
}
if(!lua_isinteger(L, 2)) {
luaL_error(L, "inventorySet: Expected item ID as second argument");
return 0;
}
if(!lua_isinteger(L, 3)) {
luaL_error(L, "inventorySet: Expected quantity as third argument");
return 0;
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
itemid_t item = (itemid_t)lua_tointeger(L, 2);
uint8_t quantity = (uint8_t)lua_tointeger(L, 3);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
inventorySet(inventory, item, quantity);
return 0;
}
int moduleInventoryAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Requires inventory pointer, item ID and quantity (uint8_t)
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventoryAdd: Expected inventory pointer as first argument");
return 0;
}
if(!lua_isinteger(L, 2)) {
luaL_error(L, "inventoryAdd: Expected item ID as second argument");
return 0;
}
if(!lua_isinteger(L, 3)) {
luaL_error(L, "inventoryAdd: Expected quantity as third argument");
return 0;
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
itemid_t item = (itemid_t)lua_tointeger(L, 2);
uint8_t quantity = (uint8_t)lua_tointeger(L, 3);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
inventoryAdd(inventory, item, quantity);
return 0;
}
int moduleInventoryRemove(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Requires inventory pointer and item ID
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventoryRemove: Expected inventory pointer as first argument");
return 0;
}
if(!lua_isinteger(L, 2)) {
luaL_error(L, "inventoryRemove: Expected item ID as second argument");
return 0;
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
itemid_t item = (itemid_t)lua_tointeger(L, 2);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
// if there is a third argument (quantity), then we are actually doing a
// partial removal.
if(lua_gettop(L) >= 3) {
if(!lua_isinteger(L, 3)) {
luaL_error(L, "inventoryRemove: Expected quantity as third argument");
return 0;
}
uint8_t amount = (uint8_t)lua_tointeger(L, 3);
uint8_t currentQuantity = inventoryGetCount(inventory, item);
if(amount >= currentQuantity) {
// Remove entire stack
inventoryRemove(inventory, item);
return 0;
}
// Set new quantity
inventorySet(inventory, item, currentQuantity - amount);
return 0;
}
inventoryRemove(inventory, item);
return 0;
}
int moduleInventoryGetCount(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Requires inventory pointer and item ID
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventoryGetCount: Expected inventory pointer as first argument");
return 0;
}
if(!lua_isinteger(L, 2)) {
luaL_error(L, "inventoryGetCount: Expected item ID as second argument");
return 0;
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
itemid_t item = (itemid_t)lua_tointeger(L, 2);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
uint8_t count = inventoryGetCount(inventory, item);
lua_pushinteger(L, count);
return 1;
}
int moduleInventoryIsFull(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Requires inventory pointer
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventoryIsFull: Expected inventory pointer as first argument");
return 0;
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
bool_t isFull = inventoryIsFull(inventory);
lua_pushboolean(L, isFull);
return 1;
}
int moduleInventoryItemFull(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Requires inventory pointer and item ID
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventoryItemFull: Expected inventory pointer as first argument");
return 0;
}
if(!lua_isinteger(L, 2)) {
luaL_error(L, "inventoryItemFull: Expected item ID as second argument");
return 0;
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
itemid_t item = (itemid_t)lua_tointeger(L, 2);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
bool_t isFull = inventoryItemFull(inventory, item);
lua_pushboolean(L, isFull);
return 1;
}
int moduleInventorySort(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Requires inventory pointer, sort type and reverse flag
if(!lua_islightuserdata(L, 1)) {
luaL_error(L, "inventorySort: Expected inventory pointer as first argument");
return 0;
}
if(!lua_isinteger(L, 2)) {
luaL_error(L, "inventorySort: Expected sort type as second argument");
return 0;
}
// Optional, reverse
bool_t reverse = false;
if(lua_gettop(L) >= 3) {
if(!lua_isboolean(L, 3)) {
luaL_error(L, "inventorySort: Expected reverse flag as third argument");
return 0;
}
reverse = (bool_t)lua_toboolean(L, 3);
}
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
inventorysort_t sortBy = (inventorysort_t)lua_tointeger(L, 2);
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
inventorySort(inventory, sortBy, reverse);
return 0;
}
void moduleItem(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
// Item information
// Bind BACKPACK const pointer
scriptContextRegPointer(context, "BACKPACK", (void *)&BACKPACK);
// Bind Methods
scriptContextRegFunc(
context, "inventoryItemExists", moduleInventoryItemExists
);
scriptContextRegFunc(context, "inventoryAdd", moduleInventoryAdd);
scriptContextRegFunc(context, "inventorySet", moduleInventorySet);
scriptContextRegFunc(context, "inventoryRemove", moduleInventoryRemove);
scriptContextRegFunc(context, "inventoryGetCount", moduleInventoryGetCount);
scriptContextRegFunc(context, "inventoryIsFull", moduleInventoryIsFull);
scriptContextRegFunc(context, "inventoryItemFull", moduleInventoryItemFull);
scriptContextRegFunc(context, "inventorySort", moduleInventorySort);
}

View File

@@ -49,6 +49,19 @@ void scriptContextRegFunc(
lua_register(context->luaState, fnName, function);
}
void scriptContextRegPointer(
scriptcontext_t *context,
const char_t *name,
void *pointer
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(name, "Name cannot be NULL");
assertNotNull(pointer, "Pointer cannot be NULL");
lua_pushlightuserdata(context->luaState, pointer);
lua_setglobal(context->luaState, name);
}
errorret_t scriptContextCallFunc(
scriptcontext_t *context,
const char_t *fnName,

View File

@@ -37,6 +37,19 @@ void scriptContextRegFunc(
lua_CFunction function
);
/**
* Register a pointer within a script context.
*
* @param context The script context to use.
* @param name The name of the pointer in Lua.
* @param pointer The pointer to register.
*/
void scriptContextRegPointer(
scriptcontext_t *context,
const char_t *name,
void *pointer
);
/**
* Call a Lua function within a script context.
*

View File

@@ -10,12 +10,14 @@
#include "script/module/moduleinput.h"
#include "script/module/moduleplatform.h"
#include "script/module/modulescene.h"
#include "script/module/moduleitem.h"
const scriptmodule_t SCRIPT_MODULE_LIST[] = {
{ .name = "system", .callback = moduleSystem },
{ .name = "input", .callback = moduleInput },
{ .name = "platform", .callback = modulePlatform },
{ .name = "scene", .callback = moduleScene },
{ .name = "item", .callback = moduleItem },
};
#define SCRIPT_MODULE_COUNT ( \

View File

@@ -42,7 +42,6 @@ void uiRender(void) {
// Render UI elements here
if(UI.fontTexture.width > 0) {
uiDebugRender(UI.fontTileset, &UI.fontTexture);
// uiTextboxRender();
}
cameraPopMatrix();
}