item but as a file
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
#include "input/input.h"
|
#include "input/input.h"
|
||||||
#include "locale/localemanager.h"
|
#include "locale/localemanager.h"
|
||||||
|
#include "rpg/item/item.h"
|
||||||
#include "rpg/rpg.h"
|
#include "rpg/rpg.h"
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
@@ -39,6 +40,7 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
errorChain(assetInit());
|
errorChain(assetInit());
|
||||||
// errorChain(saveInit());
|
// errorChain(saveInit());
|
||||||
errorChain(localeManagerInit());
|
errorChain(localeManagerInit());
|
||||||
|
errorChain(itemInit());
|
||||||
errorChain(displayInit());
|
errorChain(displayInit());
|
||||||
errorChain(uiInit());
|
errorChain(uiInit());
|
||||||
errorChain(rpgInit());
|
errorChain(rpgInit());
|
||||||
|
|||||||
@@ -165,10 +165,10 @@ typedef struct cutscene_s {
|
|||||||
#define CUTSCENE_SET_PAUSE(FLAGS) \
|
#define CUTSCENE_SET_PAUSE(FLAGS) \
|
||||||
{ .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = (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, \
|
.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.
|
// Runs all listed items simultaneously and waits until all are done.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||||
|
#include "rpg/item/item.h"
|
||||||
#include "rpg/item/itemgive.h"
|
#include "rpg/item/itemgive.h"
|
||||||
#include "ui/rpg/textbox/uitextboxmain.h"
|
#include "ui/rpg/textbox/uitextboxmain.h"
|
||||||
|
|
||||||
@@ -13,7 +14,8 @@ void cutsceneItemGiveStart(
|
|||||||
const cutsceneitem_t *item,
|
const cutsceneitem_t *item,
|
||||||
cutsceneitemdata_t *data
|
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(
|
bool_t cutsceneItemGiveUpdate(
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "rpg/item/item.h"
|
#include "dusk.h"
|
||||||
|
|
||||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
itemid_t item;
|
const char_t *itemName;
|
||||||
uint8_t quantity;
|
uint8_t quantity;
|
||||||
} cutsceneitemgive_t;
|
} 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_INTERACT, 4, 4, 0),
|
||||||
// CUTSCENE_ENTITY_WALK_TO(CUTSCENE_ENTITY_INTERACTED, 8, 2, 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_ENTITY_REMOVE(CUTSCENE_ENTITY_INTERACT),
|
||||||
CUTSCENE_TEXT("Done."),
|
CUTSCENE_TEXT("Done."),
|
||||||
);
|
);
|
||||||
@@ -11,12 +11,3 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
backpack.c
|
backpack.c
|
||||||
itemgive.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;
|
backpack_t BACKPACK;
|
||||||
|
|
||||||
void backpackInit() {
|
void backpackInit() {
|
||||||
for(uint8_t i = 0; i < ITEM_TYPE_COUNT; i++) {
|
for(uint32_t i = 0; i < ITEM_TYPE_COUNT_MAX; i++) {
|
||||||
inventoryInit(
|
inventoryInit(
|
||||||
&BACKPACK.inventories[i],
|
&BACKPACK.inventories[i],
|
||||||
BACKPACK.storage[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_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];
|
return &BACKPACK.inventories[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
void backpackAdd(const itemid_t item, const uint8_t quantity) {
|
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_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);
|
inventoryAdd(backpackGetInventory(ITEMS[item].type), item, quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void backpackRemove(const itemid_t item) {
|
void backpackRemove(const itemid_t item) {
|
||||||
assertTrue(item > ITEM_ID_NULL, "Item ID must not be null");
|
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);
|
inventoryRemove(backpackGetInventory(ITEMS[item].type), item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void backpackSet(const itemid_t item, const uint8_t quantity) {
|
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_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);
|
inventorySet(backpackGetInventory(ITEMS[item].type), item, quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t backpackGetCount(const itemid_t item) {
|
uint8_t backpackGetCount(const itemid_t item) {
|
||||||
assertTrue(item > ITEM_ID_NULL, "Item ID must not be null");
|
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);
|
return inventoryGetCount(backpackGetInventory(ITEMS[item].type), item);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t backpackItemExists(const itemid_t item) {
|
bool_t backpackItemExists(const itemid_t item) {
|
||||||
assertTrue(item > ITEM_ID_NULL, "Item ID must not be null");
|
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);
|
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_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));
|
return inventoryIsFull(backpackGetInventory(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t backpackItemFull(const itemid_t item) {
|
bool_t backpackItemFull(const itemid_t item) {
|
||||||
assertTrue(item > ITEM_ID_NULL, "Item ID must not be null");
|
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);
|
return inventoryItemFull(backpackGetInventory(ITEMS[item].type), item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void backpackSort(
|
void backpackSort(
|
||||||
const itemtype_t type,
|
const itemtypeid_t type,
|
||||||
const inventorysort_t sortBy,
|
const inventorysort_t sortBy,
|
||||||
const bool_t reverse
|
const bool_t reverse
|
||||||
) {
|
) {
|
||||||
assertTrue(type > ITEM_TYPE_NULL, "Item type must not be null");
|
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);
|
inventorySort(backpackGetInventory(type), sortBy, reverse);
|
||||||
}
|
}
|
||||||
@@ -8,9 +8,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "inventory.h"
|
#include "inventory.h"
|
||||||
|
|
||||||
|
#define ITEM_TYPE_SLOT_COUNT_MAX 64
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
inventorystack_t storage[ITEM_TYPE_COUNT][ITEM_TYPE_COUNT_MAX];
|
inventorystack_t storage[ITEM_TYPE_COUNT_MAX][ITEM_TYPE_SLOT_COUNT_MAX];
|
||||||
inventory_t inventories[ITEM_TYPE_COUNT];
|
inventory_t inventories[ITEM_TYPE_COUNT_MAX];
|
||||||
} backpack_t;
|
} backpack_t;
|
||||||
|
|
||||||
extern backpack_t BACKPACK;
|
extern backpack_t BACKPACK;
|
||||||
@@ -26,7 +28,7 @@ void backpackInit();
|
|||||||
* @param type The item type.
|
* @param type The item type.
|
||||||
* @returns Pointer to the inventory for that 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.
|
* 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.
|
* @param type The item type to check.
|
||||||
* @returns true if the type's inventory is full.
|
* @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.
|
* 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.
|
* @param reverse Whether to sort in reverse order.
|
||||||
*/
|
*/
|
||||||
void backpackSort(
|
void backpackSort(
|
||||||
const itemtype_t type,
|
const itemtypeid_t type,
|
||||||
const inventorysort_t sortBy,
|
const inventorysort_t sortBy,
|
||||||
const bool_t reverse
|
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) {
|
int_t inventorySortByType(const void *a, const void *b) {
|
||||||
const inventorystack_t *stackA = (const inventorystack_t*)a;
|
const inventorystack_t *stackA = (const inventorystack_t*)a;
|
||||||
const inventorystack_t *stackB = (const inventorystack_t*)b;
|
const inventorystack_t *stackB = (const inventorystack_t*)b;
|
||||||
const itemtype_t typeA = ITEMS[stackA->item].type;
|
const itemtypeid_t typeA = ITEMS[stackA->item].type;
|
||||||
const itemtype_t typeB = ITEMS[stackB->item].type;
|
const itemtypeid_t typeB = ITEMS[stackB->item].type;
|
||||||
if(typeA < typeB) return -1;
|
if(typeA < typeB) return -1;
|
||||||
if(typeA > typeB) return 1;
|
if(typeA > typeB) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -198,8 +198,8 @@ int_t inventorySortByType(const void *a, const void *b) {
|
|||||||
int_t inventorySortByTypeReverse(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 *stackA = (const inventorystack_t*)a;
|
||||||
const inventorystack_t *stackB = (const inventorystack_t*)b;
|
const inventorystack_t *stackB = (const inventorystack_t*)b;
|
||||||
const itemtype_t typeA = ITEMS[stackA->item].type;
|
const itemtypeid_t typeA = ITEMS[stackA->item].type;
|
||||||
const itemtype_t typeB = ITEMS[stackB->item].type;
|
const itemtypeid_t typeB = ITEMS[stackB->item].type;
|
||||||
if(typeA < typeB) return 1;
|
if(typeA < typeB) return 1;
|
||||||
if(typeA > typeB) return -1;
|
if(typeA > typeB) return -1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+132
-1
@@ -7,8 +7,125 @@
|
|||||||
|
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include "assert/assert.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 "locale/localemanager.h"
|
||||||
#include "asset/loader/locale/assetlocaleloader.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(
|
errorret_t itemGetName(
|
||||||
const itemid_t item,
|
const itemid_t item,
|
||||||
@@ -16,7 +133,7 @@ errorret_t itemGetName(
|
|||||||
const size_t bufferSize
|
const size_t bufferSize
|
||||||
) {
|
) {
|
||||||
assertTrue(item > ITEM_ID_NULL, "Item ID must not be null");
|
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(
|
errorChain(assetLocaleGetString(
|
||||||
&LOCALE.entry->data.locale,
|
&LOCALE.entry->data.locale,
|
||||||
@@ -28,3 +145,17 @@ errorret_t itemGetName(
|
|||||||
|
|
||||||
errorOk();
|
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
|
#pragma once
|
||||||
#include "error/error.h"
|
#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.
|
* 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!.");
|
assertTrue(itemEntIndex != 0xFF, "No available entity slots!.");
|
||||||
entity_t *itemEnt = &ENTITIES[itemEntIndex];
|
entity_t *itemEnt = &ENTITIES[itemEntIndex];
|
||||||
entityInit(itemEnt, ENTITY_TYPE_ITEM);
|
entityInit(itemEnt, ENTITY_TYPE_ITEM);
|
||||||
entityItemSet(itemEnt, ITEM_ID_POTION, 1);
|
entityItemSet(itemEnt, itemGetIdByName("POTION"), 1);
|
||||||
entityPositionSet(itemEnt, (worldpos_t){ 12, 2, 0 });
|
entityPositionSet(itemEnt, (worldpos_t){ 12, 2, 0 });
|
||||||
|
|
||||||
// TEST: Give the player a starting assortment of items.
|
// TEST: Give the player a starting assortment of items.
|
||||||
backpackAdd(ITEM_ID_POTION, 5);
|
backpackAdd(itemGetIdByName("POTION"), 5);
|
||||||
backpackAdd(ITEM_ID_POTATO, 3);
|
backpackAdd(itemGetIdByName("POTATO"), 3);
|
||||||
backpackAdd(ITEM_ID_APPLE, 8);
|
backpackAdd(itemGetIdByName("APPLE"), 8);
|
||||||
|
|
||||||
// TEST: Create a test map area.
|
// TEST: Create a test map area.
|
||||||
uint8_t areaIndex = mapAreaAdd(
|
uint8_t areaIndex = mapAreaAdd(
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ void uiBackpackTabChanged(
|
|||||||
const uint8_t index,
|
const uint8_t index,
|
||||||
const uimenuitem_t *item
|
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);
|
const inventory_t *inventory = backpackGetInventory(type);
|
||||||
|
|
||||||
errorCatch(uiItemListSetItemStacks(
|
errorCatch(uiItemListSetItemStacks(
|
||||||
@@ -41,11 +41,16 @@ void uiBackpackTabSelected(
|
|||||||
errorret_t uiBackpackInit(void) {
|
errorret_t uiBackpackInit(void) {
|
||||||
memoryZero(&UI_BACKPACK, sizeof(uibackpack_t));
|
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(
|
MENU_BEGIN(
|
||||||
&UI_BACKPACK.tabsMenu, UI_BACKPACK.tabs,
|
&UI_BACKPACK.tabsMenu, UI_BACKPACK.tabs,
|
||||||
uiBackpackTabSelected, NULL, uiBackpackTabChanged
|
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(
|
stringFormat(
|
||||||
UI_BACKPACK.tabLabels[i], UI_BACKPACK_TAB_LABEL_MAX - 1,
|
UI_BACKPACK.tabLabels[i], UI_BACKPACK_TAB_LABEL_MAX - 1,
|
||||||
"Category %u", i + 1
|
"Category %u", i + 1
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "ui/widget/uiitemlist.h"
|
#include "ui/widget/uiitemlist.h"
|
||||||
#include "rpg/item/item.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_TAB_LABEL_MAX 32
|
||||||
#define UI_BACKPACK_ITEM_LIST_COLUMNS 4
|
#define UI_BACKPACK_ITEM_LIST_COLUMNS 4
|
||||||
#define UI_BACKPACK_ITEM_LIST_ROWS 5
|
#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