mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-21 05:34:10 -04:00
ItemService improvements (#2322)
* ItemService improvements * Move Poe increment to item
This commit is contained in:
@@ -97,7 +97,7 @@ public:
|
||||
/* 0xDEC */ u8 field_0xdec[0xdf9 - 0xdec];
|
||||
/* 0xDF9 */ u8 field_0xdf9;
|
||||
#if TARGET_PC
|
||||
bool mItemCheckOverridden;
|
||||
bool mItemCheckHandled;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
#ifndef D_A_D_A_ITEMBASE_STATIC_H
|
||||
#define D_A_D_A_ITEMBASE_STATIC_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
|
||||
class fopAc_ac_c;
|
||||
|
||||
int CheckFieldItemCreateHeap(fopAc_ac_c* actor);
|
||||
int CheckItemCreateHeap(fopAc_ac_c* i_this);
|
||||
|
||||
#if TARGET_PC
|
||||
const char* dItem_fieldModelArc(u8 itemNo);
|
||||
#endif
|
||||
|
||||
#endif /* D_A_D_A_ITEMBASE_STATIC_H */
|
||||
|
||||
@@ -142,7 +142,12 @@ enum {
|
||||
/* 0x2F */ dItemNo_WEAR_KOKIRI_e,
|
||||
/* 0x30 */ dItemNo_ARMOR_e,
|
||||
/* 0x31 */ dItemNo_WEAR_ZORA_e,
|
||||
#if TARGET_PC
|
||||
/* 0x32 */ dItemNo_MAGIC_LV1_e,
|
||||
dItemNo_SHADOW_CRYSTAL_e = dItemNo_MAGIC_LV1_e,
|
||||
#else
|
||||
/* 0x32 */ dItemNo_MAGIC_LV1_e,
|
||||
#endif
|
||||
/* 0x33 */ dItemNo_DUNGEON_EXIT_2_e,
|
||||
/* 0x34 */ dItemNo_WALLET_LV1_e,
|
||||
/* 0x35 */ dItemNo_WALLET_LV2_e,
|
||||
|
||||
+7
-1
@@ -259,13 +259,19 @@ using std::isnan;
|
||||
#if TARGET_PC && defined(DUSK_BUILDING_GAME)
|
||||
#include "dusk/mods/item.hpp"
|
||||
#define DUSK_ITEM_CHECK(name, item_no, giver) \
|
||||
(item_no) = ::dusk::mods::item_check(name, (item_no), giver)
|
||||
(item_no) = ::dusk::mods::item_check_commit(name, (item_no), giver).itemNo
|
||||
#define DUSK_ITEM_CHECK_EXPR(name, item_no, giver) \
|
||||
(::dusk::mods::item_check_commit(name, (item_no), giver).itemNo)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW(name, item_no, giver) \
|
||||
(item_no) = ::dusk::mods::item_check(name, (item_no), giver)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW_EXPR(name, item_no, giver) \
|
||||
(::dusk::mods::item_check(name, (item_no), giver))
|
||||
#define DUSK_GIVE_TAG(name) IF_DUSK_ARG(::dusk::mods::item_give_tag(name))
|
||||
#else
|
||||
#define DUSK_ITEM_CHECK(name, item_no, giver)
|
||||
#define DUSK_ITEM_CHECK_EXPR(name, item_no, giver) (item_no)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW(name, item_no, giver)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW_EXPR(name, item_no, giver) (item_no)
|
||||
#define DUSK_GIVE_TAG(name)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -188,8 +188,6 @@ MOD_EXPORT ModResult mod_initialize(ModError* error) {
|
||||
g_stageHook = 0;
|
||||
return mods::set_error(error, MOD_ERROR, "failed to register mod panel");
|
||||
}
|
||||
|
||||
mods::log::info("auxiliary WebGPU window ready");
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* ItemService check names.
|
||||
*/
|
||||
|
||||
#define ITEM_CHECK_BOSS_PREFIX "boss:" /* <stage> */
|
||||
#define ITEM_CHECK_BUG_PREFIX "bug:" /* <insect_item> */
|
||||
#define ITEM_CHECK_CHEST_PREFIX "chest:" /* <stage>:<box> */
|
||||
#define ITEM_CHECK_FREESTANDING_PREFIX "freestanding:" /* <stage>:<bit> */
|
||||
#define ITEM_CHECK_POE_PREFIX "poe:" /* <stage>:<switch> */
|
||||
#define ITEM_CHECK_SHOP_PREFIX "shop:" /* <stage>:<item> */
|
||||
#define ITEM_CHECK_SKY_PREFIX "sky:" /* <stage>:<room> */
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_PREFIX "dungeon_reward:" /* <stage> */
|
||||
|
||||
#define ITEM_CHECK_ARCHERY_REWARD "archery_reward:F_SP109"
|
||||
#define ITEM_CHECK_ASHEI_SKETCH "ashei_sketch"
|
||||
#define ITEM_CHECK_AURU_MEMO "auru_memo"
|
||||
#define ITEM_CHECK_BALL_AND_CHAIN "ball_and_chain:D_MN11"
|
||||
#define ITEM_CHECK_BULBLIN_KEY "bulblin_key:D_MN09"
|
||||
#define ITEM_CHECK_CORAL_EARRING "coral_earring"
|
||||
#define ITEM_CHECK_CORO_BOTTLE "coro_bottle"
|
||||
#define ITEM_CHECK_DUNGEON_MAP_SNOWPEAK "dungeon_map:D_MN11"
|
||||
#define ITEM_CHECK_FAIRY_REWARD "fairy_reward:D_SB01"
|
||||
#define ITEM_CHECK_FISHING_BOTTLE "fishing_bottle"
|
||||
#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_ILIA_CHARM "ilia_charm"
|
||||
#define ITEM_CHECK_ILIA_MEMORY "ilia_memory"
|
||||
#define ITEM_CHECK_IZA_REWARD_1 "iza_reward_1"
|
||||
#define ITEM_CHECK_IZA_REWARD_2 "iza_reward_2"
|
||||
#define ITEM_CHECK_JOVANI_REWARD_1 "jovani_reward_1"
|
||||
#define ITEM_CHECK_JOVANI_REWARD_2 "jovani_reward_2"
|
||||
#define ITEM_CHECK_KEY_SHARD_1 "key_shard_1:D_MN04"
|
||||
#define ITEM_CHECK_KEY_SHARD_2 "key_shard_2:D_MN04"
|
||||
#define ITEM_CHECK_KEY_SHARD_3 "key_shard_3:D_MN04"
|
||||
#define ITEM_CHECK_ORDON_SHIELD "ordon_shield"
|
||||
#define ITEM_CHECK_ORDON_SWORD "ordon_sword"
|
||||
#define ITEM_CHECK_PLUMM_REWARD "plumm_minigame_reward"
|
||||
#define ITEM_CHECK_PRAYER_REWARD "prayer_reward"
|
||||
#define ITEM_CHECK_RENADO_LETTER "renado_letter"
|
||||
#define ITEM_CHECK_SERA_REWARD "sera_reward"
|
||||
#define ITEM_CHECK_SKYBOOK "skybook"
|
||||
#define ITEM_CHECK_SNOWBOARD_REWARD "snowboard_race_reward"
|
||||
#define ITEM_CHECK_STAR_REWARD_1 "star_reward_1"
|
||||
#define ITEM_CHECK_STAR_REWARD_2 "star_reward_2"
|
||||
#define ITEM_CHECK_TELMA_INVOICE "telma_invoice"
|
||||
#define ITEM_CHECK_ULI_CRADLE_REWARD "uli_cradle_reward"
|
||||
#define ITEM_CHECK_WOOD_STATUE "wood_statue"
|
||||
#define ITEM_CHECK_ZORA_ARMOR "zora_armor"
|
||||
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_FOREST "dungeon_reward:D_MN05"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_GORON "dungeon_reward:D_MN04"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_LAKEBED "dungeon_reward:D_MN01"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_ARBITERS "dungeon_reward:D_MN10"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_SNOWPEAK "dungeon_reward:D_MN11"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_TIME "dungeon_reward:D_MN06"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_CITY "dungeon_reward:D_MN07"
|
||||
|
||||
#define ITEM_CHECK_MASTER_SWORD "master_sword"
|
||||
#define ITEM_CHECK_SHADOW_CRYSTAL "shadow_crystal"
|
||||
@@ -17,10 +17,12 @@ typedef uint64_t ItemGiveHandle;
|
||||
/*
|
||||
* Item check resolution and inventory grants.
|
||||
*
|
||||
* Check names are case-sensitive. Resolvers must be free of side effects because the game may
|
||||
* resolve a check more than once, including once for display and again when granting the item.
|
||||
* Registrations and pending grants are removed when the calling mod is detached. Callbacks run
|
||||
* on the game thread.
|
||||
* Check names are case-sensitive. Resolvers must be free of side effects because previews may be
|
||||
* resolved repeatedly. For checks representing a non-item side effect, vanilla_item is 0xFF:
|
||||
* resolving to 0xFF preserves that side effect, while resolving to another item replaces it.
|
||||
*
|
||||
* Registrations and pending grants are removed when the calling mod is detached. Callbacks run on
|
||||
* the game thread. Check names are listed in <mods/items.h>.
|
||||
*/
|
||||
|
||||
/* Host-owned callback data, valid only for the duration of the callback. */
|
||||
@@ -72,14 +74,14 @@ typedef struct ItemService {
|
||||
|
||||
ModResult (*clear_check_resolver)(ModContext* ctx, ItemCheckHandle handle);
|
||||
|
||||
/* Resolve without granting an item or notifying give observers. */
|
||||
/* Resolve a live preview without granting an item or notifying give observers. */
|
||||
ModResult (*resolve_check)(
|
||||
ModContext* ctx, const char* name, uint8_t vanilla_item, uint8_t* out_item);
|
||||
|
||||
/*
|
||||
* Add a grant to the global FIFO. check_name may be NULL unless ITEM_GIVE_RESOLVE is set.
|
||||
* Returns MOD_UNAVAILABLE when the queue is full. Entries wait until gameplay is in a safe
|
||||
* state and are cleared when the active save slot changes.
|
||||
* Entries wait until gameplay is in a safe state and are cleared when the active save slot
|
||||
* changes.
|
||||
*/
|
||||
ModResult (*give_item)(
|
||||
ModContext* ctx, const char* check_name, uint8_t item_no, uint32_t flags);
|
||||
|
||||
@@ -1027,6 +1027,9 @@ void daAlink_c::setGetItemFace(u16 i_itemNo) {
|
||||
|| i_itemNo == dItemNo_ANCIENT_DOCUMENT2_e
|
||||
|| i_itemNo == dItemNo_DROP_CONTAINER_e
|
||||
|| i_itemNo == dItemNo_DROP_CONTAINER02_e
|
||||
#if TARGET_PC
|
||||
|| i_itemNo == dItemNo_SHADOW_CRYSTAL_e
|
||||
#endif
|
||||
|| i_itemNo == dItemNo_DROP_CONTAINER03_e)
|
||||
{
|
||||
setFaceBasicBck(dRes_ID_ALANM_BCK_FI_e);
|
||||
@@ -2009,7 +2012,11 @@ void daAlink_c::setGetSubBgm(int i_itemNo) {
|
||||
/* dItemNo_WEAR_KOKIRI_e */ SETYPE_NONE,
|
||||
/* dItemNo_ARMOR_e */ SETYPE_ITEM_GET,
|
||||
/* dItemNo_WEAR_ZORA_e */ SETYPE_ITEM_GET,
|
||||
#if TARGET_PC
|
||||
/* dItemNo_SHADOW_CRYSTAL_e */ SETYPE_ITEM_GET,
|
||||
#else
|
||||
/* dItemNo_MAGIC_LV1_e */ SETYPE_NONE,
|
||||
#endif
|
||||
/* dItemNo_DUNGEON_EXIT_2_e */ SETYPE_ITEM_GET_MINI,
|
||||
/* dItemNo_WALLET_LV1_e */ SETYPE_NONE,
|
||||
/* dItemNo_WALLET_LV2_e */ SETYPE_ITEM_GET,
|
||||
@@ -2307,8 +2314,13 @@ int daAlink_c::procCoGetItemInit() {
|
||||
item_no = dComIfGp_event_getGtItm();
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
const u32 giveTag = mDemo.getParam0() != 0x100 && mDemo.getParam1() != 0 ?
|
||||
static_cast<u32>(mDemo.getParam1()) :
|
||||
dusk::mods::item_give_queue_take_tag();
|
||||
#endif
|
||||
fpc_ProcID item_partner_id = fopAcM_createItemForPresentDemo(¤t.pos, item_no, 0, -1,
|
||||
fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(dusk::mods::item_give_queue_take_tag()));
|
||||
fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
if (item_partner_id != fpcM_ERROR_PROCESS_ID_e) {
|
||||
dComIfGp_event_setItemPartnerId(item_partner_id);
|
||||
}
|
||||
@@ -2533,6 +2545,16 @@ int daAlink_c::procCoGetItem() {
|
||||
} else if (mProcVar2.field_0x300c == 0x23 && checkStageName("D_MN11")) {
|
||||
field_0x32cc = 0x5C0;
|
||||
} else if (mProcVar2.field_0x300c == 0xE0) {
|
||||
#if TARGET_PC
|
||||
// Dusklight increments the Poe count when the displayed item is granted.
|
||||
if (dComIfGs_getPohSpiritNum() + 1 == 20) {
|
||||
field_0x32cc = 0x4CF;
|
||||
} else if (dComIfGs_getPohSpiritNum() + 1 == 60) {
|
||||
field_0x32cc = 0x4D0;
|
||||
} else {
|
||||
field_0x32cc = mProcVar2.field_0x300c + 0x65;
|
||||
}
|
||||
#else
|
||||
if (dComIfGs_getPohSpiritNum() == 20) {
|
||||
field_0x32cc = 0x4CF;
|
||||
} else if (dComIfGs_getPohSpiritNum() == 60) {
|
||||
@@ -2540,6 +2562,7 @@ int daAlink_c::procCoGetItem() {
|
||||
} else {
|
||||
field_0x32cc = mProcVar2.field_0x300c + 0x65;
|
||||
}
|
||||
#endif
|
||||
} else if (mProcVar2.field_0x300c == 0x21) {
|
||||
static u32 const heartPieceMessage[5] = {0x86, 0x9C, 0x9D, 0x9E, 0x9F};
|
||||
field_0x32cc = heartPieceMessage[dComIfGs_getMaxLife() % 5];
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include "f_op/f_op_actor_enemy.h"
|
||||
#include "Z2AudioLib/Z2Instances.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
enum daB_DS_Joint {
|
||||
DS_JNT_BACKBONE1,
|
||||
DS_JNT_BACKBONE2,
|
||||
@@ -4086,7 +4090,8 @@ void daB_DS_c::executeBattle2Dead() {
|
||||
dComIfGs_onStageBossEnemy(0x13);
|
||||
#if TARGET_PC
|
||||
// This reward has no original grant at this point in the cutscene.
|
||||
dusk::mods::item_check_enqueue("Arbiters Grounds Dungeon Reward", dItemNo_NONE_e);
|
||||
dusk::mods::item_check_enqueue_deferred(
|
||||
ITEM_CHECK_DUNGEON_REWARD_ARBITERS, dItemNo_NONE_e);
|
||||
#endif
|
||||
/* dSv_event_flag_c::F_0265 - Arbiter's Grounds - Arbiter's Grounds clear */
|
||||
dComIfGs_onEventBit(0x2010);
|
||||
|
||||
@@ -1090,6 +1090,13 @@ inline int daDemo00_c::execute() {
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
#if TARGET_PC
|
||||
// Suppress demo22_01's M_077 write. On Dusklight, the transform flag
|
||||
// is set by the Shadow Crystal item.
|
||||
if (dSv_event_flag_c::saveBitLabels[sp0E] == dSv_event_flag_c::M_077) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[sp0E]);
|
||||
break;
|
||||
|
||||
|
||||
@@ -727,19 +727,25 @@ void daE_HP_c::executeDead() {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
mItemCheckOverridden =
|
||||
dusk::mods::item_check_poe(bitSw, dItemNo_POU_SPIRIT_e, this) != dItemNo_POU_SPIRIT_e;
|
||||
if (mItemCheckOverridden) {
|
||||
dusk::mods::item_check_enqueue_poe(bitSw, dItemNo_POU_SPIRIT_e);
|
||||
} else
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_poe(bitSw), dItemNo_POU_SPIRIT_e, this);
|
||||
mItemCheckHandled = true;
|
||||
if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, this);
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::ForcedDemo);
|
||||
}
|
||||
#else
|
||||
dComIfGs_addPohSpiritNum();
|
||||
#endif
|
||||
dComIfGs_addPohSpiritNum();
|
||||
|
||||
field_0x784 = -1;
|
||||
|
||||
if (dComIfGs_getPohSpiritNum() == 20 IF_DUSK(&&!mItemCheckOverridden)) {
|
||||
#if !TARGET_PC
|
||||
if (dComIfGs_getPohSpiritNum() == 20) {
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[0x1c9]);
|
||||
}
|
||||
#endif
|
||||
|
||||
movemode++;
|
||||
}
|
||||
@@ -759,7 +765,7 @@ void daE_HP_c::executeDead() {
|
||||
field_0x788 = 1;
|
||||
}
|
||||
}
|
||||
} else if (field_0x788 != 0 IF_DUSK(|| mItemCheckOverridden)) {
|
||||
} else if (field_0x788 != 0 IF_DUSK(|| mItemCheckHandled)) {
|
||||
fopAcM_createDisappear(this, ¤t.pos, 8, 3, 0xff);
|
||||
fopAcM_delete(this);
|
||||
} else {
|
||||
|
||||
+21
-12
@@ -1133,21 +1133,24 @@ static void e_po_dead(e_po_class* i_this) {
|
||||
camera_player->mCamera.SetTrimSize(0);
|
||||
dComIfGp_event_reset();
|
||||
#if TARGET_PC
|
||||
if (dusk::mods::item_check_poe(i_this->BitSW, dItemNo_POU_SPIRIT_e, a_this) ==
|
||||
dItemNo_POU_SPIRIT_e)
|
||||
{
|
||||
#endif
|
||||
dComIfGs_addPohSpiritNum();
|
||||
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 {
|
||||
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::ForcedDemo);
|
||||
}
|
||||
#else
|
||||
dComIfGs_addPohSpiritNum();
|
||||
#if !PLATFORM_SHIELD
|
||||
if (dComIfGs_getPohSpiritNum() == 0x14) {
|
||||
/* dSv_event_flag_c::F_0457 - Castle Town - Revived cat */
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[457]);
|
||||
}
|
||||
#endif
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
daPy_getPlayerActorClass()->cancelOriginalDemo();
|
||||
#endif
|
||||
} else if (mArg0Check(i_this, 0) != 0) {
|
||||
if (!fopAcM_isSwitch(a_this, 0x22)) {
|
||||
if (fopAcM_SearchByID(i_this->field_0x5B8, &local_1b0_actor) != 0 &&
|
||||
@@ -1274,10 +1277,16 @@ static void e_po_dead(e_po_class* i_this) {
|
||||
} else {
|
||||
if (i_this->field_0x75C == -1) {
|
||||
#if TARGET_PC
|
||||
const u8 itemNo =
|
||||
dusk::mods::item_check_poe(i_this->BitSW, dItemNo_POU_SPIRIT_e, a_this);
|
||||
i_this->field_0x75C = fopAcM_createItemForPresentDemo(&a_this->current.pos, itemNo,
|
||||
0, -1, -1, NULL, NULL, dusk::mods::item_give_tag_poe(i_this->BitSW));
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_poe(i_this->BitSW), dItemNo_POU_SPIRIT_e, a_this);
|
||||
if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, a_this);
|
||||
i_this->field_0x75B = 1;
|
||||
} else {
|
||||
i_this->field_0x75C = fopAcM_createItemForPresentDemo(
|
||||
&a_this->current.pos, itemCheck.itemNo, 0, -1, -1, NULL, NULL,
|
||||
itemCheck.tag);
|
||||
}
|
||||
#else
|
||||
i_this->field_0x75C = fopAcM_createItemForPresentDemo(&a_this->current.pos, 0xE0, 0,
|
||||
-1, -1, NULL, NULL);
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#include "f_op/f_op_camera_mng.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
class daE_RDB_HIO_c : public JORReflexible {
|
||||
public:
|
||||
daE_RDB_HIO_c();
|
||||
@@ -1250,9 +1254,18 @@ static void demo_camera(e_rdb_class* i_this) {
|
||||
}
|
||||
|
||||
if (iVar1 != 0) {
|
||||
daPy_getPlayerActorClass()->changeDemoMode(11,
|
||||
DUSK_ITEM_CHECK_EXPR("bulblin_key:D_MN09", dItemNo_SMALL_KEY_e, &i_this->enemy), 0,
|
||||
0);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_BULBLIN_KEY, dItemNo_SMALL_KEY_e, &i_this->enemy);
|
||||
if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, &i_this->enemy);
|
||||
}
|
||||
daPy_getPlayerActorClass()->changeDemoMode(
|
||||
11, itemCheck.itemNo == dItemNo_NONE_e ? 0 : itemCheck.itemNo,
|
||||
itemCheck.itemNo == dItemNo_NONE_e ? 0 : static_cast<int>(itemCheck.tag), 0);
|
||||
#else
|
||||
daPy_getPlayerActorClass()->changeDemoMode(11, dItemNo_SMALL_KEY_e, 0, 0);
|
||||
#endif
|
||||
i_this->mDemoMode = 12;
|
||||
i_this->field_0x10aa = 0;
|
||||
i_this->field_0xfe5 = 1;
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/version.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
class dmg_rod_HIO_c : public JORReflexible {
|
||||
@@ -2955,7 +2957,17 @@ static void lure_heart(dmg_rod_class* i_this) {
|
||||
if (obj_life != NULL) {
|
||||
fopAcM_delete(obj_life);
|
||||
fopAcM_onItem(obj_life, 0x80);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_FISHING_HEART_PIECE, dItemNo_KAKERA_HEART_e, actor);
|
||||
if (itemCheck.itemNo == dItemNo_KAKERA_HEART_e) {
|
||||
execItemGet(dItemNo_KAKERA_HEART_e, itemCheck.tag, actor);
|
||||
} else if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, actor);
|
||||
}
|
||||
#else
|
||||
execItemGet(dItemNo_KAKERA_HEART_e);
|
||||
#endif
|
||||
u8 eventReg = dComIfGs_getEventReg(0xECFF);
|
||||
eventReg |= (u8)0x40;
|
||||
dComIfGs_setEventReg(0xECFF, eventReg);
|
||||
@@ -4090,7 +4102,15 @@ static void uki_catch(dmg_rod_class* i_this) {
|
||||
} else if (mgfish->mCaughtType == MG_CATCH_BIN) {
|
||||
i_this->msgflow.init(actor, 0x139A, 0, NULL);
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[468]);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_FISHING_BOTTLE, dItemNo_EMPTY_BOTTLE_e, actor);
|
||||
if (itemCheck.itemNo == dItemNo_EMPTY_BOTTLE_e) {
|
||||
dComIfGs_setEmptyBottle();
|
||||
}
|
||||
#else
|
||||
dComIfGs_setEmptyBottle();
|
||||
#endif
|
||||
} else if (mgfish->mCaughtType == MG_CATCH_KN) {
|
||||
i_this->msgflow.init(actor, 0x139C, 0, NULL);
|
||||
} else if (mgfish->mCaughtType == MG_CATCH_ED) {
|
||||
@@ -4167,6 +4187,18 @@ static void uki_catch(dmg_rod_class* i_this) {
|
||||
if (mgfish->mCaughtType == MG_CATCH_LH) {
|
||||
dComIfGp_setItemRupeeCount(10.0f + cM_rndF(40.9f));
|
||||
}
|
||||
#if TARGET_PC
|
||||
else if (mgfish->mCaughtType == MG_CATCH_BIN)
|
||||
{
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_FISHING_BOTTLE, dItemNo_EMPTY_BOTTLE_e, actor);
|
||||
if (itemCheck.itemNo == dItemNo_EMPTY_BOTTLE_e ||
|
||||
itemCheck.itemNo == dItemNo_NONE_e)
|
||||
{
|
||||
dusk::mods::item_check_complete(itemCheck, actor);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
dComIfGs_addFishNum(fish_kind);
|
||||
if (i_this->field_0x14c0 != 0) {
|
||||
|
||||
@@ -1806,17 +1806,21 @@ int daNpcChin_c::_Evt_GameSucceed_CutMain(const int& param_0) {
|
||||
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (itemId1 == dItemNo_ARROW_LV2_e) {
|
||||
itemCheckName = "star_reward_1";
|
||||
} else if (itemId1 == dItemNo_ARROW_LV3_e) {
|
||||
itemCheckName = "star_reward_2";
|
||||
}
|
||||
if (itemCheckName != nullptr) {
|
||||
itemId1 = dusk::mods::item_check(itemCheckName, itemId1, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(itemCheckName, itemId1, this);
|
||||
itemId1 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
fpc_ProcID itemId2 = fopAcM_createItemForPresentDemo(¤t.pos, itemId1, 0, -1, -1,
|
||||
0, 0 IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
0, 0 IF_DUSK_ARG(itemGiveTag));
|
||||
if (itemId2 != -1) {
|
||||
dComIfGp_event_setItemPartnerId(itemId2);
|
||||
}
|
||||
|
||||
@@ -4019,14 +4019,16 @@ BOOL daNpc_grA_c::talk(void*) {
|
||||
if (r26 && talkProc(NULL, TRUE, NULL)) {
|
||||
if (mFlow.getEventId(&sp8) == 1) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (sp8 == dItemNo_BOMB_IN_BAG_e) {
|
||||
itemCheckName = "goron_reward:F_SP113";
|
||||
sp8 = dusk::mods::item_check(itemCheckName, sp8, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("goron_reward:F_SP113", sp8, this);
|
||||
sp8 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
field_0x1480 = fopAcM_createItemForPresentDemo(¤t.pos, sp8, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
if (field_0x1480 != fpcM_ERROR_PROCESS_ID_e) {
|
||||
s16 r25 = dComIfGp_getEventManager().getEventIdx(this, "DEFAULT_GETITEM", 0xff);
|
||||
dComIfGp_getEvent()->reset(this);
|
||||
|
||||
@@ -1495,9 +1495,11 @@ int daNpcIns_c::talk(void* param_1) {
|
||||
#if TARGET_PC
|
||||
u32 itemGiveTag = 0;
|
||||
if (s_givenInsectId != dItemNo_NONE_e) {
|
||||
itemNo = dusk::mods::item_check_bug(
|
||||
s_givenInsectId, itemNo & 0xFF, this);
|
||||
itemGiveTag = dusk::mods::item_give_tag_bug(s_givenInsectId);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_bug(s_givenInsectId), itemNo & 0xFF,
|
||||
this);
|
||||
itemNo = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
s_givenInsectId = dItemNo_NONE_e;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1182,15 +1182,17 @@ int daNpc_Kkri_c::talk(void*) {
|
||||
case 1:
|
||||
if (mItemPartnerId == fpcM_ERROR_PROCESS_ID_e) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (item_no == dItemNo_OIL_BOTTLE3_e) {
|
||||
itemCheckName = "coro_bottle";
|
||||
item_no = dusk::mods::item_check(itemCheckName, item_no, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("coro_bottle", item_no, this);
|
||||
item_no = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(¤t.pos, item_no,
|
||||
0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
|
||||
if (fopAcM_IsExecuting(mItemPartnerId)) {
|
||||
|
||||
@@ -1192,14 +1192,16 @@ int daNpc_myna2_c::ECut_gameGoalSuccess(int i_staffId) {
|
||||
int itemNo = 0;
|
||||
if (mFlow.getEventId(&itemNo) == 1) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (itemNo == dItemNo_KAKERA_HEART_e) {
|
||||
itemCheckName = "plumm_minigame_reward";
|
||||
itemNo = dusk::mods::item_check(itemCheckName, itemNo, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("plumm_minigame_reward", itemNo, this);
|
||||
itemNo = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemPid = fopAcM_createItemForPresentDemo(¤t.pos, itemNo, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -960,17 +960,21 @@ int daNpc_Pouya_c::cutHaveFavorToAsk(int param_0) {
|
||||
if (mItemPartnerId == fpcM_ERROR_PROCESS_ID_e) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (local_64 == dItemNo_DROP_BOTTLE_e) {
|
||||
itemCheckName = "jovani_reward_1";
|
||||
} else if (local_64 == dItemNo_SILVER_RUPEE_e) {
|
||||
itemCheckName = "jovani_reward_2";
|
||||
}
|
||||
if (itemCheckName != nullptr) {
|
||||
local_64 = dusk::mods::item_check(itemCheckName, local_64, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(itemCheckName, local_64, this);
|
||||
local_64 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(¤t.pos, local_64, 0,
|
||||
-1, -1, 0, 0 IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
-1, -1, 0, 0 IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
if (fopAcM_IsExecuting(mItemPartnerId)) {
|
||||
field_0xfce = 1;
|
||||
|
||||
@@ -2611,17 +2611,21 @@ BOOL daNpc_zrA_c::ECut_thanksBlast(int i_staffID) {
|
||||
if (mFlow.getEventId(&item_id) == 1) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (item_id == dItemNo_BOMB_IN_BAG_e) {
|
||||
itemCheckName = "iza_reward_1";
|
||||
} else if (item_id == dItemNo_BOMB_BAG_LV2_e) {
|
||||
itemCheckName = "iza_reward_2";
|
||||
}
|
||||
if (itemCheckName != nullptr) {
|
||||
item_id = dusk::mods::item_check(itemCheckName, item_id, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(itemCheckName, item_id, this);
|
||||
item_id = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemID = fopAcM_createItemForPresentDemo(¤t.pos, item_id, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
field_0x9eb = true;
|
||||
break;
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
#include "d/actor/d_a_obj_ystone.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
static DUSK_CONST char* l_arcName = "ef_Portal";
|
||||
|
||||
static char const* l_clearEvName[9] = {
|
||||
@@ -77,6 +82,27 @@ static int getNowLevel() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static const char* dungeon_reward_check_name(int level) {
|
||||
switch (level) {
|
||||
case 0:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_FOREST;
|
||||
case 1:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_GORON;
|
||||
case 2:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_LAKEBED;
|
||||
case 4:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_SNOWPEAK;
|
||||
case 5:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_TIME;
|
||||
case 6:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_CITY;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void daObjBossWarp_c::initBaseMtx() {
|
||||
scale.y = 0.15f;
|
||||
mpModel->setBaseScale(scale);
|
||||
@@ -485,6 +511,9 @@ int daObjBossWarp_c::demoProc() {
|
||||
player->onSceneChangeArea(scene, 0xff, 0);
|
||||
break;
|
||||
case 4: // STONE_FALL
|
||||
#if TARGET_PC
|
||||
{
|
||||
#endif
|
||||
if (ystone != NULL) {
|
||||
mYstonePos = ystone->current.pos;
|
||||
if (getNowLevel() < 3) {
|
||||
@@ -506,28 +535,52 @@ int daObjBossWarp_c::demoProc() {
|
||||
mDoMtx_stack_c::multVec(&mYstoneTargetPos, &mYstoneTargetPos);
|
||||
mYstonePos.x = mYstoneTargetPos.x;
|
||||
mYstonePos.z = mYstoneTargetPos.z;
|
||||
switch (getNowLevel()) {
|
||||
case 0:
|
||||
dComIfGs_onCollectCrystal(0);
|
||||
break;
|
||||
case 1:
|
||||
dComIfGs_onCollectCrystal(1);
|
||||
break;
|
||||
case 2:
|
||||
dComIfGs_onCollectCrystal(2);
|
||||
break;
|
||||
case 4:
|
||||
dComIfGs_onCollectMirror(1);
|
||||
break;
|
||||
case 5:
|
||||
dComIfGs_onCollectMirror(2);
|
||||
break;
|
||||
case 6:
|
||||
dComIfGs_onCollectMirror(3);
|
||||
break;
|
||||
#if TARGET_PC
|
||||
int level = getNowLevel();
|
||||
const char* checkName = dungeon_reward_check_name(level);
|
||||
dusk::mods::ItemCheckResult itemCheck{};
|
||||
bool applyVanillaReward = true;
|
||||
if (checkName != nullptr) {
|
||||
itemCheck = dusk::mods::item_check_commit(checkName, dItemNo_NONE_e, this);
|
||||
applyVanillaReward = itemCheck.itemNo == dItemNo_NONE_e;
|
||||
}
|
||||
if (applyVanillaReward) {
|
||||
switch (level) {
|
||||
#else
|
||||
switch (getNowLevel()) {
|
||||
#endif
|
||||
case 0:
|
||||
dComIfGs_onCollectCrystal(0);
|
||||
break;
|
||||
case 1:
|
||||
dComIfGs_onCollectCrystal(1);
|
||||
break;
|
||||
case 2:
|
||||
dComIfGs_onCollectCrystal(2);
|
||||
break;
|
||||
case 4:
|
||||
dComIfGs_onCollectMirror(1);
|
||||
break;
|
||||
case 5:
|
||||
dComIfGs_onCollectMirror(2);
|
||||
break;
|
||||
case 6:
|
||||
dComIfGs_onCollectMirror(3);
|
||||
break;
|
||||
}
|
||||
#if TARGET_PC
|
||||
if (checkName != nullptr) {
|
||||
dusk::mods::item_check_complete(itemCheck, this);
|
||||
}
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::Silent);
|
||||
}
|
||||
#endif
|
||||
mCounter = 0;
|
||||
break;
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
case 5: // STONE_MIDNA
|
||||
mCounter = 0;
|
||||
break;
|
||||
|
||||
@@ -287,7 +287,11 @@ int daItem_c::_daItem_create() {
|
||||
BOOL flag = dItem_data::chkFlag(m_itemNo, 2);
|
||||
|
||||
#if DEBUG
|
||||
#if TARGET_PC
|
||||
if (dItem_fieldModelArc(m_itemNo) == NULL) {
|
||||
#else
|
||||
if (dItem_data::getFieldArc(m_itemNo) == NULL) {
|
||||
#endif
|
||||
// "Item Num<%d>: No Resource Archive specified!!\n"
|
||||
OS_REPORT_ERROR("アイテム番号<%d>:リソースのアーカイブ指定がありません!!\n", m_itemNo);
|
||||
return cPhs_ERROR_e;
|
||||
@@ -319,6 +323,20 @@ int daItem_c::_daItem_create() {
|
||||
if (flag) {
|
||||
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
|
||||
phase_state = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(this, CheckFieldItemCreateHeap,
|
||||
@@ -412,7 +430,11 @@ int daItem_c::_daItem_delete() {
|
||||
mSparkleEmtr.remove();
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
DeleteBase(dItem_fieldModelArc(m_itemNo));
|
||||
#else
|
||||
DeleteBase(dItem_data::getFieldArc(m_itemNo));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -520,9 +542,10 @@ void daItem_c::procInitGetDemoEvent() {
|
||||
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = m_itemNo;
|
||||
if (mItemOverridden) {
|
||||
m_itemNo = dusk::mods::item_check_tagged(mItemGiveTag, mOriginalItemNo, this);
|
||||
}
|
||||
const auto itemCheck = dusk::mods::item_check_commit(mItemGiveTag, mOriginalItemNo, this);
|
||||
m_itemNo = itemCheck.itemNo;
|
||||
mItemGiveTag = itemCheck.tag;
|
||||
mItemOverridden = m_itemNo != mOriginalItemNo;
|
||||
#endif
|
||||
m_item_id = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(mItemGiveTag));
|
||||
@@ -907,9 +930,10 @@ void daItem_c::itemGetNextExecute() {
|
||||
void daItem_c::itemGet() {
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = m_itemNo;
|
||||
if (mItemOverridden) {
|
||||
m_itemNo = dusk::mods::item_check_tagged(mItemGiveTag, mOriginalItemNo, this);
|
||||
}
|
||||
const auto itemCheck = dusk::mods::item_check_commit(mItemGiveTag, mOriginalItemNo, this);
|
||||
m_itemNo = itemCheck.itemNo;
|
||||
mItemGiveTag = itemCheck.tag;
|
||||
mItemOverridden = m_itemNo != mOriginalItemNo;
|
||||
#endif
|
||||
switch (m_itemNo) {
|
||||
#if TARGET_PC
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/actor/d_a_obj_life_container.h"
|
||||
#include "d/d_a_itembase_static.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "d/d_item_data.h"
|
||||
@@ -184,11 +185,23 @@ int daObjLife_c::create() {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
#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));
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(
|
||||
this, useGetModel ? CheckItemCreateHeap : CheckFieldItemCreateHeap, 0x4000))
|
||||
{
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
#else
|
||||
int phase_state = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(this, CheckFieldItemCreateHeap, 0x4000)) {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Create()) {
|
||||
return cPhs_ERROR_e;
|
||||
@@ -325,9 +338,10 @@ int daObjLife_c::initActionOrderGetDemo() {
|
||||
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = m_itemNo;
|
||||
if (mItemOverridden) {
|
||||
m_itemNo = dusk::mods::item_check_tagged(mItemGiveTag, mOriginalItemNo, this);
|
||||
}
|
||||
const auto itemCheck = dusk::mods::item_check_commit(mItemGiveTag, mOriginalItemNo, this);
|
||||
m_itemNo = itemCheck.itemNo;
|
||||
mItemGiveTag = itemCheck.tag;
|
||||
mItemOverridden = m_itemNo != mOriginalItemNo;
|
||||
#endif
|
||||
mItemId = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(mItemGiveTag));
|
||||
@@ -519,7 +533,11 @@ int daObjLife_c::_delete() {
|
||||
endEffect00();
|
||||
endEffect02();
|
||||
|
||||
#if TARGET_PC
|
||||
DeleteBase(dItem_fieldModelArc(m_itemNo));
|
||||
#else
|
||||
DeleteBase(dItem_data::getFieldArc(m_itemNo));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file d_a_obj_master_sword.cpp
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
@@ -10,6 +10,12 @@
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "d/d_item.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
DUSK_GAME_DATA daObjMasterSword_Attr_c const daObjMasterSword_c::mAttr = {1.0f};
|
||||
|
||||
void daObjMasterSword_c::initBaseMtx() {
|
||||
@@ -145,7 +151,11 @@ void daObjMasterSword_c::create_init() {
|
||||
int daObjMasterSword_c::create() {
|
||||
fopAcM_ct(this, daObjMasterSword_c);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dComIfGs_isEventBit(dSv_event_flag_c::F_0264)) {
|
||||
#else
|
||||
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[getFlagNo()])) {
|
||||
#endif
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
@@ -186,12 +196,41 @@ int daObjMasterSword_c::execute() {
|
||||
mBrk.play();
|
||||
|
||||
if (dComIfGs_isTmpBit(dSv_event_tmp_flag_c::tempBitLabels[73])) {
|
||||
#if TARGET_PC
|
||||
const auto masterSword = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_MASTER_SWORD, dItemNo_MASTER_SWORD_e, this);
|
||||
if (masterSword.itemNo == dItemNo_MASTER_SWORD_e) {
|
||||
dComIfGs_onItemFirstBit(dItemNo_MASTER_SWORD_e);
|
||||
dMeter2Info_setSword(dItemNo_MASTER_SWORD_e, false);
|
||||
dComIfGs_setSelectEquipSword(dItemNo_MASTER_SWORD_e);
|
||||
dusk::mods::item_check_complete(masterSword, this);
|
||||
} else if (masterSword.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(masterSword, this);
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(masterSword, dusk::mods::ItemGiveMode::Demo);
|
||||
}
|
||||
|
||||
dComIfGp_setItemLifeCount(dComIfGs_getMaxLife(), 0);
|
||||
|
||||
const auto shadowCrystal = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_SHADOW_CRYSTAL, dItemNo_SHADOW_CRYSTAL_e, this);
|
||||
if (shadowCrystal.itemNo == dItemNo_SHADOW_CRYSTAL_e) {
|
||||
execItemGet(shadowCrystal.itemNo, shadowCrystal.tag, this);
|
||||
} else if (shadowCrystal.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(shadowCrystal, this);
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(shadowCrystal, dusk::mods::ItemGiveMode::Demo);
|
||||
}
|
||||
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::F_0264);
|
||||
#else
|
||||
dComIfGs_onItemFirstBit(dItemNo_MASTER_SWORD_e);
|
||||
dMeter2Info_setSword(dItemNo_MASTER_SWORD_e, false);
|
||||
dComIfGs_setSelectEquipSword(dItemNo_MASTER_SWORD_e);
|
||||
|
||||
dComIfGp_setItemLifeCount(dComIfGs_getMaxLife(), 0);
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[getFlagNo()]);
|
||||
#endif
|
||||
fopAcM_delete(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ int daItemShield_c::__CreateHeap() {
|
||||
int daItemShield_c::create() {
|
||||
fopAcM_ct(this, daItemShield_c);
|
||||
m_itemNo = dItemNo_WOOD_SHIELD_e;
|
||||
DUSK_ITEM_CHECK("ordon_shield", m_itemNo, this);
|
||||
DUSK_ITEM_CHECK_PREVIEW("ordon_shield", m_itemNo, this);
|
||||
if (fopAcM_isSwitch(this, getSwBit2())) {
|
||||
OS_REPORT("木の盾:もう取ったので出ません\n");
|
||||
return cPhs_ERROR_e;
|
||||
|
||||
@@ -37,7 +37,7 @@ int daObjSword_c::Create() {
|
||||
cPhs_Step daObjSword_c::create() {
|
||||
fopAcM_ct(this, daObjSword_c);
|
||||
m_itemNo = 0x28;
|
||||
DUSK_ITEM_CHECK("ordon_sword", m_itemNo, this);
|
||||
DUSK_ITEM_CHECK_PREVIEW("ordon_sword", m_itemNo, this);
|
||||
if (fopAcM_isItem(this, getItemBit())) {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ int daObjZCloth_c::Create() {
|
||||
int daObjZCloth_c::create() {
|
||||
fopAcM_ct(this, daObjZCloth_c);
|
||||
m_itemNo = 0x31;
|
||||
DUSK_ITEM_CHECK("zora_armor", m_itemNo, this);
|
||||
DUSK_ITEM_CHECK_PREVIEW("zora_armor", m_itemNo, this);
|
||||
int phase = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
|
||||
if (phase == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(this, (heapCallbackFunc)CheckFieldItemCreateHeap, 0x2fb0)) {
|
||||
|
||||
@@ -363,10 +363,13 @@ int daTagStatue_c::demoProc() {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
item = dusk::mods::item_check_sky_character(item & 0xFF, this);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_sky_character(), item & 0xFF, this);
|
||||
item = itemCheck.itemNo;
|
||||
#endif
|
||||
mItemId = fopAcM_createItemForTrBoxDemo(¤t.pos, item, -1,
|
||||
fopAcM_GetRoomNo(this), 0, 0 IF_DUSK_ARG(dusk::mods::item_give_tag_sky_character()));
|
||||
mItemId =
|
||||
fopAcM_createItemForTrBoxDemo(¤t.pos, item, -1, fopAcM_GetRoomNo(this), 0,
|
||||
0 IF_DUSK_ARG(itemCheck.tag));
|
||||
|
||||
JUT_ASSERT(580, mItemId != fpcM_ERROR_PROCESS_ID_e);
|
||||
|
||||
|
||||
@@ -1391,8 +1391,9 @@ u8 daTbox_c::getBombItemNoMain(u8 i_itemNo) {
|
||||
int daTbox_c::setGetDemoItem() {
|
||||
u8 item_no = getItemNo();
|
||||
#if TARGET_PC
|
||||
const u32 giveTag = dusk::mods::item_give_tag_chest(getTboxNo());
|
||||
item_no = dusk::mods::item_check_tagged(giveTag, mOriginalItemNo, this);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_chest(getTboxNo()), mOriginalItemNo, this);
|
||||
item_no = itemCheck.itemNo;
|
||||
#endif
|
||||
if (item_no == dItemNo_BOMB_5_e || item_no == dItemNo_BOMB_10_e || item_no == dItemNo_BOMB_20_e || item_no == dItemNo_BOMB_30_e ||
|
||||
item_no == dItemNo_WATER_BOMB_5_e || item_no == dItemNo_WATER_BOMB_10_e || item_no == dItemNo_WATER_BOMB_20_e || item_no == dItemNo_WATER_BOMB_30_e ||
|
||||
@@ -1404,10 +1405,10 @@ int daTbox_c::setGetDemoItem() {
|
||||
fpc_ProcID item_id;
|
||||
if (field_0x718) {
|
||||
item_id = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
} else {
|
||||
item_id = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
}
|
||||
|
||||
if (item_id != fpcM_ERROR_PROCESS_ID_e) {
|
||||
|
||||
@@ -383,15 +383,18 @@ int daTbox2_c::setGetDemoItem() {
|
||||
u8 item_no = getItemNo();
|
||||
#if TARGET_PC
|
||||
int tboxNo = fopAcM_GetParamBit(this, 16, 8);
|
||||
const u32 giveTag = dusk::mods::item_give_tag_chest(tboxNo);
|
||||
item_no = dusk::mods::item_check_tagged(giveTag, mOriginalItemNo, this);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_chest(tboxNo), mOriginalItemNo, this);
|
||||
item_no = itemCheck.itemNo;
|
||||
#endif
|
||||
|
||||
u32 partner_id;
|
||||
if (mReturnRupee) {
|
||||
partner_id = fopAcM_createItemForPresentDemo(¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
partner_id = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
} else {
|
||||
partner_id = fopAcM_createItemForTrBoxDemo(¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
partner_id = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
}
|
||||
|
||||
if (partner_id != -1) {
|
||||
|
||||
@@ -57,6 +57,13 @@ int CheckItemCreateHeap(fopAc_ac_c* i_this) {
|
||||
dItem_data::getBrkName(item_no), dItem_data::getBtpName(item_no));
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
const char* dItem_fieldModelArc(u8 itemNo) {
|
||||
const char* arcName = dItem_data::getFieldArc(itemNo);
|
||||
return arcName != NULL ? arcName : dItem_data::getArcName(itemNo);
|
||||
}
|
||||
#endif
|
||||
|
||||
int CheckFieldItemCreateHeap(fopAc_ac_c* i_this) {
|
||||
daItemBase_c* a_this = static_cast<daItemBase_c*>(i_this);
|
||||
|
||||
|
||||
+17
-1
@@ -741,8 +741,12 @@ void item_func_ARMOR() {}
|
||||
void item_func_WEAR_ZORA() {}
|
||||
|
||||
void item_func_MAGIC_LV1() {
|
||||
#if TARGET_PC
|
||||
dComIfGs_onEventBit(0xD04);
|
||||
#else
|
||||
dComIfGp_setItemMagicCount(16);
|
||||
dComIfGp_setItemMaxMagicCount(16);
|
||||
#endif
|
||||
}
|
||||
|
||||
void item_func_DUNGEON_EXIT_2() {
|
||||
@@ -1152,7 +1156,15 @@ void item_func_M_MAYFLY() {}
|
||||
|
||||
void item_func_F_MAYFLY() {}
|
||||
|
||||
void item_func_POU_SPIRIT() {}
|
||||
void item_func_POU_SPIRIT() {
|
||||
#if TARGET_PC
|
||||
dComIfGs_addPohSpiritNum();
|
||||
if (dComIfGs_getPohSpiritNum() == 20) {
|
||||
/* dSv_event_flag_c::F_0457 - Castle Town - Revived cat */
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[457]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void item_func_ANCIENT_DOCUMENT() {
|
||||
dComIfGs_setItem(SLOT_22, dItemNo_ANCIENT_DOCUMENT_e);
|
||||
@@ -1411,7 +1423,11 @@ int item_getcheck_func_WEAR_ZORA() {
|
||||
}
|
||||
|
||||
int item_getcheck_func_MAGIC_LV1() {
|
||||
#if TARGET_PC
|
||||
return dComIfGs_isEventBit(0xD04);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int item_getcheck_func_DUNGEON_EXIT_2() {
|
||||
|
||||
@@ -53,7 +53,11 @@ DUSK_GAME_DATA dItem_itemResource dItem_data::item_resource[] = {
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x006B, 0x64, 0x0000},
|
||||
{"O_gD_marm", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x0041, 0x64, 0x01A9},
|
||||
{"O_gD_zora", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x004D, 0x64, 0x01AA},
|
||||
#if TARGET_PC
|
||||
{"O_gD_Injy", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x002E, 0x64, 0x0000},
|
||||
#else
|
||||
{"O_gD_Injy", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x002D, 0x64, 0x0000},
|
||||
#endif
|
||||
{"O_gD_TKS", 0x0008,-0x0001, 0x0005,-0x0001,-0x0001, -0x1, -0x1, 0x0028, 0x64, 0x0000},
|
||||
{"O_gD_puL2", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x0047, 0x64, 0x0000},
|
||||
{"O_gD_puL2", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x0048, 0x64, 0x0000},
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "dusk/language.hpp"
|
||||
#include "dusk/logging.h"
|
||||
#include "dusk/menu_pointer.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "dusk/mods/svc/flow.hpp"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/version.hpp"
|
||||
@@ -832,6 +833,9 @@ u32 dMsgObject_c::getMessageIndex(u32 param_0) {
|
||||
|
||||
u32 dMsgObject_c::getRevoMessageIndex(u32 param_1) {
|
||||
#if TARGET_PC
|
||||
const u16 sourceGroup = param_1 > 5000 ? static_cast<u16>(s_groupID) : 0;
|
||||
param_1 = dusk::mods::item_check_message(sourceGroup, param_1);
|
||||
|
||||
u16 customGroup = 0;
|
||||
if (param_1 <= 0xffff &&
|
||||
dusk::flow::custom_message_group(static_cast<u16>(param_1), customGroup))
|
||||
|
||||
+28
-2
@@ -42,7 +42,9 @@
|
||||
#if TARGET_PC
|
||||
#include "dusk/autosave.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "dusk/ui/ui.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
@@ -1192,11 +1194,35 @@ static int phase_1(dScnPly_c* i_this) {
|
||||
}
|
||||
|
||||
// Stage: Ordon Spring, Room: Ordon Spring
|
||||
#if TARGET_PC
|
||||
const bool iliaMemoryArrival =
|
||||
!strcmp(dComIfGp_getStartStageName(), "F_SP104") && dComIfGp_getStartStageRoomNo() == 1 &&
|
||||
dComIfGp_getStartStagePoint() == 23 && dComIfGp_getStartStageLayer() == 12;
|
||||
const u32 iliaMemoryTag = dusk::mods::item_give_tag(ITEM_CHECK_ILIA_MEMORY);
|
||||
if (!iliaMemoryArrival) {
|
||||
dusk::mods::item_check_cancel(iliaMemoryTag);
|
||||
}
|
||||
if (iliaMemoryArrival)
|
||||
#else
|
||||
if (!strcmp(dComIfGp_getStartStageName(), "F_SP104") && dComIfGp_getStartStageRoomNo() == 1 &&
|
||||
dComIfGp_getStartStagePoint() == 23 && dComIfGp_getStartStageLayer() == 12)
|
||||
#endif
|
||||
{
|
||||
dComIfGs_onItemFirstBit(dItemNo_HORSE_FLUTE_e);
|
||||
dComIfGs_setItem(SLOT_21, dItemNo_HORSE_FLUTE_e);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(iliaMemoryTag, dItemNo_HORSE_FLUTE_e, nullptr);
|
||||
if (itemCheck.itemNo == dItemNo_HORSE_FLUTE_e) {
|
||||
#endif
|
||||
dComIfGs_onItemFirstBit(dItemNo_HORSE_FLUTE_e);
|
||||
dComIfGs_setItem(SLOT_21, dItemNo_HORSE_FLUTE_e);
|
||||
#if TARGET_PC
|
||||
dusk::mods::item_check_complete(itemCheck, nullptr);
|
||||
} else if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, nullptr);
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::Silent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((u8)dKy_darkworld_stage_check(dComIfGp_getStartStageName(),
|
||||
|
||||
@@ -906,15 +906,17 @@ int dShopSystem_c::seq_start(fopAc_ac_c* actor, dMsgFlow_c* i_flow) {
|
||||
if (mFlow.getEventId(&itemNo) == 1) {
|
||||
if (mItemPartnerId == fpcM_ERROR_PROCESS_ID_e) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (itemNo == dItemNo_HALF_MILK_BOTTLE_e) {
|
||||
itemCheckName = "sera_reward";
|
||||
itemNo = dusk::mods::item_check(itemCheckName, itemNo, actor);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("sera_reward", itemNo, actor);
|
||||
itemNo = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemPartnerId =
|
||||
fopAcM_createItemForPresentDemo(¤t.pos, itemNo, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
|
||||
if (fpcEx_IsExist(mItemPartnerId)) {
|
||||
@@ -1205,7 +1207,9 @@ int dShopSystem_c::seq_decide_yes(fopAc_ac_c* actor, dMsgFlow_c* i_flow) {
|
||||
if (mItemPartnerId == fpcM_ERROR_PROCESS_ID_e) {
|
||||
#if TARGET_PC
|
||||
const u32 itemGiveTag = dusk::mods::item_give_tag_shop(itemNo & 0xFF);
|
||||
itemNo = dusk::mods::item_check_shop(itemNo & 0xFF, actor);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(itemGiveTag, itemNo & 0xFF, actor);
|
||||
itemNo = itemCheck.itemNo;
|
||||
#endif
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, itemNo, 0, -1, -1, NULL, NULL IF_DUSK_ARG(itemGiveTag));
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace dusk {
|
||||
{ dItemNo_WEAR_KOKIRI_e, {"Hero's Clothes"} },
|
||||
{ dItemNo_ARMOR_e, {"Magic Armor"} },
|
||||
{ dItemNo_WEAR_ZORA_e, {"Zora Armor"} },
|
||||
{ dItemNo_MAGIC_LV1_e, {"Magic Level 1"} },
|
||||
{ dItemNo_SHADOW_CRYSTAL_e, {"Shadow Crystal"} },
|
||||
{ dItemNo_DUNGEON_EXIT_2_e, {"Ooccoo Sr.", ITEMTYPE_EQUIP_e} },
|
||||
{ dItemNo_WALLET_LV1_e, {"Wallet"} },
|
||||
{ dItemNo_WALLET_LV2_e, {"Big Wallet"} },
|
||||
|
||||
+67
-6
@@ -1,21 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
|
||||
class fopAc_ac_c;
|
||||
|
||||
namespace dusk::mods {
|
||||
|
||||
enum class ItemGiveMode : uint8_t {
|
||||
Demo,
|
||||
Silent,
|
||||
ForcedDemo,
|
||||
};
|
||||
|
||||
struct ItemCheckResult {
|
||||
uint32_t tag = 0;
|
||||
uint8_t itemNo = 0;
|
||||
};
|
||||
|
||||
uint8_t item_check(const char* name, uint8_t itemNo, fopAc_ac_c* giver);
|
||||
uint8_t item_check_tagged(uint32_t giveTag, 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);
|
||||
|
||||
uint8_t item_check_chest(uint8_t boxNo, uint8_t itemNo, fopAc_ac_c* chest);
|
||||
uint8_t item_check_boss(uint8_t itemNo, fopAc_ac_c* boss);
|
||||
uint8_t item_check_freestanding(uint8_t bitNo, uint8_t itemNo, fopAc_ac_c* item);
|
||||
uint8_t item_check_poe(uint8_t bitNo, uint8_t itemNo, fopAc_ac_c* poe);
|
||||
uint8_t item_check_shop(uint8_t itemNo, fopAc_ac_c* giver);
|
||||
uint8_t item_check_bug(uint8_t insectId, uint8_t itemNo, fopAc_ac_c* agitha);
|
||||
uint8_t item_check_sky_character(uint8_t itemNo, fopAc_ac_c* statue);
|
||||
|
||||
uint32_t item_give_tag(const char* name);
|
||||
uint32_t item_give_tag_chest(uint8_t boxNo);
|
||||
@@ -26,12 +36,63 @@ uint32_t item_give_tag_shop(uint8_t itemNo);
|
||||
uint32_t item_give_tag_bug(uint8_t insectId);
|
||||
uint32_t item_give_tag_sky_character();
|
||||
|
||||
void item_check_enqueue(const char* name, uint8_t itemNo);
|
||||
void item_check_enqueue_poe(uint8_t bitNo, uint8_t itemNo);
|
||||
void item_check_enqueue_deferred(const char* name, uint8_t itemNo);
|
||||
bool item_check_enqueue(ItemCheckResult check, ItemGiveMode mode);
|
||||
|
||||
void item_check_complete(ItemCheckResult check, fopAc_ac_c* giver);
|
||||
void item_check_cancel(uint32_t giveTag);
|
||||
void item_check_clear_committed();
|
||||
void item_granted(uint8_t itemNo, uint32_t giveTag, fopAc_ac_c* giver);
|
||||
|
||||
uint32_t item_check_message(uint16_t group, uint32_t messageId);
|
||||
|
||||
bool item_give_queue_dispatching();
|
||||
uint32_t item_give_queue_take_tag();
|
||||
|
||||
namespace detail {
|
||||
struct CommittedCheck {
|
||||
uint8_t vanillaItem = 0;
|
||||
uint8_t resolvedItem = 0;
|
||||
bool queued = false;
|
||||
};
|
||||
|
||||
class ItemCommitStore {
|
||||
public:
|
||||
CommittedCheck* find(uint32_t giveTag) {
|
||||
const auto it = mChecks.find(giveTag);
|
||||
return it != mChecks.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const CommittedCheck* find(uint32_t giveTag) const {
|
||||
const auto it = mChecks.find(giveTag);
|
||||
return it != mChecks.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
template <typename ResolveFn>
|
||||
CommittedCheck& commit(uint32_t giveTag, uint8_t vanillaItem, ResolveFn&& resolve) {
|
||||
const auto existing = mChecks.find(giveTag);
|
||||
if (existing != mChecks.end()) {
|
||||
return existing->second;
|
||||
}
|
||||
|
||||
const uint8_t resolvedItem = std::forward<ResolveFn>(resolve)();
|
||||
return mChecks
|
||||
.emplace(
|
||||
giveTag, CommittedCheck{.vanillaItem = vanillaItem, .resolvedItem = resolvedItem})
|
||||
.first->second;
|
||||
}
|
||||
|
||||
bool contains(uint32_t giveTag) const { return mChecks.contains(giveTag); }
|
||||
|
||||
void erase(uint32_t giveTag) { mChecks.erase(giveTag); }
|
||||
|
||||
void clear() { mChecks.clear(); }
|
||||
|
||||
bool empty() const { return mChecks.empty(); }
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32_t, CommittedCheck> mChecks;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
} // namespace dusk::mods
|
||||
|
||||
+143
-28
@@ -6,9 +6,14 @@
|
||||
|
||||
#include "aurora/lib/logging.hpp"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_item_data.h"
|
||||
#include "mods/items.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@@ -45,6 +50,78 @@ struct PendingResolve {
|
||||
void* userData = nullptr;
|
||||
};
|
||||
|
||||
struct MessageCheck {
|
||||
uint16_t group = 0;
|
||||
uint16_t messageId = 0;
|
||||
const char* name = nullptr;
|
||||
uint8_t vanillaItem = 0;
|
||||
bool enqueueAtDisplay = true;
|
||||
};
|
||||
|
||||
constexpr std::array kMessageChecks{
|
||||
MessageCheck{
|
||||
.group = 0,
|
||||
.messageId = 1822,
|
||||
.name = ITEM_CHECK_FISHING_BOTTLE,
|
||||
.vanillaItem = dItemNo_EMPTY_BOTTLE_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 7,
|
||||
.messageId = 7564,
|
||||
.name = ITEM_CHECK_FISHING_HEART_PIECE,
|
||||
.vanillaItem = dItemNo_KAKERA_HEART_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 7,
|
||||
.messageId = 7578,
|
||||
.name = ITEM_CHECK_FISHING_HEART_PIECE,
|
||||
.vanillaItem = dItemNo_KAKERA_HEART_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 5,
|
||||
.messageId = 5001,
|
||||
.name = ITEM_CHECK_DUNGEON_REWARD_FOREST,
|
||||
.vanillaItem = dItemNo_NONE_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 5,
|
||||
.messageId = 6011,
|
||||
.name = ITEM_CHECK_DUNGEON_REWARD_GORON,
|
||||
.vanillaItem = dItemNo_NONE_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 5,
|
||||
.messageId = 7001,
|
||||
.name = ITEM_CHECK_DUNGEON_REWARD_LAKEBED,
|
||||
.vanillaItem = dItemNo_NONE_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 5,
|
||||
.messageId = 9301,
|
||||
.name = ITEM_CHECK_DUNGEON_REWARD_SNOWPEAK,
|
||||
.vanillaItem = dItemNo_NONE_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 5,
|
||||
.messageId = 9401,
|
||||
.name = ITEM_CHECK_DUNGEON_REWARD_TIME,
|
||||
.vanillaItem = dItemNo_NONE_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 5,
|
||||
.messageId = 11001,
|
||||
.name = ITEM_CHECK_DUNGEON_REWARD_CITY,
|
||||
.vanillaItem = dItemNo_NONE_e,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 0,
|
||||
.messageId = 233,
|
||||
.name = ITEM_CHECK_ILIA_MEMORY,
|
||||
.vanillaItem = dItemNo_HORSE_FLUTE_e,
|
||||
.enqueueAtDisplay = false,
|
||||
},
|
||||
};
|
||||
|
||||
std::unordered_map<LoadedMod*, ModItemChecks> s_modChecks;
|
||||
std::unordered_set<std::string> s_warnedCollisions;
|
||||
ItemCheckHandle s_nextCheckHandle = 1;
|
||||
@@ -79,7 +156,28 @@ std::string bug_check_name(uint8_t insectId) {
|
||||
}
|
||||
|
||||
std::string sky_character_check_name() {
|
||||
return fmt::format("skychar:{}:{}", current_stage_name(), dStage_roomControl_c::getStayNo());
|
||||
return fmt::format("sky:{}:{}", current_stage_name(), dStage_roomControl_c::getStayNo());
|
||||
}
|
||||
|
||||
bool ilia_memory_context() {
|
||||
return std::strcmp(current_stage_name(), "R_SP109") == 0 &&
|
||||
dComIfGp_roomControl_getStayNo() == 0 && dComIfG_play_c::getLayerNo(0) == 9;
|
||||
}
|
||||
|
||||
uint16_t item_get_message(uint8_t itemNo) {
|
||||
if (itemNo == dItemNo_KAKERA_HEART_e) {
|
||||
constexpr std::array<uint16_t, 5> heartPieceMessages{0x86, 0x9C, 0x9D, 0x9E, 0x9F};
|
||||
return heartPieceMessages[dComIfGs_getMaxLife() % heartPieceMessages.size()];
|
||||
}
|
||||
return static_cast<uint16_t>(itemNo + 0x65);
|
||||
}
|
||||
|
||||
void invalidate_committed_check(const std::string& name) {
|
||||
if (name.empty()) {
|
||||
item_check_clear_committed();
|
||||
} else {
|
||||
item_check_cancel(item_give_tag(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -176,14 +274,6 @@ uint8_t item_check_freestanding(uint8_t bitNo, uint8_t itemNo, fopAc_ac_c* item)
|
||||
return item_check(name.c_str(), itemNo, item);
|
||||
}
|
||||
|
||||
uint8_t item_check_poe(uint8_t bitNo, uint8_t itemNo, fopAc_ac_c* poe) {
|
||||
if (s_modChecks.empty()) {
|
||||
return itemNo;
|
||||
}
|
||||
const auto name = poe_check_name(bitNo);
|
||||
return item_check(name.c_str(), itemNo, poe);
|
||||
}
|
||||
|
||||
uint8_t item_check_shop(uint8_t itemNo, fopAc_ac_c* giver) {
|
||||
if (s_modChecks.empty()) {
|
||||
return itemNo;
|
||||
@@ -192,20 +282,24 @@ uint8_t item_check_shop(uint8_t itemNo, fopAc_ac_c* giver) {
|
||||
return item_check(name.c_str(), itemNo, giver);
|
||||
}
|
||||
|
||||
uint8_t item_check_bug(uint8_t insectId, uint8_t itemNo, fopAc_ac_c* agitha) {
|
||||
if (s_modChecks.empty()) {
|
||||
return itemNo;
|
||||
}
|
||||
const auto name = bug_check_name(insectId);
|
||||
return item_check(name.c_str(), itemNo, agitha);
|
||||
}
|
||||
uint32_t item_check_message(uint16_t group, uint32_t messageId) {
|
||||
for (const auto& check : kMessageChecks) {
|
||||
if (check.group != group || check.messageId != messageId ||
|
||||
(check.group == 0 && check.messageId == 233 && !ilia_memory_context()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t item_check_sky_character(uint8_t itemNo, fopAc_ac_c* statue) {
|
||||
if (s_modChecks.empty()) {
|
||||
return itemNo;
|
||||
const ItemCheckResult result = item_check_commit(check.name, check.vanillaItem, nullptr);
|
||||
if (result.itemNo == check.vanillaItem || result.itemNo == dItemNo_NONE_e) {
|
||||
return messageId;
|
||||
}
|
||||
if (check.enqueueAtDisplay) {
|
||||
item_check_enqueue(result, ItemGiveMode::Silent);
|
||||
}
|
||||
return item_get_message(result.itemNo);
|
||||
}
|
||||
const auto name = sky_character_check_name();
|
||||
return item_check(name.c_str(), itemNo, statue);
|
||||
return messageId;
|
||||
}
|
||||
|
||||
uint32_t item_give_tag_chest(uint8_t boxNo) {
|
||||
@@ -236,10 +330,6 @@ uint32_t item_give_tag_sky_character() {
|
||||
return item_give_tag(sky_character_check_name().c_str());
|
||||
}
|
||||
|
||||
void item_check_enqueue_poe(uint8_t bitNo, uint8_t itemNo) {
|
||||
item_check_enqueue(poe_check_name(bitNo).c_str(), itemNo);
|
||||
}
|
||||
|
||||
namespace svc {
|
||||
|
||||
ModResult item_check_set_override(LoadedMod& mod, const char* name, uint8_t itemNo) {
|
||||
@@ -247,10 +337,12 @@ ModResult item_check_set_override(LoadedMod& mod, const char* name, uint8_t item
|
||||
for (auto& checkOverride : checks.overrides) {
|
||||
if (checkOverride.name == name) {
|
||||
checkOverride.itemNo = itemNo;
|
||||
invalidate_committed_check(checkOverride.name);
|
||||
return MOD_OK;
|
||||
}
|
||||
}
|
||||
checks.overrides.push_back({.name = name, .itemNo = itemNo});
|
||||
invalidate_committed_check(checks.overrides.back().name);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
@@ -261,6 +353,9 @@ ModResult item_check_clear_override(LoadedMod& mod, const char* name) {
|
||||
}
|
||||
const auto removed = std::erase_if(modIt->second.overrides,
|
||||
[&](const auto& checkOverride) { return checkOverride.name == name; });
|
||||
if (removed != 0) {
|
||||
invalidate_committed_check(name);
|
||||
}
|
||||
return removed != 0 ? MOD_OK : MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
@@ -272,6 +367,7 @@ ModResult item_check_add_resolver(LoadedMod& mod, const char* name, ItemCheckRes
|
||||
resolver.fn = fn;
|
||||
resolver.userData = userData;
|
||||
outHandle = resolver.handle;
|
||||
invalidate_committed_check(resolver.name);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
@@ -280,12 +376,31 @@ ModResult item_check_remove_resolver(LoadedMod& mod, ItemCheckHandle handle) {
|
||||
if (modIt == s_modChecks.end()) {
|
||||
return MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
const auto removed = std::erase_if(
|
||||
modIt->second.resolvers, [&](const auto& resolver) { return resolver.handle == handle; });
|
||||
return removed != 0 ? MOD_OK : MOD_INVALID_ARGUMENT;
|
||||
const auto resolverIt =
|
||||
std::find_if(modIt->second.resolvers.begin(), modIt->second.resolvers.end(),
|
||||
[&](const auto& resolver) { return resolver.handle == handle; });
|
||||
if (resolverIt == modIt->second.resolvers.end()) {
|
||||
return MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
const std::string name = resolverIt->name;
|
||||
modIt->second.resolvers.erase(resolverIt);
|
||||
invalidate_committed_check(name);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
void item_checks_remove_mod(LoadedMod& mod) {
|
||||
if (const auto modIt = s_modChecks.find(&mod); modIt != s_modChecks.end()) {
|
||||
for (const auto& resolver : modIt->second.resolvers) {
|
||||
if (resolver.name.empty()) {
|
||||
item_check_clear_committed();
|
||||
break;
|
||||
}
|
||||
invalidate_committed_check(resolver.name);
|
||||
}
|
||||
for (const auto& checkOverride : modIt->second.overrides) {
|
||||
invalidate_committed_check(checkOverride.name);
|
||||
}
|
||||
}
|
||||
s_modChecks.erase(&mod);
|
||||
s_warnedCollisions.clear();
|
||||
}
|
||||
|
||||
+130
-37
@@ -17,6 +17,7 @@
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace dusk::mods {
|
||||
@@ -28,6 +29,8 @@ aurora::Module Log{"dusk::mods::item_gives"};
|
||||
std::deque<std::string> s_giveNames;
|
||||
std::unordered_map<std::string, uint32_t> s_giveNameIds;
|
||||
|
||||
detail::ItemCommitStore s_committedChecks;
|
||||
|
||||
const char* item_give_name(uint32_t tag) {
|
||||
if (tag == 0 || tag > s_giveNames.size()) {
|
||||
return nullptr;
|
||||
@@ -92,7 +95,18 @@ void notify_gives(const char* checkName, uint8_t itemNo, fopAc_ac_c* giver, Item
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t kGiveQueueLimit = 64;
|
||||
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)
|
||||
{
|
||||
Log.error("committed check '{}' completed with item {:#x} instead of {:#x}",
|
||||
item_give_name(giveTag) != nullptr ? item_give_name(giveTag) : "", itemNo,
|
||||
committed->resolvedItem);
|
||||
}
|
||||
s_committedChecks.erase(giveTag);
|
||||
notify_gives(item_give_name(giveTag), itemNo, giver, origin);
|
||||
}
|
||||
|
||||
constexpr int kGiveMaxRetries = 5;
|
||||
|
||||
struct QueuedGive {
|
||||
@@ -101,6 +115,7 @@ struct QueuedGive {
|
||||
uint8_t itemNo = 0;
|
||||
bool silent = false;
|
||||
bool resolveAtDispatch = false;
|
||||
bool forced = false;
|
||||
};
|
||||
|
||||
std::deque<QueuedGive> s_giveQueue;
|
||||
@@ -111,6 +126,11 @@ bool s_inFlight = false;
|
||||
bool s_inFlightSpawned = false;
|
||||
bool s_dispatchingSilent = false;
|
||||
|
||||
bool has_forced_give() {
|
||||
return std::any_of(
|
||||
s_giveQueue.begin(), s_giveQueue.end(), [](const QueuedGive& give) { return give.forced; });
|
||||
}
|
||||
|
||||
bool safe_to_dispatch() {
|
||||
daAlink_c* link = daAlink_getAlinkActorClass();
|
||||
if (link == nullptr) {
|
||||
@@ -142,13 +162,13 @@ bool safe_to_dispatch() {
|
||||
bool resolve_queued_give(const QueuedGive& give, ItemGiveOrigin origin, uint8_t& outItem) {
|
||||
outItem = give.itemNo;
|
||||
if (give.resolveAtDispatch) {
|
||||
outItem = item_check(item_give_name(give.tag), give.itemNo, nullptr);
|
||||
outItem = item_check_commit(give.tag, give.itemNo, nullptr).itemNo;
|
||||
}
|
||||
if (outItem != dItemNo_NONE_e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
notify_gives(item_give_name(give.tag), dItemNo_NONE_e, nullptr, origin);
|
||||
complete_check(dItemNo_NONE_e, give.tag, nullptr, origin);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -171,11 +191,40 @@ void dispatch_demo_give() {
|
||||
|
||||
daAlink_c* link = daAlink_getAlinkActorClass();
|
||||
dComIfGp_getEvent()->setGtItm(s_inFlightItem);
|
||||
link->procCoGetItemInit();
|
||||
link->mProcID = daAlink_c::PROC_GET_ITEM;
|
||||
const s16 eventIndex = dComIfGp_getEventManager().getEventIdx(link, "DEFAULT_GETITEM", 0xFF);
|
||||
fopAcM_orderChangeEventId(link, eventIndex, 1, 0xFFFF);
|
||||
}
|
||||
|
||||
void dispatch_next_give() {
|
||||
while (!s_giveQueue.empty()) {
|
||||
while (!s_giveQueue.empty() && s_giveQueue.front().silent) {
|
||||
const QueuedGive give = s_giveQueue.front();
|
||||
s_giveQueue.pop_front();
|
||||
dispatch_silent_give(give);
|
||||
}
|
||||
if (s_giveQueue.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QueuedGive give = s_giveQueue.front();
|
||||
s_giveQueue.pop_front();
|
||||
|
||||
uint8_t itemNo = 0;
|
||||
if (!resolve_queued_give(give, ITEM_GIVE_ORIGIN_QUEUE, itemNo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
s_inFlightGive = give;
|
||||
s_inFlightItem = itemNo;
|
||||
s_inFlightRetries = 0;
|
||||
s_inFlight = true;
|
||||
s_inFlightSpawned = false;
|
||||
dispatch_demo_give();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
uint32_t item_give_tag(const char* name) {
|
||||
@@ -192,16 +241,30 @@ uint32_t item_give_tag(const char* name) {
|
||||
return tag;
|
||||
}
|
||||
|
||||
uint8_t item_check_tagged(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c* giver) {
|
||||
ItemCheckResult item_check_commit(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c* giver) {
|
||||
const char* name = item_give_name(giveTag);
|
||||
return name != nullptr ? item_check(name, itemNo, giver) : itemNo;
|
||||
if (name == nullptr) {
|
||||
return {.tag = giveTag, .itemNo = itemNo};
|
||||
}
|
||||
|
||||
if (const auto* committed = s_committedChecks.find(giveTag); committed != nullptr) {
|
||||
if (committed->vanillaItem != itemNo) {
|
||||
Log.error("committed check '{}' changed vanilla item from {:#x} to {:#x}", name,
|
||||
committed->vanillaItem, itemNo);
|
||||
}
|
||||
return {.tag = giveTag, .itemNo = committed->resolvedItem};
|
||||
}
|
||||
|
||||
const auto& committed =
|
||||
s_committedChecks.commit(giveTag, itemNo, [&] { return item_check(name, itemNo, giver); });
|
||||
return {.tag = giveTag, .itemNo = committed.resolvedItem};
|
||||
}
|
||||
|
||||
void item_check_enqueue(const char* name, uint8_t itemNo) {
|
||||
if (s_giveQueue.size() >= kGiveQueueLimit) {
|
||||
Log.warn("item give queue is full; dropping check '{}'", name != nullptr ? name : "");
|
||||
return;
|
||||
}
|
||||
ItemCheckResult item_check_commit(const char* name, uint8_t itemNo, fopAc_ac_c* giver) {
|
||||
return item_check_commit(item_give_tag(name), itemNo, giver);
|
||||
}
|
||||
|
||||
void item_check_enqueue_deferred(const char* name, uint8_t itemNo) {
|
||||
s_giveQueue.push_back({
|
||||
.tag = item_give_tag(name),
|
||||
.itemNo = itemNo,
|
||||
@@ -209,6 +272,53 @@ void item_check_enqueue(const char* name, uint8_t itemNo) {
|
||||
});
|
||||
}
|
||||
|
||||
bool item_check_enqueue(ItemCheckResult check, ItemGiveMode mode) {
|
||||
auto* committed = s_committedChecks.find(check.tag);
|
||||
if (committed == nullptr) {
|
||||
Log.error("cannot enqueue uncommitted check '{}'",
|
||||
item_give_name(check.tag) != nullptr ? item_give_name(check.tag) : "");
|
||||
return false;
|
||||
}
|
||||
if (committed->resolvedItem != 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);
|
||||
return false;
|
||||
}
|
||||
if (committed->queued) {
|
||||
return false;
|
||||
}
|
||||
|
||||
committed->queued = true;
|
||||
s_giveQueue.push_back({
|
||||
.tag = check.tag,
|
||||
.itemNo = committed->resolvedItem,
|
||||
.silent = mode == ItemGiveMode::Silent,
|
||||
.forced = mode == ItemGiveMode::ForcedDemo,
|
||||
});
|
||||
if (mode == ItemGiveMode::ForcedDemo && !s_inFlight) {
|
||||
dispatch_next_give();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void item_check_complete(ItemCheckResult check, fopAc_ac_c* giver) {
|
||||
complete_check(check.itemNo, check.tag, giver, ITEM_GIVE_ORIGIN_GAME);
|
||||
}
|
||||
|
||||
void item_check_cancel(uint32_t giveTag) {
|
||||
s_committedChecks.erase(giveTag);
|
||||
std::erase_if(s_giveQueue,
|
||||
[&](const QueuedGive& give) { return give.owner == nullptr && give.tag == giveTag; });
|
||||
}
|
||||
|
||||
void item_check_clear_committed() {
|
||||
std::erase_if(s_giveQueue, [&](const QueuedGive& give) {
|
||||
return give.owner == nullptr && s_committedChecks.contains(give.tag);
|
||||
});
|
||||
s_committedChecks.clear();
|
||||
}
|
||||
|
||||
void item_granted(uint8_t itemNo, uint32_t giveTag, fopAc_ac_c* giver) {
|
||||
ItemGiveOrigin origin = ITEM_GIVE_ORIGIN_GAME;
|
||||
if (s_dispatchingSilent) {
|
||||
@@ -218,7 +328,7 @@ void item_granted(uint8_t itemNo, uint32_t giveTag, fopAc_ac_c* giver) {
|
||||
s_inFlight = false;
|
||||
s_inFlightSpawned = false;
|
||||
}
|
||||
notify_gives(item_give_name(giveTag), itemNo, giver, origin);
|
||||
complete_check(itemNo, giveTag, giver, origin);
|
||||
}
|
||||
|
||||
bool item_give_queue_dispatching() {
|
||||
@@ -236,17 +346,21 @@ uint32_t item_give_queue_take_tag() {
|
||||
namespace svc {
|
||||
|
||||
void item_gives_tick() {
|
||||
if ((!s_inFlight && s_giveQueue.empty()) || !safe_to_dispatch()) {
|
||||
if (!s_inFlight && s_giveQueue.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_inFlight) {
|
||||
if (!safe_to_dispatch()) {
|
||||
return;
|
||||
}
|
||||
if (++s_inFlightRetries > kGiveMaxRetries) {
|
||||
Log.error("item {:#x} for '{}' did not complete after {} attempts; dropping it",
|
||||
s_inFlightItem,
|
||||
item_give_name(s_inFlightGive.tag) != nullptr ? item_give_name(s_inFlightGive.tag) :
|
||||
"",
|
||||
kGiveMaxRetries);
|
||||
item_check_cancel(s_inFlightGive.tag);
|
||||
s_inFlight = false;
|
||||
s_inFlightSpawned = false;
|
||||
return;
|
||||
@@ -256,29 +370,10 @@ void item_gives_tick() {
|
||||
return;
|
||||
}
|
||||
|
||||
while (!s_giveQueue.empty() && s_giveQueue.front().silent) {
|
||||
const QueuedGive give = s_giveQueue.front();
|
||||
s_giveQueue.pop_front();
|
||||
dispatch_silent_give(give);
|
||||
}
|
||||
if (s_giveQueue.empty()) {
|
||||
if (!has_forced_give() && !safe_to_dispatch()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QueuedGive give = s_giveQueue.front();
|
||||
uint8_t itemNo = 0;
|
||||
if (!resolve_queued_give(give, ITEM_GIVE_ORIGIN_QUEUE, itemNo)) {
|
||||
s_giveQueue.pop_front();
|
||||
return;
|
||||
}
|
||||
|
||||
s_giveQueue.pop_front();
|
||||
s_inFlightGive = give;
|
||||
s_inFlightItem = itemNo;
|
||||
s_inFlightRetries = 0;
|
||||
s_inFlight = true;
|
||||
s_inFlightSpawned = false;
|
||||
dispatch_demo_give();
|
||||
dispatch_next_give();
|
||||
}
|
||||
|
||||
void item_gives_clear() {
|
||||
@@ -289,12 +384,10 @@ void item_gives_clear() {
|
||||
s_giveQueue.clear();
|
||||
s_inFlight = false;
|
||||
s_inFlightSpawned = false;
|
||||
s_committedChecks.clear();
|
||||
}
|
||||
|
||||
ModResult item_give_enqueue(LoadedMod& mod, const char* checkName, uint8_t itemNo, uint32_t flags) {
|
||||
if (s_giveQueue.size() >= kGiveQueueLimit) {
|
||||
return MOD_UNAVAILABLE;
|
||||
}
|
||||
s_giveQueue.push_back({
|
||||
.owner = &mod,
|
||||
.tag = item_give_tag(checkName),
|
||||
|
||||
@@ -275,7 +275,7 @@ std::map<int, itemInfo> itemMap = {
|
||||
{dItemNo_WEAR_KOKIRI_e, {"Hero's Clothes"}},
|
||||
{dItemNo_ARMOR_e, {"Magic Armor"}},
|
||||
{dItemNo_WEAR_ZORA_e, {"Zora Armor"}},
|
||||
{dItemNo_MAGIC_LV1_e, {"Magic Level 1"}},
|
||||
{dItemNo_SHADOW_CRYSTAL_e, {"Shadow Crystal"}},
|
||||
{dItemNo_DUNGEON_EXIT_2_e, {"Ooccoo Sr.", ITEMTYPE_EQUIP_e}},
|
||||
{dItemNo_WALLET_LV1_e, {"Wallet"}},
|
||||
{dItemNo_WALLET_LV2_e, {"Big Wallet"}},
|
||||
|
||||
@@ -1592,6 +1592,12 @@ fpc_ProcID fopAcM_createItemForBoss(const cXyz* i_pos, int i_itemNo, int i_roomN
|
||||
int _ = -1;
|
||||
#if TARGET_PC
|
||||
const u8 originalItemNo = i_itemNo & 0xFF;
|
||||
// Overridden item checks do not set StageLife, so boss containers
|
||||
// also need a persistent local item bit.
|
||||
constexpr u8 kBossHeartContainerFlag = 0x9F;
|
||||
if (originalItemNo == dItemNo_UTAWA_HEART_e && param_8 == -1) {
|
||||
param_8 = kBossHeartContainerFlag;
|
||||
}
|
||||
u32 giveTag;
|
||||
if (i_itemCheckName != NULL) {
|
||||
i_itemNo = dusk::mods::item_check(i_itemCheckName, originalItemNo, NULL);
|
||||
|
||||
Reference in New Issue
Block a user