item but as a file
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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."),
|
||||
);
|
||||
@@ -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)
|
||||
)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
@@ -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;
|
||||
|
||||
+132
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
+4
-4
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
-114
@@ -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))
|
||||
Reference in New Issue
Block a user