mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-09-02 16:47:59 -04:00
Merge pull request #2374 from TwilitRealm/rando-mod-internal
mods: randomizer
This commit is contained in:
@@ -4,3 +4,6 @@
|
||||
[submodule "extern/borealis"]
|
||||
path = extern/borealis
|
||||
url = https://github.com/encounter/borealis.git
|
||||
[submodule "mods/randomizer"]
|
||||
path = mods/randomizer
|
||||
url = https://github.com/TwilitRealm/dusklight-randomizer.git
|
||||
|
||||
@@ -571,6 +571,7 @@ if (DUSK_ENABLE_CODE_MODS AND CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR
|
||||
add_subdirectory(mods/window_demo)
|
||||
add_subdirectory(mods/flow_demo)
|
||||
add_subdirectory(mods/basic_cosmetics_mod)
|
||||
add_subdirectory(mods/randomizer)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -1483,6 +1483,7 @@ set(DUSK_FILES
|
||||
src/dusk/mods/loader/prepatch.cpp
|
||||
src/dusk/mods/loader/prepatch.hpp
|
||||
src/dusk/mods/item.hpp
|
||||
src/dusk/mods/item_actor.cpp
|
||||
src/dusk/mods/item_checks.cpp
|
||||
src/dusk/mods/item_gives.cpp
|
||||
src/dusk/mods/log_buffer.cpp
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
s32 getBgmLoadStatus(u32 wave) { return getWaveLoadStatus(wave, 1); }
|
||||
u8 getDemoSeWaveNum() { return loadedDemoWave; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x00 */ JAISoundID BGM_ID;
|
||||
/* 0x04 */ int sceneNum;
|
||||
/* 0x08 */ int timer;
|
||||
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
bool checkFlag(u16 flag) { return field_0x68e & flag; }
|
||||
void setAction(u8 action) { mAction = action; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x56C */ request_of_phase_process_class mPhase1;
|
||||
/* 0x574 */ request_of_phase_process_class mPhase2;
|
||||
/* 0x57C */ J3DModel* mModel1;
|
||||
|
||||
@@ -296,7 +296,7 @@ public:
|
||||
|
||||
static DUSK_GAME_DATA char DUSK_CONST* DUSK_CONST mCutNameList[18];
|
||||
static DUSK_GAME_DATA cutFunc DUSK_CONST mCutList[18];
|
||||
private:
|
||||
// private:
|
||||
/* 0x0E40 */ NPC_FAIRY_HIO_CLASS* mHIO;
|
||||
/* 0x0E44 */ dCcD_Cyl mCyl;
|
||||
/* 0x0F80 */ u8 mType;
|
||||
|
||||
@@ -287,7 +287,7 @@ public:
|
||||
|
||||
static DUSK_GAME_DATA char DUSK_CONST* DUSK_CONST mCutNameList[10];
|
||||
static DUSK_GAME_DATA cutFunc DUSK_CONST mCutList[10];
|
||||
private:
|
||||
// private:
|
||||
/* 0x0E40 */ mDoExt_McaMorfSO* mFishModelMorf;
|
||||
/* 0x0E44 */ mDoExt_McaMorfSO* mLeafModelMorf;
|
||||
/* 0x0E48 */ NPC_YKM_HIO_CLASS* mpHIO;
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
static DUSK_GAME_DATA char DUSK_CONST* DUSK_CONST mEvtCutNameList[2];
|
||||
static DUSK_GAME_DATA EventFn DUSK_CONST mEvtCutList[2];
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0xB48 */ Z2Creature mCreatureSound;
|
||||
/* 0xBD8 */ daNpcF_MatAnm_c* mpMatAnm;
|
||||
/* 0xBDC */ daNpcF_Lookat_c mLookat;
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
void himoCalc();
|
||||
void adjustShapeAngle() {}
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x0B48 */ Z2Creature mCreatureSound;
|
||||
/* 0x0BD8 */ daNpcF_MatAnm_c* mpMatAnm;
|
||||
/* 0x0BDC */ mDoExt_invisibleModel mInvisibleModel;
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
bool isFirst() { return fopAcM_GetParamBit(this, 0x1b, 1); }
|
||||
void setAction(u8 action) { mAction = action; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x568 */ request_of_phase_process_class mPhaseReq;
|
||||
/* 0x570 */ J3DModel* mpModel;
|
||||
/* 0x574 */ mDoExt_btkAnm* mpBtkAnm[2];
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
current.pos = new_pos;
|
||||
}
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x92C */ fpc_ProcID mItemId;
|
||||
/* 0x930 */ int mCounter;
|
||||
/* 0x934 */ u8 mStatus;
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
static DUSK_GAME_DATA daObjMasterSword_Attr_c const mAttr;
|
||||
static DUSK_GAME_DATA actionFunc ActionTable[];
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x568 */ J3DModel* mpModel;
|
||||
/* 0x56C */ request_of_phase_process_class mPhase;
|
||||
/* 0x574 */ mDoExt_btkAnm mBtk;
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
u8 getModelType() { return fopAcM_GetParamBit(this, 8, 4); }
|
||||
u8 getItemNo() { return fopAcM_GetParamBit(this, 0, 8); }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x718 */ u8 mReturnRupee;
|
||||
/* 0x71C */ request_of_phase_process_class mPhase;
|
||||
/* 0x724 */ J3DModel* mpModel;
|
||||
|
||||
@@ -1291,6 +1291,7 @@ public:
|
||||
}
|
||||
void set(const char*, s8, s16, s8, s8, u8);
|
||||
void offEnable() { enabled = 0; }
|
||||
void onEnable() { enabled = 1; }
|
||||
BOOL isEnable() const { return enabled; }
|
||||
s8 getWipe() const { return wipe; }
|
||||
u8 getWipeSpeed() const { return wipe_speed; }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <new>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
class JKRHeap;
|
||||
typedef void (*JKRErrorHandler)(void*, u32, int);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "d/d_kankyo.h"
|
||||
#include "d/d_kantera_icon_meter.h"
|
||||
#include "d/d_menu_collect.h"
|
||||
#include "d/d_menu_dmap.h"
|
||||
#include "d/d_menu_fishing.h"
|
||||
#include "d/d_menu_fmap2D.h"
|
||||
#include "d/d_menu_insect.h"
|
||||
@@ -345,7 +346,7 @@ void menu_skill_screen_set_do_icon_post(ModContext*, void* args, void*, void*) {
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
}
|
||||
|
||||
// A, B, and Z buttons on the map screen
|
||||
// A, B, and Z buttons on the field map screen
|
||||
DEFINE_HOOK(&dMenu_Fmap_c::_create, MenuFMapCreate);
|
||||
void menu_fmap_create_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuFMap = mods::arg<dMenu_Fmap_c*>(args, 0);
|
||||
@@ -356,6 +357,16 @@ void menu_fmap_create_post(ModContext*, void* args, void*, void*) {
|
||||
recolor_ui_button(get_cvars().zButtonColor, MULTI_CHAR('zbtn'), screen);
|
||||
}
|
||||
|
||||
// A and B buttons on the dungeon map screen
|
||||
DEFINE_HOOK_SYMBOL("dMenu_DmapBg_c::buttonIconScreenInit", void(dMenu_DmapBg_c*), MenuDMapButtonIconScreenInit);
|
||||
void menu_dmap_button_icon_screen_init_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuDMap = mods::arg<dMenu_DmapBg_c*>(args, 0);
|
||||
auto screen = menuDMap->mButtonScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
}
|
||||
|
||||
// A button on the howling screen
|
||||
DEFINE_HOOK(&dMsgObject_c::talkStartInit, MsgObjectTalkStartInit);
|
||||
void msg_object_talk_start_init_post(ModContext*, void* args, void*, void*) {
|
||||
@@ -685,6 +696,8 @@ ModResult add_all_hooks() {
|
||||
ADD_POST_HOOK(OutFontCreatePane, out_font_create_pane_post, COutFont_c::createPane)
|
||||
ADD_POST_HOOK(OutFontSetDrawFont, out_font_set_draw_font_post, COutFontSet_c::drawFont)
|
||||
ADD_POST_HOOK(MenuFMapCreate, menu_fmap_create_post, dMenu_Fmap_c::_create)
|
||||
ADD_POST_HOOK(MenuDMapButtonIconScreenInit, menu_dmap_button_icon_screen_init_post,
|
||||
dMenu_DmapBg_c::buttonIconScreenInit)
|
||||
ADD_POST_HOOK(
|
||||
MsgObjectTalkStartInit, msg_object_talk_start_init_post, dMsgObject_c::talkStartInit)
|
||||
ADD_POST_HOOK(MeterHakushaCreate, meter_hakusha_create_post, dMeterHakusha_c::_create)
|
||||
@@ -724,6 +737,7 @@ ModResult remove_all_hooks() {
|
||||
UNINSTALL_HOOK(OutFontCreatePane)
|
||||
UNINSTALL_HOOK(OutFontSetDrawFont)
|
||||
UNINSTALL_HOOK(MenuFMapCreate)
|
||||
UNINSTALL_HOOK(MenuDMapButtonIconScreenInit)
|
||||
UNINSTALL_HOOK(MsgObjectTalkStartInit)
|
||||
UNINSTALL_HOOK(MeterHakushaCreate)
|
||||
UNINSTALL_HOOK(ItemBaseCreateItemHeap)
|
||||
|
||||
Submodule
+1
Submodule mods/randomizer added at 61ba8c4058
@@ -10,7 +10,7 @@
|
||||
#define ITEM_CHECK_FREESTANDING_PREFIX "freestanding:" /* <stage>:<bit> */
|
||||
#define ITEM_CHECK_GOLDEN_WOLF_PREFIX "golden_wolf:" /* <event_flag> */
|
||||
#define ITEM_CHECK_POE_PREFIX "poe:" /* <stage>:<switch> */
|
||||
#define ITEM_CHECK_SHOP_PREFIX "shop:" /* <stage>:<item> */
|
||||
#define ITEM_CHECK_SHOP_PREFIX "shop:" /* <stage>:<room>:<item> */
|
||||
#define ITEM_CHECK_SKY_PREFIX "sky:" /* <stage>:<room> */
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_PREFIX "dungeon_reward:" /* <stage> */
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#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_CORO_GATE_KEY "coro_gate_key"
|
||||
#define ITEM_CHECK_CORO_LANTERN "coro_lantern"
|
||||
#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"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#define ITEM_SERVICE_ID "dev.twilitrealm.dusklight.item"
|
||||
#define ITEM_SERVICE_MAJOR 2u
|
||||
#define ITEM_SERVICE_MINOR 1u
|
||||
#define ITEM_SERVICE_MINOR 3u
|
||||
|
||||
/* 0 is never a valid handle. */
|
||||
typedef uint64_t ItemCheckHandle;
|
||||
@@ -32,11 +32,13 @@ typedef struct ItemCheckInfo {
|
||||
uint8_t vanilla_item;
|
||||
uint8_t current_item;
|
||||
uint8_t current_display_item;
|
||||
bool was_resolved;
|
||||
} ItemCheckInfo;
|
||||
|
||||
typedef struct ItemCheckResolution {
|
||||
uint8_t item;
|
||||
uint8_t display_item; /* leave unset (0xFF/NONE) to use the item */
|
||||
bool was_resolved;
|
||||
} ItemCheckResolution;
|
||||
|
||||
/* Return true and write out_result to replace the result, or false to leave it unchanged. */
|
||||
@@ -97,6 +99,13 @@ typedef struct ItemService {
|
||||
ModContext* ctx, ItemGiveObserveFn fn, void* user_data, ItemGiveHandle* out_handle);
|
||||
|
||||
ModResult (*unobserve_gives)(ModContext* ctx, ItemGiveHandle handle);
|
||||
|
||||
/* Minor version 2 */
|
||||
|
||||
/* Resolve a live preview (item + display item) without granting an item or notifying give
|
||||
* observers. */
|
||||
ModResult (*resolve_check_full)(ModContext* ctx, const char* name, uint8_t vanilla_item,
|
||||
ItemCheckResolution* out_resolution);
|
||||
} ItemService;
|
||||
|
||||
MOD_DECLARE_SERVICE(ItemService, svc_item, ITEM_SERVICE_ID, ITEM_SERVICE_MAJOR, ITEM_SERVICE_MINOR);
|
||||
|
||||
@@ -462,7 +462,7 @@ 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);
|
||||
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);
|
||||
@@ -550,7 +550,7 @@ static int daDitem_Execute(daDitem_c* i_this) {
|
||||
}
|
||||
|
||||
int daDitem_c::draw() {
|
||||
switch (m_itemNo) {
|
||||
switch (DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo)) {
|
||||
case dItemNo_WOOD_STICK_e:
|
||||
draw_WOOD_STICK();
|
||||
break;
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include "d/actor/d_a_e_po.h"
|
||||
#include "d/actor/d_a_obj_poFire.h"
|
||||
#if TARGET_PC
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#endif
|
||||
#include "d/d_cc_d.h"
|
||||
#include "d/d_cc_uty.h"
|
||||
#include "f_op/f_op_actor_enemy.h"
|
||||
|
||||
@@ -4022,16 +4022,53 @@ BOOL daNpc_grA_c::talk(void*) {
|
||||
if (r26 && talkProc(NULL, TRUE, NULL)) {
|
||||
if (mFlow.getEventId(&sp8) == 1) {
|
||||
#if TARGET_PC
|
||||
const u8 originalItem = sp8;
|
||||
u32 itemGiveTag = 0;
|
||||
if (sp8 == dItemNo_BOMB_IN_BAG_e) {
|
||||
bool isItemCheck = false;
|
||||
if (originalItem == dItemNo_BOMB_IN_BAG_e) {
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("goron_reward:F_SP113", sp8, this);
|
||||
dusk::mods::item_check_commit("goron_reward:F_SP113", originalItem, this);
|
||||
sp8 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
isItemCheck = true;
|
||||
} else {
|
||||
const char* stage = dComIfGp_getStartStageName();
|
||||
const bool isAdultGoronShop = (strcmp(stage, "R_SP160") == 0 && originalItem == dItemNo_HYLIA_SHIELD_e) ||
|
||||
(strcmp(stage, "F_SP116") == 0 && originalItem == dItemNo_ARROW_30_e);
|
||||
if (isAdultGoronShop) {
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_shop(originalItem), originalItem, this);
|
||||
sp8 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
isItemCheck = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isItemCheck && sp8 == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete({itemGiveTag, dItemNo_NONE_e}, this);
|
||||
r29 = 1;
|
||||
if (mType == 0xb) {
|
||||
field_0x1691 = 1;
|
||||
}
|
||||
} else {
|
||||
field_0x1480 = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, sp8, 0, -1, -1, NULL, NULL, itemGiveTag);
|
||||
if (field_0x1480 != fpcM_ERROR_PROCESS_ID_e) {
|
||||
s16 r25 =
|
||||
dComIfGp_getEventManager().getEventIdx(this, "DEFAULT_GETITEM", 0xff);
|
||||
dComIfGp_getEvent()->reset(this);
|
||||
fopAcM_orderChangeEventId(this, r25, 1, -1);
|
||||
field_0x9ec = 1;
|
||||
r29 = 1;
|
||||
mOrderNewEvt = 1;
|
||||
if (mType == 0xb) {
|
||||
field_0x1691 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
field_0x1480 = fopAcM_createItemForPresentDemo(¤t.pos, sp8, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
NULL);
|
||||
if (field_0x1480 != fpcM_ERROR_PROCESS_ID_e) {
|
||||
s16 r25 = dComIfGp_getEventManager().getEventIdx(this, "DEFAULT_GETITEM", 0xff);
|
||||
dComIfGp_getEvent()->reset(this);
|
||||
@@ -4043,6 +4080,7 @@ BOOL daNpc_grA_c::talk(void*) {
|
||||
field_0x1691 = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (mType == 0xa && field_0x1486 == 0 && daNpcF_chkEvtBit(0x187)) {
|
||||
dComIfGp_getEvent()->reset(this);
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "d/actor/d_a_npc_grc.h"
|
||||
#include "d/actor/d_a_npc.h"
|
||||
#include "Z2AudioLib/Z2Instances.h"
|
||||
#if TARGET_PC
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
enum grC_RES_File_ID {
|
||||
@@ -1476,8 +1479,27 @@ BOOL daNpc_grC_c::talk(void* param_1) {
|
||||
rv = TRUE;
|
||||
|
||||
if (mFlow.getEventId(&i_itemNo) == 1) {
|
||||
mItemID = fopAcM_createItemForPresentDemo(¤t.pos, i_itemNo, 0, -1, -1, NULL, NULL);
|
||||
#if TARGET_PC
|
||||
const bool isCastleTownShop =
|
||||
strcmp(dComIfGp_getStartStageName(), "R_SP160") == 0 &&
|
||||
(i_itemNo == dItemNo_RED_BOTTLE_e || i_itemNo == dItemNo_OIL_BOTTLE_e);
|
||||
u32 itemGiveTag = 0;
|
||||
if (isCastleTownShop) {
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_shop(i_itemNo), i_itemNo, this);
|
||||
i_itemNo = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
|
||||
if (isCastleTownShop && i_itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete({itemGiveTag, dItemNo_NONE_e}, this);
|
||||
} else {
|
||||
mItemID = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, i_itemNo, 0, -1, -1, NULL, NULL, itemGiveTag);
|
||||
}
|
||||
#else
|
||||
mItemID = fopAcM_createItemForPresentDemo(¤t.pos, i_itemNo, 0, -1, -1, NULL, NULL);
|
||||
#endif
|
||||
if (mItemID != fpcM_ERROR_PROCESS_ID_e) {
|
||||
s16 i_eventID = dComIfGp_getEventManager().getEventIdx(this, "DEFAULT_GETITEM", 0xFF);
|
||||
dComIfGp_getEvent()->reset(this);
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include "d/actor/d_a_npc_kkri.h"
|
||||
#include "d/actor/d_a_e_ym.h"
|
||||
#if TARGET_PC
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
static DUSK_CONSTEXPR int l_bmdData[2][2] = {
|
||||
@@ -1183,16 +1186,39 @@ int daNpc_Kkri_c::talk(void*) {
|
||||
if (mItemPartnerId == fpcM_ERROR_PROCESS_ID_e) {
|
||||
#if TARGET_PC
|
||||
u32 itemGiveTag = 0;
|
||||
if (item_no == dItemNo_OIL_BOTTLE3_e) {
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("coro_bottle", item_no, this);
|
||||
const char* itemCheckName = nullptr;
|
||||
switch (item_no) {
|
||||
case dItemNo_OIL_BOTTLE3_e:
|
||||
itemCheckName = ITEM_CHECK_CORO_BOTTLE;
|
||||
break;
|
||||
case dItemNo_KANTERA_e:
|
||||
itemCheckName = ITEM_CHECK_CORO_LANTERN;
|
||||
break;
|
||||
case dItemNo_KEY_OF_FILONE_e:
|
||||
itemCheckName = ITEM_CHECK_CORO_GATE_KEY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (itemCheckName != nullptr) {
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
itemCheckName, item_no, this);
|
||||
item_no = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
|
||||
if (item_no == dItemNo_NONE_e && itemCheckName != nullptr) {
|
||||
dusk::mods::item_check_complete({itemGiveTag, dItemNo_NONE_e}, this);
|
||||
field_0xfd5 = 1;
|
||||
mEvtNo = 1;
|
||||
evtChange();
|
||||
} else {
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, item_no, 0, -1, -1, NULL, NULL, itemGiveTag);
|
||||
}
|
||||
#else
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, item_no, 0, -1, -1, NULL, NULL);
|
||||
#endif
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(¤t.pos, item_no,
|
||||
0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
|
||||
if (fopAcM_IsExecuting(mItemPartnerId)) {
|
||||
|
||||
@@ -268,7 +268,7 @@ int daItem_c::_daItem_create() {
|
||||
const u32 params = fopAcM_GetParam(this);
|
||||
mOriginalItemNo = params & 0xFF;
|
||||
mItemGiveTag = dusk::mods::item_give_tag_freestanding(daItem_prm::getItemBitNo(this));
|
||||
const auto [item, displayItem] =
|
||||
const auto [item, displayItem, _] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
|
||||
mItemOverridden = item != mOriginalItemNo;
|
||||
setDisplayItemNo(displayItem);
|
||||
@@ -935,10 +935,6 @@ void daItem_c::itemGet() {
|
||||
mItemOverridden = m_itemNo != mOriginalItemNo;
|
||||
#endif
|
||||
switch (m_itemNo) {
|
||||
#if TARGET_PC
|
||||
case dItemNo_UTAWA_HEART_e:
|
||||
case dItemNo_KAKERA_HEART_e:
|
||||
#endif
|
||||
case dItemNo_HEART_e:
|
||||
mDoAud_seStart(Z2SE_HEART_PIECE_GET, NULL, 0, 0);
|
||||
execItemGet(m_itemNo IF_DUSK_ARG(mItemGiveTag) IF_DUSK_ARG(this));
|
||||
@@ -980,9 +976,6 @@ void daItem_c::itemGet() {
|
||||
case dItemNo_PACHINKO_SHOT_e:
|
||||
mDoAud_seStart(Z2SE_CONSUMP_ITEM_GET, NULL, 0, 0);
|
||||
execItemGet(m_itemNo IF_DUSK_ARG(mItemGiveTag) IF_DUSK_ARG(this));
|
||||
#if TARGET_PC
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
#if TARGET_PC
|
||||
if (mItemOverridden) {
|
||||
|
||||
@@ -99,6 +99,15 @@ int daObjLife_c::Create() {
|
||||
mRotateSpeed = 7000;
|
||||
|
||||
#if TARGET_PC
|
||||
// Restore speeds that were skipped if created from a boss with create instead of fastCreate
|
||||
auto bossItemSpeeds = dusk::mods::get_boss_item_actor_speeds();
|
||||
if (bossItemSpeeds.f != 0.f || bossItemSpeeds.y != 0.f) {
|
||||
mOverrideHover = false;
|
||||
speedF = bossItemSpeeds.f;
|
||||
speed.y = bossItemSpeeds.y;
|
||||
dusk::mods::set_boss_item_actor_speeds(0.f, 0.f);
|
||||
}
|
||||
|
||||
if (mOverrideHover) {
|
||||
fopAcM_SetGravity(this, 0.0f);
|
||||
mRotateSpeed = 550;
|
||||
@@ -153,20 +162,20 @@ int daObjLife_c::create() {
|
||||
if (mItemGiveOriginalNo == dItemNo_NONE_e) {
|
||||
mOriginalItemNo = parameterItemNo;
|
||||
mItemGiveTag = dusk::mods::item_give_tag_freestanding(getSaveBitNo());
|
||||
const auto [item, displayItem] =
|
||||
const auto [item, displayItem, was_resolved] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
|
||||
setDisplayItemNo(displayItem);
|
||||
mItemOverridden = item != mOriginalItemNo;
|
||||
mItemOverridden = was_resolved;
|
||||
if (mItemOverridden) {
|
||||
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] =
|
||||
const auto [item, displayItem, was_resolved] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
|
||||
setDisplayItemNo(displayItem);
|
||||
mItemOverridden = item != mOriginalItemNo;
|
||||
mItemOverridden = was_resolved;
|
||||
if (item != parameterItemNo) {
|
||||
fopAcM_SetParam(this, (params & 0xFFFFFF00) | item);
|
||||
}
|
||||
|
||||
@@ -151,11 +151,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -199,7 +195,7 @@ int daObjMasterSword_c::execute() {
|
||||
#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) {
|
||||
if (!masterSword.was_resolved) {
|
||||
dComIfGs_onItemFirstBit(dItemNo_MASTER_SWORD_e);
|
||||
dMeter2Info_setSword(dItemNo_MASTER_SWORD_e, false);
|
||||
dComIfGs_setSelectEquipSword(dItemNo_MASTER_SWORD_e);
|
||||
@@ -214,7 +210,7 @@ int daObjMasterSword_c::execute() {
|
||||
|
||||
const auto shadowCrystal = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_SHADOW_CRYSTAL, dItemNo_SHADOW_CRYSTAL_e, this);
|
||||
if (shadowCrystal.itemNo == dItemNo_SHADOW_CRYSTAL_e) {
|
||||
if (!shadowCrystal.was_resolved) {
|
||||
execItemGet(shadowCrystal.itemNo, shadowCrystal.tag, this);
|
||||
} else if (shadowCrystal.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(shadowCrystal, this);
|
||||
@@ -222,15 +218,14 @@ int daObjMasterSword_c::execute() {
|
||||
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
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[getFlagNo()]);
|
||||
fopAcM_delete(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ int daKey_c::create() {
|
||||
|
||||
#if TARGET_PC
|
||||
mItemGiveTag = dusk::mods::item_give_tag_freestanding(getSaveBitNo());
|
||||
const auto [item, displayItem] =
|
||||
const auto [item, displayItem, _] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, dItemNo_SMALL_KEY_e, this);
|
||||
m_itemNo = item;
|
||||
if (m_itemNo == dItemNo_NONE_e) {
|
||||
|
||||
@@ -106,8 +106,9 @@ const char* daShopItem_c::getShopArcname() {
|
||||
if (m_itemNo != dItemNo_NONE_e && mItemGiveOriginalNo == dItemNo_NONE_e) {
|
||||
mItemGiveOriginalNo = m_itemNo;
|
||||
mItemGiveTag = dusk::mods::item_give_tag_shop(mItemGiveOriginalNo);
|
||||
const auto [_, displayItem] =
|
||||
const auto [_, displayItem, was_resolved] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mItemGiveOriginalNo, this);
|
||||
setDisplayItemNo(displayItem);
|
||||
mItemOverridden = displayItem != mItemGiveOriginalNo;
|
||||
if (mItemOverridden) {
|
||||
mOverrideData = mData[mShopItemID];
|
||||
|
||||
+4
-1
@@ -269,7 +269,10 @@ static void (*item_func_ptr[256])() = {
|
||||
item_func_noentry,
|
||||
};
|
||||
|
||||
inline void getItemFunc(u8 i_itemNo) {
|
||||
#if !TARGET_PC
|
||||
inline
|
||||
#endif
|
||||
void getItemFunc(u8 i_itemNo) {
|
||||
dComIfGs_onItemFirstBit(i_itemNo);
|
||||
item_func_ptr[i_itemNo]();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ struct ItemCheckResult {
|
||||
uint32_t tag = 0;
|
||||
uint8_t itemNo = 0;
|
||||
uint8_t displayItemNo = 0;
|
||||
bool was_resolved = false;
|
||||
};
|
||||
|
||||
ItemCheckResolution item_check_resolve(const char* name, uint8_t itemNo, fopAc_ac_c* giver);
|
||||
@@ -57,6 +58,13 @@ uint32_t item_check_message(uint16_t group, uint32_t messageId);
|
||||
bool item_give_queue_dispatching();
|
||||
uint32_t item_give_queue_take_tag();
|
||||
|
||||
struct BossItemActorSpeeds {
|
||||
f32 f;
|
||||
f32 y;
|
||||
};
|
||||
void set_boss_item_actor_speeds(f32 f, f32 y);
|
||||
BossItemActorSpeeds get_boss_item_actor_speeds();
|
||||
|
||||
namespace detail {
|
||||
struct CommittedCheck {
|
||||
uint8_t vanillaItem = 0;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "item.hpp"
|
||||
|
||||
namespace dusk::mods {
|
||||
|
||||
static BossItemActorSpeeds bossItemActorSpeeds{};
|
||||
void set_boss_item_actor_speeds(f32 f, f32 y) {
|
||||
bossItemActorSpeeds.f = f;
|
||||
bossItemActorSpeeds.y = y;
|
||||
}
|
||||
|
||||
BossItemActorSpeeds get_boss_item_actor_speeds() {
|
||||
return bossItemActorSpeeds;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,6 +120,12 @@ constexpr std::array kMessageChecks{
|
||||
.vanillaItem = dItemNo_HORSE_FLUTE_e,
|
||||
.enqueueAtDisplay = false,
|
||||
},
|
||||
MessageCheck{
|
||||
.group = 2,
|
||||
.messageId = 6531,
|
||||
.name = ITEM_CHECK_SHAD_DOMINION_ROD,
|
||||
.vanillaItem = dItemNo_COPY_ROD_2_e,
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<LoadedMod*, ModItemChecks> s_modChecks;
|
||||
@@ -152,7 +158,7 @@ std::string poe_check_name(uint8_t bitNo) {
|
||||
}
|
||||
|
||||
std::string shop_check_name(uint8_t itemNo) {
|
||||
return fmt::format("shop:{}:{}", current_stage_name(), itemNo);
|
||||
return fmt::format("shop:{}:{}:{}", current_stage_name(), dStage_roomControl_c::getStayNo(), itemNo);
|
||||
}
|
||||
|
||||
std::string bug_check_name(uint8_t insectId) {
|
||||
@@ -229,6 +235,7 @@ ItemCheckResolution item_check_resolve(const char* name, uint8_t itemNo, fopAc_a
|
||||
.vanilla_item = itemNo,
|
||||
.current_item = itemNo,
|
||||
.current_display_item = itemNo,
|
||||
.was_resolved = false,
|
||||
};
|
||||
for (const auto& resolve : resolves) {
|
||||
if (!resolve.mod->active) {
|
||||
@@ -237,6 +244,7 @@ ItemCheckResolution item_check_resolve(const char* name, uint8_t itemNo, fopAc_a
|
||||
if (resolve.fixedValue) {
|
||||
info.current_item = resolve.itemNo;
|
||||
info.current_display_item = resolve.itemNo;
|
||||
info.was_resolved = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -251,6 +259,7 @@ ItemCheckResolution item_check_resolve(const char* name, uint8_t itemNo, fopAc_a
|
||||
}
|
||||
info.current_item = resolution.item;
|
||||
info.current_display_item = resolution.display_item;
|
||||
info.was_resolved = true;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
fail_mod(*resolve.mod, MOD_ERROR,
|
||||
@@ -263,6 +272,7 @@ ItemCheckResolution item_check_resolve(const char* name, uint8_t itemNo, fopAc_a
|
||||
return {
|
||||
.item = info.current_item,
|
||||
.display_item = info.current_display_item,
|
||||
.was_resolved = info.was_resolved,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -265,6 +265,7 @@ ItemCheckResult item_check_commit(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c*
|
||||
.tag = giveTag,
|
||||
.itemNo = committed->resolution.item,
|
||||
.displayItemNo = committed->resolution.display_item,
|
||||
.was_resolved = committed->resolution.was_resolved,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -274,6 +275,7 @@ ItemCheckResult item_check_commit(uint32_t giveTag, uint8_t itemNo, fopAc_ac_c*
|
||||
.tag = giveTag,
|
||||
.itemNo = committed.resolution.item,
|
||||
.displayItemNo = committed.resolution.display_item,
|
||||
.was_resolved = committed.resolution.was_resolved,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,17 @@ ModResult item_resolve_check(
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult item_resolve_check_full(ModContext* context, const char* name, uint8_t originalItemNo,
|
||||
ItemCheckResolution* outResolution) {
|
||||
if (mod_from_context(context) == nullptr || !is_valid_check_name(name) ||
|
||||
outResolution == nullptr)
|
||||
{
|
||||
return MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
*outResolution = item_check_resolve(name, originalItemNo, nullptr);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult item_give_item(
|
||||
ModContext* context, const char* checkName, uint8_t itemNo, uint32_t flags) {
|
||||
auto* mod = mod_from_context(context);
|
||||
@@ -130,6 +141,7 @@ constexpr ItemService s_itemService{
|
||||
.give_item = item_give_item,
|
||||
.observe_gives = item_observe_gives,
|
||||
.unobserve_gives = item_unobserve_gives,
|
||||
.resolve_check_full = item_resolve_check_full,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -200,6 +200,7 @@ void save_slot_written(uint32_t slot, const void* slotData) {
|
||||
store.snapshotCrc = utils::crc32(slotData, kQuestLogSize);
|
||||
}
|
||||
flush_sidecar();
|
||||
s_currentSlot = static_cast<int32_t>(slot);
|
||||
notify(slot, &SaveObserverRecord::onWritten, "save-written");
|
||||
}
|
||||
|
||||
|
||||
@@ -1621,6 +1621,7 @@ fpc_ProcID fopAcM_createItemForBoss(const cXyz* i_pos, int i_itemNo, int i_roomN
|
||||
|
||||
if (i_itemNo != originalItemNo) {
|
||||
const u32 params = 0xFFFF0000 | param_8 << 8 | (i_itemNo & 0xFF);
|
||||
dusk::mods::set_boss_item_actor_speeds(i_speedF, i_speedY);
|
||||
return fopAcM_create(fpcNm_Obj_LifeContainer_e, params, i_pos, i_roomNo, i_angle,
|
||||
i_scale, -1, giveTag, originalItemNo);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user