Clean up some trainer hill

This commit is contained in:
GriffinR 2022-03-04 11:02:19 -05:00
parent eca5233abe
commit 62f3f144ab
9 changed files with 456 additions and 880 deletions

View File

@ -100,9 +100,9 @@
special CallTrainerHillFunction
.endm
@ Set the challenge mode to HILL_TAG_* (Normal, Variety, Unique, or Expert)
.macro trainerhill_settag tag:req
setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_TAG
copyvar VAR_0x8005, \tag
@ Set the challenge mode to HILL_MODE_* (Normal, Variety, Unique, or Expert)
.macro trainerhill_setmode mode:req
setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_MODE
copyvar VAR_0x8005, \mode
special CallTrainerHillFunction
.endm

View File

@ -157,7 +157,7 @@ TrainerHill_Entrance_EventScript_ChooseChallenge::
switch VAR_RESULT
case 4, TrainerHill_Entrance_EventScript_CancelEntry
case MULTI_B_PRESSED, TrainerHill_Entrance_EventScript_CancelEntry
trainerhill_settag VAR_RESULT
trainerhill_setmode VAR_RESULT
setvar VAR_TRAINER_HILL_IS_ACTIVE, 1
setvar VAR_TEMP_5, 0
special HealPlayerParty

View File

@ -8,6 +8,12 @@
#define TRAINER_HILL_ROOF 5
#define TRAINER_HILL_ENTRANCE 6
#define HILL_MODE_NORMAL 0
#define HILL_MODE_VARIETY 1
#define HILL_MODE_UNIQUE 2
#define HILL_MODE_EXPERT 3
#define NUM_TRAINER_HILL_MODES 4
#define NUM_TRAINER_HILL_FLOORS 4
#define NUM_TRAINER_HILL_FLOORS_JP 2
@ -30,20 +36,33 @@
#define TRAINER_HILL_FUNC_SET_GAME_SAVED 14
#define TRAINER_HILL_FUNC_CLEAR_GAME_SAVED 15
#define TRAINER_HILL_FUNC_GET_WON 16
#define TRAINER_HILL_FUNC_SET_TAG 17
#define TRAINER_HILL_FUNC_SET_MODE 17
#define TRAINER_HILL_TEXT_INTRO 2
#define TRAINER_HILL_TEXT_PLAYER_LOST 3
#define TRAINER_HILL_TEXT_PLAYER_WON 4
#define TRAINER_HILL_TEXT_AFTER 5
#define TRAINER_HILL_TRAINERS_PER_FLOOR 2
#define NUM_TRAINER_HILL_TRAINERS (NUM_TRAINER_HILL_FLOORS * TRAINER_HILL_TRAINERS_PER_FLOOR)
#define NUM_TRAINER_HILL_TRAINERS_JP (NUM_TRAINER_HILL_FLOORS_JP * TRAINER_HILL_TRAINERS_PER_FLOOR)
#define HILL_TRAINERS_PER_FLOOR 2
#define NUM_TRAINER_HILL_TRAINERS (NUM_TRAINER_HILL_FLOORS * HILL_TRAINERS_PER_FLOOR)
#define NUM_TRAINER_HILL_TRAINERS_JP (NUM_TRAINER_HILL_FLOORS_JP * HILL_TRAINERS_PER_FLOOR)
// Values returned by TrainerHillGetChallengeStatus
#define TRAINER_HILL_PLAYER_STATUS_LOST 0
#define TRAINER_HILL_PLAYER_STATUS_ECARD_SCANNED 1
#define TRAINER_HILL_PLAYER_STATUS_NORMAL 2
#define HILL_TRAINER_NAME_LENGTH 11
#define TRAINER_HILL_OTID 0x10000000
// The full map of each Trainer Hill floor is 16x21.
// The first 5x21 at the top is the entrance/exit area,
// and the remaining 16x16 is the randomized portion of
// the room where the trainers are.
#define HILL_FLOOR_WIDTH 16
#define HILL_FLOOR_HEIGHT_MAIN 16
#define HILL_FLOOR_HEIGHT_MARGIN 5
#define HILL_FLOOR_HEIGHT (HILL_FLOOR_HEIGHT_MAIN + HILL_FLOOR_HEIGHT_MARGIN)
#endif

View File

@ -35,7 +35,7 @@ struct EReaderTrainerHillTrainer
{
u8 trainerNum;
struct TrainerHillTrainer trainer;
struct TrHillDisplay display;
struct TrainerHillFloorMap map;
u32 checksum;
}; // size=0x274

View File

@ -14,6 +14,7 @@
#include "constants/maps.h"
#include "constants/pokemon.h"
#include "constants/easy_chat.h"
#include "constants/trainer_hill.h"
// Prevent cross-jump optimization.
#define BLOCK_CROSS_JUMP asm("");
@ -279,8 +280,6 @@ struct BattleTowerPokemon
u8 friendship;
};
#define NULL_BATTLE_TOWER_POKEMON { .nickname = __("$$$$$$$$$$$") }
struct EmeraldBattleTowerRecord
{
/*0x00*/ u8 lvlMode; // 0 = level 50, 1 = level 100
@ -808,7 +807,7 @@ struct TrainerNameRecord
u8 trainerName[PLAYER_NAME_LENGTH + 1];
};
struct SaveTrainerHill
struct TrainerHillSave
{
/*0x3D64*/ u32 timer;
/*0x3D68*/ u32 bestTime;
@ -820,7 +819,7 @@ struct SaveTrainerHill
/*0x3D6E*/ u16 hasLost:1;
/*0x3D6E*/ u16 maybeECardScanDuringChallenge:1;
/*0x3D6E*/ u16 field_3D6E_0f:1;
/*0x3D6E*/ u16 tag:2;
/*0x3D6E*/ u16 mode:2; // HILL_MODE_*
};
struct WonderNewsMetadata
@ -1003,7 +1002,7 @@ struct SaveBlock1
/*0x31F8*/ struct EnigmaBerry enigmaBerry;
/*0x322C*/ struct MysteryGiftSave mysteryGift;
/*0x3598*/ u8 unused_3598[0x180];
/*0x3718*/ u32 trainerHillTimes[4];
/*0x3718*/ u32 trainerHillTimes[NUM_TRAINER_HILL_MODES];
/*0x3728*/ struct RamScript ramScript;
/*0x3B14*/ struct RecordMixingGift recordMixingGift;
/*0x3B24*/ u8 seen2[NUM_DEX_FLAG_BYTES];
@ -1011,7 +1010,7 @@ struct SaveBlock1
/*0x3B98*/ struct TrainerNameRecord trainerNameRecords[20];
/*0x3C88*/ u8 registeredTexts[UNION_ROOM_KB_ROW_COUNT][21];
/*0x3D5A*/ u8 unused_3D5A[10];
/*0x3D64*/ struct SaveTrainerHill trainerHill;
/*0x3D64*/ struct TrainerHillSave trainerHill;
/*0x3D70*/ struct WaldaPhrase waldaPhrase;
// sizeof: 0x3D88
};

View File

@ -1,7 +1,7 @@
#ifndef GUARD_TRAINER_HILL_H
#define GUARD_TRAINER_HILL_H
#define HILL_TRAINER_NAME_LENGTH 11
#define DUMMY_HILL_MON { .nickname = __("$$$$$$$$$$$") }
struct TrainerHillTrainer
{
@ -15,44 +15,30 @@ struct TrainerHillTrainer
struct BattleTowerPokemon mons[PARTY_SIZE];
};
struct TrHillRoomTrainers
struct TrainerHillFloorMap
{
u8 name[2][HILL_TRAINER_NAME_LENGTH];
u8 facilityClass[2];
u8 metatileData[HILL_FLOOR_WIDTH * HILL_FLOOR_HEIGHT_MAIN]; // Add NUM_METATILES_IN_PRIMARY to the values in this array to get metatile ids.
u16 collisionData[HILL_FLOOR_WIDTH]; // One bit for each tile in column-major order, so every array entry is one row. 1 = impassable, 0 = passable
u8 trainerCoords[HILL_TRAINERS_PER_FLOOR]; // Starting at (0,6). Format is 0bYYYYXXXX.
u8 trainerDirections; // DIR_* - 1, 4 bits per trainer
u8 trainerRanges; // 4 bits per trainer
};
struct TrHillDisplay
{
// Metatile data. Add 0x200 to the values in this array to get metatiles.
// This data then overwrites the metatiles in the map starting at (0,5)
u8 metatileData[0x100];
// Collision data. One bit for each tile in column-major order,
// so every array entry is one row. 1 = impassable, 0 = passable
u16 collisionData[16];
// Trainer coordinates, starting at (0,6). Format is 0bYYYYXXXX.
u8 coords[2];
// Trainer facing directions. Same as (DIR_* - 1).
// Effectively an array of nibbles, one for each trainer.
u8 direction;
// Trainer sight ranges. Effectively an array of nibbles, one for each trainer.
u8 range;
};
struct TrHillFloor
struct TrainerHillFloor
{
u8 trainerNum1;
u8 trainerNum2;
struct TrainerHillTrainer trainers[2];
struct TrHillDisplay display;
struct TrainerHillTrainer trainers[HILL_TRAINERS_PER_FLOOR];
struct TrainerHillFloorMap map;
};
struct TrHillTag
struct TrainerHillChallenge
{
u8 numTrainers;
u8 unused1;
u8 numFloors;
u32 checksum;
struct TrHillFloor floors[0];
u32 checksum; // A byte array sum of the floor data
struct TrainerHillFloor floors[0]; // Floor data is assumed to follow, so this will be intentionally read out of bounds
};
extern u32 *gTrainerHillVBlankCounter;

File diff suppressed because it is too large Load Diff

View File

@ -57,22 +57,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_WORD_TO_HER, EC_WORD_WIN, EC_WORD_JOKING, EC_WORD_HIGHS, EC_WORD_SCARY, EC_WORD_ELLIPSIS_EXCL },
.speechAfter = { EC_WORD_IGNORANT, EC_WORD_SO, EC_WORD_TODAY, EC_WORD_NIGHTTIME, EC_WORD_YOU_RE, EC_WORD_ELLIPSIS_ELLIPSIS_ELLIPSIS },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_SWALOT,
.heldItem = ITEM_SHELL_BELL,
.moves = { MOVE_SLUDGE_BOMB, MOVE_SHADOW_BALL, MOVE_PAIN_SPLIT, MOVE_YAWN },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 55,
.attackEV = 255,
.defenseEV = 100,
.speedEV = 0,
.spAttackEV = 0,
.spDefenseEV = 100,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -82,21 +80,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 1,
.personality = 0x80,
.nickname = __("マルノーム$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_DUSTOX,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_SILVER_WIND, MOVE_SLUDGE_BOMB, MOVE_SHADOW_BALL, MOVE_GIGA_DRAIN },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -106,21 +102,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x6,
.nickname = __("ドクケイル$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_RELICANTH,
.heldItem = ITEM_QUICK_CLAW,
.moves = { MOVE_ANCIENT_POWER, MOVE_SURF, MOVE_EARTHQUAKE, MOVE_AMNESIA },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 100,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 155,
.spDefenseEV = 255,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -130,7 +124,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x2f,
.nickname = __("ジーランス$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -143,22 +137,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_MOVE2(MINIMIZE), EC_WORD_AS_MUCH_AS, EC_EMPTY_WORD, EC_WORD_THEY_RE, EC_WORD_SAD, EC_WORD_EXCL },
.speechAfter = { EC_MOVE(BITE), EC_WORD_AS_MUCH_AS, EC_EMPTY_WORD, EC_WORD_THEY_RE, EC_WORD_ANGRY, EC_WORD_EXCL },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_CACTURNE,
.heldItem = ITEM_QUICK_CLAW,
.moves = { MOVE_GIGA_DRAIN, MOVE_FAINT_ATTACK, MOVE_THUNDER_PUNCH, MOVE_GROWTH },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 55,
.attackEV = 0,
.defenseEV = 100,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 100,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -168,21 +160,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x8c,
.nickname = __("ノクタス$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_SWELLOW,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_FACADE, MOVE_AERIAL_ACE, MOVE_QUICK_ATTACK, MOVE_DOUBLE_TEAM },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 0,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -192,21 +182,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x80,
.nickname = __("オオスバメ$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_WHISCASH,
.heldItem = ITEM_CHESTO_BERRY,
.moves = { MOVE_SURF, MOVE_EARTHQUAKE, MOVE_AMNESIA, MOVE_REST },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -216,7 +204,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x0,
.nickname = __("ナマズン$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -229,22 +217,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_WORD_THAT, EC_WORD_ABOVE, EC_WORD_LOST, EC_WORD_STORES, EC_WORD_JOKING, EC_WORD_ELLIPSIS_ELLIPSIS_ELLIPSIS },
.speechAfter = { EC_WORD_ENTERTAINING, EC_WORD_NONE, EC_WORD_HEY_QUES, EC_WORD_ALMOST, EC_WORD_EXCL, EC_EMPTY_WORD },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_DELCATTY,
.heldItem = ITEM_LUM_BERRY,
.moves = { MOVE_SING, MOVE_BODY_SLAM, MOVE_SHADOW_BALL, MOVE_IRON_TAIL },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 255,
.spAttackEV = 0,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -254,21 +240,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x3,
.nickname = __("エネコロロ$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_ROSELIA,
.heldItem = ITEM_LEFTOVERS,
.moves = { MOVE_GIGA_DRAIN, MOVE_GRASS_WHISTLE, MOVE_TOXIC, MOVE_LEECH_SEED },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -278,21 +262,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 1,
.personality = 0x6,
.nickname = __("ロゼリア$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_BEAUTIFLY,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_SILVER_WIND, MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_PSYCHIC },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 100,
.attackEV = 200,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 200,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -302,7 +284,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x6,
.nickname = __("アゲハント$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -315,22 +297,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_WORD_OUTSIDE, EC_WORD_UNCLE, EC_WORD_SURPRISE, EC_WORD_THESE, EC_WORD_HEY_QUES, EC_WORD_ELLIPSIS_EXCL },
.speechAfter = { EC_WORD_HE_S, EC_WORD_NO_1, EC_WORD_STRONG, EC_WORD_CHILDREN, EC_WORD_CAN_T, EC_WORD_EXCL_EXCL },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_MAWILE,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_CRUNCH, MOVE_FLAMETHROWER, MOVE_THUNDER_PUNCH, MOVE_COMET_PUNCH },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 0,
.defenseEV = 100,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 155,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -340,21 +320,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 1,
.personality = 0x0,
.nickname = __("クチート$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_SHARPEDO,
.heldItem = ITEM_SCOPE_LENS,
.moves = { MOVE_SURF, MOVE_CRUNCH, MOVE_DOUBLE_EDGE, MOVE_EARTHQUAKE },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -364,21 +342,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x96,
.nickname = __("サメハダー$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_BANETTE,
.heldItem = ITEM_LUM_BERRY,
.moves = { MOVE_PSYCHIC, MOVE_SHADOW_BALL, MOVE_THUNDERBOLT, MOVE_WILL_O_WISP },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -388,7 +364,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x96,
.nickname = __("ジュペッタ$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -447,40 +423,40 @@ static bool32 ValidateTrainerHillChecksum(struct EReaderTrainerHillSet *hillSet)
return TRUE;
}
static bool32 TryWriteTrainerHill_Internal(struct EReaderTrainerHillSet * hillSet, struct TrHillTag * hillTag)
static bool32 TryWriteTrainerHill_Internal(struct EReaderTrainerHillSet * hillSet, struct TrainerHillChallenge * challenge)
{
int i;
AGB_ASSERT_EX(hillSet->dummy == 0, "cereader_tool.c", 450);
AGB_ASSERT_EX(hillSet->id == 0, "cereader_tool.c", 452);
memset(hillTag, 0, SECTOR_SIZE);
hillTag->numTrainers = hillSet->numTrainers;
hillTag->unused1 = GetTrainerHillUnkVal();
hillTag->numFloors = (hillSet->numTrainers + 1) / TRAINER_HILL_TRAINERS_PER_FLOOR;
memset(challenge, 0, SECTOR_SIZE);
challenge->numTrainers = hillSet->numTrainers;
challenge->unused1 = GetTrainerHillUnkVal();
challenge->numFloors = (hillSet->numTrainers + 1) / HILL_TRAINERS_PER_FLOOR;
for (i = 0; i < hillSet->numTrainers; i++)
{
if (!(i & 1))
{
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainerNum1 = hillSet->trainers[i].trainerNum;
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].display = hillSet->trainers[i].display;
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[0] = hillSet->trainers[i].trainer;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainerNum1 = hillSet->trainers[i].trainerNum;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].map = hillSet->trainers[i].map;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[0] = hillSet->trainers[i].trainer;
}
else
{
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainerNum2 = hillSet->trainers[i].trainerNum;
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[1] = hillSet->trainers[i].trainer;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainerNum2 = hillSet->trainers[i].trainerNum;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[1] = hillSet->trainers[i].trainer;
}
}
if (i & 1)
{
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[1] = sTrainerHillTrainerTemplates_JP[i / TRAINER_HILL_TRAINERS_PER_FLOOR];
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[1] = sTrainerHillTrainerTemplates_JP[i / HILL_TRAINERS_PER_FLOOR];
}
hillTag->checksum = CalcByteArraySum((u8 *)hillTag->floors, NUM_TRAINER_HILL_FLOORS * sizeof(struct TrHillFloor));
if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_HILL, (u8 *)hillTag) != SAVE_STATUS_OK)
challenge->checksum = CalcByteArraySum((u8 *)challenge->floors, NUM_TRAINER_HILL_FLOORS * sizeof(struct TrainerHillFloor));
if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_HILL, (u8 *)challenge) != SAVE_STATUS_OK)
return FALSE;
return TRUE;

View File

@ -32,23 +32,21 @@
#include "constants/trainer_hill.h"
#include "constants/trainer_types.h"
#define HILL_TAG_NORMAL 0
#define HILL_TAG_VARIETY 1
#define HILL_TAG_UNIQUE 2
#define HILL_TAG_EXPERT 3
#define HILL_MAX_TIME 215999 // 60 * 60 * 60 - 1
// EWRAM
struct TrHillStruct2
struct FloorTrainers
{
u8 floorId;
struct TrHillTag tag;
struct TrHillFloor floors[NUM_TRAINER_HILL_FLOORS];
u8 name[HILL_TRAINERS_PER_FLOOR][HILL_TRAINER_NAME_LENGTH];
u8 facilityClass[HILL_TRAINERS_PER_FLOOR];
};
static EWRAM_DATA struct TrHillStruct2 *sHillData = NULL;
static EWRAM_DATA struct TrHillRoomTrainers *sRoomTrainers = NULL;
static EWRAM_DATA struct {
u8 floorId;
struct TrainerHillChallenge challenge;
struct TrainerHillFloor floors[NUM_TRAINER_HILL_FLOORS];
} *sHillData = NULL;
static EWRAM_DATA struct FloorTrainers *sFloorTrainers = NULL;
EWRAM_DATA u32 *gTrainerHillVBlankCounter = NULL;
// This file's functions.
@ -69,7 +67,7 @@ static void GetGameSaved(void);
static void SetGameSaved(void);
static void ClearGameSaved(void);
static void GetChallengeWon(void);
static void TrainerHillSetTag(void);
static void TrainerHillSetMode(void);
static void SetUpDataStruct(void);
static void FreeDataStruct(void);
static void TrainerHillDummy(void);
@ -202,12 +200,12 @@ static const u16 *const *const sPrizeListSets[] =
static const u16 sEReader_Pal[] = INCBIN_U16("graphics/trainer_hill/ereader.gbapal");
static const u8 sRecordWinColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY};
static const struct TrHillTag *const sDataPerTag[] =
static const struct TrainerHillChallenge *const sChallengeData[NUM_TRAINER_HILL_MODES] =
{
&sDataTagNormal,
&sDataTagVariety,
&sDataTagUnique,
&sDataTagExpert,
[HILL_MODE_NORMAL] = &sChallenge_Normal,
[HILL_MODE_VARIETY] = &sChallenge_Variety,
[HILL_MODE_UNIQUE] = &sChallenge_Unique,
[HILL_MODE_EXPERT] = &sChallenge_Expert,
};
// Unused.
@ -238,15 +236,15 @@ static void (* const sHillFunctions[])(void) =
[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,
[TRAINER_HILL_FUNC_SET_MODE] = TrainerHillSetMode,
};
static const u8 *const sTagMatchStrings[] =
static const u8 *const sModeStrings[NUM_TRAINER_HILL_MODES] =
{
gText_NormalTagMatch,
gText_VarietyTagMatch,
gText_UniqueTagMatch,
gText_ExpertTagMatch,
[HILL_MODE_NORMAL] = gText_NormalTagMatch,
[HILL_MODE_VARIETY] = gText_VarietyTagMatch,
[HILL_MODE_UNIQUE] = gText_UniqueTagMatch,
[HILL_MODE_EXPERT] = gText_ExpertTagMatch,
};
static const struct ObjectEventTemplate sTrainerObjectEventTemplate =
@ -261,18 +259,17 @@ static const struct ObjectEventTemplate sTrainerObjectEventTemplate =
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)
[TRAINER_HILL_1F - 1] = MAP_NUM(TRAINER_HILL_2F),
[TRAINER_HILL_2F - 1] = MAP_NUM(TRAINER_HILL_3F),
[TRAINER_HILL_3F - 1] = MAP_NUM(TRAINER_HILL_4F),
[TRAINER_HILL_4F - 1] = MAP_NUM(TRAINER_HILL_ROOF)
};
static const u8 sTrainerPartySlots[][PARTY_SIZE / 2] =
static const u8 sTrainerPartySlots[HILL_TRAINERS_PER_FLOOR][PARTY_SIZE / 2] =
{
{0, 1, 2},
{3, 4, 5}
};
// code
void CallTrainerHillFunction(void)
{
SetUpDataStruct();
@ -287,7 +284,7 @@ void ResetTrainerHillResults(void)
gSaveBlock2Ptr->frontier.savedGame = 0;
gSaveBlock2Ptr->frontier.unk_EF9 = 0;
gSaveBlock1Ptr->trainerHill.bestTime = 0;
for (i = 0; i < 4; i++)
for (i = 0; i < NUM_TRAINER_HILL_MODES; i++)
SetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i], HILL_MAX_TIME);
}
@ -300,7 +297,7 @@ u8 GetTrainerHillOpponentClass(u16 trainerId)
{
u8 id = trainerId - 1;
return gFacilityClassToTrainerClass[sRoomTrainers->facilityClass[id]];
return gFacilityClassToTrainerClass[sFloorTrainers->facilityClass[id]];
}
void GetTrainerHillTrainerName(u8 *dst, u16 trainerId)
@ -309,7 +306,7 @@ void GetTrainerHillTrainerName(u8 *dst, u16 trainerId)
u8 id = trainerId - 1;
for (i = 0; i < HILL_TRAINER_NAME_LENGTH; i++)
dst[i] = sRoomTrainers->name[id][i];
dst[i] = sFloorTrainers->name[id][i];
}
u8 GetTrainerHillTrainerFrontSpriteId(u16 trainerId)
@ -329,15 +326,14 @@ void InitTrainerHillBattleStruct(void)
s32 i, j;
SetUpDataStruct();
sRoomTrainers = AllocZeroed(sizeof(*sRoomTrainers));
sFloorTrainers = AllocZeroed(sizeof(*sFloorTrainers));
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
for (j = 0; j < HILL_TRAINER_NAME_LENGTH; j++)
{
sRoomTrainers->name[i][j] = sHillData->floors[sHillData->floorId].trainers[i].name[j];
}
sRoomTrainers->facilityClass[i] = sHillData->floors[sHillData->floorId].trainers[i].facilityClass;
sFloorTrainers->name[i][j] = sHillData->floors[sHillData->floorId].trainers[i].name[j];
sFloorTrainers->facilityClass[i] = sHillData->floors[sHillData->floorId].trainers[i].facilityClass;
}
SetTrainerHillVBlankCounter(&gSaveBlock1Ptr->trainerHill.timer);
FreeDataStruct();
@ -345,8 +341,7 @@ void InitTrainerHillBattleStruct(void)
void FreeTrainerHillBattleStruct(void)
{
if (sRoomTrainers != NULL)
FREE_AND_SET_NULL(sRoomTrainers);
TRY_FREE_AND_SET_NULL(sFloorTrainers);
}
static void SetUpDataStruct(void)
@ -355,15 +350,20 @@ static void SetUpDataStruct(void)
{
sHillData = AllocZeroed(sizeof(*sHillData));
sHillData->floorId = gMapHeader.mapLayoutId - LAYOUT_TRAINER_HILL_1F;
CpuCopy32(sDataPerTag[gSaveBlock1Ptr->trainerHill.tag], &sHillData->tag, sizeof(sHillData->tag) + 4 * sizeof(struct TrHillFloor));
// This copy depends on the floor data for each challenge being directly after the
// challenge header data, and for the field 'floors' in sHillData to come directly
// after the field 'challenge'.
// e.g. for HILL_MODE_NORMAL, it will copy sChallenge_Normal to sHillData->challenge and
// it will copy sFloors_Normal to sHillData->floors
CpuCopy32(sChallengeData[gSaveBlock1Ptr->trainerHill.mode], &sHillData->challenge, sizeof(sHillData->challenge) + sizeof(sHillData->floors));
TrainerHillDummy();
}
}
static void FreeDataStruct(void)
{
if (sHillData != NULL)
FREE_AND_SET_NULL(sHillData);
TRY_FREE_AND_SET_NULL(sHillData);
}
void CopyTrainerHillTrainerText(u8 which, u16 trainerId)
@ -428,7 +428,7 @@ static void GiveChallengePrize(void)
{
u16 itemId = GetPrizeItemId();
if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS || gSaveBlock1Ptr->trainerHill.receivedPrize)
if (sHillData->challenge.numFloors != NUM_TRAINER_HILL_FLOORS || gSaveBlock1Ptr->trainerHill.receivedPrize)
{
gSpecialVar_Result = 2;
}
@ -456,7 +456,7 @@ static void CheckFinalTime(void)
else if (GetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime) > gSaveBlock1Ptr->trainerHill.timer)
{
SetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime, gSaveBlock1Ptr->trainerHill.timer);
gSaveBlock1Ptr->trainerHillTimes[gSaveBlock1Ptr->trainerHill.tag] = gSaveBlock1Ptr->trainerHill.bestTime;
gSaveBlock1Ptr->trainerHillTimes[gSaveBlock1Ptr->trainerHill.mode] = gSaveBlock1Ptr->trainerHill.bestTime;
gSpecialVar_Result = 0;
}
else
@ -529,9 +529,9 @@ static void BufferChallengeTime(void)
static void GetAllFloorsUsed(void)
{
SetUpDataStruct();
if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS)
if (sHillData->challenge.numFloors != NUM_TRAINER_HILL_FLOORS)
{
ConvertIntToDecimalStringN(gStringVar1, sHillData->tag.numFloors, STR_CONV_MODE_LEFT_ALIGN, 1);
ConvertIntToDecimalStringN(gStringVar1, sHillData->challenge.numFloors, STR_CONV_MODE_LEFT_ALIGN, 1);
gSpecialVar_Result = FALSE;
}
else
@ -592,9 +592,9 @@ void PrintOnTrainerHillRecordsWindow(void)
AddTextPrinterParameterized3(0, FONT_NORMAL, x, 2, sRecordWinColors, TEXT_SKIP_DRAW, gText_TimeBoard);
y = 18;
for (i = 0; i < 4; i++)
for (i = 0; i < NUM_TRAINER_HILL_MODES; i++)
{
AddTextPrinterParameterized3(0, FONT_NORMAL, 0, y, sRecordWinColors, TEXT_SKIP_DRAW, sTagMatchStrings[i]);
AddTextPrinterParameterized3(0, FONT_NORMAL, 0, y, sRecordWinColors, TEXT_SKIP_DRAW, sModeStrings[i]);
y += 15;
total = GetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i]);
minutes = total / (60 * 60);
@ -637,23 +637,23 @@ void LoadTrainerHillObjectEventTemplates(void)
return;
SetUpDataStruct();
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
gSaveBlock2Ptr->frontier.trainerIds[i] = 0xFFFF;
CpuFill32(0, gSaveBlock1Ptr->objectEventTemplates, sizeof(gSaveBlock1Ptr->objectEventTemplates));
floorId = GetFloorId();
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
u8 bits;
eventTemplates[i] = sTrainerObjectEventTemplate;
eventTemplates[i].localId = i + 1;
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;
eventTemplates[i].x = sHillData->floors[floorId].map.trainerCoords[i] & 0xF;
eventTemplates[i].y = ((sHillData->floors[floorId].map.trainerCoords[i] >> 4) & 0xF) + 5;
bits = i << 2;
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;
eventTemplates[i].movementType = ((sHillData->floors[floorId].map.trainerDirections >> bits) & 0xF) + MOVEMENT_TYPE_FACE_UP;
eventTemplates[i].trainerRange_berryTreeId = (sHillData->floors[floorId].map.trainerRanges >> bits) & 0xF;
eventTemplates[i].script = TrainerHill_EventScript_TrainerBattle;
gSaveBlock2Ptr->frontier.trainerIds[i] = i + 1;
}
@ -669,14 +669,14 @@ bool32 LoadTrainerHillFloorObjectEventScripts(void)
return TRUE;
}
static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 stride) // stride is always 16
static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 floorWidth) // floorWidth is always 16
{
bool8 impassable;
u16 metatile;
u16 elevation;
impassable = (sHillData->floors[floorId].display.collisionData[y] >> (15 - x) & 1);
metatile = sHillData->floors[floorId].display.metatileData[stride * y + x] + NUM_METATILES_IN_PRIMARY;
impassable = (sHillData->floors[floorId].map.collisionData[y] >> (15 - x) & 1);
metatile = sHillData->floors[floorId].map.metatileData[floorWidth * y + x] + NUM_METATILES_IN_PRIMARY;
elevation = 3 << MAPGRID_ELEVATION_SHIFT;
return ((impassable << MAPGRID_COLLISION_SHIFT) & MAPGRID_COLLISION_MASK) | elevation | (metatile & MAPGRID_METATILE_ID_MASK);
@ -684,7 +684,7 @@ static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 stride) // stride i
void GenerateTrainerHillFloorLayout(u16 *mapArg)
{
s32 i, j;
s32 y, x;
u16 *src, *dst;
u8 mapId = GetCurrentTrainerHillMapId();
@ -705,24 +705,25 @@ void GenerateTrainerHillFloorLayout(u16 *mapArg)
mapId = GetFloorId();
src = gMapHeader.mapLayout->map;
gBackupMapLayout.map = mapArg;
gBackupMapLayout.width = 31;
gBackupMapLayout.height = 35;
// Dimensions include border area loaded beyond map
gBackupMapLayout.width = HILL_FLOOR_WIDTH + 15;
gBackupMapLayout.height = HILL_FLOOR_HEIGHT + 14;
dst = mapArg + 224;
// First 5 rows of the map (Entrance / Exit) are always the same
for (i = 0; i < 5; i++)
for (y = 0; y < HILL_FLOOR_HEIGHT_MARGIN; y++)
{
for (j = 0; j < 16; j++)
dst[j] = src[j];
for (x = 0; x < HILL_FLOOR_WIDTH; x++)
dst[x] = src[x];
dst += 31;
src += 16;
}
// Load the 16x16 floor-specific layout
for (i = 0; i < 16; i++)
for (y = 0; y < HILL_FLOOR_HEIGHT_MAIN; y++)
{
for (j = 0; j < 16; j++)
dst[j] = GetMetatileForFloor(mapId, j, i, 16);
for (x = 0; x < HILL_FLOOR_WIDTH; x++)
dst[x] = GetMetatileForFloor(mapId, x, y, HILL_FLOOR_WIDTH);
dst += 31;
}
@ -812,8 +813,8 @@ u16 LocalIdToHillTrainerId(u8 localId)
bool8 GetHillTrainerFlag(u8 objectEventId)
{
u32 floorId = GetFloorId() * 2;
u8 bitId = gObjectEvents[objectEventId].localId - 1 + floorId;
u32 trainerIndexStart = GetFloorId() * HILL_TRAINERS_PER_FLOOR;
u8 bitId = gObjectEvents[objectEventId].localId - 1 + trainerIndexStart;
return gSaveBlock2Ptr->frontier.trainerFlags & gBitTable[bitId];
}
@ -821,24 +822,24 @@ bool8 GetHillTrainerFlag(u8 objectEventId)
void SetHillTrainerFlag(void)
{
u8 i;
u8 floorId = GetFloorId() * 2;
u8 trainerIndexStart = GetFloorId() * HILL_TRAINERS_PER_FLOOR;
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_A)
{
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i];
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[trainerIndexStart + i];
break;
}
}
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_B)
{
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i];
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[trainerIndexStart + i];
break;
}
}
@ -861,14 +862,14 @@ static void CreateNPCTrainerHillParty(u16 trainerId, u8 firstMonId)
u8 trId, level;
s32 i, floorId, partySlot;
if (trainerId == 0 || trainerId > 2)
if (trainerId == 0 || trainerId > HILL_TRAINERS_PER_FLOOR)
return;
trId = trainerId - 1;
SetUpDataStruct();
level = GetHighestLevelInPlayerParty();
floorId = GetFloorId();
for (i = firstMonId, partySlot = 0; i < firstMonId + 3; i++, partySlot++)
for (i = firstMonId, partySlot = 0; i < firstMonId + PARTY_SIZE / 2; i++, partySlot++)
{
u8 id = sTrainerPartySlots[trId][partySlot];
struct Pokemon *mon = &gEnemyParty[i];
@ -890,7 +891,7 @@ void FillHillTrainersParties(void)
{
ZeroEnemyPartyMons();
CreateNPCTrainerHillParty(gTrainerBattleOpponent_A, 0);
CreateNPCTrainerHillParty(gTrainerBattleOpponent_B, 3);
CreateNPCTrainerHillParty(gTrainerBattleOpponent_B, PARTY_SIZE / 2);
}
// This function is unused, but my best guess is
@ -935,7 +936,7 @@ u8 GetNumFloorsInTrainerHillChallenge(void)
u8 floors;
SetUpDataStruct();
floors = sHillData->tag.numFloors;
floors = sHillData->challenge.numFloors;
FreeDataStruct();
return floors;
@ -989,9 +990,9 @@ static void GetChallengeWon(void)
gSpecialVar_Result = TRUE;
}
static void TrainerHillSetTag(void)
static void TrainerHillSetMode(void)
{
gSaveBlock1Ptr->trainerHill.tag = gSpecialVar_0x8005;
gSaveBlock1Ptr->trainerHill.mode = gSpecialVar_0x8005;
gSaveBlock1Ptr->trainerHill.bestTime = gSaveBlock1Ptr->trainerHillTimes[gSpecialVar_0x8005];
}
@ -1030,12 +1031,12 @@ static u16 GetPrizeItemId(void)
prizeListSetId = var / 256;
prizeListSetId %= 2;
if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->tag.numTrainers == NUM_TRAINER_HILL_TRAINERS)
if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->challenge.numTrainers == NUM_TRAINER_HILL_TRAINERS)
i = GetPrizeListId(TRUE);
else
i = GetPrizeListId(FALSE);
if (gSaveBlock1Ptr->trainerHill.tag == HILL_TAG_EXPERT)
if (gSaveBlock1Ptr->trainerHill.mode == HILL_MODE_EXPERT)
i = (i + 1) % NUM_TRAINER_HILL_PRIZE_LISTS;
prizeList = sPrizeListSets[prizeListSetId][i];