summaryrefslogtreecommitdiff
path: root/src/trainer_hill.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/trainer_hill.c')
-rw-r--r--src/trainer_hill.c927
1 files changed, 927 insertions, 0 deletions
diff --git a/src/trainer_hill.c b/src/trainer_hill.c
new file mode 100644
index 000000000..4f3645963
--- /dev/null
+++ b/src/trainer_hill.c
@@ -0,0 +1,927 @@
+#include "global.h"
+#include "alloc.h"
+#include "battle.h"
+#include "battle_tower.h"
+#include "battle_setup.h"
+#include "event_data.h"
+#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"
+#include "text.h"
+#include "window.h"
+#include "util.h"
+#include "constants/event_object_movement_constants.h"
+#include "constants/maps.h"
+
+#define HILL_TRAINER_NAME_LENGTH 11
+#define HILL_MAX_TIME 215999 // 60 * 60 * 60 - 1
+
+struct TrHillStruct1
+{
+ u8 name[2][HILL_TRAINER_NAME_LENGTH];
+ u8 facilityClass[2];
+};
+
+struct TrainerHillTrainer
+{
+ u8 name[HILL_TRAINER_NAME_LENGTH];
+ u8 facilityClass;
+ u32 field_18;
+ u16 speechBefore[6];
+ u16 speechWin[6];
+ u16 speechLose[6];
+ u16 speechAfter[6];
+ struct BattleTowerPokemon mons[PARTY_SIZE];
+};
+
+struct TrHillStruct5
+{
+ u8 unk0;
+ u8 unk1;
+ struct TrainerHillTrainer trainers[2];
+ u8 data[0x100];
+ u16 unk3A0[2];
+ u8 data2[0x20 - 4];
+ u8 coords[2]; // x first 4 bits, y last 4 bites
+ u8 direction; // array of 4 bites for each trainer
+ u8 range; // array of 4 bites for each trainer
+};
+
+struct TrHillStruct4
+{
+ u8 unkField_0;
+ u8 unkField_1;
+ u8 unkField_2;
+ u8 unkField_3;
+ u8 unkField_4;
+ u8 unkField_5;
+ u8 unkField_6;
+ struct TrHillStruct5 unk0[4];
+};
+
+struct TrHillStruct2
+{
+ u8 layoutId;
+ struct TrHillStruct4 unk4;
+};
+
+extern struct TrHillStruct2 *gUnknown_0203CF54;
+extern struct TrHillStruct1 *gUnknown_0203CF58;
+
+// This file's functions.
+void sub_81D56B0(void);
+void sub_81D5710(void);
+bool32 sub_81D5F48(void);
+void nullsub_2(void);
+void sub_81D5DF4(u32 *dst, u32 val);
+bool32 sub_81D3B34(void);
+u16 sub_81D6640(void);
+u32 sub_81D5DF0(u32 *src);
+u8 GetCurrentTrainerHillMapId(void);
+u8 sub_81D6490(void);
+void sub_81D642C(struct Pokemon *mon, u8 level);
+bool32 sub_81D6534(void);
+
+// const data
+extern void (* const gUnknown_0862A618[])(void);
+extern const struct TrHillStruct4 *const gUnknown_0862A5F8[];
+extern const u16 gUnknown_0862A5D4[];
+extern const u8 gText_TimeBoard[];
+extern const u8 gText_TimeCleared[];
+extern const u8 gText_XMinYDotZSec[];
+extern const u8 gUnknown_0862A5F4[];
+
+extern const u8 *const gUnknown_0862A660[];
+extern const struct EventObjectTemplate gUnknown_0862A670;
+extern const u32 gUnknown_0862A688[4];
+extern const u8 gUnknown_0862A698[][3];
+extern const u16 *const *const gUnknown_0862A5CC[];
+struct
+{
+ u8 trainerClass;
+ u8 musicId;
+} extern const gUnknown_0862A3B4[0x36];
+
+extern const u8 EventScript_2C83F0[];
+
+void sp194_trainer_tower(void)
+{
+ sub_81D56B0();
+ gUnknown_0862A618[gSpecialVar_0x8004]();
+ sub_81D5710();
+}
+
+void sub_81D54BC(void)
+{
+ s32 i;
+
+ gSaveBlock2Ptr->frontier.field_EF9_1 = 0;
+ gSaveBlock2Ptr->frontier.field_EF9_0 = 0;
+ gSaveBlock1Ptr->trainerHill.field_3D68 = 0;
+ for (i = 0; i < 4; i++)
+ sub_81D5DF4(&gSaveBlock1Ptr->field_3718[i], HILL_MAX_TIME);
+}
+
+u8 sub_81D5520(void)
+{
+ return gMapHeader.mapLayoutId - 159;
+}
+
+u8 GetTrainerHillOpponentClass(u16 trainerId)
+{
+ u8 id = trainerId - 1;
+
+ return gFacilityClassToTrainerClass[gUnknown_0203CF58->facilityClass[id]];
+}
+
+void GetTrainerHillTrainerName(u8 *dst, u16 trainerId)
+{
+ s32 i;
+ u8 id = trainerId - 1;
+
+ for (i = 0; i < HILL_TRAINER_NAME_LENGTH; i++)
+ dst[i] = gUnknown_0203CF58->name[id][i];
+}
+
+u8 GetTrainerHillTrainerFrontSpriteId(u16 trainerId)
+{
+ u8 id, facilityClass;
+
+ sub_81D56B0();
+ id = trainerId - 1;
+ facilityClass = gUnknown_0203CF54->unk4.unk0[gUnknown_0203CF54->layoutId].trainers[id].facilityClass;
+ sub_81D5710();
+
+ return gFacilityClassToPicIndex[facilityClass];
+}
+
+void sub_81D55D0(void)
+{
+ s32 i, j;
+
+ sub_81D56B0();
+ gUnknown_0203CF58 = AllocZeroed(sizeof(*gUnknown_0203CF58));
+
+ for (i = 0; i < 2; i++)
+ {
+ for (j = 0; j < HILL_TRAINER_NAME_LENGTH; j++)
+ {
+ gUnknown_0203CF58->name[i][j] = gUnknown_0203CF54->unk4.unk0[gUnknown_0203CF54->layoutId].trainers[i].name[j];
+ }
+ gUnknown_0203CF58->facilityClass[i] = gUnknown_0203CF54->unk4.unk0[gUnknown_0203CF54->layoutId].trainers[i].facilityClass;
+ }
+ sub_80008DC(&gSaveBlock1Ptr->trainerHill.field_3D64);
+ sub_81D5710();
+}
+
+void sub_81D5694(void)
+{
+ if (gUnknown_0203CF58 != NULL)
+ FREE_AND_SET_NULL(gUnknown_0203CF58);
+}
+
+void sub_81D56B0(void)
+{
+ if (gUnknown_0203CF54 == NULL)
+ {
+ gUnknown_0203CF54 = AllocZeroed(sizeof(*gUnknown_0203CF54));
+ gUnknown_0203CF54->layoutId = gMapHeader.mapLayoutId - 159;
+ CpuCopy32(gUnknown_0862A5F8[gSaveBlock1Ptr->trainerHill.field_3D6E_1], &gUnknown_0203CF54->unk4, sizeof(gUnknown_0203CF54->unk4));
+ nullsub_2();
+ }
+}
+
+void sub_81D5710(void)
+{
+ if (gUnknown_0203CF54 != NULL)
+ FREE_AND_SET_NULL(gUnknown_0203CF54);
+}
+
+void CopyTrainerHillTrainerText(u8 which, u16 trainerId)
+{
+ u8 id, layoutId;
+
+ sub_81D56B0();
+ layoutId = sub_81D5520();
+ id = trainerId - 1;
+
+ switch (which)
+ {
+ case 2:
+ FrontierSpeechToString(gUnknown_0203CF54->unk4.unk0[layoutId].trainers[id].speechBefore);
+ break;
+ case 3:
+ FrontierSpeechToString(gUnknown_0203CF54->unk4.unk0[layoutId].trainers[id].speechWin);
+ break;
+ case 4:
+ FrontierSpeechToString(gUnknown_0203CF54->unk4.unk0[layoutId].trainers[id].speechLose);
+ break;
+ case 5:
+ FrontierSpeechToString(gUnknown_0203CF54->unk4.unk0[layoutId].trainers[id].speechAfter);
+ break;
+ }
+
+ sub_81D5710();
+}
+
+void sub_81D581C(void)
+{
+ nullsub_2();
+ if (!sub_81D3B34())
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0f = 1;
+ else
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0f = 0;
+
+ gSaveBlock1Ptr->trainerHill.field_3D6C = 0;
+ sub_80008DC(&gSaveBlock1Ptr->trainerHill.field_3D64);
+ gSaveBlock1Ptr->trainerHill.field_3D64 = 0;
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0c = 0;
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0b = 0;
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0e = 0;
+ gSaveBlock2Ptr->frontier.field_EE0 = 0;
+ gBattleOutcome = 0;
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0a = 0;
+}
+
+void sub_81D58D8(void)
+{
+ sub_80008E8();
+ gSpecialVar_Result = 0;
+ if (gSaveBlock1Ptr->trainerHill.field_3D6E_0c)
+ gSpecialVar_Result++;
+ if (gSaveBlock1Ptr->trainerHill.field_3D6E_0a && gSaveBlock1Ptr->trainerHill.field_3D6E_0b)
+ gSpecialVar_Result++;
+
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0c = 1;
+}
+
+void sub_81D5924(void)
+{
+ u16 itemId = sub_81D6640();
+
+ if (gUnknown_0203CF54->unk4.unkField_2 != 4 || gSaveBlock1Ptr->trainerHill.field_3D6E_0a)
+ {
+ gSpecialVar_Result = 2;
+ }
+ else if (AddBagItem(itemId, 1) == TRUE)
+ {
+ CopyItemName(itemId, gStringVar2);
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0a = 1;
+ gSaveBlock2Ptr->frontier.field_EF9_0 = 0;
+ gSpecialVar_Result = 0;
+ }
+ else
+ {
+ gSpecialVar_Result = 1;
+ }
+}
+
+void sub_81D59D0(void)
+{
+ if (gSaveBlock1Ptr->trainerHill.field_3D6E_0b)
+ {
+ gSpecialVar_Result = 2;
+ }
+ else if (sub_81D5DF0(&gSaveBlock1Ptr->trainerHill.field_3D68) > gSaveBlock1Ptr->trainerHill.field_3D64)
+ {
+ sub_81D5DF4(&gSaveBlock1Ptr->trainerHill.field_3D68, gSaveBlock1Ptr->trainerHill.field_3D64);
+ gSaveBlock1Ptr->field_3718[gSaveBlock1Ptr->trainerHill.field_3D6E_1] = gSaveBlock1Ptr->trainerHill.field_3D68;
+ gSpecialVar_Result = 0;
+ }
+ else
+ {
+ gSpecialVar_Result = 1;
+ }
+
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0b = 1;
+}
+
+void sub_81D5A70(void)
+{
+ if (!gSaveBlock1Ptr->trainerHill.field_3D6E_0c)
+ {
+ if (gSaveBlock1Ptr->trainerHill.field_3D64 >= HILL_MAX_TIME)
+ gSaveBlock1Ptr->trainerHill.field_3D64 = HILL_MAX_TIME;
+ else
+ sub_80008DC(&gSaveBlock1Ptr->trainerHill.field_3D64);
+ }
+}
+
+void sub_81D5AB4(void)
+{
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0d = 1;
+}
+
+void sub_81D5AD0(void)
+{
+ if (gSaveBlock1Ptr->trainerHill.field_3D6E_0d)
+ {
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0d = 0;
+ gSpecialVar_Result = 0;
+ }
+ else if (gSaveBlock1Ptr->trainerHill.field_3D6E_0e)
+ {
+ gSaveBlock1Ptr->trainerHill.field_3D6E_0e = 0;
+ gSpecialVar_Result = 1;
+ }
+ else
+ {
+ gSpecialVar_Result = 2;
+ }
+}
+
+void sub_81D5B2C(void)
+{
+ s32 total, minutes, secondsWhole, secondsFraction;
+
+ total = gSaveBlock1Ptr->trainerHill.field_3D64;
+ 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);
+}
+
+void sub_81D5BBC(void)
+{
+ sub_81D56B0();
+ if (gUnknown_0203CF54->unk4.unkField_2 != 4)
+ {
+ ConvertIntToDecimalStringN(gStringVar1, gUnknown_0203CF54->unk4.unkField_2, STR_CONV_MODE_LEFT_ALIGN, 1);
+ gSpecialVar_Result = 0;
+ }
+ else
+ {
+ gSpecialVar_Result = 1;
+ }
+
+ sub_81D5710();
+}
+
+void sub_81D5C00(void)
+{
+ sub_81D56B0();
+ gSpecialVar_Result = 0;
+ sub_81D5710();
+}
+
+bool8 sub_81D5C18(void)
+{
+ if (VarGet(VAR_0x40D6) == 0)
+ return FALSE;
+ else if (gSaveBlock1Ptr->trainerHill.field_3D6E_0c)
+ return FALSE;
+ else if (GetCurrentTrainerHillMapId() != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void sub_81D5C5C(void)
+{
+ if (!sub_81D5C18())
+ gSpecialVar_Result = 0;
+ else
+ gSpecialVar_Result = 1;
+}
+
+void nullsub_129(void)
+{
+
+}
+
+void nullsub_2(void)
+{
+
+}
+
+void PrintOnTrainerHillRecordsWindow(void)
+{
+ s32 i, x, y;
+ u32 total, minutes, secondsWhole, secondsFraction;
+
+ sub_81D56B0();
+ FillWindowPixelBuffer(0, 0);
+ x = GetStringCenterAlignXOffset(1, gText_TimeBoard, 0xD0);
+ AddTextPrinterParameterized3(0, 1, x, 2, gUnknown_0862A5F4, TEXT_SPEED_FF, gText_TimeBoard);
+
+ y = 18;
+ for (i = 0; i < 4; i++)
+ {
+ AddTextPrinterParameterized3(0, 1, 0, y, gUnknown_0862A5F4, TEXT_SPEED_FF, gUnknown_0862A660[i]);
+ y += 15;
+ total = sub_81D5DF0(&gSaveBlock1Ptr->field_3718[i]);
+ 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);
+ AddTextPrinterParameterized3(0, 1, x, y, gUnknown_0862A5F4, TEXT_SPEED_FF, gStringVar4);
+ y += 17;
+ }
+
+ PutWindowTilemap(0);
+ CopyWindowToVram(0, 3);
+ sub_81D5710();
+}
+
+// In fire red the counter had to be xored by the encryption key in Sav2.
+u32 sub_81D5DF0(u32 *src)
+{
+ return *src;
+}
+
+void sub_81D5DF4(u32 *dst, u32 val)
+{
+ *dst = val;
+}
+
+void sub_81D5DF8(void)
+{
+ u8 i, layoutId;
+ struct EventObjectTemplate *eventTemplates = gSaveBlock1Ptr->eventObjectTemplates;
+
+ if (!sub_81D5F48())
+ return;
+
+ sub_81D56B0();
+ for (i = 0; i < 2; i++)
+ gSaveBlock2Ptr->frontier.field_CB4[i] = 0xFFFF;
+ CpuFill32(0, gSaveBlock1Ptr->eventObjectTemplates, sizeof(gSaveBlock1Ptr->eventObjectTemplates));
+
+ layoutId = sub_81D5520();
+ for (i = 0; i < 2; i++)
+ {
+ u8 bits;
+
+ eventTemplates[i] = gUnknown_0862A670;
+ eventTemplates[i].localId = i + 1;
+ eventTemplates[i].graphicsId = FacilityClassToGraphicsId(gUnknown_0203CF54->unk4.unk0[layoutId].trainers[i].facilityClass);
+ eventTemplates[i].x = gUnknown_0203CF54->unk4.unk0[layoutId].coords[i] & 0xF;
+ eventTemplates[i].y = ((gUnknown_0203CF54->unk4.unk0[layoutId].coords[i] >> 4) & 0xF) + 5;
+ bits = i << 2;
+ eventTemplates[i].movementType = ((gUnknown_0203CF54->unk4.unk0[layoutId].direction >> bits) & 0xF) + MOVEMENT_TYPE_FACE_UP;
+ eventTemplates[i].trainerRange_berryTreeId = (gUnknown_0203CF54->unk4.unk0[layoutId].range >> bits) & 0xF;
+ eventTemplates[i].script = EventScript_2C83F0;
+ gSaveBlock2Ptr->frontier.field_CB4[i] = i + 1;
+ }
+
+ sub_81D5710();
+}
+
+bool32 sub_81D5F48(void)
+{
+ sub_81D56B0();
+ sub_81D5710();
+ return TRUE;
+}
+
+// Functionally equivalent.
+#ifdef NONMATCHING
+u32 sub_81D5F58(u8 layoutId, u32 bit, u32 arg2, u32 arg3)
+{
+ u32 var0, var1, var2, var3;
+
+ var0 = (gUnknown_0203CF54->unk4.unk0[layoutId].unk3A0[arg2] >> (15 - bit)) & 1;
+ var1 = gUnknown_0203CF54->unk4.unk0[layoutId].data[arg2 * arg3 + bit];
+ var3 = 0x200;
+ var2 = 0x3000;
+
+ return ((var0 << 10) | var2) | (var1 | var3);
+}
+#else
+NAKED
+u32 sub_81D5F58(u8 layoutId, u32 bit, u32 arg2, u32 arg3)
+{
+ asm_unified("\n\
+ push {r4,r5,lr}\n\
+ lsls r0, 24\n\
+ lsrs r0, 24\n\
+ ldr r4, =gUnknown_0203CF54\n\
+ ldr r4, [r4]\n\
+ mov r12, r4\n\
+ lsls r4, r2, 1\n\
+ lsls r5, r0, 4\n\
+ subs r5, r0\n\
+ lsls r5, 3\n\
+ subs r5, r0\n\
+ lsls r5, 3\n\
+ adds r4, r5\n\
+ movs r0, 0xE8\n\
+ lsls r0, 2\n\
+ add r0, r12\n\
+ adds r0, r4\n\
+ ldrh r0, [r0]\n\
+ movs r4, 0xF\n\
+ subs r4, r1\n\
+ asrs r0, r4\n\
+ movs r4, 0x1\n\
+ ands r0, r4\n\
+ muls r2, r3\n\
+ adds r2, r1\n\
+ adds r2, r5\n\
+ movs r1, 0xA8\n\
+ lsls r1, 2\n\
+ add r1, r12\n\
+ adds r1, r2\n\
+ ldrb r1, [r1]\n\
+ movs r2, 0x80\n\
+ lsls r2, 2\n\
+ adds r3, r2, 0\n\
+ movs r2, 0xC0\n\
+ lsls r2, 6\n\
+ lsls r0, 10\n\
+ orrs r0, r2\n\
+ orrs r1, r3\n\
+ orrs r0, r1\n\
+ pop {r4,r5}\n\
+ pop {r1}\n\
+ bx r1\n\
+ .pool");
+}
+#endif // NONMATCHING
+
+void sub_81D5FB4(u16 *mapArg)
+{
+ s32 i, j;
+ u16 *src, *dst;
+ u8 layoutId = GetCurrentTrainerHillMapId();
+
+ if (layoutId == 6)
+ {
+ InitMapFromSavedGame();
+ return;
+ }
+
+ sub_81D56B0();
+ if (layoutId == 5)
+ {
+ InitMapFromSavedGame();
+ sub_81D5710();
+ return;
+ }
+
+ layoutId = sub_81D5520();
+ src = gMapHeader.mapLayout->map;
+ gBackupMapLayout.map = mapArg;
+ gBackupMapLayout.width = 31;
+ gBackupMapLayout.height = 35;
+ dst = mapArg + 224;
+ for (i = 0; i < 5; i++)
+ {
+ for (j = 0; j < 16; j++)
+ dst[j] = src[j];
+ dst += 31;
+ src += 16;
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ for (j = 0; j < 16; j++)
+ dst[j] = sub_81D5F58(layoutId, j, i, 0x10);
+ dst += 31;
+ }
+
+ mapheader_run_script_with_tag_x1();
+ sub_81D5710();
+}
+
+bool32 InTrainerHill(void)
+{
+ bool32 ret;
+
+ if (gMapHeader.mapLayoutId == 0x19F
+ || gMapHeader.mapLayoutId == 0x1A0
+ || gMapHeader.mapLayoutId == 0x1A1
+ || gMapHeader.mapLayoutId == 0x1A2)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ return ret;
+}
+
+u8 GetCurrentTrainerHillMapId(void)
+{
+ u8 ret;
+
+ if (gMapHeader.mapLayoutId == 0x19F)
+ ret = 1;
+ else if (gMapHeader.mapLayoutId == 0x1A0)
+ ret = 2;
+ else if (gMapHeader.mapLayoutId == 0x1A1)
+ ret = 3;
+ else if (gMapHeader.mapLayoutId == 0x1A2)
+ ret = 4;
+ else if (gMapHeader.mapLayoutId == 0x1A3)
+ ret = 5;
+ else if (gMapHeader.mapLayoutId == 0x19E)
+ ret = 6;
+ else
+ ret = 0;
+
+ return ret;
+}
+
+bool32 sub_81D6100(void)
+{
+ bool32 ret;
+
+ if (gMapHeader.mapLayoutId == 0x1A3)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ return ret;
+}
+
+const struct WarpEvent* sub_81D6120(void)
+{
+ const struct MapHeader *header = Overworld_GetMapHeaderByGroupAndId(MAP_GROUP(TRAINER_HILL_4F), MAP_NUM(TRAINER_HILL_4F));
+
+ return &header->events->warps[1];
+}
+
+const struct WarpEvent* sub_81D6134(u8 warpEventId)
+{
+ u8 id;
+ const struct MapHeader *header;
+
+ if (warpEventId == 1)
+ return &gMapHeader.events->warps[1];
+
+ id = sub_81D6490();
+ if ((u8)(id - 1) >= 4)
+ id = 4;
+
+ header = Overworld_GetMapHeaderByGroupAndId(MAP_GROUP(TRAINER_HILL_4F), gUnknown_0862A688[id - 1]);
+ return &header->events->warps[0];
+}
+
+u16 sub_81D6180(u8 localId)
+{
+ return gSaveBlock2Ptr->frontier.field_CB4[localId - 1];
+}
+
+bool8 GetTrainerHillTrainerFlag(u8 eventObjectId)
+{
+ u32 layoutId = sub_81D5520() * 2;
+ u8 bitId = gEventObjects[eventObjectId].localId - 1 + layoutId;
+
+ return gSaveBlock2Ptr->frontier.field_EE0 & gBitTable[bitId];
+}
+
+void sub_81D61E8(void)
+{
+ u8 i;
+ u8 layoutId = sub_81D5520() * 2;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (gSaveBlock2Ptr->frontier.field_CB4[i] == gTrainerBattleOpponent_A)
+ {
+ gSaveBlock2Ptr->frontier.field_EE0 |= gBitTable[layoutId + i];
+ break;
+ }
+ }
+
+ if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (gSaveBlock2Ptr->frontier.field_CB4[i] == gTrainerBattleOpponent_B)
+ {
+ gSaveBlock2Ptr->frontier.field_EE0 |= gBitTable[layoutId + i];
+ break;
+ }
+ }
+ }
+}
+
+const u8 *sub_81D62AC(void)
+{
+ return EventScript_2C83F0;
+}
+
+void sub_81D62B4(void)
+{
+ CopyTrainerHillTrainerText(5, gSpecialVar_LastTalked);
+ sub_80982B8();
+}
+
+void sub_81D62CC(u16 trainerId, u8 firstMonId)
+{
+ u8 trId, level;
+ s32 i, layoutId, arrId;
+
+ if ((u16)(trainerId - 1) > 1)
+ return;
+
+ trId = trainerId - 1;
+ sub_81D56B0();
+ level = GetHighestLevelInPlayerParty();
+ layoutId = sub_81D5520();
+ for (i = firstMonId, arrId = 0; i < firstMonId + 3; i++, arrId++)
+ {
+ u8 id = gUnknown_0862A698[trId][arrId];
+ struct Pokemon *mon = &gEnemyParty[i];
+
+ CreateBattleTowerMon(mon, &gUnknown_0203CF54->unk4.unk0[layoutId].trainers[trId].mons[id]);
+ sub_81D642C(mon, level);
+ }
+
+ sub_81D5710();
+}
+
+void sub_81D6384(void)
+{
+ ZeroEnemyPartyMons();
+ sub_81D62CC(gTrainerBattleOpponent_A, 0);
+}
+
+void sub_81D639C(void)
+{
+ ZeroEnemyPartyMons();
+ sub_81D62CC(gTrainerBattleOpponent_A, 0);
+ sub_81D62CC(gTrainerBattleOpponent_B, 3);
+}
+
+// This function is unused, but my best guess is
+// it was supposed to return AI scripts for trainer
+// hill trainers.
+u32 sub_81D63C4(void)
+{
+ return 7;
+}
+
+u8 sub_81D63C8(u16 trainerId)
+{
+ s32 i;
+ u8 trId, facilityClass;
+
+ sub_81D56B0();
+ trId = trainerId - 1;
+ facilityClass = gUnknown_0203CF54->unk4.unk0[gUnknown_0203CF54->layoutId].trainers[trId].facilityClass;
+ sub_81D5710();
+
+ for (i = 0; i < ARRAY_COUNT(gUnknown_0862A3B4); i++)
+ {
+ if (gUnknown_0862A3B4[i].trainerClass == gFacilityClassToTrainerClass[facilityClass])
+ return gUnknown_0862A3B4[i].musicId;
+ }
+
+ return 0;
+}
+
+void sub_81D642C(struct Pokemon *mon, u8 level)
+{
+ 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);
+}
+
+u8 sub_81D6490(void)
+{
+ u8 ret;
+
+ sub_81D56B0();
+ ret = gUnknown_0203CF54->unk4.unkField_2;
+ sub_81D5710();
+
+ return ret;
+}
+
+void sub_81D64AC(void)
+{
+ gSaveBlock2Ptr->frontier.field_EE0 = 0xFF;
+}
+
+void sub_81D64C0(void)
+{
+ if (sub_81D6534() == TRUE)
+ LoadPalette(gUnknown_0862A5D4, 0x70, 0x20);
+}
+
+void sub_81D64DC(void)
+{
+ gSpecialVar_Result = gSaveBlock2Ptr->frontier.field_EF9_1;
+}
+
+void sub_81D64FC(void)
+{
+ gSaveBlock2Ptr->frontier.field_EF9_1 = 1;
+}
+
+void sub_81D6518(void)
+{
+ gSaveBlock2Ptr->frontier.field_EF9_1 = 0;
+}
+
+bool32 sub_81D6534(void)
+{
+ if (!sub_81D5C18() || GetCurrentTrainerHillMapId() == 6)
+ return FALSE;
+
+ sub_81D5C00();
+ if (gSpecialVar_Result == 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+void sub_81D6568(void)
+{
+ if (gSaveBlock1Ptr->trainerHill.field_3D6E_0d)
+ gSpecialVar_Result = 0;
+ else
+ gSpecialVar_Result = 1;
+}
+
+void sub_81D65A0(void)
+{
+ gSaveBlock1Ptr->trainerHill.field_3D6E_1 = gSpecialVar_0x8005;
+ gSaveBlock1Ptr->trainerHill.field_3D68 = gSaveBlock1Ptr->field_3718[gSpecialVar_0x8005];
+}
+
+u8 sub_81D65E8(u8 arg0)
+{
+ u8 var, i, modBy;
+
+ var = 0;
+ for (i = 0; i < 4; i++)
+ {
+ var ^= gUnknown_0203CF54->unk4.unk0[i].unk0 & 0x1F;
+ var ^= gUnknown_0203CF54->unk4.unk0[i].unk1 & 0x1F;
+ }
+
+ if (arg0)
+ modBy = 10;
+ else
+ modBy = 5;
+
+ var %= modBy;
+ return var;
+}
+
+u16 sub_81D6640(void)
+{
+ u8 i;
+ const u16 *ptr;
+ s32 var = 0, var2, minutes, id;
+
+ for (i = 0; i < 4; i++)
+ {
+ var += gUnknown_0203CF54->unk4.unk0[i].unk0;
+ var += gUnknown_0203CF54->unk4.unk0[i].unk1;
+ }
+
+ var2 = var / 256;
+ var2 %= 2;
+ if (FlagGet(FLAG_SYS_GAME_CLEAR) && gUnknown_0203CF54->unk4.unkField_0 == 8)
+ i = sub_81D65E8(1);
+ else
+ i = sub_81D65E8(0);
+
+ if (gSaveBlock1Ptr->trainerHill.field_3D6E_1 == 3)
+ i = (i + 1) % 10;
+
+ ptr = gUnknown_0862A5CC[var2][i];
+ minutes = (signed)(gSaveBlock1Ptr->trainerHill.field_3D64) / (60 * 60);
+ 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;
+
+ return ptr[id];
+}