summaryrefslogtreecommitdiff
path: root/src/battle_tower.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/battle_tower.c')
-rw-r--r--src/battle_tower.c1303
1 files changed, 1296 insertions, 7 deletions
diff --git a/src/battle_tower.c b/src/battle_tower.c
index feab13d69..dfbef8fe5 100644
--- a/src/battle_tower.c
+++ b/src/battle_tower.c
@@ -1,13 +1,59 @@
#include "global.h"
#include "battle_tower.h"
+#include "random.h"
+#include "text.h"
+#include "event_data.h"
+#include "string_util.h"
+#include "battle_message.h"
+#include "data.h"
+#include "pokedex.h"
+#include "overworld.h"
+#include "battle_transition.h"
+#include "easy_chat.h"
+#include "battle_setup.h"
+#include "battle_main.h"
+#include "task.h"
+#include "battle.h"
+#include "party_menu.h"
+#include "new_game.h"
+#include "save.h"
+#include "item.h"
+#include "script_pokemon_util_80A0058.h"
#include "constants/species.h"
#include "constants/items.h"
#include "constants/moves.h"
#include "constants/pokemon.h"
+#include "constants/vars.h"
+#include "constants/map_objects.h"
+
+static EWRAM_DATA u16 sSpecialVar_0x8004_Copy = 0;
+
+#define TakeBravoTrainerBattleTowerOffTheAir()
+#define ewram160FB (*((u8 *)&gBattleStruct->field_DA))
+
+static void ResetBattleTowerStreak(u8 levelType);
+static void SetBattleTowerTrainerGfxId(u8 trainerClass);
+static void CheckMonBattleTowerBanlist(u16 species, u16 heldItem, u16 hp, u8 battleTowerLevelType, u8 monLevel, u16 *validPartySpecies, u16 *validPartyHeldItems, u8 *numValid);
+static void SaveCurrentWinStreak(void);
+static void ValidateBattleTowerRecordChecksums(void);
+static void SetBattleTowerRecordChecksum(struct BattleTowerRecord * record);
+static void ClearBattleTowerRecord(struct BattleTowerRecord * record);
+static void PopulateBravoTrainerBattleTowerLostData(void);
+static u16 GetCurrentBattleTowerWinStreak(u8 levelType);
+static void SetEReaderTrainerChecksum(struct BattleTowerEReaderTrainer * eReaderTrainer);
+static void PrintEReaderTrainerFarewellMessage(void);
+
+const u8 unref_83FFAAC[] = {
+ 0x05, 0x04, 0x01, 0x10, 0x04, 0x02, 0x05, 0x06,
+ 0x03, 0x10, 0x06, 0x04, 0x00, 0x01, 0x02, 0x03,
+ 0x00, 0x02, 0x03
+};
+
+const u8 unref_83FFABF[] = _("100");
#include "data/battle_tower/trainers.h"
-const u16 sBattleTowerHeldItems[] = {
+static const u16 sBattleTowerHeldItems[] = {
ITEM_NONE,
ITEM_KINGS_ROCK,
ITEM_SITRUS_BERRY,
@@ -76,22 +122,22 @@ const u16 sBattleTowerHeldItems[] = {
#include "data/battle_tower/level_50_mons.h"
#include "data/battle_tower/level_100_mons.h"
-const u8 sMaleTrainerClasses[] =
+static const u8 sMaleTrainerClasses[] =
{
};
-const u8 sFemaleTrainerClasses[] =
+static const u8 sFemaleTrainerClasses[] =
{
};
-const u8 sMaleTrainerGfx[] =
+static const u8 sMaleTrainerGfx[] =
{
};
-const u8 sFemaleTrainerGfx[] =
+static const u8 sFemaleTrainerGfx[] =
{
};
@@ -110,7 +156,7 @@ const u16 gBattleTowerBannedSpecies[] = {
0xFFFF
};
-const u16 sShortStreakPrizes[] = {
+static const u16 sShortStreakPrizes[] = {
ITEM_HP_UP,
ITEM_PROTEIN,
ITEM_IRON,
@@ -119,7 +165,7 @@ const u16 sShortStreakPrizes[] = {
ITEM_ZINC
};
-const u16 sLongStreakPrizes[] = {
+static const u16 sLongStreakPrizes[] = {
ITEM_BRIGHT_POWDER,
ITEM_WHITE_HERB,
ITEM_QUICK_CLAW,
@@ -131,3 +177,1246 @@ const u16 sLongStreakPrizes[] = {
ITEM_CHOICE_BAND
};
+void ScrSpecial_BattleTowerMapScript2(void)
+{
+ u8 count = 0;
+ s32 levelType;
+
+ for (levelType = 0; levelType < 2; levelType++)
+ {
+ switch (gSaveBlock2Ptr->battleTower.var_4AE[levelType])
+ {
+ default:
+ case 0:
+ ResetBattleTowerStreak(levelType);
+ if (count == 0)
+ VarSet(VAR_0x4000, 5);
+ break;
+ case 1:
+ ResetBattleTowerStreak(levelType);
+ VarSet(VAR_0x4000, BTSPECIAL_RESULT_SAVE_SCUM);
+ count++;
+ break;
+ case 3:
+ break;
+ case 4:
+ VarSet(VAR_0x4000, BTSPECIAL_RESULT_WON7);
+ count++;
+ break;
+ case 5:
+ VarSet(VAR_0x4000, BTSPECIAL_RESULT_LOST);
+ count++;
+ break;
+ case 6:
+ break;
+ case 2:
+ VarSet(VAR_0x4000, BTSPECIAL_RESULT_QUICKSAVE);
+ count++;
+ break;
+ }
+ }
+ if (gSaveBlock2Ptr->battleTower.var_4AE[0] == 3 && gSaveBlock2Ptr->battleTower.var_4AE[1] == 3)
+ VarSet(VAR_0x4000, BTSPECIAL_RESULT_INACTIVE);
+ ValidateBattleTowerRecordChecksums();
+}
+
+static void ResetBattleTowerStreak(u8 levelType)
+{
+ gSaveBlock2Ptr->battleTower.var_4AE[levelType] = 0;
+ gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] = 1;
+ gSaveBlock2Ptr->battleTower.curStreakChallengesNum[levelType] = 1;
+}
+
+static bool8 ShouldBattleEReaderTrainer(u8 levelType, u16 winStreak)
+{
+ u8 trainerTeamLevel;
+ u8 monLevel;
+ s32 i;
+ u16 validPartySpecies[6];
+ u16 validPartyHeldItems[6];
+ u8 numValid;
+
+ numValid = 0;
+
+ ValidateEReaderTrainer();
+
+ if (gSpecialVar_Result != 0 || gSaveBlock2Ptr->battleTower.ereaderTrainer.winStreak != winStreak)
+ return FALSE;
+
+ if (levelType != 0)
+ trainerTeamLevel = 100;
+ else
+ trainerTeamLevel = 50;
+
+ for (i = 0; i < 3; i++)
+ {
+ monLevel = gSaveBlock2Ptr->battleTower.ereaderTrainer.party[i].level;
+ if (gSaveBlock2Ptr->battleTower.ereaderTrainer.party[i].level != trainerTeamLevel)
+ return FALSE;
+
+ CheckMonBattleTowerBanlist(
+ gSaveBlock2Ptr->battleTower.ereaderTrainer.party[i].species,
+ gSaveBlock2Ptr->battleTower.ereaderTrainer.party[i].heldItem,
+ 1,
+ levelType,
+ monLevel,
+ validPartySpecies,
+ validPartyHeldItems,
+ &numValid);
+ }
+
+ return (numValid == 3);
+}
+
+static bool8 ChooseSpecialBattleTowerTrainer(void)
+{
+ s32 recordIndex, i;
+ u8 battleTowerLevelType;
+ u16 winStreak;
+ bool8 retVal;
+ s32 numCandidates;
+ u32 trainerIds[5];
+
+ numCandidates = 0;
+ battleTowerLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ winStreak = GetCurrentBattleTowerWinStreak(battleTowerLevelType);
+ if (ShouldBattleEReaderTrainer(battleTowerLevelType, winStreak))
+ {
+ gSaveBlock2Ptr->battleTower.battleTowerTrainerId = BATTLE_TOWER_EREADER_TRAINER_ID;
+ retVal = TRUE;
+ }
+ else
+ {
+ // Check if one of the battle tower trainers from record mixing should be the next trainer.
+ for (recordIndex = 0; recordIndex < 5; recordIndex++)
+ {
+ struct BattleTowerRecord *record = &gSaveBlock2Ptr->battleTower.records[recordIndex];
+ u32 recordHasData = 0;
+ u32 checksum = 0;
+
+ for (i = 0; i < sizeof(struct BattleTowerRecord) / sizeof(u32) - 1; i++)
+ {
+ recordHasData |= ((u32 *) record)[i];
+ checksum += ((u32 *) record)[i];
+ }
+
+ if (gSaveBlock2Ptr->battleTower.records[recordIndex].winStreak == winStreak
+ && gSaveBlock2Ptr->battleTower.records[recordIndex].battleTowerLevelType == battleTowerLevelType
+ && recordHasData
+ && gSaveBlock2Ptr->battleTower.records[recordIndex].checksum == checksum)
+ {
+ trainerIds[numCandidates] = recordIndex;
+ numCandidates++;
+ }
+ }
+
+ if (numCandidates == 0)
+ {
+ retVal = FALSE;
+ }
+ else
+ {
+ gSaveBlock2Ptr->battleTower.battleTowerTrainerId =
+ trainerIds[Random() % numCandidates] + BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID;
+ retVal = TRUE;
+ }
+ }
+ return retVal;
+}
+
+void ChooseNextBattleTowerTrainer(void)
+{
+ int i;
+ u16 trainerId;
+ bool8 levelType;
+
+ levelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+ if (ChooseSpecialBattleTowerTrainer())
+ {
+ SetBattleTowerTrainerGfxId(gSaveBlock2Ptr->battleTower.battleTowerTrainerId);
+ gSaveBlock2Ptr->battleTower.battledTrainerIds[gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1] = gSaveBlock2Ptr->battleTower.battleTowerTrainerId;
+ return;
+ }
+
+ if (gSaveBlock2Ptr->battleTower.curStreakChallengesNum[levelType] <= 7)
+ {
+ if (gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] == 7)
+ {
+ do
+ {
+ trainerId = ((Random() & 0xFF) * 5) >> 7;
+ trainerId += (gSaveBlock2Ptr->battleTower.curStreakChallengesNum[levelType] - 1) * 10 + 20;
+
+ // Ensure trainer wasn't previously fought in this challenge.
+ for (i = 0; i < gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1 && gSaveBlock2Ptr->battleTower.battledTrainerIds[i] != trainerId; i++);
+ }
+ while (i != gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1);
+ gSaveBlock2Ptr->battleTower.battleTowerTrainerId = trainerId;
+ }
+ else
+ {
+ do
+ {
+ trainerId = (((Random() & 0xFF) * 5) >> 6);
+ trainerId += (gSaveBlock2Ptr->battleTower.curStreakChallengesNum[levelType] - 1) * 10;
+
+ // Ensure trainer wasn't previously fought in this challenge.
+ for (i = 0; i < gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1 && gSaveBlock2Ptr->battleTower.battledTrainerIds[i] != trainerId; i++);
+ }
+ while (i != gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1);
+ gSaveBlock2Ptr->battleTower.battleTowerTrainerId = trainerId;
+ }
+ }
+ else
+ {
+ do
+ {
+ trainerId = (((Random() & 0xFF) * 30) >> 8) + 70;
+
+ // Ensure trainer wasn't previously fought in this challenge.
+ for (i = 0; i < gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1 && gSaveBlock2Ptr->battleTower.battledTrainerIds[i] != trainerId; i++);
+ }
+ while (i != gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1);
+ gSaveBlock2Ptr->battleTower.battleTowerTrainerId = trainerId;
+ }
+
+ SetBattleTowerTrainerGfxId(gSaveBlock2Ptr->battleTower.battleTowerTrainerId);
+ // Don't bother saving this trainer, since it's the last one in the challenge.
+ if (gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] < 7)
+ gSaveBlock2Ptr->battleTower.battledTrainerIds[gSaveBlock2Ptr->battleTower.curChallengeBattleNum[levelType] - 1] = gSaveBlock2Ptr->battleTower.battleTowerTrainerId;
+}
+
+static void SetBattleTowerTrainerGfxId(u8 trainerClass)
+{
+ VarSet(VAR_OBJ_GFX_ID_0, MAP_OBJ_GFX_YOUNGSTER);
+}
+
+void SetEReaderTrainerGfxId(void)
+{
+ SetBattleTowerTrainerGfxId(BATTLE_TOWER_EREADER_TRAINER_ID);
+}
+
+// Unreferenced; formerly used by Record Mixing in R/S
+static void UpdateOrInsertReceivedBattleTowerRecord(struct BattleTowerRecord * record0)
+{
+ s32 i;
+ s32 j;
+ s32 k;
+ s32 l = 0;
+ struct BattleTowerRecord * record = record0;
+
+ u16 winStreaks[6];
+ u16 indices[6];
+
+ for (i = 0; i < 5; i++)
+ {
+ k = 0;
+ for (j = 0; j < 4; j++)
+ {
+ if (gSaveBlock2Ptr->battleTower.records[i].trainerId[j] != record->trainerId[j])
+ break;
+ }
+ if (j == 4)
+ {
+ for (k = 0; k < 7; k++)
+ {
+ if (gSaveBlock2Ptr->battleTower.records[i].name[j] != record->name[j])
+ break;
+ if (record->name[j] == EOS)
+ {
+ k = 7;
+ break;
+ }
+ }
+ }
+ if (k == 7)
+ break;
+ }
+
+ if (i < 5)
+ {
+ gSaveBlock2Ptr->battleTower.records[i] = *record;
+ return;
+ }
+
+ for (i = 0; i < 5; i++)
+ {
+ if (gSaveBlock2Ptr->battleTower.records[i].winStreak == 0)
+ break;
+ }
+
+ if (i < 5)
+ {
+ gSaveBlock2Ptr->battleTower.records[i] = *record;
+ return;
+ }
+
+ winStreaks[0] = gSaveBlock2Ptr->battleTower.records[0].winStreak;
+ indices[0] = 0;
+ l++;
+
+ for (i = 1; i < 5; i++)
+ {
+ for (j = 0; j < l; j++)
+ {
+ if (gSaveBlock2Ptr->battleTower.records[i].winStreak < winStreaks[j])
+ {
+ j = 0;
+ l = 1;
+ winStreaks[0] = gSaveBlock2Ptr->battleTower.records[i].winStreak;
+ indices[0] = i;
+ break;
+ }
+ if (gSaveBlock2Ptr->battleTower.records[i].winStreak > winStreaks[j])
+ break;
+ }
+ if (j == l)
+ {
+ winStreaks[l] = gSaveBlock2Ptr->battleTower.records[i].winStreak;
+ indices[l] = i;
+ l++;
+ }
+ }
+ i = Random() % l;
+ gSaveBlock2Ptr->battleTower.records[indices[i]] = *record;
+}
+
+u8 GetBattleTowerTrainerFrontSpriteId(void)
+{
+ if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
+ {
+ return gFacilityClassToPicIndex[gSaveBlock2Ptr->battleTower.ereaderTrainer.trainerClass];
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID)
+ {
+ return gFacilityClassToPicIndex[gBattleTowerTrainers[gSaveBlock2Ptr->battleTower.battleTowerTrainerId].trainerClass];
+ }
+ else
+ {
+ return gFacilityClassToPicIndex[gSaveBlock2Ptr->battleTower.records[gSaveBlock2Ptr->battleTower.battleTowerTrainerId - BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID].trainerClass];
+ }
+}
+
+u8 GetBattleTowerTrainerClassNameId(void)
+{
+ if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
+ {
+ return gFacilityClassToTrainerClass[gSaveBlock2Ptr->battleTower.ereaderTrainer.trainerClass];
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId >= BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID)
+ {
+ return gFacilityClassToTrainerClass[gSaveBlock2Ptr->battleTower.records[gSaveBlock2Ptr->battleTower.battleTowerTrainerId - BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID].trainerClass];
+ }
+ else
+ {
+ return gFacilityClassToTrainerClass[gBattleTowerTrainers[gSaveBlock2Ptr->battleTower.battleTowerTrainerId].trainerClass];
+ }
+}
+
+void GetBattleTowerTrainerName(u8 *dest)
+{
+ s32 i;
+ if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
+ {
+ for (i = 0; i < 7; i++)
+ dest[i] = gSaveBlock2Ptr->battleTower.ereaderTrainer.name[i];
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID)
+ {
+ for (i = 0; i < 3; i++)
+ dest[i] = gBattleTowerTrainers[gSaveBlock2Ptr->battleTower.battleTowerTrainerId].name[i];
+ }
+ else
+ {
+ for (i = 0; i < 7; i++)
+ dest[i] = gSaveBlock2Ptr->battleTower.records[gSaveBlock2Ptr->battleTower.battleTowerTrainerId - BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID].name[i];
+ }
+ dest[i] = EOS;
+}
+
+static void FillBattleTowerTrainerParty(void)
+{
+ s32 partyIndex;
+ s32 i;
+ u16 chosenMonIndices[3];
+ u8 friendship;
+ u8 level;
+ u8 fixedIV;
+ u8 battleMonsOffset;
+ u8 monPoolSize;
+ u8 teamFlags;
+ const struct BattleTowerPokemonTemplate *battleTowerMons;
+
+ battleMonsOffset = 0;
+ monPoolSize = 60;
+ friendship = 255;
+
+ ZeroEnemyPartyMons();
+
+ // Different trainers have access to different sets of pokemon to use in battle.
+ // The pokemon later in gBattleTowerLevel100Mons or gBattleTowerLevel50Mons are
+ // stronger. Additionally, the later trainers' pokemon are granted higher IVs.
+ if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < 20)
+ {
+ fixedIV = 6;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < 30)
+ {
+ fixedIV = 9;
+ battleMonsOffset = 30;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < 40)
+ {
+ fixedIV = 12;
+ battleMonsOffset = 60;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < 50)
+ {
+ fixedIV = 15;
+ battleMonsOffset = 90;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < 60)
+ {
+ fixedIV = 18;
+ battleMonsOffset = 120;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < 70)
+ {
+ fixedIV = 21;
+ battleMonsOffset = 150;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < 80)
+ {
+ fixedIV = 31;
+ battleMonsOffset = 180;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID)
+ {
+ fixedIV = 31;
+ battleMonsOffset = 200;
+ monPoolSize = 100;
+ }
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
+ {
+ // Load E-Reader trainer's party.
+ do
+ {
+ for (partyIndex = 0; partyIndex < 3; partyIndex++)
+ CreateBattleTowerMon(&gEnemyParty[partyIndex], &gSaveBlock2Ptr->battleTower.ereaderTrainer.party[partyIndex]);
+ return;
+ } while (0);
+ }
+ else
+ {
+ // Load a battle tower record's party. (From record mixing)
+ for (partyIndex = 0; partyIndex < 3; partyIndex++)
+ {
+ CreateBattleTowerMon(
+ &gEnemyParty[partyIndex],
+ &gSaveBlock2Ptr->battleTower.records[gSaveBlock2Ptr->battleTower.battleTowerTrainerId - BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID].party[partyIndex]);
+ }
+ return;
+ }
+
+ // Use the appropriate list of pokemon and level depending on the
+ // current challenge type. (level 50 or level 100 challenge)
+ if (gSaveBlock2Ptr->battleTower.battleTowerLevelType != 0)
+ {
+ battleTowerMons = gBattleTowerLevel100Mons;
+ level = 100;
+ }
+ else
+ {
+ battleTowerMons = gBattleTowerLevel50Mons;
+ level = 50;
+ }
+
+ teamFlags = gBattleTowerTrainers[gSaveBlock2Ptr->battleTower.battleTowerTrainerId].teamFlags;
+
+ // Attempt to fill the trainer's party with random Pokemon until 3 have been
+ // successfully chosen. The trainer's party may not have duplicate pokemon species
+ // or duplicate held items. Each pokemon must have all of the trainer's team flags
+ // set, as well. If any of those conditions are not met, then the loop starts over
+ // and another pokemon is chosen at random.
+ partyIndex = 0;
+ while (partyIndex != 3)
+ {
+ // Pick a random pokemon index based on the number of pokemon available to choose from
+ // and the starting offset in the battle tower pokemon array.
+ s32 battleMonIndex = ((Random() & 0xFF) * monPoolSize) / 256 + battleMonsOffset;
+
+ // Ensure the chosen pokemon has compatible team flags with the trainer.
+ if (teamFlags == 0 || (battleTowerMons[battleMonIndex].teamFlags & teamFlags) == teamFlags)
+ {
+ // Ensure this pokemon species isn't a duplicate.
+ for (i = 0; i < partyIndex; i++)
+ {
+ if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES, NULL) == battleTowerMons[battleMonIndex].species)
+ break;
+ }
+
+ if (i != partyIndex)
+ continue;
+
+ // Ensure this pokemon's held item isn't a duplicate.
+ for (i = 0; i < partyIndex; i++)
+ {
+ if (GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM, NULL) != ITEM_NONE
+ && GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM, NULL) == sBattleTowerHeldItems[battleTowerMons[battleMonIndex].heldItem])
+ break;
+ }
+
+ if (i != partyIndex)
+ continue;
+
+ // Ensure this exact pokemon index isn't a duplicate. This check doesn't seem necessary
+ // because the species and held items were already checked directly above. Perhaps this
+ // is leftover code before the logic for duplicate species and held items was added.
+ //for (i = 0; i < partyIndex && chosenMonIndices[i] != battleMonIndex; i++);
+ for (i = 0; i < partyIndex; i++)
+ {
+ if (chosenMonIndices[i] == battleMonIndex)
+ break;
+ }
+
+ if (i != partyIndex)
+ continue;
+
+ chosenMonIndices[partyIndex] = battleMonIndex;
+
+ // Place the chosen pokemon into the trainer's party.
+ CreateMonWithEVSpread(
+ &gEnemyParty[partyIndex],
+ battleTowerMons[battleMonIndex].species,
+ level,
+ fixedIV,
+ battleTowerMons[battleMonIndex].evSpread);
+
+ // Give the chosen pokemon its specified moves.
+ for (i = 0; i < 4; i++)
+ {
+ SetMonMoveSlot(&gEnemyParty[partyIndex], battleTowerMons[battleMonIndex].moves[i], i);
+ if (battleTowerMons[battleMonIndex].moves[i] == MOVE_FRUSTRATION)
+ friendship = 0; // MOVE_FRUSTRATION is more powerful the lower the pokemon's friendship is.
+ }
+
+ SetMonData(&gEnemyParty[partyIndex], MON_DATA_FRIENDSHIP, &friendship);
+ SetMonData(&gEnemyParty[partyIndex], MON_DATA_HELD_ITEM, &sBattleTowerHeldItems[battleTowerMons[battleMonIndex].heldItem]);
+
+ // The pokemon was successfully added to the trainer's party, so it's safe to move on to
+ // the next party slot.
+ partyIndex++;
+ }
+ }
+}
+
+static u8 AppendBattleTowerBannedSpeciesName(u16 species, u8 count)
+{
+ if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT))
+ {
+ if (count == 0)
+ StringAppend(gStringVar1, gUnknown_83FE859);
+ count++;
+ StringAppend(gStringVar1, gSpeciesNames[species]);
+ switch (count)
+ {
+ case 2:
+ StringAppend(gStringVar1, gUnknown_83FE85E);
+ break;
+ case 5:
+ case 8:
+ case 11:
+ StringAppend(gStringVar1, gUnknown_83FE85C);
+ break;
+ default:
+ StringAppend(gStringVar1, gUnknown_83FE859);
+ break;
+ }
+ }
+ return count;
+}
+
+static void CheckMonBattleTowerBanlist(u16 species, u16 heldItem, u16 hp, u8 battleTowerLevelType, u8 monLevel, u16 *validPartySpecies, u16 *validPartyHeldItems, u8 *numValid)
+{
+ s32 i;
+ u32 counter = 0;
+
+ if (species == SPECIES_EGG || species == SPECIES_NONE)
+ return;
+
+ while (1)
+ {
+ if (gBattleTowerBannedSpecies[counter] == 0xFFFF)
+ break;
+
+ if (gBattleTowerBannedSpecies[counter] == species)
+ break;
+
+ counter++;
+ }
+
+ if (gBattleTowerBannedSpecies[counter] != 0xFFFF)
+ return;
+
+ if (battleTowerLevelType == 0 && monLevel > 50)
+ return;
+
+ for (i = 0; i < *numValid && validPartySpecies[i] != species ; i++);
+ if (i != *numValid)
+ return;
+
+ if (heldItem != ITEM_NONE)
+ {
+ for (i = 0; i < *numValid && validPartyHeldItems[i] != heldItem ; i++);
+ if (i != *numValid)
+ return;
+ }
+
+ validPartySpecies[*numValid] = species;
+ validPartyHeldItems[*numValid] = heldItem;
+ *numValid = *numValid + 1;
+}
+
+void CheckPartyBattleTowerBanlist(void)
+{
+ s32 i;
+ u16 species2;
+ u16 heldItem;
+ u8 level;
+ u16 hp;
+ u32 numBanlistCaught;
+ u16 validPartySpecies[6];
+ u16 validPartyHeldItems[6];
+ u8 counter;
+
+ counter = 0;
+
+ for (i = 0; i < PARTY_SIZE; i++)
+ {
+ species2 = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2);
+ heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
+ level = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL);
+ hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
+
+ CheckMonBattleTowerBanlist(species2, heldItem, hp, gSpecialVar_Result, level, validPartySpecies, validPartyHeldItems, &counter);
+ }
+
+ if (counter < 3)
+ {
+ gStringVar1[0] = EOS;
+ gSpecialVar_0x8004 = 1;
+ counter = 0;
+
+ for (i = 0; gBattleTowerBannedSpecies[i] != 0xFFFF; i++)
+ counter = AppendBattleTowerBannedSpeciesName(gBattleTowerBannedSpecies[i], counter);
+
+ i = StringLength(gStringVar1);
+ gStringVar1[i - 1] = EOS;
+ if (counter < 3)
+ StringAppend(gStringVar1, gUnknown_83FE860);
+ else
+ StringAppend(gStringVar1, gUnknown_83FE864);
+ }
+ else
+ {
+ gSpecialVar_0x8004 = 0;
+ gSaveBlock2Ptr->battleTower.battleTowerLevelType = gSpecialVar_Result;
+ }
+}
+
+static void PrintBattleTowerTrainerMessage(const u16 *greeting)
+{
+ s32 i;
+ if (EC_DoesEasyChatStringFitOnLine(greeting, 3, 2, 18))
+ {
+ ConvertEasyChatWordsToString(gStringVar4, greeting, 2, 3);
+ i = 0;
+ while (gStringVar4[i++] != CHAR_NEWLINE)
+ ;
+ while (gStringVar4[i] != CHAR_NEWLINE)
+ i++;
+ gStringVar4[i] = CHAR_PROMPT_SCROLL;
+ }
+ else
+ {
+ ConvertEasyChatWordsToString(gStringVar4, greeting, 3, 2);
+ }
+}
+
+void PrintBattleTowerTrainerGreeting(void)
+{
+ if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
+ PrintBattleTowerTrainerMessage(gSaveBlock2Ptr->battleTower.ereaderTrainer.greeting);
+ else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID)
+ PrintBattleTowerTrainerMessage(gBattleTowerTrainers[gSaveBlock2Ptr->battleTower.battleTowerTrainerId].greeting);
+ else
+ PrintBattleTowerTrainerMessage(gSaveBlock2Ptr->battleTower.records[gSaveBlock2Ptr->battleTower.battleTowerTrainerId - BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID].greeting);
+}
+
+static void CB2_FinishEReaderBattle(void)
+{
+ s32 i;
+ u16 heldItem;
+
+ switch (sSpecialVar_0x8004_Copy)
+ {
+ case 0:
+ break;
+ case 1:
+ for (i = 0; i < PARTY_SIZE; i++)
+ {
+ heldItem = GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_HELD_ITEM);
+ SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &heldItem);
+ }
+ break;
+ case 2:
+ PrintEReaderTrainerFarewellMessage();
+ break;
+ }
+
+ SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
+}
+
+static void Task_WaitBT(u8 taskId)
+{
+ if (BT_IsDone() == TRUE)
+ {
+ gMain.savedCallback = CB2_FinishEReaderBattle;
+ CleanupOverworldWindowsAndTilemaps();
+ SetMainCallback2(CB2_InitBattle);
+ DestroyTask(taskId);
+ }
+}
+
+
+void StartSpecialBattle(void)
+{
+ s32 i;
+ u16 heldItem;
+ u8 transition;
+
+ sSpecialVar_0x8004_Copy = gSpecialVar_0x8004;
+ switch (sSpecialVar_0x8004_Copy)
+ {
+ case 0: // battle tower battle
+ gBattleTypeFlags = (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_TRAINER);
+ gTrainerBattleOpponent_A = 0;
+
+ FillBattleTowerTrainerParty();
+
+ CreateTask(Task_WaitBT, 1);
+ PlayMapChosenOrBattleBGM(0);
+ transition = BattleSetup_GetBattleTowerBattleTransition();
+ BT_StartOnField(transition);
+ break;
+ case 1: // secret base battle
+ for (i = 0; i < PARTY_SIZE; i++)
+ {
+ heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
+ SetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_HELD_ITEM, &heldItem);
+ }
+
+ CreateTask(Task_WaitBT, 1);
+ PlayMapChosenOrBattleBGM(0);
+ transition = BattleSetup_GetBattleTowerBattleTransition();
+ BT_StartOnField(transition);
+ break;
+ case 2: // e-reader trainer battle
+ ZeroEnemyPartyMons();
+
+ for (i = 0; i < 3; i++)
+ CreateBattleTowerMon(&gEnemyParty[i], &gSaveBlock2Ptr->battleTower.ereaderTrainer.party[i]);
+
+ gBattleTypeFlags = (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER);
+ gTrainerBattleOpponent_A = 0;
+
+ CreateTask(Task_WaitBT, 1);
+ PlayMapChosenOrBattleBGM(0);
+ transition = BattleSetup_GetBattleTowerBattleTransition();
+ BT_StartOnField(transition);
+ break;
+ }
+}
+
+void SetBattleTowerProperty(void)
+{
+ s32 i;
+ u8 battleTowerLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ switch (gSpecialVar_0x8004)
+ {
+ case 0:
+ ewram160FB = gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType];
+ gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType] = gSpecialVar_0x8005;
+ break;
+ case 1:
+ gSaveBlock2Ptr->battleTower.battleTowerLevelType = gSpecialVar_0x8005;
+ break;
+ case 2:
+ gSaveBlock2Ptr->battleTower.curChallengeBattleNum[battleTowerLevelType] = gSpecialVar_0x8005;
+ break;
+ case 3:
+ gSaveBlock2Ptr->battleTower.curStreakChallengesNum[battleTowerLevelType] = gSpecialVar_0x8005;
+ break;
+ case 4:
+ gSaveBlock2Ptr->battleTower.battleTowerTrainerId = gSpecialVar_0x8005;
+ break;
+ case 5:
+ for (i = 0; i < 3; i++)
+ gSaveBlock2Ptr->battleTower.selectedPartyMons[i] = gSelectedOrderFromParty[i];
+ break;
+ case 6:
+ if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
+ ClearEReaderTrainer(&gSaveBlock2Ptr->battleTower.ereaderTrainer);
+ if (gSaveBlock2Ptr->battleTower.totalBattleTowerWins < 9999)
+ gSaveBlock2Ptr->battleTower.totalBattleTowerWins++;
+ gSaveBlock2Ptr->battleTower.curChallengeBattleNum[battleTowerLevelType]++;
+ SaveCurrentWinStreak();
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.curChallengeBattleNum[battleTowerLevelType];
+ gStringVar1[0] = gSaveBlock2Ptr->battleTower.curChallengeBattleNum[battleTowerLevelType] + 0xA1;
+ gStringVar1[1] = 0xFF;
+ break;
+ case 7:
+ if (gSaveBlock2Ptr->battleTower.curStreakChallengesNum[battleTowerLevelType] < 1430)
+ gSaveBlock2Ptr->battleTower.curStreakChallengesNum[battleTowerLevelType]++;
+ SaveCurrentWinStreak();
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.curStreakChallengesNum[battleTowerLevelType];
+ break;
+ case 8:
+ gSaveBlock2Ptr->battleTower.unk_554 = gSpecialVar_0x8005;
+ break;
+ case 9:
+ break;
+ case 10:
+ SetGameStat(GAME_STAT_BATTLE_TOWER_BEST_STREAK, gSaveBlock2Ptr->battleTower.bestBattleTowerWinStreak);
+ break;
+ case 11:
+ if (gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType] != 3)
+ ResetBattleTowerStreak(battleTowerLevelType);
+ break;
+ case 12:
+ gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType] = ewram160FB;
+ break;
+ case 13:
+ gSaveBlock2Ptr->battleTower.currentWinStreaks[battleTowerLevelType] = GetCurrentBattleTowerWinStreak(battleTowerLevelType);
+ break;
+ case 14:
+ gSaveBlock2Ptr->battleTower.lastStreakLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+ break;
+ }
+}
+
+void BattleTowerUtil(void)
+{
+ u8 battleTowerLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ switch (gSpecialVar_0x8004)
+ {
+ case 0:
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType];
+ break;
+ case 1:
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+ break;
+ case 2:
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.curChallengeBattleNum[battleTowerLevelType];
+ break;
+ case 3:
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.curStreakChallengesNum[battleTowerLevelType];
+ break;
+ case 4:
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.battleTowerTrainerId;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ break;
+ case 8:
+ gSpecialVar_Result = gSaveBlock2Ptr->battleTower.unk_554;
+ break;
+ case 9:
+ gSpecialVar_Result = GetCurrentBattleTowerWinStreak(battleTowerLevelType);
+ break;
+ case 10:
+ SetGameStat(GAME_STAT_BATTLE_TOWER_BEST_STREAK, gSaveBlock2Ptr->battleTower.bestBattleTowerWinStreak);
+ break;
+ case 11:
+ ResetBattleTowerStreak(battleTowerLevelType);
+ break;
+ case 12:
+ gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType] = ewram160FB;
+ break;
+ case 13:
+ gSaveBlock2Ptr->battleTower.currentWinStreaks[battleTowerLevelType] = GetCurrentBattleTowerWinStreak(battleTowerLevelType);
+ break;
+ case 14:
+ gSaveBlock2Ptr->battleTower.lastStreakLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+ break;
+ }
+}
+
+void SetBattleTowerParty(void)
+{
+ s32 i;
+
+ for (i = 0; i < 3; i++)
+ gSelectedOrderFromParty[i] = gSaveBlock2Ptr->battleTower.selectedPartyMons[i];
+
+ ReducePlayerPartyToThree();
+}
+
+static void SaveCurrentWinStreak(void)
+{
+ u8 levelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+ u16 streak = GetCurrentBattleTowerWinStreak(levelType);
+
+ if (gSaveBlock2Ptr->battleTower.recordWinStreaks[levelType] < streak)
+ gSaveBlock2Ptr->battleTower.recordWinStreaks[levelType] = streak;
+
+ if (gSaveBlock2Ptr->battleTower.recordWinStreaks[0] > gSaveBlock2Ptr->battleTower.recordWinStreaks[1])
+ {
+ streak = gSaveBlock2Ptr->battleTower.recordWinStreaks[0];
+ SetGameStat(GAME_STAT_BATTLE_TOWER_BEST_STREAK, streak);
+
+ if (streak > 9999)
+ gSaveBlock2Ptr->battleTower.bestBattleTowerWinStreak = 9999;
+ else
+ gSaveBlock2Ptr->battleTower.bestBattleTowerWinStreak = streak;
+ }
+ else
+ {
+ streak = gSaveBlock2Ptr->battleTower.recordWinStreaks[1];
+ SetGameStat(GAME_STAT_BATTLE_TOWER_BEST_STREAK, streak);
+
+ if (streak > 9999)
+ gSaveBlock2Ptr->battleTower.bestBattleTowerWinStreak = 9999;
+ else
+ gSaveBlock2Ptr->battleTower.bestBattleTowerWinStreak = streak;
+ }
+}
+
+static void SetPlayerBattleTowerRecord(void)
+{
+ s32 i;
+ u8 trainerClass;
+ struct BattleTowerRecord *playerRecord = &gSaveBlock2Ptr->battleTower.playerRecord;
+ u8 battleTowerLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ if (gSaveBlock2Ptr->playerGender != MALE)
+ {
+ trainerClass = sFemaleTrainerClasses[(gSaveBlock2Ptr->playerTrainerId[0] + gSaveBlock2Ptr->playerTrainerId[1]
+ + gSaveBlock2Ptr->playerTrainerId[2] + gSaveBlock2Ptr->playerTrainerId[3]) % NELEMS(sFemaleTrainerClasses)];
+ }
+ else
+ {
+ trainerClass = sMaleTrainerClasses[(gSaveBlock2Ptr->playerTrainerId[0] + gSaveBlock2Ptr->playerTrainerId[1]
+ + gSaveBlock2Ptr->playerTrainerId[2] + gSaveBlock2Ptr->playerTrainerId[3]) % NELEMS(sMaleTrainerClasses)];
+ }
+
+ playerRecord->battleTowerLevelType = battleTowerLevelType;
+ playerRecord->trainerClass = trainerClass;
+
+ CopyTrainerId(playerRecord->trainerId, gSaveBlock2Ptr->playerTrainerId);
+ StringCopy7(playerRecord->name, gSaveBlock2Ptr->playerName);
+
+ playerRecord->winStreak = GetCurrentBattleTowerWinStreak(battleTowerLevelType);
+
+ for (i = 0; i < 6; i++)
+ playerRecord->greeting[i] = gSaveBlock1Ptr->easyChatBattleStart[i];
+
+ for (i = 0; i < 3; i++)
+ sub_803E23C(&gPlayerParty[gSaveBlock2Ptr->battleTower.selectedPartyMons[i] - 1], &playerRecord->party[i]);
+
+ SetBattleTowerRecordChecksum(&gSaveBlock2Ptr->battleTower.playerRecord);
+ SaveCurrentWinStreak();
+}
+
+void SaveBattleTowerProgress(void)
+{
+ u8 battleTowerLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ if (gSpecialVar_0x8004 == 3 || gSpecialVar_0x8004 == 0)
+ {
+ if (gSaveBlock2Ptr->battleTower.curStreakChallengesNum[battleTowerLevelType] > 1
+ || gSaveBlock2Ptr->battleTower.curChallengeBattleNum[battleTowerLevelType] > 1)
+ SetPlayerBattleTowerRecord();
+ }
+
+ PopulateBravoTrainerBattleTowerLostData();
+
+ gSaveBlock2Ptr->battleTower.battleOutcome = gBattleOutcome;
+
+ if (gSpecialVar_0x8004 != 3)
+ gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType] = gSpecialVar_0x8004;
+
+ VarSet(VAR_0x4000, BTSPECIAL_TEST);
+ gSaveBlock2Ptr->battleTower.unk_554 = 1;
+ TrySavingData(SAVE_EREADER);
+}
+
+void BattleTower_SoftReset(void)
+{
+ DoSoftReset();
+}
+
+static void ValidateBattleTowerRecordChecksums(void)
+{
+ u32 i;
+ s32 recordIndex;
+ struct BattleTowerRecord *record;
+ u32 checksum;
+
+ record = &gSaveBlock2Ptr->battleTower.playerRecord;
+ checksum = 0;
+ for (i = 0; i < (sizeof(struct BattleTowerRecord) / sizeof(u32)) - 1; i++)
+ checksum += ((u32 *)record)[i];
+
+ if (gSaveBlock2Ptr->battleTower.playerRecord.checksum != checksum)
+ ClearBattleTowerRecord(&gSaveBlock2Ptr->battleTower.playerRecord);
+
+ for (recordIndex = 0; recordIndex < 5; recordIndex++)
+ {
+ record = &gSaveBlock2Ptr->battleTower.records[recordIndex];
+ checksum = 0;
+ for (i = 0; i < (sizeof(struct BattleTowerRecord) / sizeof(u32)) - 1; i++)
+ checksum += ((u32 *)record)[i];
+
+ if (gSaveBlock2Ptr->battleTower.records[recordIndex].checksum != checksum)
+ ClearBattleTowerRecord(&gSaveBlock2Ptr->battleTower.records[recordIndex]);
+ }
+}
+
+static void SetBattleTowerRecordChecksum(struct BattleTowerRecord *record)
+{
+ u32 i;
+
+ record->checksum = 0;
+ for (i = 0; i < (sizeof(struct BattleTowerRecord) / sizeof(u32)) - 1; i++)
+ record->checksum += ((u32 *)record)[i];
+}
+
+static void ClearBattleTowerRecord(struct BattleTowerRecord *record)
+{
+ u32 i;
+
+ for (i = 0; i < sizeof(struct BattleTowerRecord) / sizeof(u32); i++)
+ ((u32 *)record)[i] = 0;
+}
+
+static void PopulateBravoTrainerBattleTowerLostData(void)
+{
+ s32 i;
+
+ GetBattleTowerTrainerName(gSaveBlock2Ptr->battleTower.defeatedByTrainerName);
+ gSaveBlock2Ptr->battleTower.defeatedBySpecies = gBattleMons[1].species;
+ gSaveBlock2Ptr->battleTower.firstMonSpecies = gBattleMons[0].species;
+
+ for (i = 0; i < POKEMON_NAME_LENGTH; i++)
+ gSaveBlock2Ptr->battleTower.firstMonNickname[i] = gBattleMons[0].nickname[i];
+}
+
+static u16 GetCurrentBattleTowerWinStreak(u8 battleTowerLevelType)
+{
+ u16 winStreak = ((gSaveBlock2Ptr->battleTower.curStreakChallengesNum[battleTowerLevelType] - 1) * 7 - 1)
+ + gSaveBlock2Ptr->battleTower.curChallengeBattleNum[battleTowerLevelType];
+
+ if (winStreak > 9999)
+ return 9999;
+ else
+ return winStreak;
+}
+
+void DetermineBattleTowerPrize(void)
+{
+ u8 levelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ if (gSaveBlock2Ptr->battleTower.curStreakChallengesNum[levelType] - 1 > 5)
+ gSaveBlock2Ptr->battleTower.prizeItem = sLongStreakPrizes[Random() % NELEMS(sLongStreakPrizes)];
+ else
+ gSaveBlock2Ptr->battleTower.prizeItem = sShortStreakPrizes[Random() % NELEMS(sShortStreakPrizes)];
+}
+
+void GiveBattleTowerPrize(void)
+{
+ u8 battleTowerLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ if (AddBagItem(gSaveBlock2Ptr->battleTower.prizeItem, 1) == TRUE)
+ {
+ CopyItemName(gSaveBlock2Ptr->battleTower.prizeItem, gStringVar1);
+ gSpecialVar_Result = 1;
+ }
+ else
+ {
+ gSpecialVar_Result = 0;
+ gSaveBlock2Ptr->battleTower.var_4AE[battleTowerLevelType] = 6;
+ }
+}
+
+void AwardBattleTowerRibbons(void)
+{
+ s32 i;
+ u32 partyIndex;
+ struct Pokemon *pokemon;
+ u8 ribbonType;
+ u8 battleTowerLevelType = gSaveBlock2Ptr->battleTower.battleTowerLevelType;
+
+ if (battleTowerLevelType != 0)
+ ribbonType = MON_DATA_VICTORY_RIBBON;
+ else
+ ribbonType = MON_DATA_WINNING_RIBBON;
+
+ gSpecialVar_Result = 0;
+
+ if (GetCurrentBattleTowerWinStreak(battleTowerLevelType) > 55)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ partyIndex = gSaveBlock2Ptr->battleTower.selectedPartyMons[i] - 1;
+ pokemon = &gPlayerParty[partyIndex];
+ if (!GetMonData(pokemon, ribbonType))
+ {
+ gSpecialVar_Result = 1;
+ SetMonData(pokemon, ribbonType, &gSpecialVar_Result);
+ }
+ }
+ }
+
+ if (gSpecialVar_Result != 0)
+ IncrementGameStat(GAME_STAT_RECEIVED_RIBBONS);
+}
+
+// This is a leftover debugging function that is used to populate the E-Reader
+// trainer with the player's current data.
+static void Debug_FillEReaderTrainerWithPlayerData(void)
+{
+ struct BattleTowerEReaderTrainer *ereaderTrainer;
+ s32 i;
+ s32 j;
+
+ ereaderTrainer = &gSaveBlock2Ptr->battleTower.ereaderTrainer;
+
+ if (gSaveBlock2Ptr->playerGender != MALE)
+ {
+ ereaderTrainer->trainerClass = sFemaleTrainerClasses[(gSaveBlock2Ptr->playerTrainerId[0] + gSaveBlock2Ptr->playerTrainerId[1]
+ + gSaveBlock2Ptr->playerTrainerId[2] + gSaveBlock2Ptr->playerTrainerId[3]) % NELEMS(sFemaleTrainerClasses)];
+ }
+ else
+ {
+ ereaderTrainer->trainerClass = sMaleTrainerClasses[(gSaveBlock2Ptr->playerTrainerId[0] + gSaveBlock2Ptr->playerTrainerId[1]
+ + gSaveBlock2Ptr->playerTrainerId[2] + gSaveBlock2Ptr->playerTrainerId[3]) % NELEMS(sMaleTrainerClasses)];
+ }
+
+ CopyTrainerId(ereaderTrainer->trainerId, gSaveBlock2Ptr->playerTrainerId);
+ StringCopy7(ereaderTrainer->name, gSaveBlock2Ptr->playerName);
+
+ ereaderTrainer->winStreak = 1;
+
+ j = 7;
+ for (i = 0; i < 6; i++)
+ {
+ ereaderTrainer->greeting[i] = gSaveBlock1Ptr->easyChatBattleStart[i];
+ ereaderTrainer->farewellPlayerLost[i] = j;
+ ereaderTrainer->farewellPlayerWon[i] = j + 6;
+ j++;
+ }
+
+ for (i = 0; i < 3; i++)
+ sub_803E23C(&gPlayerParty[i], &ereaderTrainer->party[i]);
+
+ SetEReaderTrainerChecksum(ereaderTrainer);
+}
+
+u8 GetEreaderTrainerFrontSpriteId(void)
+{
+ return gFacilityClassToPicIndex[gSaveBlock2Ptr->battleTower.ereaderTrainer.trainerClass];
+}
+
+u8 GetEreaderTrainerClassId(void)
+{
+ return gFacilityClassToTrainerClass[gSaveBlock2Ptr->battleTower.ereaderTrainer.trainerClass];
+}
+
+void CopyEReaderTrainerName5(u8 *trainerName)
+{
+ s32 i;
+
+ for (i = 0; i < 5; i++)
+ trainerName[i] = gSaveBlock2Ptr->battleTower.ereaderTrainer.name[i];
+
+ trainerName[i] = EOS;
+}
+
+// Checks if the saved E-Reader trainer is valid.
+void ValidateEReaderTrainer(void)
+{
+ u32 i;
+ u32 checksum;
+ struct BattleTowerEReaderTrainer *ereaderTrainer;
+
+ gSpecialVar_Result = 0;
+ ereaderTrainer = &gSaveBlock2Ptr->battleTower.ereaderTrainer;
+
+ checksum = 0;
+ for (i = 0; i < sizeof(struct BattleTowerEReaderTrainer) / sizeof(u32) - 1; i++)
+ checksum |= ((u32 *)ereaderTrainer)[i];
+
+ if (checksum == 0)
+ {
+ gSpecialVar_Result = 1;
+ return;
+ }
+
+ checksum = 0;
+ for (i = 0; i < sizeof(struct BattleTowerEReaderTrainer) / sizeof(u32) - 1; i++)
+ checksum += ((u32 *)ereaderTrainer)[i];
+
+ if (gSaveBlock2Ptr->battleTower.ereaderTrainer.checksum != checksum)
+ {
+ ClearEReaderTrainer(&gSaveBlock2Ptr->battleTower.ereaderTrainer);
+ gSpecialVar_Result = 1;
+ }
+}
+
+static void SetEReaderTrainerChecksum(struct BattleTowerEReaderTrainer *ereaderTrainer)
+{
+ s32 i;
+
+ ereaderTrainer->checksum = 0;
+ for (i = 0; i < sizeof(struct BattleTowerEReaderTrainer) / sizeof(u32) - 1; i++)
+ ereaderTrainer->checksum += ((u32 *)ereaderTrainer)[i];
+}
+
+void ClearEReaderTrainer(struct BattleTowerEReaderTrainer *ereaderTrainer)
+{
+ u32 i;
+
+ for (i = 0; i < sizeof(struct BattleTowerEReaderTrainer) / sizeof(u32); i++)
+ ((u32 *)ereaderTrainer)[i] = 0;
+}
+
+void PrintEReaderTrainerGreeting(void)
+{
+ PrintBattleTowerTrainerMessage(gSaveBlock2Ptr->battleTower.ereaderTrainer.greeting);
+}
+
+static void PrintEReaderTrainerFarewellMessage(void)
+{
+ if (gBattleOutcome == B_OUTCOME_DREW)
+ gStringVar4[0] = EOS;
+ else if (gBattleOutcome == B_OUTCOME_WON)
+ PrintBattleTowerTrainerMessage(gSaveBlock2Ptr->battleTower.ereaderTrainer.farewellPlayerWon);
+ else
+ PrintBattleTowerTrainerMessage(gSaveBlock2Ptr->battleTower.ereaderTrainer.farewellPlayerLost);
+}
+
+void Dummy_TryEnableBravoTrainerBattleTower(void)
+{
+ s32 i;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (gSaveBlock2Ptr->battleTower.var_4AE[i] == 1)
+ TakeBravoTrainerBattleTowerOffTheAir();
+ }
+}