Merge branch 'rando-mod' of https://github.com/TwilitRealm/dusk into rando-mod

This commit is contained in:
gymnast86
2026-08-24 02:20:36 -07:00
8 changed files with 196 additions and 132 deletions
+135 -97
View File
@@ -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<daDitem_c*>(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<daShopItem_c*>(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<daItem_c*>(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<daObjLife_c*>(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<daObjLife_c*>(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<daObjSwBallC_c__Create>(svc_hook);
mods::hook::uninstall<daObjSwBallC_c__actionWait>(svc_hook);
mods::hook::uninstall<daDitem_c__execute>(svc_hook);
mods::hook::uninstall<daDitem_c__CreateInit>(svc_hook);
mods::hook::uninstall<daShopItem_c__CreateInit>(svc_hook);
mods::hook::uninstall<daObjBossWarp_c__demoProc>(svc_hook);
@@ -3378,6 +3415,7 @@ ModResult uninstall() {
mods::hook::uninstall<daObjLife_c__setEffect>(svc_hook);
mods::hook::uninstall<daObjLife_c__create>(svc_hook);
mods::hook::uninstall<daObjLife_c__Create>(svc_hook);
mods::hook::uninstall<daObjLife_c__actionGetDemo>(svc_hook);
mods::hook::uninstall<daObjLife_c__calcScale>(svc_hook);
+11 -15
View File
@@ -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<u8>({
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<int>(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) {
+2 -1
View File
@@ -10,6 +10,7 @@
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
@@ -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
+26 -17
View File
@@ -83,61 +83,70 @@ std::optional<u16> parse_flag_check(const char* name, std::string_view prefix) {
return static_cast<u16>(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 <typename Map>
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<uint8_t>(verifyProgressiveItem(it->second));
return true;
return set_resolution(info, outResult, static_cast<uint8_t>(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<uint8_t>(verifyProgressiveItem(it->second.itemId));
return true;
return set_resolution(
info, outResult, static_cast<uint8_t>(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<uint8_t>(verifyProgressiveItem(it->second.itemId));
return true;
return set_resolution(info, outResult,
static_cast<uint8_t>(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<u16>((*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<u8>(std::atoi(info->name + bugPrefix.size()));
if (auto it = ctx.mBugRewardOverrides.find(insect); it != ctx.mBugRewardOverrides.end()) {
out->item = static_cast<uint8_t>(verifyProgressiveItem(it->second));
return true;
return set_resolution(
info, outResult, static_cast<uint8_t>(verifyProgressiveItem(it->second)));
}
return false;
}
+8 -1
View File
@@ -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);
+1 -1
View File
@@ -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;
+1
View File
@@ -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];
+12
View File
@@ -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