added battle_controller_player_partner, added functionality for BATTLE_TYPE_INGAME_PARTNER with multi_2_vs_2, fixed issues in battle_controller_opponent

This commit is contained in:
cawtds
2024-08-03 13:41:35 +02:00
parent 87b7d73494
commit 557ae12ffb
42 changed files with 1367 additions and 258 deletions

View File

@@ -5,6 +5,7 @@
.include "asm/macros/map.inc"
.include "asm/macros/m4a.inc"
.include "asm/macros/trainer_tower.inc"
.include "asm/macros/battle_frontier/battle_tower.inc"
.macro region_map_location x, y, width, height, name
.byte \x

View File

@@ -0,0 +1,23 @@
@Custom multi-battle commands
.macro multi_do type:req, partnerId: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
@special CallFrontierUtilFunc
special LoadPlayerParty
.endm
.macro multi_2_vs_2 trainer1Id:req, trainer1LoseText:req, trainer2Id:req, trainer2LoseText:req, partnerId:req
special SavePlayerParty
trainerbattle TRAINER_BATTLE_SET_TRAINER_A, \trainer1Id, 0, NULL, \trainer1LoseText @ set first trainer mons
trainerbattle TRAINER_BATTLE_SET_TRAINER_B, \trainer2Id, 0, NULL, \trainer2LoseText @ set second trainer mons
multi_do MULTI_BATTLE_2_VS_2, \partnerId
.endm

View File

@@ -729,6 +729,12 @@
.elseif \type == TRAINER_BATTLE_EARLY_RIVAL
.4byte \pointer1 @ text
.4byte \pointer2 @ text
.elseif \type == TRAINER_BATTLE_SET_TRAINER_A
.4byte \pointer1 @ text
.4byte \pointer2 @ text
.elseif \type == TRAINER_BATTLE_SET_TRAINER_B
.4byte \pointer1 @ text
.4byte \pointer2 @ text
.endif
.endm

View File

@@ -48,6 +48,7 @@ BattleScript_PayDayMoneyAndPickUpItems::
end2
BattleScript_LocalBattleLost::
jumpifbattletype BATTLE_TYPE_INGAME_PARTNER, BattleScript_LocalBattleLostPrintWhiteOut
jumpifbattletype BATTLE_TYPE_TRAINER_TOWER, BattleScript_BattleTowerLost
jumpifbattletype BATTLE_TYPE_EREADER_TRAINER, BattleScript_LocalBattleLostEnd
jumpifhalfword CMP_EQUAL, gTrainerBattleOpponent_A, TRAINER_SECRET_BASE, BattleScript_LocalBattleLostEnd

View File

@@ -2,6 +2,7 @@
#include "config/battle.h"
#include "constants/global.h"
#include "constants/flags.h"
#include "constants/battle_tower.h"
#include "constants/event_objects.h"
#include "constants/event_object_movement.h"
#include "constants/decorations.h"

View File

@@ -98,7 +98,7 @@ SevenIsland_House_Room1_EventScript_TrainerVisiting::
call EventScript_AskSaveGame
goto_if_eq VAR_RESULT, 0, SevenIsland_House_Room1_EventScript_DeclineBattle
special SavePlayerParty
special ReducePlayerPartyToThree
special ReducePlayerPartyToSelectedMons
msgbox SevenIsland_House_Room1_Text_DontHoldAnythingBack
closemessage
call_if_eq VAR_FACING, DIR_NORTH, SevenIsland_House_Room1_EventScript_EnterBattleRoomNorth

View File

@@ -256,7 +256,7 @@ gSpecials::
def_special ChooseBattleTowerPlayerParty
def_special ValidateEReaderTrainer
def_special NullFieldSpecial
def_special ReducePlayerPartyToThree
def_special ReducePlayerPartyToSelectedMons
def_special BedroomPC
def_special PlayerPC
def_special ShowTownMap
@@ -348,7 +348,7 @@ gSpecials::
def_special NullFieldSpecial
def_special Dummy_TryEnableBravoTrainerBattleTower
def_special DoesPartyHaveEnigmaBerry
def_special NullFieldSpecial
def_special DoSpecialTrainerBattle
def_special SetPostgameFlags
def_special StartMarowakBattle
def_special ForcePlayerOntoBike

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
115 197 164
255 222 205
222 180 148
189 148 115
123 90 82
189 115 205
164 82 172
82 82 90
49 49 57
213 222 238
172 189 213
123 148 164
255 98 90
197 65 65
255 255 255
0 0 0

View File

@@ -330,6 +330,10 @@ void SetControllerToRecordedPlayer(u32 battler);
void SetControllerToOpponent(u32 battler);
void OpponentBufferExecCompleted(u32 battler);
// player partner controller
void Controller_PlayerPartnerShowIntroHealthbox(u32 battler); // Also used by the link partner.
void SetControllerToPlayerPartner(u32 battler);
// safari controller
void SetControllerToSafari(u32 battler);

View File

@@ -118,6 +118,9 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk);
bool32 IsWildMonSmart(void);
u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags);
void ModifyPersonalityForNature(u32 *personality, u32 newNature);
u32 GeneratePersonalityForGender(u32 gender, u32 species);
void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMon *partyEntry);
extern const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES];

View File

@@ -42,5 +42,7 @@ const u8 *GetTrainerALoseText(void);
const u8 *GetTrainerBLoseText(void);
const u8 *GetTrainerWonSpeech(void);
void BattleSetup_StartTrainerBattle_Debug(void);
u8 GetWildBattleTransition(void);
u8 GetTrainerBattleTransition(void);
#endif // GUARD_BATTLE_SETUP_H

View File

@@ -35,5 +35,6 @@ void CopyEReaderTrainerName5(u8 *dest);
void GetBattleTowerTrainerName(u8 *text);
u8 GetEreaderTrainerClassId(void);
u8 GetBattleTowerTrainerClassNameId(void);
void DoSpecialTrainerBattle(void);
#endif //GUARD_BATTLE_TOWER_H

View File

@@ -3,6 +3,6 @@
#define GUARD_CONSTANTS_BATTLE_PARTNERS_H
#define PARTNER_NONE 0
// #define PARTNER_STEVEN 1
#define PARTNER_STEVEN 1
#endif // GUARD_CONSTANTS_BATTLE_PARTNERS_H

View File

@@ -11,5 +11,7 @@
#define TRAINER_BATTLE_REMATCH_DOUBLE 7
#define TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE_NO_MUSIC 8
#define TRAINER_BATTLE_EARLY_RIVAL 9
#define TRAINER_BATTLE_SET_TRAINER_A 10
#define TRAINER_BATTLE_SET_TRAINER_B 11
#endif // GUARD_CONSTANTS_BATTLE_SETUP_H

View File

@@ -79,4 +79,13 @@
#define BTSPECIAL_RESULT_QUICKSAVE 4
#define BTSPECIAL_RESULT_INACTIVE 5
// 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
#define SPECIAL_BATTLE_MULTI 10
#endif //GUARD_CONSTANTS_BATTLE_TOWER_H

View File

@@ -42,6 +42,12 @@
// party sizes
#define PARTY_SIZE 6
#define MULTI_PARTY_SIZE (PARTY_SIZE / 2)
#define FRONTIER_PARTY_SIZE 3
#define FRONTIER_DOUBLES_PARTY_SIZE 4
#define FRONTIER_MULTI_PARTY_SIZE 2
#define MAX_FRONTIER_PARTY_SIZE (max(FRONTIER_PARTY_SIZE, \
max(FRONTIER_DOUBLES_PARTY_SIZE,\
FRONTIER_MULTI_PARTY_SIZE)))
// capacities of various saveblock objects
#define DAYCARE_MON_COUNT 2

View File

@@ -174,6 +174,7 @@
#define TRAINER_BACK_PIC_RUBY_SAPPHIRE_MAY 3
#define TRAINER_BACK_PIC_POKEDUDE 4
#define TRAINER_BACK_PIC_OLD_MAN 5
#define TRAINER_BACK_PIC_STEVEN 6
// Special Trainer Ids.
#define TRAINER_UNION_ROOM 0xC00

View File

@@ -25,6 +25,10 @@ struct MonCoords
#define MAX_TRAINER_ITEMS 4
#define TRAINER_PIC_WIDTH 64
#define TRAINER_PIC_HEIGHT 64
#define TRAINER_PIC_SIZE (TRAINER_PIC_WIDTH * TRAINER_PIC_HEIGHT / 2)
enum {
BATTLER_AFFINE_NORMAL,
BATTLER_AFFINE_EMERGE,
@@ -140,6 +144,7 @@ extern const struct SpriteFrameImage gTrainerBackPicTable_Pokedude[];
extern const struct SpriteFrameImage gTrainerBackPicTable_OldMan[];
extern const struct SpriteFrameImage gTrainerBackPicTable_RSBrendan[];
extern const struct SpriteFrameImage gTrainerBackPicTable_RSMay[];
extern const struct SpriteFrameImage gTrainerBackPicTable_Steven[];
extern const union AnimCmd sAnim_GeneralFrame0[];

View File

@@ -2685,6 +2685,7 @@ extern const u32 gTrainerPalette_LeafBackPic[];
extern const u32 gTrainerPalette_RedBackPic[];
extern const u32 gTrainerPalette_PokedudeBackPic[];
extern const u32 gTrainerPalette_OldManBackPic[];
extern const u32 gTrainerPalette_Steven[];
extern const u32 gTrainerPalette_RSPokemonBreederM[];
extern const u32 gTrainerPalette_RSPokemonBreederF[];
extern const u32 gTrainerPalette_RSPokemonRangerM[];
@@ -4935,6 +4936,7 @@ extern const u8 gTrainerBackPic_Pokedude[];
extern const u8 gTrainerBackPic_OldMan[];
extern const u8 gTrainerBackPic_RSBrendan[];
extern const u8 gTrainerBackPic_RSMay[];
extern const u8 gTrainerBackPic_Steven[];
// mail
extern const u16 gFile_graphics_mail_orange_palette_pal[];

View File

@@ -23,7 +23,7 @@ extern struct PartyMenu gPartyMenu;
extern bool8 gPartyMenuUseExitCallback;
extern u8 gSelectedMonPartyId;
extern MainCallback gPostMenuFieldCallback;
extern u8 gSelectedOrderFromParty[3];
extern u8 gSelectedOrderFromParty[MAX_FRONTIER_PARTY_SIZE];
extern u8 gBattlePartyCurrentOrder[PARTY_SIZE / 2];
extern void (*gItemUseCB)(u8, TaskFunc);

View File

@@ -832,7 +832,7 @@ void BoxMonRestorePP(struct BoxPokemon *boxMon);
void SetMonPreventsSwitchingString(void);
void SetWildMonHeldItem(void);
bool8 IsMonShiny(struct Pokemon *mon);
u8 *GetTrainerPartnerName(void);
const u8 *GetTrainerPartnerName(void);
void BattleAnimateFrontSprite(struct Sprite *sprite, u16 species, bool8 noCry, u8 panMode);
void DoMonFrontSpriteAnimation(struct Sprite *sprite, u16 species, bool8 noCry, u8 panModeAnimFlag);
void BattleAnimateBackSprite(struct Sprite *sprite, u16 species);

View File

@@ -5,7 +5,7 @@ u32 ScriptGiveMon(u16 species, u8 level, u16 item);
bool8 ScriptGiveEgg(u16 species);
void ScriptSetMonMoveSlot(u8 partyIdx, u16 move, u8 slot);
void HealPlayerParty(void);
void ReducePlayerPartyToThree(void);
void ReducePlayerPartyToSelectedMons(void);
void CreateScriptedWildMon(u16 species, u8 level, u16 item);
void CreateScriptedDoubleWildMon(u16 species1, u8 level1, u16 item1, u16 species2, u8 level2, u16 item2);

View File

@@ -122,45 +122,56 @@ static void Intro_DelayAndEnd(u32 battler)
static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
{
bool32 healthboxAnimDone = FALSE;
bool32 twoMons = FALSE;
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
healthboxAnimDone = TRUE;
}
else if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[battler ^ BIT_FLANK]].callback == gSprites[gHealthboxSpriteIds[battler]].callback)
else
{
healthboxAnimDone = TRUE;
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
{
healthboxAnimDone = TRUE;
}
twoMons = TRUE;
}
if (IsCryPlayingOrClearCrySongs())
healthboxAnimDone = FALSE;
if (healthboxAnimDone)
{
if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT)
if (twoMons || !IsBattlerSpriteVisible(BATTLE_PARTNER(battler)))
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim
|| !gBattleSpritesDataPtr->healthBoxesData[battler ^ BIT_FLANK].finishedShinyMonAnim)
if (!gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
return;
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
return;
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler ^ BIT_FLANK].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler ^ BIT_FLANK].finishedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE;
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
}
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT)
m4aMPlayContinue(&gMPlayInfo_BGM);
}
else
{
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 256);
if (!gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
return;
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT)
{
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
}
}
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3;
gBattlerControllerFuncs[battler] = Intro_DelayAndEnd;
}
@@ -168,38 +179,89 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
static void Intro_TryShinyAnimShowHealthbox(u32 battler)
{
bool32 bgmRestored = FALSE;
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[battler ^ BIT_FLANK].ballAnimActive)
&& !gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim)
TryShinyAnimation(battler, &gEnemyParty[gBattlerPartyIndexes[battler]]);
if (!gBattleSpritesDataPtr->healthBoxesData[battler ^ BIT_FLANK].triedShinyMonAnim)
TryShinyAnimation(battler ^ BIT_FLANK, &gEnemyParty[gBattlerPartyIndexes[battler ^ BIT_FLANK]]);
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(battler) == 3)
TryShinyAnimation(battler, &gEnemyParty[gBattlerPartyIndexes[battler]]);
}
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
{
TryShinyAnimation(BATTLE_PARTNER(battler), &gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]);
}
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted)
{
if (++gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay == 1)
return;
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0;
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], &gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], HEALTHBOX_ALL);
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
}
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gEnemyParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
}
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = TRUE;
}
if (!gBattleSpritesDataPtr->healthBoxesData[battler].waitForCry
&& gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].waitForCry
&& !IsCryPlayingOrClearCrySongs())
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored)
{
DestroySprite(&gSprites[gBattleControllerData[battler ^ BIT_FLANK]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler ^ BIT_FLANK],
&gEnemyParty[gBattlerPartyIndexes[battler ^ BIT_FLANK]],
HEALTHBOX_ALL);
StartHealthboxSlideIn(battler ^ BIT_FLANK);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler ^ BIT_FLANK]);
SetBattlerShadowSpriteCallback(battler ^ BIT_FLANK, GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler ^ BIT_FLANK]], MON_DATA_SPECIES));
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT)
m4aMPlayContinue(&gMPlayInfo_BGM);
}
else
{
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
}
}
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = TRUE;
bgmRestored = TRUE;
}
if (bgmRestored)
{
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT)
{
if (++gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay == 1)
return;
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0;
}
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]);
SetBattlerShadowSpriteCallback(BATTLE_PARTNER(battler), GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], MON_DATA_SPECIES));
}
DestroySprite(&gSprites[gBattleControllerData[battler]]);
SetBattlerShadowSpriteCallback(battler, GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES));
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = FALSE;
gBattlerControllerFuncs[battler] = Intro_WaitForShinyAnimAndHealthbox;
}
DestroySprite(&gSprites[gBattleControllerData[battler]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler],
&gEnemyParty[gBattlerPartyIndexes[battler]],
HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
SetBattlerShadowSpriteCallback(battler, GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES));
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
gBattlerControllerFuncs[battler] = Intro_WaitForShinyAnimAndHealthbox;
}
}

View File

@@ -107,40 +107,6 @@ static void LinkPartnerBufferRunCommand(u32 battler)
}
}
static void Intro_DelayAndEnd(u32 battler)
{
if (--gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay == (u8)-1)
{
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0;
LinkPartnerBufferExecCompleted(battler);
}
}
static void Intro_WaitForHealthbox(u32 battler)
{
bool32 finished = FALSE;
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
finished = TRUE;
}
else if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
{
finished = TRUE;
}
if (IsCryPlayingOrClearCrySongs())
finished = FALSE;
if (finished)
{
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3;
gBattlerControllerFuncs[battler] = Intro_DelayAndEnd;
}
}
static void WaitForMonAnimAfterLoad(u32 battler)
{
if (gSprites[gBattlerSpriteIds[battler]].animEnded && gSprites[gBattlerSpriteIds[battler]].x2 == 0)
@@ -262,37 +228,6 @@ static void LinkPartnerHandleHealthBarUpdate(u32 battler)
BtlController_HandleHealthBarUpdate(battler, FALSE);
}
// Also used by the link partner.
void Controller_PlayerPartnerShowIntroHealthbox(u32 battler)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive
&& gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy
&& ++gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay != 1)
{
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0;
TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]);
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], HEALTHBOX_ALL);
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
}
DestroySprite(&gSprites[gBattleControllerData[battler]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
gBattlerControllerFuncs[battler] = Intro_WaitForHealthbox;
}
}
static void LinkPartnerHandleIntroTrainerBallThrow(u32 battler)
{
u32 trainerPicId = LinkPlayerGetTrainerPicId(GetBattlerMultiplayerId(battler));

View File

@@ -291,21 +291,19 @@ static void Intro_TryShinyAnimShowHealthbox(u32 battler)
static void TryShinyAnimAfterMonAnim(u32 battler)
{
if (gSprites[gBattlerSpriteIds[battler]].animEnded == TRUE
&& gSprites[gBattlerSpriteIds[battler]].x2 == 0)
if (gSprites[gBattlerSpriteIds[battler]].x2 == 0
&& !gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
TryShinyAnimation(battler, &gEnemyParty[gBattlerPartyIndexes[battler]]);
if (gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy
&& gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim)
{
TryShinyAnimation(battler, &gEnemyParty[gBattlerPartyIndexes[battler]]);
}
else if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
{
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
OpponentBufferExecCompleted(battler);
}
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
OpponentBufferExecCompleted(battler);
}
}
@@ -330,7 +328,8 @@ static void SwitchIn_HandleSoundAndEnd(u32 battler)
static void SwitchIn_ShowHealthbox(u32 battler)
{
if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)
{
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
@@ -347,10 +346,14 @@ static void SwitchIn_ShowHealthbox(u32 battler)
static void SwitchIn_TryShinyAnim(u32 battler)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim && !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim)
{
TryShinyAnimation(battler, &gEnemyParty[gBattlerPartyIndexes[battler]]);
}
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
&& !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
{
DestroySprite(&gSprites[gBattleControllerData[battler]]);
SetBattlerShadowSpriteCallback(battler, GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES));

View File

@@ -0,0 +1,452 @@
#include "global.h"
#include "battle.h"
#include "battle_ai_main.h"
#include "battle_ai_util.h"
#include "battle_anim.h"
#include "battle_controllers.h"
#include "battle_message.h"
#include "battle_interface.h"
#include "battle_setup.h"
#include "battle_tower.h"
#include "battle_z_move.h"
#include "bg.h"
#include "data.h"
#include "item_use.h"
#include "link.h"
#include "main.h"
#include "m4a.h"
#include "palette.h"
#include "party_menu.h"
#include "pokeball.h"
#include "pokemon.h"
#include "reshow_battle_screen.h"
#include "sound.h"
#include "string_util.h"
#include "task.h"
#include "text.h"
#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"
static void PlayerPartnerHandleLoadMonSprite(u32 battler);
static void PlayerPartnerHandleSwitchInAnim(u32 battler);
static void PlayerPartnerHandleDrawTrainerPic(u32 battler);
static void PlayerPartnerHandleTrainerSlideBack(u32 battler);
static void PlayerPartnerHandleChooseAction(u32 battler);
static void PlayerPartnerHandleChooseMove(u32 battler);
static void PlayerPartnerHandleChoosePokemon(u32 battler);
static void PlayerPartnerHandleHealthBarUpdate(u32 battler);
static void PlayerPartnerHandleIntroTrainerBallThrow(u32 battler);
static void PlayerPartnerHandleDrawPartyStatusSummary(u32 battler);
static void PlayerPartnerHandleBattleAnimation(u32 battler);
static void PlayerPartnerHandleEndLinkBattle(u32 battler);
static void PlayerPartnerBufferRunCommand(u32 battler);
static void PlayerPartnerBufferExecCompleted(u32 battler);
static void SwitchIn_WaitAndEnd(u32 battler);
static void (*const sPlayerPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) =
{
[CONTROLLER_GETMONDATA] = BtlController_HandleGetMonData,
[CONTROLLER_GETRAWMONDATA] = BtlController_Empty,
[CONTROLLER_SETMONDATA] = BtlController_HandleSetMonData,
[CONTROLLER_SETRAWMONDATA] = BtlController_HandleSetRawMonData,
[CONTROLLER_LOADMONSPRITE] = PlayerPartnerHandleLoadMonSprite,
[CONTROLLER_SWITCHINANIM] = PlayerPartnerHandleSwitchInAnim,
[CONTROLLER_RETURNMONTOBALL] = BtlController_HandleReturnMonToBall,
[CONTROLLER_DRAWTRAINERPIC] = PlayerPartnerHandleDrawTrainerPic,
[CONTROLLER_TRAINERSLIDE] = BtlController_Empty,
[CONTROLLER_TRAINERSLIDEBACK] = PlayerPartnerHandleTrainerSlideBack,
[CONTROLLER_FAINTANIMATION] = BtlController_HandleFaintAnimation,
[CONTROLLER_PALETTEFADE] = BtlController_Empty,
[CONTROLLER_SUCCESSBALLTHROWANIM] = BtlController_Empty,
[CONTROLLER_BALLTHROWANIM] = BtlController_Empty,
[CONTROLLER_PAUSE] = BtlController_Empty,
[CONTROLLER_MOVEANIMATION] = BtlController_HandleMoveAnimation,
[CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString,
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty,
[CONTROLLER_CHOOSEACTION] = PlayerPartnerHandleChooseAction,
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty,
[CONTROLLER_CHOOSEMOVE] = PlayerPartnerHandleChooseMove,
[CONTROLLER_OPENBAG] = BtlController_Empty,
[CONTROLLER_CHOOSEPOKEMON] = PlayerPartnerHandleChoosePokemon,
[CONTROLLER_23] = BtlController_Empty,
[CONTROLLER_HEALTHBARUPDATE] = PlayerPartnerHandleHealthBarUpdate,
[CONTROLLER_EXPUPDATE] = PlayerHandleExpUpdate, // Partner's player gets experience the same way as the player.
[CONTROLLER_STATUSICONUPDATE] = BtlController_HandleStatusIconUpdate,
[CONTROLLER_STATUSANIMATION] = BtlController_HandleStatusAnimation,
[CONTROLLER_STATUSXOR] = BtlController_Empty,
[CONTROLLER_DATATRANSFER] = BtlController_Empty,
[CONTROLLER_DMA3TRANSFER] = BtlController_Empty,
[CONTROLLER_PLAYBGM] = BtlController_Empty,
[CONTROLLER_32] = BtlController_Empty,
[CONTROLLER_TWORETURNVALUES] = BtlController_Empty,
[CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty,
[CONTROLLER_ONERETURNVALUE] = BtlController_Empty,
[CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty,
[CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar,
[CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar,
[CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag,
[CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag,
[CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation,
[CONTROLLER_CANTSWITCH] = BtlController_Empty,
[CONTROLLER_PLAYSE] = BtlController_HandlePlaySE,
[CONTROLLER_PLAYFANFAREORBGM] = BtlController_HandlePlayFanfareOrBGM,
[CONTROLLER_FAINTINGCRY] = BtlController_HandleFaintingCry,
[CONTROLLER_INTROSLIDE] = BtlController_HandleIntroSlide,
[CONTROLLER_INTROTRAINERBALLTHROW] = PlayerPartnerHandleIntroTrainerBallThrow,
[CONTROLLER_DRAWPARTYSTATUSSUMMARY] = PlayerPartnerHandleDrawPartyStatusSummary,
[CONTROLLER_HIDEPARTYSTATUSSUMMARY] = BtlController_HandleHidePartyStatusSummary,
[CONTROLLER_ENDBOUNCE] = BtlController_Empty,
[CONTROLLER_SPRITEINVISIBILITY] = BtlController_HandleSpriteInvisibility,
[CONTROLLER_BATTLEANIMATION] = PlayerPartnerHandleBattleAnimation,
[CONTROLLER_LINKSTANDBYMSG] = BtlController_Empty,
[CONTROLLER_RESETACTIONMOVESELECTION] = BtlController_Empty,
[CONTROLLER_ENDLINKBATTLE] = PlayerPartnerHandleEndLinkBattle,
[CONTROLLER_DEBUGMENU] = BtlController_Empty,
[CONTROLLER_TERMINATOR_NOP] = BtlController_TerminatorNop
};
void SetControllerToPlayerPartner(u32 battler)
{
gBattlerControllerEndFuncs[battler] = PlayerPartnerBufferExecCompleted;
gBattlerControllerFuncs[battler] = PlayerPartnerBufferRunCommand;
}
static void PlayerPartnerBufferRunCommand(u32 battler)
{
if (gBattleControllerExecFlags & gBitTable[battler])
{
if (gBattleResources->bufferA[battler][0] < ARRAY_COUNT(sPlayerPartnerBufferCommands))
sPlayerPartnerBufferCommands[gBattleResources->bufferA[battler][0]](battler);
else
PlayerPartnerBufferExecCompleted(battler);
}
}
static void Intro_DelayAndEnd(u32 battler)
{
if (--gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay == (u8)-1)
{
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0;
BattleControllerComplete(battler);
}
}
static void Intro_WaitForHealthbox(u32 battler)
{
bool32 finished = FALSE;
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
finished = TRUE;
}
else
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
{
finished = TRUE;
}
}
if (IsCryPlayingOrClearCrySongs())
finished = FALSE;
if (finished)
{
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3;
gBattlerControllerFuncs[battler] = Intro_DelayAndEnd;
}
}
// Also used by the link partner.
void Controller_PlayerPartnerShowIntroHealthbox(u32 battler)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive
&& gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy
&& ++gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay != 1)
{
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0;
TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]);
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], HEALTHBOX_ALL);
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
}
DestroySprite(&gSprites[gBattleControllerData[battler]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
gBattlerControllerFuncs[battler] = Intro_WaitForHealthbox;
}
}
static void WaitForMonAnimAfterLoad(u32 battler)
{
if (gSprites[gBattlerSpriteIds[battler]].animEnded && gSprites[gBattlerSpriteIds[battler]].x2 == 0)
PlayerPartnerBufferExecCompleted(battler);
}
static void SwitchIn_ShowSubstitute(u32 battler)
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
{
CopyBattleSpriteInvisibility(battler);
if (gBattleSpritesDataPtr->battlerData[battler].behindSubstitute)
InitAndLaunchSpecialAnimation(battler, battler, battler, B_ANIM_MON_TO_SUBSTITUTE);
gBattlerControllerFuncs[battler] = SwitchIn_WaitAndEnd;
}
}
static void SwitchIn_WaitAndEnd(u32 battler)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].specialAnimActive
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)
{
PlayerPartnerBufferExecCompleted(battler);
}
}
static void SwitchIn_ShowHealthbox(u32 battler)
{
if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
{
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
CreateTask(Task_PlayerController_RestoreBgmAfterCry, 10);
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[battler]], battler);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
gBattlerControllerFuncs[battler] = SwitchIn_ShowSubstitute;
}
}
static void SwitchIn_TryShinyAnim(u32 battler)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
{
TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]);
}
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
{
DestroySprite(&gSprites[gBattleControllerData[battler]]);
gBattlerControllerFuncs[battler] = SwitchIn_ShowHealthbox;
}
}
static void PlayerPartnerBufferExecCompleted(u32 battler)
{
gBattlerControllerFuncs[battler] = PlayerPartnerBufferRunCommand;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
u8 playerId = GetMultiplayerId();
PrepareBufferDataTransferLink(battler, 2, 4, &playerId);
gBattleResources->bufferA[battler][0] = CONTROLLER_TERMINATOR_NOP;
}
else
{
gBattleControllerExecFlags &= ~gBitTable[battler];
}
}
static void PlayerPartnerHandleLoadMonSprite(u32 battler)
{
BtlController_HandleLoadMonSprite(battler, WaitForMonAnimAfterLoad);
}
static void PlayerPartnerHandleSwitchInAnim(u32 battler)
{
BtlController_HandleSwitchInAnim(battler, TRUE, SwitchIn_TryShinyAnim);
}
// some explanation here
// in emerald it's possible to have a tag battle in the battle frontier facilities with AI
// which use the front sprite for both the player and the partner as opposed to any other battles (including the one with Steven) that use the back pic as well as animate it
static void PlayerPartnerHandleDrawTrainerPic(u32 battler)
{
bool32 isFrontPic;
s16 xPos, yPos;
u32 trainerPicId;
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
{
trainerPicId = gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic;
xPos = 90;
yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
}
else if (IsAiVsAiBattle())
{
trainerPicId = GetTrainerPicFromId(gPartnerTrainerId);
xPos = 60;
yPos = 80;
}
else
{
trainerPicId = GetBattleTowerTrainerFrontSpriteId(gPartnerTrainerId);
xPos = 32;
yPos = 80;
}
// Use back pic only if the partner Steven or is custom.
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
isFrontPic = FALSE;
else
isFrontPic = TRUE;
BtlController_HandleDrawTrainerPic(battler, trainerPicId, isFrontPic, xPos, yPos, -1);
}
static void PlayerPartnerHandleTrainerSlideBack(u32 battler)
{
BtlController_HandleTrainerSlideBack(battler, 35, FALSE);
}
static void PlayerPartnerHandleChooseAction(u32 battler)
{
AI_TrySwitchOrUseItem(battler);
PlayerPartnerBufferExecCompleted(battler);
}
static void PlayerPartnerHandleChooseMove(u32 battler)
{
u8 chosenMoveId;
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]);
chosenMoveId = gBattleStruct->aiMoveOrAction[battler];
gBattlerTarget = gBattleStruct->aiChosenTarget[battler];
if (chosenMoveId == AI_CHOICE_SWITCH)
{
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, 0xFFFF);
}
else
{
if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED))
gBattlerTarget = battler;
if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH)
{
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
}
// If partner can and should use a gimmick (considering trainer data), do it
if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE
&& !(gBattleStruct->gimmick.usableGimmick[battler] == GIMMICK_Z_MOVE
&& !ShouldUseZMove(battler, gBattlerTarget, moveInfo->moves[chosenMoveId])))
{
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_GIMMICK) | (gBattlerTarget << 8));
}
else
{
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8));
}
}
PlayerPartnerBufferExecCompleted(battler);
}
static void PlayerPartnerHandleChoosePokemon(u32 battler)
{
s32 chosenMonId;
// Choosing Revival Blessing target
if ((gBattleResources->bufferA[battler][1] & 0xF) == PARTY_ACTION_CHOOSE_FAINTED_MON)
{
chosenMonId = gSelectedMonPartyId = GetFirstFaintedPartyIndex(battler);
}
// Switching out
else if (gBattleStruct->monToSwitchIntoId[battler] >= PARTY_SIZE || !IsValidForBattle(&gPlayerParty[gBattleStruct->monToSwitchIntoId[battler]]))
{
chosenMonId = GetMostSuitableMonToSwitchInto(battler, TRUE);
if (chosenMonId == PARTY_SIZE || !IsValidForBattle(&gPlayerParty[chosenMonId])) // just switch to the next mon
{
s32 firstId = (IsAiVsAiBattle()) ? 0 : (PARTY_SIZE / 2);
u32 battler1 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
u32 battler2 = IsDoubleBattle() ? GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT) : battler1;
for (chosenMonId = firstId; chosenMonId < PARTY_SIZE; chosenMonId++)
{
if (GetMonData(&gPlayerParty[chosenMonId], MON_DATA_HP) != 0
&& chosenMonId != gBattlerPartyIndexes[battler1]
&& chosenMonId != gBattlerPartyIndexes[battler2])
{
break;
}
}
}
*(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId;
}
else // Mon to switch out has been already chosen.
{
chosenMonId = gBattleStruct->monToSwitchIntoId[battler];
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
gBattleStruct->monToSwitchIntoId[battler] = chosenMonId;
}
BtlController_EmitChosenMonReturnValue(battler, BUFFER_B, chosenMonId, NULL);
PlayerPartnerBufferExecCompleted(battler);
}
static void PlayerPartnerHandleHealthBarUpdate(u32 battler)
{
BtlController_HandleHealthBarUpdate(battler, FALSE);
}
static void PlayerPartnerHandleIntroTrainerBallThrow(u32 battler)
{
const u32 *trainerPal;
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
trainerPal = gTrainerBackPicPaletteTable[gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].data;
else if (IsAiVsAiBattle())
trainerPal = gTrainerBackPicPaletteTable[GetTrainerPicFromId(gPartnerTrainerId)].data;
else
trainerPal = gTrainerBackPicPaletteTable[GetBattleTowerTrainerFrontSpriteId(gPartnerTrainerId)].data; // 2 vs 2 multi battle in Battle Frontier, load front sprite and pal.
BtlController_HandleIntroTrainerBallThrow(battler, 0xD6F9, trainerPal, 24, Controller_PlayerPartnerShowIntroHealthbox, StartAnimLinearTranslation);
}
static void PlayerPartnerHandleDrawPartyStatusSummary(u32 battler)
{
BtlController_HandleDrawPartyStatusSummary(battler, B_SIDE_PLAYER, TRUE);
}
static void PlayerPartnerHandleBattleAnimation(u32 battler)
{
BtlController_HandleBattleAnimation(battler, FALSE);
}
static void PlayerPartnerHandleEndLinkBattle(u32 battler)
{
gBattleOutcome = gBattleResources->bufferA[battler][1];
FadeOutMapMusic(5);
BeginFastPaletteFade(3);
PlayerPartnerBufferExecCompleted(battler);
gBattlerControllerFuncs[battler] = SetBattleEndCallbacks;
}

View File

@@ -129,9 +129,56 @@ static void InitSinglePlayerBtlControllers(void)
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
// TODO:
DebugPrintfLevel(MGBA_LOG_ERROR, "BATTLE_TYPE_INGAME_PARTNER not implemented");
return;
gBattleMainFunc = BeginBattleIntro;
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
{
gBattlerControllerFuncs[0] = SetControllerToRecordedPlayer;
gBattlerPositions[0] = B_POSITION_PLAYER_LEFT;
gBattlerControllerFuncs[1] = SetControllerToOpponent;
gBattlerPositions[1] = B_POSITION_OPPONENT_LEFT;
gBattlerControllerFuncs[2] = SetControllerToPlayerPartner;
gBattlerPositions[2] = B_POSITION_PLAYER_RIGHT;
gBattlerControllerFuncs[3] = SetControllerToOpponent;
gBattlerPositions[3] = B_POSITION_OPPONENT_RIGHT;
}
else
{
gBattlerControllerFuncs[0] = SetControllerToPlayer;
gBattlerPositions[0] = B_POSITION_PLAYER_LEFT;
gBattlerControllerFuncs[1] = SetControllerToOpponent;
gBattlerPositions[1] = B_POSITION_OPPONENT_LEFT;
gBattlerControllerFuncs[2] = SetControllerToPlayerPartner;
gBattlerPositions[2] = B_POSITION_PLAYER_RIGHT;
gBattlerControllerFuncs[3] = SetControllerToOpponent;
gBattlerPositions[3] = B_POSITION_OPPONENT_RIGHT;
}
gBattlersCount = MAX_BATTLERS_COUNT;
BufferBattlePartyCurrentOrderBySide(0, 0);
BufferBattlePartyCurrentOrderBySide(1, 0);
BufferBattlePartyCurrentOrderBySide(2, 1);
BufferBattlePartyCurrentOrderBySide(3, 1);
gBattlerPartyIndexes[0] = 0;
gBattlerPartyIndexes[1] = 0;
if (BATTLE_TWO_VS_ONE_OPPONENT || WILD_DOUBLE_BATTLE)
{
gBattlerPartyIndexes[2] = 3;
gBattlerPartyIndexes[3] = 1;
}
else
{
gBattlerPartyIndexes[2] = 3;
gBattlerPartyIndexes[3] = 3;
}
}
else if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
{
@@ -141,9 +188,8 @@ static void InitSinglePlayerBtlControllers(void)
gBattlerControllerFuncs[0] = SetControllerToSafari;
else if (gBattleTypeFlags & (BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
gBattlerControllerFuncs[0] = SetControllerToOakOrOldMan;
// TODO:
// else if (IsAiVsAiBattle())
// gBattlerControllerFuncs[0] = SetControllerToPlayerPartner;
else if (IsAiVsAiBattle())
gBattlerControllerFuncs[0] = SetControllerToPlayerPartner;
else
gBattlerControllerFuncs[0] = SetControllerToPlayer;
@@ -195,20 +241,18 @@ static void InitSinglePlayerBtlControllers(void)
{
gBattleMainFunc = BeginBattleIntro;
// TODO: Partner battle
// if (IsAiVsAiBattle())
// gBattlerControllerFuncs[0] = SetControllerToPlayerPartner;
// else
if (IsAiVsAiBattle())
gBattlerControllerFuncs[0] = SetControllerToPlayerPartner;
else
gBattlerControllerFuncs[0] = SetControllerToPlayer;
gBattlerPositions[0] = B_POSITION_PLAYER_LEFT;
gBattlerControllerFuncs[1] = SetControllerToOpponent;
gBattlerPositions[1] = B_POSITION_OPPONENT_LEFT;
// TODO: Partner battle
// if (IsAiVsAiBattle())
// gBattlerControllerFuncs[2] = SetControllerToPlayerPartner;
// else
if (IsAiVsAiBattle())
gBattlerControllerFuncs[2] = SetControllerToPlayerPartner;
else
gBattlerControllerFuncs[2] = SetControllerToPlayer;
gBattlerPositions[2] = B_POSITION_PLAYER_RIGHT;

View File

@@ -62,7 +62,9 @@ static void HandleEndTurn_MonFled(void);
static void HandleEndTurn_FinishBattle(void);
static void CB2_InitBattleInternal(void);
static void CB2_PreInitMultiBattle(void);
static void CB2_PreInitIngamePlayerPartnerBattle(void);
static void CB2_HandleStartMultiBattle(void);
static void CB2_HandleStartMultiPartnerBattle(void);
static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer);
static void CB2_HandleStartBattle(void);
static void TryCorrectShedinjaLanguage(struct Pokemon *mon);
@@ -115,6 +117,7 @@ EWRAM_DATA u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT + 13] = {0}; // expanded
EWRAM_DATA u32 gBattleTypeFlags = 0;
EWRAM_DATA u8 gBattleTerrain = 0;
EWRAM_DATA struct MultiPartnerMenuPokemon gMultiPartnerParty[MULTI_PARTY_SIZE] = {0};
EWRAM_DATA static struct MultiPartnerMenuPokemon* sMultiPartnerPartyBuffer = NULL;
EWRAM_DATA u8 *gBattleAnimBgTileBuffer = NULL;
EWRAM_DATA u8 *gBattleAnimBgTilemapBuffer = NULL;
EWRAM_DATA u32 gBattleControllerExecFlags = 0;
@@ -448,7 +451,7 @@ void CB2_InitBattle(void)
}
else
{
// SetMainCallback2(CB2_PreInitIngamePlayerPartnerBattle);
SetMainCallback2(CB2_PreInitIngamePlayerPartnerBattle);
}
gBattleCommunication[MULTIUSE_STATE] = 0;
}
@@ -554,7 +557,11 @@ static void CB2_InitBattleInternal(void)
SetVBlankCallback(VBlankCB_Battle);
SetUpBattleVars();
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
SetMainCallback2(CB2_HandleStartMultiPartnerBattle);
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
SetMainCallback2(CB2_HandleStartMultiPartnerBattle);
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
SetMainCallback2(CB2_HandleStartMultiBattle);
else
SetMainCallback2(CB2_HandleStartBattle);
@@ -987,6 +994,35 @@ static void PrepareOwnMultiPartnerBuffer(void)
memcpy(gBattleStruct->multiBuffer.multiBattleMons, gMultiPartnerParty, sizeof(gMultiPartnerParty));
}
static void SetMultiPartnerMenuParty(u8 offset)
{
s32 i, j;
u8 *cur;
for (i = 0; i < MULTI_PARTY_SIZE; i++)
{
gMultiPartnerParty[i].species = GetMonData(&gPlayerParty[offset + i], MON_DATA_SPECIES);
gMultiPartnerParty[i].heldItem = GetMonData(&gPlayerParty[offset + i], MON_DATA_HELD_ITEM);
GetMonData(&gPlayerParty[offset + i], MON_DATA_NICKNAME, gMultiPartnerParty[i].nickname);
gMultiPartnerParty[i].level = GetMonData(&gPlayerParty[offset + i], MON_DATA_LEVEL);
gMultiPartnerParty[i].hp = GetMonData(&gPlayerParty[offset + i], MON_DATA_HP);
gMultiPartnerParty[i].maxhp = GetMonData(&gPlayerParty[offset + i], MON_DATA_MAX_HP);
gMultiPartnerParty[i].status = GetMonData(&gPlayerParty[offset + i], MON_DATA_STATUS);
gMultiPartnerParty[i].personality = GetMonData(&gPlayerParty[offset + i], MON_DATA_PERSONALITY);
gMultiPartnerParty[i].gender = GetMonGender(&gPlayerParty[offset + i]);
StripExtCtrlCodes(gMultiPartnerParty[i].nickname);
if (GetMonData(&gPlayerParty[offset + i], MON_DATA_LANGUAGE) != LANGUAGE_JAPANESE)
{
for (cur = gMultiPartnerParty[i].nickname, j = 0; cur[j] != EOS; j++)
;
while (j < 6)
cur[j++] = 0;
cur[j] = EOS;
}
}
memcpy(sMultiPartnerPartyBuffer, gMultiPartnerParty, sizeof(gMultiPartnerParty));
}
static void CB2_PreInitMultiBattle(void)
{
s32 i;
@@ -1062,41 +1098,41 @@ static void CB2_PreInitMultiBattle(void)
}
}
// static void CB2_PreInitIngamePlayerPartnerBattle(void)
// {
// u32 *savedBattleTypeFlags;
// void (**savedCallback)(void);
static void CB2_PreInitIngamePlayerPartnerBattle(void)
{
u32 *savedBattleTypeFlags;
void (**savedCallback)(void);
// savedCallback = &gBattleStruct->savedCallback;
// savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags;
savedCallback = &gBattleStruct->savedCallback;
savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags;
// RunTasks();
// AnimateSprites();
// BuildOamBuffer();
RunTasks();
AnimateSprites();
BuildOamBuffer();
// switch (gBattleCommunication[MULTIUSE_STATE])
// {
// case 0:
// sMultiPartnerPartyBuffer = Alloc(sizeof(gMultiPartnerParty));
// SetMultiPartnerMenuParty(MULTI_PARTY_SIZE);
// gBattleCommunication[MULTIUSE_STATE]++;
// *savedCallback = gMain.savedCallback;
// *savedBattleTypeFlags = gBattleTypeFlags;
// gMain.savedCallback = CB2_PreInitIngamePlayerPartnerBattle;
// ShowPartyMenuToShowcaseMultiBattleParty();
// break;
// case 1:
// if (!gPaletteFade.active)
// {
// gBattleCommunication[MULTIUSE_STATE] = 2;
// gBattleTypeFlags = *savedBattleTypeFlags;
// gMain.savedCallback = *savedCallback;
// SetMainCallback2(CB2_InitBattleInternal);
// FREE_AND_SET_NULL(sMultiPartnerPartyBuffer);
// }
// break;
// }
// }
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
sMultiPartnerPartyBuffer = Alloc(sizeof(gMultiPartnerParty));
SetMultiPartnerMenuParty(MULTI_PARTY_SIZE);
gBattleCommunication[MULTIUSE_STATE]++;
*savedCallback = gMain.savedCallback;
*savedBattleTypeFlags = gBattleTypeFlags;
gMain.savedCallback = CB2_PreInitIngamePlayerPartnerBattle;
ShowPartyMenuToShowcaseMultiBattleParty();
break;
case 1:
if (!gPaletteFade.active)
{
gBattleCommunication[MULTIUSE_STATE] = 2;
gBattleTypeFlags = *savedBattleTypeFlags;
gMain.savedCallback = *savedCallback;
SetMainCallback2(CB2_InitBattleInternal);
FREE_AND_SET_NULL(sMultiPartnerPartyBuffer);
}
break;
}
}
static void CB2_HandleStartMultiBattle(void)
{
@@ -1361,6 +1397,255 @@ static void CB2_HandleStartMultiBattle(void)
}
}
static void CB2_HandleStartMultiPartnerBattle(void)
{
u8 playerMultiplayerId;
u8 partnerMultiplayerId;
RunTasks();
AnimateSprites();
BuildOamBuffer();
playerMultiplayerId = GetMultiplayerId();
gBattleScripting.multiplayerId = playerMultiplayerId;
partnerMultiplayerId = playerMultiplayerId ^ BIT_SIDE;
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
if (!IsDma3ManagerBusyWithBgCopy())
{
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
BattleInterfaceSetWindowPals();
gBattleCommunication[MULTIUSE_STATE] = 1;
}
if (gWirelessCommType)
LoadWirelessStatusIndicatorSpriteGfx();
// fall through
case 1:
// if (gBattleTypeFlags & BATTLE_TYPE_LINK)
// {
// if (gReceivedRemoteLinkPlayers)
// {
// u8 language;
// gLinkPlayers[0].id = 0;
// gLinkPlayers[1].id = 2;
// gLinkPlayers[2].id = 1;
// gLinkPlayers[3].id = 3;
// GetFrontierTrainerName(gLinkPlayers[2].name, gTrainerBattleOpponent_A);
// GetFrontierTrainerName(gLinkPlayers[3].name, gTrainerBattleOpponent_B);
// GetBattleTowerTrainerLanguage(&language, gTrainerBattleOpponent_A);
// gLinkPlayers[2].language = language;
// GetBattleTowerTrainerLanguage(&language, gTrainerBattleOpponent_B);
// gLinkPlayers[3].language = language;
// if (IsLinkTaskFinished())
// {
// // 0x300
// *(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureLo) = 0;
// *(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureHi) = 3;
// BufferPartyVsScreenHealth_AtStart();
// SetPlayerBerryDataInBattleStruct();
// SendBlock(BitmaskAllOtherLinkPlayers(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
// gBattleCommunication[MULTIUSE_STATE] = 2;
// }
// if (gWirelessCommType)
// CreateWirelessStatusIndicatorSprite(0, 0);
// }
// }
// else
// {
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
gBattleTypeFlags |= BATTLE_TYPE_IS_MASTER;
gBattleCommunication[MULTIUSE_STATE] = 13;
SetAllPlayersBerryData();
// }
break;
case 2:
if ((GetBlockReceivedStatus() & 3) == 3)
{
u8 taskId;
ResetBlockReceivedFlags();
LinkBattleComputeBattleTypeFlags(2, playerMultiplayerId);
SetAllPlayersBerryData();
taskId = CreateTask(InitLinkBattleVsScreen, 0);
gTasks[taskId].data[1] = 0x10E;
gTasks[taskId].data[2] = 0x5A;
gTasks[taskId].data[5] = 0;
gTasks[taskId].data[3] = 0x145;
gTasks[taskId].data[4] = 0x145;
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 3:
// Link battle, send/receive party Pokémon in groups
if (IsLinkTaskFinished())
{
// Send Pokémon 1-2
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if ((GetBlockReceivedStatus() & 3) == 3)
{
// Recv partner's Pokémon 1-2, and copy partner's and own Pokémon into party positions
ResetBlockReceivedFlags();
if (gLinkPlayers[playerMultiplayerId].id != 0)
{
memcpy(gPlayerParty, gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon) * 2);
memcpy(&gPlayerParty[MULTI_PARTY_SIZE], gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2);
}
else
{
memcpy(gPlayerParty, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2);
memcpy(&gPlayerParty[MULTI_PARTY_SIZE], gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon) * 2);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 5:
if (IsLinkTaskFinished())
{
// Send Pokémon 3
SendBlock(BitmaskAllOtherLinkPlayers(), &gPlayerParty[2], sizeof(struct Pokemon));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 6:
if ((GetBlockReceivedStatus() & 3) == 3)
{
// Recv partner's Pokémon 3, and copy partner's and own Pokémon into party positions
ResetBlockReceivedFlags();
if (gLinkPlayers[playerMultiplayerId].id != 0)
{
memcpy(&gPlayerParty[2], gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon));
memcpy(&gPlayerParty[2 + MULTI_PARTY_SIZE], gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon));
}
else
{
memcpy(&gPlayerParty[2], gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon));
memcpy(&gPlayerParty[2 + MULTI_PARTY_SIZE], gBlockRecvBuffer[partnerMultiplayerId], sizeof(struct Pokemon));
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
if (IsLinkTaskFinished())
{
// Send enemy Pokémon 1-2 to partner
SendBlock(BitmaskAllOtherLinkPlayers(), gEnemyParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
if ((GetBlockReceivedStatus() & 3) == 3)
{
// Recv enemy Pokémon 1-2 (if not master)
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
memcpy(gEnemyParty, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 9:
if (IsLinkTaskFinished())
{
// Send enemy Pokémon 3-4 to partner
SendBlock(BitmaskAllOtherLinkPlayers(), &gEnemyParty[2], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 10:
if ((GetBlockReceivedStatus() & 3) == 3)
{
// Recv enemy Pokémon 3-4 (if not master)
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
memcpy(&gEnemyParty[2], gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 11:
if (IsLinkTaskFinished())
{
// Send enemy Pokémon 5-6 to partner
SendBlock(BitmaskAllOtherLinkPlayers(), &gEnemyParty[4], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 12:
if ((GetBlockReceivedStatus() & 3) == 3)
{
// Recv enemy Pokémon 5-6 (if not master)
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
memcpy(&gEnemyParty[4], gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
TryCorrectShedinjaLanguage(&gPlayerParty[0]);
TryCorrectShedinjaLanguage(&gPlayerParty[1]);
TryCorrectShedinjaLanguage(&gPlayerParty[2]);
TryCorrectShedinjaLanguage(&gPlayerParty[3]);
TryCorrectShedinjaLanguage(&gPlayerParty[4]);
TryCorrectShedinjaLanguage(&gPlayerParty[5]);
TryCorrectShedinjaLanguage(&gEnemyParty[0]);
TryCorrectShedinjaLanguage(&gEnemyParty[1]);
TryCorrectShedinjaLanguage(&gEnemyParty[2]);
TryCorrectShedinjaLanguage(&gEnemyParty[3]);
TryCorrectShedinjaLanguage(&gEnemyParty[4]);
TryCorrectShedinjaLanguage(&gEnemyParty[5]);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 13:
InitBattleControllers();
RecordedBattle_SetTrainerInfo();
gBattleCommunication[SPRITES_INIT_STATE1] = 0;
gBattleCommunication[SPRITES_INIT_STATE2] = 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
gBattleCommunication[MULTIUSE_STATE] = 14;
else
gBattleCommunication[MULTIUSE_STATE] = 16;
break;
case 14:
// Send rng seed for recorded battle
if (IsLinkTaskFinished())
{
SendBlock(BitmaskAllOtherLinkPlayers(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 15:
// Receive rng seed for recorded battle (only read it if partner is the link master)
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (!(gBattleTypeFlags & BATTLE_TYPE_IS_MASTER))
memcpy(&gRecordedBattleRngSeed, gBlockRecvBuffer[partnerMultiplayerId], sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 16:
// Finish, start battle
if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2]))
{
// TrySetLinkBattleTowerEnemyPartyLevel();
gPreBattleCallback1 = gMain.callback1;
gMain.callback1 = BattleMainCB1;
SetMainCallback2(BattleMainCB2);
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
gBattleTypeFlags |= BATTLE_TYPE_LINK_IN_BATTLE;
}
break;
}
}
void BattleMainCB2(void)
{
AnimateSprites();

View File

@@ -2825,6 +2825,10 @@ static const u8 *BattleStringGetPlayerName(u8 *text, u8 battler)
{
toCpy = gLinkPlayers[2].name;
}
else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
toCpy = gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName;
}
else
{
toCpy = gSaveBlock2Ptr->playerName;
@@ -2922,12 +2926,10 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
case B_TXT_PARTNER_CLASS:
// TODO: trainer name
// toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name;
toCpy = gText_TODO;
toCpy = gTrainerClasses[gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass].name;;
break;
case B_TXT_PARTNER_NAME:
// TODO: trainer name
// toCpy = BattleStringGetPlayerName(text, GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT));
toCpy = gText_TODO;
toCpy = BattleStringGetPlayerName(text, GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT));
break;
case B_TXT_COPY_VAR_1:
toCpy = gStringVar1;

View File

@@ -1,5 +1,6 @@
#include "global.h"
#include "task.h"
#include "battle_setup.h"
#include "help_system.h"
#include "overworld.h"
#include "item.h"
@@ -62,8 +63,6 @@ static void DoSafariBattle(void);
static void DoGhostBattle(void);
static void DoStandardWildBattle(bool32 isDouble);
static void CB2_EndWildBattle(void);
static u8 GetWildBattleTransition(void);
static u8 GetTrainerBattleTransition(void);
static void CB2_EndScriptedWildBattle(void);
static void CB2_EndMarowakBattle(void);
static bool32 IsPlayerDefeated(u32 battleOutcome);
@@ -681,7 +680,7 @@ static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons)
return sum;
}
static u8 GetWildBattleTransition(void)
u8 GetWildBattleTransition(void)
{
u8 transitionType = GetBattleTransitionTypeByMap();
u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL);
@@ -693,7 +692,7 @@ static u8 GetWildBattleTransition(void)
return sBattleTransitionTable_Wild[transitionType][1];
}
static u8 GetTrainerBattleTransition(void)
u8 GetTrainerBattleTransition(void)
{
u8 minPartyCount;
u8 transitionType;
@@ -880,7 +879,8 @@ static void SetMapVarsToTrainer(void)
const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data)
{
InitTrainerBattleVariables();
if (TrainerBattleLoadArg8(data) != TRAINER_BATTLE_SET_TRAINER_B)
InitTrainerBattleVariables();
sTrainerBattleMode = TrainerBattleLoadArg8(data);
switch (sTrainerBattleMode)
{
@@ -916,6 +916,12 @@ const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data)
case TRAINER_BATTLE_EARLY_RIVAL:
TrainerBattleLoadArgs(sEarlyRivalBattleParams, data);
return EventScript_DoNoIntroTrainerBattle;
case TRAINER_BATTLE_SET_TRAINER_A:
TrainerBattleLoadArgs(sOrdinaryBattleParams, data);
return sTrainerBattleEndScript;
case TRAINER_BATTLE_SET_TRAINER_B:
TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data);
return sTrainerBattleEndScript;
default:
if (gApproachingTrainerId == 0)
{

View File

@@ -19,6 +19,7 @@
#include "save.h"
#include "item.h"
#include "script_pokemon_util.h"
#include "constants/abilities.h"
#include "constants/items.h"
#include "constants/moves.h"
#include "constants/pokemon.h"
@@ -984,7 +985,7 @@ void SetBattleTowerParty(void)
for (i = 0; i < 3; i++)
gSelectedOrderFromParty[i] = gSaveBlock2Ptr->battleTower.selectedPartyMons[i];
ReducePlayerPartyToThree();
ReducePlayerPartyToSelectedMons();
}
static void SaveCurrentWinStreak(void)
@@ -1292,3 +1293,165 @@ void Dummy_TryEnableBravoTrainerBattleTower(void)
TakeBravoTrainerBattleTowerOffTheAir();
}
}
#define STEVEN_OTID 61226
static void FillPartnerParty(u16 trainerId)
{
s32 i, j, k;
u32 firstIdPart = 0, secondIdPart = 0, thirdIdPart = 0;
u32 personality;
u32 otID;
u8 trainerName[(PLAYER_NAME_LENGTH * 3) + 1];
s32 ball = -1;
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
{
for (i = 0; i < 3; i++)
ZeroMonData(&gPlayerParty[i + 3]);
for (i = 0; i < 3 && i < gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].partySize; i++)
{
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();
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[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName);
SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_NAME, trainerName);
j = gBattlePartners[SanitizeTrainerId(trainerId - TRAINER_PARTNER(PARTNER_NONE))].encounterMusic_gender >> 7;
SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_GENDER, &j);
}
}
}
static void HandleSpecialTrainerBattleEnd(void)
{
s32 i;
switch (gBattleScripting.specialTrainerBattleType)
{
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)
{
gBattleScripting.specialTrainerBattleType = gSpecialVar_0x8004;
switch (gSpecialVar_0x8004)
{
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
{
gTrainerBattleOpponent_B = 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;
}
gPartnerTrainerId = VarGet(gSpecialVar_0x8006) + TRAINER_PARTNER(PARTNER_NONE);
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;
}
}

View File

@@ -656,7 +656,7 @@ static void Task_StartWiredCableClubBattle(u8 taskId)
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE;
break;
case USING_MULTI_BATTLE:
ReducePlayerPartyToThree();
ReducePlayerPartyToSelectedMons();
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI;
break;
}
@@ -729,7 +729,7 @@ static void Task_StartWirelessCableClubBattle(u8 taskId)
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE;
break;
case USING_MULTI_BATTLE:
ReducePlayerPartyToThree();
ReducePlayerPartyToSelectedMons();
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI;
break;
}

View File

@@ -93,6 +93,14 @@ const struct SpriteFrameImage gTrainerBackPicTable_RSMay[] =
{gTrainerBackPic_RSMay + 0x1800, 0x0800},
};
const struct SpriteFrameImage gTrainerBackPicTable_Steven[] =
{
{gTrainerBackPic_Steven + TRAINER_PIC_SIZE * 0, TRAINER_PIC_SIZE},
{gTrainerBackPic_Steven + TRAINER_PIC_SIZE * 1, TRAINER_PIC_SIZE},
{gTrainerBackPic_Steven + TRAINER_PIC_SIZE * 2, TRAINER_PIC_SIZE},
{gTrainerBackPic_Steven + TRAINER_PIC_SIZE * 3, TRAINER_PIC_SIZE},
};
const union AnimCmd sAnim_GeneralFrame0[] =
{
ANIMCMD_FRAME(0, 0),

View File

@@ -8,13 +8,61 @@ const struct Trainer gBattlePartners[] = {
.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"),
// },
[PARTNER_STEVEN] =
{
.trainerName = _("STEVEN"),
.trainerClass = TRAINER_CLASS_RIVAL_LATE,
.trainerPic = TRAINER_BACK_PIC_STEVEN,
.encounterMusic_gender =
TRAINER_ENCOUNTER_MUSIC_MALE,
.partySize = 3,
.party = (const struct TrainerMon[])
{
{
.species = SPECIES_METANG,
.gender = TRAINER_MON_RANDOM_GENDER,
.ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0),
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
.lvl = 42,
.nature = NATURE_BRAVE,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
MOVE_LIGHT_SCREEN,
MOVE_PSYCHIC,
MOVE_REFLECT,
MOVE_METAL_CLAW,
},
},
{
.species = SPECIES_SKARMORY,
.gender = TRAINER_MON_RANDOM_GENDER,
.ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252),
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
.lvl = 43,
.nature = NATURE_IMPISH,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
MOVE_TOXIC,
MOVE_AERIAL_ACE,
MOVE_PROTECT,
MOVE_STEEL_WING,
},
},
{
.species = SPECIES_AGGRON,
.gender = TRAINER_MON_RANDOM_GENDER,
.ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6),
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
.lvl = 44,
.nature = NATURE_ADAMANT,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
MOVE_THUNDER,
MOVE_PROTECT,
MOVE_SOLAR_BEAM,
MOVE_DRAGON_CLAW,
},
},
},
},
};

View File

@@ -446,6 +446,7 @@ const u8 gTrainerBackPic_Red[] = INCBIN_U8("graphics/trainers/back_pics/red_back
const u8 gTrainerBackPic_Leaf[] = INCBIN_U8("graphics/trainers/back_pics/leaf_back_pic.4bpp");
const u8 gTrainerBackPic_Pokedude[] = INCBIN_U8("graphics/trainers/back_pics/pokedude_back_pic.4bpp");
const u8 gTrainerBackPic_OldMan[] = INCBIN_U8("graphics/trainers/back_pics/old_man_back_pic.4bpp");
const u8 gTrainerBackPic_Steven[] = INCBIN_U8("graphics/trainers/back_pics/steven.4bpp");
const u8 gTrainerBackPic_RSBrendan[] = INCBIN_U8("graphics/trainers/back_pics/ruby_sapphire_brendan_back_pic.4bpp");
const u8 gTrainerBackPic_RSMay[] = INCBIN_U8("graphics/trainers/back_pics/ruby_sapphire_may_back_pic.4bpp");
@@ -454,3 +455,4 @@ const u32 gTrainerPalette_RedBackPic[] = INCBIN_U32("graphics/trainers/palettes/
const u32 gTrainerPalette_LeafBackPic[] = INCBIN_U32("graphics/trainers/palettes/leaf_back_pic.gbapal.lz");
const u32 gTrainerPalette_PokedudeBackPic[] = INCBIN_U32("graphics/trainers/palettes/pokedude_back_pic.gbapal.lz");
const u32 gTrainerPalette_OldManBackPic[] = INCBIN_U32("graphics/trainers/palettes/old_man_back_pic.gbapal.lz");
const u32 gTrainerPalette_Steven[] = INCBIN_U32("graphics/trainers/palettes/steven.gbapal.lz");

View File

@@ -50,6 +50,26 @@ static const union AnimCmd sAnimCmd_RSMay_1[] = {
ANIMCMD_END
};
static const union AnimCmd sAnimCmd_Hoenn[] =
{
ANIMCMD_FRAME(0, 24),
ANIMCMD_FRAME(1, 9),
ANIMCMD_FRAME(2, 24),
ANIMCMD_FRAME(0, 9),
ANIMCMD_FRAME(3, 50),
ANIMCMD_END,
};
static const union AnimCmd sAnimCmd_Point_HGSS[] =
{
ANIMCMD_FRAME(3, 9),
ANIMCMD_FRAME(0, 9),
ANIMCMD_FRAME(2, 24),
ANIMCMD_FRAME(2, 24),
ANIMCMD_FRAME(3, 50),
ANIMCMD_END,
};
const union AnimCmd *const sBackAnims_Red[] = {
sAnim_GeneralFrame0,
sAnimCmd_Red_1
@@ -80,11 +100,19 @@ const union AnimCmd *const sBackAnims_RSMay[] = {
sAnimCmd_RSMay_1
};
static const union AnimCmd *const sBackAnims_Hoenn[] =
{
sAnim_GeneralFrame3,
sAnimCmd_Hoenn,
sAnimCmd_Point_HGSS,
};
const union AnimCmd *const *const gTrainerBackAnimsPtrTable[] = {
sBackAnims_Red,
sBackAnims_Leaf,
sBackAnims_RSBrendan,
sBackAnims_RSMay,
sBackAnims_Pokedude,
sBackAnims_OldMan
sBackAnims_OldMan,
sBackAnims_Hoenn,
};

View File

@@ -4,7 +4,8 @@ const struct MonCoords gTrainerBackPicCoords[] = {
[TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN] = {.size = 8, .y_offset = 4},
[TRAINER_BACK_PIC_RUBY_SAPPHIRE_MAY] = {.size = 8, .y_offset = 4},
[TRAINER_BACK_PIC_POKEDUDE] = {.size = 8, .y_offset = 4},
[TRAINER_BACK_PIC_OLD_MAN] = {.size = 8, .y_offset = 4}
[TRAINER_BACK_PIC_OLD_MAN] = {.size = 8, .y_offset = 4},
[TRAINER_BACK_PIC_STEVEN] = {.size = 8, .y_offset = 4},
};
const struct CompressedSpriteSheet gTrainerBackPicTable[] = {
@@ -13,7 +14,8 @@ const struct CompressedSpriteSheet gTrainerBackPicTable[] = {
{ (const u32 *)gTrainerBackPic_RSBrendan, 0x2000, 2 },
{ (const u32 *)gTrainerBackPic_RSMay, 0x2000, 3 },
{ (const u32 *)gTrainerBackPic_Pokedude, 0x2000, 4 },
{ (const u32 *)gTrainerBackPic_OldMan, 0x2000, 5 }
{ (const u32 *)gTrainerBackPic_OldMan, 0x2000, 5 },
{ (const u32 *)gTrainerBackPic_Steven, 0x2000, 6 },
};
const struct CompressedSpritePalette gTrainerBackPicPaletteTable[] = {
@@ -22,5 +24,6 @@ const struct CompressedSpritePalette gTrainerBackPicPaletteTable[] = {
{ gTrainerPalette_RSBrendan1, 2 },
{ gTrainerPalette_RSMay1, 3 },
{ gTrainerPalette_PokedudeBackPic, 4 },
{ gTrainerPalette_OldManBackPic, 5 }
{ gTrainerPalette_OldManBackPic, 5 },
{ gTrainerPalette_Steven, 6 },
};

View File

@@ -427,7 +427,7 @@ EWRAM_DATA MainCallback gPostMenuFieldCallback = NULL;
static EWRAM_DATA u16 *sSlot1TilemapBuffer = NULL; // for switching party slots
static EWRAM_DATA u16 *sSlot2TilemapBuffer = NULL;
static EWRAM_DATA struct Pokemon *sSacredAshQuestLogMonBackup = NULL;
EWRAM_DATA u8 gSelectedOrderFromParty[3] = {0};
EWRAM_DATA u8 gSelectedOrderFromParty[MAX_FRONTIER_PARTY_SIZE] = {0};
static EWRAM_DATA u16 sPartyMenuItemId = ITEM_NONE;
ALIGNED(4) EWRAM_DATA u8 gBattlePartyCurrentOrder[PARTY_SIZE / 2] = {0}; // bits 0-3 are the current pos of Slot 1, 4-7 are Slot 2, and so on
@@ -1226,7 +1226,7 @@ static void DrawCancelConfirmButtons(void)
bool8 IsMultiBattle(void)
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattleTypeFlags & BATTLE_TYPE_LINK)
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gMain.inBattle)
return TRUE;
else
return FALSE;

View File

@@ -546,7 +546,7 @@ u8 DoPokeballSendOutAnimation(u32 battler, s16 pan, u8 kindOfThrow)
static void Task_DoPokeballSendOutAnim(u8 taskId)
{
u32 throwCaseId, battlerId, ballId, ballSpriteId;
u32 throwCaseId, ballId, battlerId, ballSpriteId;
bool32 notSendOut = FALSE;
u32 throwXoffset = (B_ENEMY_THROW_BALLS >= GEN_6) ? 24 : 0;
s32 throwYoffset = (B_ENEMY_THROW_BALLS >= GEN_6) ? -16 : 24;
@@ -990,7 +990,7 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
if ((battlerId == GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) || battlerId == GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT))
&& IsDoubleBattle() && gBattleSpritesDataPtr->animationData->introAnimActive)
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (IsBGMPlaying())
m4aMPlayStop(&gMPlayInfo_BGM);
@@ -1033,6 +1033,7 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
gSprites[gBattlerSpriteIds[sprite->sBattler]].callback = SpriteCB_OpponentMonFromBall;
else
gSprites[gBattlerSpriteIds[sprite->sBattler]].callback = SpriteCB_PlayerMonFromBall;
AnimateSprite(&gSprites[gBattlerSpriteIds[sprite->sBattler]]);
gSprites[gBattlerSpriteIds[sprite->sBattler]].data[1] = 0x1000;
}
@@ -1208,6 +1209,8 @@ static void SpriteCB_MonSendOut_2(struct Sprite *sprite)
}
}
#undef HIBYTE
static void SpriteCB_ReleaseMon2FromBall(struct Sprite *sprite)
{
if (sprite->data[0]++ > 24)

View File

@@ -993,6 +993,15 @@ static const struct SpriteTemplate sTrainerBackSpriteTemplates[] =
.affineAnims = gAffineAnims_BattleSpritePlayerSide,
.callback = SpriteCB_AllyMon,
},
[TRAINER_BACK_PIC_STEVEN] = {
.tileTag = TAG_NONE,
.paletteTag = 0,
.oam = &gOamData_BattlerPlayer,
.anims = NULL,
.images = gTrainerBackPicTable_Steven,
.affineAnims = gAffineAnims_BattleSpritePlayerSide,
.callback = SpriteCB_AllyMon,
},
};
// Classes dummied out
@@ -5685,10 +5694,17 @@ bool8 IsMonShiny(struct Pokemon *mon)
return GetMonData(mon, MON_DATA_IS_SHINY, NULL);
}
u8 *GetTrainerPartnerName(void)
const u8 *GetTrainerPartnerName(void)
{
u8 id = GetMultiplayerId();
return gLinkPlayers[GetBattlerMultiplayerId(gLinkPlayers[id].id ^ 2)].name;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
return GetTrainerNameFromId(gPartnerTrainerId);
}
else
{
u8 id = GetMultiplayerId();
return gLinkPlayers[GetBattlerMultiplayerId(gLinkPlayers[id].id ^ 2)].name;
}
}
#define READ_PTR_FROM_TASK(taskId, dataId) \
@@ -5714,16 +5730,6 @@ static void Task_AnimateAfterDelay(u8 taskId)
}
}
// static void Task_PokemonSummaryAnimateAfterDelay(u8 taskId)
// {
// if (--gTasks[taskId].sAnimDelay == 0)
// {
// StartMonSummaryAnimation(READ_PTR_FROM_TASK(taskId, 0), gTasks[taskId].sAnimId);
// SummaryScreen_SetAnimDelayTaskId(TASK_NONE);
// DestroyTask(taskId);
// }
// }
void BattleAnimateFrontSprite(struct Sprite *sprite, u16 species, bool8 noCry, u8 panMode)
{
if (gHitMarker & HITMARKER_NO_ANIMATIONS && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)))
@@ -5779,34 +5785,6 @@ void DoMonFrontSpriteAnimation(struct Sprite *sprite, u16 species, bool8 noCry,
}
}
// void PokemonSummaryDoMonAnimation(struct Sprite *sprite, u16 species, bool8 oneFrame)
// {
// if (!oneFrame && HasTwoFramesAnimation(species))
// StartSpriteAnim(sprite, 1);
// if (gSpeciesInfo[species].frontAnimDelay != 0)
// {
// // Animation has delay, start delay task
// u8 taskId = CreateTask(Task_PokemonSummaryAnimateAfterDelay, 0);
// STORE_PTR_IN_TASK(sprite, taskId, 0);
// gTasks[taskId].sAnimId = gSpeciesInfo[species].frontAnimId;
// gTasks[taskId].sAnimDelay = gSpeciesInfo[species].frontAnimDelay;
// SummaryScreen_SetAnimDelayTaskId(taskId);
// SetSpriteCB_MonAnimDummy(sprite);
// }
// else
// {
// // No delay, start animation
// StartMonSummaryAnimation(sprite, gSpeciesInfo[species].frontAnimId);
// }
// }
// void StopPokemonAnimationDelayTask(void)
// {
// u8 delayTaskId = FindTaskIdByFunc(Task_PokemonSummaryAnimateAfterDelay);
// if (delayTaskId != TASK_NONE)
// DestroyTask(delayTaskId);
// }
void BattleAnimateBackSprite(struct Sprite *sprite, u16 species)
{
if (gHitMarker & HITMARKER_NO_ANIMATIONS && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)))

View File

@@ -474,7 +474,7 @@ static void CB2_ReturnFromChooseBattleTowerParty(void)
gSpecialVar_Result = FALSE;
break;
default:
ReducePlayerPartyToThree();
ReducePlayerPartyToSelectedMons();
gSpecialVar_Result = TRUE;
break;
}
@@ -482,24 +482,25 @@ static void CB2_ReturnFromChooseBattleTowerParty(void)
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
}
void ReducePlayerPartyToThree(void)
void ReducePlayerPartyToSelectedMons(void)
{
struct Pokemon * party = AllocZeroed(3 * sizeof(struct Pokemon));
struct Pokemon party[MAX_FRONTIER_PARTY_SIZE];
int i;
// copy the selected pokemon according to the order.
for (i = 0; i < 3; i++)
CpuFill32(0, party, sizeof party);
// copy the selected Pokémon according to the order.
for (i = 0; i < MAX_FRONTIER_PARTY_SIZE; i++)
if (gSelectedOrderFromParty[i]) // as long as the order keeps going (did the player select 1 mon? 2? 3?), do not stop
party[i] = gPlayerParty[gSelectedOrderFromParty[i] - 1]; // index is 0 based, not literal
CpuFill32(0, gPlayerParty, sizeof gPlayerParty);
// overwrite the first 3 with the order copied to.
for (i = 0; i < 3; i++)
// overwrite the first 4 with the order copied to.
for (i = 0; i < MAX_FRONTIER_PARTY_SIZE; i++)
gPlayerParty[i] = party[i];
CalculatePlayerPartyCount();
Free(party);
}
void Script_GetChosenMonOffensiveEVs(void)