#include "ActorBehavior.h" #include "2s2h/CustomMessage/CustomMessage.h" #include "2s2h/Rando/Logic/Logic.h" #include "2s2h/Rando/StaticData/StaticData.h" extern "C" { #include "variables.h" #include "overlays/actors/ovl_En_Go/z_en_go.h" void Player_StartTalking(PlayState* play, Actor* actor); void Player_SetupTalk(PlayState* play, Player* player); s32 Player_SetupWaitForPutAway(PlayState* play, Player* player, AfterPutAwayFunc afterPutAwayFunc); } static std::vector skipCmds = {}; static bool freePowderKegGrantActive = false; void Rando::ActorBehavior::InitEnGoBehavior() { COND_ID_HOOK(OnActorInit, ACTOR_EN_GO, IS_RANDO, [](Actor* actor) { skipCmds.clear(); }); // Medigoron - Scripted Actors COND_VB_SHOULD(VB_EXEC_MSG_EVENT, IS_RANDO, { u32 cmdId = va_arg(args, u32); Actor* actor = va_arg(args, Actor*); if (actor->id != ACTOR_EN_GO || ENGO_GET_TYPE(actor) != ENGO_MEDIGORON) { return; } if (!skipCmds.empty() && cmdId == skipCmds.at(0)) { skipCmds.erase(skipCmds.begin()); *should = false; return; } MsgScript* script = va_arg(args, MsgScript*); Player* player = GET_PLAYER(gPlayState); if (cmdId == MSCRIPT_CMD_ID_CHECK_ITEM) { MsgScriptCmdCheckItem* cmd = (MsgScriptCmdCheckItem*)script; s16 skip = SCRIPT_PACK_16(cmd->offsetH, cmd->offsetL); s16 jumpTarget = 0x009A; if (!RANDO_SAVE_CHECKS[RC_GORON_VILLAGE_MEDIGORON].cycleObtained) { jumpTarget = 0x008C; } s16 offsetAdjustment = (skip == 0x009A - 0x002B || skip == 0x008C - 0x002B) ? 0x002B : 0x0041; s16 skipOffset = jumpTarget - offsetAdjustment; script[3] = skipOffset >> 8; script[4] = skipOffset & 0xFF; return; } if (cmdId == MSCRIPT_CMD_ID_BEGIN_TEXT || cmdId == MSCRIPT_CMD_ID_CONTINUE_TEXT) { // Could also be MsgScriptCmdContinueText, but structs are essentially identical MsgScriptCmdBeginText* cmd = (MsgScriptCmdBeginText*)script; u16 textId = SCRIPT_PACK_16(cmd->textIdH, cmd->textIdL); // Only override behavior if the player has yet to discover powder kegs if (textId != 0x0C8C || HAS_ITEM(ITEM_POWDER_KEG)) { return; } *should = false; gPlayState->msgCtx.choiceIndex = 0; skipCmds.clear(); skipCmds.push_back(MSCRIPT_CMD_ID_AWAIT_TEXT); return; } // Identify text choice branch at 0x004E by skip offset values if (cmdId == MSCRIPT_CMD_ID_CHECK_TEXT_CHOICE) { MsgScriptCmdCheckTextChoice* cmd = (MsgScriptCmdCheckTextChoice*)script; s16 skipChoice1 = SCRIPT_PACK_16(cmd->offset0H, cmd->offset0L); s16 skipChoice2 = SCRIPT_PACK_16(cmd->offset1H, cmd->offset1L); s16 skipChoice3 = SCRIPT_PACK_16(cmd->offset2H, cmd->offset2L); switch (skipChoice1, skipChoice2, skipChoice3) { case (0x0, 0x00AD - 0x00A8, 0x0): // Skip item grant and additional dialogue if player hasn't found a Keg yet if (!HAS_ITEM(ITEM_POWDER_KEG)) { s16 skipOffset = 0x00AE - 0x00A8; script[1] = script[3] = script[5] = skipOffset >> 8; script[2] = script[4] = script[6] = skipOffset & 0xFF; break; } // Restore overwritten script default values script[1] = script[2] = script[5] = script[6] = 0x0; script[3] = (0x00AD - 0x00A8) >> 8; script[4] = (0x00AD - 0x00A8) & 0xFF; } return; } if (cmdId == MSCRIPT_CMD_ID_OFFER_ITEM) { if (freePowderKegGrantActive) { *should = false; EnGo* enGo = (EnGo*)actor; Player* player = GET_PLAYER(gPlayState); player->talkActor = &enGo->actor; if (!RANDO_SAVE_CHECKS[RC_GORON_VILLAGE_MEDIGORON].cycleObtained) { RANDO_SAVE_CHECKS[RC_GORON_VILLAGE_MEDIGORON].eligible = true; } s16 skipOffset = 0x00C3 - 0x00BD; script[3] = skipOffset >> 8; script[4] = skipOffset & 0xFF; return; } // Restore overwritten script default values s16 skipOffset = 0; script[3] = skipOffset >> 8; script[4] = skipOffset & 0xFF; return; } }); COND_ID_HOOK(OnOpenText, 0x0C81, IS_RANDO, [](u16* textId, bool* loadFromMessageTable) { auto entry = CustomMessage::LoadVanillaMessageTableEntry(*textId); Audio_PlaySfx(NA_SE_EN_GOLON_WAKE_UP); // Original script plays this as part of the text. entry.msg = "Want a %rPowder Keg%w?\n"; entry.msg += "The Goron Elder said I can't sell my\n"; entry.msg += "Powder Kegs to anyone new,\n"; entry.msg += "\x12"; entry.msg += "but I can give you one to\n"; entry.msg += "blow up the boulder near the track.\x19"; CustomMessage::LoadCustomMessageIntoFont(entry); *loadFromMessageTable = false; }); COND_ID_HOOK(OnOpenText, 0x0C83, IS_RANDO, [](u16* textId, bool* loadFromMessageTable) { auto entry = CustomMessage::LoadVanillaMessageTableEntry(*textId); Audio_PlaySfx(NA_SE_EN_GOLON_WAKE_UP); // Original script plays this as part of the text. entry.msg = "If you can %rdestroy%w the boulder\n"; entry.msg += "that blocks the entrance to the\n"; entry.msg += "%rGoron Racetrack%w near here ...\n"; entry.msg += "\x12"; entry.msg += "using the %rPowder Keg%w I'm about\n"; entry.msg += "to give you, then I'll give you\n"; entry.msg += "%g{randoItem}%w."; entry.msg += "\x19"; CustomMessage::Replace( &entry.msg, "{randoItem}", Rando::StaticData::GetItemName(RANDO_SAVE_CHECKS[RC_GORON_VILLAGE_MEDIGORON].randoItemId, true)); CustomMessage::LoadCustomMessageIntoFont(entry); *loadFromMessageTable = false; }); COND_ID_HOOK(OnOpenText, 0x0C86, IS_RANDO, [](u16* textId, bool* loadFromMessageTable) { freePowderKegGrantActive = true; auto entry = CustomMessage::LoadVanillaMessageTableEntry(*textId); Audio_PlaySfx(NA_SE_EN_GOLON_VOICE_EATFULL); // Original script plays this as part of the text. entry.msg = "I heard you cleared the boulder\n"; entry.msg += "near the racetrack! Here's the\n"; entry.msg += "reward the Elder set aside for \n"; entry.msg += "anyone who could do it."; CustomMessage::EnsureMessageEnd(&entry.msg); CustomMessage::LoadCustomMessageIntoFont(entry); *loadFromMessageTable = false; }); COND_ID_HOOK(OnOpenText, 0x0C87, IS_RANDO, [](u16* textId, bool* loadFromMessageTable) { if (freePowderKegGrantActive) { freePowderKegGrantActive = false; auto entry = CustomMessage::LoadVanillaMessageTableEntry(*textId); Audio_PlaySfx(NA_SE_EN_GOLON_VOICE_GENERAL); // Original script plays this as part of the text. entry.msg = "Come back if you're interested in\n"; entry.msg += "my Powder Kegs."; CustomMessage::EnsureMessageEnd(&entry.msg); CustomMessage::LoadCustomMessageIntoFont(entry); *loadFromMessageTable = false; } }); COND_ID_HOOK(OnOpenText, 0x0C8D, IS_RANDO, [](u16* textId, bool* loadFromMessageTable) { if (!HAS_ITEM(ITEM_POWDER_KEG)) { auto entry = CustomMessage::LoadVanillaMessageTableEntry(*textId); Audio_PlaySfx(NA_SE_EN_GOLON_VOICE_GENERAL); // Original script plays this as part of the text. entry.msg = "Sorry, but the Goron Elder revoked\n"; entry.msg += "my ability to certify you to carry\n"; entry.msg += "my Powder Kegs. You'll have to find\n"; entry.msg += "one somewhere else first, goro."; CustomMessage::EnsureMessageEnd(&entry.msg); CustomMessage::LoadCustomMessageIntoFont(entry); *loadFromMessageTable = false; } }); }