Merge remote-tracking branch 'origin/main' into rando-mod

This commit is contained in:
Luke Street
2026-08-23 22:37:50 -06:00
18 changed files with 260 additions and 114 deletions
+9
View File
@@ -32,6 +32,12 @@ struct daItemBase_data {
class daItemBase_c : public fopAc_ac_c {
public:
u8 getItemNo();
#if TARGET_PC
u8 getDisplayItemNo() const {
return mDisplayItemNo != 0xFF ? mDisplayItemNo : m_itemNo;
}
void setDisplayItemNo(u8 itemNo) { mDisplayItemNo = itemNo; }
#endif
void hide();
void show();
void changeDraw();
@@ -79,6 +85,9 @@ public:
/* 0x928 */ s16 m_get_timer;
/* 0x92A */ u8 m_itemNo;
/* 0x92B */ u8 field_0x92b;
#if TARGET_PC
u8 mDisplayItemNo = 0xFF;
#endif
};
#endif /* D_A_D_A_ITEMBASE_H */
+4 -2
View File
@@ -532,10 +532,12 @@ s32 fopAcM_delete(fpc_ProcID i_actorID);
fpc_ProcID fopAcM_create(s16 i_procName, u16 i_setId, u32 i_parameters, const cXyz* i_pos,
int i_roomNo, const csXyz* i_angle, const cXyz* i_scale, s8 i_argument,
createFunc i_createFunc IF_DUSK_ARG(u32 i_itemGiveTag = 0));
createFunc i_createFunc IF_DUSK_ARG(u32 i_itemGiveTag = 0)
IF_DUSK_ARG(u8 i_itemOriginalNo = 0xFF));
fpc_ProcID fopAcM_create(s16 i_procName, u32 i_parameters, const cXyz* i_pos, int i_roomNo,
const csXyz* i_angle, const cXyz* i_scale, s8 i_argument IF_DUSK_ARG(u32 i_itemGiveTag = 0));
const csXyz* i_angle, const cXyz* i_scale, s8 i_argument IF_DUSK_ARG(u32 i_itemGiveTag = 0)
IF_DUSK_ARG(u8 i_itemOriginalNo = 0xFF));
inline fpc_ProcID fopAcM_Create(s16 i_procName, createFunc i_createFunc, void* params) {
return fpcM_Create(i_procName, i_createFunc,params);
+11 -11
View File
@@ -93,50 +93,50 @@ bool lookup_override(const Map& map, u16 key, uint8_t* out_item) {
return true;
}
bool resolve_check(ModContext*, const ItemCheckInfo* info, uint8_t* out_item, void*) {
bool resolve_check(ModContext*, const ItemCheckInfo* info, ItemCheckResolution* out, 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));
out->item = static_cast<uint8_t>(verifyProgressiveItem(it->second.itemId));
return true;
}
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, &out->item);
}
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));
out->item = static_cast<uint8_t>(verifyProgressiveItem(it->second.itemId));
return true;
}
return false;
}
return lookup_override(ctx.mFreestandingItemOverrides, key->key, out_item);
return lookup_override(ctx.mFreestandingItemOverrides, key->key, &out->item);
}
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, &out->item);
}
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, &out->item);
}
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, &out->item);
}
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, &out->item);
}
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, &out->item);
}
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));
out->item = static_cast<uint8_t>(verifyProgressiveItem(it->second));
return true;
}
return false;
+2
View File
@@ -27,6 +27,7 @@
#define ITEM_CHECK_FISHING_HEART_PIECE "fishing_heart_piece"
#define ITEM_CHECK_GOATS_REWARD "goats_reward"
#define ITEM_CHECK_GORON_REWARD "goron_reward:F_SP113"
#define ITEM_CHECK_GORON_SPRINGWATER_RUSH "goron_springwater_rush"
#define ITEM_CHECK_ILIA_CHARM "ilia_charm"
#define ITEM_CHECK_ILIA_MEMORY "ilia_memory"
#define ITEM_CHECK_IZA_REWARD_1 "iza_reward_1"
@@ -42,6 +43,7 @@
#define ITEM_CHECK_PRAYER_REWARD "prayer_reward"
#define ITEM_CHECK_RENADO_LETTER "renado_letter"
#define ITEM_CHECK_SERA_REWARD "sera_reward"
#define ITEM_CHECK_SHAD_DOMINION_ROD "shad_dominion_rod"
#define ITEM_CHECK_SKYBOOK "skybook"
#define ITEM_CHECK_SNOWBOARD_REWARD "snowboard_race_reward"
#define ITEM_CHECK_STAR_REWARD_1 "star_reward_1"
+9 -3
View File
@@ -8,7 +8,7 @@
#define ITEM_SERVICE_ID "dev.twilitrealm.dusklight.item"
#define ITEM_SERVICE_MAJOR 2u
#define ITEM_SERVICE_MINOR 0u
#define ITEM_SERVICE_MINOR 1u
/* 0 is never a valid handle. */
typedef uint64_t ItemCheckHandle;
@@ -31,11 +31,17 @@ typedef struct ItemCheckInfo {
const void* giver_actor; /* fopAc_ac_c*, or NULL when unavailable */
uint8_t vanilla_item;
uint8_t current_item;
uint8_t current_display_item;
} ItemCheckInfo;
/* Return true and write out_item to replace current_item, or false to leave it unchanged. */
typedef struct ItemCheckResolution {
uint8_t item;
uint8_t display_item; /* leave unset (0xFF/NONE) to use the item */
} ItemCheckResolution;
/* Return true and write out_result to replace the result, or false to leave it unchanged. */
typedef bool (*ItemCheckResolveFn)(
ModContext* ctx, const ItemCheckInfo* info, uint8_t* out_item, void* user_data);
ModContext* ctx, const ItemCheckInfo* info, ItemCheckResolution* out_result, void* user_data);
typedef enum ItemGiveOrigin {
ITEM_GIVE_ORIGIN_GAME = 0,
+14 -2
View File
@@ -449,7 +449,7 @@ int daDitem_c::Delete() {
endInsectEffect();
mSound.deleteObject();
return DeleteBase(dItem_data::getArcName(m_itemNo));
return DeleteBase(dItem_data::getArcName(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo)));
}
static int daDitem_Delete(daDitem_c* i_this) {
@@ -461,8 +461,16 @@ int daDitem_c::create() {
m_itemNo = daDitem_prm::getNo(this);
#if TARGET_PC
const auto [item, displayItem] = dusk::mods::item_check_resolve(mItemGiveTag, m_itemNo, this);
m_itemNo = item;
setDisplayItemNo(displayItem);
const char* arc_name = dItem_data::getArcName(displayItem);
s16 bmd_name = dItem_data::getBmdName(displayItem);
#else
const char* arc_name = dItem_data::getArcName(m_itemNo);
s16 bmd_name = dItem_data::getBmdName(m_itemNo);
#endif
if (bmd_name < 0 || arc_name == NULL) {
if (bmd_name == 0) {
@@ -476,9 +484,13 @@ int daDitem_c::create() {
}
m_itemNo = dItemNo_GREEN_RUPEE_e;
#if TARGET_PC
setDisplayItemNo(dItemNo_NONE_e);
#endif
}
int phase_state = dComIfG_resLoad(&mPhase, dItem_data::getArcName(m_itemNo));
int phase_state = dComIfG_resLoad(
&mPhase, dItem_data::getArcName(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo)));
if (phase_state == cPhs_COMPLEATE_e) {
if (!fopAcM_entrySolidHeap(this, CheckItemCreateHeap, 0x80003390)) {
return cPhs_ERROR_e;
+2 -12
View File
@@ -1135,17 +1135,7 @@ static void e_po_dead(e_po_class* i_this) {
camera_player->mCamera.Start();
camera_player->mCamera.SetTrimSize(0);
dComIfGp_event_reset();
#if TARGET_PC
const auto itemCheck = dusk::mods::item_check_commit(
dusk::mods::item_give_tag_poe(i_this->BitSW), dItemNo_POU_SPIRIT_e, a_this);
daPy_getPlayerActorClass()->cancelOriginalDemo();
if (itemCheck.itemNo == dItemNo_NONE_e) {
dusk::mods::item_check_complete(itemCheck, a_this);
} else {
daAlink_getAlinkActorClass()->procWolfAtnActorMoveInit();
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::ForcedDemo);
}
#else
#if !TARGET_PC
dComIfGs_addPohSpiritNum();
#if !PLATFORM_SHIELD
if (dComIfGs_getPohSpiritNum() == 0x14) {
@@ -1153,8 +1143,8 @@ static void e_po_dead(e_po_class* i_this) {
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[457]);
}
#endif
daPy_getPlayerActorClass()->cancelOriginalDemo();
#endif
daPy_getPlayerActorClass()->cancelOriginalDemo();
} else if (mArg0Check(i_this, 0) != 0) {
if (!fopAcM_isSwitch(a_this, 0x22)) {
if (fopAcM_SearchByID(i_this->field_0x5B8, &local_1b0_actor) != 0 &&
+5 -5
View File
@@ -242,21 +242,21 @@ BOOL daItemBase_c::chkFlag(int i_flag) {
}
s8 daItemBase_c::getTevFrm() {
return dItem_data::getTevFrm(m_itemNo);
return dItem_data::getTevFrm(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
}
s8 daItemBase_c::getBtpFrm() {
return dItem_data::getBtpFrm(m_itemNo);
return dItem_data::getBtpFrm(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
}
u8 daItemBase_c::getShadowSize() {
return dItem_data::getShadowSize(m_itemNo);
return dItem_data::getShadowSize(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
}
u8 daItemBase_c::getCollisionH() {
return dItem_data::getH(m_itemNo);
return dItem_data::getH(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
}
u8 daItemBase_c::getCollisionR() {
return dItem_data::getR(m_itemNo);
return dItem_data::getR(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
}
+5 -2
View File
@@ -12,6 +12,9 @@
#include "d/actor/d_a_npc_gra.h"
#include "d/actor/d_a_tag_gra.h"
#include "Z2AudioLib/Z2Instances.h"
#if TARGET_PC
#include "mods/items.h"
#endif
#include <cstring>
DUSK_GAME_DATA const daNpc_grA_HIOParam daNpc_grA_Param_c::m = {
@@ -1323,7 +1326,7 @@ BOOL daNpc_grA_c::isDelete() {
return FALSE;
}
fopAcM_createItemForBoss(&current.pos, 0x21, fopAcM_GetRoomNo(this), NULL, NULL, 0.0f, 0.0f,
0x80);
0x80 IF_DUSK_ARG(ITEM_CHECK_GORON_SPRINGWATER_RUSH));
return TRUE;
}
return TRUE;
@@ -2812,7 +2815,7 @@ BOOL daNpc_grA_c::ECut_carrySpaWater(int i_staffID) {
c.y += 200.0f;
csXyz c2(0, fopAcM_searchPlayerAngleY(this), 0);
fopAcM_createItemForBoss(&c, 0x21, fopAcM_GetRoomNo(this), &c2, NULL, 0.0f, 20.0f,
0x80);
0x80 IF_DUSK_ARG(ITEM_CHECK_GORON_SPRINGWATER_RUSH));
} break;
}
}
+23 -24
View File
@@ -158,8 +158,8 @@ void daItem_c::CreateInit() {
mCcCyl.SetCoHitCallback(itemGetCoCallBack);
mCcCyl.SetTgHitCallback(itemGetTgCallBack);
f32 cylHeight = dItem_data::getH(m_itemNo);
f32 cylRadius = dItem_data::getR(m_itemNo);
f32 cylHeight = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo));
f32 cylRadius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo));
if (scale.x > 1.0f) {
cylHeight *= scale.x;
@@ -267,12 +267,13 @@ int daItem_c::_daItem_create() {
#if TARGET_PC
const u32 params = fopAcM_GetParam(this);
mOriginalItemNo = params & 0xFF;
const u8 resolvedItem = dusk::mods::item_check_freestanding(
daItem_prm::getItemBitNo(this), mOriginalItemNo, this);
mItemOverridden = resolvedItem != mOriginalItemNo;
mItemGiveTag = dusk::mods::item_give_tag_freestanding(daItem_prm::getItemBitNo(this));
const auto [item, displayItem] =
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
mItemOverridden = item != mOriginalItemNo;
setDisplayItemNo(displayItem);
if (mItemOverridden) {
fopAcM_SetParam(this, (params & 0xFFFFFF00) | resolvedItem);
fopAcM_SetParam(this, (params & 0xFFFFFF00) | item);
}
#endif
field_0x95d = true;
@@ -288,7 +289,7 @@ int daItem_c::_daItem_create() {
#if DEBUG
#if TARGET_PC
if (dItem_fieldModelArc(m_itemNo) == NULL) {
if (dItem_fieldModelArc(getDisplayItemNo()) == NULL) {
#else
if (dItem_data::getFieldArc(m_itemNo) == NULL) {
#endif
@@ -324,23 +325,21 @@ int daItem_c::_daItem_create() {
CreateInit();
} else {
#if TARGET_PC
// Resolved items may have no field model; display their get-demo model instead.
if (dItem_data::getFieldArc(m_itemNo) == NULL) {
phase_state = dComIfG_resLoad(&mPhase, dItem_data::getArcName(m_itemNo));
if (phase_state == cPhs_COMPLEATE_e) {
if (!fopAcM_entrySolidHeap(this, CheckItemCreateHeap, 0x4000)) {
return cPhs_ERROR_e;
}
CreateInit();
}
return phase_state;
}
#endif
const u8 displayItemNo = getDisplayItemNo();
phase_state = dComIfG_resLoad(&mPhase, dItem_fieldModelArc(displayItemNo));
#else
phase_state = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
#endif
if (phase_state == cPhs_COMPLEATE_e) {
#if TARGET_PC
const bool useModelFallback = dItem_data::getFieldArc(displayItemNo) == NULL;
if (!fopAcM_entrySolidHeap(this,
useModelFallback ? CheckItemCreateHeap : CheckFieldItemCreateHeap,
useModelFallback ? 0x4000 : dItem_data::getFieldHeapSize(displayItemNo)))
#else
if (!fopAcM_entrySolidHeap(this, CheckFieldItemCreateHeap,
dItem_data::getFieldHeapSize(m_itemNo)))
#endif
{
return cPhs_ERROR_e;
}
@@ -357,7 +356,7 @@ int daItem_c::_daItem_execute() {
CountTimer();
eyePos = current.pos;
eyePos.y += (f32)dItem_data::getH(m_itemNo) / 2;
eyePos.y += (f32)DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)) / 2;
attention_info.position = current.pos;
@@ -431,7 +430,7 @@ int daItem_c::_daItem_delete() {
}
#if TARGET_PC
DeleteBase(dItem_fieldModelArc(m_itemNo));
DeleteBase(dItem_fieldModelArc(getDisplayItemNo()));
#else
DeleteBase(dItem_data::getFieldArc(m_itemNo));
#endif
@@ -604,8 +603,8 @@ void daItem_c::procInitBoomerangCarry() {
scale = mItemScale;
mBoomerangMove.initOffset(&current.pos);
u8 height = dItem_data::getH(m_itemNo);
u8 radius = dItem_data::getR(m_itemNo);
u8 height = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo));
u8 radius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo));
mCcCyl.SetR((f32)radius * 2.0f);
mCcCyl.SetH((f32)height * 2.0f);
mCcCyl.OnCoSPrmBit(1);
+26 -11
View File
@@ -88,8 +88,8 @@ int daObjLife_c::Create() {
mCcCyl.SetStts(&mCcStts);
mCcCyl.SetCoHitCallback(lifeGetCoCallBack);
mCcCyl.SetTgHitCallback(lifeGetTgCallBack);
mCcCyl.SetR(dItem_data::getR(m_itemNo));
mCcCyl.SetH(dItem_data::getH(m_itemNo));
mCcCyl.SetR(DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo)));
mCcCyl.SetH(DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)));
fopAcM_SetCullSize(this, fopAc_CULLSPHERE_0_e);
fopAcM_SetGravity(this, -3.2f);
@@ -152,12 +152,23 @@ int daObjLife_c::create() {
const u8 parameterItemNo = params & 0xFF;
if (mItemGiveOriginalNo == dItemNo_NONE_e) {
mOriginalItemNo = parameterItemNo;
const u8 resolvedItem =
dusk::mods::item_check_freestanding(getSaveBitNo(), mOriginalItemNo, this);
mItemGiveTag = dusk::mods::item_give_tag_freestanding(getSaveBitNo());
mItemOverridden = resolvedItem != mOriginalItemNo;
const auto [item, displayItem] =
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
setDisplayItemNo(displayItem);
mItemOverridden = item != mOriginalItemNo;
if (mItemOverridden) {
fopAcM_SetParam(this, (params & 0xFFFFFF00) | resolvedItem);
fopAcM_SetParam(this, (params & 0xFFFFFF00) | item);
}
} else if (mGoldenWolfItem) {
mOriginalItemNo = mItemGiveOriginalNo;
mItemGiveTag = dusk::mods::item_give_tag_golden_wolf(static_cast<u16>(field_0x938));
const auto [item, displayItem] =
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
setDisplayItemNo(displayItem);
mItemOverridden = item != mOriginalItemNo;
if (item != parameterItemNo) {
fopAcM_SetParam(this, (params & 0xFFFFFF00) | item);
}
} else if (mGoldenWolfItem) {
mOriginalItemNo = mItemGiveOriginalNo;
@@ -171,6 +182,9 @@ int daObjLife_c::create() {
}
} else {
mOriginalItemNo = mItemGiveOriginalNo;
setDisplayItemNo(
dusk::mods::item_check_resolve(mItemGiveTag, parameterItemNo, this)
.display_item);
mItemOverridden = parameterItemNo != mOriginalItemNo;
}
mOverrideHover =
@@ -197,8 +211,9 @@ int daObjLife_c::create() {
#if TARGET_PC
// Resolved items may have no field model; display their get-demo model instead.
const bool useGetModel = dItem_data::getFieldArc(m_itemNo) == NULL;
int phase_state = dComIfG_resLoad(&mPhase, dItem_fieldModelArc(m_itemNo));
const u8 displayItemNo = getDisplayItemNo();
const bool useGetModel = dItem_data::getFieldArc(displayItemNo) == NULL;
int phase_state = dComIfG_resLoad(&mPhase, dItem_fieldModelArc(displayItemNo));
if (phase_state == cPhs_COMPLEATE_e) {
if (!fopAcM_entrySolidHeap(
this, useGetModel ? CheckItemCreateHeap : CheckFieldItemCreateHeap, 0x4000))
@@ -421,8 +436,8 @@ int daObjLife_c::actionInitBoomerangCarry() {
mCcCyl.OnTgSPrmBit(1);
mCcCyl.OnCoSPrmBit(1);
f32 height = dItem_data::getH(m_itemNo) * 4.0f;
f32 radius = dItem_data::getR(m_itemNo) * 4.0f;
f32 height = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)) * 4.0f;
f32 radius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo)) * 4.0f;
mCcCyl.SetR(radius);
mCcCyl.SetH(height);
@@ -544,7 +559,7 @@ int daObjLife_c::_delete() {
endEffect02();
#if TARGET_PC
DeleteBase(dItem_fieldModelArc(m_itemNo));
DeleteBase(dItem_fieldModelArc(getDisplayItemNo()));
#else
DeleteBase(dItem_data::getFieldArc(m_itemNo));
#endif
+53 -7
View File
@@ -1,6 +1,6 @@
/**
* @file d_a_obj_smallkey.cpp
*
*
*/
#include "d/dolzel_rel.h" // IWYU pragma: keep
@@ -119,9 +119,9 @@ int daKey_c::Create() {
mCcCyl.SetStts(&mCcStts);
mCcCyl.SetCoHitCallback(keyGetCoCallBack);
mCcCyl.SetTgHitCallback(keyGetTgCallBack);
mCcCyl.SetR(dItem_data::getR(m_itemNo));
mCcCyl.SetH(dItem_data::getH(m_itemNo));
mCcCyl.SetR(DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo)));
mCcCyl.SetH(DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)));
fopAcM_SetCullSize(this, fopAc_CULLSPHERE_0_e);
if (getSwNo() == 0xFF) {
@@ -155,7 +155,21 @@ int daKey_c::create() {
mIsPrmInit = TRUE;
}
#if TARGET_PC
mItemGiveTag = dusk::mods::item_give_tag_freestanding(getSaveBitNo());
const auto [item, displayItem] =
dusk::mods::item_check_resolve(mItemGiveTag, dItemNo_SMALL_KEY_e, this);
m_itemNo = item;
if (m_itemNo == dItemNo_NONE_e) {
// Keep the pickup visible until the empty check is collected.
m_itemNo = dItemNo_SMALL_KEY_e;
setDisplayItemNo(dItemNo_NONE_e);
} else {
setDisplayItemNo(displayItem);
}
#else
m_itemNo = dItemNo_SMALL_KEY_e;
#endif
if (strcmp(dComIfGp_getStartStageName(), "F_SP118") == 0) {
OS_REPORT(" SMKEY 0\n");
@@ -170,9 +184,21 @@ int daKey_c::create() {
return cPhs_ERROR_e;
}
#if TARGET_PC
const u8 displayItemNo = getDisplayItemNo();
int phase_state = dComIfG_resLoad(&mPhase, dItem_fieldModelArc(displayItemNo));
#else
int phase_state = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
#endif
if (phase_state == cPhs_COMPLEATE_e) {
#if TARGET_PC
const bool useModelFallback = dItem_data::getFieldArc(displayItemNo) == NULL;
if (!fopAcM_entrySolidHeap(
this, useModelFallback ? CheckItemCreateHeap : CheckFieldItemCreateHeap, 0x4000))
{
#else
if (!fopAcM_entrySolidHeap(this, CheckFieldItemCreateHeap, 0x840)) {
#endif
return cPhs_ERROR_e;
}
@@ -317,10 +343,26 @@ int daKey_c::initActionOrderGetDemo() {
hide();
effectStop();
#if TARGET_PC
const auto itemCheck =
dusk::mods::item_check_commit(mItemGiveTag, dItemNo_SMALL_KEY_e, this);
m_itemNo = itemCheck.itemNo;
if (m_itemNo == dItemNo_NONE_e) {
dusk::mods::item_check_complete(itemCheck, this);
dComIfGs_onTbox(getSaveBitNo());
dTres_c::offStatus(getSaveBitNo(), 1);
dComIfGp_event_reset();
fopAcM_delete(this);
return 1;
}
#endif
fopAcM_orderItemEvent(this, 0, 0);
eventInfo.onCondition(8);
mItemId = fopAcM_createItemForTrBoxDemo(&current.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL, NULL);
mItemId = fopAcM_createItemForTrBoxDemo(
&current.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL,
NULL IF_DUSK_ARG(itemCheck.tag));
JUT_ASSERT(699, mItemId != fpcM_ERROR_PROCESS_ID_e);
setStatus(STATUS_ORDER_GET_DEMO_e);
@@ -387,8 +429,8 @@ int daKey_c::actionInitBoomerangCarry() {
mCcCyl.OnTgSPrmBit(1);
mCcCyl.OnCoSPrmBit(1);
u8 height = dItem_data::getH(m_itemNo);
u8 radius = dItem_data::getR(m_itemNo);
u8 height = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo));
u8 radius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo));
mCcCyl.SetR(4.0f * radius);
mCcCyl.SetH(4.0f * height);
@@ -527,7 +569,11 @@ int daKey_c::draw() {
int daKey_c::_delete() {
effectStop();
#if TARGET_PC
DeleteBase(dItem_fieldModelArc(getDisplayItemNo()));
#else
DeleteBase(dItem_data::getFieldArc(m_itemNo));
#endif
return 1;
}
+11 -9
View File
@@ -105,17 +105,19 @@ const char* daShopItem_c::getShopArcname() {
#if TARGET_PC
if (m_itemNo != dItemNo_NONE_e && mItemGiveOriginalNo == dItemNo_NONE_e) {
mItemGiveOriginalNo = m_itemNo;
const u8 resolvedItem = dusk::mods::item_check_shop(mItemGiveOriginalNo, this);
mItemOverridden = resolvedItem != mItemGiveOriginalNo;
mItemGiveTag = dusk::mods::item_give_tag_shop(mItemGiveOriginalNo);
const auto [_, displayItem] =
dusk::mods::item_check_resolve(mItemGiveTag, mItemGiveOriginalNo, this);
mItemOverridden = displayItem != mItemGiveOriginalNo;
if (mItemOverridden) {
mOverrideData = mData[mShopItemID];
mOverrideData.mArcName = dItem_data::getArcName(resolvedItem);
mOverrideData.mBmdName = dItem_data::getBmdName(resolvedItem);
mOverrideData.mBtkName = dItem_data::getBtkName(resolvedItem);
mOverrideData.mBckName = dItem_data::getBckName(resolvedItem);
mOverrideData.mBrkName = dItem_data::getBrkName(resolvedItem);
mOverrideData.mBtpName = dItem_data::getBtpName(resolvedItem);
mOverrideData.mTevFrm = dItem_data::getTevFrm(resolvedItem);
mOverrideData.mArcName = dItem_data::getArcName(displayItem);
mOverrideData.mBmdName = dItem_data::getBmdName(displayItem);
mOverrideData.mBtkName = dItem_data::getBtkName(displayItem);
mOverrideData.mBckName = dItem_data::getBckName(displayItem);
mOverrideData.mBrkName = dItem_data::getBrkName(displayItem);
mOverrideData.mBtpName = dItem_data::getBtpName(displayItem);
mOverrideData.mTevFrm = dItem_data::getTevFrm(displayItem);
mOverrideData.mBtpFrm = -1;
mOverrideData.mFlag = static_cast<u32>(-1);
mOverrideData.mOffsetY = mShopItemID == SHOP_ITEMNO_ARMOR ? 60.0f : 15.0f;
+2 -2
View File
@@ -50,7 +50,7 @@ bool daItemBase_c::chkDead() {
int CheckItemCreateHeap(fopAc_ac_c* i_this) {
daItemBase_c* a_this = static_cast<daItemBase_c*>(i_this);
u8 item_no = a_this->getItemNo();
u8 item_no = DUSK_IF_ELSE(a_this->getDisplayItemNo(), a_this->getItemNo());
return a_this->CreateItemHeap(dItem_data::getArcName(item_no), dItem_data::getBmdName(item_no),
dItem_data::getBtkName(item_no), dItem_data::getBpkName(item_no),
dItem_data::getBckName(item_no), dItem_data::getBxaName(item_no),
@@ -67,7 +67,7 @@ const char* dItem_fieldModelArc(u8 itemNo) {
int CheckFieldItemCreateHeap(fopAc_ac_c* i_this) {
daItemBase_c* a_this = static_cast<daItemBase_c*>(i_this);
u8 item_no = a_this->getItemNo();
u8 item_no = DUSK_IF_ELSE(a_this->getDisplayItemNo(), a_this->getItemNo());
return a_this->CreateItemHeap(
dItem_data::getFieldArc(item_no), dItem_data::getItemBmdName(item_no),
dItem_data::getItemBtkName(item_no), dItem_data::getItemBpkName(item_no),
+13 -4
View File
@@ -1,7 +1,10 @@
#pragma once
#include "mods/svc/item.h"
#include <cstdint>
#include <unordered_map>
#include <utility>
class fopAc_ac_c;
@@ -16,8 +19,11 @@ enum class ItemGiveMode : uint8_t {
struct ItemCheckResult {
uint32_t tag = 0;
uint8_t itemNo = 0;
uint8_t displayItemNo = 0;
};
ItemCheckResolution item_check_resolve(const char* name, uint8_t itemNo, fopAc_ac_c* giver);
ItemCheckResolution item_check_resolve(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c* giver);
uint8_t item_check(const char* name, uint8_t itemNo, fopAc_ac_c* giver);
ItemCheckResult item_check_commit(const char* name, uint8_t itemNo, fopAc_ac_c* giver);
ItemCheckResult item_check_commit(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c* giver);
@@ -54,7 +60,7 @@ uint32_t item_give_queue_take_tag();
namespace detail {
struct CommittedCheck {
uint8_t vanillaItem = 0;
uint8_t resolvedItem = 0;
ItemCheckResolution resolution{};
bool queued = false;
};
@@ -77,10 +83,13 @@ public:
return existing->second;
}
const uint8_t resolvedItem = std::forward<ResolveFn>(resolve)();
const ItemCheckResolution resolution = std::forward<ResolveFn>(resolve)();
return mChecks
.emplace(
giveTag, CommittedCheck{.vanillaItem = vanillaItem, .resolvedItem = resolvedItem})
.emplace(giveTag,
CommittedCheck{
.vanillaItem = vanillaItem,
.resolution = resolution,
})
.first->second;
}
+22 -6
View File
@@ -186,9 +186,9 @@ void invalidate_committed_check(const std::string& name) {
} // namespace
uint8_t item_check(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
ItemCheckResolution item_check_resolve(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
if (name == nullptr || *name == '\0' || s_modChecks.empty()) {
return itemNo;
return {.item = itemNo, .display_item = itemNo};
}
// Callbacks may change registrations, so copy the applicable chain before invoking one.
@@ -228,6 +228,7 @@ uint8_t item_check(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
.giver_actor = giver,
.vanilla_item = itemNo,
.current_item = itemNo,
.current_display_item = itemNo,
};
for (const auto& resolve : resolves) {
if (!resolve.mod->active) {
@@ -235,13 +236,21 @@ uint8_t item_check(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
}
if (resolve.fixedValue) {
info.current_item = resolve.itemNo;
info.current_display_item = resolve.itemNo;
continue;
}
uint8_t resolvedItem = info.current_item;
ItemCheckResolution resolution{
.item = info.current_item,
.display_item = dItemNo_NONE_e,
};
try {
if (resolve.fn(resolve.mod->context.get(), &info, &resolvedItem, resolve.userData)) {
info.current_item = resolvedItem;
if (resolve.fn(resolve.mod->context.get(), &info, &resolution, resolve.userData)) {
if (resolution.display_item == UINT8_MAX) {
resolution.display_item = resolution.item;
}
info.current_item = resolution.item;
info.current_display_item = resolution.display_item;
}
} catch (const std::exception& e) {
fail_mod(*resolve.mod, MOD_ERROR,
@@ -251,7 +260,14 @@ uint8_t item_check(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
fmt::format("Unknown exception in item check resolver for '{}'", name));
}
}
return info.current_item;
return {
.item = info.current_item,
.display_item = info.current_display_item,
};
}
uint8_t item_check(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
return item_check_resolve(name, itemNo, giver).item;
}
uint8_t item_check_chest(uint8_t boxNo, uint8_t itemNo, fopAc_ac_c* chest) {
+27 -10
View File
@@ -97,11 +97,11 @@ void notify_gives(const char* checkName, uint8_t itemNo, fopAc_ac_c* giver, Item
void complete_check(uint8_t itemNo, uint32_t giveTag, fopAc_ac_c* giver, ItemGiveOrigin origin) {
if (const auto* committed = s_committedChecks.find(giveTag);
committed != nullptr && committed->resolvedItem != itemNo)
committed != nullptr && committed->resolution.item != itemNo)
{
Log.error("committed check '{}' completed with item {:#x} instead of {:#x}",
item_give_name(giveTag) != nullptr ? item_give_name(giveTag) : "", itemNo,
committed->resolvedItem);
committed->resolution.item);
}
s_committedChecks.erase(giveTag);
notify_gives(item_give_name(giveTag), itemNo, giver, origin);
@@ -241,10 +241,19 @@ uint32_t item_give_tag(const char* name) {
return tag;
}
ItemCheckResolution item_check_resolve(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c* giver) {
if (const auto* committed = s_committedChecks.find(giveTag); committed != nullptr) {
return committed->resolution;
}
const char* name = item_give_name(giveTag);
return name != nullptr ? item_check_resolve(name, itemNo, giver) :
ItemCheckResolution{.item = itemNo, .display_item = itemNo};
}
ItemCheckResult item_check_commit(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c* giver) {
const char* name = item_give_name(giveTag);
if (name == nullptr) {
return {.tag = giveTag, .itemNo = itemNo};
return {.tag = giveTag, .itemNo = itemNo, .displayItemNo = itemNo};
}
if (const auto* committed = s_committedChecks.find(giveTag); committed != nullptr) {
@@ -252,12 +261,20 @@ ItemCheckResult item_check_commit(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c*
Log.error("committed check '{}' changed vanilla item from {:#x} to {:#x}", name,
committed->vanillaItem, itemNo);
}
return {.tag = giveTag, .itemNo = committed->resolvedItem};
return {
.tag = giveTag,
.itemNo = committed->resolution.item,
.displayItemNo = committed->resolution.display_item,
};
}
const auto& committed =
s_committedChecks.commit(giveTag, itemNo, [&] { return item_check(name, itemNo, giver); });
return {.tag = giveTag, .itemNo = committed.resolvedItem};
const auto& committed = s_committedChecks.commit(
giveTag, itemNo, [&] { return item_check_resolve(name, itemNo, giver); });
return {
.tag = giveTag,
.itemNo = committed.resolution.item,
.displayItemNo = committed.resolution.display_item,
};
}
ItemCheckResult item_check_commit(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
@@ -279,10 +296,10 @@ bool item_check_enqueue(ItemCheckResult check, ItemGiveMode mode) {
item_give_name(check.tag) != nullptr ? item_give_name(check.tag) : "");
return false;
}
if (committed->resolvedItem != check.itemNo) {
if (committed->resolution.item != check.itemNo) {
Log.error("committed check '{}' changed item from {:#x} to {:#x}",
item_give_name(check.tag) != nullptr ? item_give_name(check.tag) : "", check.itemNo,
committed->resolvedItem);
committed->resolution.item);
return false;
}
if (committed->queued) {
@@ -292,7 +309,7 @@ bool item_check_enqueue(ItemCheckResult check, ItemGiveMode mode) {
committed->queued = true;
s_giveQueue.push_back({
.tag = check.tag,
.itemNo = committed->resolvedItem,
.itemNo = committed->resolution.item,
.silent = mode == ItemGiveMode::Silent,
.forced = mode == ItemGiveMode::ForcedDemo,
});
+22 -4
View File
@@ -257,9 +257,10 @@ s32 fopAcM_delete(fpc_ProcID i_actorID) {
fpc_ProcID fopAcM_create(s16 i_procName, u16 i_setId, u32 i_parameters, const cXyz* i_pos,
int i_roomNo, const csXyz* i_angle, const cXyz* i_scale, s8 i_argument,
createFunc i_createFunc IF_DUSK_ARG(u32 i_itemGiveTag)) {
createFunc i_createFunc IF_DUSK_ARG(u32 i_itemGiveTag) IF_DUSK_ARG(u8 i_itemOriginalNo)) {
fopAcM_prm_class* append = createAppend(i_setId, i_parameters, i_pos, i_roomNo, i_angle,
i_scale, i_argument, fpcM_ERROR_PROCESS_ID_e IF_DUSK_ARG(i_itemGiveTag));
i_scale, i_argument, fpcM_ERROR_PROCESS_ID_e IF_DUSK_ARG(i_itemGiveTag)
IF_DUSK_ARG(i_itemOriginalNo));
if (append == NULL) {
return fpcM_ERROR_PROCESS_ID_e;
}
@@ -268,9 +269,10 @@ fpc_ProcID fopAcM_create(s16 i_procName, u16 i_setId, u32 i_parameters, const cX
}
fpc_ProcID fopAcM_create(s16 i_procName, u32 i_parameters, const cXyz* i_pos, int i_roomNo,
const csXyz* i_angle, const cXyz* i_scale, s8 i_argument IF_DUSK_ARG(u32 i_itemGiveTag)) {
const csXyz* i_angle, const cXyz* i_scale, s8 i_argument IF_DUSK_ARG(u32 i_itemGiveTag)
IF_DUSK_ARG(u8 i_itemOriginalNo)) {
return fopAcM_create(i_procName, 0xFFFF, i_parameters, i_pos, i_roomNo, i_angle, i_scale,
i_argument, NULL IF_DUSK_ARG(i_itemGiveTag));
i_argument, NULL IF_DUSK_ARG(i_itemGiveTag) IF_DUSK_ARG(i_itemOriginalNo));
}
fopAc_ac_c* fopAcM_fastCreate(s16 i_procName, u32 i_parameters, const cXyz* i_pos, int i_roomNo,
@@ -1606,6 +1608,22 @@ fpc_ProcID fopAcM_createItemForBoss(const cXyz* i_pos, int i_itemNo, int i_roomN
i_itemNo = dusk::mods::item_check_boss(originalItemNo, NULL);
giveTag = dusk::mods::item_give_tag_boss();
}
if (i_itemNo == dItemNo_NONE_e) {
const auto itemCheck = dusk::mods::item_check_commit(giveTag, originalItemNo, NULL);
i_itemNo = itemCheck.itemNo;
if (i_itemNo == dItemNo_NONE_e) {
dusk::mods::item_check_complete(itemCheck, NULL);
dComIfGs_onItem(param_8, i_roomNo);
return fpcM_ERROR_PROCESS_ID_e;
}
}
if (i_itemNo != originalItemNo) {
const u32 params = 0xFFFF0000 | param_8 << 8 | (i_itemNo & 0xFF);
return fopAcM_create(fpcNm_Obj_LifeContainer_e, params, i_pos, i_roomNo, i_angle,
i_scale, -1, giveTag, originalItemNo);
}
#endif
u32 params = 0xFFFF0000 | param_8 << 8 | (i_itemNo & 0xFF);