mirror of
https://github.com/rh-hideout/pokeemerald-expansion.git
synced 2026-03-21 18:04:50 -05:00
Trainerbattle Type Differentiation (#6424)
Co-authored-by: CallmeEchoo <callmeechoo@github.com> Co-authored-by: Your Name <you@example.com>
This commit is contained in:
parent
25623fbade
commit
29f83ea5e0
|
|
@ -98,14 +98,13 @@
|
|||
waitstate
|
||||
.endm
|
||||
|
||||
.macro multi_do type:req, partnerId:req
|
||||
.macro multi_do type:req
|
||||
special ReducePlayerPartyToSelectedMons
|
||||
setvar VAR_0x8004, FRONTIER_UTIL_FUNC_SET_DATA
|
||||
setvar VAR_0x8005, FRONTIER_DATA_SELECTED_MON_ORDER
|
||||
special CallFrontierUtilFunc @ saves the mon order, so the non-selected mons get restored afterwards
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_MULTI
|
||||
setvar VAR_0x8005, \type | MULTI_BATTLE_CHOOSE_MONS
|
||||
setvar VAR_0x8006, \partnerId
|
||||
special DoSpecialTrainerBattle
|
||||
waitstate
|
||||
setvar VAR_0x8004, FRONTIER_UTIL_FUNC_SAVE_PARTY
|
||||
|
|
@ -115,26 +114,26 @@
|
|||
|
||||
.macro multi_2_vs_2 trainer1Id:req, trainer1LoseText:req, trainer2Id:req, trainer2LoseText:req, partnerId:req
|
||||
special SavePlayerParty
|
||||
trainerbattle TRAINER_BATTLE_SET_TRAINERS_FOR_MULTI_BATTLE, OBJ_ID_NONE, \trainer1Id, NULL, \trainer1LoseText, NULL, OBJ_ID_NONE, \trainer2Id, NULL, \trainer2LoseText, NULL, NULL, NULL, FALSE, TRUE, FALSE, FALSE
|
||||
multi_do MULTI_BATTLE_2_VS_2, \partnerId
|
||||
setmultitrainerbattle \trainer1Id, \trainer1LoseText, \trainer2Id, \trainer2LoseText, \partnerId
|
||||
multi_do MULTI_BATTLE_2_VS_2
|
||||
.endm
|
||||
|
||||
.macro multi_2_vs_1 trainer1Id:req, trainer1LoseText:req, partnerId:req
|
||||
special SavePlayerParty
|
||||
trainerbattle TRAINER_BATTLE_SET_TRAINERS_FOR_MULTI_BATTLE, OBJ_ID_NONE, \trainer1Id, NULL, \trainer1LoseText, NULL, OBJ_ID_NONE, TRAINER_NONE, NULL, NULL, NULL, NULL, NULL, FALSE, TRUE, FALSE, FALSE
|
||||
multi_do MULTI_BATTLE_2_VS_1, \partnerId
|
||||
setmultitrainerbattle \trainer1Id, \trainer1LoseText, TRAINER_NONE, NULL, \partnerId
|
||||
multi_do MULTI_BATTLE_2_VS_1
|
||||
.endm
|
||||
|
||||
@ Wild mons need to be assigned to gEnemyParty 0 and 3 slots, other slots need to be cleared out.
|
||||
.macro multi_wild partnerId:req
|
||||
special SavePlayerParty
|
||||
multi_do MULTI_BATTLE_2_VS_WILD, \partnerId
|
||||
setmultitrainerbattle TRAINER_NONE, NULL, TRAINER_NONE, NULL, \partnerId
|
||||
multi_do MULTI_BATTLE_2_VS_WILD
|
||||
.endm
|
||||
|
||||
.macro multi_do_fixed type:req, partnerId:req
|
||||
.macro multi_do_fixed type:req
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_MULTI
|
||||
setvar VAR_0x8005, \type
|
||||
setvar VAR_0x8006, \partnerId
|
||||
special DoSpecialTrainerBattle
|
||||
waitstate
|
||||
setvar VAR_0x8004, FRONTIER_UTIL_FUNC_SAVE_PARTY
|
||||
|
|
@ -144,18 +143,19 @@
|
|||
|
||||
.macro multi_fixed_2_vs_2 trainer1Id:req, trainer1LoseText:req, trainer2Id:req, trainer2LoseText:req, partnerId:req
|
||||
special SavePlayerParty
|
||||
trainerbattle TRAINER_BATTLE_SET_TRAINERS_FOR_MULTI_BATTLE, OBJ_ID_NONE, \trainer1Id, NULL, \trainer1LoseText, NULL, OBJ_ID_NONE, \trainer2Id, NULL, \trainer2LoseText, NULL, NULL, NULL, FALSE, TRUE, FALSE, FALSE
|
||||
multi_do_fixed MULTI_BATTLE_2_VS_2, \partnerId
|
||||
setmultitrainerbattle \trainer1Id, \trainer1LoseText, \trainer2Id, \trainer2LoseText, \partnerId
|
||||
multi_do_fixed MULTI_BATTLE_2_VS_2
|
||||
.endm
|
||||
|
||||
.macro multi_fixed_2_vs_1 trainer1Id:req, trainer1LoseText:req, partnerId:req
|
||||
special SavePlayerParty
|
||||
trainerbattle TRAINER_BATTLE_SET_TRAINERS_FOR_MULTI_BATTLE, OBJ_ID_NONE, \trainer1Id, NULL, \trainer1LoseText, NULL, OBJ_ID_NONE, TRAINER_NONE, NULL, NULL, NULL, NULL, NULL, FALSE, TRUE, FALSE, FALSE
|
||||
multi_do_fixed MULTI_BATTLE_2_VS_1, \partnerId
|
||||
setmultitrainerbattle \trainer1Id, \trainer1LoseText, TRAINER_NONE, NULL, \partnerId
|
||||
multi_do_fixed MULTI_BATTLE_2_VS_1
|
||||
.endm
|
||||
|
||||
@ Wild mons need to be assigned to gEnemyParty 0 and 3 slots, other slots need to be cleared out.
|
||||
.macro multi_fixed_wild partnerId:req
|
||||
special SavePlayerParty
|
||||
multi_do_fixed MULTI_BATTLE_2_VS_WILD, \partnerId
|
||||
setmultitrainerbattle TRAINER_NONE, NULL, TRAINER_NONE, NULL, \partnerId
|
||||
multi_do_fixed MULTI_BATTLE_2_VS_WILD
|
||||
.endm
|
||||
|
|
|
|||
|
|
@ -2599,6 +2599,27 @@
|
|||
cant_see_if 5
|
||||
.endm
|
||||
|
||||
.macro setmultitrainerbattle trainer_a:req, lose_text_a:req, trainer_b:req, lose_text_b:req, partnerId:req
|
||||
callnative SetMultiTrainerBattle
|
||||
.2byte \trainer_a
|
||||
.4byte \lose_text_a
|
||||
.2byte \trainer_b
|
||||
.4byte \lose_text_b
|
||||
.2byte \partnerId
|
||||
.endm
|
||||
|
||||
@ facility version of `trainerbattle` macro. Used in Battle Pyramid and Trainer Hill
|
||||
.macro facilitytrainerbattle facility:req
|
||||
callnative FacilityTrainerBattle
|
||||
.byte \facility
|
||||
.endm
|
||||
|
||||
@ immediately starts a battle of the given facility
|
||||
.macro dofacilitytrainerbattle facility:req
|
||||
callnative DoFacilityTrainerBattle
|
||||
.byte \facility
|
||||
.endm
|
||||
|
||||
@ Follower NPCs
|
||||
|
||||
@ Sets an existing NPC up to follow the player.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "constants/battle_pike.h"
|
||||
#include "constants/battle_pyramid.h"
|
||||
#include "constants/battle_setup.h"
|
||||
#include "constants/battle_special.h"
|
||||
#include "constants/battle_tent.h"
|
||||
#include "constants/battle_tower.h"
|
||||
#include "constants/berry.h"
|
||||
|
|
|
|||
|
|
@ -364,9 +364,7 @@ BattleFrontier_BattleArenaBattleRoom_EventScript_DoArenaBattle::
|
|||
setvar VAR_TEMP_2, 0
|
||||
frontier_set FRONTIER_DATA_RECORD_DISABLED, FALSE
|
||||
special HealPlayerParty
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_ARENA
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_ARENA
|
||||
waitstate
|
||||
frontier_restorehelditems
|
||||
special HealPlayerParty
|
||||
|
|
|
|||
|
|
@ -445,10 +445,8 @@ BattleFrontier_BattleDomeBattleRoom_EventScript_TuckerDraw::
|
|||
BattleFrontier_BattleDomeBattleRoom_EventScript_DoDomeBattle::
|
||||
frontier_set FRONTIER_DATA_RECORD_DISABLED, FALSE
|
||||
special HealPlayerParty
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_DOME
|
||||
setvar VAR_0x8005, 0
|
||||
setvar VAR_TEMP_9, 1
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_DOME
|
||||
waitstate
|
||||
setvar VAR_TEMP_9, 0
|
||||
dome_restorehelditems
|
||||
|
|
|
|||
|
|
@ -80,9 +80,7 @@ BattleFrontier_BattleFactoryBattleRoom_EventScript_BattleOpponent::
|
|||
closemessage
|
||||
frontier_set FRONTIER_DATA_RECORD_DISABLED, FALSE
|
||||
special HealPlayerParty
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_FACTORY
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FRONTIER_FACILITY_FACTORY
|
||||
waitstate
|
||||
switch VAR_RESULT
|
||||
case 1, BattleFrontier_BattleFactoryBattleRoom_EventScript_DefeatedOpponent
|
||||
|
|
@ -171,9 +169,7 @@ BattleFrontier_BattleFactoryBattleRoom_EventScript_DoNolandBattle::
|
|||
closemessage
|
||||
frontier_set FRONTIER_DATA_RECORD_DISABLED, FALSE
|
||||
special HealPlayerParty
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_FACTORY
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_FACTORY
|
||||
waitstate
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -274,9 +274,7 @@ BattleFrontier_BattlePalaceBattleRoom_EventScript_DoPalaceBattle::
|
|||
setvar VAR_TEMP_2, 0
|
||||
frontier_set FRONTIER_DATA_RECORD_DISABLED, FALSE
|
||||
special HealPlayerParty
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_PALACE
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_PALACE
|
||||
waitstate
|
||||
frontier_restorehelditems
|
||||
special HealPlayerParty
|
||||
|
|
|
|||
|
|
@ -31,9 +31,7 @@ BattleFrontier_BattlePikeRoomNormal_EventScript_EnterSingleBattleRoom::
|
|||
waitmessage
|
||||
closemessage
|
||||
releaseall
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_PIKE_SINGLE
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_PIKE_SINGLE
|
||||
waitstate
|
||||
switch VAR_RESULT
|
||||
case 1, BattleFrontier_BattlePikeRoomNormal_EventScript_WonSingleBattle
|
||||
|
|
@ -61,9 +59,7 @@ BattleFrontier_BattlePikeRoomNormal_EventScript_EnterHardBattleRoom::
|
|||
waitmessage
|
||||
closemessage
|
||||
releaseall
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_PIKE_SINGLE
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_PIKE_SINGLE
|
||||
waitstate
|
||||
switch VAR_RESULT
|
||||
case 1, BattleFrontier_BattlePikeRoomNormal_EventScript_WonHardBattle
|
||||
|
|
@ -252,9 +248,7 @@ BattleFrontier_BattlePikeRoomNormal_EventScript_EnterDoubleBattleRoom::
|
|||
pike_gettrainerintro 1
|
||||
msgbox gStringVar4, MSGBOX_DEFAULT
|
||||
closemessage
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_PIKE_DOUBLE
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_PIKE_DOUBLE
|
||||
waitstate
|
||||
switch VAR_RESULT
|
||||
case 1, BattleFrontier_BattlePikeRoomNormal_EventScript_WonDoubleBattle
|
||||
|
|
@ -380,9 +374,7 @@ BattleFrontier_BattlePikeRoomNormal_EventScript_DoPikeQueenBattle::
|
|||
closemessage
|
||||
applymovement LOCALID_PLAYER, BattleFrontier_BattlePikeRoomNormal_Movement_PlayerWalkUp2
|
||||
waitmovement 0
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_PIKE_SINGLE
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_PIKE_SINGLE
|
||||
waitstate
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ BattlePyramid_WarpToTop::
|
|||
|
||||
@ TRAINER_PHILLIP is used as a placeholder
|
||||
BattlePyramid_TrainerBattle::
|
||||
trainerbattle TRAINER_BATTLE_HILL, LOCALID_NONE, TRAINER_PHILLIP, BattleFacility_TrainerBattle_PlaceholderText, BattleFacility_TrainerBattle_PlaceholderText, NULL, LOCALID_NONE, TRAINER_NONE, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE
|
||||
facilitytrainerbattle FACILITY_BATTLE_PYRAMID
|
||||
pyramid_showhint
|
||||
waitmessage
|
||||
waitbuttonpress
|
||||
|
|
|
|||
|
|
@ -180,9 +180,7 @@ BattleFrontier_BattlePyramidTop_EventScript_DefeatedBrandonGold::
|
|||
|
||||
BattleFrontier_BattlePyramidTop_EventScript_DoBrandonBattle::
|
||||
closemessage
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_PYRAMID
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_PYRAMID
|
||||
waitstate
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -296,9 +296,7 @@ BattleFrontier_BattleTowerBattleRoom_EventScript_DoTowerBattle::
|
|||
setvar VAR_TEMP_2, 0
|
||||
frontier_set FRONTIER_DATA_RECORD_DISABLED, FALSE
|
||||
special HealPlayerParty
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_TOWER
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_TOWER
|
||||
waitstate
|
||||
copyvar VAR_0x8004, VAR_FRONTIER_BATTLE_MODE
|
||||
goto_if_eq VAR_0x8004, FRONTIER_MODE_LINK_MULTIS, BattleFrontier_BattleTowerBattleRoom_EventScript_EndTowerBattle
|
||||
|
|
|
|||
|
|
@ -57,9 +57,7 @@ SlateportCity_BattleTentBattleRoom_EventScript_EnterRoom::
|
|||
waitmessage
|
||||
closemessage
|
||||
special HealPlayerParty
|
||||
setvar VAR_0x8004, SPECIAL_BATTLE_FACTORY
|
||||
setvar VAR_0x8005, 0
|
||||
special DoSpecialTrainerBattle
|
||||
dofacilitytrainerbattle FACILITY_BATTLE_PYRAMID
|
||||
waitstate
|
||||
switch VAR_RESULT
|
||||
case 1, SlateportCity_BattleTentBattleRoom_EventScript_DefeatedOpponent
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ TrainerHill_1F_Movement_SetInvisible::
|
|||
|
||||
@ TRAINER_PHILLIP is an actual Trainer on the SS Tidal, but is used as a placeholder here
|
||||
TrainerHill_EventScript_TrainerBattle::
|
||||
trainerbattle TRAINER_BATTLE_HILL, LOCALID_NONE, TRAINER_PHILLIP, BattleFacility_TrainerBattle_PlaceholderText, BattleFacility_TrainerBattle_PlaceholderText, NULL, LOCALID_NONE, TRAINER_NONE, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE
|
||||
facilitytrainerbattle FACILITY_BATTLE_TRAINER_HILL
|
||||
trainerhill_postbattletext
|
||||
waitmessage
|
||||
waitbuttonpress
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef GUARD_BATTLE_DOME_H
|
||||
#define GUARD_BATTLE_DOME_H
|
||||
|
||||
#include "constants/battle_dome.h"
|
||||
|
||||
int GetDomeTrainerSelectedMons(u16 tournamentTrainerId);
|
||||
int TrainerIdToDomeTournamentId(u16 trainerId);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@ void FillFactoryBrainParty(void);
|
|||
u8 GetNumPastRentalsRank(u8 battleMode, u8 lvlMode);
|
||||
u64 GetAiScriptsInBattleFactory(void);
|
||||
void SetMonMoveAvoidReturn(struct Pokemon *mon, u16 moveArg, u8 moveSlot);
|
||||
void FillFactoryTrainerParty(void);
|
||||
|
||||
#endif // GUARD_BATTLE_FACTORY_H
|
||||
|
|
|
|||
32
include/battle_frontier.h
Normal file
32
include/battle_frontier.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef GUARD_BATTLE_FRONTIER_H
|
||||
#define GUARD_BATTLE_FRONTIER_H
|
||||
|
||||
#include "data.h"
|
||||
#include "script.h"
|
||||
|
||||
struct BattleFrontierTrainer
|
||||
{
|
||||
u8 facilityClass;
|
||||
u8 filler1[3];
|
||||
u8 trainerName[PLAYER_NAME_LENGTH + 1];
|
||||
u16 speechBefore[EASY_CHAT_BATTLE_WORDS_COUNT];
|
||||
u16 speechWin[EASY_CHAT_BATTLE_WORDS_COUNT];
|
||||
u16 speechLose[EASY_CHAT_BATTLE_WORDS_COUNT];
|
||||
const u16 *monSet;
|
||||
};
|
||||
|
||||
// Temporary storage for monIds of the opponent team
|
||||
// during team generation in battle factory and similar facilities.
|
||||
extern u16 gFrontierTempParty[MAX_FRONTIER_PARTY_SIZE];
|
||||
|
||||
extern const struct BattleFrontierTrainer *gFacilityTrainers;
|
||||
extern const struct TrainerMon *gFacilityTrainerMons;
|
||||
extern const struct BattleFrontierTrainer gBattleFrontierTrainers[];
|
||||
extern const struct TrainerMon gBattleFrontierMons[];
|
||||
|
||||
void DoFacilityTrainerBattle(struct ScriptContext *ctx);
|
||||
void FillFrontierTrainerParty(u8 monsCount);
|
||||
void FillFrontierTrainersParties(u8 monsCount);
|
||||
void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 otID, u32 flags, struct Pokemon *dst);
|
||||
|
||||
#endif // GUARD_BATTLE_FRONTIER_H
|
||||
11
include/battle_partner.h
Normal file
11
include/battle_partner.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef BATTLE_PARTNER_H
|
||||
#define BATTLE_PARTNER_H
|
||||
|
||||
#include "difficulty.h"
|
||||
#include "constants/battle_partner.h"
|
||||
|
||||
extern const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT];
|
||||
|
||||
void FillPartnerParty(u16 trainerId);
|
||||
|
||||
#endif // BATTLE_PARTNER_H
|
||||
|
|
@ -42,7 +42,6 @@ typedef union PACKED TrainerBattleParameter
|
|||
u8 data[sizeof(struct _TrainerBattleParameter)];
|
||||
} TrainerBattleParameter;
|
||||
|
||||
|
||||
extern const struct RematchTrainer gRematchTable[REMATCH_TABLE_ENTRIES];
|
||||
|
||||
extern TrainerBattleParameter gTrainerBattleParameter;
|
||||
|
|
@ -70,6 +69,7 @@ void ResetTrainerOpponentIds(void);
|
|||
void SetMapVarsToTrainerA(void);
|
||||
void SetMapVarsToTrainerB(void);
|
||||
const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data);
|
||||
const u8* BattleSetup_ConfigureFacilityTrainerBattle(u8 facility, const u8* scriptEndPtr);
|
||||
void ConfigureAndSetUpOneTrainerBattle(u8 trainerObjEventId, const u8 *trainerScript);
|
||||
void ConfigureTwoTrainersBattle(u8 trainerObjEventId, const u8 *trainerScript);
|
||||
void SetUpTwoTrainersBattle(void);
|
||||
|
|
@ -107,6 +107,7 @@ void TrainerBattleLoadArgs(const u8 *data);
|
|||
void TrainerBattleLoadArgsTrainerA(const u8 *data);
|
||||
void TrainerBattleLoadArgsTrainerB(const u8 *data);
|
||||
void TrainerBattleLoadArgsSecondTrainer(const u8 *data);
|
||||
void InitTrainerBattleParameter(void);
|
||||
|
||||
void DoStandardWildBattle_Debug(void);
|
||||
void BattleSetup_StartTrainerBattle_Debug(void);
|
||||
|
|
|
|||
13
include/battle_special.h
Normal file
13
include/battle_special.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef GUARD_BATTLE_SPECIAL_H
|
||||
#define GUARD_BATTLE_SPECIAL_H
|
||||
|
||||
void DoSpecialTrainerBattle(void);
|
||||
void SetEReaderTrainerGfxId(void);
|
||||
u8 GetEreaderTrainerFrontSpriteId(void);
|
||||
enum TrainerClassID GetEreaderTrainerClassId(void);
|
||||
void GetEreaderTrainerName(u8 *dst);
|
||||
void ValidateEReaderTrainer(void);
|
||||
void ClearEReaderTrainer(struct BattleTowerEReaderTrainer *ereaderTrainer);
|
||||
void CopyEReaderTrainerGreeting(void);
|
||||
|
||||
#endif // GUARD_BATTLE_SPECIAL_H
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#define GUARD_BATTLE_TOWER_H
|
||||
|
||||
#include "data.h"
|
||||
#include "battle_frontier.h"
|
||||
|
||||
struct RSBattleTowerRecord
|
||||
{
|
||||
|
|
@ -15,68 +16,27 @@ struct RSBattleTowerRecord
|
|||
/*0xA0*/ u32 checksum;
|
||||
};
|
||||
|
||||
struct BattleFrontierTrainer
|
||||
{
|
||||
u8 facilityClass;
|
||||
u8 filler1[3];
|
||||
u8 trainerName[PLAYER_NAME_LENGTH + 1];
|
||||
u16 speechBefore[EASY_CHAT_BATTLE_WORDS_COUNT];
|
||||
u16 speechWin[EASY_CHAT_BATTLE_WORDS_COUNT];
|
||||
u16 speechLose[EASY_CHAT_BATTLE_WORDS_COUNT];
|
||||
const u16 *monSet;
|
||||
};
|
||||
|
||||
extern const u8 gTowerMaleFacilityClasses[30];
|
||||
extern const u16 gTowerMaleTrainerGfxIds[30];
|
||||
extern const u8 gTowerFemaleFacilityClasses[20];
|
||||
extern const u16 gTowerFemaleTrainerGfxIds[20];
|
||||
extern const struct TrainerMon gBattleFrontierMons[];
|
||||
extern const struct BattleFrontierTrainer gBattleFrontierTrainers[];
|
||||
extern const struct TrainerMon gSlateportBattleTentMons[];
|
||||
extern const struct BattleFrontierTrainer gSlateportBattleTentTrainers[];
|
||||
|
||||
// Temporary storage for monIds of the opponent team
|
||||
// during team generation in battle factory and similar facilities.
|
||||
extern u16 gFrontierTempParty[];
|
||||
|
||||
extern const struct BattleFrontierTrainer *gFacilityTrainers;
|
||||
extern const struct TrainerMon *gFacilityTrainerMons;
|
||||
|
||||
void CallBattleTowerFunc(void);
|
||||
u16 GetRandomScaledFrontierTrainerId(u8 challengeNum, u8 battleNum);
|
||||
void SetBattleFacilityTrainerGfxId(u16 trainerId, u8 tempVarId);
|
||||
void SetEReaderTrainerGfxId(void);
|
||||
u16 GetBattleFacilityTrainerGfxId(u16 trainerId);
|
||||
void PutNewBattleTowerRecord(struct EmeraldBattleTowerRecord *newRecordEm);
|
||||
u8 GetFrontierTrainerFrontSpriteId(u16 trainerId);
|
||||
enum TrainerClassID GetFrontierOpponentClass(u16 trainerId);
|
||||
void GetFrontierTrainerName(u8 *dst, u16 trainerId);
|
||||
void FillFrontierTrainerParty(u8 monsCount);
|
||||
void FillFrontierTrainersParties(u8 monsCount);
|
||||
u16 GetRandomFrontierMonFromSet(u16 trainerId);
|
||||
void FrontierSpeechToString(const u16 *words);
|
||||
void DoSpecialTrainerBattle(void);
|
||||
void CalcEmeraldBattleTowerChecksum(struct EmeraldBattleTowerRecord *record);
|
||||
void CalcRubyBattleTowerChecksum(struct RSBattleTowerRecord *record);
|
||||
u16 GetCurrentBattleTowerWinStreak(u8 lvlMode, u8 battleMode);
|
||||
u8 GetEreaderTrainerFrontSpriteId(void);
|
||||
enum TrainerClassID GetEreaderTrainerClassId(void);
|
||||
void GetEreaderTrainerName(u8 *dst);
|
||||
void ValidateEReaderTrainer(void);
|
||||
void ClearEReaderTrainer(struct BattleTowerEReaderTrainer *ereaderTrainer);
|
||||
void CopyEReaderTrainerGreeting(void);
|
||||
void TryHideBattleTowerReporter(void);
|
||||
bool32 RubyBattleTowerRecordToEmerald(struct RSBattleTowerRecord *src, struct EmeraldBattleTowerRecord *dst);
|
||||
bool32 EmeraldBattleTowerRecordToRuby(struct EmeraldBattleTowerRecord *src, struct RSBattleTowerRecord *dst);
|
||||
void CalcApprenticeChecksum(struct Apprentice *apprentice);
|
||||
void GetBattleTowerTrainerLanguage(u8 *dst, u16 trainerId);
|
||||
u8 SetFacilityPtrsGetLevel(void);
|
||||
u8 GetFrontierEnemyMonLevel(u8 lvlMode);
|
||||
s32 GetHighestLevelInPlayerParty(void);
|
||||
u16 FacilityClassToGraphicsId(u8 facilityClass);
|
||||
u8 SetTentPtrsGetLevel(void);
|
||||
bool32 ValidateBattleTowerRecord(u8 recordId); // unused
|
||||
void TrySetLinkBattleTowerEnemyPartyLevel(void);
|
||||
void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 otID, u32 flags, struct Pokemon *dst);
|
||||
void FillPartnerParty(u16 trainerId);
|
||||
void FillTentTrainerParty(u8 monsCount);
|
||||
|
||||
|
||||
#endif //GUARD_BATTLE_TOWER_H
|
||||
|
|
|
|||
|
|
@ -33,17 +33,20 @@
|
|||
#define CHALLENGE_STATUS_LOST 4
|
||||
|
||||
// Special trainer battles.
|
||||
#define SPECIAL_BATTLE_TOWER 0
|
||||
#define SPECIAL_BATTLE_SECRET_BASE 1
|
||||
#define SPECIAL_BATTLE_EREADER 2
|
||||
#define SPECIAL_BATTLE_DOME 3
|
||||
#define SPECIAL_BATTLE_PALACE 4
|
||||
#define SPECIAL_BATTLE_ARENA 5
|
||||
#define SPECIAL_BATTLE_FACTORY 6
|
||||
#define SPECIAL_BATTLE_PIKE_SINGLE 7
|
||||
#define SPECIAL_BATTLE_PIKE_DOUBLE 8
|
||||
#define SPECIAL_BATTLE_PYRAMID 9
|
||||
#define SPECIAL_BATTLE_MULTI 10
|
||||
#define SPECIAL_BATTLE_MULTI 3
|
||||
|
||||
// Facility trainer Battles
|
||||
#define FACILITY_BATTLE_TOWER 0
|
||||
#define FACILITY_BATTLE_DOME 1
|
||||
#define FACILITY_BATTLE_PALACE 2
|
||||
#define FACILITY_BATTLE_ARENA 3
|
||||
#define FACILITY_BATTLE_FACTORY 4
|
||||
#define FACILITY_BATTLE_PIKE_SINGLE 5
|
||||
#define FACILITY_BATTLE_PIKE_DOUBLE 6
|
||||
#define FACILITY_BATTLE_PYRAMID 7
|
||||
#define FACILITY_BATTLE_TRAINER_HILL 8
|
||||
|
||||
#define MAX_BATTLE_FRONTIER_POINTS 9999
|
||||
#define MAX_STREAK 9999
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
#define TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE 6
|
||||
#define TRAINER_BATTLE_REMATCH_DOUBLE 7
|
||||
#define TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE_NO_MUSIC 8
|
||||
#define TRAINER_BATTLE_PYRAMID 9
|
||||
#define TRAINER_BATTLE_SET_TRAINERS_FOR_MULTI_BATTLE 10
|
||||
#define TRAINER_BATTLE_HILL 12
|
||||
#define TRAINER_BATTLE_TWO_TRAINERS_NO_INTRO 13
|
||||
|
||||
#endif // GUARD_CONSTANTS_BATTLE_SETUP_H
|
||||
|
|
|
|||
10
include/constants/battle_special.h
Normal file
10
include/constants/battle_special.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef GUARD_CONSTANTS_BATTLE_SPECIAL_H
|
||||
#define GUARD_CONSTANTS_BATTLE_SPECIAL_H
|
||||
|
||||
// Ids for special multi battle types
|
||||
#define MULTI_BATTLE_2_VS_2 0
|
||||
#define MULTI_BATTLE_2_VS_WILD 1
|
||||
#define MULTI_BATTLE_2_VS_1 2
|
||||
#define MULTI_BATTLE_CHOOSE_MONS 0x80
|
||||
|
||||
#endif // GUARD_CONSTANTS_BATTLE_SPECIAL_H
|
||||
|
|
@ -38,10 +38,4 @@
|
|||
#define BATTLE_TOWER_LINKSTAT_MEMBER_RETIRE 2
|
||||
#define BATTLE_TOWER_LINKSTAT_LEADER_RETIRE 3
|
||||
|
||||
// Ids for special multi battle types
|
||||
#define MULTI_BATTLE_2_VS_2 0
|
||||
#define MULTI_BATTLE_2_VS_WILD 1
|
||||
#define MULTI_BATTLE_2_VS_1 2
|
||||
#define MULTI_BATTLE_CHOOSE_MONS 0x80
|
||||
|
||||
#endif //GUARD_CONSTANTS_BATTLE_TOWER_H
|
||||
|
|
|
|||
|
|
@ -25,6 +25,21 @@ u8 GetFrontierBrainMonNature(u8 monId);
|
|||
u8 GetFrontierBrainMonEvs(u8 monId, u8 evStatId);
|
||||
s32 GetFronterBrainSymbol(void);
|
||||
void ClearEnemyPartyAfterChallenge(void);
|
||||
bool8 IsFrontierTrainerFemale(u16 trainerId);
|
||||
u8 GetFrontierTrainerFixedIvs(u16 trainerId);
|
||||
u16 GetRandomScaledFrontierTrainerId(u8 challengeNum, u8 battleNum);
|
||||
void SetBattleFacilityTrainerGfxId(u16 trainerId, u8 tempVarId);
|
||||
u16 GetBattleFacilityTrainerGfxId(u16 trainerId);
|
||||
u8 GetFrontierTrainerFrontSpriteId(u16 trainerId);
|
||||
enum TrainerClassID GetFrontierOpponentClass(u16 trainerId);
|
||||
u8 GetFrontierTrainerFacilityClass(u16 trainerId);
|
||||
void GetFrontierTrainerName(u8 *dst, u16 trainerId);
|
||||
u16 GetRandomFrontierMonFromSet(u16 trainerId);
|
||||
void FrontierSpeechToString(const u16 *words);
|
||||
u8 SetFacilityPtrsGetLevel(void);
|
||||
u8 GetFrontierEnemyMonLevel(u8 lvlMode);
|
||||
s32 GetHighestLevelInPlayerParty(void);
|
||||
u16 FacilityClassToGraphicsId(u8 facilityClass);
|
||||
void ShowBattleFrontierCaughtBannedSpecies(void);
|
||||
|
||||
#endif // GUARD_FRONTIER_UTIL_H
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "data.h"
|
||||
#include "event_data.h"
|
||||
#include "event_object_movement.h"
|
||||
#include "frontier_util.h"
|
||||
#include "field_player_avatar.h"
|
||||
#include "international_string_util.h"
|
||||
#include "item.h"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "battle_tv.h"
|
||||
#include "bg.h"
|
||||
#include "data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "link.h"
|
||||
#include "main.h"
|
||||
#include "m4a.h"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "battle_tv.h"
|
||||
#include "bg.h"
|
||||
#include "data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "link.h"
|
||||
#include "main.h"
|
||||
#include "m4a.h"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "battle_message.h"
|
||||
#include "battle_interface.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_special.h"
|
||||
#include "battle_tv.h"
|
||||
#include "battle_z_move.h"
|
||||
#include "bg.h"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "battle_z_move.h"
|
||||
#include "bg.h"
|
||||
#include "data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "item_use.h"
|
||||
#include "link.h"
|
||||
#include "main.h"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "battle_tv.h"
|
||||
#include "bg.h"
|
||||
#include "data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "item_menu.h"
|
||||
#include "item_use.h"
|
||||
#include "link.h"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "battle_z_move.h"
|
||||
#include "bg.h"
|
||||
#include "data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "item_use.h"
|
||||
#include "link.h"
|
||||
#include "main.h"
|
||||
|
|
|
|||
|
|
@ -848,3 +848,81 @@ void SetMonMoveAvoidReturn(struct Pokemon *mon, u16 moveArg, u8 moveSlot)
|
|||
move = MOVE_FRUSTRATION;
|
||||
SetMonMoveSlot(mon, move, moveSlot);
|
||||
}
|
||||
|
||||
static void FillFactoryFrontierTrainerParty(u16 trainerId, u8 firstMonId)
|
||||
{
|
||||
u8 i;
|
||||
u8 level;
|
||||
u8 fixedIV;
|
||||
u32 otID;
|
||||
|
||||
if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
// By mistake Battle Tower's Level 50 challenge number is used to determine the IVs for Battle Factory.
|
||||
#ifdef BUGFIX
|
||||
u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
|
||||
u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE);
|
||||
u8 challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / FRONTIER_STAGES_PER_CHALLENGE;
|
||||
#else
|
||||
u8 UNUSED lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
|
||||
u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE);
|
||||
u8 challengeNum = gSaveBlock2Ptr->frontier.towerWinStreaks[battleMode][FRONTIER_LVL_50] / FRONTIER_STAGES_PER_CHALLENGE;
|
||||
#endif
|
||||
if (gSaveBlock2Ptr->frontier.curChallengeBattleNum < FRONTIER_STAGES_PER_CHALLENGE - 1)
|
||||
fixedIV = GetFactoryMonFixedIV(challengeNum, FALSE);
|
||||
else
|
||||
fixedIV = GetFactoryMonFixedIV(challengeNum, TRUE); // Last trainer in challenge uses higher IVs
|
||||
}
|
||||
else if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
for (i = firstMonId; i < firstMonId + FRONTIER_PARTY_SIZE; i++)
|
||||
CreateBattleTowerMon(&gEnemyParty[i], &gSaveBlock2Ptr->frontier.ereaderTrainer.party[i - firstMonId]);
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
return;
|
||||
}
|
||||
else if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
{
|
||||
FillFactoryBrainParty();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
fixedIV = MAX_PER_STAT_IVS;
|
||||
}
|
||||
|
||||
level = SetFacilityPtrsGetLevel();
|
||||
otID = T1_READ_32(gSaveBlock2Ptr->playerTrainerId);
|
||||
for (i = 0; i < FRONTIER_PARTY_SIZE; i++)
|
||||
{
|
||||
u16 monId = gFrontierTempParty[i];
|
||||
CreateFacilityMon(&gFacilityTrainerMons[monId],
|
||||
level, fixedIV, otID, FLAG_FRONTIER_MON_FACTORY,
|
||||
&gEnemyParty[firstMonId + i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void FillFactoryTentTrainerParty(u16 trainerId, u8 firstMonId)
|
||||
{
|
||||
u8 i;
|
||||
u8 level = TENT_MIN_LEVEL;
|
||||
u8 fixedIV = 0;
|
||||
u32 otID = T1_READ_32(gSaveBlock2Ptr->playerTrainerId);
|
||||
|
||||
for (i = 0; i < FRONTIER_PARTY_SIZE; i++)
|
||||
{
|
||||
u16 monId = gFrontierTempParty[i];
|
||||
CreateFacilityMon(&gFacilityTrainerMons[monId],
|
||||
level, fixedIV, otID, 0,
|
||||
&gEnemyParty[firstMonId + i]);
|
||||
}
|
||||
}
|
||||
|
||||
void FillFactoryTrainerParty(void)
|
||||
{
|
||||
ZeroEnemyPartyMons();
|
||||
if (gSaveBlock2Ptr->frontier.lvlMode != FRONTIER_LVL_TENT)
|
||||
FillFactoryFrontierTrainerParty(TRAINER_BATTLE_PARAM.opponentA, 0);
|
||||
else
|
||||
FillFactoryTentTrainerParty(TRAINER_BATTLE_PARAM.opponentA, 0);
|
||||
}
|
||||
|
|
|
|||
395
src/battle_frontier.c
Normal file
395
src/battle_frontier.c
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
#include "global.h"
|
||||
#include "main.h"
|
||||
#include "battle.h"
|
||||
#include "battle_main.h"
|
||||
#include "battle_frontier.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_dome.h"
|
||||
#include "battle_factory.h"
|
||||
#include "battle_partner.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_transition.h"
|
||||
#include "event_data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "overworld.h"
|
||||
#include "script.h"
|
||||
#include "string_util.h"
|
||||
#include "task.h"
|
||||
#include "text.h"
|
||||
#include "constants/abilities.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/battle_frontier_mons.h"
|
||||
|
||||
static void FillTrainerParty(u16 trainerId, u8 firstMonId, u8 monCount);
|
||||
|
||||
// EWRAM vars.
|
||||
EWRAM_DATA const struct BattleFrontierTrainer *gFacilityTrainers = NULL;
|
||||
EWRAM_DATA const struct TrainerMon *gFacilityTrainerMons = NULL;
|
||||
|
||||
// IWRAM common
|
||||
COMMON_DATA u16 gFrontierTempParty[MAX_FRONTIER_PARTY_SIZE] = {0};
|
||||
|
||||
static void HandleFacilityTrainerBattleEnd(void)
|
||||
{
|
||||
u8 facility = gBattleScripting.specialTrainerBattleType;
|
||||
switch (facility)
|
||||
{
|
||||
case FACILITY_BATTLE_TOWER:
|
||||
case FACILITY_BATTLE_DOME:
|
||||
case FACILITY_BATTLE_PALACE:
|
||||
case FACILITY_BATTLE_ARENA:
|
||||
case FACILITY_BATTLE_FACTORY:
|
||||
case FACILITY_BATTLE_PIKE_SINGLE:
|
||||
case FACILITY_BATTLE_PIKE_DOUBLE:
|
||||
case FACILITY_BATTLE_PYRAMID:
|
||||
if (gSaveBlock2Ptr->frontier.battlesCount < 0xFFFFFF)
|
||||
{
|
||||
gSaveBlock2Ptr->frontier.battlesCount++;
|
||||
if (gSaveBlock2Ptr->frontier.battlesCount % 20 == 0)
|
||||
UpdateGymLeaderRematch();
|
||||
}
|
||||
else
|
||||
{
|
||||
gSaveBlock2Ptr->frontier.battlesCount = 0xFFFFFF;
|
||||
}
|
||||
break;
|
||||
case FACILITY_BATTLE_TRAINER_HILL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
||||
}
|
||||
|
||||
static void Task_StartBattleAfterTransition(u8 taskId)
|
||||
{
|
||||
if (IsBattleTransitionDone() == TRUE)
|
||||
{
|
||||
gMain.savedCallback = HandleFacilityTrainerBattleEnd;
|
||||
SetMainCallback2(CB2_InitBattle);
|
||||
DestroyTask(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
static void DoFacilityTrainerBattleInternal(u8 facility)
|
||||
{
|
||||
gBattleScripting.specialTrainerBattleType = facility;
|
||||
|
||||
switch (facility)
|
||||
{
|
||||
case FACILITY_BATTLE_TOWER:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_BATTLE_TOWER;
|
||||
switch (VarGet(VAR_FRONTIER_BATTLE_MODE))
|
||||
{
|
||||
case FRONTIER_MODE_SINGLES:
|
||||
FillFrontierTrainerParty(FRONTIER_PARTY_SIZE);
|
||||
break;
|
||||
case FRONTIER_MODE_DOUBLES:
|
||||
FillFrontierTrainerParty(FRONTIER_DOUBLES_PARTY_SIZE);
|
||||
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE;
|
||||
break;
|
||||
case FRONTIER_MODE_MULTIS:
|
||||
FillFrontierTrainersParties(FRONTIER_MULTI_PARTY_SIZE);
|
||||
gPartnerTrainerId = gSaveBlock2Ptr->frontier.trainerIds[17];
|
||||
FillPartnerParty(gPartnerTrainerId);
|
||||
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS;
|
||||
break;
|
||||
case FRONTIER_MODE_LINK_MULTIS:
|
||||
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE | BATTLE_TYPE_LINK | BATTLE_TYPE_MULTI | BATTLE_TYPE_TOWER_LINK_MULTI;
|
||||
FillFrontierTrainersParties(FRONTIER_MULTI_PARTY_SIZE);
|
||||
break;
|
||||
}
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_TOWER));
|
||||
break;
|
||||
case FACILITY_BATTLE_DOME:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOME;
|
||||
if (VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_DOUBLES)
|
||||
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE;
|
||||
if (TRAINER_BATTLE_PARAM.opponentA == TRAINER_FRONTIER_BRAIN)
|
||||
FillFrontierTrainerParty(DOME_BATTLE_PARTY_SIZE);
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
CreateTask_PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_DOME));
|
||||
break;
|
||||
case FACILITY_BATTLE_PALACE:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE;
|
||||
if (VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_DOUBLES)
|
||||
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE;
|
||||
if (gSaveBlock2Ptr->frontier.lvlMode != FRONTIER_LVL_TENT)
|
||||
FillFrontierTrainerParty(FRONTIER_PARTY_SIZE);
|
||||
else
|
||||
FillTentTrainerParty(FRONTIER_PARTY_SIZE);
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_PALACE));
|
||||
break;
|
||||
case FACILITY_BATTLE_ARENA:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_ARENA;
|
||||
if (gSaveBlock2Ptr->frontier.lvlMode != FRONTIER_LVL_TENT)
|
||||
FillFrontierTrainerParty(FRONTIER_PARTY_SIZE);
|
||||
else
|
||||
FillTentTrainerParty(FRONTIER_PARTY_SIZE);
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_ARENA));
|
||||
break;
|
||||
case FACILITY_BATTLE_FACTORY:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_FACTORY;
|
||||
if (VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_DOUBLES)
|
||||
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE;
|
||||
FillFactoryTrainerParty();
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_FACTORY));
|
||||
break;
|
||||
case FACILITY_BATTLE_PIKE_SINGLE:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_BATTLE_TOWER;
|
||||
FillFrontierTrainerParty(FRONTIER_PARTY_SIZE);
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_PIKE));
|
||||
break;
|
||||
case FACILITY_BATTLE_PIKE_DOUBLE:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS;
|
||||
FillFrontierTrainersParties(1);
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_PIKE));
|
||||
break;
|
||||
case FACILITY_BATTLE_PYRAMID:
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_PYRAMID;
|
||||
FillFrontierTrainerParty(FRONTIER_PARTY_SIZE);
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_PYRAMID));
|
||||
break;
|
||||
case FACILITY_BATTLE_TRAINER_HILL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DoFacilityTrainerBattle(struct ScriptContext *ctx)
|
||||
{
|
||||
u8 facility = ScriptReadByte(ctx);
|
||||
|
||||
DoFacilityTrainerBattleInternal(facility);
|
||||
}
|
||||
|
||||
void FacilityTrainerBattle(struct ScriptContext *ctx)
|
||||
{
|
||||
InitTrainerBattleParameter();
|
||||
|
||||
u8 facility = ScriptReadByte(ctx);
|
||||
ctx->scriptPtr = BattleSetup_ConfigureFacilityTrainerBattle(facility, ctx->scriptPtr);
|
||||
}
|
||||
|
||||
void FillFrontierTrainerParty(u8 monsCount)
|
||||
{
|
||||
ZeroEnemyPartyMons();
|
||||
FillTrainerParty(TRAINER_BATTLE_PARAM.opponentA, 0, monsCount);
|
||||
}
|
||||
|
||||
void FillFrontierTrainersParties(u8 monsCount)
|
||||
{
|
||||
ZeroEnemyPartyMons();
|
||||
FillTrainerParty(TRAINER_BATTLE_PARAM.opponentA, 0, monsCount);
|
||||
FillTrainerParty(TRAINER_BATTLE_PARAM.opponentB, 3, monsCount);
|
||||
}
|
||||
|
||||
static void FillTrainerParty(u16 trainerId, u8 firstMonId, u8 monCount)
|
||||
{
|
||||
s32 i, j;
|
||||
u16 chosenMonIndices[MAX_FRONTIER_PARTY_SIZE];
|
||||
u8 level = SetFacilityPtrsGetLevel();
|
||||
u8 fixedIV = 0;
|
||||
u8 bfMonCount;
|
||||
const u16 *monSet = NULL;
|
||||
u32 otID = 0;
|
||||
|
||||
if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
// Normal battle frontier trainer.
|
||||
fixedIV = GetFrontierTrainerFixedIvs(trainerId);
|
||||
monSet = gFacilityTrainers[TRAINER_BATTLE_PARAM.opponentA].monSet;
|
||||
}
|
||||
else if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
for (i = firstMonId; i < firstMonId + FRONTIER_PARTY_SIZE; i++)
|
||||
CreateBattleTowerMon(&gEnemyParty[i], &gSaveBlock2Ptr->frontier.ereaderTrainer.party[i - firstMonId]);
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
return;
|
||||
}
|
||||
else if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
{
|
||||
CreateFrontierBrainPokemon();
|
||||
return;
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
// Record mixed player.
|
||||
for (j = 0, i = firstMonId; i < firstMonId + monCount; j++, i++)
|
||||
{
|
||||
if (gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].party[j].species != SPECIES_NONE
|
||||
&& gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].party[j].level <= level)
|
||||
{
|
||||
CreateBattleTowerMon_HandleLevel(&gEnemyParty[i], &gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].party[j], FALSE);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apprentice.
|
||||
for (i = firstMonId; i < firstMonId + FRONTIER_PARTY_SIZE; i++)
|
||||
CreateApprenticeMon(&gEnemyParty[i], &gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE], i - firstMonId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Regular battle frontier trainer.
|
||||
// Attempt to fill the trainer's party with random Pokémon until 3 have been
|
||||
// successfully chosen. The trainer's party may not have duplicate Pokémon species
|
||||
// or duplicate held items.
|
||||
for (bfMonCount = 0; monSet[bfMonCount] != 0xFFFF; bfMonCount++)
|
||||
;
|
||||
i = 0;
|
||||
otID = Random32();
|
||||
while (i != monCount)
|
||||
{
|
||||
u16 monId = monSet[Random() % bfMonCount];
|
||||
|
||||
// "High tier" Pokémon are only allowed on open level mode
|
||||
// 20 is not a possible value for level here
|
||||
if ((level == FRONTIER_MAX_LEVEL_50 || level == 20) && monId > FRONTIER_MONS_HIGH_TIER)
|
||||
continue;
|
||||
|
||||
// Ensure this Pokémon species isn't a duplicate.
|
||||
for (j = 0; j < i + firstMonId; j++)
|
||||
{
|
||||
if (GetMonData(&gEnemyParty[j], MON_DATA_SPECIES, NULL) == gFacilityTrainerMons[monId].species)
|
||||
break;
|
||||
}
|
||||
if (j != i + firstMonId)
|
||||
continue;
|
||||
|
||||
// Ensure this Pokemon's held item isn't a duplicate.
|
||||
for (j = 0; j < i + firstMonId; j++)
|
||||
{
|
||||
if (GetMonData(&gEnemyParty[j], MON_DATA_HELD_ITEM, NULL) != ITEM_NONE
|
||||
&& GetMonData(&gEnemyParty[j], MON_DATA_HELD_ITEM, NULL) == gFacilityTrainerMons[monId].heldItem)
|
||||
break;
|
||||
}
|
||||
if (j != i + firstMonId)
|
||||
continue;
|
||||
|
||||
// Ensure this exact Pokémon index isn't a duplicate. This check doesn't seem necessary
|
||||
// because the species and held items were already checked directly above.
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
if (chosenMonIndices[j] == monId)
|
||||
break;
|
||||
}
|
||||
if (j != i)
|
||||
continue;
|
||||
|
||||
chosenMonIndices[i] = monId;
|
||||
|
||||
// Place the chosen Pokémon into the trainer's party.
|
||||
CreateFacilityMon(&gFacilityTrainerMons[monId], level, fixedIV, otID, 0, &gEnemyParty[i + firstMonId]);
|
||||
|
||||
// The Pokémon was successfully added to the trainer's party, so it's safe to move on to
|
||||
// the next party slot.
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 otID, u32 flags, struct Pokemon *dst)
|
||||
{
|
||||
u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball;
|
||||
u16 move;
|
||||
u32 personality = 0, ability, friendship, j;
|
||||
|
||||
if (fmon->gender == TRAINER_MON_MALE)
|
||||
{
|
||||
personality = GeneratePersonalityForGender(MON_MALE, fmon->species);
|
||||
}
|
||||
else if (fmon->gender == TRAINER_MON_FEMALE)
|
||||
{
|
||||
personality = GeneratePersonalityForGender(MON_FEMALE, fmon->species);
|
||||
}
|
||||
|
||||
ModifyPersonalityForNature(&personality, fmon->nature);
|
||||
CreateMon(dst, fmon->species, level, fixedIV, TRUE, personality, otID, OT_ID_PRESET);
|
||||
|
||||
friendship = MAX_FRIENDSHIP;
|
||||
// Give the chosen Pokémon its specified moves.
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
move = fmon->moves[j];
|
||||
if (flags & FLAG_FRONTIER_MON_FACTORY && move == MOVE_RETURN)
|
||||
move = MOVE_FRUSTRATION;
|
||||
|
||||
SetMonMoveSlot(dst, move, j);
|
||||
if (GetMoveEffect(move) == EFFECT_FRUSTRATION)
|
||||
friendship = 0; // Frustration is more powerful the lower the pokemon's friendship is.
|
||||
}
|
||||
|
||||
SetMonData(dst, MON_DATA_FRIENDSHIP, &friendship);
|
||||
SetMonData(dst, MON_DATA_HELD_ITEM, &fmon->heldItem);
|
||||
|
||||
// try to set ability. Otherwise, random of non-hidden as per vanilla
|
||||
if (fmon->ability != ABILITY_NONE)
|
||||
{
|
||||
const struct SpeciesInfo *speciesInfo = &gSpeciesInfo[fmon->species];
|
||||
u32 maxAbilities = ARRAY_COUNT(speciesInfo->abilities);
|
||||
for (ability = 0; ability < maxAbilities; ++ability)
|
||||
{
|
||||
if (speciesInfo->abilities[ability] == fmon->ability)
|
||||
break;
|
||||
}
|
||||
if (ability >= maxAbilities)
|
||||
ability = 0;
|
||||
SetMonData(dst, MON_DATA_ABILITY_NUM, &ability);
|
||||
}
|
||||
|
||||
if (fmon->ev != NULL)
|
||||
{
|
||||
SetMonData(dst, MON_DATA_HP_EV, &(fmon->ev[0]));
|
||||
SetMonData(dst, MON_DATA_ATK_EV, &(fmon->ev[1]));
|
||||
SetMonData(dst, MON_DATA_DEF_EV, &(fmon->ev[2]));
|
||||
SetMonData(dst, MON_DATA_SPATK_EV, &(fmon->ev[3]));
|
||||
SetMonData(dst, MON_DATA_SPDEF_EV, &(fmon->ev[4]));
|
||||
SetMonData(dst, MON_DATA_SPEED_EV, &(fmon->ev[5]));
|
||||
}
|
||||
|
||||
if (fmon->iv)
|
||||
SetMonData(dst, MON_DATA_IVS, &(fmon->iv));
|
||||
|
||||
if (fmon->isShiny)
|
||||
{
|
||||
u32 data = TRUE;
|
||||
SetMonData(dst, MON_DATA_IS_SHINY, &data);
|
||||
}
|
||||
if (fmon->dynamaxLevel > 0)
|
||||
{
|
||||
u32 data = fmon->dynamaxLevel;
|
||||
SetMonData(dst, MON_DATA_DYNAMAX_LEVEL, &data);
|
||||
}
|
||||
if (fmon->gigantamaxFactor)
|
||||
{
|
||||
u32 data = fmon->gigantamaxFactor;
|
||||
SetMonData(dst, MON_DATA_GIGANTAMAX_FACTOR, &data);
|
||||
}
|
||||
if (fmon->teraType)
|
||||
{
|
||||
u32 data = fmon->teraType;
|
||||
SetMonData(dst, MON_DATA_TERA_TYPE, &data);
|
||||
}
|
||||
|
||||
|
||||
SetMonData(dst, MON_DATA_POKEBALL, &ball);
|
||||
CalculateMonStats(dst);
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dma3.h"
|
||||
#include "event_data.h"
|
||||
#include "evolution_scene.h"
|
||||
#include "frontier_util.h"
|
||||
#include "field_weather.h"
|
||||
#include "follower_npc.h"
|
||||
#include "graphics.h"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "battle_controllers.h"
|
||||
#include "battle_message.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_special.h"
|
||||
#include "battle_z_move.h"
|
||||
#include "data.h"
|
||||
#include "event_data.h"
|
||||
|
|
|
|||
178
src/battle_partner.c
Normal file
178
src/battle_partner.c
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
#include "global.h"
|
||||
#include "main.h"
|
||||
#include "battle.h"
|
||||
#include "battle_partner.h"
|
||||
#include "battle_frontier.h"
|
||||
#include "data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "difficulty.h"
|
||||
#include "string_util.h"
|
||||
#include "text.h"
|
||||
|
||||
#include "constants/abilities.h"
|
||||
#include "constants/battle_ai.h"
|
||||
|
||||
#include "data/partner_parties.h"
|
||||
const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT] =
|
||||
{
|
||||
#include "data/battle_partners.h"
|
||||
};
|
||||
|
||||
#define STEVEN_OTID 61226
|
||||
|
||||
void FillPartnerParty(u16 trainerId)
|
||||
{
|
||||
s32 i, j, k;
|
||||
u32 firstIdPart = 0, secondIdPart = 0, thirdIdPart = 0;
|
||||
u32 ivs, level, personality;
|
||||
u16 monId;
|
||||
u32 otID;
|
||||
u8 trainerName[(PLAYER_NAME_LENGTH * 3) + 1];
|
||||
s32 ball = -1;
|
||||
enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(trainerId);
|
||||
SetFacilityPtrsGetLevel();
|
||||
|
||||
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
{
|
||||
for (i = 0; i < 3; i++)
|
||||
ZeroMonData(&gPlayerParty[i + 3]);
|
||||
|
||||
for (i = 0; i < 3 && i < gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].partySize; i++)
|
||||
{
|
||||
const struct TrainerMon *partyData = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].party;
|
||||
const u8 *partnerName = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName;
|
||||
|
||||
for (k = 0; partnerName[k] != EOS && k < 3; k++)
|
||||
{
|
||||
if (k == 0)
|
||||
{
|
||||
firstIdPart = partnerName[k];
|
||||
secondIdPart = partnerName[k];
|
||||
thirdIdPart = partnerName[k];
|
||||
}
|
||||
else if (k == 1)
|
||||
{
|
||||
secondIdPart = partnerName[k];
|
||||
thirdIdPart = partnerName[k];
|
||||
}
|
||||
else if (k == 2)
|
||||
{
|
||||
thirdIdPart = partnerName[k];
|
||||
}
|
||||
}
|
||||
if (trainerId == TRAINER_PARTNER(PARTNER_STEVEN))
|
||||
otID = STEVEN_OTID;
|
||||
else
|
||||
otID = ((firstIdPart % 72) * 1000) + ((secondIdPart % 23) * 10) + (thirdIdPart % 37) % 65536;
|
||||
|
||||
personality = Random32();
|
||||
if (partyData[i].gender == TRAINER_MON_MALE)
|
||||
personality = (personality & 0xFFFFFF00) | GeneratePersonalityForGender(MON_MALE, partyData[i].species);
|
||||
else if (partyData[i].gender == TRAINER_MON_FEMALE)
|
||||
personality = (personality & 0xFFFFFF00) | GeneratePersonalityForGender(MON_FEMALE, partyData[i].species);
|
||||
ModifyPersonalityForNature(&personality, partyData[i].nature);
|
||||
CreateMon(&gPlayerParty[i + 3], partyData[i].species, partyData[i].lvl, 0, TRUE, personality, OT_ID_PRESET, otID);
|
||||
j = partyData[i].isShiny;
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_IS_SHINY, &j);
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
|
||||
CustomTrainerPartyAssignMoves(&gPlayerParty[i + 3], &partyData[i]);
|
||||
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_IVS, &(partyData[i].iv));
|
||||
if (partyData[i].ev != NULL)
|
||||
{
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_HP_EV, &(partyData[i].ev[0]));
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_ATK_EV, &(partyData[i].ev[1]));
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_DEF_EV, &(partyData[i].ev[2]));
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_SPATK_EV, &(partyData[i].ev[3]));
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_SPDEF_EV, &(partyData[i].ev[4]));
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_SPEED_EV, &(partyData[i].ev[5]));
|
||||
}
|
||||
if (partyData[i].ability != ABILITY_NONE)
|
||||
{
|
||||
const struct SpeciesInfo *speciesInfo = &gSpeciesInfo[partyData[i].species];
|
||||
u32 maxAbilities = ARRAY_COUNT(speciesInfo->abilities);
|
||||
for (j = 0; j < maxAbilities; j++)
|
||||
{
|
||||
if (speciesInfo->abilities[j] == partyData[i].ability)
|
||||
break;
|
||||
}
|
||||
if (j < maxAbilities)
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_ABILITY_NUM, &j);
|
||||
}
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_FRIENDSHIP, &(partyData[i].friendship));
|
||||
if (partyData[i].ball != ITEM_NONE)
|
||||
{
|
||||
ball = partyData[i].ball;
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_POKEBALL, &ball);
|
||||
}
|
||||
if (partyData[i].nickname != NULL)
|
||||
{
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_NICKNAME, partyData[i].nickname);
|
||||
}
|
||||
CalculateMonStats(&gPlayerParty[i + 3]);
|
||||
|
||||
StringCopy(trainerName, gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName);
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_NAME, trainerName);
|
||||
j = gBattlePartners[difficulty][SanitizeTrainerId(trainerId - TRAINER_PARTNER(PARTNER_NONE))].encounterMusic_gender >> 7;
|
||||
SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_GENDER, &j);
|
||||
}
|
||||
}
|
||||
else if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
// Scrapped, lol.
|
||||
trainerName[0] = gGameLanguage;
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
level = SetFacilityPtrsGetLevel();
|
||||
ivs = GetFrontierTrainerFixedIvs(trainerId);
|
||||
otID = Random32();
|
||||
for (i = 0; i < FRONTIER_MULTI_PARTY_SIZE; i++)
|
||||
{
|
||||
monId = gSaveBlock2Ptr->frontier.trainerIds[i + 18];
|
||||
CreateFacilityMon(&gFacilityTrainerMons[monId], level, ivs, otID, 0, &gPlayerParty[MULTI_PARTY_SIZE + i]);
|
||||
for (j = 0; j < PLAYER_NAME_LENGTH + 1; j++)
|
||||
trainerName[j] = gFacilityTrainers[trainerId].trainerName[j];
|
||||
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_NAME, &trainerName);
|
||||
j = IsFrontierTrainerFemale(trainerId);
|
||||
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_GENDER, &j);
|
||||
}
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
trainerId -= TRAINER_RECORD_MIXING_FRIEND;
|
||||
for (i = 0; i < FRONTIER_MULTI_PARTY_SIZE; i++)
|
||||
{
|
||||
struct EmeraldBattleTowerRecord *record = &gSaveBlock2Ptr->frontier.towerRecords[trainerId];
|
||||
struct BattleTowerPokemon monData = record->party[gSaveBlock2Ptr->frontier.trainerIds[18 + i]];
|
||||
StringCopy(trainerName, record->name);
|
||||
if (record->language == LANGUAGE_JAPANESE)
|
||||
{
|
||||
if (monData.nickname[0] != EXT_CTRL_CODE_BEGIN || monData.nickname[1] != EXT_CTRL_CODE_JPN)
|
||||
{
|
||||
monData.nickname[5] = EOS;
|
||||
ConvertInternationalString(monData.nickname, LANGUAGE_JAPANESE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (monData.nickname[0] == EXT_CTRL_CODE_BEGIN && monData.nickname[1] == EXT_CTRL_CODE_JPN)
|
||||
trainerName[5] = EOS;
|
||||
}
|
||||
CreateBattleTowerMon_HandleLevel(&gPlayerParty[MULTI_PARTY_SIZE + i], &monData, TRUE);
|
||||
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_NAME, trainerName);
|
||||
j = IsFrontierTrainerFemale(trainerId + TRAINER_RECORD_MIXING_FRIEND);
|
||||
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_GENDER, &j);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trainerId -= TRAINER_RECORD_MIXING_APPRENTICE;
|
||||
for (i = 0; i < FRONTIER_MULTI_PARTY_SIZE; i++)
|
||||
{
|
||||
CreateApprenticeMon(&gPlayerParty[MULTI_PARTY_SIZE + i], &gSaveBlock2Ptr->apprentices[trainerId], gSaveBlock2Ptr->frontier.trainerIds[18 + i]);
|
||||
j = IsFrontierTrainerFemale(trainerId + TRAINER_RECORD_MIXING_APPRENTICE);
|
||||
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_GENDER, &j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include "field_weather.h"
|
||||
#include "battle_tower.h"
|
||||
#include "gym_leader_rematch.h"
|
||||
#include "battle_frontier.h"
|
||||
#include "battle_pike.h"
|
||||
#include "battle_pyramid.h"
|
||||
#include "fldeff.h"
|
||||
|
|
@ -42,6 +43,7 @@
|
|||
#include "data.h"
|
||||
#include "vs_seeker.h"
|
||||
#include "item.h"
|
||||
#include "script.h"
|
||||
#include "field_name_box.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/battle_setup.h"
|
||||
|
|
@ -958,7 +960,7 @@ void ResetTrainerOpponentIds(void)
|
|||
TRAINER_BATTLE_PARAM.opponentB = 0;
|
||||
}
|
||||
|
||||
static void InitTrainerBattleVariables(void)
|
||||
void InitTrainerBattleParameter(void)
|
||||
{
|
||||
memset(gTrainerBattleParameter.data, 0, sizeof(TrainerBattleParameter));
|
||||
sTrainerBattleEndScript = NULL;
|
||||
|
|
@ -966,7 +968,7 @@ static void InitTrainerBattleVariables(void)
|
|||
|
||||
void TrainerBattleLoadArgs(const u8 *data)
|
||||
{
|
||||
InitTrainerBattleVariables();
|
||||
InitTrainerBattleParameter();
|
||||
memcpy(gTrainerBattleParameter.data, data, sizeof(TrainerBattleParameter));
|
||||
sTrainerBattleEndScript = (u8*)data + sizeof(TrainerBattleParameter);
|
||||
}
|
||||
|
|
@ -1059,30 +1061,6 @@ const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data)
|
|||
TRAINER_BATTLE_PARAM.opponentA = GetRematchTrainerId(TRAINER_BATTLE_PARAM.opponentA);
|
||||
return EventScript_TryDoRematchBattle;
|
||||
#endif //FREE_MATCH_CALL
|
||||
case TRAINER_BATTLE_PYRAMID:
|
||||
if (gApproachingTrainerId == 0)
|
||||
{
|
||||
SetMapVarsToTrainerA();
|
||||
TRAINER_BATTLE_PARAM.opponentA = LocalIdToPyramidTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRAINER_BATTLE_PARAM.opponentB = LocalIdToPyramidTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
return EventScript_TryDoNormalTrainerBattle;
|
||||
case TRAINER_BATTLE_SET_TRAINERS_FOR_MULTI_BATTLE:
|
||||
return sTrainerBattleEndScript;
|
||||
case TRAINER_BATTLE_HILL:
|
||||
if (gApproachingTrainerId == 0)
|
||||
{
|
||||
SetMapVarsToTrainerA();
|
||||
TRAINER_BATTLE_PARAM.opponentA = LocalIdToHillTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRAINER_BATTLE_PARAM.opponentB = LocalIdToHillTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
return EventScript_TryDoNormalTrainerBattle;
|
||||
case TRAINER_BATTLE_TWO_TRAINERS_NO_INTRO:
|
||||
gNoOfApproachingTrainers = 2; // set TWO_OPPONENTS gBattleTypeFlags
|
||||
gApproachingTrainerId = 1; // prevent trainer approach
|
||||
|
|
@ -1096,6 +1074,39 @@ const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data)
|
|||
}
|
||||
}
|
||||
|
||||
const u8* BattleSetup_ConfigureFacilityTrainerBattle(u8 facility, const u8* scriptEndPtr)
|
||||
{
|
||||
sTrainerBattleEndScript = (u8*)scriptEndPtr;
|
||||
|
||||
switch (facility)
|
||||
{
|
||||
case FACILITY_BATTLE_PYRAMID:
|
||||
if (gApproachingTrainerId == 0)
|
||||
{
|
||||
SetMapVarsToTrainerA();
|
||||
TRAINER_BATTLE_PARAM.opponentA = LocalIdToPyramidTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRAINER_BATTLE_PARAM.opponentB = LocalIdToPyramidTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
return EventScript_TryDoNormalTrainerBattle;
|
||||
case FACILITY_BATTLE_TRAINER_HILL:
|
||||
if (gApproachingTrainerId == 0)
|
||||
{
|
||||
SetMapVarsToTrainerA();
|
||||
TRAINER_BATTLE_PARAM.opponentA = LocalIdToHillTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRAINER_BATTLE_PARAM.opponentB = LocalIdToHillTrainerId(gSpecialVar_LastTalked);
|
||||
}
|
||||
return EventScript_TryDoNormalTrainerBattle;
|
||||
default:
|
||||
return sTrainerBattleEndScript;
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureAndSetUpOneTrainerBattle(u8 trainerObjEventId, const u8 *trainerScript)
|
||||
{
|
||||
gSelectedObjectEvent = trainerObjEventId;
|
||||
|
|
@ -1960,3 +1971,15 @@ u16 CountBattledRematchTeams(u16 trainerId)
|
|||
|
||||
return i;
|
||||
}
|
||||
|
||||
void SetMultiTrainerBattle(struct ScriptContext *ctx)
|
||||
{
|
||||
InitTrainerBattleParameter();
|
||||
|
||||
TRAINER_BATTLE_PARAM.opponentA = ScriptReadHalfword(ctx);
|
||||
TRAINER_BATTLE_PARAM.defeatTextA = (u8*)ScriptReadWord(ctx);
|
||||
TRAINER_BATTLE_PARAM.opponentB = ScriptReadHalfword(ctx);
|
||||
TRAINER_BATTLE_PARAM.defeatTextB = (u8*)ScriptReadWord(ctx);
|
||||
gPartnerTrainerId = TRAINER_PARTNER(ScriptReadHalfword(ctx));
|
||||
};
|
||||
|
||||
|
|
|
|||
277
src/battle_special.c
Normal file
277
src/battle_special.c
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
#include "global.h"
|
||||
#include "main.h"
|
||||
#include "battle_special.h"
|
||||
#include "battle.h"
|
||||
#include "battle_frontier.h"
|
||||
#include "battle_partner.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_transition.h"
|
||||
#include "event_data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "new_game.h"
|
||||
#include "overworld.h"
|
||||
#include "recorded_battle.h"
|
||||
#include "string_util.h"
|
||||
#include "task.h"
|
||||
#include "text.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/battle_special.h"
|
||||
|
||||
static void HandleSpecialTrainerBattleEnd(void);
|
||||
static void Task_StartBattleAfterTransition(u8 taskId);
|
||||
static void UNUSED FillEReaderTrainerWithPlayerData(void);
|
||||
static void CopyEReaderTrainerFarewellMessage(void);
|
||||
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
static void SetEReaderTrainerChecksum(struct BattleTowerEReaderTrainer *ereaderTrainer);
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
|
||||
static void HandleSpecialTrainerBattleEnd(void)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
RecordedBattle_SaveBattleOutcome();
|
||||
switch (gBattleScripting.specialTrainerBattleType)
|
||||
{
|
||||
case SPECIAL_BATTLE_SECRET_BASE:
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
u16 itemBefore = GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_HELD_ITEM);
|
||||
SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &itemBefore);
|
||||
}
|
||||
break;
|
||||
case SPECIAL_BATTLE_EREADER:
|
||||
CopyEReaderTrainerFarewellMessage();
|
||||
break;
|
||||
case SPECIAL_BATTLE_MULTI:
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES))
|
||||
gSaveBlock1Ptr->playerParty[i] = gPlayerParty[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
||||
}
|
||||
|
||||
static void Task_StartBattleAfterTransition(u8 taskId)
|
||||
{
|
||||
if (IsBattleTransitionDone() == TRUE)
|
||||
{
|
||||
gMain.savedCallback = HandleSpecialTrainerBattleEnd;
|
||||
SetMainCallback2(CB2_InitBattle);
|
||||
DestroyTask(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
void DoSpecialTrainerBattle(void)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
gBattleScripting.specialTrainerBattleType = gSpecialVar_0x8004;
|
||||
switch (gSpecialVar_0x8004)
|
||||
{
|
||||
case SPECIAL_BATTLE_SECRET_BASE:
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
u16 itemBefore = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
||||
SetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_HELD_ITEM, &itemBefore);
|
||||
}
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_SECRET_BASE));
|
||||
break;
|
||||
case SPECIAL_BATTLE_EREADER:
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
ZeroEnemyPartyMons();
|
||||
for (i = 0; i < (int)ARRAY_COUNT(gSaveBlock2Ptr->frontier.ereaderTrainer.party); i++)
|
||||
CreateBattleTowerMon(&gEnemyParty[i], &gSaveBlock2Ptr->frontier.ereaderTrainer.party[i]);
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_EREADER_TRAINER;
|
||||
TRAINER_BATTLE_PARAM.opponentA = 0;
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_E_READER));
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
break;
|
||||
case SPECIAL_BATTLE_MULTI:
|
||||
if (gSpecialVar_0x8005 & MULTI_BATTLE_2_VS_WILD) // Player + AI against wild mon
|
||||
{
|
||||
gBattleTypeFlags = BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER;
|
||||
}
|
||||
else if (gSpecialVar_0x8005 & MULTI_BATTLE_2_VS_1) // Player + AI against one trainer
|
||||
{
|
||||
TRAINER_BATTLE_PARAM.opponentB = 0xFFFF;
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER;
|
||||
}
|
||||
else // MULTI_BATTLE_2_VS_2
|
||||
{
|
||||
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER;
|
||||
}
|
||||
|
||||
FillPartnerParty(gPartnerTrainerId);
|
||||
CreateTask(Task_StartBattleAfterTransition, 1);
|
||||
PlayMapChosenOrBattleBGM(0);
|
||||
if (gSpecialVar_0x8005 & MULTI_BATTLE_2_VS_WILD)
|
||||
BattleTransition_StartOnField(GetWildBattleTransition());
|
||||
else
|
||||
BattleTransition_StartOnField(GetTrainerBattleTransition());
|
||||
|
||||
if (gSpecialVar_0x8005 & MULTI_BATTLE_CHOOSE_MONS) // Skip mons restoring(done in the script)
|
||||
gBattleScripting.specialTrainerBattleType = 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetEReaderTrainerGfxId(void)
|
||||
{
|
||||
SetBattleFacilityTrainerGfxId(TRAINER_EREADER, 0);
|
||||
}
|
||||
|
||||
// This is a leftover debugging function that is used to populate the E-Reader
|
||||
// trainer with the player's current data.
|
||||
static void UNUSED FillEReaderTrainerWithPlayerData(void)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
struct BattleTowerEReaderTrainer *ereaderTrainer = &gSaveBlock2Ptr->frontier.ereaderTrainer;
|
||||
s32 i, j;
|
||||
|
||||
if (gSaveBlock2Ptr->playerGender != MALE)
|
||||
{
|
||||
ereaderTrainer->facilityClass = gTowerFemaleFacilityClasses[(gSaveBlock2Ptr->playerTrainerId[0] + gSaveBlock2Ptr->playerTrainerId[1]
|
||||
+ gSaveBlock2Ptr->playerTrainerId[2] + gSaveBlock2Ptr->playerTrainerId[3]) % ARRAY_COUNT(gTowerFemaleFacilityClasses)];
|
||||
}
|
||||
else
|
||||
{
|
||||
ereaderTrainer->facilityClass = gTowerMaleFacilityClasses[(gSaveBlock2Ptr->playerTrainerId[0] + gSaveBlock2Ptr->playerTrainerId[1]
|
||||
+ gSaveBlock2Ptr->playerTrainerId[2] + gSaveBlock2Ptr->playerTrainerId[3]) % ARRAY_COUNT(gTowerMaleFacilityClasses)];
|
||||
}
|
||||
|
||||
CopyTrainerId(ereaderTrainer->trainerId, gSaveBlock2Ptr->playerTrainerId);
|
||||
StringCopy_PlayerName(ereaderTrainer->name, gSaveBlock2Ptr->playerName);
|
||||
|
||||
ereaderTrainer->winStreak = 1;
|
||||
|
||||
j = 7;
|
||||
for (i = 0; i < EASY_CHAT_BATTLE_WORDS_COUNT; i++)
|
||||
{
|
||||
ereaderTrainer->greeting[i] = gSaveBlock1Ptr->easyChatBattleStart[i];
|
||||
ereaderTrainer->farewellPlayerLost[i] = j;
|
||||
ereaderTrainer->farewellPlayerWon[i] = j + 6;
|
||||
j++;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)ARRAY_COUNT(ereaderTrainer->party); i++)
|
||||
ConvertPokemonToBattleTowerPokemon(&gPlayerParty[i], &ereaderTrainer->party[i]);
|
||||
|
||||
SetEReaderTrainerChecksum(ereaderTrainer);
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
|
||||
u8 GetEreaderTrainerFrontSpriteId(void)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
return gFacilityClassToPicIndex[gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass];
|
||||
#else
|
||||
return 0;
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
|
||||
enum TrainerClassID GetEreaderTrainerClassId(void)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
return gFacilityClassToTrainerClass[gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass];
|
||||
#else
|
||||
return 0;
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
|
||||
void GetEreaderTrainerName(u8 *dst)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
dst[i] = gSaveBlock2Ptr->frontier.ereaderTrainer.name[i];
|
||||
|
||||
dst[i] = EOS;
|
||||
#else
|
||||
dst[0] = EOS;
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
|
||||
// Checks if the saved E-Reader trainer is valid.
|
||||
void ValidateEReaderTrainer(void)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
u32 i;
|
||||
u32 checksum;
|
||||
struct BattleTowerEReaderTrainer *ereaderTrainer;
|
||||
|
||||
gSpecialVar_Result = FALSE;
|
||||
ereaderTrainer = &gSaveBlock2Ptr->frontier.ereaderTrainer;
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; i < (sizeof(struct BattleTowerEReaderTrainer) - 4) / 4; i++) // - 4, because of the last field being the checksum itself.
|
||||
checksum |= ((u32 *)ereaderTrainer)[i];
|
||||
|
||||
if (checksum == 0)
|
||||
{
|
||||
gSpecialVar_Result = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; i < (sizeof(struct BattleTowerEReaderTrainer) - 4) / 4; i++) // - 4, because of the last field being the checksum itself.
|
||||
checksum += ((u32 *)ereaderTrainer)[i];
|
||||
|
||||
if (gSaveBlock2Ptr->frontier.ereaderTrainer.checksum != checksum)
|
||||
{
|
||||
ClearEReaderTrainer(&gSaveBlock2Ptr->frontier.ereaderTrainer);
|
||||
gSpecialVar_Result = TRUE;
|
||||
}
|
||||
#else
|
||||
gSpecialVar_Result = FALSE;
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
static void SetEReaderTrainerChecksum(struct BattleTowerEReaderTrainer *ereaderTrainer)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
ereaderTrainer->checksum = 0;
|
||||
for (i = 0; i < (sizeof(struct BattleTowerEReaderTrainer) - 4) / 4; i++) // - 4, because of the last field being the checksum itself.
|
||||
ereaderTrainer->checksum += ((u32 *)ereaderTrainer)[i];
|
||||
}
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
|
||||
void ClearEReaderTrainer(struct BattleTowerEReaderTrainer *ereaderTrainer)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < (sizeof(struct BattleTowerEReaderTrainer)) / 4; i++)
|
||||
((u32 *)ereaderTrainer)[i] = 0;
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
|
||||
void CopyEReaderTrainerGreeting(void)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
FrontierSpeechToString(gSaveBlock2Ptr->frontier.ereaderTrainer.greeting);
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
|
||||
static void CopyEReaderTrainerFarewellMessage(void)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
if (gBattleOutcome == B_OUTCOME_DREW)
|
||||
gStringVar4[0] = EOS;
|
||||
else if (gBattleOutcome == B_OUTCOME_WON)
|
||||
FrontierSpeechToString(gSaveBlock2Ptr->frontier.ereaderTrainer.farewellPlayerWon);
|
||||
else
|
||||
FrontierSpeechToString(gSaveBlock2Ptr->frontier.ereaderTrainer.farewellPlayerLost);
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
1456
src/battle_tower.c
1456
src/battle_tower.c
File diff suppressed because it is too large
Load Diff
|
|
@ -2,7 +2,7 @@
|
|||
#include "debug.h"
|
||||
#include "malloc.h"
|
||||
#include "battle.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_special.h"
|
||||
#include "cable_club.h"
|
||||
#include "data.h"
|
||||
#include "decoration.h"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "follower_npc.h"
|
||||
#include "follower_npc_alternate_sprites.h"
|
||||
#include "battle.h"
|
||||
#include "battle_partner.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_tower.h"
|
||||
#include "bike.h"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
#include "global.h"
|
||||
#include "frontier_util.h"
|
||||
#include "easy_chat.h"
|
||||
#include "event_data.h"
|
||||
#include "battle_setup.h"
|
||||
#include "overworld.h"
|
||||
#include "random.h"
|
||||
#include "battle_frontier.h"
|
||||
#include "battle_special.h"
|
||||
#include "battle_tower.h"
|
||||
#include "field_specials.h"
|
||||
#include "battle.h"
|
||||
|
|
@ -29,6 +32,7 @@
|
|||
#include "load_save.h"
|
||||
#include "battle_dome.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/battle_frontier_mons.h"
|
||||
#include "constants/battle_move_effects.h"
|
||||
#include "constants/battle_pike.h"
|
||||
#include "constants/frontier_util.h"
|
||||
|
|
@ -788,6 +792,31 @@ static const u8 *const sHallFacilityToRecordsText[] =
|
|||
[RANKING_HALL_TOWER_LINK] = gText_FrontierFacilityWinStreak,
|
||||
};
|
||||
|
||||
// Trainer ID ranges for possible frontier trainers to encounter on particular challenges
|
||||
// Trainers are scaled by difficulty, so higher trainer IDs have better teams
|
||||
static const u16 sFrontierTrainerIdRanges[][2] =
|
||||
{
|
||||
{FRONTIER_TRAINER_BRADY, FRONTIER_TRAINER_JILL}, // 0 - 99
|
||||
{FRONTIER_TRAINER_TREVIN, FRONTIER_TRAINER_CHLOE}, // 80 - 119
|
||||
{FRONTIER_TRAINER_ERIK, FRONTIER_TRAINER_SOFIA}, // 100 - 139
|
||||
{FRONTIER_TRAINER_NORTON, FRONTIER_TRAINER_JAZLYN}, // 120 - 159
|
||||
{FRONTIER_TRAINER_BRADEN, FRONTIER_TRAINER_ALISON}, // 140 - 179
|
||||
{FRONTIER_TRAINER_ZACHERY, FRONTIER_TRAINER_LAMAR}, // 160 - 199
|
||||
{FRONTIER_TRAINER_HANK, FRONTIER_TRAINER_TESS}, // 180 - 219
|
||||
{FRONTIER_TRAINER_JAXON, FRONTIER_TRAINER_GRETEL}, // 200 - 299
|
||||
};
|
||||
|
||||
static const u16 sFrontierTrainerIdRangesHard[][2] =
|
||||
{
|
||||
{FRONTIER_TRAINER_ERIK, FRONTIER_TRAINER_CHLOE}, // 100 - 119
|
||||
{FRONTIER_TRAINER_NORTON, FRONTIER_TRAINER_SOFIA}, // 120 - 139
|
||||
{FRONTIER_TRAINER_BRADEN, FRONTIER_TRAINER_JAZLYN}, // 140 - 159
|
||||
{FRONTIER_TRAINER_ZACHERY, FRONTIER_TRAINER_ALISON}, // 160 - 179
|
||||
{FRONTIER_TRAINER_HANK, FRONTIER_TRAINER_LAMAR}, // 180 - 199
|
||||
{FRONTIER_TRAINER_JAXON, FRONTIER_TRAINER_TESS}, // 200 - 219
|
||||
{FRONTIER_TRAINER_LEON, FRONTIER_TRAINER_RAUL}, // 220 - 239
|
||||
{FRONTIER_TRAINER_JAXON, FRONTIER_TRAINER_GRETEL}, // 200 - 299
|
||||
};
|
||||
|
||||
#define BANNED_SPECIES_SHOWN 6
|
||||
|
||||
|
|
@ -2715,6 +2744,602 @@ void ClearEnemyPartyAfterChallenge()
|
|||
}
|
||||
}
|
||||
|
||||
bool8 IsFrontierTrainerFemale(u16 trainerId)
|
||||
{
|
||||
u32 i;
|
||||
u8 facilityClass;
|
||||
|
||||
SetFacilityPtrsGetLevel();
|
||||
if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
facilityClass = gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass;
|
||||
#else
|
||||
facilityClass = 0;
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
else if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
{
|
||||
return IsFrontierBrainFemale();
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
facilityClass = gFacilityTrainers[trainerId].facilityClass;
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
facilityClass = gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].facilityClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
facilityClass = gApprentices[gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE].id].facilityClass;
|
||||
}
|
||||
|
||||
// Search female classes.
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerFemaleFacilityClasses); i++)
|
||||
{
|
||||
if (gTowerFemaleFacilityClasses[i] == facilityClass)
|
||||
break;
|
||||
}
|
||||
if (i != ARRAY_COUNT(gTowerFemaleFacilityClasses))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Frontier Trainer parties are roughly scaled in difficulty with higher trainer IDs, so scale IVs as well
|
||||
// Duplicated in Battle Dome as GetDomeTrainerMonIvs
|
||||
u8 GetFrontierTrainerFixedIvs(u16 trainerId)
|
||||
{
|
||||
u8 fixedIv;
|
||||
|
||||
if (trainerId <= FRONTIER_TRAINER_JILL) // 0 - 99
|
||||
fixedIv = 3;
|
||||
else if (trainerId <= FRONTIER_TRAINER_CHLOE) // 100 - 119
|
||||
fixedIv = 6;
|
||||
else if (trainerId <= FRONTIER_TRAINER_SOFIA) // 120 - 139
|
||||
fixedIv = 9;
|
||||
else if (trainerId <= FRONTIER_TRAINER_JAZLYN) // 140 - 159
|
||||
fixedIv = 12;
|
||||
else if (trainerId <= FRONTIER_TRAINER_ALISON) // 160 - 179
|
||||
fixedIv = 15;
|
||||
else if (trainerId <= FRONTIER_TRAINER_LAMAR) // 180 - 199
|
||||
fixedIv = 18;
|
||||
else if (trainerId <= FRONTIER_TRAINER_TESS) // 200 - 219
|
||||
fixedIv = 21;
|
||||
else // 220+ (- 299)
|
||||
fixedIv = MAX_PER_STAT_IVS;
|
||||
|
||||
return fixedIv;
|
||||
}
|
||||
|
||||
|
||||
u16 GetRandomScaledFrontierTrainerId(u8 challengeNum, u8 battleNum)
|
||||
{
|
||||
u16 trainerId;
|
||||
|
||||
if (challengeNum <= 7)
|
||||
{
|
||||
if (battleNum == FRONTIER_STAGES_PER_CHALLENGE - 1)
|
||||
{
|
||||
// The last battle in each challenge has a jump in difficulty, pulls from a table with higher ranges
|
||||
trainerId = (sFrontierTrainerIdRangesHard[challengeNum][1] - sFrontierTrainerIdRangesHard[challengeNum][0]) + 1;
|
||||
trainerId = sFrontierTrainerIdRangesHard[challengeNum][0] + (Random() % trainerId);
|
||||
}
|
||||
else
|
||||
{
|
||||
trainerId = (sFrontierTrainerIdRanges[challengeNum][1] - sFrontierTrainerIdRanges[challengeNum][0]) + 1;
|
||||
trainerId = sFrontierTrainerIdRanges[challengeNum][0] + (Random() % trainerId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// After challenge 7, trainer IDs always come from the last, hardest range, which is the same for both trainer ID tables
|
||||
trainerId = (sFrontierTrainerIdRanges[7][1] - sFrontierTrainerIdRanges[7][0]) + 1;
|
||||
trainerId = sFrontierTrainerIdRanges[7][0] + (Random() % trainerId);
|
||||
}
|
||||
|
||||
return trainerId;
|
||||
}
|
||||
|
||||
static void UNUSED GetRandomScaledFrontierTrainerIdRange(u8 challengeNum, u8 battleNum, u16 *trainerIdPtr, u8 *rangePtr)
|
||||
{
|
||||
u16 trainerId, range;
|
||||
|
||||
if (challengeNum <= 7)
|
||||
{
|
||||
if (battleNum == FRONTIER_STAGES_PER_CHALLENGE - 1)
|
||||
{
|
||||
// The last battle in each challenge has a jump in difficulty, pulls from a table with higher ranges
|
||||
range = (sFrontierTrainerIdRangesHard[challengeNum][1] - sFrontierTrainerIdRangesHard[challengeNum][0]) + 1;
|
||||
trainerId = sFrontierTrainerIdRangesHard[challengeNum][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
range = (sFrontierTrainerIdRanges[challengeNum][1] - sFrontierTrainerIdRanges[challengeNum][0]) + 1;
|
||||
trainerId = sFrontierTrainerIdRanges[challengeNum][0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// After challenge 7, trainer IDs always come from the last, hardest range, which is the same for both trainer ID tables
|
||||
range = (sFrontierTrainerIdRanges[7][1] - sFrontierTrainerIdRanges[7][0]) + 1;
|
||||
trainerId = sFrontierTrainerIdRanges[7][0];
|
||||
}
|
||||
|
||||
*trainerIdPtr = trainerId;
|
||||
*rangePtr = range;
|
||||
}
|
||||
|
||||
void SetBattleFacilityTrainerGfxId(u16 trainerId, u8 tempVarId)
|
||||
{
|
||||
u32 i;
|
||||
u8 facilityClass;
|
||||
u8 trainerObjectGfxId;
|
||||
|
||||
SetFacilityPtrsGetLevel();
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
facilityClass = gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass;
|
||||
}
|
||||
else if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
#else
|
||||
if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
{
|
||||
SetFrontierBrainObjEventGfx_2();
|
||||
return;
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
facilityClass = gFacilityTrainers[trainerId].facilityClass;
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
facilityClass = gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].facilityClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
facilityClass = gApprentices[gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE].id].facilityClass;
|
||||
}
|
||||
|
||||
// Search male classes.
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerMaleFacilityClasses); i++)
|
||||
{
|
||||
if (gTowerMaleFacilityClasses[i] == facilityClass)
|
||||
break;
|
||||
}
|
||||
if (i != ARRAY_COUNT(gTowerMaleFacilityClasses))
|
||||
{
|
||||
trainerObjectGfxId = gTowerMaleTrainerGfxIds[i];
|
||||
switch (tempVarId)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
VarSet(VAR_OBJ_GFX_ID_0, trainerObjectGfxId);
|
||||
return;
|
||||
case 1:
|
||||
VarSet(VAR_OBJ_GFX_ID_1, trainerObjectGfxId);
|
||||
return;
|
||||
case 15:
|
||||
VarSet(VAR_OBJ_GFX_ID_E, trainerObjectGfxId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Search female classes.
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerFemaleFacilityClasses); i++)
|
||||
{
|
||||
if (gTowerFemaleFacilityClasses[i] == facilityClass)
|
||||
break;
|
||||
}
|
||||
if (i != ARRAY_COUNT(gTowerFemaleFacilityClasses))
|
||||
{
|
||||
trainerObjectGfxId = gTowerFemaleTrainerGfxIds[i];
|
||||
switch (tempVarId)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
VarSet(VAR_OBJ_GFX_ID_0, trainerObjectGfxId);
|
||||
return;
|
||||
case 1:
|
||||
VarSet(VAR_OBJ_GFX_ID_1, trainerObjectGfxId);
|
||||
return;
|
||||
case 15:
|
||||
VarSet(VAR_OBJ_GFX_ID_E, trainerObjectGfxId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (tempVarId)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
VarSet(VAR_OBJ_GFX_ID_0, OBJ_EVENT_GFX_BOY_1);
|
||||
return;
|
||||
case 1:
|
||||
VarSet(VAR_OBJ_GFX_ID_1, OBJ_EVENT_GFX_BOY_1);
|
||||
return;
|
||||
case 15:
|
||||
VarSet(VAR_OBJ_GFX_ID_E, OBJ_EVENT_GFX_BOY_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
u16 GetBattleFacilityTrainerGfxId(u16 trainerId)
|
||||
{
|
||||
u32 i;
|
||||
u8 facilityClass;
|
||||
u16 trainerObjectGfxId;
|
||||
|
||||
SetFacilityPtrsGetLevel();
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
facilityClass = gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass;
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
#else
|
||||
if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
{
|
||||
facilityClass = gFacilityTrainers[trainerId].facilityClass;
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
facilityClass = gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].facilityClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
facilityClass = gApprentices[gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE].id].facilityClass;
|
||||
}
|
||||
|
||||
// Search male classes.
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerMaleFacilityClasses); i++)
|
||||
{
|
||||
if (gTowerMaleFacilityClasses[i] == facilityClass)
|
||||
break;
|
||||
}
|
||||
if (i != ARRAY_COUNT(gTowerMaleFacilityClasses))
|
||||
{
|
||||
trainerObjectGfxId = gTowerMaleTrainerGfxIds[i];
|
||||
return trainerObjectGfxId;
|
||||
}
|
||||
|
||||
// Search female classes.
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerFemaleFacilityClasses); i++)
|
||||
{
|
||||
if (gTowerFemaleFacilityClasses[i] == facilityClass)
|
||||
break;
|
||||
}
|
||||
if (i != ARRAY_COUNT(gTowerFemaleFacilityClasses))
|
||||
{
|
||||
trainerObjectGfxId = gTowerFemaleTrainerGfxIds[i];
|
||||
return trainerObjectGfxId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OBJ_EVENT_GFX_BOY_1;
|
||||
}
|
||||
}
|
||||
|
||||
u8 GetFrontierTrainerFrontSpriteId(u16 trainerId)
|
||||
{
|
||||
SetFacilityPtrsGetLevel();
|
||||
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
return gFacilityClassToPicIndex[gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass];
|
||||
}
|
||||
else if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
#else
|
||||
if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
{
|
||||
return GetFrontierBrainTrainerPicIndex();
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
return gFacilityClassToPicIndex[gFacilityTrainers[trainerId].facilityClass];
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
return gFacilityClassToPicIndex[GetRecordedBattleRecordMixFriendClass()];
|
||||
else
|
||||
return gFacilityClassToPicIndex[gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].facilityClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
return gFacilityClassToPicIndex[gApprentices[GetRecordedBattleApprenticeId()].facilityClass];
|
||||
else
|
||||
return gFacilityClassToPicIndex[gApprentices[gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE].id].facilityClass];
|
||||
}
|
||||
}
|
||||
|
||||
enum TrainerClassID GetFrontierOpponentClass(u16 trainerId)
|
||||
{
|
||||
u8 trainerClass = 0;
|
||||
enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(trainerId);
|
||||
SetFacilityPtrsGetLevel();
|
||||
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
trainerClass = gFacilityClassToTrainerClass[gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass];
|
||||
}
|
||||
else if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
#else
|
||||
if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
{
|
||||
return GetFrontierBrainTrainerClass();
|
||||
}
|
||||
else if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
{
|
||||
trainerClass = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass;
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
trainerClass = gFacilityClassToTrainerClass[gFacilityTrainers[trainerId].facilityClass];
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
{
|
||||
trainerClass = gFacilityClassToTrainerClass[GetRecordedBattleRecordMixFriendClass()];
|
||||
}
|
||||
else
|
||||
{
|
||||
trainerClass = gFacilityClassToTrainerClass[gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].facilityClass];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
{
|
||||
trainerClass = gFacilityClassToTrainerClass[gApprentices[GetRecordedBattleApprenticeId()].facilityClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
trainerClass = gFacilityClassToTrainerClass[gApprentices[gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE].id].facilityClass];
|
||||
}
|
||||
}
|
||||
|
||||
return trainerClass;
|
||||
}
|
||||
|
||||
u8 GetFrontierTrainerFacilityClass(u16 trainerId)
|
||||
{
|
||||
u8 facilityClass;
|
||||
SetFacilityPtrsGetLevel();
|
||||
|
||||
if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
facilityClass = gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass;
|
||||
#else
|
||||
facilityClass = 0;
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
facilityClass = gFacilityTrainers[trainerId].facilityClass;
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
facilityClass = GetRecordedBattleRecordMixFriendClass();
|
||||
else
|
||||
facilityClass = gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND].facilityClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
facilityClass = gApprentices[GetRecordedBattleApprenticeId()].facilityClass;
|
||||
else
|
||||
facilityClass = gApprentices[gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE].id].facilityClass;
|
||||
}
|
||||
|
||||
return facilityClass;
|
||||
}
|
||||
|
||||
void GetFrontierTrainerName(u8 *dst, u16 trainerId)
|
||||
{
|
||||
s32 i = 0;
|
||||
enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(trainerId);
|
||||
SetFacilityPtrsGetLevel();
|
||||
|
||||
if (trainerId == TRAINER_EREADER)
|
||||
{
|
||||
#if FREE_BATTLE_TOWER_E_READER == FALSE
|
||||
for (i = 0; i < PLAYER_NAME_LENGTH; i++)
|
||||
dst[i] = gSaveBlock2Ptr->frontier.ereaderTrainer.name[i];
|
||||
#endif //FREE_BATTLE_TOWER_E_READER
|
||||
}
|
||||
else if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
{
|
||||
CopyFrontierBrainTrainerName(dst);
|
||||
return;
|
||||
}
|
||||
else if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
{
|
||||
for (i = 0; gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i] != EOS; i++)
|
||||
dst[i] = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i];
|
||||
}
|
||||
else if (trainerId < FRONTIER_TRAINERS_COUNT)
|
||||
{
|
||||
for (i = 0; i < PLAYER_NAME_LENGTH; i++)
|
||||
dst[i] = gFacilityTrainers[trainerId].trainerName[i];
|
||||
}
|
||||
else if (trainerId < TRAINER_RECORD_MIXING_APPRENTICE)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
{
|
||||
GetRecordedBattleRecordMixFriendName(dst);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct EmeraldBattleTowerRecord *record = &gSaveBlock2Ptr->frontier.towerRecords[trainerId - TRAINER_RECORD_MIXING_FRIEND];
|
||||
TVShowConvertInternationalString(dst, record->name, record->language);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 id, language;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
{
|
||||
id = GetRecordedBattleApprenticeId();
|
||||
language = GetRecordedBattleApprenticeLanguage();
|
||||
}
|
||||
else
|
||||
{
|
||||
struct Apprentice *apprentice = &gSaveBlock2Ptr->apprentices[trainerId - TRAINER_RECORD_MIXING_APPRENTICE];
|
||||
id = apprentice->id;
|
||||
language = apprentice->language;
|
||||
}
|
||||
TVShowConvertInternationalString(dst, GetApprenticeNameInLanguage(id, language), language);
|
||||
return;
|
||||
}
|
||||
|
||||
dst[i] = EOS;
|
||||
}
|
||||
|
||||
u16 GetRandomFrontierMonFromSet(u16 trainerId)
|
||||
{
|
||||
u8 level = SetFacilityPtrsGetLevel();
|
||||
const u16 *monSet = gFacilityTrainers[trainerId].monSet;
|
||||
u8 numMons = 0;
|
||||
u32 monId = monSet[numMons];
|
||||
|
||||
while (monId != 0xFFFF)
|
||||
{
|
||||
numMons++;
|
||||
monId = monSet[numMons];
|
||||
if (monId == 0xFFFF)
|
||||
break;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// "High tier" Pokémon are only allowed on open level mode
|
||||
// 20 is not a possible value for level here
|
||||
monId = monSet[Random() % numMons];
|
||||
} while((level == FRONTIER_MAX_LEVEL_50 || level == 20) && monId > FRONTIER_MONS_HIGH_TIER);
|
||||
|
||||
return monId;
|
||||
}
|
||||
|
||||
void FrontierSpeechToString(const u16 *words)
|
||||
{
|
||||
ConvertEasyChatWordsToString(gStringVar4, words, 3, 2);
|
||||
if (GetStringWidth(FONT_NORMAL, gStringVar4, -1) > 204u)
|
||||
{
|
||||
s32 i = 0;
|
||||
|
||||
ConvertEasyChatWordsToString(gStringVar4, words, 2, 3);
|
||||
while (gStringVar4[i++] != CHAR_NEWLINE)
|
||||
;
|
||||
while (gStringVar4[i] != CHAR_NEWLINE)
|
||||
i++;
|
||||
|
||||
gStringVar4[i] = CHAR_PROMPT_SCROLL;
|
||||
}
|
||||
}
|
||||
|
||||
u8 SetFacilityPtrsGetLevel(void)
|
||||
{
|
||||
if (gSaveBlock2Ptr->frontier.lvlMode == FRONTIER_LVL_TENT)
|
||||
{
|
||||
return SetTentPtrsGetLevel();
|
||||
}
|
||||
else
|
||||
{
|
||||
gFacilityTrainers = gBattleFrontierTrainers;
|
||||
gFacilityTrainerMons = gBattleFrontierMons;
|
||||
return GetFrontierEnemyMonLevel(gSaveBlock2Ptr->frontier.lvlMode);
|
||||
}
|
||||
}
|
||||
|
||||
u8 GetFrontierEnemyMonLevel(u8 lvlMode)
|
||||
{
|
||||
u8 level;
|
||||
|
||||
switch (lvlMode)
|
||||
{
|
||||
default:
|
||||
case FRONTIER_LVL_50:
|
||||
level = FRONTIER_MAX_LEVEL_50;
|
||||
break;
|
||||
case FRONTIER_LVL_OPEN:
|
||||
level = GetHighestLevelInPlayerParty();
|
||||
if (level < FRONTIER_MIN_LEVEL_OPEN)
|
||||
level = FRONTIER_MIN_LEVEL_OPEN;
|
||||
break;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
s32 GetHighestLevelInPlayerParty(void)
|
||||
{
|
||||
s32 highestLevel = 0;
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL)
|
||||
&& GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) != SPECIES_EGG)
|
||||
{
|
||||
s32 level = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL, NULL);
|
||||
if (level > highestLevel)
|
||||
highestLevel = level;
|
||||
}
|
||||
}
|
||||
|
||||
return highestLevel;
|
||||
}
|
||||
|
||||
u16 FacilityClassToGraphicsId(u8 facilityClass)
|
||||
{
|
||||
u16 trainerObjectGfxId;
|
||||
u8 i;
|
||||
|
||||
// Search male classes.
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerMaleFacilityClasses); i++)
|
||||
{
|
||||
if (gTowerMaleFacilityClasses[i] == facilityClass)
|
||||
break;
|
||||
}
|
||||
if (i != ARRAY_COUNT(gTowerMaleFacilityClasses))
|
||||
{
|
||||
trainerObjectGfxId = gTowerMaleTrainerGfxIds[i];
|
||||
return trainerObjectGfxId;
|
||||
}
|
||||
|
||||
// Search female classes.
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerFemaleFacilityClasses); i++)
|
||||
{
|
||||
if (gTowerFemaleFacilityClasses[i] == facilityClass)
|
||||
break;
|
||||
}
|
||||
if (i != ARRAY_COUNT(gTowerFemaleFacilityClasses))
|
||||
{
|
||||
trainerObjectGfxId = gTowerFemaleTrainerGfxIds[i];
|
||||
return trainerObjectGfxId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OBJ_EVENT_GFX_BOY_1;
|
||||
}
|
||||
}
|
||||
|
||||
#define tWindowId data[0]
|
||||
#define tMenuTaskId data[1]
|
||||
#define tArrowTaskId data[2]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "global.h"
|
||||
#include "berry.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_special.h"
|
||||
#include "easy_chat.h"
|
||||
#include "event_data.h"
|
||||
#include "mail.h"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "event_data.h"
|
||||
#include "easy_chat.h"
|
||||
#include "script.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_special.h"
|
||||
#include "wonder_news.h"
|
||||
#include "string_util.h"
|
||||
#include "new_game.h"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "decompress.h"
|
||||
#include "overworld.h"
|
||||
#include "script.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_special.h"
|
||||
#include "mystery_gift.h"
|
||||
#include "mystery_event_script.h"
|
||||
#include "mystery_gift_client.h"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "battle_tower.h"
|
||||
#include "battle_z_move.h"
|
||||
#include "data.h"
|
||||
#include "frontier_util.h"
|
||||
#include "daycare.h"
|
||||
#include "dexnav.h"
|
||||
#include "event_data.h"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "ereader_helpers.h"
|
||||
#include "event_data.h"
|
||||
#include "event_scripts.h"
|
||||
#include "frontier_util.h"
|
||||
#include "fieldmap.h"
|
||||
#include "field_message_box.h"
|
||||
#include "international_string_util.h"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "trainer_hill.h"
|
||||
#include "util.h"
|
||||
#include "battle_pyramid.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/battle_setup.h"
|
||||
#include "constants/event_objects.h"
|
||||
#include "constants/event_object_movement.h"
|
||||
|
|
@ -420,6 +421,33 @@ bool8 CheckForTrainersWantingBattle(void)
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
if (InBattlePyramid_() || InTrainerHillChallenge())
|
||||
{
|
||||
u8 facility = InBattlePyramid_() ? FACILITY_BATTLE_PYRAMID : FACILITY_BATTLE_TRAINER_HILL;
|
||||
|
||||
if (gNoOfApproachingTrainers > 0)
|
||||
{
|
||||
ResetTrainerOpponentIds();
|
||||
InitTrainerBattleParameter();
|
||||
|
||||
gSelectedObjectEvent = gApproachingTrainers[0].objectEventId;
|
||||
gSpecialVar_LastTalked = gObjectEvents[gApproachingTrainers[0].objectEventId].localId;
|
||||
BattleSetup_ConfigureFacilityTrainerBattle(facility, gApproachingTrainers[0].trainerScriptPtr + 2);
|
||||
if (gNoOfApproachingTrainers > 1)
|
||||
{
|
||||
gApproachingTrainerId++;
|
||||
gSelectedObjectEvent = gApproachingTrainers[1].objectEventId;
|
||||
gSpecialVar_LastTalked = gObjectEvents[gApproachingTrainers[1].objectEventId].localId;
|
||||
BattleSetup_ConfigureFacilityTrainerBattle(facility, gApproachingTrainers[0].trainerScriptPtr + 2);
|
||||
gApproachingTrainerId = 0;
|
||||
}
|
||||
ScriptContext_SetupScript(EventScript_StartTrainerApproach);
|
||||
LockPlayerFieldControls();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (gNoOfApproachingTrainers == 1)
|
||||
{
|
||||
ResetTrainerOpponentIds();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user