diff options
Diffstat (limited to 'src/battle_pike.c')
-rw-r--r-- | src/battle_pike.c | 1271 |
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; +} |