diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_2.c | 40 | ||||
-rw-r--r-- | src/battle_message.c | 7 | ||||
-rw-r--r-- | src/battle_script_commands.c | 9 | ||||
-rw-r--r-- | src/battle_setup.c | 1884 | ||||
-rw-r--r-- | src/berry_blender.c | 2 | ||||
-rwxr-xr-x | src/clear_save_data_screen.c | 2 | ||||
-rw-r--r-- | src/clock.c | 93 | ||||
-rw-r--r-- | src/egg_hatch.c | 4 | ||||
-rw-r--r-- | src/evolution_scene.c | 2 | ||||
-rw-r--r-- | src/load_save.c | 6 | ||||
-rw-r--r-- | src/mail.c | 302 | ||||
-rw-r--r-- | src/mail_data.c | 203 | ||||
-rw-r--r-- | src/pokemon_2.c | 2 | ||||
-rw-r--r-- | src/pokemon_3.c | 87 | ||||
-rw-r--r-- | src/recorded_battle.c | 2 | ||||
-rw-r--r-- | src/safari_zone.c | 2 | ||||
-rw-r--r-- | src/scrcmd.c | 32 | ||||
-rw-r--r-- | src/secret_base.c | 2 | ||||
-rw-r--r-- | src/starter_choose.c | 2 | ||||
-rw-r--r-- | src/trainer_see.c | 68 | ||||
-rw-r--r-- | src/tv.c | 2 | ||||
-rw-r--r-- | src/wallclock.c | 1057 |
22 files changed, 3560 insertions, 250 deletions
diff --git a/src/battle_2.c b/src/battle_2.c index 52530f6b3..7bde3d174 100644 --- a/src/battle_2.c +++ b/src/battle_2.c @@ -17,6 +17,7 @@ #include "item.h" #include "constants/items.h" #include "constants/hold_effects.h" +#include "constants/trainers.h" #include "link.h" #include "bg.h" #include "dma3.h" @@ -38,7 +39,6 @@ #include "pokedex.h" #include "constants/abilities.h" #include "constants/moves.h" -#include "trainer_classes.h" #include "evolution_scene.h" #include "roamer.h" #include "tv.h" @@ -185,7 +185,7 @@ extern void sub_80356D0(void); extern void GetFrontierTrainerName(u8* dst, u16 trainerId); // battle tower extern void sub_8166188(void); // battle tower, sets link battle mons level but why? extern void sub_8165B88(u8* dst, u16 trainerId); // battle tower, gets language -extern void sub_81DB4DC(u8* dst, u8 arg2); // +extern void PadNameString(u8* dst, u8 arg2); // extern void sub_81B9150(void); extern void sub_800AC34(void); extern void sub_80B3AF8(u8 taskId); // cable club @@ -415,7 +415,7 @@ static void CB2_InitBattleInternal(void) gBattleTerrain = BattleSetup_GetTerrainId(); if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) - gBattleTerrain = BATTLE_TERRAIN_INSIDE; + gBattleTerrain = BATTLE_TERRAIN_BUILDING; sub_80356D0(); LoadBattleTextboxAndBackground(); @@ -1140,7 +1140,7 @@ static void sub_80379F8(u8 arrayIdPlus) gUnknown_02022FF8[i].gender = GetMonGender(&gPlayerParty[arrayIdPlus + i]); StripExtCtrlCodes(gUnknown_02022FF8[i].nickname); if (GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_LANGUAGE) != LANGUAGE_JAPANESE) - sub_81DB4DC(gUnknown_02022FF8[i].nickname, 0); + PadNameString(gUnknown_02022FF8[i].nickname, CHAR_SPACE); } memcpy(gUnknown_02023058, gUnknown_02022FF8, sizeof(gUnknown_02022FF8)); } @@ -1718,7 +1718,7 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir { const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -1726,11 +1726,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); break; } - case PARTY_FLAG_CUSTOM_MOVES: + case F_TRAINER_PARTY_CUSTOM_MOVESET: { const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -1744,11 +1744,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir } break; } - case PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -1758,11 +1758,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); break; } - case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -4749,19 +4749,19 @@ static void HandleEndTurn_BattleWon(void) switch (gTrainers[gTrainerBattleOpponent_A].trainerClass) { - case CLASS_ELITE_FOUR: - case CLASS_CHAMPION: + case TRAINER_CLASS_ELITE_FOUR: + case TRAINER_CLASS_CHAMPION: PlayBGM(BGM_KACHI5); break; - case CLASS_TEAM_AQUA: - case CLASS_TEAM_MAGMA: - case CLASS_AQUA_ADMIN: - case CLASS_AQUA_LEADER: - case CLASS_MAGMA_ADMIN: - case CLASS_MAGMA_LEADER: + case TRAINER_CLASS_TEAM_AQUA: + case TRAINER_CLASS_TEAM_MAGMA: + case TRAINER_CLASS_AQUA_ADMIN: + case TRAINER_CLASS_AQUA_LEADER: + case TRAINER_CLASS_MAGMA_ADMIN: + case TRAINER_CLASS_MAGMA_LEADER: PlayBGM(BGM_KACHI4); break; - case CLASS_LEADER: + case TRAINER_CLASS_LEADER: PlayBGM(BGM_KACHI3); break; default: diff --git a/src/battle_message.c b/src/battle_message.c index ec1cfd626..cab4bdf42 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -12,6 +12,7 @@ #include "window.h" #include "palette.h" #include "battle_controllers.h" +#include "battle_setup.h" extern u16 gLastUsedItem; extern u8 gLastUsedAbility; @@ -54,8 +55,6 @@ extern void sub_81D5554(u8 *txtPtr, u16 trainerId); // pokenav extern void GetEreaderTrainerName(u8 *txtPtr); extern void sub_81A36D0(u8 arg0, u16 trainerId); // battle_frontier_2 extern void sub_81D572C(u8 arg0, u16 trainerId); // pokenav -extern const u8* GetTrainer1LoseText(void); // battle_setup -extern const u8* GetTrainer2LoseText(void); // battle_setup extern void GetFrontierTrainerName(u8 *dst, u16 trainerId); extern s32 GetStringCenterAlignXOffsetWithLetterSpacing(u8 fontId, const u8 *str, s32 totalWidth, s16 letterSpacing); extern u8 GetTextSpeedInRecordedBattle(void); @@ -2068,7 +2067,7 @@ u32 BattleStringExpandPlaceholders(const u8* src, u8* dst) } else { - toCpy = GetTrainer1LoseText(); + toCpy = GetTrainerALoseText(); } break; case B_TXT_TRAINER1_WIN_TEXT: // trainerA win text @@ -2165,7 +2164,7 @@ u32 BattleStringExpandPlaceholders(const u8* src, u8* dst) } else { - toCpy = GetTrainer2LoseText(); + toCpy = GetTrainerBLoseText(); } break; case B_TXT_TRAINER2_WIN_TEXT: diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 88d583c1f..656f9f43a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -17,6 +17,7 @@ #include "battle_interface.h" #include "constants/species.h" #include "constants/songs.h" +#include "constants/trainers.h" #include "text.h" #include "sound.h" #include "pokedex.h" @@ -6236,19 +6237,19 @@ static u32 GetTrainerMoneyToGive(u16 trainerId) lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; } break; - case PARTY_FLAG_CUSTOM_MOVES: + case F_TRAINER_PARTY_CUSTOM_MOVESET: { const struct TrainerMonNoItemCustomMoves *party = gTrainers[trainerId].party.NoItemCustomMoves; lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; } break; - case PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemDefaultMoves *party = gTrainers[trainerId].party.ItemDefaultMoves; lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; } break; - case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemCustomMoves *party = gTrainers[trainerId].party.ItemCustomMoves; lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; @@ -10334,7 +10335,7 @@ static void atkE4_getsecretpowereffect(void) case BATTLE_TERRAIN_POND: gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SPD_MINUS_1; break; - case BATTLE_TERRAIN_ROCK: + case BATTLE_TERRAIN_MOUNTAIN: gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION; break; case BATTLE_TERRAIN_CAVE: diff --git a/src/battle_setup.c b/src/battle_setup.c new file mode 100644 index 000000000..3d4f5afcc --- /dev/null +++ b/src/battle_setup.c @@ -0,0 +1,1884 @@ +#include "global.h" +#include "constants/trainers.h" +#include "battle.h" +#include "battle_setup.h" +#include "battle_transition.h" +#include "main.h" +#include "task.h" +#include "pokemon_3.h" +#include "safari_zone.h" +#include "script.h" +#include "constants/game_stat.h" +#include "event_data.h" +#include "constants/species.h" +#include "songs.h" +#include "metatile_behavior.h" +#include "constants/maps.h" +#include "field_player_avatar.h" +#include "fieldmap.h" +#include "random.h" +#include "starter_choose.h" +#include "script_pokemon_80F8.h" +#include "constants/items.h" +#include "palette.h" +#include "window.h" +#include "field_map_obj.h" +#include "event_scripts.h" +#include "trainer_see.h" +#include "field_message_box.h" +#include "sound.h" +#include "strings.h" +#include "secret_base.h" +#include "string_util.h" + +enum +{ + TRAINER_PARAM_LOAD_VAL_8BIT, + TRAINER_PARAM_LOAD_VAL_16BIT, + TRAINER_PARAM_LOAD_VAL_32BIT, + TRAINER_PARAM_CLEAR_VAL_8BIT, + TRAINER_PARAM_CLEAR_VAL_16BIT, + TRAINER_PARAM_CLEAR_VAL_32BIT, + TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR, +}; + +struct TrainerBattleParameter +{ + void *varPtr; + u8 ptrType; +}; + +extern bool8 InBattlePyramid(void); +extern bool8 InBattlePike(void); +extern bool32 InTrainerHill(void); +extern bool32 FieldPoisonEffectIsRunning(void); +extern void overworld_free_bg_tilemaps(void); +extern void prev_quest_postbuffer_cursor_backup_reset(void); +extern void ResetPoisonStepCounter(void); +extern void sub_81BE72C(void); +extern void FreezeMapObjects(void); +extern void sub_808BCF4(void); +extern void sub_80EECC8(void); +extern void c2_exit_to_overworld_1_continue_scripts_restart_music(void); +extern void c2_exit_to_overworld_2_switch(void); +extern void Overworld_ClearSavedMusic(void); +extern void CB2_WhiteOut(void); +extern void sub_80AF6F0(void); +extern void PlayBattleBGM(void); +extern void sub_81DA57C(void); +extern u8 GetSav1Weather(void); +extern u8 Overworld_GetFlashLevel(void); +extern u16 sub_81A9AA8(u8 localId); +extern u16 sub_81D6180(u8 localId); +extern bool8 GetBattlePyramidTrainerFlag(u8 mapObjId); +extern bool8 GetTrainerHillTrainerFlag(u8 mapObjId); +extern bool8 sub_81D5C18(void); +extern void sub_816306C(u8 a0); +extern void sub_8163048(u8 a0); +extern void sub_81A9B04(void); +extern void sub_81D639C(void); +extern void sub_81D6384(void); +extern void sub_81D61E8(void); +extern void sub_80982B8(void); +extern void sub_81A9EDC(u16 a0); +extern void sub_81D572C(u8 a0, u16 arg1); +extern void IncrementGameStat(u8 statId); +extern u32 GetGameStat(u8 statId); + +extern u32 gBattleTypeFlags; +extern u8 gBattleOutcome; +extern void (*gFieldCallback)(void); +extern u8 gApproachingTrainerId; +extern u8 gNoOfApproachingTrainers; +extern u16 gUnknown_03006080; + +// this file's functions +static void DoBattlePikeWildBattle(void); +static void DoSafariBattle(void); +static void DoStandardWildBattle(void); +static void CB2_EndWildBattle(void); +static void CB2_EndScriptedWildBattle(void); +static u8 GetWildBattleTransition(void); +static u8 GetTrainerBattleTransition(void); +static void sub_80B1218(void); +static void sub_80B1234(void); +static void CB2_GiveStarter(void); +static void CB2_StartFirstBattle(void); +static void CB2_EndFirstBattle(void); +static void CB2_EndTrainerBattle(void); +static bool32 IsPlayerDefeated(u32 battleOutcome); +static u16 GetRematchTrainerId(u16 trainerId); +static void RegisterTrainerInMatchCall(void); +static void HandleRematchVarsOnBattleEnd(void); +static const u8 *GetIntroSpeechOfApproachingTrainer(void); +static const u8 *GetTrainerCantBattleSpeech(void); + +// ewram data +EWRAM_DATA static u16 sTrainerBattleMode = 0; +EWRAM_DATA u16 gTrainerBattleOpponent_A = 0; +EWRAM_DATA u16 gTrainerBattleOpponent_B = 0; +EWRAM_DATA u16 gPartnerTrainerId = 0; +EWRAM_DATA static u16 sTrainerMapObjectLocalId = 0; +EWRAM_DATA static u8 *sTrainerAIntroSpeech = NULL; +EWRAM_DATA static u8 *sTrainerBIntroSpeech = NULL; +EWRAM_DATA static u8 *sTrainerADefeatSpeech = NULL; +EWRAM_DATA static u8 *sTrainerBDefeatSpeech = NULL; +EWRAM_DATA static u8 *sTrainerVictorySpeech = NULL; +EWRAM_DATA static u8 *sTrainerCannotBattleSpeech = NULL; +EWRAM_DATA static u8 *sTrainerBattleEndScript = NULL; +EWRAM_DATA static u8 *sTrainerABattleScriptRetAddr = NULL; +EWRAM_DATA static u8 *sTrainerBBattleScriptRetAddr = NULL; +EWRAM_DATA static bool8 sShouldCheckTrainerBScript = FALSE; +EWRAM_DATA static u8 sNoOfPossibleTrainerRetScripts = 0; + +// const rom data + +// The first transition is used if the enemy pokemon are lower level than our pokemon. +// Otherwise, the second transition is used. +static const u8 sBattleTransitionTable_Wild[][2] = +{ + {B_TRANSITION_SLICE, B_TRANSITION_WHITEFADE}, // Normal + {B_TRANSITION_CLOCKWISE_BLACKFADE, B_TRANSITION_GRID_SQUARES}, // Cave + {B_TRANSITION_BLUR, B_TRANSITION_GRID_SQUARES}, // Cave with flash used + {B_TRANSITION_WAVE, B_TRANSITION_RIPPLE}, // Water +}; + +static const u8 sBattleTransitionTable_Trainer[][2] = +{ + {B_TRANSITION_POKEBALLS_TRAIL, B_TRANSITION_SHARDS}, // Normal + {B_TRANSITION_SHUFFLE, B_TRANSITION_BIG_POKEBALL}, // Cave + {B_TRANSITION_BLUR, B_TRANSITION_GRID_SQUARES}, // Cave with flash used + {B_TRANSITION_SWIRL, B_TRANSITION_RIPPLE}, // Water +}; + +static const u8 sUnknown_0854FE98[] = +{ + B_TRANSITION_29, B_TRANSITION_30, B_TRANSITION_31, B_TRANSITION_32, + B_TRANSITION_34, B_TRANSITION_35, B_TRANSITION_36, B_TRANSITION_37, + B_TRANSITION_38, B_TRANSITION_39, B_TRANSITION_40, B_TRANSITION_41 +}; + +static const u8 sUnknown_0854FEA4[] = +{ + B_TRANSITION_31, B_TRANSITION_32, B_TRANSITION_33 +}; + +static const u8 sUnknown_0854FEA7[] = +{ + B_TRANSITION_29, B_TRANSITION_31, B_TRANSITION_32, B_TRANSITION_33 +}; + +static const struct TrainerBattleParameter sOrdinaryBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sContinueScriptBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sDoubleBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sOrdinaryNoIntroBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sContinueScriptDoubleBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sTrainerBOrdinaryBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerBIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sTrainerBContinueScriptBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerBIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +const struct RematchTrainer gRematchTable[REMATCH_TABLE_ENTRIES] = +{ + {{0x0025, 0x0028, 0x0029, 0x002a, 0x002b}, 0x0000, 0x0021}, + {{0x02e1, 0x032c, 0x032d, 0x032e, 0x032f}, 0x0000, 0x0014}, + {{0x002c, 0x002f, 0x0030, 0x0031, 0x0032}, 0x0000, 0x001a}, + {{0x0039, 0x003c, 0x003d, 0x003e, 0x003f}, 0x0000, 0x0018}, + {{0x0040, 0x0043, 0x0044, 0x0045, 0x0046}, 0x0000, 0x0018}, + {{0x02af, 0x02b0, 0x02b1, 0x02b2, 0x02b3}, 0x0000, 0x0027}, + {{0x02ff, 0x033c, 0x033d, 0x033e, 0x033f}, 0x0000, 0x0024}, + {{0x005e, 0x0065, 0x0066, 0x0067, 0x0068}, 0x0000, 0x001a}, + {{0x004e, 0x0054, 0x0055, 0x0056, 0x0057}, 0x0000, 0x001a}, + {{0x006c, 0x006e, 0x006f, 0x0070, 0x0071}, 0x0018, 0x0014}, + {{0x0072, 0x0078, 0x0079, 0x007a, 0x007b}, 0x0000, 0x0013}, + {{0x0090, 0x034c, 0x034d, 0x034e, 0x034f}, 0x0018, 0x0038}, + {{0x007f, 0x0084, 0x0085, 0x0086, 0x0087}, 0x0000, 0x0024}, + {{0x0088, 0x008b, 0x008c, 0x008d, 0x008e}, 0x0000, 0x0013}, + {{0x008f, 0x0093, 0x0094, 0x0095, 0x0096}, 0x0000, 0x001d}, + {{0x009b, 0x00af, 0x00b0, 0x00b1, 0x00b2}, 0x0000, 0x0016}, + {{0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb}, 0x0000, 0x001e}, + {{0x02a0, 0x0338, 0x0339, 0x033a, 0x033b}, 0x0000, 0x002a}, + {{0x00c3, 0x0340, 0x0341, 0x0342, 0x0343}, 0x0000, 0x0026}, + {{0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8}, 0x0000, 0x0021}, + {{0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2}, 0x0000, 0x001d}, + {{0x00d8, 0x00db, 0x00dc, 0x00dd, 0x00de}, 0x0018, 0x000d}, + {{0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad}, 0x0018, 0x0001}, + {{0x00e2, 0x00e4, 0x00e5, 0x00e6, 0x00e7}, 0x0000, 0x0023}, + {{0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2}, 0x0000, 0x0026}, + {{0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd}, 0x0000, 0x0026}, + {{0x00fe, 0x0101, 0x0102, 0x0103, 0x0104}, 0x0000, 0x0024}, + {{0x0118, 0x011a, 0x011b, 0x011c, 0x011d}, 0x0000, 0x001f}, + {{0x0111, 0x0114, 0x0115, 0x0116, 0x0117}, 0x0000, 0x001f}, + {{0x011f, 0x0120, 0x0121, 0x0122, 0x0123}, 0x0000, 0x0020}, + {{0x012e, 0x012f, 0x0130, 0x0131, 0x0132}, 0x0000, 0x0019}, + {{0x0125, 0x0127, 0x0128, 0x0129, 0x012a}, 0x0000, 0x0012}, + {{0x0133, 0x0134, 0x0135, 0x0136, 0x0137}, 0x0000, 0x001e}, + {{0x0139, 0x013a, 0x013b, 0x013c, 0x013d}, 0x0018, 0x000c}, + {{0x013e, 0x0148, 0x0149, 0x014a, 0x014b}, 0x0000, 0x0011}, + {{0x0153, 0x015a, 0x015b, 0x015c, 0x015d}, 0x0000, 0x0015}, + {{0x0178, 0x017b, 0x017c, 0x017d, 0x017e}, 0x0000, 0x002b}, + {{0x0171, 0x0172, 0x0173, 0x0174, 0x0175}, 0x0000, 0x0020}, + {{0x0166, 0x0168, 0x0169, 0x016a, 0x016b}, 0x0000, 0x0019}, + {{0x016c, 0x016d, 0x016e, 0x016f, 0x0170}, 0x0000, 0x0020}, + {{0x0182, 0x0184, 0x0185, 0x0186, 0x0187}, 0x0000, 0x002b}, + {{0x0161, 0x0162, 0x0163, 0x0164, 0x0165}, 0x0000, 0x0019}, + {{0x0179, 0x0334, 0x0335, 0x0336, 0x0337}, 0x0000, 0x0029}, + {{0x0188, 0x0189, 0x018a, 0x018b, 0x018c}, 0x0018, 0x0001}, + {{0x0196, 0x0199, 0x019a, 0x019b, 0x019c}, 0x0000, 0x0023}, + {{0x01a3, 0x01a5, 0x01a6, 0x01a7, 0x01a8}, 0x0000, 0x001c}, + {{0x01ab, 0x01ae, 0x01af, 0x01b0, 0x01b1}, 0x0000, 0x001e}, + {{0x01b2, 0x01b5, 0x01b6, 0x01b7, 0x01b8}, 0x0000, 0x001c}, + {{0x01c1, 0x01d1, 0x01d2, 0x01d3, 0x01d4}, 0x0000, 0x0027}, + {{0x01da, 0x01dd, 0x01de, 0x01df, 0x01e0}, 0x0018, 0x000d}, + {{0x01e1, 0x01e2, 0x01e7, 0x01e8, 0x01e9}, 0x0000, 0x0012}, + {{0x01ec, 0x01f1, 0x01f2, 0x01f3, 0x01f4}, 0x0000, 0x0028}, + {{0x02e4, 0x0330, 0x0331, 0x0332, 0x0333}, 0x0000, 0x0017}, + {{0x0200, 0x0203, 0x0204, 0x0205, 0x0206}, 0x0000, 0x0019}, + {{0x0221, 0x0224, 0x0225, 0x0226, 0x0227}, 0x0000, 0x0020}, + {{0x021a, 0x021d, 0x021e, 0x021f, 0x0220}, 0x0000, 0x0020}, + {{0x0009, 0x0348, 0x0349, 0x034a, 0x034b}, 0x0018, 0x0011}, + {{0x022f, 0x0232, 0x0233, 0x0234, 0x0235}, 0x0000, 0x0022}, + {{0x0228, 0x022b, 0x022c, 0x022d, 0x022e}, 0x0000, 0x0022}, + {{0x025c, 0x025f, 0x0260, 0x0261, 0x0262}, 0x0000, 0x0013}, + {{0x026d, 0x026e, 0x026f, 0x0270, 0x0271}, 0x0018, 0x000b}, + {{0x0273, 0x027c, 0x027d, 0x027e, 0x027f}, 0x0000, 0x001b}, + {{0x0001, 0x0344, 0x0345, 0x0346, 0x0347}, 0x0018, 0x000c}, + {{0x0282, 0x0283, 0x0284, 0x0285, 0x0286}, 0x0018, 0x003e}, + {{0x0291, 0x0292, 0x0293, 0x0294, 0x0294}, 0x0018, 0x002b}, + {{0x0109, 0x0302, 0x0303, 0x0304, 0x0305}, 0x0000, 0x0003}, + {{0x010a, 0x0306, 0x0307, 0x0308, 0x0309}, 0x0000, 0x000b}, + {{0x010b, 0x030a, 0x030b, 0x030c, 0x030d}, 0x0000, 0x0002}, + {{0x010c, 0x030e, 0x030f, 0x0310, 0x0311}, 0x0000, 0x000c}, + {{0x010d, 0x0312, 0x0313, 0x0314, 0x0315}, 0x0000, 0x0000}, + {{0x010e, 0x0316, 0x0317, 0x0318, 0x0319}, 0x0000, 0x0004}, + {{0x010f, 0x031a, 0x031b, 0x031c, 0x031d}, 0x0000, 0x0006}, + {{0x0110, 0x031e, 0x031f, 0x0320, 0x0321}, 0x0000, 0x0007}, + {{0x0105, 0x0105, 0x0105, 0x0105, 0x0105}, 0x0000, 0x0008}, + {{0x0106, 0x0106, 0x0106, 0x0106, 0x0106}, 0x0000, 0x0008}, + {{0x0107, 0x0107, 0x0107, 0x0107, 0x0107}, 0x0000, 0x0008}, + {{0x0108, 0x0108, 0x0108, 0x0108, 0x0108}, 0x0000, 0x0008}, + {{0x014f, 0x014f, 0x014f, 0x014f, 0x014f}, 0x0000, 0x0008}, +}; + +static const u16 sBadgeFlags[8] = +{ + FLAG_BADGE01_GET, FLAG_BADGE02_GET, FLAG_BADGE03_GET, FLAG_BADGE04_GET, + FLAG_BADGE05_GET, FLAG_BADGE06_GET, FLAG_BADGE07_GET, FLAG_BADGE08_GET, +}; + +#define tState data[0] +#define tTransition data[1] + +static void Task_BattleStart(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + switch (tState) + { + case 0: + if (!FieldPoisonEffectIsRunning()) // is poison not active? + { + BattleTransition_StartOnField(tTransition); + sub_81BE72C(); + tState++; // go to case 1. + } + break; + case 1: + if (IsBattleTransitionDone() == TRUE) + { + overworld_free_bg_tilemaps(); + SetMainCallback2(CB2_InitBattle); + prev_quest_postbuffer_cursor_backup_reset(); + ResetPoisonStepCounter(); + DestroyTask(taskId); + } + break; + } +} + +static void CreateBattleStartTask(u8 transition, u16 song) +{ + u8 taskId = CreateTask(Task_BattleStart, 1); + + gTasks[taskId].tTransition = transition; + PlayMapChosenOrBattleBGM(song); +} + +#undef tState +#undef tTransition + +void BattleSetup_StartWildBattle(void) +{ + if (GetSafariZoneFlag()) + DoSafariBattle(); + else + DoStandardWildBattle(); +} + +void BattleSetup_StartBattlePikeWildBattle(void) +{ + DoBattlePikeWildBattle(); +} + +static void DoStandardWildBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = 0; + if (InBattlePyramid()) + { + VarSet(VAR_0x400E, 0); + gBattleTypeFlags |= BATTLE_TYPE_PYRAMID; + } + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void BattleSetup_StartRoamerBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = BATTLE_TYPE_ROAMER; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +static void DoSafariBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndSafariBattle; + gBattleTypeFlags = BATTLE_TYPE_SAFARI; + CreateBattleStartTask(GetWildBattleTransition(), 0); +} + +static void DoBattlePikeWildBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = BATTLE_TYPE_PIKE; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +static void DoTrainerBattle(void) +{ + CreateBattleStartTask(GetTrainerBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_TRAINER_BATTLES); + sub_80B1234(); +} + +static void sub_80B0828(void) +{ + if (InBattlePyramid()) + CreateBattleStartTask(sub_80B100C(10), 0); + else + CreateBattleStartTask(sub_80B100C(11), 0); + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_TRAINER_BATTLES); + sub_80B1234(); +} + +// Initiates battle where Wally catches Ralts +void StartWallyTutorialBattle(void) +{ + CreateMaleMon(&gEnemyParty[0], SPECIES_RALTS, 5); + ScriptContext2_Enable(); + gMain.savedCallback = c2_exit_to_overworld_1_continue_scripts_restart_music; + gBattleTypeFlags = BATTLE_TYPE_WALLY_TUTORIAL; + CreateBattleStartTask(B_TRANSITION_SLICE, 0); +} + +void BattleSetup_StartScriptedWildBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = 0; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void BattleSetup_StartLatiBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void BattleSetup_StartLegendaryBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY; + + switch (GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL)) + { + default: + case SPECIES_GROUDON: + gBattleTypeFlags |= BATTLE_TYPE_GROUDON; + CreateBattleStartTask(B_TRANSITION_GROUDON, BGM_BATTLE34); + break; + case SPECIES_KYOGRE: + gBattleTypeFlags |= BATTLE_TYPE_KYOGRE; + CreateBattleStartTask(B_TRANSITION_KYOGRE, BGM_BATTLE34); + break; + case SPECIES_RAYQUAZA: + gBattleTypeFlags |= BATTLE_TYPE_RAYQUAZA; + CreateBattleStartTask(B_TRANSITION_RAYQUAZA, BGM_BATTLE_LEGENDARY); + break; + case SPECIES_DEOXYS: + CreateBattleStartTask(B_TRANSITION_BLUR, BGM_FRLG_BATTLE_DEOXYS); + break; + case SPECIES_LUGIA: + case SPECIES_HO_OH: + CreateBattleStartTask(B_TRANSITION_BLUR, BGM_FRLG_BATTLE_LEGENDARY); + break; + case SPECIES_MEW: + CreateBattleStartTask(B_TRANSITION_GRID_SQUARES, BGM_BATTLE_MEW); + break; + } + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void StartGroudonKyogreBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_KYOGRE_GROUDON; + + if (gGameVersion == VERSION_RUBY) + CreateBattleStartTask(B_TRANSITION_SHARDS, BGM_BATTLE34); // GROUDON + else + CreateBattleStartTask(B_TRANSITION_RIPPLE, BGM_BATTLE34); // KYOGRE + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void StartRegiBattle(void) +{ + u8 transitionId; + u16 species; + + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_REGI; + + species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES); + switch (species) + { + case SPECIES_REGIROCK: + transitionId = B_TRANSITION_REGIROCK; + break; + case SPECIES_REGICE: + transitionId = B_TRANSITION_REGICE; + break; + case SPECIES_REGISTEEL: + transitionId = B_TRANSITION_REGISTEEL; + break; + default: + transitionId = B_TRANSITION_GRID_SQUARES; + break; + } + CreateBattleStartTask(transitionId, BGM_BATTLE36); + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +static void CB2_EndWildBattle(void) +{ + CpuFill16(0, (void*)(BG_PLTT), BG_PLTT_SIZE); + ResetOamRange(0, 128); + + if (IsPlayerDefeated(gBattleOutcome) == TRUE && !InBattlePyramid() && !InBattlePike()) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_2_switch); + gFieldCallback = sub_80AF6F0; + } +} + +static void CB2_EndScriptedWildBattle(void) +{ + CpuFill16(0, (void*)(BG_PLTT), BG_PLTT_SIZE); + ResetOamRange(0, 128); + + if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + if (InBattlePyramid()) + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + else + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + } +} + +u8 BattleSetup_GetTerrainId(void) +{ + u16 tileBehavior; + s16 x, y; + + PlayerGetDestCoords(&x, &y); + tileBehavior = MapGridGetMetatileBehaviorAt(x, y); + + if (MetatileBehavior_IsTallGrass(tileBehavior)) + return BATTLE_TERRAIN_GRASS; + if (MetatileBehavior_IsLongGrass(tileBehavior)) + return BATTLE_TERRAIN_LONG_GRASS; + if (MetatileBehavior_IsSandOrDeepSand(tileBehavior)) + return BATTLE_TERRAIN_SAND; + + switch (gMapHeader.mapType) + { + case MAP_TYPE_TOWN: + case MAP_TYPE_CITY: + case MAP_TYPE_ROUTE: + break; + case MAP_TYPE_UNDERGROUND: + if (MetatileBehavior_IsMB_0B(tileBehavior)) + return BATTLE_TERRAIN_BUILDING; + if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + return BATTLE_TERRAIN_POND; + return BATTLE_TERRAIN_CAVE; + case MAP_TYPE_INDOOR: + case MAP_TYPE_SECRET_BASE: + return BATTLE_TERRAIN_BUILDING; + case MAP_TYPE_UNDERWATER: + return BATTLE_TERRAIN_UNDERWATER; + case MAP_TYPE_6: + if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + return BATTLE_TERRAIN_WATER; + return BATTLE_TERRAIN_PLAIN; + } + if (MetatileBehavior_IsDeepOrOceanWater(tileBehavior)) + return BATTLE_TERRAIN_WATER; + if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + return BATTLE_TERRAIN_POND; + if (MetatileBehavior_IsMountain(tileBehavior)) + return BATTLE_TERRAIN_MOUNTAIN; + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING)) + { + if (MetatileBehavior_GetBridgeSth(tileBehavior)) + return BATTLE_TERRAIN_POND; + if (MetatileBehavior_IsBridge(tileBehavior) == TRUE) + return BATTLE_TERRAIN_WATER; + } + if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(ROUTE113) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(ROUTE113)) + return BATTLE_TERRAIN_SAND; + if (GetSav1Weather() == 8) + return BATTLE_TERRAIN_SAND; + + return BATTLE_TERRAIN_PLAIN; +} + +static u8 GetBattleTransitionTypeByMap(void) +{ + u16 tileBehavior; + s16 x, y; + + PlayerGetDestCoords(&x, &y); + tileBehavior = MapGridGetMetatileBehaviorAt(x, y); + if (Overworld_GetFlashLevel()) + return B_TRANSITION_SHUFFLE; + if (!MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + { + switch (gMapHeader.mapType) + { + case MAP_TYPE_UNDERGROUND: + return B_TRANSITION_SWIRL; + case MAP_TYPE_UNDERWATER: + return B_TRANSITION_BIG_POKEBALL; + default: + return B_TRANSITION_BLUR; + } + } + return B_TRANSITION_BIG_POKEBALL; +} + +static u16 GetSumOfPlayerPartyLevel(u8 numMons) +{ + u8 sum = 0; + int i; + + for (i = 0; i < PARTY_SIZE; i++) + { + u32 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + + if (species != SPECIES_EGG && species != SPECIES_NONE && GetMonData(&gPlayerParty[i], MON_DATA_HP) != 0) + { + sum += GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); + if (--numMons == 0) + break; + } + } + return sum; +} + +static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons) +{ + u8 i; + u8 sum; + u32 count = numMons; + + if (gTrainers[opponentId].partySize < count) + count = gTrainers[opponentId].partySize; + + sum = 0; + + switch (gTrainers[opponentId].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *party; + party = gTrainers[opponentId].party.NoItemDefaultMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_CUSTOM_MOVESET: + { + const struct TrainerMonNoItemCustomMoves *party; + party = gTrainers[opponentId].party.NoItemCustomMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemDefaultMoves *party; + party = gTrainers[opponentId].party.ItemDefaultMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemCustomMoves *party; + party = gTrainers[opponentId].party.ItemCustomMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + } + + return sum; +} + +static u8 GetWildBattleTransition(void) +{ + u8 transitionType = GetBattleTransitionTypeByMap(); + u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); + u8 playerLevel = GetSumOfPlayerPartyLevel(1); + + if (enemyLevel < playerLevel) + { + if (InBattlePyramid()) + return B_TRANSITION_BLUR; + else + return sBattleTransitionTable_Wild[transitionType][0]; + } + else + { + if (InBattlePyramid()) + return B_TRANSITION_GRID_SQUARES; + else + return sBattleTransitionTable_Wild[transitionType][1]; + } +} + +static u8 GetTrainerBattleTransition(void) +{ + u8 minPartyCount; + u8 transitionType; + u8 enemyLevel; + u8 playerLevel; + + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + return B_TRANSITION_CHAMPION; + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_ELITE_FOUR) + { + if (gTrainerBattleOpponent_A == TRAINER_SIDNEY) + return B_TRANSITION_SYDNEY; + if (gTrainerBattleOpponent_A == TRAINER_PHOEBE) + return B_TRANSITION_PHOEBE; + if (gTrainerBattleOpponent_A == TRAINER_GLACIA) + return B_TRANSITION_GLACIA; + if (gTrainerBattleOpponent_A == TRAINER_DRAKE) + return B_TRANSITION_DRAKE; + return B_TRANSITION_CHAMPION; + } + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_CHAMPION) + return B_TRANSITION_CHAMPION; + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_TEAM_MAGMA + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_MAGMA_LEADER + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_MAGMA_ADMIN) + return B_TRANSITION_MAGMA; + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_TEAM_AQUA + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_AQUA_LEADER + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_AQUA_ADMIN) + return B_TRANSITION_AQUA; + + if (gTrainers[gTrainerBattleOpponent_A].doubleBattle == TRUE) + minPartyCount = 2; // double battles always at least have 2 pokemon. + else + minPartyCount = 1; + + transitionType = GetBattleTransitionTypeByMap(); + enemyLevel = GetSumOfEnemyPartyLevel(gTrainerBattleOpponent_A, minPartyCount); + playerLevel = GetSumOfPlayerPartyLevel(minPartyCount); + + if (enemyLevel < playerLevel) + return sBattleTransitionTable_Trainer[transitionType][0]; + else + return sBattleTransitionTable_Trainer[transitionType][1]; +} + +u8 sub_80B100C(s32 arg0) +{ + u16 var; + u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); + u8 playerLevel = GetSumOfPlayerPartyLevel(1); + + if (enemyLevel < playerLevel) + { + switch (arg0) + { + case 11: + case 12: + case 13: + return B_TRANSITION_POKEBALLS_TRAIL; + case 10: + return sUnknown_0854FEA4[Random() % ARRAY_COUNT(sUnknown_0854FEA4)]; + case 3: + return sUnknown_0854FEA7[Random() % ARRAY_COUNT(sUnknown_0854FEA7)]; + } + + if (VarGet(VAR_0x40CE) != 3) + return sUnknown_0854FE98[Random() % ARRAY_COUNT(sUnknown_0854FE98)]; + } + else + { + switch (arg0) + { + case 11: + case 12: + case 13: + return B_TRANSITION_BIG_POKEBALL; + case 10: + return sUnknown_0854FEA4[Random() % ARRAY_COUNT(sUnknown_0854FEA4)]; + case 3: + return sUnknown_0854FEA7[Random() % ARRAY_COUNT(sUnknown_0854FEA7)]; + } + + if (VarGet(VAR_0x40CE) != 3) + return sUnknown_0854FE98[Random() % ARRAY_COUNT(sUnknown_0854FE98)]; + } + + var = gSaveBlock2Ptr->field_CB4[gSaveBlock2Ptr->battlePyramidWildHeaderId * 2 + 0] + + gSaveBlock2Ptr->field_CB4[gSaveBlock2Ptr->battlePyramidWildHeaderId * 2 + 1]; + + return sUnknown_0854FE98[var % ARRAY_COUNT(sUnknown_0854FE98)]; +} + +void ChooseStarter(void) +{ + SetMainCallback2(CB2_ChooseStarter); + gMain.savedCallback = CB2_GiveStarter; +} + +static void CB2_GiveStarter(void) +{ + u16 starterMon; + + *GetVarPointer(VAR_FIRST_POKE) = gSpecialVar_Result; + starterMon = GetStarterPokemon(gSpecialVar_Result); + ScriptGiveMon(starterMon, 5, 0, 0, 0, 0); + ResetTasks(); + PlayBattleBGM(); + SetMainCallback2(CB2_StartFirstBattle); + BattleTransition_Start(B_TRANSITION_BLUR); +} + +static void CB2_StartFirstBattle(void) +{ + UpdatePaletteFade(); + RunTasks(); + + if (IsBattleTransitionDone() == TRUE) + { + gBattleTypeFlags = BATTLE_TYPE_FIRST_BATTLE; + gMain.savedCallback = CB2_EndFirstBattle; + FreeAllWindowBuffers(); + SetMainCallback2(CB2_InitBattle); + prev_quest_postbuffer_cursor_backup_reset(); + ResetPoisonStepCounter(); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); + } +} + +static void CB2_EndFirstBattle(void) +{ + Overworld_ClearSavedMusic(); + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); +} + +static void sub_80B1218(void) +{ + if (GetGameStat(GAME_STAT_WILD_BATTLES) % 60 == 0) + sub_81DA57C(); +} + +static void sub_80B1234(void) +{ + if (GetGameStat(GAME_STAT_TRAINER_BATTLES) % 20 == 0) + sub_81DA57C(); +} + +// why not just use the macros? maybe its because they didnt want to uncast const every time? +static u32 TrainerBattleLoadArg32(const u8 *ptr) +{ + return T1_READ_32(ptr); +} + +static u16 TrainerBattleLoadArg16(const u8 *ptr) +{ + return T1_READ_16(ptr); +} + +static u8 TrainerBattleLoadArg8(const u8 *ptr) +{ + return T1_READ_8(ptr); +} + +static u16 GetTrainerAFlag(void) +{ + return FLAG_TRAINER_FLAG_START + gTrainerBattleOpponent_A; +} + +static u16 GetTrainerBFlag(void) +{ + return FLAG_TRAINER_FLAG_START + gTrainerBattleOpponent_B; +} + +static bool32 IsPlayerDefeated(u32 battleOutcome) +{ + switch (battleOutcome) + { + case BATTLE_LOST: + case BATTLE_DREW: + return TRUE; + case BATTLE_WON: + case BATTLE_RAN: + case BATTLE_PLAYER_TELEPORTED: + case BATTLE_POKE_FLED: + case BATTLE_CAUGHT: + return FALSE; + default: + return FALSE; + } +} + +void ResetTrainerOpponentIds(void) +{ + gTrainerBattleOpponent_A = 0; + gTrainerBattleOpponent_B = 0; +} + +static void InitTrainerBattleVariables(void) +{ + sTrainerBattleMode = 0; + if (gApproachingTrainerId == 0) + { + sTrainerAIntroSpeech = NULL; + sTrainerADefeatSpeech = NULL; + sTrainerABattleScriptRetAddr = NULL; + } + else + { + sTrainerBIntroSpeech = NULL; + sTrainerBDefeatSpeech = NULL; + sTrainerBBattleScriptRetAddr = NULL; + } + sTrainerMapObjectLocalId = 0; + sTrainerVictorySpeech = NULL; + sTrainerCannotBattleSpeech = NULL; + sTrainerBattleEndScript = NULL; +} + +static inline void SetU8(void *ptr, u8 value) +{ + *(u8*)(ptr) = value; +} + +static inline void SetU16(void *ptr, u16 value) +{ + *(u16*)(ptr) = value; +} + +static inline void SetU32(void *ptr, u32 value) +{ + *(u32*)(ptr) = value; +} + +static inline void SetPtr(const void *ptr, const void* value) +{ + *(const void**)(ptr) = value; +} + +static void TrainerBattleLoadArgs(const struct TrainerBattleParameter *specs, const u8 *data) +{ + while (1) + { + switch (specs->ptrType) + { + case TRAINER_PARAM_LOAD_VAL_8BIT: + SetU8(specs->varPtr, TrainerBattleLoadArg8(data)); + data += 1; + break; + case TRAINER_PARAM_LOAD_VAL_16BIT: + SetU16(specs->varPtr, TrainerBattleLoadArg16(data)); + data += 2; + break; + case TRAINER_PARAM_LOAD_VAL_32BIT: + SetU32(specs->varPtr, TrainerBattleLoadArg32(data)); + data += 4; + break; + case TRAINER_PARAM_CLEAR_VAL_8BIT: + SetU8(specs->varPtr, 0); + break; + case TRAINER_PARAM_CLEAR_VAL_16BIT: + SetU16(specs->varPtr, 0); + break; + case TRAINER_PARAM_CLEAR_VAL_32BIT: + SetU32(specs->varPtr, 0); + break; + case TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR: + SetPtr(specs->varPtr, data); + return; + } + specs++; + } +} + +void SetMapVarsToTrainer(void) +{ + if (sTrainerMapObjectLocalId != 0) + { + gSpecialVar_LastTalked = sTrainerMapObjectLocalId; + gSelectedMapObject = GetFieldObjectIdByLocalIdAndMap(sTrainerMapObjectLocalId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + } +} + +const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data) +{ + InitTrainerBattleVariables(); + sTrainerBattleMode = TrainerBattleLoadArg8(data); + + switch (sTrainerBattleMode) + { + case 3: + TrainerBattleLoadArgs(sOrdinaryNoIntroBattleParams, data); + return EventScript_2713C2; + case 4: + TrainerBattleLoadArgs(sDoubleBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoDoubleTrainerBattle; + case 2: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sContinueScriptBattleParams, data); + SetMapVarsToTrainer(); + } + else + { + TrainerBattleLoadArgs(sTrainerBContinueScriptBattleParams, data); + } + return EventScript_271362; + case 1: + TrainerBattleLoadArgs(sContinueScriptBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_271362; + case 6: + case 8: + TrainerBattleLoadArgs(sContinueScriptDoubleBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoDoubleTrainerBattle; + case 7: + TrainerBattleLoadArgs(sDoubleBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = GetRematchTrainerId(gTrainerBattleOpponent_A); + return EventScript_TryDoDoubleRematchBattle; + case 5: + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = GetRematchTrainerId(gTrainerBattleOpponent_A); + return EventScript_2713D1; + case 9: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = sub_81A9AA8(gSpecialVar_LastTalked); + } + else + { + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + gTrainerBattleOpponent_B = sub_81A9AA8(gSpecialVar_LastTalked); + } + return EventScript_271362; + case 10: + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + return NULL; + case 11: + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + return NULL; + case 12: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = sub_81D6180(gSpecialVar_LastTalked); + } + else + { + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + gTrainerBattleOpponent_B = sub_81D6180(gSpecialVar_LastTalked); + } + return EventScript_271362; + default: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + } + else + { + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + } + return EventScript_271362; + } +} + +void ConfigureAndSetUpOneTrainerBattle(u8 trainerMapObjId, const u8 *trainerScript) +{ + gSelectedMapObject = trainerMapObjId; + gSpecialVar_LastTalked = gMapObjects[trainerMapObjId].localId; + BattleSetup_ConfigureTrainerBattle(trainerScript + 1); + ScriptContext1_SetupScript(EventScript_271354); + ScriptContext2_Enable(); +} + +void ConfigureTwoTrainersBattle(u8 trainerMapObjId, const u8 *trainerScript) +{ + gSelectedMapObject = trainerMapObjId; + gSpecialVar_LastTalked = gMapObjects[trainerMapObjId].localId; + BattleSetup_ConfigureTrainerBattle(trainerScript + 1); +} + +void SetUpTwoTrainersBattle(void) +{ + ScriptContext1_SetupScript(EventScript_271354); + ScriptContext2_Enable(); +} + +bool32 GetTrainerFlagFromScriptPointer(const u8 *data) +{ + u32 flag = TrainerBattleLoadArg16(data + 2); + return FlagGet(FLAG_TRAINER_FLAG_START + flag); +} + +void sub_80B16D8(void) +{ + struct MapObject *mapObject = &gMapObjects[gSelectedMapObject]; + + npc_set_running_behaviour_etc(mapObject, npc_running_behaviour_by_direction(mapObject->mapobj_unk_18)); +} + +u8 GetTrainerBattleMode(void) +{ + return sTrainerBattleMode; +} + +bool8 GetTrainerFlag(void) +{ + if (InBattlePyramid()) + return GetBattlePyramidTrainerFlag(gSelectedMapObject); + else if (InTrainerHill()) + return GetTrainerHillTrainerFlag(gSelectedMapObject); + else + return FlagGet(GetTrainerAFlag()); +} + +static void SetBattledTrainersFlags(void) +{ + if (gTrainerBattleOpponent_B != 0) + FlagSet(GetTrainerBFlag()); + FlagSet(GetTrainerAFlag()); +} + +static void SetBattledTrainerFlag(void) +{ + FlagSet(GetTrainerAFlag()); +} + +bool8 HasTrainerBeenFought(u16 trainerId) +{ + return FlagGet(FLAG_TRAINER_FLAG_START + trainerId); +} + +void SetTrainerFlag(u16 trainerId) +{ + FlagSet(FLAG_TRAINER_FLAG_START + trainerId); +} + +void ClearTrainerFlag(u16 trainerId) +{ + FlagClear(FLAG_TRAINER_FLAG_START + trainerId); +} + +void BattleSetup_StartTrainerBattle(void) +{ + if (gNoOfApproachingTrainers == 2) + gBattleTypeFlags = (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_TRAINER); + else + gBattleTypeFlags = (BATTLE_TYPE_TRAINER); + + if (InBattlePyramid()) + { + VarSet(VAR_0x400E, 0); + gBattleTypeFlags |= BATTLE_TYPE_PYRAMID; + + if (gNoOfApproachingTrainers == 2) + { + sub_816306C(1); + ZeroMonData(&gEnemyParty[1]); + ZeroMonData(&gEnemyParty[2]); + ZeroMonData(&gEnemyParty[4]); + ZeroMonData(&gEnemyParty[5]); + } + else + { + sub_8163048(1); + ZeroMonData(&gEnemyParty[1]); + ZeroMonData(&gEnemyParty[2]); + } + + sub_81A9B04(); + } + else if (sub_81D5C18()) + { + gBattleTypeFlags |= BATTLE_TYPE_x4000000; + + if (gNoOfApproachingTrainers == 2) + sub_81D639C(); + else + sub_81D6384(); + + sub_81D61E8(); + } + + sNoOfPossibleTrainerRetScripts = gNoOfApproachingTrainers; + gNoOfApproachingTrainers = 0; + sShouldCheckTrainerBScript = FALSE; + gUnknown_03006080 = 0; + gMain.savedCallback = CB2_EndTrainerBattle; + + if (InBattlePyramid() || sub_81D5C18()) + sub_80B0828(); + else + DoTrainerBattle(); + + ScriptContext1_Stop(); +} + +static void CB2_EndTrainerBattle(void) +{ + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + } + else if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + if (InBattlePyramid() || sub_81D5C18()) + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + else + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + if (!InBattlePyramid() && !sub_81D5C18()) + { + RegisterTrainerInMatchCall(); + SetBattledTrainersFlags(); + } + } +} + +static void CB2_EndRematchBattle(void) +{ + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + } + else if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + RegisterTrainerInMatchCall(); + SetBattledTrainersFlags(); + HandleRematchVarsOnBattleEnd(); + } +} + +void BattleSetup_StartRematchBattle(void) +{ + gBattleTypeFlags = BATTLE_TYPE_TRAINER; + gMain.savedCallback = CB2_EndRematchBattle; + DoTrainerBattle(); + ScriptContext1_Stop(); +} + +void ShowTrainerIntroSpeech(void) +{ + if (InBattlePyramid()) + { + if (gNoOfApproachingTrainers == 0 || gNoOfApproachingTrainers == 1) + sub_81A9EDC(sub_81A9AA8(gSpecialVar_LastTalked)); + else + sub_81A9EDC(sub_81A9AA8(gMapObjects[gApproachingTrainers[gApproachingTrainerId].mapObjectId].localId)); + + sub_80982B8(); + } + else if (sub_81D5C18()) + { + if (gNoOfApproachingTrainers == 0 || gNoOfApproachingTrainers == 1) + sub_81D572C(2, sub_81D6180(gSpecialVar_LastTalked)); + else + sub_81D572C(2, sub_81D6180(gMapObjects[gApproachingTrainers[gApproachingTrainerId].mapObjectId].localId)); + + sub_80982B8(); + } + else + { + ShowFieldMessage(GetIntroSpeechOfApproachingTrainer()); + } +} + +const u8 *BattleSetup_GetScriptAddrAfterBattle(void) +{ + if (sTrainerBattleEndScript != NULL) + return sTrainerBattleEndScript; + else + return EventScript_TestSignpostMsg; +} + +const u8 *BattleSetup_GetTrainerPostBattleScript(void) +{ + if (sShouldCheckTrainerBScript) + { + sShouldCheckTrainerBScript = FALSE; + if (sTrainerBBattleScriptRetAddr != NULL) + { + gUnknown_03006080 = 1; + return sTrainerBBattleScriptRetAddr; + } + } + else + { + if (sTrainerABattleScriptRetAddr != NULL) + { + gUnknown_03006080 = 0; + return sTrainerABattleScriptRetAddr; + } + } + + return EventScript_TryGetTrainerScript; +} + +void ShowTrainerCantBattleSpeech(void) +{ + ShowFieldMessage(GetTrainerCantBattleSpeech()); +} + +void SetUpTrainerEncounterMusic(void) +{ + u16 trainerId; + u16 music; + + if (gApproachingTrainerId == 0) + trainerId = gTrainerBattleOpponent_A; + else + trainerId = gTrainerBattleOpponent_B; + + if (sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_NO_MUSIC + && sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE_NO_MUSIC) + { + switch (GetTrainerEncounterMusicId(trainerId)) + { + case TRAINER_ENCOUNTER_MUSIC_MALE: + music = BGM_BOYEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_FEMALE: + music = BGM_GIRLEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_GIRL: + music = BGM_SYOUJOEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_INTENSE: + music = BGM_HAGESHII; + break; + case TRAINER_ENCOUNTER_MUSIC_COOL: + music = BGM_KAKKOII; + break; + case TRAINER_ENCOUNTER_MUSIC_AQUA: + music = BGM_AQA_0; + break; + case TRAINER_ENCOUNTER_MUSIC_MAGMA: + music = BGM_MGM0; + break; + case TRAINER_ENCOUNTER_MUSIC_SWIMMER: + music = BGM_SWIMEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_TWINS: + music = BGM_HUTAGO; + break; + case TRAINER_ENCOUNTER_MUSIC_ELITE_FOUR: + music = BGM_SITENNOU; + break; + case TRAINER_ENCOUNTER_MUSIC_HIKER: + music = BGM_YAMA_EYE; + break; + case TRAINER_ENCOUNTER_MUSIC_INTERVIEWER: + music = BGM_INTER_V; + break; + case TRAINER_ENCOUNTER_MUSIC_RICH: + music = BGM_TEST; + break; + default: + music = BGM_AYASII; + } + PlayNewMapMusic(music); + } +} + +static const u8 *ReturnEmptyStringIfNull(const u8 *string) +{ + if (string == NULL) + return gText_EmptyString2; + else + return string; +} + +static const u8 *GetIntroSpeechOfApproachingTrainer(void) +{ + if (gApproachingTrainerId == 0) + return ReturnEmptyStringIfNull(sTrainerAIntroSpeech); + else + return ReturnEmptyStringIfNull(sTrainerBIntroSpeech); +} + +const u8 *GetTrainerALoseText(void) +{ + const u8 *string; + + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + string = GetSecretBaseTrainerLoseText(); + else + string = sTrainerADefeatSpeech; + + StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(string)); + return gStringVar4; +} + +const u8 *GetTrainerBLoseText(void) +{ + StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(sTrainerBDefeatSpeech)); + return gStringVar4; +} + +const u8 *GetTrainerWonSpeech(void) +{ + return ReturnEmptyStringIfNull(sTrainerVictorySpeech); +} + +static const u8 *GetTrainerCantBattleSpeech(void) +{ + return ReturnEmptyStringIfNull(sTrainerCannotBattleSpeech); +} + +static s32 FirstBattleTrainerIdToRematchTableId(const struct RematchTrainer *table, u16 trainerId) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (table[i].trainerIds[0] == trainerId) + return i; + } + + return -1; +} + +static s32 TrainerIdToRematchTableId(const struct RematchTrainer *table, u16 trainerId) +{ + s32 i, j; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + for (j = 0; j < REMATCHES_COUNT; j++) + { + if (table[i].trainerIds[j] == 0) + break; + if (table[i].trainerIds[j] == trainerId) + return i; + } + } + + return -1; +} + +static bool32 sub_80B1D94(s32 rematchTableId) +{ + if (rematchTableId >= REMATCH_ELITE_FOUR_ENTRIES) + return TRUE; + else if (rematchTableId == REMATCH_WALLY_ENTRY) + return (FlagGet(FLAG_0x07E) == FALSE); + else + return FALSE; +} + +static void SetRematchIdForTrainer(const struct RematchTrainer *table, u32 tableId) +{ + s32 i; + + for (i = 1; i < REMATCHES_COUNT; i++) + { + u16 trainerId = table[tableId].trainerIds[i]; + + if (trainerId == 0) + break; + if (!HasTrainerBeenFought(trainerId)) + break; + } + + gSaveBlock1Ptr->trainerRematches[tableId] = i; +} + +static bool32 UpdateRandomTrainerRematches(const struct RematchTrainer *table, u16 mapGroup, u16 mapNum) +{ + s32 i; + bool32 ret = FALSE; + + for (i = 0; i <= REMATCH_WALLY_ENTRY; i++) + { + if (table[i].mapGroup == mapGroup && table[i].mapNum == mapNum && !sub_80B1D94(i)) + { + if (gSaveBlock1Ptr->trainerRematches[i] != 0) + { + // Trainer already wants a rematch. Don't bother updating it + ret = TRUE; + } + else if (FlagGet(FLAG_MATCH_CALL_REGISTERED + i) + && (Random() % 100) <= 30) // 31% chance of getting a rematch + { + SetRematchIdForTrainer(table, i); + ret = TRUE; + } + } + } + + return ret; +} + +void UpdateRematchIfDefeated(s32 rematchTableId) +{ + if (HasTrainerBeenFought(gRematchTable[rematchTableId].trainerIds[0]) == TRUE) + SetRematchIdForTrainer(gRematchTable, rematchTableId); +} + +static bool32 DoesSomeoneWantRematchIn_(const struct RematchTrainer *table, u16 mapGroup, u16 mapNum) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (table[i].mapGroup == mapGroup && table[i].mapNum == mapNum && gSaveBlock1Ptr->trainerRematches[i] != 0) + return TRUE; + } + + return FALSE; +} + +static bool32 IsRematchTrainerIn_(const struct RematchTrainer *table, u16 mapGroup, u16 mapNum) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (table[i].mapGroup == mapGroup && table[i].mapNum == mapNum) + return TRUE; + } + + return FALSE; +} + +static bool8 IsFirstTrainerIdReadyForRematch(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + if (tableId >= 100) + return FALSE; + if (gSaveBlock1Ptr->trainerRematches[tableId] == 0) + return FALSE; + + return TRUE; +} + +static bool8 IsTrainerReadyForRematch_(const struct RematchTrainer *table, u16 trainerId) +{ + s32 tableId = TrainerIdToRematchTableId(table, trainerId); + + if (tableId == -1) + return FALSE; + if (tableId >= 100) + return FALSE; + if (gSaveBlock1Ptr->trainerRematches[tableId] == 0) + return FALSE; + + return TRUE; +} + +static u16 GetRematchTrainerIdFromTable(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + const struct RematchTrainer *trainerEntry; + s32 i; + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + + trainerEntry = &table[tableId]; + for (i = 1; i < REMATCHES_COUNT; i++) + { + if (trainerEntry->trainerIds[i] == 0) // previous entry was this trainer's last one + return trainerEntry->trainerIds[i - 1]; + if (!HasTrainerBeenFought(trainerEntry->trainerIds[i])) + return trainerEntry->trainerIds[i]; + } + + return trainerEntry->trainerIds[REMATCHES_COUNT - 1]; // already beaten at max stage +} + +static u16 GetLastBeatenRematchTrainerIdFromTable(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + const struct RematchTrainer *trainerEntry; + s32 i; + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + + trainerEntry = &table[tableId]; + for (i = 1; i < REMATCHES_COUNT; i++) + { + if (trainerEntry->trainerIds[i] == 0) // previous entry was this trainer's last one + return trainerEntry->trainerIds[i - 1]; + if (!HasTrainerBeenFought(trainerEntry->trainerIds[i])) + return trainerEntry->trainerIds[i - 1]; + } + + return trainerEntry->trainerIds[REMATCHES_COUNT - 1]; // already beaten at max stage +} + +static void ClearTrainerWantRematchState(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + s32 tableId = TrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId != -1) + gSaveBlock1Ptr->trainerRematches[tableId] = 0; +} + +static u32 GetTrainerMatchCallFlag(u32 trainerId) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (gRematchTable[i].trainerIds[0] == trainerId) + return FLAG_MATCH_CALL_REGISTERED + i; + } + + return 0xFFFF; +} + +static void RegisterTrainerInMatchCall(void) +{ + if (FlagGet(FLAG_HAS_MATCH_CALL)) + { + u32 matchCallFlagId = GetTrainerMatchCallFlag(gTrainerBattleOpponent_A); + if (matchCallFlagId != 0xFFFF) + FlagSet(matchCallFlagId); + } +} + +static bool8 WasSecondRematchWon(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + if (!HasTrainerBeenFought(table[tableId].trainerIds[1])) + return FALSE; + + return TRUE; +} + +static bool32 HasAtLeastFiveBadges(void) +{ + s32 i, count; + + for (count = 0, i = 0; i < ARRAY_COUNT(sBadgeFlags); i++) + { + if (FlagGet(sBadgeFlags[i]) == TRUE) + { + if (++count >= 5) + return TRUE; + } + } + + return FALSE; +} + +#define STEP_COUNTER_MAX 255 + +void IncrementRematchStepCounter(void) +{ + if (HasAtLeastFiveBadges()) + { + if (gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX) + gSaveBlock1Ptr->trainerRematchStepCounter = STEP_COUNTER_MAX; + else + gSaveBlock1Ptr->trainerRematchStepCounter++; + } +} + +static bool32 IsRematchStepCounterMaxed(void) +{ + if (HasAtLeastFiveBadges() && gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX) + return TRUE; + else + return FALSE; +} + +void TryUpdateRandomTrainerRematches(u16 mapGroup, u16 mapNum) +{ + if (IsRematchStepCounterMaxed() && UpdateRandomTrainerRematches(gRematchTable, mapGroup, mapNum) == TRUE) + gSaveBlock1Ptr->trainerRematchStepCounter = 0; +} + +bool32 DoesSomeoneWantRematchIn(u16 mapGroup, u16 mapNum) +{ + return DoesSomeoneWantRematchIn_(gRematchTable, mapGroup, mapNum); +} + +bool32 IsRematchTrainerIn(u16 mapGroup, u16 mapNum) +{ + return IsRematchTrainerIn_(gRematchTable, mapGroup, mapNum); +} + +static u16 GetRematchTrainerId(u16 trainerId) +{ + return GetRematchTrainerIdFromTable(gRematchTable, trainerId); +} + +u16 GetLastBeatenRematchTrainerId(u16 trainerId) +{ + return GetLastBeatenRematchTrainerIdFromTable(gRematchTable, trainerId); +} + +bool8 ShouldTryRematchBattle(void) +{ + if (IsFirstTrainerIdReadyForRematch(gRematchTable, gTrainerBattleOpponent_A)) + return TRUE; + + return WasSecondRematchWon(gRematchTable, gTrainerBattleOpponent_A); +} + +bool8 IsTrainerReadyForRematch(void) +{ + return IsTrainerReadyForRematch_(gRematchTable, gTrainerBattleOpponent_A); +} + +static void HandleRematchVarsOnBattleEnd(void) +{ + ClearTrainerWantRematchState(gRematchTable, gTrainerBattleOpponent_A); + SetBattledTrainersFlags(); +} + +void ShouldTryGetTrainerScript(void) +{ + if (sNoOfPossibleTrainerRetScripts > 1) + { + sNoOfPossibleTrainerRetScripts = 0; + sShouldCheckTrainerBScript = TRUE; + gSpecialVar_Result = TRUE; + } + else + { + sShouldCheckTrainerBScript = FALSE; + gSpecialVar_Result = FALSE; + } +} + +u16 CountBattledRematchTeams(u16 trainerId) +{ + s32 i; + + if (HasTrainerBeenFought(gRematchTable[trainerId].trainerIds[0]) != TRUE) + return 0; + + for (i = 1; i < REMATCHES_COUNT; i++) + { + if (gRematchTable[trainerId].trainerIds[i] == 0) + break; + if (!HasTrainerBeenFought(gRematchTable[trainerId].trainerIds[i])) + break; + } + + return i; +} diff --git a/src/berry_blender.c b/src/berry_blender.c index fe646954d..810162746 100644 --- a/src/berry_blender.c +++ b/src/berry_blender.c @@ -2442,7 +2442,7 @@ static void CB2_HandleBlenderEndGame(void) sBerryBlenderData->gameEndState++; break; case 10: - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 1: case -1: diff --git a/src/clear_save_data_screen.c b/src/clear_save_data_screen.c index d00944ac1..6d6a1545b 100755 --- a/src/clear_save_data_screen.c +++ b/src/clear_save_data_screen.c @@ -88,7 +88,7 @@ static void Task_DoClearSaveDataScreenYesNo(u8 taskId) static void Task_ClearSaveDataScreenYesNoChoice(u8 taskId) { - switch(sub_8198C58()) + switch(ProcessMenuInputNoWrap_()) { case 0: FillWindowPixelBuffer(0, 17); diff --git a/src/clock.c b/src/clock.c new file mode 100644 index 000000000..7cea30166 --- /dev/null +++ b/src/clock.c @@ -0,0 +1,93 @@ +#include "global.h" +#include "rom6.h" +#include "event_data.h" +#include "rtc.h" +#include "lottery_corner.h" +#include "dewford_trend.h" +#include "tv.h" +#include "field_screen.h" +#include "berry.h" +#include "main.h" +#include "overworld.h" +#include "wallclock.h" + +// static types + +// static declarations + +static void UpdatePerDay(struct Time *localTime); +static void UpdatePerMinute(struct Time *localTime); + +// rodata + +// text + +static void InitTimeBasedEvents(void) +{ + FlagSet(FLAG_SYS_CLOCK_SET); + RtcCalcLocalTime(); + gSaveBlock2Ptr->lastBerryTreeUpdate = gLocalTime; + VarSet(VAR_DAYS, gLocalTime.days); +} + +void DoTimeBasedEvents(void) +{ + if (FlagGet(FLAG_SYS_CLOCK_SET) && !sub_813B9C0()) + { + RtcCalcLocalTime(); + UpdatePerDay(&gLocalTime); + UpdatePerMinute(&gLocalTime); + } +} + +static void UpdatePerDay(struct Time *localTime) +{ + u16 *days = GetVarPointer(VAR_DAYS); + u16 daysSince; + + if (*days != localTime->days && *days <= localTime->days) + { + daysSince = localTime->days - *days; + ClearUpperFlags(); + UpdateDewfordTrendPerDay(daysSince); + UpdateTVShowsPerDay(daysSince); + UpdateWeatherPerDay(daysSince); + UpdatePartyPokerusTime(daysSince); + UpdateMirageRnd(daysSince); + UpdateBirchState(daysSince); + UpdateFrontierManiac(daysSince); + UpdateFrontierGambler(daysSince); + SetShoalItemFlag(daysSince); + SetRandomLotteryNumber(daysSince); + *days = localTime->days; + } +} + +static void UpdatePerMinute(struct Time *localTime) +{ + struct Time difference; + int minutes; + + CalcTimeDifference(&difference, &gSaveBlock2Ptr->lastBerryTreeUpdate, localTime); + minutes = 24 * 60 * difference.days + 60 * difference.hours + difference.minutes; + if (minutes != 0) + { + if (minutes >= 0) + { + BerryTreeTimeUpdate(minutes); + gSaveBlock2Ptr->lastBerryTreeUpdate = *localTime; + } + } +} + +static void ReturnFromStartWallClock(void) +{ + InitTimeBasedEvents(); + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); +} + +void StartWallClock(void) +{ + SetMainCallback2(Cb2_StartWallClock); + gMain.savedCallback = ReturnFromStartWallClock; +} diff --git a/src/egg_hatch.c b/src/egg_hatch.c index 032607806..a31eb0520 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -58,7 +58,7 @@ extern const u8 gText_HatchedFromEgg[]; extern const u8 gText_NickHatchPrompt[]; extern u8 sav1_map_get_name(void); -extern s8 sub_8198C58(void); +extern s8 ProcessMenuInputNoWrap_(void); extern void TVShowConvertInternationalString(u8* str1, u8* str2, u8); extern void sub_806A068(u16, u8); extern void fade_screen(u8, u8); @@ -669,7 +669,7 @@ static void CB2_EggHatch_1(void) } break; case 10: - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 0: GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar3); diff --git a/src/evolution_scene.c b/src/evolution_scene.c index c17921b74..2b88fec3a 100644 --- a/src/evolution_scene.c +++ b/src/evolution_scene.c @@ -1168,7 +1168,7 @@ static void Task_TradeEvolutionScene(u8 taskID) } break; case 4: - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 0: sEvoCursorPos = 0; diff --git a/src/load_save.c b/src/load_save.c index 2b40f2e92..e0106c0a8 100644 --- a/src/load_save.c +++ b/src/load_save.c @@ -1,4 +1,4 @@ -#include "global.h" +#include "global.h" #include "gba/flash_internal.h" #include "load_save.h" #include "main.h" @@ -28,7 +28,7 @@ struct LoadedSaveData /*0x00F0*/ struct ItemSlot pokeBalls[16]; /*0x0130*/ struct ItemSlot TMsHMs[64]; /*0x0230*/ struct ItemSlot berries[46]; - /*0x02E8*/ struct MailStruct mail[16]; + /*0x02E8*/ struct MailStruct mail[MAIL_COUNT]; }; EWRAM_DATA struct SaveBlock2 gSaveblock2 = {0}; @@ -330,7 +330,7 @@ void LoadSerializedGame(void) void copy_bags_and_unk_data_from_save_blocks(void) { int i; - + // load player items. for (i = 0; i < 30; i++) gLoadedSaveData.items[i] = gSaveBlock1Ptr->bagPocket_Items[i]; diff --git a/src/mail.c b/src/mail.c index 877035fb6..ec7ff2ce2 100644 --- a/src/mail.c +++ b/src/mail.c @@ -1,4 +1,5 @@ #include "global.h" +#include "mail.h" #include "constants/items.h" #include "main.h" #include "overworld.h" @@ -18,8 +19,43 @@ #include "constants/species.h" #include "malloc.h" #include "easy_chat.h" -#include "mail_data.h" -#include "mail.h" + +extern const u16 gUnknown_08DBE818[]; +extern const u16 gUnknown_08DBE838[]; +extern const u16 gUnknown_08DBE858[]; +extern const u16 gUnknown_08DBE878[]; +extern const u16 gUnknown_08DBE898[]; +extern const u16 gUnknown_08DBE8B8[]; +extern const u16 gUnknown_08DBE8D8[]; +extern const u16 gUnknown_08DBE8F8[]; +extern const u16 gUnknown_08DBE918[]; +extern const u16 gUnknown_08DBE938[]; +extern const u16 gUnknown_08DBE958[]; +extern const u16 gUnknown_08DBE978[]; +extern const u8 gUnknown_08DBE998[]; +extern const u8 gUnknown_08DBFBA4[]; +extern const u8 gUnknown_08DBEB38[]; +extern const u8 gUnknown_08DBFC7C[]; +extern const u8 gUnknown_08DBEC74[]; +extern const u8 gUnknown_08DBFD5C[]; +extern const u8 gUnknown_08DBEE84[]; +extern const u8 gUnknown_08DBFE68[]; +extern const u8 gUnknown_08DBEF5C[]; +extern const u8 gUnknown_08DBFF44[]; +extern const u8 gUnknown_08DBF154[]; +extern const u8 gUnknown_08DC0034[]; +extern const u8 gUnknown_08DBF2D4[]; +extern const u8 gUnknown_08DC0114[]; +extern const u8 gUnknown_08DBF37C[]; +extern const u8 gUnknown_08DC01F4[]; +extern const u8 gUnknown_08DBF50C[]; +extern const u8 gUnknown_08DC0300[]; +extern const u8 gUnknown_08DBF64C[]; +extern const u8 gUnknown_08DC03F0[]; +extern const u8 gUnknown_08DBF7B4[]; +extern const u8 gUnknown_08DC04E8[]; +extern const u8 gUnknown_08DBF904[]; +extern const u8 gUnknown_08DC0600[]; // Static type declarations @@ -51,9 +87,7 @@ struct MailGraphics u16 color12; }; -// Static RAM declarations - -static EWRAM_DATA struct +struct MailRead { /*0x0000*/ u8 strbuf[8][64]; /*0x0200*/ u8 playerName[12]; @@ -72,22 +106,26 @@ static EWRAM_DATA struct /*0x0228*/ const struct MailLayout *layout; /*0x022c*/ u8 bg1TilemapBuffer[0x1000]; /*0x122c*/ u8 bg2TilemapBuffer[0x1000]; -} *gUnknown_0203A134 = NULL; +}; + +// Static RAM declarations + +static EWRAM_DATA struct MailRead *sMailRead = NULL; // Static ROM declarations -void sub_81219F0(void); -void sub_8121A1C(void); -void sub_8121B1C(void); -void sub_8121C50(void); -void sub_8121C64(void); -void sub_8121C98(void); -void sub_8121CC0(void); -void sub_8121D00(void); +static void CB2_InitMailRead(void); +static void sub_8121A1C(void); +static void sub_8121B1C(void); +static void VBlankCB_MailRead(void); +static void CB2_MailRead(void); +static void CB2_WaitForPaletteExitOnKeyPress(void); +static void CB2_ExitOnKeyPress(void); +static void CB2_ExitMailReadFreeVars(void); // .rodata -const struct BgTemplate gUnknown_0859F290[] = { +static const struct BgTemplate sUnknown_0859F290[] = { { .bg = 0, .charBaseIndex = 2, @@ -106,7 +144,7 @@ const struct BgTemplate gUnknown_0859F290[] = { } }; -const struct WindowTemplate gUnknown_0859F29C[] = { +static const struct WindowTemplate sUnknown_0859F29C[] = { { .priority = 0, .tilemapLeft = 2, @@ -119,55 +157,18 @@ const struct WindowTemplate gUnknown_0859F29C[] = { DUMMY_WIN_TEMPLATE }; -const u8 gUnknown_0859F2AC[] = { +static const u8 sUnknown_0859F2AC[] = { 0, 10, 11 }; -const u16 gUnknown_0859F2B0[][2] = { +static const u16 sUnknown_0859F2B0[][2] = { { 0x6ACD, 0x51A5 }, { 0x45FC, 0x38D4 } }; -extern const u16 gUnknown_08DBE818[]; -extern const u16 gUnknown_08DBE838[]; -extern const u16 gUnknown_08DBE858[]; -extern const u16 gUnknown_08DBE878[]; -extern const u16 gUnknown_08DBE898[]; -extern const u16 gUnknown_08DBE8B8[]; -extern const u16 gUnknown_08DBE8D8[]; -extern const u16 gUnknown_08DBE8F8[]; -extern const u16 gUnknown_08DBE918[]; -extern const u16 gUnknown_08DBE938[]; -extern const u16 gUnknown_08DBE958[]; -extern const u16 gUnknown_08DBE978[]; -extern const u8 gUnknown_08DBE998[]; -extern const u8 gUnknown_08DBFBA4[]; -extern const u8 gUnknown_08DBEB38[]; -extern const u8 gUnknown_08DBFC7C[]; -extern const u8 gUnknown_08DBEC74[]; -extern const u8 gUnknown_08DBFD5C[]; -extern const u8 gUnknown_08DBEE84[]; -extern const u8 gUnknown_08DBFE68[]; -extern const u8 gUnknown_08DBEF5C[]; -extern const u8 gUnknown_08DBFF44[]; -extern const u8 gUnknown_08DBF154[]; -extern const u8 gUnknown_08DC0034[]; -extern const u8 gUnknown_08DBF2D4[]; -extern const u8 gUnknown_08DC0114[]; -extern const u8 gUnknown_08DBF37C[]; -extern const u8 gUnknown_08DC01F4[]; -extern const u8 gUnknown_08DBF50C[]; -extern const u8 gUnknown_08DC0300[]; -extern const u8 gUnknown_08DBF64C[]; -extern const u8 gUnknown_08DC03F0[]; -extern const u8 gUnknown_08DBF7B4[]; -extern const u8 gUnknown_08DC04E8[]; -extern const u8 gUnknown_08DBF904[]; -extern const u8 gUnknown_08DC0600[]; - -const struct MailGraphics gUnknown_0859F2B8[] = { +static const struct MailGraphics sUnknown_0859F2B8[] = { { gUnknown_08DBE818, gUnknown_08DBE998, gUnknown_08DBFBA4, 0x02c0, 0x0000, 0x294a, 0x6739 }, { @@ -195,13 +196,13 @@ const struct MailGraphics gUnknown_0859F2B8[] = { } }; -const struct UnkMailStruct Unknown_0859F3A8[] = { +static const struct UnkMailStruct Unknown_0859F3A8[] = { { .numEasyChatWords = 3, .lineHeight = 16 }, { .numEasyChatWords = 3, .lineHeight = 16 }, { .numEasyChatWords = 3, .lineHeight = 16 } }; -const struct MailLayout gUnknown_0859F3B4[] = { +static const struct MailLayout sUnknown_0859F3B4[] = { { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, @@ -216,7 +217,7 @@ const struct MailLayout gUnknown_0859F3B4[] = { { 0x03, 0x00, 0x00, 0x02, 0x00, Unknown_0859F3A8 } }; -const struct UnkMailStruct Unknown_0859F444[] = { +static const struct UnkMailStruct Unknown_0859F444[] = { { .numEasyChatWords = 2, .lineHeight = 16 }, { .numEasyChatWords = 2, .lineHeight = 16 }, { .numEasyChatWords = 2, .lineHeight = 16 }, @@ -224,7 +225,7 @@ const struct UnkMailStruct Unknown_0859F444[] = { { .numEasyChatWords = 1, .lineHeight = 16 } }; -const struct MailLayout gUnknown_0859F458[] = { +static const struct MailLayout sUnknown_0859F458[] = { { 0x05, 0x07, 0x58, 0x0b, 0x1e, Unknown_0859F444 }, { 0x05, 0x0a, 0x60, 0x09, 0x1e, Unknown_0859F444 }, { 0x05, 0x0c, 0x68, 0x05, 0x1e, Unknown_0859F444 }, @@ -241,23 +242,23 @@ const struct MailLayout gUnknown_0859F458[] = { // What the heck are these meant to be? Call them u16 for now. -const u16 Unknown_0859F4E8[] = { +static const u16 Unknown_0859F4E8[] = { 0x00, 0x4000, 0x00, 0x00 }; -const u16 Unknown_0859F4F0[] = { +static const u16 Unknown_0859F4F0[] = { 0x00, 0x00, -1, 0x00 }; -const u16 Unknown_0859F4F8[] = { +static const u16 Unknown_0859F4F8[] = { 0x04, 0x00, -1, 0x00 }; -const u16 Unknown_0859F500[] = { +static const u16 Unknown_0859F500[] = { 0x00, 0x40, -1, 0x00 }; -const u16 *const gUnknown_0859F508[] = { +static const u16 *const sUnknown_0859F508[] = { Unknown_0859F4F0, Unknown_0859F4F8, Unknown_0859F500 @@ -265,60 +266,62 @@ const u16 *const gUnknown_0859F508[] = { // .text -void sub_8121478(struct MailStruct *mail, MainCallback callback, bool8 flag) { +void ReadMail(struct MailStruct *mail, void (*callback)(void), bool8 flag) +{ u16 buffer[2]; u16 species; - gUnknown_0203A134 = calloc(1, sizeof(*gUnknown_0203A134)); - gUnknown_0203A134->language = LANGUAGE_ENGLISH; - gUnknown_0203A134->playerIsSender = TRUE; - gUnknown_0203A134->parserSingle = CopyEasyChatWord; - gUnknown_0203A134->parserMultiple = ConvertEasyChatWordsToString; - if (mail->itemId >= ITEM_ORANGE_MAIL && mail->itemId <= ITEM_RETRO_MAIL) { - gUnknown_0203A134->mailType = mail->itemId - ITEM_ORANGE_MAIL; + sMailRead = calloc(1, sizeof(*sMailRead)); + sMailRead->language = LANGUAGE_ENGLISH; + sMailRead->playerIsSender = TRUE; + sMailRead->parserSingle = CopyEasyChatWord; + sMailRead->parserMultiple = ConvertEasyChatWordsToString; + if (IS_ITEM_MAIL(mail->itemId)) + { + sMailRead->mailType = mail->itemId - ITEM_ORANGE_MAIL; } else { - gUnknown_0203A134->mailType = 0; + sMailRead->mailType = 0; flag = FALSE; } - switch (gUnknown_0203A134->playerIsSender) + switch (sMailRead->playerIsSender) { case FALSE: default: - gUnknown_0203A134->layout = &gUnknown_0859F3B4[gUnknown_0203A134->mailType]; + sMailRead->layout = &sUnknown_0859F3B4[sMailRead->mailType]; break; case TRUE: - gUnknown_0203A134->layout = &gUnknown_0859F458[gUnknown_0203A134->mailType]; + sMailRead->layout = &sUnknown_0859F458[sMailRead->mailType]; break; } - species = sub_80D45E8(mail->species, buffer); + species = MailSpeciesToSpecies(mail->species, buffer); if (species >= SPECIES_BULBASAUR && species < NUM_SPECIES) { - switch (gUnknown_0203A134->mailType) + switch (sMailRead->mailType) { default: - gUnknown_0203A134->animsActive = 0; + sMailRead->animsActive = 0; break; case ITEM_BEAD_MAIL - ITEM_ORANGE_MAIL: - gUnknown_0203A134->animsActive = 1; + sMailRead->animsActive = 1; break; case ITEM_DREAM_MAIL - ITEM_ORANGE_MAIL: - gUnknown_0203A134->animsActive = 2; + sMailRead->animsActive = 2; break; } } else { - gUnknown_0203A134->animsActive = 0; + sMailRead->animsActive = 0; } - gUnknown_0203A134->mail = mail; - gUnknown_0203A134->callback = callback; - gUnknown_0203A134->flag = flag; - SetMainCallback2(sub_81219F0); + sMailRead->mail = mail; + sMailRead->callback = callback; + sMailRead->flag = flag; + SetMainCallback2(CB2_InitMailRead); } -bool8 sub_81215EC(void) +static bool8 MailReadBuildGraphics(void) { u16 icon; @@ -352,21 +355,21 @@ bool8 sub_81215EC(void) SetGpuReg(REG_OFFSET_BG2HOFS, 0x0000); SetGpuReg(REG_OFFSET_BG3HOFS, 0x0000); SetGpuReg(REG_OFFSET_BG3VOFS, 0x0000); - SetGpuReg(REG_OFFSET_BLDCNT, 0x0000); + SetGpuReg(REG_OFFSET_BLDCNT, 0x0000); SetGpuReg(REG_OFFSET_BLDALPHA, 0x0000); break; case 6: ResetBgsAndClearDma3BusyFlags(0); - InitBgsFromTemplates(0, gUnknown_0859F290, 3); - SetBgTilemapBuffer(1, gUnknown_0203A134->bg1TilemapBuffer); - SetBgTilemapBuffer(2, gUnknown_0203A134->bg2TilemapBuffer); + InitBgsFromTemplates(0, sUnknown_0859F290, 3); + SetBgTilemapBuffer(1, sMailRead->bg1TilemapBuffer); + SetBgTilemapBuffer(2, sMailRead->bg2TilemapBuffer); break; case 7: - InitWindows(gUnknown_0859F29C); + InitWindows(sUnknown_0859F29C); DeactivateAllTextPrinters(); break; case 8: - decompress_and_copy_tile_data_to_vram(1, gUnknown_0859F2B8[gUnknown_0203A134->mailType].tiles, 0, 0, 0); + decompress_and_copy_tile_data_to_vram(1, sUnknown_0859F2B8[sMailRead->mailType].tiles, 0, 0, 0); break; case 9: if (free_temp_tile_data_buffers_if_possible()) @@ -377,7 +380,7 @@ bool8 sub_81215EC(void) case 10: FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 30, 20); FillBgTilemapBufferRect_Palette0(2, 1, 0, 0, 30, 20); - CopyToBgTilemapBuffer(1, gUnknown_0859F2B8[gUnknown_0203A134->mailType].tileMap, 0, 0); + CopyToBgTilemapBuffer(1, sUnknown_0859F2B8[sMailRead->mailType].tileMap, 0, 0); break; case 11: CopyBgTilemapBufferToVram(0); @@ -386,24 +389,24 @@ bool8 sub_81215EC(void) break; case 12: LoadPalette(GetOverworldTextboxPalettePtr(), 240, 32); - gPlttBufferUnfaded[250] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color10; - gPlttBufferFaded[250] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color10; - gPlttBufferUnfaded[251] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color12; - gPlttBufferFaded[251] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color12; - LoadPalette(gUnknown_0859F2B8[gUnknown_0203A134->mailType].palette, 0, 32); - gPlttBufferUnfaded[10] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; - gPlttBufferFaded[10] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; - gPlttBufferUnfaded[11] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; - gPlttBufferFaded[11] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; + gPlttBufferUnfaded[250] = sUnknown_0859F2B8[sMailRead->mailType].color10; + gPlttBufferFaded[250] = sUnknown_0859F2B8[sMailRead->mailType].color10; + gPlttBufferUnfaded[251] = sUnknown_0859F2B8[sMailRead->mailType].color12; + gPlttBufferFaded[251] = sUnknown_0859F2B8[sMailRead->mailType].color12; + LoadPalette(sUnknown_0859F2B8[sMailRead->mailType].palette, 0, 32); + gPlttBufferUnfaded[10] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; + gPlttBufferFaded[10] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; + gPlttBufferUnfaded[11] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; + gPlttBufferFaded[11] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; break; case 13: - if (gUnknown_0203A134->flag) + if (sMailRead->flag) { sub_8121A1C(); } break; case 14: - if (gUnknown_0203A134->flag) + if (sMailRead->flag) { sub_8121B1C(); RunTextPrinters(); @@ -416,20 +419,20 @@ bool8 sub_81215EC(void) } break; case 16: - SetVBlankCallback(sub_8121C50); + SetVBlankCallback(VBlankCB_MailRead); gPaletteFade.bufferTransferDisabled = TRUE; break; case 17: - icon = sub_80D2E84(gUnknown_0203A134->mail->species); - switch (gUnknown_0203A134->animsActive) + icon = sub_80D2E84(sMailRead->mail->species); + switch (sMailRead->animsActive) { case 1: sub_80D2F68(icon); - gUnknown_0203A134->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x60, 0x80, 0, 0); + sMailRead->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x60, 0x80, 0, 0); break; case 2: sub_80D2F68(icon); - gUnknown_0203A134->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x28, 0x80, 0, 0); + sMailRead->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x28, 0x80, 0, 0); break; } break; @@ -440,53 +443,53 @@ bool8 sub_81215EC(void) ShowBg(2); BeginNormalPaletteFade(-1, 0, 16, 0, 0); gPaletteFade.bufferTransferDisabled = FALSE; - gUnknown_0203A134->callback2 = sub_8121C98; + sMailRead->callback2 = CB2_WaitForPaletteExitOnKeyPress; return TRUE; default: return FALSE; } - gMain.state ++; + gMain.state++; return FALSE; } -void sub_81219F0(void) +static void CB2_InitMailRead(void) { do { - if (sub_81215EC() == TRUE) + if (MailReadBuildGraphics() == TRUE) { - SetMainCallback2(sub_8121C64); + SetMainCallback2(CB2_MailRead); break; } } while (sub_81221AC() != TRUE); } -void sub_8121A1C(void) +static void sub_8121A1C(void) { u16 i; u8 total; u8 *ptr; total = 0; - for (i = 0; i < gUnknown_0203A134->layout->numSubStructs; i ++) + for (i = 0; i < sMailRead->layout->numSubStructs; i ++) { - ConvertEasyChatWordsToString(gUnknown_0203A134->strbuf[i], &gUnknown_0203A134->mail->words[total], gUnknown_0203A134->layout->var8[i].numEasyChatWords, 1); - total += gUnknown_0203A134->layout->var8[i].numEasyChatWords; + ConvertEasyChatWordsToString(sMailRead->strbuf[i], &sMailRead->mail->words[total], sMailRead->layout->var8[i].numEasyChatWords, 1); + total += sMailRead->layout->var8[i].numEasyChatWords; } - ptr = StringCopy(gUnknown_0203A134->playerName, gUnknown_0203A134->mail->playerName); - if (!gUnknown_0203A134->playerIsSender) + ptr = StringCopy(sMailRead->playerName, sMailRead->mail->playerName); + if (!sMailRead->playerIsSender) { StringCopy(ptr, gText_FromSpace); - gUnknown_0203A134->signatureWidth = gUnknown_0203A134->layout->signatureWidth - (StringLength(gUnknown_0203A134->playerName) * 8 - 0x60); + sMailRead->signatureWidth = sMailRead->layout->signatureWidth - (StringLength(sMailRead->playerName) * 8 - 0x60); } else { - sub_81DB52C(gUnknown_0203A134->playerName); - gUnknown_0203A134->signatureWidth = gUnknown_0203A134->layout->signatureWidth; + sub_81DB52C(sMailRead->playerName); + sMailRead->signatureWidth = sMailRead->layout->signatureWidth; } } -void sub_8121B1C(void) +static void sub_8121B1C(void) { u16 i; u8 strbuf[0x20]; @@ -500,77 +503,76 @@ void sub_8121B1C(void) PutWindowTilemap(1); FillWindowPixelBuffer(0, 0); FillWindowPixelBuffer(1, 0); - for (i = 0; i < gUnknown_0203A134->layout->numSubStructs; i ++) + for (i = 0; i < sMailRead->layout->numSubStructs; i ++) { - if (gUnknown_0203A134->strbuf[i][0] == EOS || gUnknown_0203A134->strbuf[i][0] == CHAR_SPACE) + if (sMailRead->strbuf[i][0] == EOS || sMailRead->strbuf[i][0] == CHAR_SPACE) { continue; } - box_print(0, 1, gUnknown_0203A134->layout->var8[i].xOffset + gUnknown_0203A134->layout->wordsYPos, y + gUnknown_0203A134->layout->wordsXPos, gUnknown_0859F2AC, 0, gUnknown_0203A134->strbuf[i]); - y += gUnknown_0203A134->layout->var8[i].lineHeight; + box_print(0, 1, sMailRead->layout->var8[i].xOffset + sMailRead->layout->wordsYPos, y + sMailRead->layout->wordsXPos, sUnknown_0859F2AC, 0, sMailRead->strbuf[i]); + y += sMailRead->layout->var8[i].lineHeight; } bufptr = StringCopy(strbuf, gText_FromSpace); - StringCopy(bufptr, gUnknown_0203A134->playerName); - box_x = GetStringCenterAlignXOffset(1, strbuf, gUnknown_0203A134->signatureWidth) + 0x68; - box_y = gUnknown_0203A134->layout->signatureYPos + 0x58; - box_print(0, 1, box_x, box_y, gUnknown_0859F2AC, 0, strbuf); + StringCopy(bufptr, sMailRead->playerName); + box_x = GetStringCenterAlignXOffset(1, strbuf, sMailRead->signatureWidth) + 0x68; + box_y = sMailRead->layout->signatureYPos + 0x58; + box_print(0, 1, box_x, box_y, sUnknown_0859F2AC, 0, strbuf); CopyWindowToVram(0, 3); CopyWindowToVram(1, 3); } -void sub_8121C50(void) +static void VBlankCB_MailRead(void) { LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } -void sub_8121C64(void) +static void CB2_MailRead(void) { - if (gUnknown_0203A134->animsActive != 0) + if (sMailRead->animsActive != 0) { AnimateSprites(); BuildOamBuffer(); } - gUnknown_0203A134->callback2(); + sMailRead->callback2(); } -void sub_8121C98(void) +static void CB2_WaitForPaletteExitOnKeyPress(void) { if (!UpdatePaletteFade()) { - gUnknown_0203A134->callback2 = sub_8121CC0; + sMailRead->callback2 = CB2_ExitOnKeyPress; } } -void sub_8121CC0(void) +static void CB2_ExitOnKeyPress(void) { if (gMain.newKeys & (A_BUTTON | B_BUTTON)) { BeginNormalPaletteFade(-1, 0, 0, 16, 0); - gUnknown_0203A134->callback2 = sub_8121D00; + sMailRead->callback2 = CB2_ExitMailReadFreeVars; } } -void sub_8121D00(void) +static void CB2_ExitMailReadFreeVars(void) { if (!UpdatePaletteFade()) { - SetMainCallback2(gUnknown_0203A134->callback); - switch (gUnknown_0203A134->animsActive) + SetMainCallback2(sMailRead->callback); + switch (sMailRead->animsActive) { case 1: case 2: - sub_80D2FF0(sub_80D2E84(gUnknown_0203A134->mail->species)); - sub_80D2EF8(&gSprites[gUnknown_0203A134->monIconSprite]); + sub_80D2FF0(sub_80D2E84(sMailRead->mail->species)); + sub_80D2EF8(&gSprites[sMailRead->monIconSprite]); } - memset(gUnknown_0203A134, 0, sizeof(*gUnknown_0203A134)); + memset(sMailRead, 0, sizeof(*sMailRead)); ResetPaletteFade(); UnsetBgTilemapBuffer(0); UnsetBgTilemapBuffer(1); ResetBgsAndClearDma3BusyFlags(0); FreeAllWindowBuffers(); - free(gUnknown_0203A134); - gUnknown_0203A134 = NULL; + FREE_AND_SET_NULL(sMailRead); } } diff --git a/src/mail_data.c b/src/mail_data.c new file mode 100644 index 000000000..ebb49febf --- /dev/null +++ b/src/mail_data.c @@ -0,0 +1,203 @@ +#include "global.h" +#include "mail.h" +#include "constants/items.h" +#include "pokemon.h" +#include "pokemon_icon.h" +#include "constants/species.h" +#include "text.h" +#include "international_string_util.h" + +void ClearMailData(void) +{ + u8 i; + + for (i = 0; i < MAIL_COUNT; i++) + ClearMailStruct(&gSaveBlock1Ptr->mail[i]); +} + +void ClearMailStruct(struct MailStruct *mail) +{ + s32 i; + + for (i = 0; i < MAIL_WORDS_COUNT; i++) + mail->words[i] = 0xFFFF; + + for (i = 0; i < PLAYER_NAME_LENGTH; i++) + mail->playerName[i] = EOS; + + for (i = 0; i < 4; i++) + mail->trainerId[i] = 0; + + mail->species = SPECIES_BULBASAUR; + mail->itemId = ITEM_NONE; +} + +bool8 MonHasMail(struct Pokemon *mon) +{ + u16 heldItem = GetMonData(mon, MON_DATA_HELD_ITEM); + if (ItemIsMail(heldItem) && GetMonData(mon, MON_DATA_MAIL) != 0xFF) + return TRUE; + else + return FALSE; +} + +u8 GiveMailToMon(struct Pokemon *mon, u16 itemId) +{ + u8 heldItem[2]; + u8 id, i; + u16 species; + u32 personality; + + heldItem[0] = itemId; + heldItem[1] = itemId >> 8; + + for (id = 0; id < PARTY_SIZE; id++) + { + if (gSaveBlock1Ptr->mail[id].itemId == 0) + { + for (i = 0; i < MAIL_WORDS_COUNT; i++) + gSaveBlock1Ptr->mail[id].words[i] = 0xFFFF; + + for (i = 0; i < PLAYER_NAME_LENGTH - 1; i++) + gSaveBlock1Ptr->mail[id].playerName[i] = gSaveBlock2Ptr->playerName[i]; + gSaveBlock1Ptr->mail[id].playerName[i] = EOS; + PadNameString(gSaveBlock1Ptr->mail[id].playerName, CHAR_SPACE); + + for (i = 0; i < 4; i++) + gSaveBlock1Ptr->mail[id].trainerId[i] = gSaveBlock2Ptr->playerTrainerId[i]; + + species = GetBoxMonData(&mon->box, MON_DATA_SPECIES); + personality = GetBoxMonData(&mon->box, MON_DATA_PERSONALITY); + gSaveBlock1Ptr->mail[id].species = SpeciesToMailSpecies(species, personality); + gSaveBlock1Ptr->mail[id].itemId = itemId; + SetMonData(mon, MON_DATA_MAIL, &id); + SetMonData(mon, MON_DATA_HELD_ITEM, heldItem); + return id; + } + } + + return 0xFF; +} + +u16 SpeciesToMailSpecies(u16 species, u32 personality) +{ + if (species == SPECIES_UNOWN) + { + u32 species = GetUnownLetterByPersonality(personality) + 30000; + return species; + } + + return species; +} + +u16 MailSpeciesToSpecies(u16 mailSpecies, u16 *buffer) +{ + u16 result; + + if (mailSpecies >= 30000 && mailSpecies < (30000 + UNOWN_FORM_COUNT)) + { + result = SPECIES_UNOWN; + *buffer = mailSpecies - 30000; + } + else + { + result = mailSpecies; + } + + return result; +} + +u8 GiveMailToMon2(struct Pokemon *mon, struct MailStruct *mail) +{ + u8 heldItem[2]; + u16 itemId = mail->itemId; + u8 mailId = GiveMailToMon(mon, itemId); + + if (mailId == 0xFF) + return 0xFF; + + gSaveBlock1Ptr->mail[mailId] = *mail; + + SetMonData(mon, MON_DATA_MAIL, &mailId); + + heldItem[0] = itemId; + heldItem[1] = itemId >> 8; + + SetMonData(mon, MON_DATA_HELD_ITEM, heldItem); + + return mailId; +} + +static bool32 DummyMailFunc(void) +{ + return FALSE; +} + +void TakeMailFromMon(struct Pokemon *mon) +{ + u8 heldItem[2]; + u8 mailId; + + if (MonHasMail(mon)) + { + mailId = GetMonData(mon, MON_DATA_MAIL); + gSaveBlock1Ptr->mail[mailId].itemId = ITEM_NONE; + mailId = 0xFF; + heldItem[0] = ITEM_NONE; + heldItem[1] = ITEM_NONE << 8; + SetMonData(mon, MON_DATA_MAIL, &mailId); + SetMonData(mon, MON_DATA_HELD_ITEM, heldItem); + } +} + +void ClearMailItemId(u8 mailId) +{ + gSaveBlock1Ptr->mail[mailId].itemId = ITEM_NONE; +} + +u8 TakeMailFromMon2(struct Pokemon *mon) +{ + u8 i; + u8 newHeldItem[2]; + u8 newMailId; + + newHeldItem[0] = ITEM_NONE; + newHeldItem[1] = ITEM_NONE << 8; + newMailId = 0xFF; + + for (i = PARTY_SIZE; i < MAIL_COUNT; i++) + { + if (gSaveBlock1Ptr->mail[i].itemId == ITEM_NONE) + { + memcpy(&gSaveBlock1Ptr->mail[i], &gSaveBlock1Ptr->mail[GetMonData(mon, MON_DATA_MAIL)], sizeof(struct MailStruct)); + gSaveBlock1Ptr->mail[GetMonData(mon, MON_DATA_MAIL)].itemId = ITEM_NONE; + SetMonData(mon, MON_DATA_MAIL, &newMailId); + SetMonData(mon, MON_DATA_HELD_ITEM, newHeldItem); + return i; + } + } + + return 0xFF; +} + +bool8 ItemIsMail(u16 itemId) +{ + switch (itemId) + { + case ITEM_ORANGE_MAIL: + case ITEM_HARBOR_MAIL: + case ITEM_GLITTER_MAIL: + case ITEM_MECH_MAIL: + case ITEM_WOOD_MAIL: + case ITEM_WAVE_MAIL: + case ITEM_BEAD_MAIL: + case ITEM_SHADOW_MAIL: + case ITEM_TROPIC_MAIL: + case ITEM_DREAM_MAIL: + case ITEM_FAB_MAIL: + case ITEM_RETRO_MAIL: + return TRUE; + default: + return FALSE; + } +} diff --git a/src/pokemon_2.c b/src/pokemon_2.c index a4d00112b..db176e025 100644 --- a/src/pokemon_2.c +++ b/src/pokemon_2.c @@ -1155,7 +1155,7 @@ u8 GetMonsStateToDoubles_2(void) s32 aliveCount = 0; s32 i; - for (i = 0; i < 6; i++) + for (i = 0; i < PARTY_SIZE; i++) { u32 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2, NULL); if (species != SPECIES_EGG && species != SPECIES_NONE diff --git a/src/pokemon_3.c b/src/pokemon_3.c index 8fb642f5f..e3b340698 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -11,8 +11,7 @@ #include "link.h" #include "constants/hold_effects.h" #include "random.h" -#include "trainer_classes.h" -#include "trainer_ids.h" +#include "constants/trainers.h" #include "constants/songs.h" #include "sound.h" #include "m4a.h" @@ -692,9 +691,9 @@ void AdjustFriendship(struct Pokemon *mon, u8 event) if ((event != 5 || !(Random() & 1)) && (event != 3 || ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) - && (gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_ELITE_FOUR - || gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_LEADER - || gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_CHAMPION)))) + && (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_ELITE_FOUR + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_LEADER + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_CHAMPION)))) { s8 mod = gUnknown_08329ECE[event][friendshipLevel]; if (mod > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) @@ -1146,55 +1145,57 @@ void ClearBattleMonForms(void) u16 GetBattleBGM(void) { if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) - return 0x1E0; + return BGM_BATTLE34; if (gBattleTypeFlags & BATTLE_TYPE_REGI) - return 0x1DF; + return BGM_BATTLE36; if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) - return 0x1DC; + return BGM_BATTLE20; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { u8 trainerClass; + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) trainerClass = GetFrontierOpponentClass(gTrainerBattleOpponent_A); else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) - trainerClass = CLASS_EXPERT; + trainerClass = TRAINER_CLASS_EXPERT; else trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; + switch (trainerClass) { - case CLASS_AQUA_LEADER: - case CLASS_MAGMA_LEADER: - return 0x1E3; - case CLASS_TEAM_AQUA: - case CLASS_TEAM_MAGMA: - case CLASS_AQUA_ADMIN: - case CLASS_MAGMA_ADMIN: - return 0x1DB; - case CLASS_LEADER: - return 0x1DD; - case CLASS_CHAMPION: - return 0x1DE; - case CLASS_PKMN_TRAINER_RIVAL: + case TRAINER_CLASS_AQUA_LEADER: + case TRAINER_CLASS_MAGMA_LEADER: + return BGM_BATTLE30; + case TRAINER_CLASS_TEAM_AQUA: + case TRAINER_CLASS_TEAM_MAGMA: + case TRAINER_CLASS_AQUA_ADMIN: + case TRAINER_CLASS_MAGMA_ADMIN: + return BGM_BATTLE31; + case TRAINER_CLASS_LEADER: + return BGM_BATTLE32; + case TRAINER_CLASS_CHAMPION: + return BGM_BATTLE33; + case TRAINER_CLASS_PKMN_TRAINER_3: if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) - return 0x1E1; + return BGM_BATTLE35; if (!StringCompare(gTrainers[gTrainerBattleOpponent_A].trainerName, gText_BattleWallyName)) - return 0x1DC; - return 0x1E1; - case CLASS_ELITE_FOUR: - return 0x1E2; - case CLASS_SALON_MAIDEN: - case CLASS_DOME_ACE: - case CLASS_PALACE_MAVEN: - case CLASS_ARENA_TYCOON: - case CLASS_FACTORY_HEAD: - case CLASS_PIKE_QUEEN: - case CLASS_PYRAMID_KING: - return 0x1D7; + return BGM_BATTLE20; + return BGM_BATTLE35; + case TRAINER_CLASS_ELITE_FOUR: + return BGM_BATTLE38; + case TRAINER_CLASS_SALON_MAIDEN: + case TRAINER_CLASS_DOME_ACE: + case TRAINER_CLASS_PALACE_MAVEN: + case TRAINER_CLASS_ARENA_TYCOON: + case TRAINER_CLASS_FACTORY_HEAD: + case TRAINER_CLASS_PIKE_QUEEN: + case TRAINER_CLASS_PYRAMID_KING: + return BGM_BATTLE_FRONTIER_BRAIN; default: - return 0x1DC; + return BGM_BATTLE20; } } - return 0x1DA; + return BGM_BATTLE27; } void PlayBattleBGM(void) @@ -1396,7 +1397,7 @@ static s32 GetWildMonTableIdInAlteringCave(u16 species) void SetWildMonHeldItem(void) { - if (!(gBattleTypeFlags & (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_TRAINER | BATTLE_TYPE_PYRAMID | BATTLE_TYPE_x100000))) + if (!(gBattleTypeFlags & (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_TRAINER | BATTLE_TYPE_PYRAMID | BATTLE_TYPE_PIKE))) { u16 rnd = Random() % 100; u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, 0); @@ -1462,12 +1463,14 @@ bool8 IsShinyOtIdPersonality(u32 otId, u32 personality) return retVal; } -const u8* GetTrainerPartnerName(void) +const u8 *GetTrainerPartnerName(void) { if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { if (gPartnerTrainerId == STEVEN_PARTNER_ID) - return gTrainers[TRAINER_ID_STEVEN].trainerName; + { + return gTrainers[TRAINER_STEVEN].trainerName; + } else { GetFrontierTrainerName(gStringVar1, gPartnerTrainerId); @@ -1682,14 +1685,14 @@ void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality) } } -const u8* GetTrainerClassNameFromId(u16 trainerId) +const u8 *GetTrainerClassNameFromId(u16 trainerId) { if (trainerId > NO_OF_TRAINERS) trainerId = 0; return gTrainerClassNames[gTrainers[trainerId].trainerClass]; } -const u8* GetTrainerNameFromId(u16 trainerId) +const u8 *GetTrainerNameFromId(u16 trainerId) { if (trainerId > NO_OF_TRAINERS) trainerId = 0; diff --git a/src/recorded_battle.c b/src/recorded_battle.c index 4f3fe4ab9..c88229c61 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -19,7 +19,7 @@ | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_ROAMER | BATTLE_TYPE_EREADER_TRAINER \ | BATTLE_TYPE_KYOGRE_GROUDON | BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_REGI \ | BATTLE_TYPE_RECORDED | BATTLE_TYPE_x4000000 | BATTLE_TYPE_SECRET_BASE \ - | BATTLE_TYPE_GROUDON | BATTLE_TYPE_KYORGE | BATTLE_TYPE_RAYQUAZA)) + | BATTLE_TYPE_GROUDON | BATTLE_TYPE_KYOGRE | BATTLE_TYPE_RAYQUAZA)) extern u32 gBattleTypeFlags; extern u16 gTrainerBattleOpponent_A; diff --git a/src/safari_zone.c b/src/safari_zone.c index 8bd1fffa7..ce1eb65bc 100644 --- a/src/safari_zone.c +++ b/src/safari_zone.c @@ -105,7 +105,7 @@ void SafariZoneRetirePrompt(void) ScriptContext1_SetupScript(EventScript_2A4B6F); } -void sub_80FC190(void) +void CB2_EndSafariBattle(void) { sSafariZoneFleedMons += gBattleResults.field_1F; if (gBattleOutcome == BATTLE_CAUGHT) diff --git a/src/scrcmd.c b/src/scrcmd.c index 504d001ea..1b10501fc 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -656,7 +656,7 @@ bool8 ScrCmd_fadescreenspeed(struct ScriptContext *ctx) bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx) { u8 mode = ScriptReadByte(ctx); - + switch (mode) { case 1: @@ -1445,7 +1445,7 @@ bool8 ScrCmd_drawboxtext(struct ScriptContext *ctx) u8 top = ScriptReadByte(ctx); u8 multichoiceId = ScriptReadByte(ctx); u8 ignoreBPress = ScriptReadByte(ctx); - + /*if (Multichoice(left, top, multichoiceId, ignoreBPress) == TRUE) { ScriptContext1_Stop(); @@ -1501,31 +1501,31 @@ bool8 ScrCmd_braillemessage(struct ScriptContext *ctx) u8 y; StringExpandPlaceholders(gStringVar4, ptr + 6); - + width = GetStringWidth(6, gStringVar4, -1) / 8; - + if (width > 0x1C) width = 0x1C; - + for (i = 0, height = 4; gStringVar4[i] != 0xFF;) { if (gStringVar4[i++] == 0xFE) height += 3; } - + if (height > 0x12) height = 0x12; - + x = width + 2; temp1 = (0x1E - x) / 2; x = temp1 + 1; temp1 = ((x - temp1 - 1) * 8 + 3); - + y = height + 2; temp2 = (0x14 - y) / 2; y = temp2 + 2; temp2 = ((y - temp2 - 1) * 8); - + sub_8198A50(&template1, 0, x, y, width, height, 0xF, 0x1); template2 = template1; gUnknown_03000F30 = AddWindow(&template2); @@ -1924,7 +1924,7 @@ bool8 ScrCmd_hidemoneybox(struct ScriptContext *ctx) { /*u8 x = ScriptReadByte(ctx); u8 y = ScriptReadByte(ctx);*/ - + HideMoneyBox(); return FALSE; } @@ -1979,13 +1979,13 @@ bool8 ScrCmd_dotrainerbattle(struct ScriptContext *ctx) return TRUE; } -bool8 ScrCmd_ontrainerbattleend(struct ScriptContext *ctx) +bool8 ScrCmd_gotopostbattlescript(struct ScriptContext *ctx) { ctx->scriptPtr = BattleSetup_GetScriptAddrAfterBattle(); return FALSE; } -bool8 ScrCmd_ontrainerbattleendgoto(struct ScriptContext *ctx) +bool8 ScrCmd_gotobeatenscript(struct ScriptContext *ctx) { ctx->scriptPtr = BattleSetup_GetTrainerPostBattleScript(); return FALSE; @@ -1995,7 +1995,7 @@ bool8 ScrCmd_checktrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); - ctx->comparisonResult = HasTrainerAlreadyBeenFought(index); + ctx->comparisonResult = HasTrainerBeenFought(index); return FALSE; } @@ -2003,7 +2003,7 @@ bool8 ScrCmd_settrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); - trainer_flag_set(index); + SetTrainerFlag(index); return FALSE; } @@ -2011,7 +2011,7 @@ bool8 ScrCmd_cleartrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); - trainer_flag_clear(index); + ClearTrainerFlag(index); return FALSE; } @@ -2374,7 +2374,7 @@ bool8 ScrCmd_checkmonobedience(struct ScriptContext *ctx) bool8 ScrCmd_cmdCF(struct ScriptContext *ctx) { const u8* v1 = sub_8099244(); - + if (v1) { ((u8*)gUnknown_020375C0) = ctx->scriptPtr; diff --git a/src/secret_base.c b/src/secret_base.c index 6926bd804..bf6bec1f8 100644 --- a/src/secret_base.c +++ b/src/secret_base.c @@ -1283,7 +1283,7 @@ u8 sub_80EA20C(u8 secretBaseRecordId) return (gSaveBlock1Ptr->secretBases[secretBaseRecordId].trainerId[0] % 5) + (gSaveBlock1Ptr->secretBases[secretBaseRecordId].gender * 5); } -const u8 *sub_80EA250(void) +const u8 *GetSecretBaseTrainerLoseText(void) { u8 param; diff --git a/src/starter_choose.c b/src/starter_choose.c index 82f8f75f6..2d78af8fb 100644 --- a/src/starter_choose.c +++ b/src/starter_choose.c @@ -265,7 +265,7 @@ static void Task_StarterChoose5(u8 taskId) { u8 spriteId; - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 0: // YES // Return the starter choice and exit. diff --git a/src/trainer_see.c b/src/trainer_see.c new file mode 100644 index 000000000..b30f27347 --- /dev/null +++ b/src/trainer_see.c @@ -0,0 +1,68 @@ +#include "global.h" +#include "trainer_see.h" +#include "battle_setup.h" + +extern u8 gApproachingTrainerId; +extern u8 gNoOfApproachingTrainers; +extern u8 gUnknown_030060AC; +extern u16 gUnknown_03006080; + +// this file's functions +u8 CheckIfTrainerWantsBattle(u8 mapObjectId); + +bool8 CheckForTrainersWantingBattle(void) +{ + u8 i; + + gNoOfApproachingTrainers = 0; + gApproachingTrainerId = 0; + + for (i = 0; i < MAP_OBJECTS_COUNT; i++) + { + u8 retVal; + + if (!gMapObjects[i].active) + continue; + if (gMapObjects[i].trainerType != 1 && gMapObjects[i].trainerType != 3) + continue; + + retVal = CheckIfTrainerWantsBattle(i); + if (retVal == 2) + break; // two trainers have been found + + if (retVal == 0) // no trainers + continue; + + if (gNoOfApproachingTrainers > 1) + break; + if (GetMonsStateToDoubles_2() != 0) // one trainer found and cant have a double battle + break; + } + + if (gNoOfApproachingTrainers == 1) + { + ResetTrainerOpponentIds(); + ConfigureAndSetUpOneTrainerBattle(gApproachingTrainers[gNoOfApproachingTrainers - 1].mapObjectId, + gApproachingTrainers[gNoOfApproachingTrainers - 1].trainerScriptPtr); + gUnknown_030060AC = 1; + return TRUE; + } + else if (gNoOfApproachingTrainers == 2) + { + ResetTrainerOpponentIds(); + for (i = 0; i < gNoOfApproachingTrainers; i++, gApproachingTrainerId++) + { + ConfigureTwoTrainersBattle(gApproachingTrainers[i].mapObjectId, + gApproachingTrainers[i].trainerScriptPtr); + } + SetUpTwoTrainersBattle(); + gApproachingTrainerId = 0; + gUnknown_030060AC = 1; + return TRUE; + } + else + { + gUnknown_030060AC = 0; + return FALSE; + } +} @@ -1793,7 +1793,7 @@ void EndMassOutbreak(void) gSaveBlock1Ptr->outbreakDaysLeft = 0; } -void sub_80ED888(u16 days) +void UpdateTVShowsPerDay(u16 days) { sub_80ED8B4(days); diff --git a/src/wallclock.c b/src/wallclock.c new file mode 100644 index 000000000..892ef3f05 --- /dev/null +++ b/src/wallclock.c @@ -0,0 +1,1057 @@ +#include "global.h" +#include "main.h" +#include "palette.h" +#include "gpu_regs.h" +#include "bg.h" +#include "rtc.h" +#include "clock.h" +#include "wallclock.h" +#include "event_data.h" +#include "graphics.h" +#include "text.h" +#include "window.h" +#include "text_window.h" +#include "menu.h" +#include "unknown_task.h" +#include "task.h" +#include "strings.h" +#include "sound.h" +#include "songs.h" +#include "trig.h" +#include "decompress.h" + +// static types + +#define tMinuteHandAngle data[0] +#define tHourHandAngle data[1] +#define tHours data[2] +#define tMinutes data[3] +#define tMvmtDir data[4] +#define tPeriod data[5] +#define tMvmtSpeed data[6] + +#define TAG_GFX_WALL_CLOCK_HAND 0x1000 +#define TAG_PAL_WALL_CLOCK_HAND 0x1000 + +// static declarations + +static void WallClockMainCallback(void); +static void Task_SetClock1(u8 taskId); +static void Task_SetClock2(u8 taskId); +static void Task_SetClock3(u8 taskId); +static void Task_SetClock4(u8 taskId); +static void Task_SetClock5(u8 taskId); +static void Task_SetClock6(u8 taskId); +static void Task_ViewClock1(u8 taskId); +static void Task_ViewClock2(u8 taskId); +static void Task_ViewClock3(u8 taskId); +static void Task_ViewClock4(u8 taskId); +static u16 CalcNewMinHandAngle(u16 a0, u8 command, u8 a2); +static bool32 AdvanceClock(u8 taskId, u8 command); +static void UpdateClockPeriod(u8 taskId, u8 command); +static void InitClockWithRtc(u8 taskId); +static void SpriteCB_MinuteHand(struct Sprite *sprite); +static void SpriteCB_HourHand(struct Sprite *sprite); +static void SpriteCB_AMIndicator(struct Sprite *sprite); +static void SpriteCB_PMIndicator(struct Sprite *sprite); + +// rodata + +static const u8 gUnknown_085B1F58[] = INCBIN_U8("graphics/wallclock/graphics_85b1f58.4bpp.lz"); +static const u16 gUnknown_085B21D4[] = INCBIN_U16("graphics/wallclock/palette_85b21d4.gbapal"); +static const struct WindowTemplate gUnknown_085B21DC[] = { + { 0x00, 0x03, 0x11, 0x18, 0x02, 0x0e, 0x200 }, + { 0x02, 0x18, 0x10, 0x06, 0x02, 0x0c, 0x230 }, + DUMMY_WIN_TEMPLATE +}; +static const struct WindowTemplate gUnknown_085B21F4 = { + 0x00, 0x18, 0x09, 0x05, 0x04, 0x0e, 0x23c +}; +static const struct BgTemplate gUnknown_085B21FC[] = { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 31, + .priority = 0 + }, + { + .bg = 2, + .charBaseIndex = 1, + .mapBaseIndex = 8, + .priority = 1 + }, + { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 7, + .priority = 2 + } +}; +static const struct CompressedSpriteSheet gUnknown_085B2208 = { + gUnknown_085B1F58, 0x2000, TAG_GFX_WALL_CLOCK_HAND +}; +static const u32 filler_85B2210[2] = {}; +static const struct SpritePalette gUnknown_085B2218[] = { + { gUnknown_08DCC01C, TAG_PAL_WALL_CLOCK_HAND }, + { gUnknown_08DCC03C, 0x1001 }, + {} +}; +static const struct OamData Unknown_085B2230 = { + .y = 0xa0, + .size = 3, + .priority = 1 +}; +static const union AnimCmd Unknown_085B2238[] = { + ANIMCMD_FRAME(0, 30), + ANIMCMD_END +}; +static const union AnimCmd Unknown_085B2240[] = { + ANIMCMD_FRAME(64, 30), + ANIMCMD_END +}; +static const union AnimCmd *const gUnknown_085B2248[] = { + Unknown_085B2238 +}; +static const union AnimCmd *const gUnknown_085B224C[] = { + Unknown_085B2240 +}; +static const struct SpriteTemplate gUnknown_085B2250 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2230, + gUnknown_085B2248, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_MinuteHand +}; +static const struct SpriteTemplate gUnknown_085B2268 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2230, + gUnknown_085B224C, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_HourHand +}; +static const struct OamData Unknown_085B2280 = { + .y = 0xa0, + .size = 1, + .priority = 3 +}; +static const union AnimCmd Unknown_085B2288[] = { + ANIMCMD_FRAME(0x84, 30), + ANIMCMD_END +}; +static const union AnimCmd Unknown_085B2290[] = { + ANIMCMD_FRAME(0x80, 30), + ANIMCMD_END +}; +static const union AnimCmd *const gUnknown_085B2298[] = { + Unknown_085B2288 +}; +static const union AnimCmd *const gUnknown_085B229C[] = { + Unknown_085B2290 +}; +static const struct SpriteTemplate gUnknown_085B22A0 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2280, + gUnknown_085B2298, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_AMIndicator +}; +static const struct SpriteTemplate gUnknown_085B22B8 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2280, + gUnknown_085B229C, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_PMIndicator +}; +static const s8 sClockHandCoords[][2] = { + { 0x00, -0x18}, + { 0x01, -0x19}, + { 0x01, -0x19}, + { 0x02, -0x19}, + { 0x02, -0x19}, + { 0x02, -0x19}, + { 0x03, -0x18}, + { 0x03, -0x19}, + { 0x04, -0x19}, + { 0x04, -0x19}, + { 0x04, -0x19}, + { 0x05, -0x19}, + { 0x05, -0x19}, + { 0x06, -0x18}, + { 0x06, -0x18}, + { 0x06, -0x18}, + { 0x07, -0x18}, + { 0x07, -0x18}, + { 0x07, -0x18}, + { 0x08, -0x18}, + { 0x08, -0x18}, + { 0x09, -0x18}, + { 0x09, -0x18}, + { 0x0a, -0x17}, + { 0x0a, -0x17}, + { 0x0b, -0x16}, + { 0x0b, -0x16}, + { 0x0b, -0x16}, + { 0x0c, -0x16}, + { 0x0c, -0x15}, + { 0x0d, -0x15}, + { 0x0d, -0x15}, + { 0x0d, -0x15}, + { 0x0e, -0x15}, + { 0x0e, -0x15}, + { 0x0e, -0x14}, + { 0x0e, -0x14}, + { 0x0f, -0x14}, + { 0x0f, -0x13}, + { 0x10, -0x13}, + { 0x10, -0x13}, + { 0x10, -0x13}, + { 0x10, -0x12}, + { 0x10, -0x12}, + { 0x11, -0x12}, + { 0x11, -0x11}, + { 0x11, -0x11}, + { 0x12, -0x11}, + { 0x12, -0x11}, + { 0x12, -0x10}, + { 0x12, -0x10}, + { 0x13, -0x10}, + { 0x13, -0x0f}, + { 0x13, -0x0f}, + { 0x14, -0x0f}, + { 0x14, -0x0e}, + { 0x14, -0x0e}, + { 0x14, -0x0d}, + { 0x14, -0x0d}, + { 0x15, -0x0d}, + { 0x15, -0x0d}, + { 0x15, -0x0c}, + { 0x16, -0x0c}, + { 0x16, -0x0c}, + { 0x16, -0x0b}, + { 0x16, -0x0b}, + { 0x16, -0x0a}, + { 0x17, -0x0a}, + { 0x17, -0x09}, + { 0x17, -0x09}, + { 0x17, -0x09}, + { 0x17, -0x09}, + { 0x17, -0x08}, + { 0x17, -0x08}, + { 0x17, -0x07}, + { 0x17, -0x07}, + { 0x17, -0x06}, + { 0x18, -0x06}, + { 0x18, -0x06}, + { 0x19, -0x05}, + { 0x19, -0x05}, + { 0x18, -0x04}, + { 0x19, -0x04}, + { 0x18, -0x03}, + { 0x19, -0x03}, + { 0x19, -0x03}, + { 0x19, -0x02}, + { 0x19, -0x02}, + { 0x18, -0x01}, + { 0x19, -0x01}, + { 0x18, 0x00}, + { 0x18, 0x00}, + { 0x18, 0x00}, + { 0x18, 0x01}, + { 0x18, 0x01}, + { 0x19, 0x02}, + { 0x18, 0x02}, + { 0x19, 0x02}, + { 0x18, 0x03}, + { 0x18, 0x03}, + { 0x19, 0x04}, + { 0x18, 0x04}, + { 0x18, 0x05}, + { 0x18, 0x05}, + { 0x18, 0x05}, + { 0x18, 0x06}, + { 0x17, 0x06}, + { 0x17, 0x06}, + { 0x17, 0x07}, + { 0x17, 0x08}, + { 0x17, 0x08}, + { 0x17, 0x08}, + { 0x17, 0x09}, + { 0x17, 0x09}, + { 0x17, 0x0a}, + { 0x16, 0x0a}, + { 0x16, 0x0a}, + { 0x16, 0x0b}, + { 0x16, 0x0b}, + { 0x16, 0x0b}, + { 0x16, 0x0c}, + { 0x15, 0x0c}, + { 0x15, 0x0c}, + { 0x15, 0x0d}, + { 0x14, 0x0d}, + { 0x14, 0x0d}, + { 0x13, 0x0d}, + { 0x13, 0x0d}, + { 0x13, 0x0e}, + { 0x13, 0x0e}, + { 0x13, 0x0f}, + { 0x13, 0x0f}, + { 0x12, 0x0f}, + { 0x12, 0x10}, + { 0x11, 0x10}, + { 0x11, 0x10}, + { 0x11, 0x11}, + { 0x11, 0x11}, + { 0x10, 0x11}, + { 0x10, 0x12}, + { 0x10, 0x12}, + { 0x0f, 0x12}, + { 0x0e, 0x12}, + { 0x0f, 0x13}, + { 0x0e, 0x13}, + { 0x0e, 0x13}, + { 0x0d, 0x13}, + { 0x0d, 0x14}, + { 0x0d, 0x14}, + { 0x0d, 0x14}, + { 0x0c, 0x14}, + { 0x0c, 0x14}, + { 0x0c, 0x15}, + { 0x0b, 0x15}, + { 0x0b, 0x15}, + { 0x0b, 0x15}, + { 0x0a, 0x15}, + { 0x0a, 0x16}, + { 0x0a, 0x16}, + { 0x09, 0x16}, + { 0x09, 0x16}, + { 0x08, 0x16}, + { 0x07, 0x16}, + { 0x07, 0x17}, + { 0x07, 0x17}, + { 0x06, 0x17}, + { 0x06, 0x17}, + { 0x05, 0x17}, + { 0x05, 0x17}, + { 0x05, 0x18}, + { 0x04, 0x18}, + { 0x04, 0x18}, + { 0x04, 0x18}, + { 0x03, 0x18}, + { 0x02, 0x18}, + { 0x02, 0x18}, + { 0x01, 0x18}, + { 0x01, 0x18}, + { 0x00, 0x18}, + { 0x00, 0x18}, + {-0x01, 0x17}, + { 0x00, 0x18}, + { 0x00, 0x18}, + {-0x01, 0x18}, + {-0x01, 0x18}, + {-0x02, 0x18}, + {-0x02, 0x18}, + {-0x03, 0x18}, + {-0x03, 0x18}, + {-0x04, 0x18}, + {-0x04, 0x18}, + {-0x05, 0x18}, + {-0x05, 0x17}, + {-0x05, 0x17}, + {-0x06, 0x17}, + {-0x06, 0x17}, + {-0x07, 0x17}, + {-0x07, 0x17}, + {-0x07, 0x17}, + {-0x08, 0x17}, + {-0x08, 0x16}, + {-0x09, 0x16}, + {-0x09, 0x16}, + {-0x0a, 0x16}, + {-0x0a, 0x16}, + {-0x0a, 0x15}, + {-0x0b, 0x15}, + {-0x0b, 0x15}, + {-0x0b, 0x15}, + {-0x0b, 0x14}, + {-0x0c, 0x14}, + {-0x0c, 0x14}, + {-0x0d, 0x14}, + {-0x0d, 0x14}, + {-0x0d, 0x13}, + {-0x0e, 0x13}, + {-0x0e, 0x13}, + {-0x0e, 0x13}, + {-0x0e, 0x12}, + {-0x0f, 0x12}, + {-0x0f, 0x12}, + {-0x0f, 0x11}, + {-0x10, 0x11}, + {-0x10, 0x11}, + {-0x11, 0x11}, + {-0x11, 0x10}, + {-0x11, 0x10}, + {-0x12, 0x10}, + {-0x11, 0x0f}, + {-0x12, 0x0f}, + {-0x12, 0x0f}, + {-0x13, 0x0f}, + {-0x13, 0x0e}, + {-0x13, 0x0e}, + {-0x13, 0x0d}, + {-0x13, 0x0d}, + {-0x14, 0x0d}, + {-0x14, 0x0c}, + {-0x14, 0x0c}, + {-0x15, 0x0c}, + {-0x15, 0x0c}, + {-0x15, 0x0b}, + {-0x15, 0x0b}, + {-0x15, 0x0a}, + {-0x15, 0x0a}, + {-0x15, 0x09}, + {-0x16, 0x09}, + {-0x16, 0x09}, + {-0x16, 0x08}, + {-0x16, 0x08}, + {-0x16, 0x07}, + {-0x17, 0x07}, + {-0x17, 0x07}, + {-0x17, 0x06}, + {-0x17, 0x06}, + {-0x17, 0x05}, + {-0x18, 0x05}, + {-0x17, 0x04}, + {-0x17, 0x04}, + {-0x18, 0x04}, + {-0x18, 0x04}, + {-0x18, 0x03}, + {-0x18, 0x03}, + {-0x18, 0x02}, + {-0x18, 0x02}, + {-0x18, 0x01}, + {-0x18, 0x01}, + {-0x18, 0x01}, + {-0x18, 0x00}, + {-0x19, 0x00}, + {-0x18, -0x01}, + {-0x19, -0x01}, + {-0x18, -0x01}, + {-0x18, -0x02}, + {-0x18, -0x02}, + {-0x18, -0x03}, + {-0x18, -0x03}, + {-0x18, -0x04}, + {-0x18, -0x04}, + {-0x18, -0x04}, + {-0x18, -0x05}, + {-0x18, -0x05}, + {-0x18, -0x06}, + {-0x18, -0x06}, + {-0x17, -0x06}, + {-0x17, -0x07}, + {-0x17, -0x07}, + {-0x17, -0x08}, + {-0x17, -0x08}, + {-0x17, -0x09}, + {-0x17, -0x09}, + {-0x16, -0x09}, + {-0x16, -0x09}, + {-0x16, -0x0a}, + {-0x16, -0x0a}, + {-0x15, -0x0a}, + {-0x15, -0x0b}, + {-0x16, -0x0b}, + {-0x16, -0x0c}, + {-0x15, -0x0c}, + {-0x15, -0x0d}, + {-0x15, -0x0d}, + {-0x14, -0x0d}, + {-0x15, -0x0e}, + {-0x14, -0x0e}, + {-0x14, -0x0e}, + {-0x13, -0x0e}, + {-0x13, -0x0f}, + {-0x13, -0x0f}, + {-0x12, -0x10}, + {-0x12, -0x10}, + {-0x12, -0x10}, + {-0x12, -0x11}, + {-0x12, -0x11}, + {-0x11, -0x11}, + {-0x11, -0x12}, + {-0x11, -0x12}, + {-0x10, -0x12}, + {-0x10, -0x12}, + {-0x10, -0x13}, + {-0x10, -0x13}, + {-0x0f, -0x13}, + {-0x0f, -0x13}, + {-0x0f, -0x14}, + {-0x0e, -0x14}, + {-0x0e, -0x14}, + {-0x0e, -0x15}, + {-0x0d, -0x15}, + {-0x0d, -0x15}, + {-0x0d, -0x15}, + {-0x0c, -0x15}, + {-0x0c, -0x16}, + {-0x0b, -0x16}, + {-0x0b, -0x16}, + {-0x0b, -0x16}, + {-0x0a, -0x16}, + {-0x0a, -0x16}, + {-0x09, -0x16}, + {-0x09, -0x17}, + {-0x09, -0x17}, + {-0x08, -0x17}, + {-0x08, -0x17}, + {-0x07, -0x17}, + {-0x07, -0x17}, + {-0x07, -0x18}, + {-0x06, -0x18}, + {-0x06, -0x18}, + {-0x05, -0x18}, + {-0x05, -0x18}, + {-0x04, -0x18}, + {-0x04, -0x18}, + {-0x04, -0x18}, + {-0x04, -0x19}, + {-0x03, -0x19}, + {-0x02, -0x19}, + {-0x02, -0x18}, + {-0x02, -0x18}, + {-0x01, -0x19}, + {-0x01, -0x19}, + { 0x00, -0x19} +}; + +// text + +static void WallClockVblankCallback(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void LoadWallClockGraphics(void) +{ + SetVBlankCallback(NULL); + SetGpuReg(REG_OFFSET_DISPCNT, 0x0000); + SetGpuReg(REG_OFFSET_BG3CNT, 0x0000); + SetGpuReg(REG_OFFSET_BG2CNT, 0x0000); + SetGpuReg(REG_OFFSET_BG1CNT, 0x0000); + SetGpuReg(REG_OFFSET_BG0CNT, 0x0000); + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(2, 0, 0); + ChangeBgY(2, 0, 0); + ChangeBgX(3, 0, 0); + ChangeBgY(3, 0, 0); + DmaFillLarge16(3, 0, (void *)VRAM, VRAM_SIZE, 0x1000); + DmaClear32(3, (void *)OAM, OAM_SIZE); + DmaClear16(3, (void *)PLTT, PLTT_SIZE); + LZ77UnCompVram(gUnknown_08DCC05C, (void *)VRAM); + if (gSpecialVar_0x8004 == 0) + { + LoadPalette(gUnknown_08DCC01C, 0x00, 0x20); + } + else + { + LoadPalette(gUnknown_08DCC03C, 0x00, 0x20); + } + LoadPalette(GetOverworldTextboxPalettePtr(), 0xe0, 0x20); + LoadPalette(gUnknown_085B21D4, 0xc0, 0x08); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_085B21FC, 3); + InitWindows(gUnknown_085B21DC); + DeactivateAllTextPrinters(); + sub_809882C(0, 0x250, 0xd0); + clear_scheduled_bg_copies_to_vram(); + remove_some_task(); + ResetTasks(); + ResetSpriteData(); + ResetPaletteFade(); + FreeAllSpritePalettes(); + LoadCompressedObjectPic(&gUnknown_085B2208); + LoadSpritePalettes(gUnknown_085B2218); +} + +static void WallClockInit(void) +{ + BeginNormalPaletteFade(-1, 0, 16, 0, 0); + EnableInterrupts(INTR_FLAG_VBLANK); + SetVBlankCallback(WallClockVblankCallback); + SetMainCallback2(WallClockMainCallback); + SetGpuReg(REG_OFFSET_BLDCNT, 0x0000); + SetGpuReg(REG_OFFSET_BLDALPHA, 0x0000); + SetGpuReg(REG_OFFSET_BLDY, 0x0000); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); + ShowBg(0); + ShowBg(2); + ShowBg(3); +} + +void Cb2_StartWallClock(void) +{ + u8 taskId; + u8 spriteId; + + LoadWallClockGraphics(); + LZ77UnCompVram(gUnknown_08DCC648, (u16 *)BG_SCREEN_ADDR(7)); + + taskId = CreateTask(Task_SetClock1, 0); + gTasks[taskId].tHours = 10; + gTasks[taskId].tMinutes = 0; + gTasks[taskId].tMvmtDir = 0; + gTasks[taskId].tPeriod = 0; + gTasks[taskId].tMvmtSpeed = 0; + gTasks[taskId].tMinuteHandAngle = 0; + gTasks[taskId].tHourHandAngle = 300; + + spriteId = CreateSprite(&gUnknown_085B2250, 0x78, 0x50, 1); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 0; + + spriteId = CreateSprite(&gUnknown_085B2268, 0x78, 0x50, 0); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 1; + + spriteId = CreateSprite(&gUnknown_085B22A0, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = 45; + + spriteId = CreateSprite(&gUnknown_085B22B8, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = 90; + + WallClockInit(); + + PrintTextOnWindow(1, 1, gText_Confirm3, 0, 1, 0, NULL); + PutWindowTilemap(1); + schedule_bg_copy_tilemap_to_vram(2); +} + +void Cb2_ViewWallClock(void) +{ + u8 taskId; + u8 spriteId; + u8 angle1; + u8 angle2; + + LoadWallClockGraphics(); + LZ77UnCompVram(gUnknown_08DCC908, (u16 *)BG_SCREEN_ADDR(7)); + + taskId = CreateTask(Task_ViewClock1, 0); + InitClockWithRtc(taskId); + if (gTasks[taskId].tPeriod == 0) + { + angle1 = 45; + angle2 = 90; + } + else + { + angle1 = 90; + angle2 = 135; + } + + spriteId = CreateSprite(&gUnknown_085B2250, 0x78, 0x50, 1); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 0; + + spriteId = CreateSprite(&gUnknown_085B2268, 0x78, 0x50, 0); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 1; + + spriteId = CreateSprite(&gUnknown_085B22A0, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = angle1; + + spriteId = CreateSprite(&gUnknown_085B22B8, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = angle2; + + WallClockInit(); + + PrintTextOnWindow(1, 1, gText_Cancel4, 0, 1, 0, NULL); + PutWindowTilemap(1); + schedule_bg_copy_tilemap_to_vram(2); +} + +static void WallClockMainCallback(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void Task_SetClock1(u8 taskId) +{ + if (!gPaletteFade.active) + { + gTasks[taskId].func = Task_SetClock2; + } +} + +static void Task_SetClock2(u8 taskId) +{ + if (gTasks[taskId].tMinuteHandAngle % 6) + { + gTasks[taskId].tMinuteHandAngle = CalcNewMinHandAngle(gTasks[taskId].tMinuteHandAngle, gTasks[taskId].tMvmtDir, gTasks[taskId].tMvmtSpeed); + } + else + { + gTasks[taskId].tMinuteHandAngle = gTasks[taskId].tMinutes * 6; + gTasks[taskId].tHourHandAngle = (gTasks[taskId].tHours % 12) * 30 + (gTasks[taskId].tMinutes / 10) * 5; + if (gMain.newKeys & A_BUTTON) + { + gTasks[taskId].func = Task_SetClock3; + } + else + { + gTasks[taskId].tMvmtDir = 0; + if (gMain.heldKeys & DPAD_LEFT) + { + gTasks[taskId].tMvmtDir = 1; + } + if (gMain.heldKeys & DPAD_RIGHT) + { + gTasks[taskId].tMvmtDir = 2; + } + if (gTasks[taskId].tMvmtDir != 0) + { + if (gTasks[taskId].tMvmtSpeed < 0xFF) + { + gTasks[taskId].tMvmtSpeed++; + } + gTasks[taskId].tMinuteHandAngle = CalcNewMinHandAngle(gTasks[taskId].tMinuteHandAngle, gTasks[taskId].tMvmtDir, gTasks[taskId].tMvmtSpeed); + AdvanceClock(taskId, gTasks[taskId].tMvmtDir); + } + else + { + gTasks[taskId].tMvmtSpeed = 0; + } + } + } +} + +static void Task_SetClock3(u8 taskId) +{ + SetWindowBorderStyle(0, FALSE, 0x250, 0x0d); + PrintTextOnWindow(0, 1, gText_IsThisTheCorrectTime, 0, 1, 0, NULL); + PutWindowTilemap(0); + schedule_bg_copy_tilemap_to_vram(0); + CreateYesNoMenu(&gUnknown_085B21F4, 0x250, 0x0d, 1); + gTasks[taskId].func = Task_SetClock4; +} + +static void Task_SetClock4(u8 taskId) +{ + switch (ProcessMenuInputNoWrap_()) + { + case 0: + PlaySE(SE_SELECT); + gTasks[taskId].func = Task_SetClock5; + break; + case 1: + case -1: + PlaySE(SE_SELECT); + sub_8198070(0, FALSE); + ClearWindowTilemap(0); + gTasks[taskId].func = Task_SetClock2; + break; + } +} + +static void Task_SetClock5(u8 taskId) +{ + RtcInitLocalTimeOffset(gTasks[taskId].tHours, gTasks[taskId].tMinutes); + BeginNormalPaletteFade(-1, 0, 0, 16, 0); + gTasks[taskId].func = Task_SetClock6; +} + +static void Task_SetClock6(u8 taskId) +{ + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + SetMainCallback2(gMain.savedCallback); + } +} + +static void Task_ViewClock1(u8 taskId) +{ + if (!gPaletteFade.active) + { + gTasks[taskId].func = Task_ViewClock2; + } +} + +static void Task_ViewClock2(u8 taskId) +{ + InitClockWithRtc(taskId); + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + gTasks[taskId].func = Task_ViewClock3; + } +} + +static void Task_ViewClock3(u8 taskId) +{ + BeginNormalPaletteFade(-1, 0, 0, 16, 0); + gTasks[taskId].func = Task_ViewClock4; +} + +static void Task_ViewClock4(u8 taskId) +{ + if (!gPaletteFade.active) + { + SetMainCallback2(gMain.savedCallback); + } +} + +static u8 CalcMinHandDelta(u16 a0) +{ + if (a0 > 60) + { + return 6; + } + if (a0 > 30) + { + return 3; + } + if (a0 > 10) + { + return 2; + } + return 1; +} + +static u16 CalcNewMinHandAngle(u16 a0, u8 command, u8 a2) +{ + u8 r1 = CalcMinHandDelta(a2); + switch (command) + { + case 1: + if (a0) a0 -= r1; + else a0 = 360 - r1; + break; + case 2: + if (a0 < 360 - r1) a0 += r1; + else a0 = 0; + break; + } + return a0; +} + +static bool32 AdvanceClock(u8 taskId, u8 command) +{ + switch (command) + { + case 1: + if (gTasks[taskId].tMinutes > 0) + { + gTasks[taskId].tMinutes--; + } + else + { + gTasks[taskId].tMinutes = 59; + if (gTasks[taskId].tHours > 0) + { + gTasks[taskId].tHours--; + } + else + { + gTasks[taskId].tHours = 23; + } + UpdateClockPeriod(taskId, command); + } + break; + case 2: + if (gTasks[taskId].tMinutes < 59) + { + gTasks[taskId].tMinutes++; + } + else + { + gTasks[taskId].tMinutes = 0; + if (gTasks[taskId].tHours < 23) + { + gTasks[taskId].tHours++; + } + else + { + gTasks[taskId].tHours = 0; + } + UpdateClockPeriod(taskId, command); + } + break; + } + return FALSE; +} + +static void UpdateClockPeriod(u8 taskId, u8 command) +{ + u8 hours = gTasks[taskId].tHours; + switch (command) + { + case 1: + switch (hours) + { + case 11: + gTasks[taskId].tPeriod = FALSE; + break; + case 23: + gTasks[taskId].tPeriod = TRUE; + break; + } + break; + case 2: + switch (hours) + { + case 0: + gTasks[taskId].tPeriod = FALSE; + break; + case 12: + gTasks[taskId].tPeriod = TRUE; + break; + } + break; + } +} + +static void InitClockWithRtc(u8 taskId) +{ + RtcCalcLocalTime(); + gTasks[taskId].tHours = gLocalTime.hours; + gTasks[taskId].tMinutes = gLocalTime.minutes; + gTasks[taskId].tMinuteHandAngle = gTasks[taskId].tMinutes * 6; + gTasks[taskId].tHourHandAngle = (gTasks[taskId].tHours % 12) * 30 + (gTasks[taskId].tMinutes / 10) * 5; + if (gLocalTime.hours < 12) + { + gTasks[taskId].tPeriod = FALSE; + } + else + { + gTasks[taskId].tPeriod = TRUE; + } +} + +static void SpriteCB_MinuteHand(struct Sprite *sprite) +{ + u16 angle = gTasks[sprite->data[0]].tMinuteHandAngle; + s16 sin = Sin2(angle) / 16; + s16 cos = Cos2(angle) / 16; + u16 xhat; + u16 yhat; + + SetOamMatrix(0, cos, sin, -sin, cos); + xhat = sClockHandCoords[angle][0]; + yhat = sClockHandCoords[angle][1]; + + if (xhat > 0x80) + { + xhat |= 0xff00; + } + if (yhat > 0x80) + { + yhat |= 0xff00; + } + sprite->pos2.x = xhat; + sprite->pos2.y = yhat; +} + +static void SpriteCB_HourHand(struct Sprite *sprite) +{ + u16 angle = gTasks[sprite->data[0]].tHourHandAngle; + s16 sin = Sin2(angle) / 16; + s16 cos = Cos2(angle) / 16; + u16 xhat; + u16 yhat; + + SetOamMatrix(1, cos, sin, -sin, cos); + xhat = sClockHandCoords[angle][0]; + yhat = sClockHandCoords[angle][1]; + if (xhat > 0x80) + { + xhat |= 0xff00; + } + if (yhat > 0x80) + { + yhat |= 0xff00; + } + sprite->pos2.x = xhat; + sprite->pos2.y = yhat; +} + +static void SpriteCB_AMIndicator(struct Sprite *sprite) +{ + if (gTasks[sprite->data[0]].tPeriod) + { + if (sprite->data[1] >= 60 && sprite->data[1] < 90) + { + sprite->data[1] += 5; + } + if (sprite->data[1] < 60) + { + sprite->data[1]++; + } + } + else + { + if (sprite->data[1] >= 46 && sprite->data[1] < 76) + { + sprite->data[1] -= 5; + } + if (sprite->data[1] > 75) + { + sprite->data[1]--; + } + } + sprite->pos2.x = Cos2(sprite->data[1]) * 30 / 0x1000; + sprite->pos2.y = Sin2(sprite->data[1]) * 30 / 0x1000; +} + +static void SpriteCB_PMIndicator(struct Sprite *sprite) +{ + if (gTasks[sprite->data[0]].tPeriod) + { + if (sprite->data[1] >= 105 && sprite->data[1] < 135) + { + sprite->data[1] += 5; + } + if (sprite->data[1] < 105) + { + sprite->data[1]++; + } + } + else + { + if (sprite->data[1] >= 91 && sprite->data[1] < 121) + { + sprite->data[1] -= 5; + } + if (sprite->data[1] > 120) + { + sprite->data[1]--; + } + } + sprite->pos2.x = Cos2(sprite->data[1]) * 30 / 0x1000; + sprite->pos2.y = Sin2(sprite->data[1]) * 30 / 0x1000; +} |