From b08ad308e4ce1b09d1ab8e80cbc1553bd9b8370c Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sat, 11 Jul 2026 11:44:34 -0500 Subject: [PATCH] item but as a file --- {src/dusk/rpg/item => assets}/item.json | 0 src/dusk/engine/engine.c | 2 + src/dusk/rpg/cutscene/cutscene.h | 4 +- .../rpg/cutscene/item/item/cutsceneitemgive.c | 4 +- .../rpg/cutscene/item/item/cutsceneitemgive.h | 4 +- src/dusk/rpg/cutscene/scene/testcutscene.h | 2 +- src/dusk/rpg/item/CMakeLists.txt | 11 +- src/dusk/rpg/item/backpack.c | 28 ++-- src/dusk/rpg/item/backpack.h | 12 +- src/dusk/rpg/item/inventory.c | 8 +- src/dusk/rpg/item/item.c | 133 +++++++++++++++++- src/dusk/rpg/item/item.h | 57 +++++++- src/dusk/rpg/rpg.c | 8 +- src/dusk/ui/frame/backpack/uibackpack.c | 9 +- src/dusk/ui/frame/backpack/uibackpack.h | 2 +- tools/item.py | 114 --------------- 16 files changed, 236 insertions(+), 162 deletions(-) rename {src/dusk/rpg/item => assets}/item.json (100%) delete mode 100644 tools/item.py diff --git a/src/dusk/rpg/item/item.json b/assets/item.json similarity index 100% rename from src/dusk/rpg/item/item.json rename to assets/item.json diff --git a/src/dusk/engine/engine.c b/src/dusk/engine/engine.c index d969a7e6..1c3b1c51 100644 --- a/src/dusk/engine/engine.c +++ b/src/dusk/engine/engine.c @@ -10,6 +10,7 @@ #include "time/time.h" #include "input/input.h" #include "locale/localemanager.h" +#include "rpg/item/item.h" #include "rpg/rpg.h" #include "display/display.h" #include "scene/scene.h" @@ -39,6 +40,7 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) { errorChain(assetInit()); // errorChain(saveInit()); errorChain(localeManagerInit()); + errorChain(itemInit()); errorChain(displayInit()); errorChain(uiInit()); errorChain(rpgInit()); diff --git a/src/dusk/rpg/cutscene/cutscene.h b/src/dusk/rpg/cutscene/cutscene.h index f954455e..03effe1f 100644 --- a/src/dusk/rpg/cutscene/cutscene.h +++ b/src/dusk/rpg/cutscene/cutscene.h @@ -165,10 +165,10 @@ typedef struct cutscene_s { #define CUTSCENE_SET_PAUSE(FLAGS) \ { .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = (FLAGS) } -#define CUTSCENE_ITEM_GIVE(ITEM_ID, QUANTITY) \ +#define CUTSCENE_ITEM_GIVE(ITEM_NAME, QUANTITY) \ { \ .type = CUTSCENE_ITEM_TYPE_ITEM_GIVE, \ - .itemGive = { .item = ITEM_ID, .quantity = QUANTITY } \ + .itemGive = { .itemName = ITEM_NAME, .quantity = QUANTITY } \ } // Runs all listed items simultaneously and waits until all are done. diff --git a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c index 69c27136..3bd3f9fe 100644 --- a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c +++ b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c @@ -6,6 +6,7 @@ */ #include "rpg/cutscene/item/cutsceneitem.h" +#include "rpg/item/item.h" #include "rpg/item/itemgive.h" #include "ui/rpg/textbox/uitextboxmain.h" @@ -13,7 +14,8 @@ void cutsceneItemGiveStart( const cutsceneitem_t *item, cutsceneitemdata_t *data ) { - itemGive(item->itemGive.item, item->itemGive.quantity); + itemid_t itemId = itemGetIdByName(item->itemGive.itemName); + itemGive(itemId, item->itemGive.quantity); } bool_t cutsceneItemGiveUpdate( diff --git a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h index 12a53c01..5c56adf8 100644 --- a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h +++ b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h @@ -6,13 +6,13 @@ */ #pragma once -#include "rpg/item/item.h" +#include "dusk.h" typedef struct cutsceneitem_s cutsceneitem_t; typedef union cutsceneitemdata_u cutsceneitemdata_t; typedef struct { - itemid_t item; + const char_t *itemName; uint8_t quantity; } cutsceneitemgive_t; diff --git a/src/dusk/rpg/cutscene/scene/testcutscene.h b/src/dusk/rpg/cutscene/scene/testcutscene.h index 10f7ba5f..e692d1a4 100755 --- a/src/dusk/rpg/cutscene/scene/testcutscene.h +++ b/src/dusk/rpg/cutscene/scene/testcutscene.h @@ -25,7 +25,7 @@ CUTSCENE(TEST_TWO, 0, DEFAULT, // CUTSCENE_ENTITY_WALK_TO(CUTSCENE_ENTITY_INTERACT, 4, 4, 0), // CUTSCENE_ENTITY_WALK_TO(CUTSCENE_ENTITY_INTERACTED, 8, 2, 0), // ), - // CUTSCENE_ITEM_GIVE(ITEM_ID_POTATO, 3), + // CUTSCENE_ITEM_GIVE("POTATO", 3), // CUTSCENE_ENTITY_REMOVE(CUTSCENE_ENTITY_INTERACT), CUTSCENE_TEXT("Done."), ); \ No newline at end of file diff --git a/src/dusk/rpg/item/CMakeLists.txt b/src/dusk/rpg/item/CMakeLists.txt index cbd4416d..29e79fb0 100644 --- a/src/dusk/rpg/item/CMakeLists.txt +++ b/src/dusk/rpg/item/CMakeLists.txt @@ -10,13 +10,4 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} inventory.c backpack.c itemgive.c -) - -# Item Definitions -dusk_run_python( - dusk_item_json_defs - tools.item - --json ${CMAKE_CURRENT_SOURCE_DIR}/item.json - --output ${DUSK_GENERATED_HEADERS_DIR}/rpg/item/itemdef.h -) -add_dependencies(${DUSK_LIBRARY_TARGET_NAME} dusk_item_json_defs) \ No newline at end of file +) \ No newline at end of file diff --git a/src/dusk/rpg/item/backpack.c b/src/dusk/rpg/item/backpack.c index 03bd91ae..bf16afdc 100644 --- a/src/dusk/rpg/item/backpack.c +++ b/src/dusk/rpg/item/backpack.c @@ -11,69 +11,69 @@ backpack_t BACKPACK; void backpackInit() { - for(uint8_t i = 0; i < ITEM_TYPE_COUNT; i++) { + for(uint32_t i = 0; i < ITEM_TYPE_COUNT_MAX; i++) { inventoryInit( &BACKPACK.inventories[i], BACKPACK.storage[i], - ITEM_TYPE_COUNT_MAX + ITEM_TYPE_SLOT_COUNT_MAX ); } } -inventory_t *backpackGetInventory(const itemtype_t type) { +inventory_t *backpackGetInventory(const itemtypeid_t type) { assertTrue(type > ITEM_TYPE_NULL, "Item type must not be null"); - assertTrue(type < ITEM_TYPE_COUNT, "Item type out of range"); + assertTrue(type <= ITEM_TYPE_COUNT, "Item type out of range"); return &BACKPACK.inventories[type]; } void backpackAdd(const itemid_t item, const uint8_t quantity) { assertTrue(item > ITEM_ID_NULL, "Item ID must not be null"); - assertTrue(item < ITEM_ID_COUNT, "Item ID out of range"); + assertTrue(item <= ITEM_COUNT, "Item ID out of range"); inventoryAdd(backpackGetInventory(ITEMS[item].type), item, quantity); } void backpackRemove(const itemid_t item) { assertTrue(item > ITEM_ID_NULL, "Item ID must not be null"); - assertTrue(item < ITEM_ID_COUNT, "Item ID out of range"); + assertTrue(item <= ITEM_COUNT, "Item ID out of range"); inventoryRemove(backpackGetInventory(ITEMS[item].type), item); } void backpackSet(const itemid_t item, const uint8_t quantity) { assertTrue(item > ITEM_ID_NULL, "Item ID must not be null"); - assertTrue(item < ITEM_ID_COUNT, "Item ID out of range"); + assertTrue(item <= ITEM_COUNT, "Item ID out of range"); inventorySet(backpackGetInventory(ITEMS[item].type), item, quantity); } uint8_t backpackGetCount(const itemid_t item) { assertTrue(item > ITEM_ID_NULL, "Item ID must not be null"); - assertTrue(item < ITEM_ID_COUNT, "Item ID out of range"); + assertTrue(item <= ITEM_COUNT, "Item ID out of range"); return inventoryGetCount(backpackGetInventory(ITEMS[item].type), item); } bool_t backpackItemExists(const itemid_t item) { assertTrue(item > ITEM_ID_NULL, "Item ID must not be null"); - assertTrue(item < ITEM_ID_COUNT, "Item ID out of range"); + assertTrue(item <= ITEM_COUNT, "Item ID out of range"); return inventoryItemExists(backpackGetInventory(ITEMS[item].type), item); } -bool_t backpackIsFull(const itemtype_t type) { +bool_t backpackIsFull(const itemtypeid_t type) { assertTrue(type > ITEM_TYPE_NULL, "Item type must not be null"); - assertTrue(type < ITEM_TYPE_COUNT, "Item type out of range"); + assertTrue(type <= ITEM_TYPE_COUNT, "Item type out of range"); return inventoryIsFull(backpackGetInventory(type)); } bool_t backpackItemFull(const itemid_t item) { assertTrue(item > ITEM_ID_NULL, "Item ID must not be null"); - assertTrue(item < ITEM_ID_COUNT, "Item ID out of range"); + assertTrue(item <= ITEM_COUNT, "Item ID out of range"); return inventoryItemFull(backpackGetInventory(ITEMS[item].type), item); } void backpackSort( - const itemtype_t type, + const itemtypeid_t type, const inventorysort_t sortBy, const bool_t reverse ) { assertTrue(type > ITEM_TYPE_NULL, "Item type must not be null"); - assertTrue(type < ITEM_TYPE_COUNT, "Item type out of range"); + assertTrue(type <= ITEM_TYPE_COUNT, "Item type out of range"); inventorySort(backpackGetInventory(type), sortBy, reverse); } \ No newline at end of file diff --git a/src/dusk/rpg/item/backpack.h b/src/dusk/rpg/item/backpack.h index 5812befa..6d7e1d31 100644 --- a/src/dusk/rpg/item/backpack.h +++ b/src/dusk/rpg/item/backpack.h @@ -8,9 +8,11 @@ #pragma once #include "inventory.h" +#define ITEM_TYPE_SLOT_COUNT_MAX 64 + typedef struct { - inventorystack_t storage[ITEM_TYPE_COUNT][ITEM_TYPE_COUNT_MAX]; - inventory_t inventories[ITEM_TYPE_COUNT]; + inventorystack_t storage[ITEM_TYPE_COUNT_MAX][ITEM_TYPE_SLOT_COUNT_MAX]; + inventory_t inventories[ITEM_TYPE_COUNT_MAX]; } backpack_t; extern backpack_t BACKPACK; @@ -26,7 +28,7 @@ void backpackInit(); * @param type The item type. * @returns Pointer to the inventory for that type. */ -inventory_t *backpackGetInventory(const itemtype_t type); +inventory_t *backpackGetInventory(const itemtypeid_t type); /** * Adds a quantity of an item to the backpack. @@ -73,7 +75,7 @@ bool_t backpackItemExists(const itemid_t item); * @param type The item type to check. * @returns true if the type's inventory is full. */ -bool_t backpackIsFull(const itemtype_t type); +bool_t backpackIsFull(const itemtypeid_t type); /** * Checks if an item's stack is full in the backpack. @@ -91,7 +93,7 @@ bool_t backpackItemFull(const itemid_t item); * @param reverse Whether to sort in reverse order. */ void backpackSort( - const itemtype_t type, + const itemtypeid_t type, const inventorysort_t sortBy, const bool_t reverse ); \ No newline at end of file diff --git a/src/dusk/rpg/item/inventory.c b/src/dusk/rpg/item/inventory.c index b3579ccb..64771059 100644 --- a/src/dusk/rpg/item/inventory.c +++ b/src/dusk/rpg/item/inventory.c @@ -188,8 +188,8 @@ int_t inventorySortByIdReverse(const void *a, const void *b) { int_t inventorySortByType(const void *a, const void *b) { const inventorystack_t *stackA = (const inventorystack_t*)a; const inventorystack_t *stackB = (const inventorystack_t*)b; - const itemtype_t typeA = ITEMS[stackA->item].type; - const itemtype_t typeB = ITEMS[stackB->item].type; + const itemtypeid_t typeA = ITEMS[stackA->item].type; + const itemtypeid_t typeB = ITEMS[stackB->item].type; if(typeA < typeB) return -1; if(typeA > typeB) return 1; return 0; @@ -198,8 +198,8 @@ int_t inventorySortByType(const void *a, const void *b) { int_t inventorySortByTypeReverse(const void *a, const void *b) { const inventorystack_t *stackA = (const inventorystack_t*)a; const inventorystack_t *stackB = (const inventorystack_t*)b; - const itemtype_t typeA = ITEMS[stackA->item].type; - const itemtype_t typeB = ITEMS[stackB->item].type; + const itemtypeid_t typeA = ITEMS[stackA->item].type; + const itemtypeid_t typeB = ITEMS[stackB->item].type; if(typeA < typeB) return 1; if(typeA > typeB) return -1; return 0; diff --git a/src/dusk/rpg/item/item.c b/src/dusk/rpg/item/item.c index d80a6b67..1504fd51 100644 --- a/src/dusk/rpg/item/item.c +++ b/src/dusk/rpg/item/item.c @@ -7,8 +7,125 @@ #include "item.h" #include "assert/assert.h" +#include "util/memory.h" +#include "util/string.h" +#include "asset/asset.h" +#include "asset/loader/assetentry.h" +#include "asset/loader/json/assetjsonloader.h" #include "locale/localemanager.h" #include "asset/loader/locale/assetlocaleloader.h" +#include "yyjson.h" + +#define ITEM_JSON_PATH "item.json" + +itemdef_t ITEMS[ITEM_COUNT_MAX]; +uint32_t ITEM_COUNT; +itemtype_t ITEM_TYPES[ITEM_TYPE_COUNT_MAX]; +uint32_t ITEM_TYPE_COUNT; + +errorret_t itemInit(void) { + memoryZero(ITEMS, sizeof(ITEMS)); + memoryZero(ITEM_TYPES, sizeof(ITEM_TYPES)); + ITEM_COUNT = 0; + ITEM_TYPE_COUNT = 0; + + assetentry_t *jsonEntry = assetLock( + ITEM_JSON_PATH, ASSET_LOADER_TYPE_JSON, NULL + ); + errorret_t ret = assetRequireLoaded(jsonEntry); + if(errorIsNotOk(ret)) { + assetUnlockEntry(jsonEntry); + errorChain(ret); + } + + yyjson_val *root = yyjson_doc_get_root(jsonEntry->data.json); + if(!yyjson_is_arr(root)) { + assetUnlockEntry(jsonEntry); + errorThrow("item.json root must be an array"); + } + + size_t idx, max; + yyjson_val *entry; + yyjson_arr_foreach(root, idx, max, entry) { + if(ITEM_COUNT >= ITEM_COUNT_MAX - 1) { + assetUnlockEntry(jsonEntry); + errorThrow( + "Too many items defined: exceeds ITEM_COUNT_MAX (%d)", + ITEM_COUNT_MAX + ); + } + + yyjson_val *idVal = yyjson_obj_get(entry, "id"); + yyjson_val *typeVal = yyjson_obj_get(entry, "type"); + yyjson_val *nameVal = yyjson_obj_get(entry, "name"); + yyjson_val *weightVal = yyjson_obj_get(entry, "weight"); + + if(!idVal || !yyjson_is_str(idVal)) { + assetUnlockEntry(jsonEntry); + errorThrow("Item entry %zu missing 'id' string", idx); + } + if(!typeVal || !yyjson_is_str(typeVal)) { + assetUnlockEntry(jsonEntry); + errorThrow("Item entry %zu missing 'type' string", idx); + } + if(!nameVal || !yyjson_is_str(nameVal)) { + assetUnlockEntry(jsonEntry); + errorThrow("Item entry %zu missing 'name' string", idx); + } + + const char_t *idStr = yyjson_get_str(idVal); + size_t idLen = yyjson_get_len(idVal); + const char_t *typeStr = yyjson_get_str(typeVal); + size_t typeLen = yyjson_get_len(typeVal); + const char_t *nameStr = yyjson_get_str(nameVal); + size_t nameLen = yyjson_get_len(nameVal); + + if(idLen >= ITEM_STRING_MAX) { + assetUnlockEntry(jsonEntry); + errorThrow("Item id '%s' exceeds max length", idStr); + } + if(nameLen + 10 >= ITEM_STRING_MAX) { + assetUnlockEntry(jsonEntry); + errorThrow("Item name '%s' exceeds max length", nameStr); + } + if(typeLen >= ITEM_STRING_MAX) { + assetUnlockEntry(jsonEntry); + errorThrow("Item type '%s' exceeds max length", typeStr); + } + + itemtypeid_t typeId = itemResolveType(typeStr, typeLen); + if(typeId == ITEM_TYPE_NULL) { + assetUnlockEntry(jsonEntry); + errorThrow( + "Too many item types defined: exceeds ITEM_TYPE_COUNT_MAX (%d)", + ITEM_TYPE_COUNT_MAX + ); + } + + ITEM_COUNT++; + itemid_t id = (itemid_t)ITEM_COUNT; + itemdef_t *def = &ITEMS[id]; + def->id = id; + def->type = typeId; + def->weight = (weightVal && yyjson_is_num(weightVal)) ? + (float_t)yyjson_get_num(weightVal) : 0.0f; + memoryCopy(def->idName, idStr, idLen + 1); + stringFormat(def->name, ITEM_STRING_MAX - 1, "item.%s.name", nameStr); + } + + assetUnlockEntry(jsonEntry); + errorOk(); +} + +itemid_t itemGetIdByName(const char_t *name) { + assertNotNull(name, "Item name cannot be NULL"); + + for(uint32_t i = 1; i <= ITEM_COUNT; i++) { + if(stringEquals(ITEMS[i].idName, name)) return (itemid_t)i; + } + + return ITEM_ID_NULL; +} errorret_t itemGetName( const itemid_t item, @@ -16,7 +133,7 @@ errorret_t itemGetName( const size_t bufferSize ) { assertTrue(item > ITEM_ID_NULL, "Item ID must not be null"); - assertTrue(item < ITEM_ID_COUNT, "Item ID out of range"); + assertTrue(item <= ITEM_COUNT, "Item ID out of range"); errorChain(assetLocaleGetString( &LOCALE.entry->data.locale, @@ -28,3 +145,17 @@ errorret_t itemGetName( errorOk(); } + +itemtypeid_t itemResolveType(const char_t *name, const size_t nameLen) { + for(uint32_t i = 1; i <= ITEM_TYPE_COUNT; i++) { + if(stringEquals(ITEM_TYPES[i].name, name)) return (itemtypeid_t)i; + } + + if(ITEM_TYPE_COUNT >= ITEM_TYPE_COUNT_MAX - 1) return ITEM_TYPE_NULL; + + ITEM_TYPE_COUNT++; + itemtypeid_t typeId = (itemtypeid_t)ITEM_TYPE_COUNT; + ITEM_TYPES[typeId].id = typeId; + memoryCopy(ITEM_TYPES[typeId].name, name, nameLen + 1); + return typeId; +} diff --git a/src/dusk/rpg/item/item.h b/src/dusk/rpg/item/item.h index 1c1beda5..09f6719a 100644 --- a/src/dusk/rpg/item/item.h +++ b/src/dusk/rpg/item/item.h @@ -7,7 +7,62 @@ #pragma once #include "error/error.h" -#include "rpg/item/itemdef.h" + +#define ITEM_COUNT_MAX 256 +#define ITEM_TYPE_COUNT_MAX 16 +#define ITEM_STRING_MAX 48 + +typedef uint16_t itemid_t; +typedef uint8_t itemtypeid_t; + +#define ITEM_ID_NULL ((itemid_t)0) +#define ITEM_TYPE_NULL ((itemtypeid_t)0) + +typedef struct { + itemid_t id; + itemtypeid_t type; + float_t weight; + char_t idName[ITEM_STRING_MAX]; + char_t name[ITEM_STRING_MAX]; +} itemdef_t; + +typedef struct { + itemtypeid_t id; + char_t name[ITEM_STRING_MAX]; +} itemtype_t; + +extern itemdef_t ITEMS[ITEM_COUNT_MAX]; +extern uint32_t ITEM_COUNT; +extern itemtype_t ITEM_TYPES[ITEM_TYPE_COUNT_MAX]; +extern uint32_t ITEM_TYPE_COUNT; + +/** + * Loads assets/item.json and parses it into the ITEMS/ITEM_TYPES tables. + * Must be called once, before any other item/backpack function. + * + * @return Any error that occurs (missing/malformed JSON, or too many + * items/types defined for ITEM_COUNT_MAX/ITEM_TYPE_COUNT_MAX). + */ +errorret_t itemInit(void); + +/** + * Looks up an item's numeric ID from its JSON "id" string. + * + * @param name The item's string ID (e.g. "POTION"), case-sensitive. + * @return The matching item ID, or ITEM_ID_NULL if not found. + */ +itemid_t itemGetIdByName(const char_t *name); + +/** + * Resolves a type name string to its numeric type ID, registering it as + * a new type in ITEM_TYPES if not already known. + * + * @param name The type's string name (e.g. "MEDICINE"). + * @param nameLen Length of name, excluding the null terminator. + * @return The resolved type ID, or ITEM_TYPE_NULL if ITEM_TYPE_COUNT_MAX + * would be exceeded. + */ +itemtypeid_t itemResolveType(const char_t *name, const size_t nameLen); /** * Gets the localized display name for an item. diff --git a/src/dusk/rpg/rpg.c b/src/dusk/rpg/rpg.c index 6e04ae7b..ad42e3e1 100644 --- a/src/dusk/rpg/rpg.c +++ b/src/dusk/rpg/rpg.c @@ -59,13 +59,13 @@ errorret_t rpgInit(void) { assertTrue(itemEntIndex != 0xFF, "No available entity slots!."); entity_t *itemEnt = &ENTITIES[itemEntIndex]; entityInit(itemEnt, ENTITY_TYPE_ITEM); - entityItemSet(itemEnt, ITEM_ID_POTION, 1); + entityItemSet(itemEnt, itemGetIdByName("POTION"), 1); entityPositionSet(itemEnt, (worldpos_t){ 12, 2, 0 }); // TEST: Give the player a starting assortment of items. - backpackAdd(ITEM_ID_POTION, 5); - backpackAdd(ITEM_ID_POTATO, 3); - backpackAdd(ITEM_ID_APPLE, 8); + backpackAdd(itemGetIdByName("POTION"), 5); + backpackAdd(itemGetIdByName("POTATO"), 3); + backpackAdd(itemGetIdByName("APPLE"), 8); // TEST: Create a test map area. uint8_t areaIndex = mapAreaAdd( diff --git a/src/dusk/ui/frame/backpack/uibackpack.c b/src/dusk/ui/frame/backpack/uibackpack.c index d2cbddbf..8d33c1b6 100644 --- a/src/dusk/ui/frame/backpack/uibackpack.c +++ b/src/dusk/ui/frame/backpack/uibackpack.c @@ -22,7 +22,7 @@ void uiBackpackTabChanged( const uint8_t index, const uimenuitem_t *item ) { - const itemtype_t type = (itemtype_t)(index + 1); + const itemtypeid_t type = (itemtypeid_t)(index + 1); const inventory_t *inventory = backpackGetInventory(type); errorCatch(uiItemListSetItemStacks( @@ -41,11 +41,16 @@ void uiBackpackTabSelected( errorret_t uiBackpackInit(void) { memoryZero(&UI_BACKPACK, sizeof(uibackpack_t)); + assertTrue( + ITEM_TYPE_COUNT - 1 <= UI_BACKPACK_TAB_COUNT, + "Item type count exceeds UI_BACKPACK_TAB_COUNT" + ); + MENU_BEGIN( &UI_BACKPACK.tabsMenu, UI_BACKPACK.tabs, uiBackpackTabSelected, NULL, uiBackpackTabChanged ); - for(uint8_t i = 0; i < UI_BACKPACK_TAB_COUNT; i++) { + for(uint32_t i = 0; i < ITEM_TYPE_COUNT - 1; i++) { stringFormat( UI_BACKPACK.tabLabels[i], UI_BACKPACK_TAB_LABEL_MAX - 1, "Category %u", i + 1 diff --git a/src/dusk/ui/frame/backpack/uibackpack.h b/src/dusk/ui/frame/backpack/uibackpack.h index bbd56ee0..9524b4a3 100644 --- a/src/dusk/ui/frame/backpack/uibackpack.h +++ b/src/dusk/ui/frame/backpack/uibackpack.h @@ -11,7 +11,7 @@ #include "ui/widget/uiitemlist.h" #include "rpg/item/item.h" -#define UI_BACKPACK_TAB_COUNT (ITEM_TYPE_COUNT - 1) +#define UI_BACKPACK_TAB_COUNT (ITEM_TYPE_COUNT_MAX - 1) #define UI_BACKPACK_TAB_LABEL_MAX 32 #define UI_BACKPACK_ITEM_LIST_COLUMNS 4 #define UI_BACKPACK_ITEM_LIST_ROWS 5 diff --git a/tools/item.py b/tools/item.py deleted file mode 100644 index f5d8b9c7..00000000 --- a/tools/item.py +++ /dev/null @@ -1,114 +0,0 @@ -import argparse -import json -import os - -parser = argparse.ArgumentParser(description="Item JSON to .h defines") -parser.add_argument("--json", required=True, help="Path to item JSON file") -parser.add_argument("--output", required=True, help="Path to output .h file") -args = parser.parse_args() - -def type_enum(name): - return "ITEM_TYPE_" + name.upper() - -def id_enum(name): - return "ITEM_ID_" + name.upper() - -# Load JSON -item_ids = [] -item_types = [] -rows = {} - -with open(args.json, encoding="utf-8") as f: - entries = json.load(f) - -if not all( - "id" in row and "type" in row and "name" in row for row in entries -): - raise ValueError("Each item must have 'id', 'type', and 'name' fields") - -for row in entries: - item_id, item_type = row["id"], row["type"] - if item_id not in item_ids: - item_ids.append(item_id) - if item_type not in item_types: - item_types.append(item_type) - rows[item_id] = row - -# Assign enum values: types and IDs each start from 1 with NULL = 0. -type_values = {} -type_count = 1 -for t in item_types: - type_values[t] = type_count - type_count += 1 - -id_values = {} -id_count = 1 -for i in item_ids: - id_values[i] = id_count - id_count += 1 - -# Count items per type -type_item_counts = { t: 0 for t in item_types } -for i in item_ids: - type_item_counts[rows[i]["type"]] += 1 - -# Build output -out = [ - "#pragma once", - '#include "dusk.h"', - "", - "typedef enum {", - " ITEM_TYPE_NULL = 0,", -] -for t in item_types: - out.append(f" {type_enum(t)} = {type_values[t]},") -out += [ - f" ITEM_TYPE_COUNT = {type_count}", - "} itemtype_t;", - "", - "typedef enum {", - " ITEM_ID_NULL = 0,", -] -for i in item_ids: - out.append(f" {id_enum(i)} = {id_values[i]},") -out += [ - f" ITEM_ID_COUNT = {id_count}", - "} itemid_t;", - "", - "typedef struct {", - " itemid_t id;", - " itemtype_t type;", - " const char_t *name;", - "} item_t;", - "", - "static const item_t ITEMS[] = {", -] -for i in item_ids: - row = rows[i] - out += [ - f" [{id_enum(i)}] = {{", - f" .id = {id_enum(i)},", - f" .type = {type_enum(row['type'])},", - f" .name = \"item.{row['name']}.name\",", - " },", - ] -out += [ - "};", - "", - "static const uint8_t ITEM_TYPE_COUNTS[] = {", -] -for t in item_types: - out.append(f" [{type_enum(t)}] = {type_item_counts[t]},") -out += [ - "};", - "", -] -max_type_count = max(type_item_counts.values()) if type_item_counts else 0 -out += [ - f"#define ITEM_TYPE_COUNT_MAX {max_type_count}", - "", -] - -os.makedirs(os.path.dirname(args.output), exist_ok=True) -with open(args.output, "w", encoding="utf-8") as f: - f.write("\n".join(out))