Replaces the build-time item.json/tools.item.py code generator with a single item_t ITEM registry populated at runtime by parsing assets/items.jsonc, so items/types can grow without a rebuild. Adds itemGetDefById/itemGetTypeById/itemGetIdByName/itemTypeGetOrCreate, updates inventory/backpack to size off the new *_DEF_COUNT_MAX caps and look up types dynamically, and reorders engine init so rpgInit (which loads items) runs before uiInit (which needs the item type count to size the backpack's tabs). Co-Authored-By: Claude Sonnet 5 <[email protected]>
86 lines
2.8 KiB
C
86 lines
2.8 KiB
C
/**
|
|
* Copyright (c) 2026 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "dusktest.h"
|
|
#include "entitytestfixture.h"
|
|
#include "ui/rpg/textbox/uitextboxmain.h"
|
|
#include "ui/focus/uifocus.h"
|
|
|
|
// An arbitrary, non-null itemid_t -- entityItemSet just stores/reports it
|
|
// verbatim, it doesn't need a real item registered in ITEM.
|
|
#define TEST_ITEM_ID ((itemid_t)1)
|
|
|
|
static entity_t *setUpItemEntity(void) {
|
|
entityTestFixtureReset();
|
|
uiFocusInit();
|
|
uiTextboxMainInit();
|
|
uiTextboxMainFocusClosed(NULL);// force-clear stale focus from a prior test
|
|
|
|
entityInit(&ENTITIES[0], ENTITY_TYPE_ITEM);
|
|
return &ENTITIES[0];
|
|
}
|
|
|
|
static void test_entityItemInit(void **state) {
|
|
|
|
entity_t *item = setUpItemEntity();
|
|
|
|
assert_int_equal(item->interact.type, ENTITY_INTERACT_CALLBACK);
|
|
assert_ptr_equal(item->interact.data.callback, entityItemInteract);
|
|
}
|
|
|
|
static void test_entityItemSet(void **state) {
|
|
|
|
entity_t *item = setUpItemEntity();
|
|
|
|
entityItemSet(item, TEST_ITEM_ID, 3);
|
|
assert_int_equal(item->data.item.item, TEST_ITEM_ID);
|
|
assert_int_equal(item->data.item.quantity, 3);
|
|
assert_false(item->data.item.collected);
|
|
}
|
|
|
|
// entityItemInteract itself is NOT covered here: it unconditionally calls
|
|
// itemGive(), which calls itemGetName(), which dereferences
|
|
// LOCALE.entry->data.locale -- a real locale asset populated only by the
|
|
// async asset-loading pipeline (see localemanager.h/assetlocaleloader.h).
|
|
// That's exactly the asset-loading dependency this test pass scoped out;
|
|
// faking it cheaply isn't possible without hand-building the loader's
|
|
// internal hash format, which is more coupling than it's worth. Backpack
|
|
// bookkeeping itself is already covered by test/item/test_inventory.c-style
|
|
// tests at the inventory/backpack layer.
|
|
|
|
static void test_entityItemMovementWaitsForCollectionAndTextbox(void **state) {
|
|
|
|
entity_t *item = setUpItemEntity();
|
|
|
|
// Not collected yet -- stays.
|
|
entityItemMovement(item);
|
|
assert_int_equal(item->type, ENTITY_TYPE_ITEM);
|
|
|
|
// Collected (set directly -- see note above on why entityItemInteract
|
|
// itself isn't driven here), but a message is still showing -- stays.
|
|
item->data.item.collected = true;
|
|
uiTextboxMainSetText("Picked up!");
|
|
entityItemMovement(item);
|
|
assert_int_equal(item->type, ENTITY_TYPE_ITEM);
|
|
|
|
// Once the textbox is dismissed, the entity despawns.
|
|
uiFocusPop();
|
|
assert_false(uiTextboxMainIsActive());
|
|
entityItemMovement(item);
|
|
assert_int_equal(item->type, ENTITY_TYPE_NULL);
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test(test_entityItemInit),
|
|
cmocka_unit_test(test_entityItemSet),
|
|
cmocka_unit_test(test_entityItemMovementWaitsForCollectionAndTextbox),
|
|
};
|
|
|
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
}
|