diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index d69e54e65..33e2bad21 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -25,6 +25,7 @@ void func_80AA106C(EnMa1* this, GlobalContext* globalCtx); void func_80AA10EC(EnMa1* this, GlobalContext* globalCtx); void func_80AA1150(EnMa1* this, GlobalContext* globalCtx); void EnMa1_DoNothing(EnMa1* this, GlobalContext* globalCtx); +void EnMa1_WaitForSongGive(EnMa1* this, GlobalContext* globalCtx); const ActorInit En_Ma1_InitVars = { ACTOR_EN_MA1, @@ -356,16 +357,20 @@ void func_80AA0EFC(EnMa1* this, GlobalContext* globalCtx) { void GivePlayerRandoRewardMalon(EnMa1* malon, GlobalContext* globalCtx, RandomizerCheck check) { GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_EPONAS_SONG); - + // Prevents flag from getting set if we weren't able to get the item (i.e. Player is holding shield + // when closing the textbox). if (malon->actor.parent != NULL && malon->actor.parent->id == GET_PLAYER(globalCtx)->actor.id && !Flags_GetTreasure(globalCtx, 0x1F)) { Flags_SetTreasure(globalCtx, 0x1F); - } else if (!Flags_GetTreasure(globalCtx, 0x1F) && - (INV_CONTENT(ITEM_OCARINA_FAIRY) != ITEM_NONE || INV_CONTENT(ITEM_OCARINA_TIME) != ITEM_NONE) && - Actor_TextboxIsClosing(&malon->actor, globalCtx) && - (globalCtx->msgCtx.textId == 0x2049 || globalCtx->msgCtx.textId == 0x204A)) { + // puts malon in the action that vanilla has her in after learning the song + // (confirmed via breakpoints in a vanilla save). + malon->actionFunc = func_80AA0D88; + } else if (!Flags_GetTreasure(globalCtx, 0x1F)) { func_8002F434(&malon->actor, globalCtx, getItemId, 10000.0f, 100.0f); } + // make malon sing again after giving the item. + malon->unk_1E8.unk_00 = 0; + malon->unk_1E0 = 1; } void func_80AA0F44(EnMa1* this, GlobalContext* globalCtx) { @@ -381,12 +386,8 @@ void func_80AA0F44(EnMa1* this, GlobalContext* globalCtx) { } } - if (gSaveContext.n64ddFlag) { - GivePlayerRandoRewardMalon(this, globalCtx, RC_SONG_FROM_MALON); - return; - } - if (gSaveContext.eventChkInf[1] & 0x40) { + // When the player pulls out the Ocarina while close to Malon if (player->stateFlags2 & 0x1000000) { player->stateFlags2 |= 0x2000000; player->unk_6A8 = &this->actor; @@ -394,10 +395,19 @@ void func_80AA0F44(EnMa1* this, GlobalContext* globalCtx) { Message_StartTextbox(globalCtx, this->actor.textId, NULL); this->unk_1E8.unk_00 = 1; this->actor.flags |= ACTOR_FLAG_16; - this->actionFunc = func_80AA106C; + // when rando'ed, skip to the Item Giving. Otherwise go to the song teaching code. + this->actionFunc = gSaveContext.n64ddFlag ? func_80AA1150 : func_80AA106C; } else if (this->actor.xzDistToPlayer < 30.0f + (f32)this->collider.dim.radius) { + // somehow flags that the player is close to malon so that pulling out the Ocarina + // triggers the code above this. player->stateFlags2 |= 0x800000; } + // If rando'ed, a textbox is closing, it's malon's 'my mom wrote this song' text, AND we do have an ocarina + // in our inventory. This allows us to grant the check when talking to malon with the ocarina in our inventory. + if (gSaveContext.n64ddFlag && (Actor_TextboxIsClosing(&this->actor, globalCtx) && globalCtx->msgCtx.textId == 0x2049) && + (INV_CONTENT(ITEM_OCARINA_FAIRY) != ITEM_NONE || INV_CONTENT(ITEM_OCARINA_TIME) != ITEM_NONE)) { + this->actionFunc = EnMa1_WaitForSongGive; + } } } @@ -419,14 +429,48 @@ void func_80AA10EC(EnMa1* this, GlobalContext* globalCtx) { } } +void EnMa1_WaitForSongGive(EnMa1* this, GlobalContext* globalCtx) { + // Actually give the song check. + GivePlayerRandoRewardMalon(this, globalCtx, RC_SONG_FROM_MALON); +} + +// Sets an Ocarina State necessary to not softlock in rando. +// This function should only be called in rando. +void EnMa1_EndTeachSong(EnMa1* this, GlobalContext* globalCtx) { + if (globalCtx->csCtx.state == CS_STATE_IDLE) { + this->actionFunc = func_80AA0F44; + globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_04; + } + + if (gSaveContext.n64ddFlag) { + // Transition to the giving the song check on the next update run. + this->actionFunc = EnMa1_WaitForSongGive; + } +} + void func_80AA1150(EnMa1* this, GlobalContext* globalCtx) { GET_PLAYER(globalCtx)->stateFlags2 |= 0x800000; + + // When rando'ed, trigger the "song learned" Ocarina mode. + if (gSaveContext.n64ddFlag && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_CLOSING)) { + globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_03; + } + if (globalCtx->msgCtx.ocarinaMode == OCARINA_MODE_03) { - globalCtx->nextEntranceIndex = 0x157; - gSaveContext.nextCutsceneIndex = 0xFFF1; - globalCtx->fadeTransition = 42; - globalCtx->sceneLoadFlag = 0x14; - this->actionFunc = EnMa1_DoNothing; + if (!gSaveContext.n64ddFlag) { + globalCtx->nextEntranceIndex = 0x157; + gSaveContext.nextCutsceneIndex = 0xFFF1; + globalCtx->fadeTransition = 42; + globalCtx->sceneLoadFlag = 0x14; + this->actionFunc = EnMa1_DoNothing; + } else { + // When rando'ed, skip the cutscene, play the chime, reset some flags, + // and give the song on next update. + func_80078884(NA_SE_SY_CORRECT_CHIME); + this->actionFunc = EnMa1_EndTeachSong; + this->actor.flags &= ~ACTOR_FLAG_16; + globalCtx->msgCtx.ocarinaMode = OCARINA_MODE_00; + } } }