#include "d/a/obj/d_a_obj_chest.h" #include "c/c_lib.h" #include "common.h" #include "d/a/d_a_item.h" #include "d/a/d_a_itembase.h" #include "d/a/d_a_player.h" #include "d/a/obj/d_a_obj_base.h" #include "d/col/bg/d_bg_s.h" #include "d/d_message.h" #include "d/d_sc_game.h" #include "d/flag/sceneflag_manager.h" #include "d/flag/storyflag_manager.h" #include "f/f_base.h" #include "m/m3d/m_fanm.h" #include "m/m3d/m_mdl.h" #include "m/m_angle.h" #include "m/m_vec.h" #include "nw4r/g3d/res/g3d_resfile.h" #include "nw4r/g3d/res/g3d_resmdl.h" #include "s/s_Math.h" #include "toBeSorted/attention.h" #include "toBeSorted/dowsing_target.h" #include "toBeSorted/event.h" #include "toBeSorted/event_manager.h" const char *dAcOChest_c::CHEST_OPEN = "ChestOpen"; const char *dAcOChest_c::CHEST_OPEN_AFTER = "ChestOpenAfter"; const char *dAcOChest_c::CHEST_FAIL = "ChestFail"; const f32 dAcOChest_c::OPEN_WARDROBE_INTERACTION_FIELD_0x24 = 10.0f; InteractionTargetDef dAcOChest_c::OPEN_WARDROBE_INTERACTION = {0, 3, 1, OPEN, 0, 140.0f, 40.0f, 40.0f, -100.0f, 100.0f, 50.0f, 1.0f}; SPECIAL_ACTOR_PROFILE(OBJ_CHEST, dAcOChest_c, fProfile::OBJ_CHEST, 0x13E, 0, 3); char *dAcOChest_c::INSIDE_MODEL_NAMES[4] = { "TansuInsideA", "TansuInsideB", "TansuInsideC", "TansuInsideD", }; STATE_DEFINE(dAcOChest_c, Wait); STATE_DEFINE(dAcOChest_c, OpenEvent); STATE_DEFINE(dAcOChest_c, FailEvent); STATE_DEFINE(dAcOChest_c, OrderOpenEventAfter); void dAcOChest_c::changeStateOpenCallback(dAcOChest_c *chest) { if (chest == nullptr) { return; } chest->changeStateOpen(); } void dAcOChest_c::changeStateWaitCallback(dAcOChest_c *chest) { if (chest == nullptr) { return; } chest->changeStateWait(); } void dAcOChest_c::changeStateFailCallback(dAcOChest_c *chest) { if (chest == nullptr) { return; } chest->changeStateFail(); } void dAcOChest_c::changeStateWait2Callback(dAcOChest_c *chest) { if (chest == nullptr) { return; } chest->changeStateWait2(); } bool dAcOChest_c::createHeap() { char *name = getName(); char *subtype = getSubtypeName(); char *modelName = getModelName(); char *openOrClose = getOpenOrClose(0); void *mdlData = getOarcResFile(name); void *anmData = getOarcResFile(modelName); TRY_CREATE(mAnmMdl.create3(*this, mdlData, anmData, subtype, openOrClose, 0x120)); if (!getFromParams(0x1C, 0xFF)) { mAnmMdl.getModel().setPriorityDraw(0x1C, 0xFFFFFFFF); } if ((s32)getFromParams(0x10, 0xFF) != 0xFF) { void *insideMdlData = getOarcResFile("TansuInside"); mResFile = nw4r::g3d::ResFile(insideMdlData); nw4r::g3d::ResMdl mdl = mResFile.GetResMdl(INSIDE_MODEL_NAMES[getFromParams(0x10, 0xFF)]); if (!mInsideMdl.create(mdl, &mAllocator, 0x120, 1, nullptr)) { return false; } } char *dzbPlcName = getDzbPlcName(); void *dzb = getOarcDZB(name, dzbPlcName); void *plc = getOarcPLC(name, dzbPlcName); fn_326_C90(); bool ok = !mBgW.Set((cBgD_t *)dzb, (PLC *)plc, cBgW::MOVE_BG_e, &mWorldMtx, &mScale); if (!ok) { return false; } return mBgW.InitMapStuff(&mAllocator); } int dAcOChest_c::create() { CREATE_ALLOCATOR_SIZE(dAcOChest_c, 0x4000); mBgW.Lock(); dBgS::GetInstance()->Regist(&mBgW, this); dBgS::GetInstance()->RegistBg(&mBgW, this); mAcceleration = 0.0f; mMaxSpeed = 0.0f; mStateMgr.changeState(StateID_Wait); mBoundingBox.Set(mVec3_c(-200.0f, -0.0f, -100.0f), mVec3_c(200.0f, 500.0f, 100.0f)); mAnmMdl.setAnm(getOpenOrClose(0), m3d::PLAY_MODE_4); mAnmMdl.setRate(0.0f); mPositionCopy2.y = mPosition.y + 150.0f; mPositionCopy3 = mPositionCopy2; if ((s32)getFromParams(0x10, 0xFF) != 0xFF) { mInsideMdl.setLocalMtx(mWorldMtx); } if (dScGame_c::isCurrentStage("F001r") && mRoomID == 1 && 900.0f < mPosition.x && mPosition.x < 1000.0f && -50.0f < mPosition.y && mPosition.y < 50.0f && -2730.0f < mPosition.z && mPosition.z < -2630.0f) { mIsLinksCloset = true; } mVec3_c dowsingPos(0.0f, 150.0f, 0.0f); ITEM_ID itemId = (ITEM_ID)getFromParams(0x8, 0xFF); bool isTreasure = dAcItem_c::isTreasure(itemId); if (isTreasure) { mDowsingTarget.initialize(DowsingTarget::SLOT_TREASURE, 0, &dowsingPos, 0.0f); } else if (dAcItem_c::isRupee(itemId)) { mDowsingTarget.initialize(DowsingTarget::SLOT_RUPEE, 0, &dowsingPos, 0.0f); } return SUCCEEDED; } int dAcOChest_c::doDelete() { return SUCCEEDED; } int dAcOChest_c::actorExecute() { ITEM_ID itemId = (ITEM_ID)getFromParams(0x8, 0xFF); if (!hasBeenOpened() && (dAcItem_c::isTreasure(itemId) || dAcItem_c::isRupee(itemId))) { mDowsingTarget.doRegister(); } else { mDowsingTarget.doUnregister(); } mStateMgr.executeState(); fn_326_C90(); return SUCCEEDED; } int dAcOChest_c::draw() { drawModelType1(&mAnmMdl.getModel()); if (hasInsideModel()) { drawModelType1(&mInsideMdl); } return SUCCEEDED; } void dAcOChest_c::initializeState_Wait() {} void dAcOChest_c::executeState_Wait() { OPEN_WARDROBE_INTERACTION.field_0x24 = OPEN_WARDROBE_INTERACTION_FIELD_0x24; AttentionManager::GetInstance()->addTarget(*this, OPEN_WARDROBE_INTERACTION, 0, nullptr); } void dAcOChest_c::finalizeState_Wait() {} void dAcOChest_c::initializeState_OpenEvent() { stateOpenEventEnter2(); } void dAcOChest_c::executeState_OpenEvent() { stateOpenUpdate2(); } void dAcOChest_c::finalizeState_OpenEvent() {} void dAcOChest_c::initializeState_OrderOpenEventAfter() {} void dAcOChest_c::executeState_OrderOpenEventAfter() { if (mGaveItem && EventManager::sInstance->isInEvent0Or7()) { char *name = getName(); void *data = getOarcZev(name); Event event(CHEST_OPEN_AFTER, data, 400, 0x100001, nullptr, (void *)changeStateWaitCallback); mEvent.scheduleEvent(event, 0); } else if (EventManager::sInstance->isInEvent(this, CHEST_OPEN_AFTER)) { ITEM_ID itemId = (ITEM_ID)getFromParams(0x8, 0xFF); if (dAcItem_c::isRupee(itemId)) { dMessage_c::getInstance()->setField_0x2FC(0xFFFFFFFF); } field_0x65D = true; stateOpenUpdate2(); mStateMgr.changeState(StateID_OpenEvent); } } void dAcOChest_c::finalizeState_OrderOpenEventAfter() {} void dAcOChest_c::initializeState_FailEvent() { stateOpenEventEnter2(); } void dAcOChest_c::executeState_FailEvent() { stateOpenUpdate2(); } void dAcOChest_c::finalizeState_FailEvent() {} void dAcOChest_c::doInteraction(s32 _unused) { char *name = getName(); void *data = getOarcZev(name); if (hasBeenOpened()) { Event event(CHEST_FAIL, data, 100, 0x100001, (void *)changeStateFailCallback, (void *)changeStateWait2Callback); mEvent.scheduleEvent(event, 0); } else { Event event(CHEST_OPEN, data, 100, 0x100001, (void *)changeStateOpenCallback, nullptr); mEvent.scheduleEvent(event, 0); } } void dAcOChest_c::fn_326_C90() { mWorldMtx.transS(mPosition); mWorldMtx.ZXYrotM(mRotation); mAnmMdl.getModel().setLocalMtx(mWorldMtx); mAnmMdl.getModel().calc(false); } void dAcOChest_c::changeStateOpen() { if (field_0x65D) { return; } u32 flag = getFromParams(0, 0xFF); if (flag < 0xFF) { SceneflagManager::sInstance->setFlag(mRoomID, flag); } fn_326_1470(); mStateMgr.changeState(StateID_OpenEvent); } void dAcOChest_c::changeStateWait() { if (!field_0x65D) { return; } fn_326_1440(); fn_326_14A0(); mStateMgr.changeState(StateID_Wait); } void dAcOChest_c::changeStateFail() { fn_326_1470(); mStateMgr.changeState(StateID_FailEvent); } void dAcOChest_c::changeStateWait2() { fn_326_1440(); fn_326_14A0(); mStateMgr.changeState(StateID_Wait); } char *dAcOChest_c::getName() { return "Tansu"; } char *dAcOChest_c::getSubtypeName() { switch (getSubtype()) { case 0: return "TansuA"; case 1: return "TansuB"; case 2: return "TansuC"; case 3: return "TansuD"; default: return "TansuA"; } } char *dAcOChest_c::getModelName() { return "Tansu"; } char *dAcOChest_c::getOpenOrClose(u8 openOrClose) { switch (openOrClose) { case 0: return "TansuOpen"; case 1: return "TansuClose"; default: return nullptr; } } char *dAcOChest_c::getDzbPlcName() { switch (getSubtype()) { case 0: return "TansuA"; case 1: return "TansuB"; case 2: return "TansuC"; case 3: return "TansuD"; default: return "TansuA"; } } s32 dAcOChest_c::getSubtype() { return getFromParams(0x1C, 0xFF); } bool dAcOChest_c::hasBeenOpened() { if ((s32)getFromParams(8, 0xFF) == 0xFF) { return true; } u32 flag = getFromParams(0, 0xFF); if (flag >= 0xFF) { return true; } return (flag < 0xFF) && SceneflagManager::sInstance->checkBoolFlag(mRoomID, flag); } void dAcOChest_c::stateOpenUpdate2() { dAcPy_c *player = dAcPy_c::LINK; switch (mEvent.getCurrentEventCommand()) { case 'wait': { mEvent.advanceNext(); break; } case 'move': { if (mEvent.isAdvance()) { int i; mEvent.getSingleIntData(&i, 'type', 0); if (i == 1) { char *openOrClose = getOpenOrClose(0); mAnmMdl.setAnm(openOrClose, m3d::PLAY_MODE_4); mAnmMdl.setFrame(0.0f); mAnmMdl.setRate(1.0f); mAnmMdl.getAnm().setPlayState(m3d::PLAY_MODE_1); } else if (i == 2) { char *openOrClose = getOpenOrClose(1); mAnmMdl.setAnm(openOrClose, m3d::PLAY_MODE_4); mAnmMdl.setFrame(0.0f); mAnmMdl.setRate(1.0f); mAnmMdl.getAnm().setPlayState(m3d::PLAY_MODE_1); } } else { mAnmMdl.play(); if (mAnmMdl.getAnm().isStop()) { mEvent.advanceNext(); } } break; } case 'comp': { mVec3_c targetPosition; mVec3_c playerPosition; mVec3_c t(0.0f, 0.0f, 122.35f); s32 targetAngle = 0x7FFF; targetPosition = t; targetAngle += mRotation.y; targetPosition.rotY(mRotation.y); targetPosition += mPosition; if (player != nullptr) { playerPosition = player->mPosition; cLib::addCalcPos(&playerPosition, targetPosition, 0.25f, 200.0f, 0.0f); s16 YRot = mRotation.y; sLib::addCalcAngle(&YRot, targetAngle, 4, 0x7FFF, 0); if ((targetPosition.squareDistanceToXZ(playerPosition) < 25.0f) && mAng::abs(YRot - mAng(targetAngle)) < 0xb6) { playerPosition = targetPosition; YRot = targetAngle; mEvent.advanceNext(); } player->setPosYRot(playerPosition, YRot, 0, 0, 0); } else { mEvent.advanceNext(); } break; } case 'item': { ITEM_ID itemId = (ITEM_ID)getFromParams(0x8, 0xFF); dAcItem_c::giveItem(itemId, 0, 0); mGaveItem = true; mStateMgr.changeState(StateID_OrderOpenEventAfter); mEvent.advanceNext(); break; } case '????': { break; } default: { mEvent.advanceNext(); } } } void dAcOChest_c::stateOpenEventEnter2() { if ((s32)getFromParams(0x10, 0xFF) == 0xFF) { return; } mHasInsideModel = true; } void dAcOChest_c::fn_326_1440() { if ((s32)getFromParams(0x10, 0xFF) == 0xFF) { return; } mHasInsideModel = false; } bool dAcOChest_c::hasInsideModel() { return mHasInsideModel; } void dAcOChest_c::fn_326_1470() { if (!mIsLinksCloset) { return; } StoryflagManager::sInstance->setFlag(STORYFLAG_ALTERNATE_WARDROBE_TEXT); } void dAcOChest_c::fn_326_14A0() { if (!mIsLinksCloset) { return; } StoryflagManager::sInstance->unsetFlag(STORYFLAG_ALTERNATE_WARDROBE_TEXT); } const u32 dAcOChest_c::unused = 0;