summaryrefslogtreecommitdiff
path: root/src/battle_pike.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/battle_pike.c')
-rw-r--r--src/battle_pike.c1271
1 files changed, 1271 insertions, 0 deletions
diff --git a/src/battle_pike.c b/src/battle_pike.c
new file mode 100644
index 000000000..a0a50d86e
--- /dev/null
+++ b/src/battle_pike.c
@@ -0,0 +1,1271 @@
+#include "global.h"
+#include "battle_pike.h"
+#include "event_data.h"
+#include "frontier_util.h"
+#include "fieldmap.h"
+#include "save.h"
+#include "battle.h"
+#include "random.h"
+#include "task.h"
+#include "battle_tower.h"
+#include "party_menu.h"
+#include "malloc.h"
+#include "palette.h"
+#include "script.h"
+#include "battle_setup.h"
+#include "constants/event_objects.h"
+#include "constants/battle_frontier.h"
+#include "constants/abilities.h"
+#include "constants/rgb.h"
+#include "constants/trainers.h"
+#include "constants/species.h"
+
+#define PIKE_ROOM_SINGLE_BATTLE 0
+#define PIKE_ROOM_HEAL_FULL 1
+#define PIKE_ROOM_NPC 2
+#define PIKE_ROOM_STATUS 3
+#define PIKE_ROOM_HEAL_PART 4
+#define PIKE_ROOM_WILD_MONS 5
+#define PIKE_ROOM_HARD_BATTLE 6
+#define PIKE_ROOM_DOUBLE_BATTLE 7
+#define PIKE_ROOM_BRAIN 8
+
+// For the room with a status effect.
+#define PIKE_STATUS_KIRLIA 0
+#define PIKE_STATUS_DUSCLOPS 1
+
+struct Unk0861231C
+{
+ u16 unk0;
+ u8 unk2;
+ u8 unk3;
+ u8 unk4;
+ u8 unk5;
+};
+
+struct PikeWildMon
+{
+ u16 species;
+ u8 levelDelta;
+ u16 moves[4];
+};
+
+extern const struct Unk0861231C gUnknown_0861231C[];
+extern const struct PikeWildMon *const *const gUnknown_08612314[2];
+extern const u16 gUnknown_086123E4[][6];
+extern const struct BattleFrontierTrainer gBattleFrontierTrainers[];
+
+// IWRAM bss
+static IWRAM_DATA u8 sRoomType;
+static IWRAM_DATA u8 sStatusMon;
+static IWRAM_DATA bool8 sUnknown_0300128E;
+static IWRAM_DATA u32 sStatusFlags;
+static IWRAM_DATA u8 sUnknown_03001294;
+
+// This file's functions.
+static void sub_81A705C(void);
+static void sub_81A7140(void);
+static void sub_81A7248(void);
+static void sub_81A73B8(void);
+static void sub_81A7070(void);
+static void sub_81A73EC(void);
+static void sub_81A7400(void);
+static void sub_81A740C(void);
+static void sub_81A7418(void);
+static void nullsub_76(void);
+static void nullsub_124(void);
+static void sub_81A7468(void);
+static void sub_81A74CC(void);
+static void sub_81A74E0(void);
+static void sub_81A7508(void);
+static void sub_81A7580(void);
+static void sub_81A8090(void);
+static void sub_81A80DC(void);
+static void sub_81A825C(void);
+static void sub_81A827C(void);
+static void sub_81A84B4(void);
+static void sub_81A84EC(void);
+static void sub_81A863C(void);
+static void sub_81A8658(void);
+static void sub_81A869C(void);
+static void sub_81A86C0(void);
+static void sub_81A8794(void);
+static void sub_81A87E8(void);
+static void sub_81A8830(void);
+static u8 GetNextRoomType(void);
+static void PrepareOneTrainer(bool8 difficult);
+static u16 sub_81A7B58(void);
+static void PrepareTwoTrainers(void);
+static void TryHealMons(u8 healCount);
+static void sub_81A7EE4(u8 taskId);
+static bool8 AtLeastTwoAliveMons(void);
+static u8 SpeciesToPikeMonId(u16 species);
+static bool8 CanEncounterWildMon(u8 monLevel);
+static u8 sub_81A8590(u8);
+static bool8 sub_81A7D8C(struct Task *task);
+static bool8 sub_81A7DE8(struct Task *task);
+
+// Const rom data.
+static const u8 gUnknown_086125DC[][4] =
+{
+ {0x23, 0x46, 0x23, 0x01},
+ {0x04, 0x09, 0x05, 0x00},
+ {0x15, 0x2a, 0x15, 0x01},
+ {0x1c, 0x38, 0x1c, 0x01},
+ {0x15, 0x2a, 0x15, 0x01},
+ {0x1c, 0x8c, 0x38, 0x01},
+ {0x15, 0x46, 0x23, 0x00},
+};
+
+static void (* const sBattlePikeFunctions[])(void) =
+{
+ sub_81A705C,
+ sub_81A7140,
+ sub_81A7248,
+ sub_81A73B8,
+ sub_81A7070,
+ sub_81A73EC,
+ sub_81A7400,
+ sub_81A740C,
+ sub_81A7418,
+ nullsub_76,
+ nullsub_124,
+ sub_81A7468,
+ sub_81A74CC,
+ sub_81A74E0,
+ sub_81A7508,
+ sub_81A7580,
+ sub_81A8090,
+ sub_81A80DC,
+ sub_81A825C,
+ sub_81A827C,
+ sub_81A84B4,
+ sub_81A84EC,
+ sub_81A863C,
+ sub_81A8658,
+ sub_81A869C,
+ sub_81A86C0,
+ sub_81A8794,
+ sub_81A87E8,
+ sub_81A8830
+};
+
+static const u8 gUnknown_0861266C[] = {3, 3, 1, 0, 0, 2, 2, 1, 4};
+
+static const u8 gUnknown_08612675[][3] =
+{
+ {2, 1, 0},
+ {2, 0, 1},
+ {1, 2, 0},
+ {1, 0, 2},
+ {0, 2, 1},
+ {0, 1, 2},
+};
+
+static bool8 (* const gUnknown_08612688[])(struct Task *) =
+{
+ sub_81A7D8C, sub_81A7DE8
+};
+
+static const u32 gUnknown_08612690[] = {0x400, 0x800};
+
+// code
+void CallBattlePikeFunction(void)
+{
+ sBattlePikeFunctions[gSpecialVar_0x8004]();
+}
+
+static void sub_81A705C(void)
+{
+ u8 roomType = GetNextRoomType();
+ sRoomType = roomType;
+}
+
+static void sub_81A7070(void)
+{
+ bool32 setPerson1, setPerson2;
+ u32 person1;
+ u16 person2;
+
+ VarSet(VAR_OBJ_GFX_ID_0, EVENT_OBJ_GFX_LINK_RECEPTIONIST);
+ VarSet(VAR_OBJ_GFX_ID_1, EVENT_OBJ_GFX_DUSCLOPS);
+ setPerson1 = TRUE;
+ setPerson2 = FALSE;
+ person1 = 0;
+ person2 = 0;
+
+ switch (sRoomType)
+ {
+ case PIKE_ROOM_SINGLE_BATTLE:
+ PrepareOneTrainer(FALSE);
+ setPerson1 = FALSE;
+ break;
+ case PIKE_ROOM_HEAL_FULL:
+ person1 = EVENT_OBJ_GFX_LINK_RECEPTIONIST;
+ break;
+ case PIKE_ROOM_NPC:
+ person1 = (u8)(sub_81A7B58());
+ break;
+ case PIKE_ROOM_STATUS:
+ person1 = EVENT_OBJ_GFX_GENTLEMAN;
+ if (sStatusMon == PIKE_STATUS_DUSCLOPS)
+ person2 = EVENT_OBJ_GFX_DUSCLOPS;
+ else
+ person2 = EVENT_OBJ_GFX_KIRLIA;
+ setPerson2 = TRUE;
+ break;
+ case PIKE_ROOM_HEAL_PART:
+ person1 = EVENT_OBJ_GFX_GENTLEMAN;
+ break;
+ case PIKE_ROOM_WILD_MONS:
+ setPerson1 = FALSE;
+ break;
+ case PIKE_ROOM_HARD_BATTLE:
+ PrepareOneTrainer(TRUE);
+ person2 = EVENT_OBJ_GFX_LINK_RECEPTIONIST;
+ setPerson1 = FALSE;
+ setPerson2 = TRUE;
+ break;
+ case PIKE_ROOM_DOUBLE_BATTLE:
+ PrepareTwoTrainers();
+ setPerson1 = FALSE;
+ break;
+ case PIKE_ROOM_BRAIN:
+ SetFrontierBrainEventObjGfx(FRONTIER_FACILITY_PIKE);
+ person2 = EVENT_OBJ_GFX_LINK_RECEPTIONIST;
+ setPerson1 = FALSE;
+ setPerson2 = TRUE;
+ break;
+ default:
+ return;
+ }
+
+ if (setPerson1 == TRUE)
+ VarSet(VAR_OBJ_GFX_ID_0, person1);
+ if (setPerson2 == TRUE)
+ VarSet(VAR_OBJ_GFX_ID_1, person2);
+}
+
+static void sub_81A7140(void)
+{
+ u32 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+
+ switch (gSpecialVar_0x8005)
+ {
+ case 0:
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.field_E02;
+ break;
+ case 1:
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.pikeWinStreaks[gSaveBlock2Ptr->frontier.lvlMode];
+ break;
+ case 2:
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.pikeRecordStreaks[gSaveBlock2Ptr->frontier.lvlMode];
+ break;
+ case 3:
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.pikeTotalStreaks[gSaveBlock2Ptr->frontier.lvlMode];
+ break;
+ case 4:
+ if (lvlMode != FRONTIER_LVL_50)
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.field_CDC & 0x800;
+ else
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.field_CDC & 0x400;
+ break;
+ }
+}
+
+static void sub_81A7248(void)
+{
+ u32 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+
+ switch (gSpecialVar_0x8005)
+ {
+ case 0:
+ gSaveBlock2Ptr->frontier.field_E02 = gSpecialVar_0x8006;
+ break;
+ case 1:
+ if (gSpecialVar_0x8006 <= 9999)
+ gSaveBlock2Ptr->frontier.pikeWinStreaks[gSaveBlock2Ptr->frontier.lvlMode] = gSpecialVar_0x8006;
+ break;
+ case 2:
+ if (gSpecialVar_0x8006 <= 9999 && gSaveBlock2Ptr->frontier.pikeRecordStreaks[gSaveBlock2Ptr->frontier.lvlMode] < gSpecialVar_0x8006)
+ gSaveBlock2Ptr->frontier.pikeRecordStreaks[gSaveBlock2Ptr->frontier.lvlMode] = gSpecialVar_0x8006;
+ break;
+ case 3:
+ if (gSpecialVar_0x8006 <= 9999)
+ gSaveBlock2Ptr->frontier.pikeTotalStreaks[gSaveBlock2Ptr->frontier.lvlMode] = gSpecialVar_0x8006;
+ break;
+ case 4:
+ if (lvlMode != FRONTIER_LVL_50)
+ {
+ if (gSpecialVar_0x8006)
+ gSaveBlock2Ptr->frontier.field_CDC |= 0x800;
+ else
+ gSaveBlock2Ptr->frontier.field_CDC &= ~(0x800);
+ }
+ else
+ {
+ if (gSpecialVar_0x8006)
+ gSaveBlock2Ptr->frontier.field_CDC |= 0x400;
+ else
+ gSaveBlock2Ptr->frontier.field_CDC &= ~(0x400);
+ }
+ break;
+ }
+}
+
+static void sub_81A73B8(void)
+{
+ if (gSaveBlock2Ptr->frontier.curChallengeBattleNum >= 15)
+ gSpecialVar_Result = TRUE;
+ else
+ gSpecialVar_Result = FALSE;
+}
+
+static void sub_81A73EC(void)
+{
+ gSpecialVar_Result = sRoomType;
+}
+
+static void sub_81A7400(void)
+{
+ sUnknown_0300128E = TRUE;
+}
+
+static void sub_81A740C(void)
+{
+ sUnknown_0300128E = FALSE;
+}
+
+static void sub_81A7418(void)
+{
+ gSaveBlock2Ptr->frontier.field_CA8 = gSpecialVar_0x8005;
+ VarSet(VAR_TEMP_0, 0);
+ gSaveBlock2Ptr->frontier.field_CA9_a = 1;
+ save_serialize_map();
+ TrySavingData(SAVE_LINK);
+}
+
+static void nullsub_76(void)
+{
+
+}
+
+static void nullsub_124(void)
+{
+
+}
+
+static void sub_81A7468(void)
+{
+ switch (sStatusFlags)
+ {
+ case STATUS1_FREEZE:
+ gSpecialVar_Result = 0;
+ break;
+ case STATUS1_BURN:
+ gSpecialVar_Result = 1;
+ break;
+ case STATUS1_TOXIC_POISON:
+ gSpecialVar_Result = 2;
+ break;
+ case STATUS1_PARALYSIS:
+ gSpecialVar_Result = 3;
+ break;
+ case STATUS1_SLEEP:
+ gSpecialVar_Result = 4;
+ break;
+ }
+}
+
+static void sub_81A74CC(void)
+{
+ gSpecialVar_Result = sStatusMon;
+}
+
+static void sub_81A74E0(void)
+{
+ u16 toHeal = (Random() % 2) + 1;
+ TryHealMons(toHeal);
+ gSpecialVar_Result = toHeal;
+}
+
+static void sub_81A7508(void)
+{
+ s32 id;
+
+ if (gSaveBlock2Ptr->frontier.curChallengeBattleNum <= 4)
+ id = gUnknown_0861231C[sUnknown_03001294].unk2;
+ else if (gSaveBlock2Ptr->frontier.curChallengeBattleNum <= 10)
+ id = gUnknown_0861231C[sUnknown_03001294].unk3;
+ else
+ id = gUnknown_0861231C[sUnknown_03001294].unk4;
+
+ FrontierSpeechToString(gUnknown_086123E4[id]);
+}
+
+static void sub_81A7580(void)
+{
+ CreateTask(sub_81A7EE4, 2);
+}
+
+static void HealMon(struct Pokemon *mon)
+{
+ u8 i;
+ u16 hp;
+ u8 ppBonuses;
+ u8 data[4];
+
+ for (i = 0; i < 4; i++)
+ data[i] = 0;
+
+ hp = GetMonData(mon, MON_DATA_MAX_HP);
+ data[0] = hp;
+ data[1] = hp >> 8;
+ SetMonData(mon, MON_DATA_HP, data);
+
+ ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES);
+ for (i = 0; i < 4; i++)
+ {
+ u16 move = GetMonData(mon, MON_DATA_MOVE1 + i);
+ data[0] = CalculatePPWithBonus(move, ppBonuses, i);
+ SetMonData(mon, MON_DATA_PP1 + i, data);
+ }
+
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ SetMonData(mon, MON_DATA_STATUS, data);
+}
+
+static bool8 DoesAbilityPreventStatus(struct Pokemon *mon, u32 status)
+{
+ u8 ability = GetMonAbility(mon);
+ bool8 ret = FALSE;
+
+ switch (status)
+ {
+ case STATUS1_FREEZE:
+ if (ability == ABILITY_MAGMA_ARMOR)
+ ret = TRUE;
+ break;
+ case STATUS1_BURN:
+ if (ability == ABILITY_WATER_VEIL)
+ ret = TRUE;
+ break;
+ case STATUS1_PARALYSIS:
+ if (ability == ABILITY_LIMBER)
+ ret = TRUE;
+ break;
+ case STATUS1_SLEEP:
+ if (ability == ABILITY_INSOMNIA || ability == ABILITY_VITAL_SPIRIT)
+ ret = TRUE;
+ break;
+ case STATUS1_TOXIC_POISON:
+ if (ability == ABILITY_IMMUNITY)
+ ret = TRUE;
+ break;
+ }
+ return ret;
+}
+
+static bool8 DoesTypePreventStatus(u16 species, u32 status)
+{
+ bool8 ret = FALSE;
+
+ switch (status)
+ {
+ case STATUS1_TOXIC_POISON:
+ if (gBaseStats[species].type1 == TYPE_STEEL || gBaseStats[species].type1 == TYPE_POISON
+ || gBaseStats[species].type2 == TYPE_STEEL || gBaseStats[species].type2 == TYPE_POISON)
+ ret = TRUE;
+ break;
+ case STATUS1_FREEZE:
+ if (gBaseStats[species].type1 == TYPE_ICE || gBaseStats[species].type2 == TYPE_ICE)
+ ret = TRUE;
+ break;
+ case STATUS1_PARALYSIS:
+ if (gBaseStats[species].type1 == TYPE_GROUND || gBaseStats[species].type1 == TYPE_ELECTRIC
+ || gBaseStats[species].type2 == TYPE_GROUND || gBaseStats[species].type2 == TYPE_ELECTRIC)
+ ret = TRUE;
+ break;
+ case STATUS1_BURN:
+ if (gBaseStats[species].type1 == TYPE_FIRE || gBaseStats[species].type2 == TYPE_FIRE)
+ ret = TRUE;
+ break;
+ case STATUS1_SLEEP:
+ break;
+ }
+ return ret;
+}
+
+static bool8 TryInflictRandomStatus(void)
+{
+ u8 j, i;
+ u8 count;
+ u8 indices[3];
+ u32 status;
+ u16 species;
+ bool8 statusChosen;
+ struct Pokemon *mon;
+
+ for (i = 0; i < 3; i++)
+ indices[i] = i;
+ for (j = 0; j < 10; j++)
+ {
+ u8 temp, id;
+
+ i = Random() % 3;
+ id = Random() % 3;
+ SWAP(indices[i], indices[id], temp);
+ }
+
+ if (gSaveBlock2Ptr->frontier.curChallengeBattleNum <= 4)
+ count = 1;
+ else if (gSaveBlock2Ptr->frontier.curChallengeBattleNum <= 9)
+ count = 2;
+ else
+ count = 3;
+
+ status = 0;
+ do
+ {
+ u8 rand;
+
+ statusChosen = FALSE;
+ rand = Random() % 100;
+
+ if (rand < 35)
+ sStatusFlags = STATUS1_TOXIC_POISON;
+ else if (rand < 60)
+ sStatusFlags = STATUS1_FREEZE;
+ else if (rand < 80)
+ sStatusFlags = STATUS1_PARALYSIS;
+ else if (rand < 90)
+ sStatusFlags = STATUS1_SLEEP;
+ else
+ sStatusFlags = STATUS1_BURN;
+
+ if (status != sStatusFlags)
+ {
+ status = sStatusFlags;
+ j = 0;
+ for (i = 0; i < 3; i++)
+ {
+ mon = &gPlayerParty[indices[i]];
+ if (pokemon_ailments_get_primary(GetMonData(mon, MON_DATA_STATUS)) == 0
+ && GetMonData(mon, MON_DATA_HP) != 0)
+ {
+ j++;
+ species = GetMonData(mon, MON_DATA_SPECIES);
+ if (!DoesTypePreventStatus(species, sStatusFlags))
+ {
+ statusChosen = TRUE;
+ break;
+ }
+ }
+ if (j == count)
+ break;
+ }
+ if (j == 0)
+ return FALSE;
+ }
+ } while (!statusChosen);
+
+ switch (sStatusFlags)
+ {
+ case STATUS1_FREEZE:
+ sStatusMon = PIKE_STATUS_DUSCLOPS;
+ break;
+ case STATUS1_BURN:
+ if (Random() % 2 != 0)
+ sStatusMon = PIKE_STATUS_DUSCLOPS;
+ else
+ sStatusMon = PIKE_STATUS_KIRLIA;
+ break;
+ case STATUS1_PARALYSIS:
+ case STATUS1_SLEEP:
+ case STATUS1_TOXIC_POISON:
+ default:
+ sStatusMon = PIKE_STATUS_KIRLIA;
+ break;
+ }
+
+ j = 0;
+ for (i = 0; i < 3; i++)
+ {
+ mon = &gPlayerParty[indices[i]];
+ if (pokemon_ailments_get_primary(GetMonData(mon, MON_DATA_STATUS)) == 0
+ && GetMonData(mon, MON_DATA_HP) != 0)
+ {
+ j++;
+ species = GetMonData(mon, MON_DATA_SPECIES);
+ if (!DoesAbilityPreventStatus(mon, sStatusFlags) && !DoesTypePreventStatus(species, sStatusFlags))
+ SetMonData(mon, MON_DATA_STATUS, &sStatusFlags);
+ }
+ if (j == count)
+ break;
+ }
+
+ return TRUE;
+}
+
+static bool8 AtLeastOneHealthyMon(void)
+{
+ u8 i;
+ u8 healthyMonsCount;
+ u8 count;
+
+ if (gSaveBlock2Ptr->frontier.curChallengeBattleNum <= 4)
+ count = 1;
+ else if (gSaveBlock2Ptr->frontier.curChallengeBattleNum <= 9)
+ count = 2;
+ else
+ count = 3;
+
+ healthyMonsCount = 0;
+ for (i = 0; i < 3; i++)
+ {
+ struct Pokemon *mon = &gPlayerParty[i];
+ if (pokemon_ailments_get_primary(GetMonData(mon, MON_DATA_STATUS)) == 0
+ && GetMonData(mon, MON_DATA_HP) != 0)
+ {
+ healthyMonsCount++;
+ }
+ if (healthyMonsCount == count)
+ break;
+ }
+
+ if (healthyMonsCount == 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static u8 GetNextRoomType(void)
+{
+ u8 sp[8];
+ u8 i;
+ u8 ret;
+ u8 var;
+ u8 count;
+ u8 *allocated;
+ u8 id;
+
+ if (gSaveBlock2Ptr->frontier.field_E10_2 == PIKE_ROOM_BRAIN)
+ return gSaveBlock2Ptr->frontier.field_E10_2;
+ if (gSpecialVar_0x8007 == gSaveBlock2Ptr->frontier.field_E10_1)
+ {
+ if (gSaveBlock2Ptr->frontier.field_E10_2 == PIKE_ROOM_STATUS)
+ TryInflictRandomStatus();
+ return gSaveBlock2Ptr->frontier.field_E10_2;
+ }
+
+ for (i = 0; i < 8; i++)
+ sp[i] = 0;
+
+ count = 8;
+ var = gUnknown_0861266C[gSaveBlock2Ptr->frontier.field_E10_2];
+ for (i = 0; i < 8; i++)
+ {
+ if (gUnknown_0861266C[i] == var)
+ {
+ sp[i] = 1;
+ count--;
+ }
+ }
+
+ if (sp[7] != 1 && !AtLeastTwoAliveMons())
+ {
+ sp[7] = 1;
+ count--;
+ }
+ if (sp[3] != 1 && !AtLeastOneHealthyMon())
+ {
+ sp[3] = 1;
+ count--;
+ }
+ if (gSaveBlock2Ptr->frontier.field_E10_3)
+ {
+ if (sp[1] != 1)
+ {
+ sp[1] = 1;
+ count--;
+ }
+ if (sp[4] != 1)
+ {
+ sp[4] = 1;
+ count--;
+ }
+ }
+
+ allocated = AllocZeroed(count);
+ id = 0;
+ for (i = 0; i < 8; i++)
+ {
+ if (sp[i] == 0)
+ allocated[id++] = i;
+ }
+
+ ret = allocated[Random() % count];
+ free(allocated);
+ if (ret == PIKE_ROOM_STATUS)
+ TryInflictRandomStatus();
+
+ return ret;
+}
+
+static u16 sub_81A7B58(void)
+{
+ sUnknown_03001294 = Random() % 25;
+ return gUnknown_0861231C[sUnknown_03001294].unk0;
+}
+
+static u8 sub_81A7B84(void)
+{
+ return sUnknown_0300128E;
+}
+
+bool32 TryGenerateBattlePikeWildMon(bool8 checkKeenEyeIntimidate)
+{
+ s32 i;
+ s32 monLevel;
+ u8 headerId = GetBattlePikeWildMonHeaderId();
+ u32 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+ const struct PikeWildMon *const *const wildMons = gUnknown_08612314[lvlMode];
+ u32 abilityBit;
+ s32 pikeMonId = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL);
+ pikeMonId = SpeciesToPikeMonId(pikeMonId);
+
+ if (gSaveBlock2Ptr->frontier.lvlMode != FRONTIER_LVL_50)
+ {
+ monLevel = GetHighestLevelInPlayerParty();
+ if (monLevel < 60)
+ {
+ monLevel = 60;
+ }
+ else
+ {
+ monLevel -= wildMons[headerId][pikeMonId].levelDelta;
+ if (monLevel < 60)
+ monLevel = 60;
+ }
+ }
+ else
+ {
+ monLevel = 50 - wildMons[headerId][pikeMonId].levelDelta;
+ }
+
+ if (checkKeenEyeIntimidate == TRUE && !CanEncounterWildMon(monLevel))
+ return FALSE;
+
+ SetMonData(&gEnemyParty[0],
+ MON_DATA_EXP,
+ &gExperienceTables[gBaseStats[wildMons[headerId][pikeMonId].species].growthRate][monLevel]);
+
+ if (gBaseStats[wildMons[headerId][pikeMonId].species].ability2)
+ abilityBit = Random() % 2;
+ else
+ abilityBit = 0;
+ SetMonData(&gEnemyParty[0], MON_DATA_ALT_ABILITY, &abilityBit);
+ for (i = 0; i < 4; i++)
+ SetMonMoveSlot(&gEnemyParty[0], wildMons[headerId][pikeMonId].moves[i], i);
+
+ CalculateMonStats(&gEnemyParty[0]);
+ return TRUE;
+}
+
+u8 GetBattlePikeWildMonHeaderId(void)
+{
+ u8 headerId;
+ u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+ u16 winStreak = gSaveBlock2Ptr->frontier.pikeWinStreaks[lvlMode];
+
+ if (winStreak <= 280)
+ headerId = 0;
+ else if (winStreak <= 560)
+ headerId = 1;
+ else if (winStreak <= 840)
+ headerId = 2;
+ else
+ headerId = 3;
+
+ return headerId;
+}
+
+static void sub_81A7D54(u8 taskId)
+{
+ while (gUnknown_08612688[gTasks[taskId].data[0]](&gTasks[taskId]));
+}
+
+static bool8 sub_81A7D8C(struct Task *task)
+{
+ if (task->data[6] == 0 || --task->data[6] == 0)
+ {
+ task->data[6] = task->data[1];
+ task->data[7] += task->data[4];
+ if (task->data[7] > 16)
+ task->data[7] = 16;
+ BlendPalettes(0xFFFFFFFF, task->data[7], RGB(11, 11, 11));
+ }
+
+ if (task->data[7] >= 16)
+ {
+ task->data[0]++;
+ task->data[6] = task->data[2];
+ }
+ return FALSE;
+}
+
+static bool8 sub_81A7DE8(struct Task *task)
+{
+ if (task->data[6] == 0 || --task->data[6] == 0)
+ {
+ task->data[6] = task->data[2];
+ task->data[7] -= task->data[5];
+ if (task->data[7] < 0)
+ task->data[7] = 0;
+ BlendPalettes(0xFFFFFFFF, task->data[7], RGB(11, 11, 11));
+ }
+
+ if (task->data[7] == 0)
+ {
+ if (--task->data[3] == 0)
+ {
+ DestroyTask(FindTaskIdByFunc(sub_81A7D54));
+ }
+ else
+ {
+ task->data[6] = task->data[1];
+ task->data[0] = 0;
+ }
+ }
+ return FALSE;
+}
+
+static void sub_81A7E60(s16 a0, s16 a1, s16 a2, s16 a3, s16 a4)
+{
+ u8 taskId = CreateTask(sub_81A7D54, 3);
+
+ gTasks[taskId].data[1] = a0;
+ gTasks[taskId].data[2] = a1;
+ gTasks[taskId].data[3] = a2;
+ gTasks[taskId].data[4] = a3;
+ gTasks[taskId].data[5] = a4;
+ gTasks[taskId].data[6] = a0;
+}
+
+static bool8 sub_81A7EC4(void)
+{
+ if (FindTaskIdByFunc(sub_81A7D54) == 0xFF)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static void sub_81A7EE4(u8 taskId)
+{
+ if (gTasks[taskId].data[0] == 0)
+ {
+ gTasks[taskId].data[0]++;
+ sub_81A7E60(0, 0, 3, 2, 2);
+ }
+ else
+ {
+ if (sub_81A7EC4())
+ {
+ EnableBothScriptContexts();
+ DestroyTask(taskId);
+ }
+ }
+}
+
+static void TryHealMons(u8 healCount)
+{
+ u8 j, i, k;
+ u8 indices[3];
+
+ if (healCount == 0)
+ return;
+
+ for (i = 0; i < 3; i++)
+ indices[i] = i;
+ for (k = 0; k < 10; k++)
+ {
+ u8 temp;
+
+ i = Random() % 3;
+ j = Random() % 3;
+ SWAP(indices[i], indices[j], temp);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ bool32 canBeHealed = FALSE;
+ struct Pokemon *mon = &gPlayerParty[indices[i]];
+ u16 curr = GetMonData(mon, MON_DATA_HP);
+ u16 max = GetMonData(mon, MON_DATA_MAX_HP);
+ if (curr < max)
+ {
+ canBeHealed = TRUE;
+ }
+ else if (pokemon_ailments_get_primary(GetMonData(mon, MON_DATA_STATUS)) != 0)
+ {
+ canBeHealed = TRUE;
+ }
+ else
+ {
+ u8 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES);
+ for (j = 0; j < 4; j++)
+ {
+ u16 move = GetMonData(mon, MON_DATA_MOVE1 + j);
+ max = CalculatePPWithBonus(move, ppBonuses, j);
+ curr = GetMonData(mon, MON_DATA_PP1 + j);
+ if (curr < max)
+ {
+ canBeHealed = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (canBeHealed == TRUE)
+ {
+ HealMon(&gPlayerParty[indices[i]]);
+ if (--healCount == 0)
+ break;
+ }
+ }
+}
+
+static void sub_81A8090(void)
+{
+ gSpecialVar_Result = InBattlePike();
+}
+
+bool8 InBattlePike(void)
+{
+ return (gMapHeader.mapLayoutId == 351 || gMapHeader.mapLayoutId == 352
+ || gMapHeader.mapLayoutId == 358 || gMapHeader.mapLayoutId == 359);
+}
+
+static void sub_81A80DC(void)
+{
+ u8 i, count, id;
+ u8 *allocated;
+
+ gSpecialVar_Result = 0;
+ if (sub_81A8590(1))
+ {
+ gSpecialVar_Result = 1;
+ gSaveBlock2Ptr->frontier.field_E10_1 = Random() % 6;
+ gSaveBlock2Ptr->frontier.field_E10_2 = PIKE_ROOM_BRAIN;
+ }
+ else
+ {
+ gSaveBlock2Ptr->frontier.field_E10_1 = Random() % 3;
+ if (gSaveBlock2Ptr->frontier.field_E10_3)
+ count = 6;
+ else
+ count = 8;
+
+ allocated = AllocZeroed(count);
+ for (i = 0, id = 0; i < count; i++)
+ {
+ if (gSaveBlock2Ptr->frontier.field_E10_3)
+ {
+ if (i != PIKE_ROOM_HEAL_FULL && i != PIKE_ROOM_HEAL_PART)
+ allocated[id++] = i;
+ }
+ else
+ {
+ allocated[i] = i;
+ }
+ }
+ gSaveBlock2Ptr->frontier.field_E10_2 = allocated[Random() % count];
+ free(allocated);
+ if (gSaveBlock2Ptr->frontier.field_E10_2 == PIKE_ROOM_STATUS && !AtLeastOneHealthyMon())
+ gSaveBlock2Ptr->frontier.field_E10_2 = PIKE_ROOM_NPC;
+ if (gSaveBlock2Ptr->frontier.field_E10_2 == PIKE_ROOM_DOUBLE_BATTLE && !AtLeastTwoAliveMons())
+ gSaveBlock2Ptr->frontier.field_E10_2 = PIKE_ROOM_NPC;
+ }
+}
+
+static void sub_81A825C(void)
+{
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.field_E10_1;
+}
+
+static void sub_81A827C(void)
+{
+ gSpecialVar_Result = gUnknown_0861266C[gSaveBlock2Ptr->frontier.field_E10_2];
+}
+
+static void PrepareOneTrainer(bool8 difficult)
+{
+ s32 i;
+ u8 lvlMode;
+ u8 battleNum;
+ u16 challengeNum;
+ u16 trainerId;
+
+ if (!difficult)
+ battleNum = 1;
+ else
+ battleNum = 6;
+
+ lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+ challengeNum = gSaveBlock2Ptr->frontier.pikeWinStreaks[lvlMode] / 14;
+ do
+ {
+ trainerId = sub_8162548(challengeNum, battleNum);
+ for (i = 0; i < gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1; i++)
+ {
+ if (gSaveBlock2Ptr->frontier.field_CB4[i] == trainerId)
+ break;
+ }
+ } while (i != gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1);
+
+ gTrainerBattleOpponent_A = trainerId;
+ gFacilityTrainers = gBattleFrontierTrainers;
+ SetBattleFacilityTrainerGfxId(gTrainerBattleOpponent_A, 0);
+ if (gSaveBlock2Ptr->frontier.curChallengeBattleNum < 14)
+ gSaveBlock2Ptr->frontier.field_CB4[gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1] = gTrainerBattleOpponent_A;
+}
+
+static void PrepareTwoTrainers(void)
+{
+ s32 i;
+ u16 trainerId;
+ u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+ u16 challengeNum = gSaveBlock2Ptr->frontier.pikeWinStreaks[lvlMode] / 14;
+
+ gFacilityTrainers = gBattleFrontierTrainers;
+ do
+ {
+ trainerId = sub_8162548(challengeNum, 1);
+ for (i = 0; i < gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1; i++)
+ {
+ if (gSaveBlock2Ptr->frontier.field_CB4[i] == trainerId)
+ break;
+ }
+ } while (i != gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1);
+
+ gTrainerBattleOpponent_A = trainerId;
+ SetBattleFacilityTrainerGfxId(gTrainerBattleOpponent_A, 0);
+ if (gSaveBlock2Ptr->frontier.curChallengeBattleNum <= 14)
+ gSaveBlock2Ptr->frontier.field_CB4[gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1] = gTrainerBattleOpponent_A;
+
+ do
+ {
+ trainerId = sub_8162548(challengeNum, 1);
+ for (i = 0; i < gSaveBlock2Ptr->frontier.curChallengeBattleNum; i++)
+ {
+ if (gSaveBlock2Ptr->frontier.field_CB4[i] == trainerId)
+ break;
+ }
+ } while (i != gSaveBlock2Ptr->frontier.curChallengeBattleNum);
+
+ gTrainerBattleOpponent_B = trainerId;
+ SetBattleFacilityTrainerGfxId(gTrainerBattleOpponent_B, 1);
+ if (gSaveBlock2Ptr->frontier.curChallengeBattleNum < 14)
+ gSaveBlock2Ptr->frontier.field_CB4[gSaveBlock2Ptr->frontier.curChallengeBattleNum - 2] = gTrainerBattleOpponent_B;
+}
+
+static void sub_81A84B4(void)
+{
+ u8 i;
+
+ for (i = 0; i < 14; i++)
+ gSaveBlock2Ptr->frontier.field_CB4[i] |= 0xFFFF;
+}
+
+static void sub_81A84EC(void)
+{
+ if (gSpecialVar_0x8005 == 0)
+ {
+ if (gTrainerBattleOpponent_A < TRAINER_RECORD_MIXING_FRIEND)
+ FrontierSpeechToString(gFacilityTrainers[gTrainerBattleOpponent_A].speechBefore);
+ }
+ else if (gSpecialVar_0x8005 == 1)
+ {
+ if (gTrainerBattleOpponent_B < TRAINER_RECORD_MIXING_FRIEND)
+ FrontierSpeechToString(gFacilityTrainers[gTrainerBattleOpponent_B].speechBefore);
+ }
+}
+
+static bool8 AtLeastTwoAliveMons(void)
+{
+ struct Pokemon *mon;
+ u8 i, countDead;
+
+ mon = &gPlayerParty[0];
+ countDead = 0;
+ for (i = 0; i < 3; i++, mon++)
+ {
+ if (GetMonData(mon, MON_DATA_HP) == 0)
+ countDead++;
+ }
+
+ if (countDead >= 2)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static u8 sub_81A8590(u8 arg0)
+{
+ u8 symbolsCount;
+
+ u8 var = 5;
+ u8 ret = 0;
+ u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+ u16 wins = gSaveBlock2Ptr->frontier.pikeWinStreaks[lvlMode];
+ wins += arg0;
+ symbolsCount = GetPlayerSymbolCountForFacility(FRONTIER_FACILITY_PIKE);
+
+ switch (symbolsCount)
+ {
+ case 0:
+ case 1:
+ if (wins == gUnknown_086125DC[var][symbolsCount] - gUnknown_086125DC[var][3])
+ ret = symbolsCount + 1;
+ break;
+ case 2:
+ default:
+ if (wins == gUnknown_086125DC[var][0] - gUnknown_086125DC[var][3])
+ ret = 3;
+ else if (wins == gUnknown_086125DC[var][1] - gUnknown_086125DC[var][3]
+ || (wins > gUnknown_086125DC[var][1]
+ && (wins - gUnknown_086125DC[var][1] + gUnknown_086125DC[var][3]) % gUnknown_086125DC[var][2] == 0))
+ ret = 4;
+ break;
+ }
+
+ return ret;
+}
+
+static void sub_81A863C(void)
+{
+ gSpecialVar_Result = sub_81A8590(0);
+}
+
+static void sub_81A8658(void)
+{
+ u8 toHealCount = gUnknown_08612675[gSaveBlock2Ptr->frontier.field_E10_1][gSpecialVar_0x8007];
+
+ TryHealMons(toHealCount);
+ gSpecialVar_Result = toHealCount;
+}
+
+static void sub_81A869C(void)
+{
+ gSaveBlock2Ptr->frontier.field_E10_3 = gSpecialVar_0x8005;
+}
+
+static void sub_81A86C0(void)
+{
+ u8 i, j;
+
+ gSpecialVar_Result = TRUE;
+ for (i = 0; i < 3; i++)
+ {
+ bool32 canBeHealed = FALSE;
+ struct Pokemon *mon = &gPlayerParty[i];
+ u16 curr = GetMonData(mon, MON_DATA_HP);
+ u16 max = GetMonData(mon, MON_DATA_MAX_HP);
+ if (curr >= max && pokemon_ailments_get_primary(GetMonData(mon, MON_DATA_STATUS)) == 0)
+ {
+ u8 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES);
+ for (j = 0; j < 4; j++)
+ {
+ u16 move = GetMonData(mon, MON_DATA_MOVE1 + j);
+ max = CalculatePPWithBonus(move, ppBonuses, j);
+ curr = GetMonData(mon, MON_DATA_PP1 + j);
+ if (curr < max)
+ {
+ canBeHealed = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ canBeHealed = TRUE;
+ }
+
+ if (canBeHealed == TRUE)
+ {
+ gSpecialVar_Result = FALSE;
+ break;
+ }
+ }
+}
+
+static void sub_81A8794(void)
+{
+ u8 i;
+
+ for (i = 0; i < 3; i++)
+ {
+ s32 heldItem = GetMonData(&gSaveBlock1Ptr->playerParty[gSaveBlock2Ptr->frontier.selectedPartyMons[i] - 1],
+ MON_DATA_HELD_ITEM);
+ gSaveBlock2Ptr->frontier.field_E12[i] = heldItem;
+ }
+}
+
+static void sub_81A87E8(void)
+{
+ u8 i;
+
+ for (i = 0; i < 3; i++)
+ {
+ SetMonData(&gPlayerParty[gSaveBlock2Ptr->frontier.selectedPartyMons[i] - 1],
+ MON_DATA_HELD_ITEM,
+ &gSaveBlock2Ptr->frontier.field_E12[i]);
+ }
+}
+
+static void sub_81A8830(void)
+{
+ u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
+
+ gSaveBlock2Ptr->frontier.field_CA8 = 0;
+ gSaveBlock2Ptr->frontier.curChallengeBattleNum = 0;
+ gSaveBlock2Ptr->frontier.field_CA9_a = 0;
+ if (!(gSaveBlock2Ptr->frontier.field_CDC & gUnknown_08612690[lvlMode]))
+ gSaveBlock2Ptr->frontier.pikeWinStreaks[lvlMode] = 0;
+
+ gTrainerBattleOpponent_A = 0;
+ gBattleOutcome = 0;
+}
+
+static bool8 CanEncounterWildMon(u8 enemyMonLevel)
+{
+ if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_BIT3))
+ {
+ u8 monAbility = GetMonAbility(&gPlayerParty[0]);
+ if (monAbility == ABILITY_KEEN_EYE || monAbility == ABILITY_INTIMIDATE)
+ {
+ u8 playerMonLevel = GetMonData(&gPlayerParty[0], MON_DATA_LEVEL);
+ if (playerMonLevel > 5 && enemyMonLevel <= playerMonLevel - 5 && Random() % 2 == 0)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static u8 SpeciesToPikeMonId(u16 species)
+{
+ u8 ret;
+
+ if (species == SPECIES_SEVIPER)
+ ret = 0;
+ else if (species == SPECIES_MILOTIC)
+ ret = 1;
+ else
+ ret = 2;
+
+ return ret;
+}