diff --git a/mods/randomizer/src/hooks.cpp b/mods/randomizer/src/hooks.cpp index 30b8dc2dcf..acdc5b7169 100644 --- a/mods/randomizer/src/hooks.cpp +++ b/mods/randomizer/src/hooks.cpp @@ -32,6 +32,7 @@ #include "d/actor/d_a_npc_zrc.h" #include "d/actor/d_a_npc_zrz.h" #include "d/actor/d_a_obj_bosswarp.h" +#include "d/actor/d_a_shop_item.h" #include "d/actor/d_a_obj_swBallC.h" #include "d/actor/d_a_obj_zra_rock.h" #include "d/actor/d_a_tag_kmsg.h" @@ -157,7 +158,9 @@ DEFINE_HOOK(&dGameover_c::_create, dGameover_c___create); DEFINE_HOOK(&daObjSwBallC_c::Create, daObjSwBallC_c__Create); DEFINE_HOOK(&daObjSwBallC_c::actionWait, daObjSwBallC_c__actionWait); -DEFINE_HOOK_SYMBOL("daDitem_Execute", int(daDitem_c*), daDitem_c__execute); +DEFINE_HOOK(&daDitem_c::CreateInit, daDitem_c__CreateInit); + +DEFINE_HOOK(&daShopItem_c::CreateInit, daShopItem_c__CreateInit); DEFINE_HOOK(&daObjBossWarp_c::demoProc, daObjBossWarp_c__demoProc); @@ -195,6 +198,7 @@ DEFINE_HOOK(&daItem_c::itemGet, daItem_c__itemGet); DEFINE_HOOK(&daObjLife_c::setEffect, daObjLife_c__setEffect); DEFINE_HOOK(&daObjLife_c::create, daObjLife_c__create); +DEFINE_HOOK(&daObjLife_c::Create, daObjLife_c__Create); DEFINE_HOOK(&daObjLife_c::actionGetDemo, daObjLife_c__actionGetDemo); DEFINE_HOOK(&daObjLife_c::calcScale, daObjLife_c__calcScale); @@ -1797,7 +1801,7 @@ HookAction hookPreSetGetSubBgm(ModContext*, void* args, void*, void*) { se_type = SETYPE_ITEM_GET_ME_S; } - if (se_type != SETYPE_NONE || i_itemNo == dItemNo_Randomizer_FOOLISH_ITEM_e) { + if (se_type != SETYPE_NONE) { mDoAud_subBgmStart(bgmLabel[se_type]); dComIfGp_setMesgBgmOn(); } @@ -2360,25 +2364,50 @@ HookAction hookPreSwBallActionWait(ModContext*, void* args, void*, void*) { return HOOK_SKIP_ORIGINAL; } -void hookPostDitemExecute(ModContext*, void* args, void* retval, void*) { +void hookPostDitemCreateInit(ModContext*, void* args, void*, void*) { auto* i_this = mods::arg(args, 0); - // Certain items use field models that are too big to fit in link's hands so we want to scale them down to fit. - switch (i_this->m_itemNo) { + // Certain items use field models that are too big to fit in link's hands so we want to scale + // them down to fit. + f32 modelScale = 0.0f; + switch (i_this->getDisplayItemNo()) { case dItemNo_Randomizer_MIRROR_PIECE_1_e: case dItemNo_Randomizer_MIRROR_PIECE_2_e: case dItemNo_Randomizer_MIRROR_PIECE_3_e: case dItemNo_Randomizer_MIRROR_PIECE_4_e: - { - i_this->scale.x = 0.05f; + modelScale = 0.05f; break; - } case dItemNo_Randomizer_MASTER_SWORD_e: case dItemNo_Randomizer_LIGHT_SWORD_e: - { - i_this->scale.x = 0.001f; + modelScale = 0.001f; + break; + default: + return; + } + + i_this->setMaxScale(modelScale); + i_this->scale.setall(modelScale); + i_this->set_mtx(); +} + +void hookPostShopItemCreateInit(ModContext*, void* args, void*, void*) { + auto* i_this = mods::arg(args, 0); + + switch (i_this->getDisplayItemNo()) { + case dItemNo_Randomizer_MASTER_SWORD_e: + case dItemNo_Randomizer_LIGHT_SWORD_e: { + f32 modelScale = 0.35f; + if (strcmp("R_SP109", dComIfGp_getStartStageName()) == 0 && + dComIfGp_getStartStageRoomNo() == 1) + { + modelScale *= 0.8f; + } + i_this->scale.setall(modelScale); + i_this->set_mtx(); break; } + default: + break; } } @@ -2671,7 +2700,7 @@ void hookPostMenuRingGetItemNum(ModContext*, void* args, void* retval, void*) { void hookPostItemCreateInit(ModContext*, void* args, void*, void*) { auto* i_this = mods::arg(args, 0); - switch (i_this->m_itemNo) { + switch (i_this->getDisplayItemNo()) { case dItemNo_Randomizer_KAKERA_HEART_e: case dItemNo_Randomizer_UTAWA_HEART_e: case dItemNo_Randomizer_ARROW_1_e: @@ -2795,7 +2824,7 @@ HookAction hookPreObjLifeSetEffect(ModContext*, void* args, void*, void*) { auto* i_this = mods::arg(args, 0); // In randomizer, we don't want rupees or poe souls to sparkle. They are bright enough. - switch (i_this->m_itemNo) { + switch (i_this->getDisplayItemNo()) { case dItemNo_Randomizer_GREEN_RUPEE_e: case dItemNo_Randomizer_BLUE_RUPEE_e: case dItemNo_Randomizer_RED_RUPEE_e: @@ -2857,90 +2886,95 @@ HookAction hookPreObjLifeCreate(ModContext*, void* args, void* retval, void*) { } fopAcM_SetParam(i_this, (params & 0xFFFFFF00) | itemId); } + } - // Also adjust the height of the object depending on the item - switch (itemId) { - case dItemNo_Randomizer_MASTER_SWORD_e: - case dItemNo_Randomizer_LIGHT_SWORD_e: - case dItemNo_Randomizer_WOOD_SHIELD_e: - case dItemNo_Randomizer_HYLIA_SHIELD_e: - case dItemNo_Randomizer_SHIELD_e: - case dItemNo_Randomizer_SPINNER_e: - { - i_this->current.pos.y += 30.f; - break; - } - case dItemNo_Randomizer_WOOD_STICK_e: - { - i_this->current.pos.y += 60.f; - break; - } - case dItemNo_Randomizer_SWORD_e: - case dItemNo_Randomizer_MIRROR_PIECE_1_e: - case dItemNo_Randomizer_MIRROR_PIECE_2_e: - case dItemNo_Randomizer_MIRROR_PIECE_3_e: - case dItemNo_Randomizer_MIRROR_PIECE_4_e: - case dItemNo_Randomizer_FUSED_SHADOW_1_e: - case dItemNo_Randomizer_FUSED_SHADOW_2_e: - case dItemNo_Randomizer_FUSED_SHADOW_3_e: - case dItemNo_Randomizer_COPY_ROD_e: - case dItemNo_Randomizer_COPY_ROD_2_e: - { - i_this->current.pos.y += 50.f; - break; - } + return HOOK_CONTINUE; +} - case dItemNo_Randomizer_BOW_e: - { - i_this->current.pos.y += 55.f; - break; - } - case dItemNo_Randomizer_BOOMERANG_e: - case dItemNo_Randomizer_FISHING_ROD_1_e: - case dItemNo_Randomizer_ARROW_LV2_e: - case dItemNo_Randomizer_ARROW_LV3_e: - { - i_this->current.pos.y += 40.f; - break; - } - case dItemNo_Randomizer_FOREST_SMALL_KEY_e: - case dItemNo_Randomizer_MINES_SMALL_KEY_e: - case dItemNo_Randomizer_LAKEBED_SMALL_KEY_e: - case dItemNo_Randomizer_ARBITERS_SMALL_KEY_e: - case dItemNo_Randomizer_SNOWPEAK_SMALL_KEY_e: - case dItemNo_Randomizer_TEMPLE_OF_TIME_SMALL_KEY_e: - case dItemNo_Randomizer_CITY_SMALL_KEY_e: - case dItemNo_Randomizer_PALACE_SMALL_KEY_e: - case dItemNo_Randomizer_HYRULE_SMALL_KEY_e: - case dItemNo_Randomizer_FOREST_BOSS_KEY_e: - case dItemNo_Randomizer_LAKEBED_BOSS_KEY_e: - case dItemNo_Randomizer_ARBITERS_BOSS_KEY_e: - case dItemNo_Randomizer_TEMPLE_OF_TIME_BOSS_KEY_e: - case dItemNo_Randomizer_CITY_BOSS_KEY_e: - case dItemNo_Randomizer_PALACE_BOSS_KEY_e: - case dItemNo_Randomizer_HYRULE_BOSS_KEY_e: - case dItemNo_Randomizer_SMALL_KEY2_e: - case dItemNo_Randomizer_LV5_BOSS_KEY_e: - case dItemNo_Randomizer_CAMP_SMALL_KEY_e: - case dItemNo_Randomizer_BOSSRIDER_KEY_e: - case dItemNo_Randomizer_PACHINKO_e: - case dItemNo_Randomizer_BOMB_BAG_LV2_e: - case dItemNo_Randomizer_BOMB_BAG_LV1_e: - case dItemNo_Randomizer_BOMB_IN_BAG_e: - case dItemNo_Randomizer_NORMAL_BOMB_e: - case dItemNo_Randomizer_POU_SPIRIT_e: - { - i_this->current.pos.y += 20.f; - break; - } - case dItemNo_Randomizer_ARMOR_e: - { - i_this->current.pos.y += 25.f; - break; - } - default: - break; - } +HookAction hookPreObjLifeCreateInit(ModContext*, void* args, void*, void*) { + auto* i_this = mods::arg(args, 0); + + if (i_this->m_itemNo == dItemNo_Randomizer_FOOLISH_ITEM_e) { + const u8 stage = getStageID(); + i_this->mOverrideHover = stage == Hyrule_Field || stage == Upper_Zoras_River || + stage == Sacred_Grove || stage == Stallord || + stage == Zant_Main_Room; + } + + // Models use different origins, so keep their visible geometry above the pedestal or ground. + switch (i_this->getDisplayItemNo()) { + case dItemNo_Randomizer_MASTER_SWORD_e: + case dItemNo_Randomizer_LIGHT_SWORD_e: + case dItemNo_Randomizer_WOOD_SHIELD_e: + case dItemNo_Randomizer_HYLIA_SHIELD_e: + case dItemNo_Randomizer_SHIELD_e: + case dItemNo_Randomizer_SPINNER_e: { + i_this->current.pos.y += 30.f; + break; + } + case dItemNo_Randomizer_WOOD_STICK_e: { + i_this->current.pos.y += 60.f; + break; + } + case dItemNo_Randomizer_SWORD_e: + case dItemNo_Randomizer_MIRROR_PIECE_1_e: + case dItemNo_Randomizer_MIRROR_PIECE_2_e: + case dItemNo_Randomizer_MIRROR_PIECE_3_e: + case dItemNo_Randomizer_MIRROR_PIECE_4_e: + case dItemNo_Randomizer_FUSED_SHADOW_1_e: + case dItemNo_Randomizer_FUSED_SHADOW_2_e: + case dItemNo_Randomizer_FUSED_SHADOW_3_e: + case dItemNo_Randomizer_COPY_ROD_e: + case dItemNo_Randomizer_COPY_ROD_2_e: { + i_this->current.pos.y += 50.f; + break; + } + case dItemNo_Randomizer_BOW_e: { + i_this->current.pos.y += 55.f; + break; + } + case dItemNo_Randomizer_BOOMERANG_e: + case dItemNo_Randomizer_FISHING_ROD_1_e: + case dItemNo_Randomizer_ARROW_LV2_e: + case dItemNo_Randomizer_ARROW_LV3_e: { + i_this->current.pos.y += 40.f; + break; + } + case dItemNo_Randomizer_FOREST_SMALL_KEY_e: + case dItemNo_Randomizer_MINES_SMALL_KEY_e: + case dItemNo_Randomizer_LAKEBED_SMALL_KEY_e: + case dItemNo_Randomizer_ARBITERS_SMALL_KEY_e: + case dItemNo_Randomizer_SNOWPEAK_SMALL_KEY_e: + case dItemNo_Randomizer_TEMPLE_OF_TIME_SMALL_KEY_e: + case dItemNo_Randomizer_CITY_SMALL_KEY_e: + case dItemNo_Randomizer_PALACE_SMALL_KEY_e: + case dItemNo_Randomizer_HYRULE_SMALL_KEY_e: + case dItemNo_Randomizer_FOREST_BOSS_KEY_e: + case dItemNo_Randomizer_LAKEBED_BOSS_KEY_e: + case dItemNo_Randomizer_ARBITERS_BOSS_KEY_e: + case dItemNo_Randomizer_TEMPLE_OF_TIME_BOSS_KEY_e: + case dItemNo_Randomizer_CITY_BOSS_KEY_e: + case dItemNo_Randomizer_PALACE_BOSS_KEY_e: + case dItemNo_Randomizer_HYRULE_BOSS_KEY_e: + case dItemNo_Randomizer_SMALL_KEY2_e: + case dItemNo_Randomizer_LV5_BOSS_KEY_e: + case dItemNo_Randomizer_CAMP_SMALL_KEY_e: + case dItemNo_Randomizer_BOSSRIDER_KEY_e: + case dItemNo_Randomizer_PACHINKO_e: + case dItemNo_Randomizer_BOMB_BAG_LV2_e: + case dItemNo_Randomizer_BOMB_BAG_LV1_e: + case dItemNo_Randomizer_BOMB_IN_BAG_e: + case dItemNo_Randomizer_NORMAL_BOMB_e: + case dItemNo_Randomizer_POU_SPIRIT_e: { + i_this->current.pos.y += 20.f; + break; + } + case dItemNo_Randomizer_ARMOR_e: { + i_this->current.pos.y += 25.f; + break; + } + default: + break; } return HOOK_CONTINUE; @@ -2970,7 +3004,7 @@ HookAction hookPreObjLifeCalcScale(ModContext*, void* args, void* retval, void*) // Change scale for certain items f32 newScale = 1.0f; - switch (i_this->m_itemNo) { + switch (i_this->getDisplayItemNo()) { case dItemNo_Randomizer_KAKERA_HEART_e: case dItemNo_Randomizer_UTAWA_HEART_e: case dItemNo_Randomizer_ARROW_10_e: @@ -3217,7 +3251,8 @@ ModResult initialize() { ADD_HOOK_POST(daObjSwBallC_c__Create, hookPostSwBallCreate); ADD_HOOK_PRE(daObjSwBallC_c__actionWait, hookPreSwBallActionWait); - ADD_HOOK_POST(daDitem_c__execute, hookPostDitemExecute); + ADD_HOOK_POST(daDitem_c__CreateInit, hookPostDitemCreateInit); + ADD_HOOK_POST(daShopItem_c__CreateInit, hookPostShopItemCreateInit); ADD_HOOK_PRE(daObjBossWarp_c__demoProc, hookPreBossWarpDemoProc); ADD_HOOK_POST(daObjBossWarp_c__demoProc, hookPostBossWarpDemoProc); @@ -3247,6 +3282,7 @@ ModResult initialize() { ADD_HOOK_PRE(daObjLife_c__setEffect, hookPreObjLifeSetEffect); ADD_HOOK_PRE(daObjLife_c__create, hookPreObjLifeCreate); + ADD_HOOK_PRE(daObjLife_c__Create, hookPreObjLifeCreateInit); ADD_HOOK_PRE(daObjLife_c__actionGetDemo, hookPreObjLifeActionGetDemo); ADD_HOOK_PRE(daObjLife_c__calcScale, hookPreObjLifeCalcScale); @@ -3353,7 +3389,8 @@ ModResult uninstall() { mods::hook::uninstall(svc_hook); mods::hook::uninstall(svc_hook); - mods::hook::uninstall(svc_hook); + mods::hook::uninstall(svc_hook); + mods::hook::uninstall(svc_hook); mods::hook::uninstall(svc_hook); @@ -3378,6 +3415,7 @@ ModResult uninstall() { mods::hook::uninstall(svc_hook); mods::hook::uninstall(svc_hook); + mods::hook::uninstall(svc_hook); mods::hook::uninstall(svc_hook); mods::hook::uninstall(svc_hook); diff --git a/mods/randomizer/src/randomizer_context.cpp b/mods/randomizer/src/randomizer_context.cpp index 250b3f16cd..9a22c53896 100644 --- a/mods/randomizer/src/randomizer_context.cpp +++ b/mods/randomizer/src/randomizer_context.cpp @@ -573,19 +573,10 @@ static bool checkFoolishItemEffectReady() return false; } - // Ensure there are pointers to the mMeterClass and mpMeterDraw structs - if (!dMeter2Info_getMeterClass()) - { - return false; - } - - if (!dMeter2Info_getMeterClass()->getMeterDrawPtr()) - { - return false; - } - // Make sure Z button isn't dimmed - if (dMeter2Info_getMeterClass()->getMeterDrawPtr()->getButtonZAlpha() != 1.f) + if (dComIfGs_isEventBit(MIDNA_ACCOMPANIES_WOLF) && dMeter2Info_getMeterClass() && + dMeter2Info_getMeterClass()->getMeterDrawPtr() && + dMeter2Info_getMeterClass()->getMeterDrawPtr()->getButtonZAlpha() != 1.f) { return false; } @@ -1032,7 +1023,7 @@ void randomizer_returnToSpawn(bool tryOverride) { dComIfGp_setNextStage("F_SP103", 1, 1, -1); } -u8 randomizer_getRandomFoolishItemModelID() { +u8 randomizer_getRandomFoolishItemModelID(std::string_view checkName) { static constexpr auto foolishItemModels = std::to_array({ dItemNo_Randomizer_ARMOR_e, dItemNo_Randomizer_WOOD_STICK_e, @@ -1053,8 +1044,13 @@ u8 randomizer_getRandomFoolishItemModelID() { dItemNo_Randomizer_ANCIENT_DOCUMENT_e, }); - u8 selectedModal = foolishItemModels[static_cast(cM_rnd() * foolishItemModels.size()) % foolishItemModels.size()]; - return verifyProgressiveItem(selectedModal); + static constexpr char separator = '\0'; + const std::string& seedHash = randomizer_GetContext().mHash; + u32 hash = randomizer::utility::crc32(seedHash.data(), seedHash.size()); + hash = randomizer::utility::crc32(&separator, sizeof(separator), hash); + hash = randomizer::utility::crc32(checkName.data(), checkName.size(), hash); + const u8 selectedModel = foolishItemModels[hash % foolishItemModels.size()]; + return verifyProgressiveItem(selectedModel); } u32 getActorPatchesCurrentStageKey(u8 roomNo) { diff --git a/mods/randomizer/src/randomizer_context.hpp b/mods/randomizer/src/randomizer_context.hpp index d15e92f593..639b15334e 100644 --- a/mods/randomizer/src/randomizer_context.hpp +++ b/mods/randomizer/src/randomizer_context.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -266,7 +267,7 @@ bool randomizer_mirrorChamberWallShouldExist(); void randomizer_returnToSpawn(bool tryDungeon); -u8 randomizer_getRandomFoolishItemModelID(); +u8 randomizer_getRandomFoolishItemModelID(std::string_view checkName); /** * Helper function to convert raw bytes of a container to a hex string diff --git a/mods/randomizer/src/session.cpp b/mods/randomizer/src/session.cpp index 9dc1dd3593..e60b65cc26 100644 --- a/mods/randomizer/src/session.cpp +++ b/mods/randomizer/src/session.cpp @@ -83,61 +83,70 @@ std::optional parse_flag_check(const char* name, std::string_view prefix) { return static_cast(flag); } +bool set_resolution( + const ItemCheckInfo* info, ItemCheckResolution* outResult, uint8_t resolvedItem) { + outResult->item = resolvedItem; + if (resolvedItem == dItemNo_Randomizer_FOOLISH_ITEM_e) { + outResult->display_item = randomizer_getRandomFoolishItemModelID(info->name); + } + return true; +} + template -bool lookup_override(const Map& map, u16 key, uint8_t* out_item) { +bool lookup_override( + const Map& map, u16 key, const ItemCheckInfo* info, ItemCheckResolution* outResult) { const auto it = map.find(key); if (it == map.end()) { return false; } - *out_item = static_cast(verifyProgressiveItem(it->second)); - return true; + return set_resolution(info, outResult, static_cast(verifyProgressiveItem(it->second))); } -bool resolve_check(ModContext*, const ItemCheckInfo* info, ItemCheckResolution* out, void*) { +bool resolve_check(ModContext*, const ItemCheckInfo* info, ItemCheckResolution* outResult, void*) { auto& ctx = randomizer_GetContext(); if (auto it = ctx.mItemLocations.find(info->name); it != ctx.mItemLocations.end()) { - out->item = static_cast(verifyProgressiveItem(it->second.itemId)); - return true; + return set_resolution( + info, outResult, static_cast(verifyProgressiveItem(it->second.itemId))); } if (auto key = parse_derived(info->name, ITEM_CHECK_CHEST_PREFIX)) { - return lookup_override(ctx.mTreasureChestOverrides, key->key, &out->item); + return lookup_override(ctx.mTreasureChestOverrides, key->key, info, outResult); } if (auto key = parse_derived(info->name, ITEM_CHECK_FREESTANDING_PREFIX)) { if (key->stage_id == Ook) { if (auto it = ctx.mItemLocations.find("Forest Temple Gale Boomerang"); it != ctx.mItemLocations.end()) { - out->item = static_cast(verifyProgressiveItem(it->second.itemId)); - return true; + return set_resolution(info, outResult, + static_cast(verifyProgressiveItem(it->second.itemId))); } return false; } - return lookup_override(ctx.mFreestandingItemOverrides, key->key, &out->item); + return lookup_override(ctx.mFreestandingItemOverrides, key->key, info, outResult); } if (auto flag = parse_flag_check(info->name, ITEM_CHECK_GOLDEN_WOLF_PREFIX)) { - return lookup_override(ctx.mGoldenWolfOverrides, *flag, &out->item); + return lookup_override(ctx.mGoldenWolfOverrides, *flag, info, outResult); } if (auto key = parse_derived(info->name, ITEM_CHECK_POE_PREFIX)) { - return lookup_override(ctx.mPoeOverrides, key->key, &out->item); + return lookup_override(ctx.mPoeOverrides, key->key, info, outResult); } if (auto stageId = parse_stage_check(info->name, ITEM_CHECK_BOSS_PREFIX)) { const u16 key = static_cast((*stageId << 8) | 0x9F); - return lookup_override(ctx.mFreestandingItemOverrides, key, &out->item); + return lookup_override(ctx.mFreestandingItemOverrides, key, info, outResult); } if (auto key = parse_derived(info->name, ITEM_CHECK_SHOP_PREFIX)) { - return lookup_override(ctx.mShopOverrides, key->key, &out->item); + return lookup_override(ctx.mShopOverrides, key->key, info, outResult); } if (auto key = parse_derived(info->name, ITEM_CHECK_SKY_PREFIX)) { - return lookup_override(ctx.mSkyCharacterOverrides, key->key, &out->item); + return lookup_override(ctx.mSkyCharacterOverrides, key->key, info, outResult); } constexpr std::string_view bugPrefix{ITEM_CHECK_BUG_PREFIX}; if (std::strncmp(info->name, bugPrefix.data(), bugPrefix.size()) == 0) { const u8 insect = static_cast(std::atoi(info->name + bugPrefix.size())); if (auto it = ctx.mBugRewardOverrides.find(insect); it != ctx.mBugRewardOverrides.end()) { - out->item = static_cast(verifyProgressiveItem(it->second)); - return true; + return set_resolution( + info, outResult, static_cast(verifyProgressiveItem(it->second))); } return false; } diff --git a/sdk/include/mods/svc/item.h b/sdk/include/mods/svc/item.h index 94fec6fb6c..67d64cc6f2 100644 --- a/sdk/include/mods/svc/item.h +++ b/sdk/include/mods/svc/item.h @@ -8,7 +8,7 @@ #define ITEM_SERVICE_ID "dev.twilitrealm.dusklight.item" #define ITEM_SERVICE_MAJOR 2u -#define ITEM_SERVICE_MINOR 1u +#define ITEM_SERVICE_MINOR 2u /* 0 is never a valid handle. */ typedef uint64_t ItemCheckHandle; @@ -97,6 +97,13 @@ typedef struct ItemService { ModContext* ctx, ItemGiveObserveFn fn, void* user_data, ItemGiveHandle* out_handle); ModResult (*unobserve_gives)(ModContext* ctx, ItemGiveHandle handle); + + /* Minor version 2 */ + + /* Resolve a live preview (item + display item) without granting an item or notifying give + * observers. */ + ModResult (*resolve_check_full)(ModContext* ctx, const char* name, uint8_t vanilla_item, + ItemCheckResolution* out_resolution); } ItemService; MOD_DECLARE_SERVICE(ItemService, svc_item, ITEM_SERVICE_ID, ITEM_SERVICE_MAJOR, ITEM_SERVICE_MINOR); diff --git a/src/d/actor/d_a_demo_item.cpp b/src/d/actor/d_a_demo_item.cpp index 465532a5f0..1af403d2a6 100644 --- a/src/d/actor/d_a_demo_item.cpp +++ b/src/d/actor/d_a_demo_item.cpp @@ -550,7 +550,7 @@ static int daDitem_Execute(daDitem_c* i_this) { } int daDitem_c::draw() { - switch (m_itemNo) { + switch (DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo)) { case dItemNo_WOOD_STICK_e: draw_WOOD_STICK(); break; diff --git a/src/d/actor/d_a_shop_item.cpp b/src/d/actor/d_a_shop_item.cpp index a7a159ab1c..304fd1b1da 100644 --- a/src/d/actor/d_a_shop_item.cpp +++ b/src/d/actor/d_a_shop_item.cpp @@ -108,6 +108,7 @@ const char* daShopItem_c::getShopArcname() { mItemGiveTag = dusk::mods::item_give_tag_shop(mItemGiveOriginalNo); const auto [_, displayItem] = dusk::mods::item_check_resolve(mItemGiveTag, mItemGiveOriginalNo, this); + setDisplayItemNo(displayItem); mItemOverridden = displayItem != mItemGiveOriginalNo; if (mItemOverridden) { mOverrideData = mData[mShopItemID]; diff --git a/src/dusk/mods/svc/item.cpp b/src/dusk/mods/svc/item.cpp index f80fc16b9b..44b0eff37e 100644 --- a/src/dusk/mods/svc/item.cpp +++ b/src/dusk/mods/svc/item.cpp @@ -75,6 +75,17 @@ ModResult item_resolve_check( return MOD_OK; } +ModResult item_resolve_check_full(ModContext* context, const char* name, uint8_t originalItemNo, + ItemCheckResolution* outResolution) { + if (mod_from_context(context) == nullptr || !is_valid_check_name(name) || + outResolution == nullptr) + { + return MOD_INVALID_ARGUMENT; + } + *outResolution = item_check_resolve(name, originalItemNo, nullptr); + return MOD_OK; +} + ModResult item_give_item( ModContext* context, const char* checkName, uint8_t itemNo, uint32_t flags) { auto* mod = mod_from_context(context); @@ -130,6 +141,7 @@ constexpr ItemService s_itemService{ .give_item = item_give_item, .observe_gives = item_observe_gives, .unobserve_gives = item_unobserve_gives, + .resolve_check_full = item_resolve_check_full, }; } // namespace