Partner Battle refactor (#3592)

* Partner Battle refactor

* fix for steven id

* clean up

* Use trainer partner names for id

* removed testing leftover

* comment change

* more review changes

* fix compiling

* remove partener count

---------

Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
Alex 2023-12-20 12:38:28 +01:00 committed by GitHub
parent bb94d302ae
commit 1e25b53433
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 160 additions and 194 deletions

View file

@ -257,14 +257,7 @@ MossdeepCity_SpaceCenter_2F_EventScript_ChoosePartyForMultiBattle::
goto MossdeepCity_SpaceCenter_2F_EventScript_ReadyForBattlePrompt
MossdeepCity_SpaceCenter_2F_EventScript_DoStevenMultiBattle::
special ReducePlayerPartyToSelectedMons
frontier_set FRONTIER_DATA_SELECTED_MON_ORDER
setvar VAR_0x8004, SPECIAL_BATTLE_STEVEN
setvar VAR_0x8005, 0
special DoSpecialTrainerBattle
waitstate
frontier_saveparty
special LoadPlayerParty
multi_2_vs_2 TRAINER_MAXIE_MOSSDEEP, MossdeepCity_SpaceCenter_2F_Text_JustWantToExpandLand, TRAINER_TABITHA_MOSSDEEP, MossdeepCity_SpaceCenter_Text_TabithaDefeat, PARTNER_STEVEN, TRAINER_BACK_PIC_STEVEN
switch VAR_RESULT
case 1, MossdeepCity_SpaceCenter_2F_EventScript_DefeatedMaxieTabitha
fadescreen FADE_TO_BLACK
@ -336,14 +329,6 @@ MossdeepCity_SpaceCenter_2F_EventScript_StevenFacePlayerWest::
turnobject LOCALID_STEVEN, DIR_EAST
return
MossdeepCity_SpaceCenter_2F_EventScript_MaxieTrainer::
trainerbattle TRAINER_BATTLE_SET_TRAINER_A, TRAINER_MAXIE_MOSSDEEP, 0, MossdeepCity_SpaceCenter_2F_Text_JustWantToExpandLand, MossdeepCity_SpaceCenter_2F_Text_JustWantToExpandLand
end
MossdeepCity_SpaceCenter_2F_EventScript_TabithaTrainer::
trainerbattle TRAINER_BATTLE_SET_TRAINER_B, TRAINER_TABITHA_MOSSDEEP, 0, MossdeepCity_SpaceCenter_Text_TabithaDefeat, MossdeepCity_SpaceCenter_Text_TabithaDefeat
end
MossdeepCity_SpaceCenter_2F_EventScript_RivalRayquazaCall::
lockall
checkplayergender

View file

@ -41,10 +41,9 @@
#define SPECIAL_BATTLE_ARENA 5
#define SPECIAL_BATTLE_FACTORY 6
#define SPECIAL_BATTLE_PIKE_SINGLE 7
#define SPECIAL_BATTLE_STEVEN 8
#define SPECIAL_BATTLE_PIKE_DOUBLE 9
#define SPECIAL_BATTLE_PYRAMID 10
#define SPECIAL_BATTLE_MULTI 11
#define SPECIAL_BATTLE_PIKE_DOUBLE 8
#define SPECIAL_BATTLE_PYRAMID 9
#define SPECIAL_BATTLE_MULTI 10
#define MAX_BATTLE_FRONTIER_POINTS 9999
#define MAX_STREAK 9999

View file

@ -0,0 +1,8 @@
#ifndef GUARD_CONSTANTS_BATTLE_PARTNERS_H
#define GUARD_CONSTANTS_BATTLE_PARTNERS_H
#define PARTNER_NONE 0
#define PARTNER_STEVEN 1
#endif // GUARD_CONSTANTS_BATTLE_PARTNERS_H

View file

@ -1,6 +1,8 @@
#ifndef GUARD_CONSTANTS_OPPONENTS_H
#define GUARD_CONSTANTS_OPPONENTS_H
#include "constants/battle_partner.h"
#define TRAINER_NONE 0
#define TRAINER_SAWYER_1 1
#define TRAINER_GRUNT_AQUA_HIDEOUT_1 2
@ -863,5 +865,6 @@
#define TRAINERS_COUNT 855
#define MAX_TRAINERS_COUNT 864
#define TRAINER_PARTNER(partner) (MAX_TRAINERS_COUNT + partner)
#endif // GUARD_CONSTANTS_OPPONENTS_H

View file

@ -14,8 +14,6 @@
#define TRAINER_SECRET_BASE 1024
#define TRAINER_LINK_OPPONENT 2048
#define TRAINER_UNION_ROOM 3072
#define TRAINER_STEVEN_PARTNER 3075
#define TRAINER_CUSTOM_PARTNER 3076
#define TRAINER_PIC_HIKER 0
#define TRAINER_PIC_AQUA_GRUNT_M 1

View file

@ -102,6 +102,8 @@ extern const struct CompressedSpriteSheet gTrainerBackPicTable[]; // functionall
extern const struct CompressedSpritePalette gTrainerBackPicPaletteTable[];
extern const struct Trainer gTrainers[];
extern const struct Trainer gBattlePartners[];
extern const u8 gTrainerClassNames[][13];
extern const u8 gMoveNames[MOVES_COUNT_DYNAMAX][MOVE_NAME_LENGTH + 1];
extern const u8 *const gZMoveNames[];

View file

@ -611,7 +611,6 @@ extern const u8 EventScript_TradeCenter_Chair1[];
extern const u8 EventScript_TradeCenter_Chair0[];
extern const u8 EventScript_ConfirmLeaveCableClubRoom[];
extern const u8 EventScript_TerminateLink[];
extern const u8 VSSeeker_Text_BatteryNotChargedNeedXSteps[];
extern const u8 VSSeeker_Text_NoTrainersWithinRange[];
extern const u8 VSSeeker_Text_TrainersNotReady[];

View file

@ -26,6 +26,7 @@
#include "constants/songs.h"
#include "constants/trainers.h"
#include "constants/battle_anim.h"
#include "constants/battle_partner.h"
// .rodata
static const u16 sUnrefArray[] = {0x0300, 0x0000}; //OamData?
@ -1146,7 +1147,7 @@ void DrawBattleEntryBackground(void)
}
else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_EREADER_TRAINER))
{
if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || gPartnerTrainerId == TRAINER_STEVEN_PARTNER || gPartnerTrainerId >= TRAINER_CUSTOM_PARTNER)
if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
{
LZDecompressVram(gBattleTerrainAnimTiles_Building, (void *)(BG_CHAR_ADDR(1)));
LZDecompressVram(gBattleTerrainAnimTilemap_Building, (void *)(BG_SCREEN_ADDR(28)));

View file

@ -31,6 +31,7 @@
#include "util.h"
#include "window.h"
#include "constants/battle_anim.h"
#include "constants/battle_partner.h"
#include "constants/hold_effects.h"
#include "constants/items.h"
#include "constants/moves.h"
@ -1875,7 +1876,7 @@ static void PlayerHandleDrawTrainerPic(u32 battler)
else // First mon, on the left.
xPos = 32;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != TRAINER_STEVEN_PARTNER && gPartnerTrainerId < TRAINER_CUSTOM_PARTNER)
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE))
{
xPos = 90;
yPos = (8 - gTrainerFrontPicCoords[trainerPicId].size) * 4 + 80;
@ -1893,7 +1894,7 @@ static void PlayerHandleDrawTrainerPic(u32 battler)
}
// Use front pic table for any tag battles unless your partner is Steven or a custom partner.
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != TRAINER_STEVEN_PARTNER && gPartnerTrainerId < TRAINER_CUSTOM_PARTNER)
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE))
{
trainerPicId = PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender);
isFrontPic = TRUE;

View file

@ -27,6 +27,7 @@
#include "util.h"
#include "window.h"
#include "constants/battle_anim.h"
#include "constants/battle_partner.h"
#include "constants/songs.h"
#include "constants/party_menu.h"
#include "constants/trainers.h"
@ -296,15 +297,9 @@ static void PlayerPartnerHandleDrawTrainerPic(u32 battler)
s16 xPos, yPos;
u32 trainerPicId;
if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
{
trainerPicId = TRAINER_BACK_PIC_STEVEN;
xPos = 90;
yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
}
else if (gPartnerTrainerId >= TRAINER_CUSTOM_PARTNER)
{
trainerPicId = gPartnerSpriteId;
trainerPicId = gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic;
xPos = 90;
yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
}
@ -321,8 +316,8 @@ static void PlayerPartnerHandleDrawTrainerPic(u32 battler)
yPos = (8 - gTrainerFrontPicCoords[trainerPicId].size) * 4 + 80;
}
// Use back pic only if the partner is Steven or a custom partner.
if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER || gPartnerTrainerId >= TRAINER_CUSTOM_PARTNER)
// Use back pic only if the partner Steven or is custom.
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
isFrontPic = FALSE;
else
isFrontPic = TRUE;
@ -439,9 +434,7 @@ static void PlayerPartnerHandleIntroTrainerBallThrow(u32 battler)
{
const u32 *trainerPal;
if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
trainerPal = gTrainerBackPicPaletteTable[TRAINER_STEVEN_PARTNER].data;
else if (gPartnerTrainerId >= TRAINER_CUSTOM_PARTNER) // Custom multi battle.
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
trainerPal = gTrainerBackPicPaletteTable[gPartnerSpriteId].data;
else if (IsAiVsAiBattle())
trainerPal = gTrainerFrontPicPaletteTable[gTrainers[gPartnerTrainerId].trainerPic].data;

View file

@ -9,6 +9,7 @@
#include "scanline_effect.h"
#include "task.h"
#include "trig.h"
#include "constants/battle_partner.h"
#include "constants/trainers.h"
extern const u8 gBattleAnimBgCntSet[];
@ -104,7 +105,7 @@ void HandleIntroSlide(u8 terrain)
{
u8 taskId;
if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) && gPartnerTrainerId != TRAINER_STEVEN_PARTNER && gPartnerTrainerId < TRAINER_CUSTOM_PARTNER)
if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE))
{
taskId = CreateTask(BattleIntroSlidePartner, 0);
}

View file

@ -56,6 +56,7 @@
#include "constants/abilities.h"
#include "constants/battle_move_effects.h"
#include "constants/battle_string_ids.h"
#include "constants/battle_partner.h"
#include "constants/hold_effects.h"
#include "constants/items.h"
#include "constants/moves.h"
@ -512,7 +513,7 @@ static void CB2_InitBattleInternal(void)
gBattle_WIN0H = DISPLAY_WIDTH;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != TRAINER_STEVEN_PARTNER && gPartnerTrainerId < TRAINER_CUSTOM_PARTNER)
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE))
{
gBattle_WIN0V = DISPLAY_HEIGHT - 1;
gBattle_WIN1H = DISPLAY_WIDTH;

View file

@ -50,6 +50,7 @@
#include "constants/battle_anim.h"
#include "constants/battle_move_effects.h"
#include "constants/battle_string_ids.h"
#include "constants/battle_partner.h"
#include "constants/hold_effects.h"
#include "constants/items.h"
#include "constants/item_effects.h"
@ -4363,7 +4364,7 @@ static bool32 NoAliveMonsForPlayerAndPartner(void)
u32 i;
u32 HP_count = 0;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && (gPartnerTrainerId == TRAINER_STEVEN_PARTNER || gPartnerTrainerId >= TRAINER_CUSTOM_PARTNER))
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
{
for (i = 0; i < PARTY_SIZE; i++)
{
@ -4383,25 +4384,12 @@ bool32 NoAliveMonsForPlayer(void)
u32 i;
u32 HP_count = 0;
// Get total HP for the player's party to determine if the player has lost
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && (gPartnerTrainerId == TRAINER_STEVEN_PARTNER || gPartnerTrainerId >= TRAINER_CUSTOM_PARTNER))
for (i = 0; i < PARTY_SIZE; i++)
{
// In multi battle with Steven, skip his Pokémon
for (i = 0; i < MULTI_PARTY_SIZE; i++)
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)
&& (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->arenaLostPlayerMons & gBitTable[i])))
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG))
HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP);
}
}
else
{
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)
&& (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->arenaLostPlayerMons & gBitTable[i])))
{
HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP);
}
HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP);
}
}

View file

@ -32,15 +32,13 @@
#include "constants/battle_tent_mons.h"
#include "constants/battle_tent_trainers.h"
#include "constants/battle_tower.h"
#include "constants/battle_partner.h"
#include "constants/frontier_util.h"
#include "constants/items.h"
#include "constants/trainers.h"
#include "constants/event_objects.h"
#include "constants/moves.h"
extern const u8 MossdeepCity_SpaceCenter_2F_EventScript_MaxieTrainer[];
extern const u8 MossdeepCity_SpaceCenter_2F_EventScript_TabithaTrainer[];
// EWRAM vars.
EWRAM_DATA const struct BattleFrontierTrainer *gFacilityTrainers = NULL;
EWRAM_DATA const struct FacilityMon *gFacilityTrainerMons = NULL;
@ -762,44 +760,11 @@ static const u8 *const *const sPartnerApprenticeTextTables[NUM_APPRENTICES] =
sPartnerApprenticeTexts16
};
struct
{
u16 species;
u8 fixedIV;
u8 level;
u8 nature;
u8 evs[NUM_STATS];
u16 moves[MAX_MON_MOVES];
} static const sStevenMons[MULTI_PARTY_SIZE] =
{
{
.species = SPECIES_METANG,
.fixedIV = MAX_PER_STAT_IVS,
.level = 42,
.nature = NATURE_BRAVE,
.evs = {0, 252, 252, 0, 6, 0},
.moves = {MOVE_LIGHT_SCREEN, MOVE_PSYCHIC, MOVE_REFLECT, MOVE_METAL_CLAW}
},
{
.species = SPECIES_SKARMORY,
.fixedIV = MAX_PER_STAT_IVS,
.level = 43,
.nature = NATURE_IMPISH,
.evs = {252, 0, 0, 0, 6, 252},
.moves = {MOVE_TOXIC, MOVE_AERIAL_ACE, MOVE_PROTECT, MOVE_STEEL_WING}
},
{
.species = SPECIES_AGGRON,
.fixedIV = MAX_PER_STAT_IVS,
.level = 44,
.nature = NATURE_ADAMANT,
.evs = {0, 252, 0, 0, 252, 6},
.moves = {MOVE_THUNDER, MOVE_PROTECT, MOVE_SOLAR_BEAM, MOVE_DRAGON_CLAW}
}
};
#include "data/battle_frontier/battle_tent.h"
#include "data/partner_parties.h"
#include "data/battle_partners.h"
static void (* const sBattleTowerFuncs[])(void) =
{
[BATTLE_TOWER_FUNC_INIT] = InitTowerChallenge,
@ -1447,13 +1412,9 @@ u8 GetFrontierOpponentClass(u16 trainerId)
{
return GetFrontierBrainTrainerClass();
}
else if (trainerId == TRAINER_STEVEN_PARTNER)
else if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
{
trainerClass = gTrainers[TRAINER_STEVEN].trainerClass;
}
else if (trainerId >= TRAINER_CUSTOM_PARTNER)
{
trainerClass = gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].trainerClass;
trainerClass = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass;
}
else if (trainerId < FRONTIER_TRAINERS_COUNT)
{
@ -1531,15 +1492,10 @@ void GetFrontierTrainerName(u8 *dst, u16 trainerId)
CopyFrontierBrainTrainerName(dst);
return;
}
else if (trainerId == TRAINER_STEVEN_PARTNER)
else if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
{
for (i = 0; i < PLAYER_NAME_LENGTH; i++)
dst[i] = gTrainers[TRAINER_STEVEN].trainerName[i];
}
else if (trainerId >= TRAINER_CUSTOM_PARTNER)
{
for (i = 0; gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].trainerName[i] != EOS; i++)
dst[i] = gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].trainerName[i];
for (i = 0; gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i] != EOS; i++)
dst[i] = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i];
}
else if (trainerId < FRONTIER_TRAINERS_COUNT)
{
@ -2136,18 +2092,6 @@ void DoSpecialTrainerBattle(void)
PlayMapChosenOrBattleBGM(0);
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_B_PIKE));
break;
case SPECIAL_BATTLE_STEVEN:
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER;
FillPartnerParty(TRAINER_STEVEN_PARTNER);
gApproachingTrainerId = 0;
BattleSetup_ConfigureTrainerBattle(MossdeepCity_SpaceCenter_2F_EventScript_MaxieTrainer + 1);
gApproachingTrainerId = 1;
BattleSetup_ConfigureTrainerBattle(MossdeepCity_SpaceCenter_2F_EventScript_TabithaTrainer + 1);
gPartnerTrainerId = TRAINER_STEVEN_PARTNER;
CreateTask(Task_StartBattleAfterTransition, 1);
PlayMapChosenOrBattleBGM(0);
BattleTransition_StartOnField(B_TRANSITION_MAGMA);
break;
case SPECIAL_BATTLE_MULTI:
if (gSpecialVar_0x8005 & MULTI_BATTLE_2_VS_WILD) // Player + AI against wild mon
{
@ -2164,7 +2108,7 @@ void DoSpecialTrainerBattle(void)
}
gPartnerSpriteId = VarGet(gSpecialVar_0x8007);
gPartnerTrainerId = VarGet(gSpecialVar_0x8006) + TRAINER_CUSTOM_PARTNER;
gPartnerTrainerId = VarGet(gSpecialVar_0x8006) + TRAINER_PARTNER(PARTNER_NONE);
FillPartnerParty(gPartnerTrainerId);
CreateTask(Task_StartBattleAfterTransition, 1);
PlayMapChosenOrBattleBGM(0);
@ -3003,7 +2947,8 @@ void TryHideBattleTowerReporter(void)
static void FillPartnerParty(u16 trainerId)
{
s32 i, j;
s32 i, j, k;
u32 firstIdPart = 0, secondIdPart = 0, thirdIdPart = 0;
u32 ivs, level, personality;
u32 friendship;
u16 monId;
@ -3012,47 +2957,38 @@ static void FillPartnerParty(u16 trainerId)
s32 ball = -1;
SetFacilityPtrsGetLevel();
if (trainerId == TRAINER_STEVEN_PARTNER)
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
{
for (i = 0; i < MULTI_PARTY_SIZE; i++)
{
do
{
j = Random32();
} while (IsShinyOtIdPersonality(STEVEN_OTID, j) || sStevenMons[i].nature != GetNatureFromPersonality(j));
CreateMon(&gPlayerParty[MULTI_PARTY_SIZE + i],
sStevenMons[i].species,
sStevenMons[i].level,
sStevenMons[i].fixedIV,
TRUE,
#ifdef BUGFIX
j,
#else
i, // BUG: personality was stored in the 'j' variable. As a result, Steven's pokemon do not have the intended natures.
#endif
OT_ID_PRESET, STEVEN_OTID);
for (j = 0; j < PARTY_SIZE; j++)
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_HP_EV + j, &sStevenMons[i].evs[j]);
for (j = 0; j < MAX_MON_MOVES; j++)
SetMonMoveSlot(&gPlayerParty[MULTI_PARTY_SIZE + i], sStevenMons[i].moves[j], j);
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_NAME, gTrainers[TRAINER_STEVEN].trainerName);
j = MALE;
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_GENDER, &j);
CalculateMonStats(&gPlayerParty[MULTI_PARTY_SIZE + i]);
}
}
else if (trainerId >= TRAINER_CUSTOM_PARTNER)
{
otID = Random32();
for (i = 0; i < 3; i++)
ZeroMonData(&gPlayerParty[i + 3]);
for (i = 0; i < 3 && i < gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].partySize; i++)
for (i = 0; i < 3 && i < gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].partySize; i++)
{
const struct TrainerMon *partyData = gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].party;
u32 otIdType = OT_ID_RANDOM_NO_SHINY;
do
const struct TrainerMon *partyData = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].party;
const u8 *partnerName = gBattlePartners[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();
} while (IsShinyOtIdPersonality(otID, personality));
@ -3064,53 +3000,50 @@ static void FillPartnerParty(u16 trainerId)
if (partyData[i].nature != 0)
ModifyPersonalityForNature(&personality, partyData[i].nature - 1);
if (partyData[i].isShiny)
{
otIdType = OT_ID_PRESET;
otID = HIHALF(personality) ^ LOHALF(personality);
}
otID ^= GET_SHINY_VALUE(otID, personality) << 16;
CreateMon(&gPlayerParty[i + 3], partyData[i].species, partyData[i].lvl, 0, TRUE, personality, otIdType, otID);
CreateMon(&gPlayerParty[i + 3], partyData[i].species, partyData[i].lvl, 0, TRUE, personality, OT_ID_PRESET, otID);
SetMonData(&gPlayerParty[i + 3], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
CustomTrainerPartyAssignMoves(&gPlayerParty[i+3], &partyData[i]);
CustomTrainerPartyAssignMoves(&gPlayerParty[i + 3], &partyData[i]);
SetMonData(&gPlayerParty[i+3], MON_DATA_IVS, &(partyData[i].iv));
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]));
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)
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_ABILITY_NUM, &j);
}
SetMonData(&gPlayerParty[i+3], MON_DATA_FRIENDSHIP, &(partyData[i].friendship));
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);
SetMonData(&gPlayerParty[i + 3], MON_DATA_POKEBALL, &ball);
}
if (partyData[i].nickname != NULL)
{
SetMonData(&gPlayerParty[i+3], MON_DATA_NICKNAME, partyData[i].nickname);
SetMonData(&gPlayerParty[i + 3], MON_DATA_NICKNAME, partyData[i].nickname);
}
CalculateMonStats(&gPlayerParty[i+3]);
CalculateMonStats(&gPlayerParty[i + 3]);
StringCopy(trainerName, gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].trainerName);
StringCopy(trainerName, gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName);
SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_NAME, trainerName);
j = gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].encounterMusic_gender >> 7;
SetMonData(&gPlayerParty[i+3], MON_DATA_OT_GENDER, &j);
j = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].encounterMusic_gender >> 7;
SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_GENDER, &j);
}
}
else if (trainerId == TRAINER_EREADER)

View file

@ -0,0 +1,21 @@
const struct Trainer gBattlePartners[] = {
[PARTNER_NONE] =
{
.party = NULL,
.trainerClass = TRAINER_CLASS_PKMN_TRAINER_1,
.encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE,
.trainerPic = TRAINER_PIC_HIKER,
.trainerName = _(""),
.items = {},
},
[PARTNER_STEVEN] =
{
.party = TRAINER_PARTY(sParty_StevenPartner),
.trainerClass = TRAINER_CLASS_RIVAL,
.encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE,
.trainerPic = TRAINER_BACK_PIC_STEVEN,
.trainerName = _("STEVEN"),
},
};

View file

@ -0,0 +1,26 @@
static const struct TrainerMon sParty_StevenPartner[] = {
{
.species = SPECIES_METANG,
.lvl = 42,
.nature = TRAINER_PARTY_NATURE(NATURE_BRAVE),
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
.ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0),
.moves = {MOVE_LIGHT_SCREEN, MOVE_PSYCHIC, MOVE_REFLECT, MOVE_METAL_CLAW},
},
{
.species = SPECIES_SKARMORY,
.lvl = 43,
.nature = TRAINER_PARTY_NATURE(NATURE_IMPISH),
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
.ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252),
.moves = {MOVE_TOXIC, MOVE_AERIAL_ACE, MOVE_PROTECT, MOVE_STEEL_WING},
},
{
.species = SPECIES_AGGRON,
.lvl = 44,
.nature = TRAINER_PARTY_NATURE(NATURE_ADAMANT),
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
.ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6),
.moves = {MOVE_THUNDER, MOVE_PROTECT, MOVE_SOLAR_BEAM, MOVE_DRAGON_CLAW},
}
};

View file

@ -43,6 +43,7 @@
#include "constants/battle_frontier.h"
#include "constants/battle_move_effects.h"
#include "constants/battle_script_commands.h"
#include "constants/battle_partner.h"
#include "constants/cries.h"
#include "constants/form_change_types.h"
#include "constants/hold_effects.h"
@ -858,7 +859,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &iv);
SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv);
}
else if (P_LEGENDARY_PERFECT_IVS >= GEN_6
else if (P_LEGENDARY_PERFECT_IVS >= GEN_6
&& (gSpeciesInfo[species].isLegendary
|| gSpeciesInfo[species].isMythical
|| gSpeciesInfo[species].isUltraBeast))
@ -1824,11 +1825,11 @@ void SetMultiuseSpriteTemplateToPokemon(u16 speciesTag, u8 battlerPosition)
gMultiuseSpriteTemplate.paletteTag = speciesTag;
if (battlerPosition == B_POSITION_PLAYER_LEFT || battlerPosition == B_POSITION_PLAYER_RIGHT)
gMultiuseSpriteTemplate.anims = gAnims_MonPic;
else
else
{
if (speciesTag > SPECIES_SHINY_TAG)
speciesTag = speciesTag - SPECIES_SHINY_TAG;
speciesTag = SanitizeSpeciesId(speciesTag);
if (gSpeciesInfo[speciesTag].frontAnimFrames != NULL)
gMultiuseSpriteTemplate.anims = gSpeciesInfo[speciesTag].frontAnimFrames;
@ -5295,7 +5296,7 @@ const u8 *GetTrainerPartnerName(void)
{
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
if (gPartnerTrainerId == TRAINER_PARTNER(PARTNER_STEVEN))
{
return gTrainers[TRAINER_STEVEN].trainerName;
}
@ -5518,16 +5519,22 @@ void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality)
const u8 *GetTrainerClassNameFromId(u16 trainerId)
{
if (trainerId >= TRAINERS_COUNT)
trainerId = TRAINER_NONE;
return gTrainerClassNames[gTrainers[trainerId].trainerClass];
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
return gTrainerClassNames[gBattlePartners[trainerId].trainerClass];
else if (trainerId < TRAINERS_COUNT)
return gTrainerClassNames[gTrainers[trainerId].trainerClass];
return gTrainerClassNames[gTrainers[TRAINER_NONE].trainerClass];
}
const u8 *GetTrainerNameFromId(u16 trainerId)
{
if (trainerId >= TRAINERS_COUNT)
trainerId = TRAINER_NONE;
return gTrainers[trainerId].trainerName;
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
return gBattlePartners[trainerId].trainerName;
else if (trainerId < TRAINERS_COUNT)
return gTrainers[trainerId].trainerName;
return gTrainers[TRAINER_NONE].trainerName;
}
bool8 HasTwoFramesAnimation(u16 species)