#include "common.h" #include "battle/battle.h" #include "script_api/battle.h" #include "npc.h" #include "effects.h" #include "hud_element.h" #include "world/partners.h" #include "sprite.h" #include "sprite/npc/BattleMerlee.h" ApiStatus ShowMerleeCoinMessage(Evt* script, s32 isInitialCall); ApiStatus ShowMerleeRanOutMessage(Evt* script, s32 isInitialCall); ApiStatus FadeInMerlee(Evt* script, s32 isInitialCall); ApiStatus FadeOutMerlee(Evt* script, s32 isInitialCall); ApiStatus MerleeUpdateFX(Evt* script, s32 isInitialCall); ApiStatus MerleeStopFX(Evt* script, s32 isInitialCall); ApiStatus PlayMerleeGatherFX(Evt* script, s32 isInitialCall); ApiStatus PlayMerleeOrbFX(Evt* script, s32 isInitialCall); void spawn_drops(Enemy* enemy); s32 D_80077C40 = 0; extern EvtScript D_800936DC; EvtScript D_80077C44 = { EVT_WAIT(10) EVT_CALL(FadeBackgroundToBlack) EVT_WAIT(10) EVT_CALL(CreateNpc, NPC_BTL_MERLEE, ANIM_BattleMerlee_Gather) EVT_CALL(SetNpcFlagBits, NPC_BTL_MERLEE, NPC_FLAG_100, TRUE) EVT_CALL(SetNpcYaw, NPC_BTL_MERLEE, 0) EVT_CALL(GetCamLookAtObjVector) EVT_CALL(SetNpcPos, NPC_BTL_MERLEE, LocalVar(0), LocalVar(1), LocalVar(2)) EVT_THREAD EVT_CALL(MerleeUpdateFX) EVT_END_THREAD EVT_CALL(FadeInMerlee) EVT_WAIT(30) EVT_CALL(SetNpcAnimation, NPC_BTL_MERLEE, ANIM_BattleMerlee_Release) EVT_CALL(MerleeStopFX) EVT_CALL(UnfadeBackgroundFromBlack) EVT_WAIT(20) EVT_THREAD EVT_CALL(FadeOutMerlee) EVT_CALL(DeleteNpc, NPC_BTL_MERLEE) EVT_END_THREAD EVT_CALL(PlaySound, SOUND_2075) EVT_CALL(GetPlayerPos, LocalVar(0), LocalVar(1), LocalVar(2)) EVT_CALL(PlayMerleeGatherFX, LocalVar(0), LocalVar(1), LocalVar(2)) EVT_CALL(PlayMerleeOrbFX, LocalVar(0), LocalVar(1), LocalVar(2)) EVT_WAIT(15) EVT_CALL(ShowMerleeCoinMessage) EVT_WAIT(15) EVT_CALL(HasMerleeCasts) EVT_IF_EQ(LocalVar(0), 1) EVT_RETURN EVT_END_IF EVT_CALL(ShowMerleeRanOutMessage) EVT_WAIT(15) EVT_RETURN EVT_END }; EvtScript SCRIPT_NpcDefeat = { EVT_CALL(GetBattleOutcome, LocalVar(0)) EVT_SWITCH(LocalVar(0)) EVT_CASE_EQ(0) EVT_CALL(OnDefeatEnemy) EVT_CASE_EQ(1) EVT_CASE_EQ(2) EVT_END_SWITCH EVT_RETURN EVT_END }; EvtScript D_80077E9C = { EVT_CALL(OnFleeBattleDrops) EVT_RETURN EVT_END }; EnemyDrops D_80077EB8 = { .dropFlags = 0x80, .itemDropChance = 10, .itemDrops = { { .item = ITEM_MUSHROOM, .weight = 50, .unk_04 = -1, }, }, .heartDrops = { { .cutoff = F16(75), .generalChance = F16(100), .attempts = 0, .chancePerAttempt = 1, }, { .cutoff = F16(50), .generalChance = F16(75), .attempts = 0, .chancePerAttempt = 2, }, { .cutoff = F16(25), .generalChance = F16(50), .attempts = 0, .chancePerAttempt = 3, }, { .cutoff = F16(0), .generalChance = F16(25), .attempts = 0, .chancePerAttempt = 4, }, }, .flowerDrops = { { .cutoff = 1, .generalChance = 3, .attempts = 0, .chancePerAttempt = 0, }, }, .minCoinBonus = 0, .maxCoinBonus = 0, }; EvtScript EnemyNpcHit = { EVT_CALL(GetOwnerEncounterTrigger, LocalVar(0)) EVT_SWITCH(LocalVar(0)) EVT_CASE_EQ(1) EVT_CASE_OR_EQ(2) EVT_CASE_OR_EQ(4) EVT_CASE_OR_EQ(6) EVT_CALL(GetSelfAnimationFromTable, 7, LocalVar(0)) EVT_EXEC_WAIT(D_800936DC) EVT_CASE_EQ(3) EVT_THREAD EVT_CALL(func_800458CC, LocalVar(0)) EVT_IF_EQ(LocalVar(0), 0) EVT_SET(LocalVar(10), 0) EVT_LOOP(30) EVT_ADD(LocalVar(10), 40) EVT_CALL(SetNpcRotation, NPC_SELF, 0, LocalVar(10), 0) EVT_WAIT(1) EVT_END_LOOP EVT_END_IF EVT_END_THREAD EVT_END_CASE_GROUP EVT_END_SWITCH EVT_RETURN EVT_END }; EvtScript EnemyNpcDefeat = { EVT_CALL(SetNpcRotation, NPC_SELF, 0, 0, 0) EVT_CALL(GetBattleOutcome, LocalVar(0)) EVT_SWITCH(LocalVar(0)) EVT_CASE_EQ(0) EVT_CALL(DoNpcDefeat) EVT_CASE_EQ(2) EVT_CALL(func_80045900, 0) EVT_CASE_EQ(3) EVT_CALL(SetEnemyFlagBits, -1, 16, 1) EVT_CALL(RemoveNpc, NPC_SELF) EVT_END_SWITCH EVT_RETURN EVT_END }; extern s8 D_8009A654; extern s16 D_8009A668; extern s32 D_800A0BA0; extern f32 D_800A0BA4; extern EffectInstance* WorldMerleeOrbEffect; extern EffectInstance* WorldMerleeWaveEffect; void set_battle_formation(Battle*); s32 get_defeated(s32 mapID, s32 encounterID) { EncounterStatus* currentEncounter = &gCurrentEncounter; s32 encounterIdx = encounterID / 32; s32 encounterShift = encounterID % 32; return currentEncounter->defeatFlags[mapID][encounterIdx] & (1 << encounterShift); } void set_defeated(s32 mapID, s32 encounterID) { EncounterStatus* currentEncounter = &gCurrentEncounter; s32 encounterIdx = encounterID / 32; s32 encounterShift; s32 flag; flag = encounterID % 32; encounterShift = flag; flag = currentEncounter->defeatFlags[mapID][encounterIdx]; currentEncounter->defeatFlags[mapID][encounterIdx] = flag | (1 << encounterShift); // TODO: The below should work but has regalloc issues: /*EncounterStatus *currentEncounter = &gCurrentEncounter; s32 encounterIdx = encounterID / 32; s32 encounterShift = encounterID % 32; currentEncounter->defeatFlags[mapID][encounterIdx] |= (1 << encounterShift);*/ } ApiStatus ShowMerleeCoinMessage(Evt* script, s32 isInitialCall) { if (isInitialCall) { show_merlee_message(0, 60); } if (is_merlee_message_done()) { return ApiStatus_BLOCK; } else { return ApiStatus_DONE2; } } ApiStatus ShowMerleeRanOutMessage(Evt* script, s32 isInitialCall) { if (isInitialCall) { show_merlee_message(1, 60); } if (is_merlee_message_done()) { return ApiStatus_BLOCK; } else { return ApiStatus_DONE2; } } ApiStatus FadeBackgroundToBlack(Evt* script, s32 isInitialCall) { if (isInitialCall) { mdl_set_all_fog_mode(1); *D_801512F0 = 1; set_background_color_blend(0, 0, 0, 0); script->functionTemp[0] = 25; } set_background_color_blend(0, 0, 0, ((25 - script->functionTemp[0]) * 10) & 254); script->functionTemp[0]--; if (script->functionTemp[0] == 0) { return ApiStatus_DONE2; } else { return ApiStatus_BLOCK; } } ApiStatus UnfadeBackgroundFromBlack(Evt* script, s32 isInitialCall) { if (isInitialCall) { script->functionTemp[0] = 25; } set_background_color_blend(0, 0, 0, (script->functionTemp[0] * 10) & 0xFE); script->functionTemp[0] -= 5; if (script->functionTemp[0] == 0) { set_background_color_blend(0, 0, 0, 0); return ApiStatus_DONE2; } else { return ApiStatus_BLOCK; } } ApiStatus FadeInMerlee(Evt* script, s32 isInitialCall) { Npc* npc = get_npc_unsafe(NPC_BTL_MERLEE); if (isInitialCall) { sfx_play_sound(SOUND_24B); npc->alpha = 0; } npc->alpha += 17; if ((u32)(npc->alpha & 0xFF) >= 0xFF) { npc->alpha = 0xFF; return ApiStatus_DONE1; } else { return ApiStatus_BLOCK; } } ApiStatus FadeOutMerlee(Evt* script, s32 isInitialCall) { Npc* npc = get_npc_unsafe(NPC_BTL_MERLEE); npc->alpha -= 17; if (npc->alpha == 0) { npc->alpha = 0; return ApiStatus_DONE1; } else { return ApiStatus_BLOCK; } } // same as BattleMerleeUpdateFX aside from syms ApiStatus MerleeUpdateFX(Evt* script, s32 isInitialCall) { Npc* merlee = get_npc_unsafe(NPC_BTL_MERLEE); EnergyOrbWaveFXData* effectData; if (isInitialCall) { script->functionTemp[1] = 0; D_800A0BA4 = merlee->pos.y; WorldMerleeOrbEffect = fx_energy_orb_wave(0, merlee->pos.x, merlee->pos.y, merlee->pos.z, 0.4f, 0); WorldMerleeWaveEffect = fx_energy_orb_wave(3, merlee->pos.x, merlee->pos.y, merlee->pos.z, 0.00001f, 0); D_800A0BB8 = 0; D_800A0BA0 = 12; sfx_play_sound(SOUND_2074); } merlee->pos.y = D_800A0BA4 + sin_rad(DEG_TO_RAD(script->functionTemp[1])) * 3.0f; script->functionTemp[1] += 10; script->functionTemp[1] = clamp_angle(script->functionTemp[1]); effectData = WorldMerleeOrbEffect->data.energyOrbWave; effectData->pos.x = merlee->pos.x; effectData->pos.y = merlee->pos.y + 16.0f; effectData->pos.z = merlee->pos.z; effectData = WorldMerleeWaveEffect->data.energyOrbWave; effectData->pos.x = merlee->pos.x; effectData->pos.y = merlee->pos.y + 16.0f; effectData->pos.z = merlee->pos.z + 5.0f; if (D_800A0BB8 == 2) { WorldMerleeOrbEffect->data.energyOrbWave->scale = 0.00001f; WorldMerleeWaveEffect->data.energyOrbWave->scale = 0.00001f; WorldMerleeOrbEffect->flags |= EFFECT_INSTANCE_FLAGS_10; WorldMerleeWaveEffect->flags |= EFFECT_INSTANCE_FLAGS_10; return ApiStatus_DONE1; } if (D_800A0BB8 == 1) { effectData = WorldMerleeOrbEffect->data.energyOrbWave; effectData->scale += 0.35; if (effectData->scale > 3.5) { effectData->scale = 3.5f; } if (D_800A0BA0 != 0) { D_800A0BA0--; } else { effectData = WorldMerleeWaveEffect->data.energyOrbWave; effectData->scale += 0.5; if (effectData->scale > 5.0) { D_800A0BB8 = 2; } } } return ApiStatus_BLOCK; } ApiStatus MerleeStopFX(Evt* script, s32 isInitialCall) { D_800A0BB8 = 1; return ApiStatus_DONE2; } ApiStatus GetCamLookAtObjVector(Evt* script, s32 isInitialCall) { script->varTable[0] = gCameras[gCurrentCameraID].lookAt_obj.x; script->varTable[1] = gCameras[gCurrentCameraID].lookAt_obj.y; script->varTable[2] = gCameras[gCurrentCameraID].lookAt_obj.z; return ApiStatus_DONE2; } ApiStatus HasMerleeCasts(Evt* script, s32 isInitialCall) { script->varTable[0] = FALSE; if (gPlayerData.merleeCastsLeft > 0) { script->varTable[0] = TRUE; } return ApiStatus_DONE2; } ApiStatus PlayMerleeGatherFX(Evt* script, s32 isInitialCall) { Bytecode* args = script->ptrReadPos; s32 var0 = evt_get_variable(script, *args++); s32 var1 = evt_get_variable(script, *args++); s32 var2 = evt_get_variable(script, *args++); fx_energy_in_out(6, var0, var1, var2, 1.2f, 30); return ApiStatus_DONE2; } ApiStatus PlayMerleeOrbFX(Evt* script, s32 isInitialCall) { Bytecode* args = script->ptrReadPos; s32 var0 = evt_get_variable(script, *args++); s32 var1 = evt_get_variable(script, *args++); s32 var2 = evt_get_variable(script, *args++); fx_energy_orb_wave(9, var0, var1, var2, 5.0f, 15); return ApiStatus_DONE2; } ApiStatus OnDefeatEnemy(Evt* script, s32 isInitialCall) { Enemy* enemy = script->owner1.enemy; Npc* npc = get_npc_unsafe(enemy->npcID); s32 temp1; if (isInitialCall) { script->functionTemp[0] = 0; script->functionTemp[1] = 20; } if (script->functionTemp[1] & 1) { npc->flags &= ~NPC_FLAG_2; } else { npc->flags |= NPC_FLAG_2; } if (script->functionTemp[1] == 15) { sfx_play_sound(SOUND_DEATH); fx_damage_stars(1, npc->pos.x, npc->pos.y + (npc->collisionHeight / 2), npc->pos.z, 0, -1.0f, 0, 10); } temp1 = script->functionTemp[1]; if (script->functionTemp[1] == 10) { fx_big_smoke_puff(npc->pos.x, npc->pos.y + 10.0f, npc->pos.z + 10.0f); if (script->functionTemp[1] == temp1) { // what? (never can be false, seemingly) spawn_drops(enemy); } } script->functionTemp[1]--; if (script->functionTemp[1] == 0) { npc->flags |= NPC_FLAG_2; return ApiStatus_DONE1; } return ApiStatus_BLOCK; } ApiStatus OnFleeBattleDrops(Evt* script, s32 isInitialCall) { PlayerStatus* playerStatus = &gPlayerStatus; PlayerData* playerData = &gPlayerData; if (isInitialCall) { script->functionTemp[0] = 0; script->functionTemp[1] = 40; script->functionTemp[2] = 0; } script->functionTemp[2]++; if (script->functionTemp[2] >= 5) { if (rand_int(100) < 50) { if (playerData->coins != 0) { playerData->coins--; make_item_entity_delayed(ITEM_COIN, playerStatus->position.x, playerStatus->position.y + playerStatus->colliderHeight, playerStatus->position.z, 3, 0, 0); } } script->functionTemp[2] = 0; } return --script->functionTemp[1] == 0; } /// Default/neutral state during world gameplay; checks for player-enemy collisions and initiates battles when they occur. INCLUDE_ASM(s32, "1a1f0_len_5390", update_encounters_neutral); void draw_encounters_neutral(void) { } void update_encounters_pre_battle(void) { EncounterStatus* currentEncounter = &gCurrentEncounter; PlayerData* playerData = &gPlayerData; Encounter* encounter; Enemy* enemy; s32 i; s32 j; switch (D_8009A5D0) { case 0: currentEncounter->fadeOutAmount = 0; currentEncounter->unk_94 = 1; currentEncounter->fadeOutAccel = 1; currentEncounter->unk_08 = -1; D_8009A654 = 0; D_80077C40 = 0; suspend_all_group(0x10); for (i = 0; i < currentEncounter->numEncounters; i++) { encounter = currentEncounter->encounterList[i]; if (encounter != NULL) { for (j = 0; j < encounter->count; j++) { enemy = encounter->enemy[j]; if (enemy != NULL && !(enemy->flags & NPC_FLAG_NO_AI)) { if (enemy->aiScript != NULL) { suspend_all_script(enemy->aiScriptID); } if (enemy->auxScript != NULL) { suspend_all_script(enemy->auxScriptID); } } } } } enemy = currentEncounter->currentEnemy; if ((enemy->flags & NPC_FLAG_MOTION_BLUR) && currentEncounter->unk_12 == 0) { currentEncounter->unk_94 = 0; currentEncounter->battleStartCountdown = 0; partner_handle_before_battle(); D_8009A5D0 = 3; return; } if (gGameStatusPtr->debugEnemyContact == 2) { currentEncounter->unk_94 = 0; currentEncounter->battleStartCountdown = 10; partner_handle_before_battle(); D_8009A5D0 = 2; return; } enemy = currentEncounter->currentEnemy; if (currentEncounter->hitType != 1 && currentEncounter->hitType != 3 && is_ability_active(ABILITY_FIRST_ATTACK) && (playerData->level >= enemy->npcSettings->level) && !(enemy->flags & ENEMY_FLAGS_40) && currentEncounter->unk_12 == 0) { currentEncounter->unk_94 = 0; currentEncounter->battleStartCountdown = 0xA; D_80077C40 = 1; D_8009A5D0 = 2; return; } enemy = currentEncounter->currentEnemy; if (( (is_ability_active(ABILITY_BUMP_ATTACK)) && (playerData->level >= enemy->npcSettings->level) && (!(enemy->flags & ENEMY_FLAGS_40) && (currentEncounter->unk_12 == 0)) ) || ( (enemy = currentEncounter->currentEnemy, (currentEncounter->hitType == 3)) && (is_ability_active(ABILITY_SPIN_ATTACK)) && playerData->level >= enemy->npcSettings->level && !(enemy->flags & ENEMY_FLAGS_40) && currentEncounter->unk_12 == 0 )) { currentEncounter->battleStartCountdown = 10; D_80077C40 = 1; currentEncounter->unk_94 = 0; D_8009A5D0 = 2; return; } if (currentEncounter->songID < 0) { switch (currentEncounter->firstStrikeType) { case 0: bgm_set_battle_song(SONG_NORMAL_BATTLE, FIRST_STRIKE_NONE); break; case 1: bgm_set_battle_song(SONG_NORMAL_BATTLE, FIRST_STRIKE_PLAYER); break; case 2: bgm_set_battle_song(SONG_NORMAL_BATTLE, FIRST_STRIKE_ENEMY); break; } } else { bgm_set_battle_song(currentEncounter->songID, FIRST_STRIKE_NONE); } bgm_push_battle_song(); D_8009A654 = 1; currentEncounter->battleStartCountdown = 10; D_8009A5D0 = 1; case 1: if (currentEncounter->fadeOutAmount == 255) { if (currentEncounter->battleStartCountdown != 0) { currentEncounter->battleStartCountdown--; break; } encounter = currentEncounter->currentEncounter; for (i = 0; i < encounter->count; i++) { enemy = encounter->enemy[i]; if (enemy != NULL && ((!(enemy->flags & NPC_FLAG_ENABLE_HIT_SCRIPT) || enemy == currentEncounter->currentEnemy)) && !(enemy->flags & NPC_FLAG_NO_AI) && enemy->hitScript != NULL) { kill_script_by_ID(enemy->hitScriptID); enemy->hitScript = NULL; } } partner_handle_before_battle(); currentEncounter->dizzyAttackStatus = 0; currentEncounter->dizzyAttackDuration = 0; enemy = currentEncounter->currentEnemy; currentEncounter->unk_10 = enemy->unk_B5; if (is_ability_active(ABILITY_DIZZY_ATTACK) && currentEncounter->hitType == 3) { currentEncounter->dizzyAttackStatus = 4; currentEncounter->dizzyAttackDuration = 3; } sfx_stop_sound(SOUND_2111); sfx_stop_sound(SOUND_2112); sfx_stop_sound(SOUND_2113); sfx_stop_sound(SOUND_2114); set_battle_formation(NULL); set_battle_stage(encounter->stage); load_battle(encounter->battle); currentEncounter->unk_07 = 1; currentEncounter->unk_08 = 0; currentEncounter->merleeCoinBonus = 0; currentEncounter->damageTaken = 0; currentEncounter->coinsEarned = 0; currentEncounter->fadeOutAccel = 0; currentEncounter->fadeOutAmount = 255; set_screen_overlay_params_front(0, 255.0f); gGameState = 5; D_8009A678 = 1; D_8009A5D0 = 0; } break; case 2: if (currentEncounter->battleStartCountdown != 0) { currentEncounter->battleStartCountdown--; break; } encounter = currentEncounter->currentEncounter; for (i = 0; i < encounter->count; i++) { enemy = encounter->enemy[i]; if (enemy != NULL && (!(enemy->flags & NPC_FLAG_ENABLE_HIT_SCRIPT) || enemy == currentEncounter->currentEnemy) && !(enemy->flags & NPC_FLAG_NO_AI) && (enemy->hitScript != 0)) { kill_script_by_ID(enemy->hitScriptID); enemy->hitScript = NULL; } } currentEncounter->unk_08 = 1; currentEncounter->unk_07 = 1; currentEncounter->battleOutcome = 0; currentEncounter->merleeCoinBonus = 0; currentEncounter->damageTaken = 0; gGameState = 5; currentEncounter->coinsEarned = 0; currentEncounter->fadeOutAccel = 0; currentEncounter->fadeOutAmount = 0; D_8009A678 = 1; D_8009A5D0 = 0; break; case 3: currentEncounter->battleOutcome = 4; currentEncounter->unk_08 = 1; currentEncounter->fadeOutAmount = 0; currentEncounter->fadeOutAccel = 0; gGameState = 5; D_8009A678 = 1; D_8009A5D0 = 0; break; } } void draw_encounters_pre_battle(void) { EncounterStatus* encounter = &gCurrentEncounter; Npc* npc = get_npc_unsafe(encounter->currentEnemy->npcID); PlayerStatus* playerStatus = &gPlayerStatus; if (encounter->unk_94 != 0) { f32 playerX, playerY, playerZ; f32 otherX, otherY, otherZ; s32 pScreenX, pScreenY, pScreenZ; s32 oScreenX, oScreenY, oScreenZ; if (encounter->fadeOutAmount != 255) { encounter->fadeOutAccel++; if (encounter->fadeOutAccel > 10) { encounter->fadeOutAccel = 10; } encounter->fadeOutAmount += encounter->fadeOutAccel; if (encounter->fadeOutAmount > 255) { encounter->fadeOutAmount = 255; } playerX = playerStatus->position.x; playerY = playerStatus->position.y; playerZ = playerStatus->position.z; otherX = npc->pos.x; otherY = npc->pos.y; otherZ = npc->pos.z; if (otherY < -990.0f) { otherX = playerX; otherY = playerY; otherZ = playerZ; } if (gGameStatusPtr->demoState == 2) { set_screen_overlay_params_back(10, encounter->fadeOutAmount); set_screen_overlay_alpha(1, 255.0f); set_screen_overlay_color(1, 0, 0, 0); get_screen_coords(gCurrentCameraID, playerX, playerY + 20.0f, playerZ, &pScreenX, &pScreenY, &pScreenZ); get_screen_coords(gCurrentCameraID, otherX, otherY + 15.0f, otherZ, &oScreenX, &oScreenY, &oScreenZ); set_screen_overlay_center(1, 0, (pScreenX - oScreenX) / 2 + oScreenX, (pScreenY - oScreenY) / 2 + oScreenY); } else { set_screen_overlay_params_front(10, encounter->fadeOutAmount); set_screen_overlay_alpha(0, 255.0f); set_screen_overlay_color(0, 0, 0, 0); get_screen_coords(gCurrentCameraID, playerX, playerY + 20.0f, playerZ, &pScreenX, &pScreenY, &pScreenZ); get_screen_coords(gCurrentCameraID, otherX, otherY + 15.0f, otherZ, &oScreenX, &oScreenY, &oScreenZ); set_screen_overlay_center(0, 0, (pScreenX - oScreenX) / 2 + oScreenX, (pScreenY - oScreenY) / 2 + oScreenY); } } } } void show_first_strike_message(void) { EncounterStatus* currentEncounter = &gCurrentEncounter; s32 posX; s32 width; s32 xOffset; s32 screenWidthHalf; if (currentEncounter->unk_94 == 0) { D_8009A668 = -200; return; } D_8009A668 += 40; xOffset = D_8009A668; if (xOffset > 0) { if (xOffset < 1600) { xOffset = 0; } else { xOffset -= 1600; } } screenWidthHalf = SCREEN_WIDTH / 2; switch (currentEncounter->firstStrikeType) { case FIRST_STRIKE_PLAYER: switch (currentEncounter->hitType) { case 2: case 4: width = get_msg_width(0x1D00AC, 0) + 24; posX = (xOffset + screenWidthHalf) - (width / 2); draw_box(0, 0x14, posX, 69, 0, width, 28, 255, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL); draw_msg(0x1D00AC, posX + 11, 75, 0xFF, 0xA, 0); break; case 6: width = get_msg_width(0x1D00AD, 0) + 24; posX = (xOffset + screenWidthHalf) - (width / 2); draw_box(0, 0x14, posX, 69, 0, width, 28, 255, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL); draw_msg(0x1D00AD, posX + 11, 75, 0xFF, 0xA, 0); break; } break; case FIRST_STRIKE_ENEMY: if (!is_ability_active(ABILITY_CHILL_OUT)) { width = get_msg_width(0x1D00AE, 0) + 24; posX = (xOffset + screenWidthHalf) - (width / 2); draw_box(0, 4, posX, 69, 0, width, 28, 255, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL); draw_msg(0x1D00AE, posX + 11, 75, 0xFF, 0xA, 0); } break; } } INCLUDE_ASM(s32, "1a1f0_len_5390", update_encounters_post_battle); void draw_encounters_post_battle(void) { EncounterStatus* currentEncounter = &gCurrentEncounter; s32 ret = currentEncounter->fadeOutAccel; if (ret != 0) { set_screen_overlay_params_front(0, currentEncounter->fadeOutAmount); set_screen_overlay_color(0, 0, 0, 0); } } void update_encounters_conversation(void) { EncounterStatus* encounter = &gCurrentEncounter; PlayerStatus* playerStatus = &gPlayerStatus; Enemy* currentEnemy; s32 flag; switch (D_8009A5D0) { case 0: currentEnemy = encounter->currentEnemy; flag = FALSE; if (currentEnemy->interactScript != NULL) { if (does_script_exist(currentEnemy->interactScriptID)) { flag = TRUE; } else { currentEnemy->interactScript = NULL; } } if (currentEnemy->hitScript != NULL) { if (does_script_exist(currentEnemy->hitScriptID)) { flag = TRUE; } else { currentEnemy->hitScript = NULL; } } if (!flag) { D_8009A5D0 = 1; } break; case 1: resume_all_group(1); currentEnemy = encounter->currentEnemy; if (currentEnemy != NULL && currentEnemy->aiScript != NULL) { resume_all_script(currentEnemy->aiScriptID); } enable_player_input(); partner_enable_input(); if (playerStatus->actionState == ACTION_STATE_TALK) { set_action_state(ACTION_STATE_IDLE); } func_800EF3D4(0); encounter->hitType = 0; resume_all_group(16); gGameState = 2; D_8009A678 = 1; D_8009A5D0 = 0; break; } } void draw_encounters_conversation(void) { } s32 check_conversation_trigger(void) { PlayerStatus* playerStatus = &gPlayerStatus; Camera* camera = &gCameras[gCurrentCameraID]; EncounterStatus* encounterStatus = &gCurrentEncounter; f32 npcX, npcY, npcZ; f32 angle; f32 deltaX, deltaZ; Encounter* encounter; f32 playerX, playerY, playerZ; f32 playerColliderHeight; f32 playerColliderRadius; f32 length; f32 npcCollisionHeight; f32 npcCollisionRadius; Encounter* encounterTemp; Npc* npc; Npc* encounterNpc; Enemy* enemy; Enemy* encounterEnemy; f32 minLength; f32 xTemp, yTemp, zTemp; s32 i, j; playerStatus->encounteredNPC = NULL; playerStatus->flags &= ~PS_FLAGS_HAS_CONVERSATION_NPC; playerColliderHeight = playerStatus->colliderHeight; playerColliderRadius = playerStatus->colliderDiameter / 2; playerX = playerStatus->position.x; playerY = playerStatus->position.y; playerZ = playerStatus->position.z; if (gPartnerActionStatus.partnerActionState != PARTNER_ACTION_NONE) { return FALSE; } encounter = NULL; npc = NULL; enemy = NULL; minLength = 65535.0f; for (i = 0; i < encounterStatus->numEncounters; i++) { encounterTemp = encounterStatus->encounterList[i]; if (encounterTemp == NULL) { continue; } for (j = 0; j < encounterTemp->count; j++) { encounterEnemy = encounterTemp->enemy[j]; if (encounterEnemy == NULL) { continue; } if (encounterEnemy->flags & (ENEMY_FLAGS_80000000 | ENEMY_FLAGS_20)) { continue; } if (!(encounterEnemy->flags & ENEMY_FLAGS_1)) { continue; } if ((encounterEnemy->flags & ENEMY_FLAGS_8000000) || encounterEnemy->interactBytecode == NULL) { continue; } encounterNpc = get_npc_unsafe(encounterEnemy->npcID); npcX = encounterNpc->pos.x; npcY = encounterNpc->pos.y; npcZ = encounterNpc->pos.z; deltaX = npcX - playerX; deltaZ = npcZ - playerZ; npcCollisionHeight = encounterNpc->collisionHeight; npcCollisionRadius = encounterNpc->collisionRadius; length = sqrtf(SQ(deltaX) + SQ(deltaZ)); if ((playerColliderRadius + npcCollisionRadius <= length) || (npcY + npcCollisionHeight < playerY) || (playerY + playerColliderHeight < npcY)) { continue; } if (clamp_angle(playerStatus->spriteFacingAngle) < 180.0f) { angle = clamp_angle(camera->currentYaw - 120.0f); if (playerStatus->trueAnimation & SPRITE_ID_BACK_FACING) { angle = clamp_angle(angle + 60.0f); } } else { angle = clamp_angle(camera->currentYaw + 120.0f); if (playerStatus->trueAnimation & SPRITE_ID_BACK_FACING) { angle = clamp_angle(angle - 60.0f); } } if (fabsf(get_clamped_angle_diff(angle, atan2(playerX, playerZ, npcX, npcZ))) > 90.0f) { continue; } if (!(encounterEnemy->flags & ENEMY_FLAGS_10000) && encounterNpc->flags & NPC_FLAG_20000000) { xTemp = npcX; yTemp = npcY; zTemp = npcZ; if (npc_test_move_taller_with_slipping(0, &xTemp, &yTemp, &zTemp, length, atan2(npcX, npcZ, playerX, playerZ), npcCollisionHeight, 2.0f * npcCollisionRadius) != 0) { continue; } } if (length < minLength) { minLength = length; encounter = encounterTemp; npc = encounterNpc; enemy = encounterEnemy; } } } if (!(playerStatus->animFlags & PA_FLAGS_8BIT_MARIO) && npc != NULL && !is_picking_up_item()) { playerStatus->encounteredNPC = npc; playerStatus->flags |= PS_FLAGS_HAS_CONVERSATION_NPC; if (playerStatus->pressedButtons & BUTTON_A) { close_status_menu(); gCurrentEncounter.hitType = ENCOUNTER_TRIGGER_CONVERSATION; enemy->encountered = ENCOUNTER_TRIGGER_CONVERSATION; encounterStatus->currentEncounter = encounter; encounterStatus->currentEnemy = enemy; encounterStatus->firstStrikeType = FIRST_STRIKE_PLAYER; return TRUE; } } return FALSE; } INCLUDE_ASM(s32, "1a1f0_len_5390", create_encounters); void init_encounters_ui(void) { } s32 is_starting_conversation(void) { s32 ret = gGameState == 3; if (gCurrentEncounter.hitType == 5) { ret = 1; } return ret; }