2019-01-13 12:12:27 +01:00
|
|
|
#include "global.h"
|
2019-09-09 03:07:54 +02:00
|
|
|
#include "malloc.h"
|
2019-01-13 12:12:27 +01:00
|
|
|
#include "battle.h"
|
|
|
|
#include "battle_tower.h"
|
|
|
|
#include "battle_setup.h"
|
2019-03-22 20:16:26 +01:00
|
|
|
#include "ereader_helpers.h"
|
2019-01-13 12:12:27 +01:00
|
|
|
#include "event_data.h"
|
2019-01-13 20:50:08 +01:00
|
|
|
#include "event_scripts.h"
|
2019-01-13 12:12:27 +01:00
|
|
|
#include "fieldmap.h"
|
|
|
|
#include "field_message_box.h"
|
|
|
|
#include "international_string_util.h"
|
|
|
|
#include "item.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "menu.h"
|
|
|
|
#include "overworld.h"
|
|
|
|
#include "palette.h"
|
|
|
|
#include "pokemon.h"
|
|
|
|
#include "script.h"
|
|
|
|
#include "string_util.h"
|
2019-01-13 13:15:23 +01:00
|
|
|
#include "strings.h"
|
2019-01-13 12:12:27 +01:00
|
|
|
#include "text.h"
|
2019-01-13 13:15:23 +01:00
|
|
|
#include "trainer_hill.h"
|
2019-01-13 12:12:27 +01:00
|
|
|
#include "window.h"
|
|
|
|
#include "util.h"
|
2019-11-13 22:10:05 +01:00
|
|
|
#include "constants/battle_ai.h"
|
2019-11-21 20:03:35 +01:00
|
|
|
#include "constants/event_object_movement.h"
|
2019-01-13 13:15:23 +01:00
|
|
|
#include "constants/event_objects.h"
|
2019-01-13 20:50:08 +01:00
|
|
|
#include "constants/items.h"
|
2019-01-31 22:51:20 +01:00
|
|
|
#include "constants/layouts.h"
|
2019-01-19 12:57:18 +01:00
|
|
|
#include "constants/moves.h"
|
2019-01-13 12:12:27 +01:00
|
|
|
#include "constants/maps.h"
|
2019-01-13 20:50:08 +01:00
|
|
|
#include "constants/trainers.h"
|
2019-01-21 17:55:27 +01:00
|
|
|
#include "constants/easy_chat.h"
|
2019-02-28 04:16:01 +01:00
|
|
|
#include "constants/trainer_hill.h"
|
2020-04-21 21:53:48 +02:00
|
|
|
#include "constants/trainer_types.h"
|
2019-01-13 20:50:08 +01:00
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
#define HILL_TAG_NORMAL 0
|
|
|
|
#define HILL_TAG_VARIETY 1
|
|
|
|
#define HILL_TAG_UNIQUE 2
|
|
|
|
#define HILL_TAG_EXPERT 3
|
|
|
|
|
2019-01-13 12:12:27 +01:00
|
|
|
#define HILL_MAX_TIME 215999 // 60 * 60 * 60 - 1
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
// EWRAM
|
2019-09-04 21:42:53 +02:00
|
|
|
struct TrHillStruct2
|
|
|
|
{
|
|
|
|
u8 floorId;
|
|
|
|
struct TrHillTag tag;
|
2019-11-13 22:10:05 +01:00
|
|
|
struct TrHillFloor floors[NUM_TRAINER_HILL_FLOORS];
|
2019-09-04 21:42:53 +02:00
|
|
|
};
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
static EWRAM_DATA struct TrHillStruct2 *sHillData = NULL;
|
|
|
|
static EWRAM_DATA struct TrHillRoomTrainers *sRoomTrainers = NULL;
|
2019-03-01 07:49:11 +01:00
|
|
|
EWRAM_DATA u32 *gTrainerHillVBlankCounter = NULL;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
|
|
|
// This file's functions.
|
2019-02-28 03:28:34 +01:00
|
|
|
static void TrainerHillStartChallenge(void);
|
2019-11-13 22:10:05 +01:00
|
|
|
static void GetOwnerState(void);
|
|
|
|
static void GiveChallengePrize(void);
|
|
|
|
static void CheckFinalTime(void);
|
2019-02-28 03:28:34 +01:00
|
|
|
static void TrainerHillResumeTimer(void);
|
|
|
|
static void TrainerHillSetPlayerLost(void);
|
2019-02-28 04:16:01 +01:00
|
|
|
static void TrainerHillGetChallengeStatus(void);
|
2019-11-13 22:10:05 +01:00
|
|
|
static void BufferChallengeTime(void);
|
|
|
|
static void GetAllFloorsUsed(void);
|
2020-06-24 22:27:00 +02:00
|
|
|
static void GetInEReaderMode(void);
|
2019-11-13 22:10:05 +01:00
|
|
|
static void IsTrainerHillChallengeActive(void);
|
|
|
|
static void ShowTrainerHillPostBattleText(void);
|
|
|
|
static void SetAllTrainerFlags(void);
|
|
|
|
static void GetGameSaved(void);
|
|
|
|
static void SetGameSaved(void);
|
|
|
|
static void ClearGameSaved(void);
|
|
|
|
static void GetChallengeWon(void);
|
2019-02-28 04:16:01 +01:00
|
|
|
static void TrainerHillSetTag(void);
|
2019-01-13 20:50:08 +01:00
|
|
|
static void SetUpDataStruct(void);
|
|
|
|
static void FreeDataStruct(void);
|
2021-03-21 04:47:08 +01:00
|
|
|
static void TrainerHillDummy(void);
|
2019-01-13 20:50:08 +01:00
|
|
|
static void SetTimerValue(u32 *dst, u32 val);
|
|
|
|
static u32 GetTimerValue(u32 *src);
|
2019-11-13 22:10:05 +01:00
|
|
|
static void SetTrainerHillMonLevel(struct Pokemon *mon, u8 level);
|
|
|
|
static u16 GetPrizeItemId(void);
|
2019-01-13 12:12:27 +01:00
|
|
|
|
|
|
|
// const data
|
2019-01-19 12:57:18 +01:00
|
|
|
#include "data/battle_frontier/trainer_hill.h"
|
2019-01-13 13:15:23 +01:00
|
|
|
|
2019-01-13 12:12:27 +01:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
u8 trainerClass;
|
|
|
|
u8 musicId;
|
2019-11-13 22:10:05 +01:00
|
|
|
} static const sTrainerClassesAndMusic[] =
|
2019-01-13 20:50:08 +01:00
|
|
|
{
|
|
|
|
{TRAINER_CLASS_TEAM_AQUA, TRAINER_ENCOUNTER_MUSIC_AQUA},
|
|
|
|
{TRAINER_CLASS_AQUA_ADMIN, TRAINER_ENCOUNTER_MUSIC_AQUA},
|
|
|
|
{TRAINER_CLASS_AQUA_LEADER, TRAINER_ENCOUNTER_MUSIC_AQUA},
|
|
|
|
{TRAINER_CLASS_AROMA_LADY, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_BATTLE_GIRL, TRAINER_ENCOUNTER_MUSIC_INTENSE},
|
|
|
|
{TRAINER_CLASS_SWIMMER_F, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_POKEFAN, TRAINER_ENCOUNTER_MUSIC_TWINS},
|
|
|
|
{TRAINER_CLASS_DRAGON_TAMER, TRAINER_ENCOUNTER_MUSIC_INTENSE},
|
|
|
|
{TRAINER_CLASS_COOLTRAINER, TRAINER_ENCOUNTER_MUSIC_COOL},
|
|
|
|
{TRAINER_CLASS_GUITARIST, TRAINER_ENCOUNTER_MUSIC_INTENSE},
|
|
|
|
{TRAINER_CLASS_SAILOR, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_TWINS, TRAINER_ENCOUNTER_MUSIC_TWINS},
|
|
|
|
{TRAINER_CLASS_INTERVIEWER, TRAINER_ENCOUNTER_MUSIC_INTERVIEWER},
|
|
|
|
{TRAINER_CLASS_RUIN_MANIAC, TRAINER_ENCOUNTER_MUSIC_HIKER},
|
|
|
|
{TRAINER_CLASS_GENTLEMAN, TRAINER_ENCOUNTER_MUSIC_RICH},
|
|
|
|
{TRAINER_CLASS_SWIMMER_M, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_POKEMANIAC, TRAINER_ENCOUNTER_MUSIC_SUSPICIOUS},
|
|
|
|
{TRAINER_CLASS_BLACK_BELT, TRAINER_ENCOUNTER_MUSIC_INTENSE},
|
|
|
|
{TRAINER_CLASS_OLD_COUPLE, TRAINER_ENCOUNTER_MUSIC_INTENSE},
|
|
|
|
{TRAINER_CLASS_BUG_MANIAC, TRAINER_ENCOUNTER_MUSIC_SUSPICIOUS},
|
|
|
|
{TRAINER_CLASS_CAMPER, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_KINDLER, TRAINER_ENCOUNTER_MUSIC_HIKER},
|
|
|
|
{TRAINER_CLASS_TEAM_MAGMA, TRAINER_ENCOUNTER_MUSIC_MAGMA},
|
|
|
|
{TRAINER_CLASS_MAGMA_ADMIN, TRAINER_ENCOUNTER_MUSIC_MAGMA},
|
|
|
|
{TRAINER_CLASS_MAGMA_LEADER, TRAINER_ENCOUNTER_MUSIC_MAGMA},
|
|
|
|
{TRAINER_CLASS_LASS, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_BUG_CATCHER, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_NINJA_BOY, TRAINER_ENCOUNTER_MUSIC_SUSPICIOUS},
|
|
|
|
{TRAINER_CLASS_RICH_BOY, TRAINER_ENCOUNTER_MUSIC_RICH},
|
|
|
|
{TRAINER_CLASS_HEX_MANIAC, TRAINER_ENCOUNTER_MUSIC_SUSPICIOUS},
|
|
|
|
{TRAINER_CLASS_BEAUTY, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_LADY, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_PARASOL_LADY, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_PICNICKER, TRAINER_ENCOUNTER_MUSIC_GIRL},
|
|
|
|
{TRAINER_CLASS_PKMN_BREEDER, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_COLLECTOR, TRAINER_ENCOUNTER_MUSIC_SUSPICIOUS},
|
|
|
|
{TRAINER_CLASS_PKMN_RANGER, TRAINER_ENCOUNTER_MUSIC_COOL},
|
|
|
|
{TRAINER_CLASS_PKMN_TRAINER_3, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_YOUNG_COUPLE, TRAINER_ENCOUNTER_MUSIC_GIRL},
|
|
|
|
{TRAINER_CLASS_PSYCHIC, TRAINER_ENCOUNTER_MUSIC_INTENSE},
|
|
|
|
{TRAINER_CLASS_SR_AND_JR, TRAINER_ENCOUNTER_MUSIC_TWINS},
|
|
|
|
{TRAINER_CLASS_ELITE_FOUR, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_YOUNGSTER, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_EXPERT, TRAINER_ENCOUNTER_MUSIC_INTENSE},
|
|
|
|
{TRAINER_CLASS_TRIATHLETE, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_BIRD_KEEPER, TRAINER_ENCOUNTER_MUSIC_COOL},
|
|
|
|
{TRAINER_CLASS_FISHERMAN, TRAINER_ENCOUNTER_MUSIC_HIKER},
|
|
|
|
{TRAINER_CLASS_CHAMPION, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_TUBER_M, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
{TRAINER_CLASS_TUBER_F, TRAINER_ENCOUNTER_MUSIC_GIRL},
|
|
|
|
{TRAINER_CLASS_SIS_AND_BRO, TRAINER_ENCOUNTER_MUSIC_SWIMMER},
|
|
|
|
{TRAINER_CLASS_HIKER, TRAINER_ENCOUNTER_MUSIC_HIKER},
|
|
|
|
{TRAINER_CLASS_LEADER, TRAINER_ENCOUNTER_MUSIC_FEMALE},
|
|
|
|
{TRAINER_CLASS_SCHOOL_KID, TRAINER_ENCOUNTER_MUSIC_MALE},
|
|
|
|
};
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static const u16 sPrizeListRareCandy1[] = {ITEM_RARE_CANDY, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListLuxuryBall1[] = {ITEM_LUXURY_BALL, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListMaxRevive1[] = {ITEM_MAX_REVIVE, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListMaxEther1[] = {ITEM_MAX_ETHER, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListElixir1[] = {ITEM_ELIXIR, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListRoar[] = {ITEM_TM05_ROAR, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListSludgeBomb[] = {ITEM_TM36_SLUDGE_BOMB, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListToxic[] = {ITEM_TM06_TOXIC, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListSunnyDay[] = {ITEM_TM11_SUNNY_DAY, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListEarthQuake[] = {ITEM_TM26_EARTHQUAKE, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
|
|
|
|
static const u16 sPrizeListRareCandy2[] = {ITEM_RARE_CANDY, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListLuxuryBall2[] = {ITEM_LUXURY_BALL, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListMaxRevive2[] = {ITEM_MAX_REVIVE, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListMaxEther2[] = {ITEM_MAX_ETHER, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListElixir2[] = {ITEM_ELIXIR, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListBrickBreak[] = {ITEM_TM31_BRICK_BREAK, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListTorment[] = {ITEM_TM41_TORMENT, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
static const u16 sPrizeListSkillSwap[] = {ITEM_TM48_SKILL_SWAP, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
2020-05-19 22:13:25 +02:00
|
|
|
static const u16 sPrizeListGigaDrain[] = {ITEM_TM19_GIGA_DRAIN, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
2019-11-13 22:10:05 +01:00
|
|
|
static const u16 sPrizeListAttract[] = {ITEM_TM45_ATTRACT, ITEM_ETHER, ITEM_MAX_POTION, ITEM_REVIVE, ITEM_FLUFFY_TAIL, ITEM_GREAT_BALL};
|
|
|
|
|
|
|
|
static const u16 *const sPrizeLists1[NUM_TRAINER_HILL_PRIZE_LISTS] =
|
|
|
|
{
|
|
|
|
sPrizeListRareCandy1,
|
|
|
|
sPrizeListLuxuryBall1,
|
|
|
|
sPrizeListMaxRevive1,
|
|
|
|
sPrizeListMaxEther1,
|
|
|
|
sPrizeListElixir1,
|
|
|
|
sPrizeListRoar,
|
|
|
|
sPrizeListSludgeBomb,
|
|
|
|
sPrizeListToxic,
|
|
|
|
sPrizeListSunnyDay,
|
|
|
|
sPrizeListEarthQuake
|
2019-01-13 20:50:08 +01:00
|
|
|
};
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static const u16 *const sPrizeLists2[NUM_TRAINER_HILL_PRIZE_LISTS] =
|
|
|
|
{
|
|
|
|
sPrizeListRareCandy2,
|
|
|
|
sPrizeListLuxuryBall2,
|
|
|
|
sPrizeListMaxRevive2,
|
|
|
|
sPrizeListMaxEther2,
|
|
|
|
sPrizeListElixir2,
|
|
|
|
sPrizeListBrickBreak,
|
|
|
|
sPrizeListTorment,
|
|
|
|
sPrizeListSkillSwap,
|
2020-05-19 22:13:25 +02:00
|
|
|
sPrizeListGigaDrain,
|
2019-11-13 22:10:05 +01:00
|
|
|
sPrizeListAttract
|
2019-01-13 20:50:08 +01:00
|
|
|
};
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static const u16 *const *const sPrizeListSets[] =
|
2019-01-13 20:50:08 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
sPrizeLists1,
|
|
|
|
sPrizeLists2
|
2019-01-13 20:50:08 +01:00
|
|
|
};
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2020-06-24 22:27:00 +02:00
|
|
|
static const u16 sEReader_Pal[] = INCBIN_U16("graphics/misc/trainer_hill_ereader.gbapal");
|
2021-04-10 04:39:34 +02:00
|
|
|
static const u8 sRecordWinColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY};
|
2019-01-13 13:15:23 +01:00
|
|
|
|
|
|
|
static const struct TrHillTag *const sDataPerTag[] =
|
|
|
|
{
|
2019-01-19 12:57:18 +01:00
|
|
|
&sDataTagNormal,
|
|
|
|
&sDataTagVariety,
|
|
|
|
&sDataTagUnique,
|
|
|
|
&sDataTagExpert,
|
2019-01-13 13:15:23 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// Unused.
|
|
|
|
static const u8 *const sFloorStrings[] =
|
|
|
|
{
|
|
|
|
gText_TrainerHill1F,
|
|
|
|
gText_TrainerHill2F,
|
|
|
|
gText_TrainerHill3F,
|
|
|
|
gText_TrainerHill4F,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void (* const sHillFunctions[])(void) =
|
|
|
|
{
|
2019-11-23 22:08:50 +01:00
|
|
|
[TRAINER_HILL_FUNC_START] = TrainerHillStartChallenge,
|
|
|
|
[TRAINER_HILL_FUNC_GET_OWNER_STATE] = GetOwnerState,
|
|
|
|
[TRAINER_HILL_FUNC_GIVE_PRIZE] = GiveChallengePrize,
|
|
|
|
[TRAINER_HILL_FUNC_CHECK_FINAL_TIME] = CheckFinalTime,
|
|
|
|
[TRAINER_HILL_FUNC_RESUME_TIMER] = TrainerHillResumeTimer,
|
|
|
|
[TRAINER_HILL_FUNC_SET_LOST] = TrainerHillSetPlayerLost,
|
|
|
|
[TRAINER_HILL_FUNC_GET_CHALLENGE_STATUS] = TrainerHillGetChallengeStatus,
|
|
|
|
[TRAINER_HILL_FUNC_GET_CHALLENGE_TIME] = BufferChallengeTime,
|
|
|
|
[TRAINER_HILL_FUNC_GET_ALL_FLOORS_USED] = GetAllFloorsUsed,
|
2020-06-24 22:27:00 +02:00
|
|
|
[TRAINER_HILL_FUNC_GET_IN_EREADER_MODE] = GetInEReaderMode,
|
2019-11-23 22:08:50 +01:00
|
|
|
[TRAINER_HILL_FUNC_IN_CHALLENGE] = IsTrainerHillChallengeActive,
|
|
|
|
[TRAINER_HILL_FUNC_POST_BATTLE_TEXT] = ShowTrainerHillPostBattleText,
|
2019-11-13 22:10:05 +01:00
|
|
|
[TRAINER_HILL_FUNC_SET_ALL_TRAINER_FLAGS] = SetAllTrainerFlags,
|
2019-11-23 22:08:50 +01:00
|
|
|
[TRAINER_HILL_FUNC_GET_GAME_SAVED] = GetGameSaved,
|
|
|
|
[TRAINER_HILL_FUNC_SET_GAME_SAVED] = SetGameSaved,
|
|
|
|
[TRAINER_HILL_FUNC_CLEAR_GAME_SAVED] = ClearGameSaved,
|
|
|
|
[TRAINER_HILL_FUNC_GET_WON] = GetChallengeWon,
|
|
|
|
[TRAINER_HILL_FUNC_SET_TAG] = TrainerHillSetTag,
|
2019-01-13 13:15:23 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static const u8 *const sTagMatchStrings[] =
|
|
|
|
{
|
|
|
|
gText_NormalTagMatch,
|
|
|
|
gText_VarietyTagMatch,
|
|
|
|
gText_UniqueTagMatch,
|
|
|
|
gText_ExpertTagMatch,
|
|
|
|
};
|
|
|
|
|
2019-11-21 04:55:44 +01:00
|
|
|
static const struct ObjectEventTemplate sTrainerObjectEventTemplate =
|
2019-01-13 13:15:23 +01:00
|
|
|
{
|
2019-11-21 05:12:51 +01:00
|
|
|
.graphicsId = OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL,
|
2019-01-13 13:15:23 +01:00
|
|
|
.elevation = 3,
|
|
|
|
.movementType = MOVEMENT_TYPE_LOOK_AROUND,
|
|
|
|
.movementRangeX = 1,
|
|
|
|
.movementRangeY = 1,
|
2020-04-21 21:53:48 +02:00
|
|
|
.trainerType = TRAINER_TYPE_NORMAL,
|
2019-01-13 13:15:23 +01:00
|
|
|
};
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static const u32 sNextFloorMapNum[NUM_TRAINER_HILL_FLOORS] =
|
|
|
|
{
|
|
|
|
MAP_NUM(TRAINER_HILL_2F),
|
|
|
|
MAP_NUM(TRAINER_HILL_3F),
|
|
|
|
MAP_NUM(TRAINER_HILL_4F),
|
|
|
|
MAP_NUM(TRAINER_HILL_ROOF)
|
|
|
|
};
|
|
|
|
static const u8 sTrainerPartySlots[][PARTY_SIZE / 2] =
|
|
|
|
{
|
|
|
|
{0, 1, 2},
|
|
|
|
{3, 4, 5}
|
|
|
|
};
|
2019-01-13 13:15:23 +01:00
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
// code
|
2019-01-13 13:15:23 +01:00
|
|
|
void CallTrainerHillFunction(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
|
|
|
sHillFunctions[gSpecialVar_0x8004]();
|
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
void ResetTrainerHillResults(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
s32 i;
|
|
|
|
|
2019-11-13 22:31:01 +01:00
|
|
|
gSaveBlock2Ptr->frontier.savedGame = 0;
|
2019-11-16 19:45:21 +01:00
|
|
|
gSaveBlock2Ptr->frontier.unk_EF9 = 0;
|
2019-02-28 04:16:01 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.bestTime = 0;
|
2019-01-13 12:12:27 +01:00
|
|
|
for (i = 0; i < 4; i++)
|
2019-01-13 13:15:23 +01:00
|
|
|
SetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i], HILL_MAX_TIME);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
static u8 GetFloorId(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-31 22:51:20 +01:00
|
|
|
return gMapHeader.mapLayoutId - LAYOUT_TRAINER_HILL_1F;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
u8 GetTrainerHillOpponentClass(u16 trainerId)
|
|
|
|
{
|
|
|
|
u8 id = trainerId - 1;
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
return gFacilityClassToTrainerClass[sRoomTrainers->facilityClass[id]];
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GetTrainerHillTrainerName(u8 *dst, u16 trainerId)
|
|
|
|
{
|
|
|
|
s32 i;
|
|
|
|
u8 id = trainerId - 1;
|
|
|
|
|
|
|
|
for (i = 0; i < HILL_TRAINER_NAME_LENGTH; i++)
|
2019-01-13 13:15:23 +01:00
|
|
|
dst[i] = sRoomTrainers->name[id][i];
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
u8 GetTrainerHillTrainerFrontSpriteId(u16 trainerId)
|
|
|
|
{
|
|
|
|
u8 id, facilityClass;
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
id = trainerId - 1;
|
2019-09-04 21:42:53 +02:00
|
|
|
facilityClass = sHillData->floors[sHillData->floorId].trainers[id].facilityClass;
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
|
|
|
|
return gFacilityClassToPicIndex[facilityClass];
|
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
void InitTrainerHillBattleStruct(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
s32 i, j;
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
|
|
|
sRoomTrainers = AllocZeroed(sizeof(*sRoomTrainers));
|
2019-01-13 12:12:27 +01:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < HILL_TRAINER_NAME_LENGTH; j++)
|
|
|
|
{
|
2019-09-04 21:42:53 +02:00
|
|
|
sRoomTrainers->name[i][j] = sHillData->floors[sHillData->floorId].trainers[i].name[j];
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
2019-09-04 21:42:53 +02:00
|
|
|
sRoomTrainers->facilityClass[i] = sHillData->floors[sHillData->floorId].trainers[i].facilityClass;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
2019-03-01 07:49:11 +01:00
|
|
|
SetTrainerHillVBlankCounter(&gSaveBlock1Ptr->trainerHill.timer);
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
void FreeTrainerHillBattleStruct(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
if (sRoomTrainers != NULL)
|
|
|
|
FREE_AND_SET_NULL(sRoomTrainers);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
static void SetUpDataStruct(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
if (sHillData == NULL)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
Undo PokeCodec's PRs
This commit undoes most of PokeCodec's PRs after the debate in chat. Some
harmless or completely superseded PRs have been left alone, as there is not
much benefit in attempting to undo them.
Reverts #1104, #1108, #1115, #1118, #1119, #1124, #1126, #1127, #1132, #1136,
#1137, #1139, #1140, #1144, #1148, #1149, #1150, #1153, #1155, #1177, #1179,
#1180, #1181, #1182 and #1183.
2020-09-13 09:22:50 +02:00
|
|
|
sHillData = AllocZeroed(sizeof(*sHillData));
|
2019-01-31 22:51:20 +01:00
|
|
|
sHillData->floorId = gMapHeader.mapLayoutId - LAYOUT_TRAINER_HILL_1F;
|
2019-09-04 21:42:53 +02:00
|
|
|
CpuCopy32(sDataPerTag[gSaveBlock1Ptr->trainerHill.tag], &sHillData->tag, sizeof(sHillData->tag) + 4 * sizeof(struct TrHillFloor));
|
2021-03-21 04:47:08 +01:00
|
|
|
TrainerHillDummy();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
static void FreeDataStruct(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
if (sHillData != NULL)
|
|
|
|
FREE_AND_SET_NULL(sHillData);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CopyTrainerHillTrainerText(u8 which, u16 trainerId)
|
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
u8 id, floorId;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
|
|
|
floorId = GetFloorId();
|
2019-01-13 12:12:27 +01:00
|
|
|
id = trainerId - 1;
|
|
|
|
|
|
|
|
switch (which)
|
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
case TRAINER_HILL_TEXT_INTRO:
|
2019-09-04 21:42:53 +02:00
|
|
|
FrontierSpeechToString(sHillData->floors[floorId].trainers[id].speechBefore);
|
2019-01-13 12:12:27 +01:00
|
|
|
break;
|
2019-11-13 22:10:05 +01:00
|
|
|
case TRAINER_HILL_TEXT_PLAYER_LOST:
|
2019-09-04 21:42:53 +02:00
|
|
|
FrontierSpeechToString(sHillData->floors[floorId].trainers[id].speechWin);
|
2019-01-13 12:12:27 +01:00
|
|
|
break;
|
2019-11-13 22:10:05 +01:00
|
|
|
case TRAINER_HILL_TEXT_PLAYER_WON:
|
2019-09-04 21:42:53 +02:00
|
|
|
FrontierSpeechToString(sHillData->floors[floorId].trainers[id].speechLose);
|
2019-01-13 12:12:27 +01:00
|
|
|
break;
|
2019-11-13 22:10:05 +01:00
|
|
|
case TRAINER_HILL_TEXT_AFTER:
|
2019-09-04 21:42:53 +02:00
|
|
|
FrontierSpeechToString(sHillData->floors[floorId].trainers[id].speechAfter);
|
2019-01-13 12:12:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-02-28 03:28:34 +01:00
|
|
|
static void TrainerHillStartChallenge(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2021-03-21 04:47:08 +01:00
|
|
|
TrainerHillDummy();
|
2019-04-04 17:55:18 +02:00
|
|
|
if (!ReadTrainerHillAndValidate())
|
2019-01-13 12:12:27 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.field_3D6E_0f = 1;
|
|
|
|
else
|
|
|
|
gSaveBlock1Ptr->trainerHill.field_3D6E_0f = 0;
|
|
|
|
|
2019-11-16 19:45:21 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.unk_3D6C = 0;
|
2019-03-01 07:49:11 +01:00
|
|
|
SetTrainerHillVBlankCounter(&gSaveBlock1Ptr->trainerHill.timer);
|
2019-02-28 03:28:34 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.timer = 0;
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.spokeToOwner = 0;
|
|
|
|
gSaveBlock1Ptr->trainerHill.checkedFinalTime = 0;
|
2019-02-28 04:16:01 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.maybeECardScanDuringChallenge = 0;
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock2Ptr->frontier.trainerFlags = 0;
|
2019-01-13 12:12:27 +01:00
|
|
|
gBattleOutcome = 0;
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.receivedPrize = 0;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void GetOwnerState(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-03-01 07:49:11 +01:00
|
|
|
ClearTrainerHillVBlankCounter();
|
2019-01-13 12:12:27 +01:00
|
|
|
gSpecialVar_Result = 0;
|
2019-11-13 22:10:05 +01:00
|
|
|
if (gSaveBlock1Ptr->trainerHill.spokeToOwner)
|
2019-01-13 12:12:27 +01:00
|
|
|
gSpecialVar_Result++;
|
2019-11-13 22:10:05 +01:00
|
|
|
if (gSaveBlock1Ptr->trainerHill.receivedPrize && gSaveBlock1Ptr->trainerHill.checkedFinalTime)
|
2019-01-13 12:12:27 +01:00
|
|
|
gSpecialVar_Result++;
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.spokeToOwner = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void GiveChallengePrize(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
u16 itemId = GetPrizeItemId();
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS || gSaveBlock1Ptr->trainerHill.receivedPrize)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
gSpecialVar_Result = 2;
|
|
|
|
}
|
|
|
|
else if (AddBagItem(itemId, 1) == TRUE)
|
|
|
|
{
|
|
|
|
CopyItemName(itemId, gStringVar2);
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.receivedPrize = TRUE;
|
2019-11-16 19:45:21 +01:00
|
|
|
gSaveBlock2Ptr->frontier.unk_EF9 = 0;
|
2019-01-13 12:12:27 +01:00
|
|
|
gSpecialVar_Result = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gSpecialVar_Result = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-16 19:54:50 +01:00
|
|
|
// If bestTime > timer, the challenge was completed faster and its a new record
|
|
|
|
// Otherwise the owner says it was a slow time and to complete it faster next time
|
2019-11-13 22:10:05 +01:00
|
|
|
static void CheckFinalTime(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
if (gSaveBlock1Ptr->trainerHill.checkedFinalTime)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
gSpecialVar_Result = 2;
|
|
|
|
}
|
2019-02-28 04:16:01 +01:00
|
|
|
else if (GetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime) > gSaveBlock1Ptr->trainerHill.timer)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-28 04:16:01 +01:00
|
|
|
SetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime, gSaveBlock1Ptr->trainerHill.timer);
|
|
|
|
gSaveBlock1Ptr->trainerHillTimes[gSaveBlock1Ptr->trainerHill.tag] = gSaveBlock1Ptr->trainerHill.bestTime;
|
2019-01-13 12:12:27 +01:00
|
|
|
gSpecialVar_Result = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gSpecialVar_Result = 1;
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.checkedFinalTime = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-02-28 03:28:34 +01:00
|
|
|
static void TrainerHillResumeTimer(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
if (!gSaveBlock1Ptr->trainerHill.spokeToOwner)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-28 03:28:34 +01:00
|
|
|
if (gSaveBlock1Ptr->trainerHill.timer >= HILL_MAX_TIME)
|
|
|
|
gSaveBlock1Ptr->trainerHill.timer = HILL_MAX_TIME;
|
2019-01-13 12:12:27 +01:00
|
|
|
else
|
2019-03-01 07:49:11 +01:00
|
|
|
SetTrainerHillVBlankCounter(&gSaveBlock1Ptr->trainerHill.timer);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-28 03:28:34 +01:00
|
|
|
static void TrainerHillSetPlayerLost(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.hasLost = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-02-28 04:16:01 +01:00
|
|
|
static void TrainerHillGetChallengeStatus(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-28 03:28:34 +01:00
|
|
|
if (gSaveBlock1Ptr->trainerHill.hasLost)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-28 04:16:01 +01:00
|
|
|
// The player lost their last match.
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.hasLost = FALSE;
|
2019-02-28 04:16:01 +01:00
|
|
|
gSpecialVar_Result = TRAINER_HILL_PLAYER_STATUS_LOST;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
2019-02-28 04:16:01 +01:00
|
|
|
else if (gSaveBlock1Ptr->trainerHill.maybeECardScanDuringChallenge)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-28 04:16:01 +01:00
|
|
|
// Unreachable code. Something relating to eCards?
|
|
|
|
gSaveBlock1Ptr->trainerHill.maybeECardScanDuringChallenge = 0;
|
|
|
|
gSpecialVar_Result = TRAINER_HILL_PLAYER_STATUS_ECARD_SCANNED;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-02-28 04:16:01 +01:00
|
|
|
// Continue playing.
|
|
|
|
gSpecialVar_Result = TRAINER_HILL_PLAYER_STATUS_NORMAL;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void BufferChallengeTime(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
s32 total, minutes, secondsWhole, secondsFraction;
|
|
|
|
|
2019-02-28 03:28:34 +01:00
|
|
|
total = gSaveBlock1Ptr->trainerHill.timer;
|
2019-01-13 12:12:27 +01:00
|
|
|
if (total >= HILL_MAX_TIME)
|
|
|
|
total = HILL_MAX_TIME;
|
|
|
|
|
|
|
|
minutes = total / (60 * 60);
|
|
|
|
total %= (60 * 60);
|
|
|
|
secondsWhole = total / 60;
|
|
|
|
total %= 60;
|
|
|
|
secondsFraction = (total * 168) / 100;
|
|
|
|
|
|
|
|
ConvertIntToDecimalStringN(gStringVar1, minutes, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
|
|
|
ConvertIntToDecimalStringN(gStringVar2, secondsWhole, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
|
|
|
ConvertIntToDecimalStringN(gStringVar3, secondsFraction, STR_CONV_MODE_LEADING_ZEROS, 2);
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
// Returns TRUE if all 4 floors are used
|
|
|
|
// Returns FALSE otherwise, and buffers the number of floors used
|
2019-11-13 22:31:01 +01:00
|
|
|
// The only time fewer than all 4 floors are used is for the JP-exclusive E-Reader and Default modes
|
2019-11-13 22:10:05 +01:00
|
|
|
static void GetAllFloorsUsed(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-11-13 22:10:05 +01:00
|
|
|
if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-09-04 21:42:53 +02:00
|
|
|
ConvertIntToDecimalStringN(gStringVar1, sHillData->tag.numFloors, STR_CONV_MODE_LEFT_ALIGN, 1);
|
2019-11-13 22:10:05 +01:00
|
|
|
gSpecialVar_Result = FALSE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSpecialVar_Result = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
// May have been dummied. Every time this is called a conditional for var result occurs afterwards
|
2020-06-24 22:27:00 +02:00
|
|
|
// Relation to E-Reader is an assumption, most dummied Trainer Hill code seems to be JP E-Reader mode related
|
|
|
|
static void GetInEReaderMode(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2020-06-24 22:27:00 +02:00
|
|
|
gSpecialVar_Result = FALSE;
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-10-07 02:04:30 +02:00
|
|
|
bool8 InTrainerHillChallenge(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-28 04:16:01 +01:00
|
|
|
if (VarGet(VAR_TRAINER_HILL_IS_ACTIVE) == 0)
|
2019-01-13 12:12:27 +01:00
|
|
|
return FALSE;
|
2019-11-13 22:10:05 +01:00
|
|
|
else if (gSaveBlock1Ptr->trainerHill.spokeToOwner)
|
2019-01-13 12:12:27 +01:00
|
|
|
return FALSE;
|
|
|
|
else if (GetCurrentTrainerHillMapId() != 0)
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void IsTrainerHillChallengeActive(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-10-07 02:04:30 +02:00
|
|
|
if (!InTrainerHillChallenge())
|
2019-11-13 22:10:05 +01:00
|
|
|
gSpecialVar_Result = FALSE;
|
2019-01-13 12:12:27 +01:00
|
|
|
else
|
2019-11-13 22:10:05 +01:00
|
|
|
gSpecialVar_Result = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2021-03-21 04:47:08 +01:00
|
|
|
static void TrainerHillDummy_Unused(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-03-21 04:47:08 +01:00
|
|
|
static void TrainerHillDummy(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void PrintOnTrainerHillRecordsWindow(void)
|
|
|
|
{
|
|
|
|
s32 i, x, y;
|
|
|
|
u32 total, minutes, secondsWhole, secondsFraction;
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-03-02 23:25:39 +01:00
|
|
|
FillWindowPixelBuffer(0, PIXEL_FILL(0));
|
2019-01-13 12:12:27 +01:00
|
|
|
x = GetStringCenterAlignXOffset(1, gText_TimeBoard, 0xD0);
|
2019-01-13 13:15:23 +01:00
|
|
|
AddTextPrinterParameterized3(0, 1, x, 2, sRecordWinColors, TEXT_SPEED_FF, gText_TimeBoard);
|
2019-01-13 12:12:27 +01:00
|
|
|
|
|
|
|
y = 18;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
AddTextPrinterParameterized3(0, 1, 0, y, sRecordWinColors, TEXT_SPEED_FF, sTagMatchStrings[i]);
|
2019-01-13 12:12:27 +01:00
|
|
|
y += 15;
|
2019-01-13 13:15:23 +01:00
|
|
|
total = GetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i]);
|
2019-01-13 12:12:27 +01:00
|
|
|
minutes = total / (60 * 60);
|
|
|
|
total %= (60 * 60);
|
|
|
|
ConvertIntToDecimalStringN(gStringVar1, minutes, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
|
|
|
secondsWhole = total / 60;
|
|
|
|
total %= 60;
|
|
|
|
ConvertIntToDecimalStringN(gStringVar2, secondsWhole, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
|
|
|
secondsFraction = (total * 168) / 100;
|
|
|
|
ConvertIntToDecimalStringN(gStringVar3, secondsFraction, STR_CONV_MODE_LEADING_ZEROS, 2);
|
|
|
|
StringExpandPlaceholders(StringCopy(gStringVar4, gText_TimeCleared), gText_XMinYDotZSec);
|
|
|
|
x = GetStringRightAlignXOffset(1, gStringVar4, 0xD0);
|
2019-01-13 13:15:23 +01:00
|
|
|
AddTextPrinterParameterized3(0, 1, x, y, sRecordWinColors, TEXT_SPEED_FF, gStringVar4);
|
2019-01-13 12:12:27 +01:00
|
|
|
y += 17;
|
|
|
|
}
|
|
|
|
|
|
|
|
PutWindowTilemap(0);
|
|
|
|
CopyWindowToVram(0, 3);
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
// Leftover from Fire Red / Leaf Green as in these games,
|
|
|
|
// the timer had to be xored by the encryption key in Sav2.
|
2019-01-13 20:50:08 +01:00
|
|
|
static u32 GetTimerValue(u32 *src)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
return *src;
|
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
static void SetTimerValue(u32 *dst, u32 val)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
*dst = val;
|
|
|
|
}
|
|
|
|
|
2019-11-21 04:55:44 +01:00
|
|
|
void LoadTrainerHillObjectEventTemplates(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
u8 i, floorId;
|
2019-11-21 04:55:44 +01:00
|
|
|
struct ObjectEventTemplate *eventTemplates = gSaveBlock1Ptr->objectEventTemplates;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-21 04:55:44 +01:00
|
|
|
if (!LoadTrainerHillFloorObjectEventScripts())
|
2019-01-13 12:12:27 +01:00
|
|
|
return;
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
for (i = 0; i < 2; i++)
|
2019-02-07 18:37:28 +01:00
|
|
|
gSaveBlock2Ptr->frontier.trainerIds[i] = 0xFFFF;
|
2019-11-21 04:55:44 +01:00
|
|
|
CpuFill32(0, gSaveBlock1Ptr->objectEventTemplates, sizeof(gSaveBlock1Ptr->objectEventTemplates));
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
floorId = GetFloorId();
|
2019-01-13 12:12:27 +01:00
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
u8 bits;
|
|
|
|
|
2019-11-21 04:55:44 +01:00
|
|
|
eventTemplates[i] = sTrainerObjectEventTemplate;
|
2019-01-13 12:12:27 +01:00
|
|
|
eventTemplates[i].localId = i + 1;
|
2019-09-04 21:42:53 +02:00
|
|
|
eventTemplates[i].graphicsId = FacilityClassToGraphicsId(sHillData->floors[floorId].trainers[i].facilityClass);
|
|
|
|
eventTemplates[i].x = sHillData->floors[floorId].display.coords[i] & 0xF;
|
|
|
|
eventTemplates[i].y = ((sHillData->floors[floorId].display.coords[i] >> 4) & 0xF) + 5;
|
2019-01-13 12:12:27 +01:00
|
|
|
bits = i << 2;
|
2019-09-04 21:42:53 +02:00
|
|
|
eventTemplates[i].movementType = ((sHillData->floors[floorId].display.direction >> bits) & 0xF) + MOVEMENT_TYPE_FACE_UP;
|
|
|
|
eventTemplates[i].trainerRange_berryTreeId = (sHillData->floors[floorId].display.range >> bits) & 0xF;
|
2019-11-13 22:10:05 +01:00
|
|
|
eventTemplates[i].script = TrainerHill_EventScript_TrainerBattle;
|
2019-02-07 18:37:28 +01:00
|
|
|
gSaveBlock2Ptr->frontier.trainerIds[i] = i + 1;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-21 04:55:44 +01:00
|
|
|
bool32 LoadTrainerHillFloorObjectEventScripts(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-11-13 22:10:05 +01:00
|
|
|
// Something may have been dummied here
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-10-26 16:31:07 +01:00
|
|
|
static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 stride) // stride is always 16
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2020-09-20 07:50:54 +02:00
|
|
|
bool8 impassable;
|
|
|
|
u16 metatile;
|
|
|
|
u16 elevation;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2020-10-26 16:31:07 +01:00
|
|
|
impassable = (sHillData->floors[floorId].display.collisionData[y] >> (15 - x) & 1);
|
2021-04-29 22:08:43 +02:00
|
|
|
metatile = sHillData->floors[floorId].display.metatileData[stride * y + x] + NUM_METATILES_IN_PRIMARY;
|
|
|
|
elevation = 3 << METATILE_ELEVATION_SHIFT;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2021-04-29 22:08:43 +02:00
|
|
|
return ((impassable << METATILE_COLLISION_SHIFT) & METATILE_COLLISION_MASK) | elevation | (metatile & METATILE_ID_MASK);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
void GenerateTrainerHillFloorLayout(u16 *mapArg)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
s32 i, j;
|
|
|
|
u16 *src, *dst;
|
2019-01-13 13:15:23 +01:00
|
|
|
u8 mapId = GetCurrentTrainerHillMapId();
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
if (mapId == TRAINER_HILL_ENTRANCE)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
InitMapFromSavedGame();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-11-13 22:10:05 +01:00
|
|
|
if (mapId == TRAINER_HILL_ROOF)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
InitMapFromSavedGame();
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
mapId = GetFloorId();
|
2019-01-13 12:12:27 +01:00
|
|
|
src = gMapHeader.mapLayout->map;
|
|
|
|
gBackupMapLayout.map = mapArg;
|
|
|
|
gBackupMapLayout.width = 31;
|
|
|
|
gBackupMapLayout.height = 35;
|
|
|
|
dst = mapArg + 224;
|
2021-04-29 22:08:43 +02:00
|
|
|
|
|
|
|
// First 5 rows of the map (Entrance / Exit) are always the same
|
2019-01-13 12:12:27 +01:00
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < 16; j++)
|
|
|
|
dst[j] = src[j];
|
|
|
|
dst += 31;
|
|
|
|
src += 16;
|
|
|
|
}
|
|
|
|
|
2021-04-29 22:08:43 +02:00
|
|
|
// Load the 16x16 floor-specific layout
|
2019-01-13 12:12:27 +01:00
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < 16; j++)
|
2021-04-29 22:08:43 +02:00
|
|
|
dst[j] = GetMetatileForFloor(mapId, j, i, 16);
|
2019-01-13 12:12:27 +01:00
|
|
|
dst += 31;
|
|
|
|
}
|
|
|
|
|
2019-02-22 08:23:46 +01:00
|
|
|
RunOnLoadMapScript();
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool32 InTrainerHill(void)
|
|
|
|
{
|
|
|
|
bool32 ret;
|
|
|
|
|
2019-01-31 22:51:20 +01:00
|
|
|
if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_1F
|
2019-11-13 22:10:05 +01:00
|
|
|
|| gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_2F
|
|
|
|
|| gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_3F
|
|
|
|
|| gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_4F)
|
2019-01-13 12:12:27 +01:00
|
|
|
ret = TRUE;
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
u8 GetCurrentTrainerHillMapId(void)
|
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
u8 mapId;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-01-31 22:51:20 +01:00
|
|
|
if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_1F)
|
2019-11-13 22:10:05 +01:00
|
|
|
mapId = TRAINER_HILL_1F;
|
2019-01-31 22:51:20 +01:00
|
|
|
else if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_2F)
|
2019-11-13 22:10:05 +01:00
|
|
|
mapId = TRAINER_HILL_2F;
|
2019-01-31 22:51:20 +01:00
|
|
|
else if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_3F)
|
2019-11-13 22:10:05 +01:00
|
|
|
mapId = TRAINER_HILL_3F;
|
2019-01-31 22:51:20 +01:00
|
|
|
else if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_4F)
|
2019-11-13 22:10:05 +01:00
|
|
|
mapId = TRAINER_HILL_4F;
|
2019-01-31 22:51:20 +01:00
|
|
|
else if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_ROOF)
|
2019-11-13 22:10:05 +01:00
|
|
|
mapId = TRAINER_HILL_ROOF;
|
2019-01-31 22:51:20 +01:00
|
|
|
else if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_ENTRANCE)
|
2019-11-13 22:10:05 +01:00
|
|
|
mapId = TRAINER_HILL_ENTRANCE;
|
2019-01-13 12:12:27 +01:00
|
|
|
else
|
2019-11-13 22:10:05 +01:00
|
|
|
mapId = 0;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
return mapId;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
// Unused
|
|
|
|
static bool32 OnTrainerHillRoof(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
bool32 onRoof;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-01-31 22:51:20 +01:00
|
|
|
if (gMapHeader.mapLayoutId == LAYOUT_TRAINER_HILL_ROOF)
|
2019-11-13 22:10:05 +01:00
|
|
|
onRoof = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
else
|
2019-11-13 22:10:05 +01:00
|
|
|
onRoof = FALSE;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
return onRoof;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
const struct WarpEvent* SetWarpDestinationTrainerHill4F(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
const struct MapHeader *header = Overworld_GetMapHeaderByGroupAndId(MAP_GROUP(TRAINER_HILL_4F), MAP_NUM(TRAINER_HILL_4F));
|
|
|
|
|
|
|
|
return &header->events->warps[1];
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
// For warping from the roof in challenges where the 4F is not the final challenge floor
|
2019-11-13 22:31:01 +01:00
|
|
|
// This would only occur in the JP-exclusive Default and E-Reader challenges
|
2019-11-13 22:10:05 +01:00
|
|
|
const struct WarpEvent* SetWarpDestinationTrainerHillFinalFloor(u8 warpEventId)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
u8 numFloors;
|
2019-01-13 12:12:27 +01:00
|
|
|
const struct MapHeader *header;
|
|
|
|
|
|
|
|
if (warpEventId == 1)
|
|
|
|
return &gMapHeader.events->warps[1];
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
numFloors = GetNumFloorsInTrainerHillChallenge();
|
|
|
|
if (numFloors == 0 || numFloors > NUM_TRAINER_HILL_FLOORS)
|
|
|
|
numFloors = NUM_TRAINER_HILL_FLOORS;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
header = Overworld_GetMapHeaderByGroupAndId(MAP_GROUP(TRAINER_HILL_4F), sNextFloorMapNum[numFloors - 1]);
|
2019-01-13 12:12:27 +01:00
|
|
|
return &header->events->warps[0];
|
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
u16 LocalIdToHillTrainerId(u8 localId)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-07 18:37:28 +01:00
|
|
|
return gSaveBlock2Ptr->frontier.trainerIds[localId - 1];
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-21 04:55:44 +01:00
|
|
|
bool8 GetHillTrainerFlag(u8 objectEventId)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
u32 floorId = GetFloorId() * 2;
|
2019-11-21 04:55:44 +01:00
|
|
|
u8 bitId = gObjectEvents[objectEventId].localId - 1 + floorId;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
return gSaveBlock2Ptr->frontier.trainerFlags & gBitTable[bitId];
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
void SetHillTrainerFlag(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
u8 i;
|
2019-01-13 13:15:23 +01:00
|
|
|
u8 floorId = GetFloorId() * 2;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
2019-02-07 18:37:28 +01:00
|
|
|
if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_A)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i];
|
2019-01-13 12:12:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
|
|
|
{
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
2019-02-07 18:37:28 +01:00
|
|
|
if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_B)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i];
|
2019-01-13 12:12:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-04 21:35:35 +02:00
|
|
|
const u8 *GetTrainerHillTrainerScript(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
return TrainerHill_EventScript_TrainerBattle;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void ShowTrainerHillPostBattleText(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
CopyTrainerHillTrainerText(TRAINER_HILL_TEXT_AFTER, gSpecialVar_LastTalked);
|
2020-06-04 00:25:16 +02:00
|
|
|
ShowFieldMessageFromBuffer();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void CreateNPCTrainerHillParty(u16 trainerId, u8 firstMonId)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
u8 trId, level;
|
2019-11-13 22:10:05 +01:00
|
|
|
s32 i, floorId, partySlot;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-01-14 20:57:44 +01:00
|
|
|
if (trainerId == 0 || trainerId > 2)
|
2019-01-13 12:12:27 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
trId = trainerId - 1;
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
level = GetHighestLevelInPlayerParty();
|
2019-01-13 13:15:23 +01:00
|
|
|
floorId = GetFloorId();
|
2019-11-13 22:10:05 +01:00
|
|
|
for (i = firstMonId, partySlot = 0; i < firstMonId + 3; i++, partySlot++)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
u8 id = sTrainerPartySlots[trId][partySlot];
|
2019-01-13 12:12:27 +01:00
|
|
|
struct Pokemon *mon = &gEnemyParty[i];
|
|
|
|
|
2019-09-04 21:42:53 +02:00
|
|
|
CreateBattleTowerMon(mon, &sHillData->floors[floorId].trainers[trId].mons[id]);
|
2019-11-13 22:10:05 +01:00
|
|
|
SetTrainerHillMonLevel(mon, level);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
void FillHillTrainerParty(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
ZeroEnemyPartyMons();
|
2019-11-13 22:10:05 +01:00
|
|
|
CreateNPCTrainerHillParty(gTrainerBattleOpponent_A, 0);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
void FillHillTrainersParties(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
ZeroEnemyPartyMons();
|
2019-11-13 22:10:05 +01:00
|
|
|
CreateNPCTrainerHillParty(gTrainerBattleOpponent_A, 0);
|
|
|
|
CreateNPCTrainerHillParty(gTrainerBattleOpponent_B, 3);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// This function is unused, but my best guess is
|
|
|
|
// it was supposed to return AI scripts for trainer
|
|
|
|
// hill trainers.
|
2019-11-13 22:10:05 +01:00
|
|
|
u32 GetTrainerHillAIFlags(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
return (AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:50:08 +01:00
|
|
|
u8 GetTrainerEncounterMusicIdInTrainerHill(u16 trainerId)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
s32 i;
|
|
|
|
u8 trId, facilityClass;
|
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
trId = trainerId - 1;
|
2019-09-04 21:42:53 +02:00
|
|
|
facilityClass = sHillData->floors[sHillData->floorId].trainers[trId].facilityClass;
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
for (i = 0; i < ARRAY_COUNT(sTrainerClassesAndMusic); i++)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
if (sTrainerClassesAndMusic[i].trainerClass == gFacilityClassToTrainerClass[facilityClass])
|
|
|
|
return sTrainerClassesAndMusic[i].musicId;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void SetTrainerHillMonLevel(struct Pokemon *mon, u8 level)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
|
|
|
|
u32 exp = gExperienceTables[gBaseStats[species].growthRate][level];
|
|
|
|
|
|
|
|
SetMonData(mon, MON_DATA_EXP, &exp);
|
|
|
|
SetMonData(mon, MON_DATA_LEVEL, &level);
|
|
|
|
CalculateMonStats(mon);
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
u8 GetNumFloorsInTrainerHillChallenge(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
u8 floors;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
SetUpDataStruct();
|
2019-11-13 22:10:05 +01:00
|
|
|
floors = sHillData->tag.numFloors;
|
2019-01-13 13:15:23 +01:00
|
|
|
FreeDataStruct();
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
return floors;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void SetAllTrainerFlags(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock2Ptr->frontier.trainerFlags = 0xFF;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2020-06-24 22:27:00 +02:00
|
|
|
// Palette never loaded, OnTrainerHillEReaderChallengeFloor always FALSE
|
|
|
|
void TryLoadTrainerHillEReaderPalette(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2020-06-24 22:27:00 +02:00
|
|
|
if (OnTrainerHillEReaderChallengeFloor() == TRUE)
|
|
|
|
LoadPalette(sEReader_Pal, 0x70, 0x20);
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void GetGameSaved(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSpecialVar_Result = gSaveBlock2Ptr->frontier.savedGame;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void SetGameSaved(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock2Ptr->frontier.savedGame = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void ClearGameSaved(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
gSaveBlock2Ptr->frontier.savedGame = FALSE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
// Always FALSE
|
2020-06-24 22:27:00 +02:00
|
|
|
bool32 OnTrainerHillEReaderChallengeFloor(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
if (!InTrainerHillChallenge() || GetCurrentTrainerHillMapId() == TRAINER_HILL_ENTRANCE)
|
2019-01-13 12:12:27 +01:00
|
|
|
return FALSE;
|
|
|
|
|
2020-06-24 22:27:00 +02:00
|
|
|
GetInEReaderMode();
|
|
|
|
if (gSpecialVar_Result == FALSE)
|
2019-01-13 12:12:27 +01:00
|
|
|
return FALSE;
|
|
|
|
else
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static void GetChallengeWon(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-02-28 03:28:34 +01:00
|
|
|
if (gSaveBlock1Ptr->trainerHill.hasLost)
|
2019-11-13 22:10:05 +01:00
|
|
|
gSpecialVar_Result = FALSE;
|
2019-01-13 12:12:27 +01:00
|
|
|
else
|
2019-11-13 22:10:05 +01:00
|
|
|
gSpecialVar_Result = TRUE;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-02-28 04:16:01 +01:00
|
|
|
static void TrainerHillSetTag(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-01-13 13:15:23 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.tag = gSpecialVar_0x8005;
|
2019-02-28 04:16:01 +01:00
|
|
|
gSaveBlock1Ptr->trainerHill.bestTime = gSaveBlock1Ptr->trainerHillTimes[gSpecialVar_0x8005];
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:31:01 +01:00
|
|
|
static u8 GetPrizeListId(bool8 maxTrainers)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
u8 prizeListId, i, modBy;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
prizeListId = 0;
|
|
|
|
for (i = 0; i < NUM_TRAINER_HILL_FLOORS; i++)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
prizeListId ^= sHillData->floors[i].trainerNum1 & 0x1F;
|
|
|
|
prizeListId ^= sHillData->floors[i].trainerNum2 & 0x1F;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:31:01 +01:00
|
|
|
// Not possible to win TMs with fewer than 8 trainers
|
|
|
|
if (maxTrainers)
|
2019-11-13 22:10:05 +01:00
|
|
|
modBy = NUM_TRAINER_HILL_PRIZE_LISTS;
|
2019-01-13 12:12:27 +01:00
|
|
|
else
|
2019-11-13 22:10:05 +01:00
|
|
|
modBy = NUM_TRAINER_HILL_PRIZE_LISTS / 2;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
prizeListId %= modBy;
|
|
|
|
return prizeListId;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
static u16 GetPrizeItemId(void)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
|
|
|
u8 i;
|
2019-11-13 22:10:05 +01:00
|
|
|
const u16 *prizeList;
|
|
|
|
s32 var = 0, prizeListSetId, minutes, id;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
for (i = 0; i < NUM_TRAINER_HILL_FLOORS; i++)
|
2019-01-13 12:12:27 +01:00
|
|
|
{
|
2019-11-13 22:10:05 +01:00
|
|
|
var += sHillData->floors[i].trainerNum1;
|
|
|
|
var += sHillData->floors[i].trainerNum2;
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
prizeListSetId = var / 256;
|
|
|
|
prizeListSetId %= 2;
|
2019-11-13 22:31:01 +01:00
|
|
|
if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->tag.numTrainers == NUM_TRAINER_HILL_TRAINERS)
|
2019-11-13 22:10:05 +01:00
|
|
|
i = GetPrizeListId(TRUE);
|
2019-01-13 12:12:27 +01:00
|
|
|
else
|
2019-11-13 22:10:05 +01:00
|
|
|
i = GetPrizeListId(FALSE);
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-01-13 13:15:23 +01:00
|
|
|
if (gSaveBlock1Ptr->trainerHill.tag == HILL_TAG_EXPERT)
|
2019-11-13 22:10:05 +01:00
|
|
|
i = (i + 1) % NUM_TRAINER_HILL_PRIZE_LISTS;
|
2019-01-13 12:12:27 +01:00
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
prizeList = sPrizeListSets[prizeListSetId][i];
|
2019-02-28 03:28:34 +01:00
|
|
|
minutes = (signed)(gSaveBlock1Ptr->trainerHill.timer) / (60 * 60);
|
2019-01-13 12:12:27 +01:00
|
|
|
if (minutes < 12)
|
|
|
|
id = 0;
|
|
|
|
else if (minutes < 13)
|
|
|
|
id = 1;
|
|
|
|
else if (minutes < 14)
|
|
|
|
id = 2;
|
|
|
|
else if (minutes < 16)
|
|
|
|
id = 3;
|
|
|
|
else if (minutes < 18)
|
|
|
|
id = 4;
|
|
|
|
else
|
|
|
|
id = 5;
|
|
|
|
|
2019-11-13 22:10:05 +01:00
|
|
|
return prizeList[id];
|
2019-01-13 12:12:27 +01:00
|
|
|
}
|