fixed 1v2 double battles, added wild double battles, removed unused

This commit is contained in:
cawtds
2024-05-12 22:39:03 +02:00
parent 56d32c797d
commit 7e2ecf588e
23 changed files with 308 additions and 191 deletions

View File

@@ -873,6 +873,9 @@ struct BattleHealthboxInfo
u8 triedShinyMonAnim : 1; // x80
u8 finishedShinyMonAnim : 1; // x1
u8 opponentDrawPartyStatusSummaryDelay : 5; // x2
u8 bgmRestored:1;
u8 waitForCry:1;
u8 healthboxSlideInStarted:1;
u8 healthboxBounceSpriteId;
u8 battlerBounceSpriteId;
u8 animationState;
@@ -914,7 +917,7 @@ extern u8 *gLinkBattleRecvBuffer;
struct MonSpritesGfx
{
void *firstDecompressed; // ptr to the decompressed sprite of the first pokemon
void *sprites[MAX_BATTLERS_COUNT];
u8 *sprites[MAX_BATTLERS_COUNT];
struct SpriteTemplate templates[MAX_BATTLERS_COUNT];
struct SpriteFrameImage images[MAX_BATTLERS_COUNT][4];
u8 field_F4[0x80 - (4 * MAX_BATTLERS_COUNT)]; // unused, original - spritesGfx
@@ -978,10 +981,7 @@ extern bool8 gTransformedShininess[MAX_BATTLERS_COUNT];
extern u8 gBattlerPositions[MAX_BATTLERS_COUNT];
extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
extern u8 gBattleOutcome;
extern u8 gBattleMonForms[MAX_BATTLERS_COUNT];
extern u32 gBattleControllerExecFlags;
// extern u8 gBattleBufferA[MAX_BATTLERS_COUNT][0x200];
// extern u8 gBattleBufferB[MAX_BATTLERS_COUNT][0x200];
extern u8 gActionSelectionCursor[MAX_BATTLERS_COUNT];
extern void (*gPreBattleCallback1)(void);
extern bool8 gDoingBattleAnim;

View File

@@ -6,6 +6,7 @@
extern u16 gPartnerTrainerId;
void StartWildBattle(void);
void StartDoubleWildBattle(void);
void StartRoamerBattle(void);
void StartOldManTutorialBattle(void);
void StartScriptedWildBattle(void);

View File

@@ -779,7 +779,6 @@ u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves);
u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves);
u8 GetNumberOfRelearnableMoves(struct Pokemon *mon);
u16 SpeciesToPokedexNum(u16 species);
void ClearBattleMonForms(void);
void PlayBattleBGM(void);
void PlayMapChosenOrBattleBGM(u16 songId);
const u32 *GetMonFrontSpritePal(struct Pokemon *mon);

View File

@@ -178,7 +178,7 @@ void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *c
u16 RenderText(struct TextPrinter *textPrinter);
s32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32);
s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing);
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str, int a3, int a4, int a5, int a6, int a7);
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str);
u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y);
u8 GetKeypadIconTileOffset(u8 keypadIconId);
u8 GetKeypadIconWidth(u8 keypadIconId);

View File

@@ -51,5 +51,6 @@ bool8 SweetScentWildEncounter(void);
void SeedWildEncounterRng(u16 randVal);
void ResetEncounterRateModifiers(void);
bool8 TryStandardWildEncounter(u32 currMetatileAttrs);
bool8 TryDoDoubleWildBattle(void);
#endif // GUARD_WILD_ENCOUNTER_H

View File

@@ -2300,7 +2300,7 @@ void AnimTask_TransformMon(u8 taskId)
else
position = GetBattlerPosition(gBattleAnimAttacker);
src = gMonSpritesGfxPtr->sprites[position] + (gBattleMonForms[gBattleAnimAttacker] << 11);
src = gMonSpritesGfxPtr->sprites[position];
dest = animBg.bgTiles;
CpuCopy32(src, dest, MON_PIC_SIZE);
LoadBgTiles(1, animBg.bgTiles, 0x800, animBg.tilesOffset);

View File

@@ -1,6 +1,7 @@
#include "global.h"
#include "gflib.h"
#include "battle_anim.h"
#include "battle_interface.h"
#include "data.h"
#include "decompress.h"
#include "pokemon_icon.h"
@@ -86,10 +87,10 @@ u8 GetBattlerSpriteCoord(u8 battlerId, u8 coordType)
{
case BATTLER_COORD_X:
case BATTLER_COORD_X_2:
retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].x;
retVal = sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].x;
break;
case BATTLER_COORD_Y:
retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y;
retVal = sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].y;
break;
case BATTLER_COORD_Y_PIC_OFFSET:
case BATTLER_COORD_Y_PIC_OFFSET_DEFAULT:
@@ -208,7 +209,7 @@ static u8 GetBattlerSpriteFinal_Y(u8 battlerId, u16 species, bool8 a3)
offset = GetBattlerYDelta(battlerId, species);
offset -= GetBattlerElevation(battlerId, species);
}
y = offset + sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y;
y = offset + sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].y;
if (a3)
{
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
@@ -782,16 +783,6 @@ void InitSpritePosToAnimAttacker(struct Sprite *sprite, bool8 respectMonPicOffse
sprite->y += gBattleAnimArgs[1];
}
// u8 GetBattlerSide(u8 battlerId)
// {
// return GET_BATTLER_SIDE2(battlerId);
// }
// u8 GetBattlerPosition(u8 battlerId)
// {
// return GET_BATTLER_POSITION(battlerId);
// }
u8 GetBattlerAtPosition(u8 position)
{
u8 i;

View File

@@ -2040,21 +2040,17 @@ void AnimTask_SetTargetToEffectBattler(u8 taskId)
void TryShinyAnimation(u8 battler, struct Pokemon *mon)
{
bool32 isShiny;
u32 otId, personality;
u32 shinyValue;
u8 taskId1, taskId2;
struct Pokemon* illusionMon;
isShiny = FALSE;
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = TRUE;
otId = GetMonData(mon, MON_DATA_OT_ID);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
illusionMon = GetIllusionMonPtr(battler);
if (illusionMon != NULL)
mon = illusionMon;
if (IsBattlerSpriteVisible(battler))
if (IsBattlerSpriteVisible(battler) && IsValidForBattle(mon))
{
shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality);
if (shinyValue < SHINY_ODDS)
isShiny = TRUE;
if (isShiny)
{
if (GetSpriteTileStartByTag(ANIM_TAG_GOLD_STARS) == 0xFFFF)

View File

@@ -1002,37 +1002,38 @@ static void Intro_DelayAndEnd(u32 battler)
static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
{
bool8 var = FALSE;
bool8 healthboxAnimDone = FALSE;
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
var = TRUE;
}
else
// Check if healthbox has finished sliding in
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
var = TRUE;
healthboxAnimDone = TRUE;
}
if (IsCryPlayingOrClearCrySongs())
var = FALSE;
if (var && gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim
else
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
healthboxAnimDone = TRUE;
}
// If healthbox and shiny anim are done
if (healthboxAnimDone && gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim
&& gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
{
// Reset shiny anim (even if it didn't occur)
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].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)
m4aMPlayContinue(&gMPlayInfo_BGM);
else
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 256);
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[battler]], battler);
if (IsDoubleBattle())
if (TwoPlayerIntroMons(battler))
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], BATTLE_PARTNER(battler));
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3;
gBattlerControllerFuncs[battler] = Intro_DelayAndEnd;
}
@@ -1040,28 +1041,86 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
static void Intro_TryShinyAnimShowHealthbox(u32 battler)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
bool32 bgmRestored = FALSE;
bool32 battlerAnimsDone = FALSE;
// Start shiny animation if applicable for 1st Pokémon
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]);
// Start shiny animation if applicable for 2nd Pokémon
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
TryShinyAnimation(BATTLE_PARTNER(battler), &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]);
// Show healthbox after ball anim
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim)
TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]);
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim)
TryShinyAnimation(BATTLE_PARTNER(battler), &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]);
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
if (!gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted)
{
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)]);
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], HEALTHBOX_ALL);
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
}
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
}
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = TRUE;
}
// Restore bgm after cry has played and healthbox anim is started
if (!gBattleSpritesDataPtr->healthBoxesData[battler].waitForCry
&& gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].waitForCry
&& !IsCryPlayingOrClearCrySongs())
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored)
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
m4aMPlayContinue(&gMPlayInfo_BGM);
else
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
}
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = TRUE;
bgmRestored = TRUE;
}
// Wait for battler anims
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
{
battlerAnimsDone = TRUE;
}
}
else
{
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)
{
battlerAnimsDone = TRUE;
}
}
// Clean up
if (bgmRestored && battlerAnimsDone)
{
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]);
DestroySprite(&gSprites[gBattleControllerData[battler]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler],
&gPlayerParty[gBattlerPartyIndexes[battler]],
HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = FALSE;
gBattlerControllerFuncs[battler] = Intro_WaitForShinyAnimAndHealthbox;
}
}

View File

@@ -70,7 +70,6 @@ void SetUpBattleVars(void)
HandleLinkBattleSetup();
gBattleControllerExecFlags = 0;
ClearBattleAnimationVars();
ClearBattleMonForms();
BattleAI_SetupItems();
BattleAI_SetupFlags();
}
@@ -315,16 +314,13 @@ static void SetBattlePartyIds(void)
{
for (i = 0; i < gBattlersCount; i++)
{
for (j = 0; j < PARTY_SIZE; ++j)
for (j = 0; j < PARTY_SIZE; j++)
{
if (i < 2)
{
if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER)
if (GetBattlerSide(i) == B_SIDE_PLAYER)
{
if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
&& !GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG))
if (IsValidForBattle(&gPlayerParty[j]))
{
gBattlerPartyIndexes[i] = j;
break;
@@ -332,10 +328,7 @@ static void SetBattlePartyIds(void)
}
else
{
if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
&& !GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG))
if (IsValidForBattle(&gEnemyParty[j]))
{
gBattlerPartyIndexes[i] = j;
break;
@@ -344,13 +337,9 @@ static void SetBattlePartyIds(void)
}
else
{
if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER)
if (GetBattlerSide(i) == B_SIDE_PLAYER)
{
if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES) != SPECIES_NONE // Probably a typo by Game Freak. The rest use SPECIES2.
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
&& !GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG)
&& gBattlerPartyIndexes[i - 2] != j)
if (IsValidForBattle(&gPlayerParty[j]) && gBattlerPartyIndexes[i - 2] != j)
{
gBattlerPartyIndexes[i] = j;
break;
@@ -358,19 +347,24 @@ static void SetBattlePartyIds(void)
}
else
{
if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
&& !GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG)
&& gBattlerPartyIndexes[i - 2] != j)
if (IsValidForBattle(&gEnemyParty[j]) && gBattlerPartyIndexes[i - 2] != j)
{
gBattlerPartyIndexes[i] = j;
break;
}
}
// No valid mons were found. Add the empty slot.
if (gBattlerPartyIndexes[i - 2] == 0)
gBattlerPartyIndexes[i] = 1;
else
gBattlerPartyIndexes[i] = 0;
}
}
}
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
gBattlerPartyIndexes[1] = 0, gBattlerPartyIndexes[3] = 3;
}
}
@@ -839,7 +833,7 @@ void BtlController_EmitChooseAction(u32 battler, u32 bufferId, u8 action, u16 it
}
// Unused
static void BtlController_EmitUnknownYesNoBox(u32 battler, u32 bufferId, u32 arg1) // TODO: Does the function name make sense for pokefirered?
static void BtlController_EmitUnknownYesNoBox(u32 battler, u32 bufferId, u32 arg1)
{
gBattleResources->transferBuffer[0] = CONTROLLER_UNKNOWNYESNOBOX;
gBattleResources->transferBuffer[1] = arg1;

View File

@@ -139,11 +139,7 @@ void SpriteCB_WaitForBattlerBallReleaseAnim(struct Sprite *sprite)
if (gSprites[spriteId].animPaused)
gSprites[spriteId].animPaused = 0;
else if (gSprites[spriteId].animEnded)
{
gSprites[spriteId].callback = SetIdleSpriteCallback;
StartSpriteAffineAnim(&gSprites[spriteId], 0);
sprite->callback = SpriteCallbackDummy;
}
}
// Unused
@@ -211,7 +207,6 @@ bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattler, u8 atkBattler, u8 de
if (tableId == B_ANIM_FORM_CHANGE && (argument & 0x80))
{
gBattleMonForms[activeBattler] = (argument & ~(0x80));
return TRUE;
}
else if (gBattleSpritesDataPtr->battlerData[activeBattler].behindSubstitute
@@ -313,6 +308,8 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
u32 monsPersonality, currentPersonality, isShiny, species, paletteOffset, position;
const void *lzPaletteData;
struct Pokemon *illusionMon = GetIllusionMonPtr(battler);
if (illusionMon != NULL)
mon = illusionMon;
if (GetMonData(mon, MON_DATA_IS_EGG) || GetMonData(mon, MON_DATA_SPECIES) == SPECIES_NONE) // Don't load GFX of egg pokemon.
return;
@@ -497,7 +494,12 @@ bool8 BattleLoadAllHealthBoxesGfx(u8 state)
else
{
if (state == 2)
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[0]);
{
if (WhichBattleCoords(0))
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[0]);
else
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheet_SinglesPlayerHealthbox);
}
else if (state == 3)
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[1]);
else if (state == 4)
@@ -697,7 +699,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
CpuCopy32(&gPlttBufferFaded[paletteOffset], &gPlttBufferUnfaded[paletteOffset], PLTT_SIZEOF(16));
gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies = targetSpecies;
}
gBattleMonForms[battlerAtk] = gBattleMonForms[battlerDef];
gSprites[gBattlerSpriteIds[battlerAtk]].y = GetBattlerSpriteDefault_Y(battlerAtk);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], 0);
}
@@ -717,11 +719,7 @@ void BattleLoadSubstituteOrMonSpriteGfx(u8 battlerId, bool8 loadMonSprite)
LZDecompressVram(gSubstituteDollTilemap, gMonSpritesGfxPtr->sprites[position]);
for (i = 1; i < 4; ++i)
{
u8 (*ptr)[4][0x800] = gMonSpritesGfxPtr->sprites[position];
++ptr;
--ptr;
DmaCopy32Defvars(3, (*ptr)[0], (*ptr)[i], 0x800);
Dma3CopyLarge32_(gMonSpritesGfxPtr->sprites[position], &gMonSpritesGfxPtr->sprites[position][MON_PIC_SIZE * i], MON_PIC_SIZE);
}
palOffset = OBJ_PLTT_ID(battlerId);
LoadCompressedPalette(gSubstituteDollPal, palOffset, PLTT_SIZE_4BPP);
@@ -738,7 +736,7 @@ void BattleLoadSubstituteOrMonSpriteGfx(u8 battlerId, bool8 loadMonSprite)
void LoadBattleMonGfxAndAnimate(u8 battlerId, bool8 loadMonSprite, u8 spriteId)
{
BattleLoadSubstituteOrMonSpriteGfx(battlerId, loadMonSprite);
StartSpriteAnim(&gSprites[spriteId], gBattleMonForms[battlerId]);
StartSpriteAnim(&gSprites[spriteId], 0);
if (!loadMonSprite)
gSprites[spriteId].y = GetSubstituteSpriteDefault_Y(battlerId);
else
@@ -946,7 +944,6 @@ void BattleInterfaceSetWindowPals(void)
void ClearTemporarySpeciesSpriteData(u8 battlerId, bool8 dontClearSubstitute)
{
gBattleSpritesDataPtr->battlerData[battlerId].transformSpecies = SPECIES_NONE;
gBattleMonForms[battlerId] = 0;
if (!dontClearSubstitute)
ClearBehindSubstituteBit(battlerId);
}

View File

@@ -67,7 +67,7 @@ struct TestingBar
static void SpriteCB_HealthBoxOther(struct Sprite *sprite);
static void SpriteCB_HealthBar(struct Sprite *sprite);
static const u8 *GetBattleInterfaceGfxPtr(u8 which);
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent);
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, u32 maxOrCurrent, s16 currHp, s16 maxHp);
static void Task_HidePartyStatusSummary_BattleStart_1(u8 taskId);
static void Task_HidePartyStatusSummary_BattleStart_2(u8 taskId);
static void SpriteCB_PartySummaryBar_Exit(struct Sprite *sprite);
@@ -682,7 +682,7 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId)
u8 healthbarSpriteId;
struct Sprite *healthbarSprite;
if (!IsDoubleBattle())
if (WhichBattleCoords(battlerId) == 0)
{
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
@@ -864,7 +864,7 @@ void InitBattlerHealthboxCoords(u8 battler)
{
s16 x = 0, y = 0;
if (!IsDoubleBattle())
if (!WhichBattleCoords(battler))
{
if (GetBattlerSide(battler) != B_SIDE_PLAYER)
x = 44, y = 30;
@@ -910,7 +910,7 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl)
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER)
{
objVram = (void *)(OBJ_VRAM0);
if (!IsDoubleBattle())
if (!WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId))
objVram += spriteTileNum + 0x820;
else
objVram += spriteTileNum + 0x420;
@@ -929,7 +929,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
u32 windowId, spriteTileNum;
u8 *windowTileData;
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER && !IsDoubleBattle())
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER && !WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId))
{
// Only in the Japanese release can HP be displayed as text outside of double battles
u8 text[8];
@@ -960,12 +960,12 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
u8 text[20] = __("{COLOR 01}{HIGHLIGHT 02}");
battler = gSprites[healthboxSpriteId].sBattlerId;
if (IsDoubleBattle() == TRUE || GetBattlerSide(battler) == B_SIDE_OPPONENT)
if (WhichBattleCoords(battler) == TRUE || GetBattlerSide(battler) == B_SIDE_OPPONENT)
{
if (maxOrCurrent != HP_CURRENT)
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxHp, maxOrCurrent);
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxOrCurrent, currHp, maxHp);
else
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, currHp, maxOrCurrent);
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxOrCurrent, currHp, maxHp);
}
else
{
@@ -992,7 +992,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
ConvertIntToDecimalStringN(text + 6, maxHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
else
ConvertIntToDecimalStringN(text + 6, currHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text);
for (i = 0; i < 3; i++)
{
@@ -1006,7 +1006,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
static const u8 sText_Slash[] = _("/");
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent)
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, u32 maxOrCurrent, s16 currHp, s16 maxHp)
{
u32 windowId, spriteTileNum;
u8 *windowTileData;
@@ -1027,11 +1027,15 @@ static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8
var = 0;
healthBarSpriteId = gSprites[healthboxSpriteId].sHealthBarSpriteId;
txtPtr = ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
if (maxOrCurrent == HP_CURRENT)
txtPtr = ConvertIntToDecimalStringN(text + 6, currHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
else
txtPtr = ConvertIntToDecimalStringN(text + 6, maxHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
if (maxOrCurrent == HP_CURRENT)
StringCopy(txtPtr, sText_Slash);
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text);
for (i = var; i < var + 3; i++)
{
@@ -1082,7 +1086,7 @@ static void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon)
var = 5;
nature = GetNature(mon);
StringCopy(text + 6, gNatureNamePointers[nature]);
RenderTextHandleBold(barFontGfx, 0, text, 0, 0, 0, 0, 0);
RenderTextHandleBold(barFontGfx, 0, text);
for (j = 6, i = 0; i < var; i++, j++)
{
@@ -1114,7 +1118,7 @@ static void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon)
ConvertIntToDecimalStringN(text + 9, gBattleStruct->safariEscapeFactor, STR_CONV_MODE_RIGHT_ALIGN, 2);
text[5] = CHAR_SPACE;
text[8] = CHAR_SLASH;
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text);
j = healthBarSpriteId; // Needed to match for some reason.
for (j = 0; j < 5; j++)
@@ -1143,7 +1147,7 @@ void SwapHpBarsWithHpText(void)
{
if (gSprites[gHealthboxSpriteIds[i]].callback == SpriteCallbackDummy
&& GetBattlerSide(i) != B_SIDE_OPPONENT
&& (IsDoubleBattle() || GetBattlerSide(i) != B_SIDE_PLAYER))
&& (WhichBattleCoords(i) || GetBattlerSide(i) != B_SIDE_PLAYER))
{
bool8 noBars;
@@ -1151,18 +1155,20 @@ void SwapHpBarsWithHpText(void)
noBars = gBattleSpritesDataPtr->battlerData[i].hpNumbersNoBars;
if (GetBattlerSide(i) == B_SIDE_PLAYER)
{
if (!IsDoubleBattle())
if (!WhichBattleCoords(i))
continue;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
continue;
if (noBars == TRUE) // bars to text
{
s16 currHp = GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_HP);
s16 maxHp = GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP);
healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].sHealthBarSpriteId;
CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * TILE_SIZE_4BPP), 8 * TILE_SIZE_4BPP);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_CURRENT, currHp, maxHp);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_MAX, currHp, maxHp);
}
else // text to bars
{
@@ -1184,11 +1190,13 @@ void SwapHpBarsWithHpText(void)
}
else
{
s16 currHp = GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_HP);
s16 maxHp = GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP);
healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].sHealthBarSpriteId;
CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * 32), 8 * TILE_SIZE_4BPP);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_CURRENT, currHp, maxHp);
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_MAX, currHp, maxHp);
}
}
else // text to bars
@@ -1496,7 +1504,7 @@ u8 CreatePartyStatusSummarySprites(u8 battlerId, struct HpAndStatus *partyInfo,
{
isOpponent = TRUE;
if (!isSwitchingMons || !IsDoubleBattle())
if (!isSwitchingMons || !WhichBattleCoords(battlerId))
x = 104, y = 40;
else
x = 104, y = 16;
@@ -1935,7 +1943,7 @@ void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon)
{
TextIntoHealthboxObject((void *)(OBJ_VRAM0 + 0x40 + spriteTileNum), windowTileData, 6);
ptr = (void *)(OBJ_VRAM0);
if (!IsDoubleBattle())
if (!WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId))
ptr += spriteTileNum + 0x800;
else
ptr += spriteTileNum + 0x400;
@@ -2005,7 +2013,7 @@ static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId)
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
status = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_STATUS);
if (!IsDoubleBattle())
if (!WhichBattleCoords(battlerId))
tileNumAdder = 0x1A;
else
tileNumAdder = 0x12;
@@ -2065,7 +2073,7 @@ static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId)
FillPalette(sStatusIconColors[statusPalId], pltAdder + OBJ_PLTT_OFFSET, PLTT_SIZEOF(1));
CpuCopy16(&gPlttBufferUnfaded[OBJ_PLTT_OFFSET + pltAdder], (u16 *)OBJ_PLTT + pltAdder, PLTT_SIZEOF(1));
CpuCopy32(statusGfxPtr, (void *)(OBJ_VRAM0 + (gSprites[healthboxSpriteId].oam.tileNum + tileNumAdder) * TILE_SIZE_4BPP), 3 * TILE_SIZE_4BPP);
if (IsDoubleBattle() == TRUE || GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
if (WhichBattleCoords(battlerId) == TRUE || GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
{
if (!gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars)
{
@@ -2171,31 +2179,30 @@ static void UpdateLeftNoOfBallsTextOnHealthbox(u8 healthboxSpriteId)
void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elementId)
{
s32 maxHp, currHp;
u8 battlerId = gSprites[healthboxSpriteId].sBattlerId;
s32 maxHp = GetMonData(mon, MON_DATA_MAX_HP);
s32 currHp = GetMonData(mon, MON_DATA_HP);
if (elementId == HEALTHBOX_ALL && !IsDoubleBattle())
GetBattlerSide(battlerId); // Pointless function call.
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER)
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
u8 isDoubles;
u8 isDoubles = WhichBattleCoords(battlerId);
maxHp = GetMonData(mon, MON_DATA_MAX_HP);
currHp = GetMonData(mon, MON_DATA_HP);
if (elementId == HEALTHBOX_LEVEL || elementId == HEALTHBOX_ALL)
UpdateLvlInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_LEVEL));
if (elementId == HEALTHBOX_CURRENT_HP || elementId == HEALTHBOX_ALL)
UpdateHpTextInHealthbox(healthboxSpriteId, HP_CURRENT, currHp, maxHp);
if (elementId == HEALTHBOX_MAX_HP || elementId == HEALTHBOX_ALL)
UpdateHpTextInHealthbox(healthboxSpriteId, HP_MAX, currHp, maxHp);
if (elementId == HEALTHBOX_HEALTH_BAR || elementId == HEALTHBOX_ALL)
{
LoadBattleBarGfx(0);
SetBattleBarStruct(battlerId, healthboxSpriteId, maxHp, currHp, 0);
MoveBattleBar(battlerId, healthboxSpriteId, HEALTH_BAR, 0);
}
isDoubles = IsDoubleBattle();
if (!isDoubles && (elementId == HEALTHBOX_EXP_BAR || elementId == HEALTHBOX_ALL))
{
u16 species;

View File

@@ -471,7 +471,7 @@ void CopyBattlerSpriteToBg(s32 bgId, u8 x, u8 y, u8 battlerPosition, u8 palno, u
u8 battler = GetBattlerAtPosition(battlerPosition);
s32 offset = tilesOffset;
CpuCopy16(gMonSpritesGfxPtr->sprites[battlerPosition] + BG_SCREEN_SIZE * gBattleMonForms[battler], tilesDest, BG_SCREEN_SIZE);
CpuCopy16(gMonSpritesGfxPtr->sprites[battlerPosition], tilesDest, BG_SCREEN_SIZE);
LoadBgTiles(bgId, tilesDest, 0x1000, tilesOffset);
for (i = y; i < y + 8; ++i)
for (j = x; j < x + 8; ++j)

View File

@@ -193,7 +193,6 @@ EWRAM_DATA struct BattleSpriteData *gBattleSpritesDataPtr = NULL;
EWRAM_DATA struct MonSpritesGfx *gMonSpritesGfxPtr = NULL;
EWRAM_DATA u16 gBattleMovePower = 0;
EWRAM_DATA u16 gMoveToLearn = 0;
EWRAM_DATA u8 gBattleMonForms[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gPartyCriticalHits[PARTY_SIZE] = {0};
EWRAM_DATA u32 gFieldStatuses = 0;
EWRAM_DATA u8 gBattlerAbility = 0;
@@ -861,7 +860,10 @@ static void CB2_InitBattleInternal(void)
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A, FALSE);
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT)
CreateNPCTrainerParty(&gEnemyParty[PARTY_SIZE / 2], gTrainerBattleOpponent_B, FALSE);
SetWildMonHeldItem();
CalculateEnemyPartyCount();
}
gMain.inBattle = TRUE;
@@ -1627,12 +1629,14 @@ static void CB2_HandleStartMultiBattle(void)
break;
case 5:
case 9:
case 13:
++gBattleCommunication[0];
gBattleCommunication[SPRITES_INIT_STATE1] = 1;
gBattleCommunication[1] = 1;
// fall through
case 6:
case 10:
if (--gBattleCommunication[SPRITES_INIT_STATE1] == 0)
case 14:
if (--gBattleCommunication[1] == 0)
++gBattleCommunication[0];
break;
}
@@ -2257,11 +2261,11 @@ static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite)
}
else // Erase bottom part of the sprite to create a smooth illusion of mon falling down.
{
u8 *dst = (u8 *)gMonSpritesGfxPtr->sprites[GetBattlerPosition(sprite->sBattler)] + (gBattleMonForms[sprite->sBattler] << 11) + (sprite->data[3] << 8);
u8 *dst = &gMonSpritesGfxPtr->sprites[GetBattlerPosition(sprite->sBattler)][(sprite->data[3] << 8)];
for (i = 0; i < 0x100; i++)
*(dst++) = 0;
StartSpriteAnim(sprite, gBattleMonForms[sprite->sBattler]);
StartSpriteAnim(sprite, 0);
}
}
}
@@ -3190,6 +3194,7 @@ static void DoBattleIntro(void)
}
break;
}
}
static void TryDoEventsBeforeFirstTurn(void)

View File

@@ -2478,7 +2478,7 @@ void BufferStringBattle(u32 battler, u16 stringId)
}
else if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY)
stringPtr = sText_WildPkmnAppeared2;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) // interesting, looks like they had something planned for wild double battles
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]])) // interesting, looks like they had something planned for wild double battles
stringPtr = sText_TwoWildPkmnAppeared;
else if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL)
stringPtr = sText_WildPkmnAppearedPause;
@@ -2489,9 +2489,13 @@ void BufferStringBattle(u32 battler, u16 stringId)
case STRINGID_INTROSENDOUT: // poke first send-out
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
{
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]))
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
stringPtr = sText_InGamePartnerSentOutZGoN;
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
stringPtr = sText_GoTwoPkmn;
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
stringPtr = sText_LinkPartnerSentOutPkmnGoPkmn;
else
stringPtr = sText_GoTwoPkmn;
@@ -2503,9 +2507,13 @@ void BufferStringBattle(u32 battler, u16 stringId)
}
else
{
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]))
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
if (BATTLE_TWO_VS_ONE_OPPONENT)
stringPtr = sText_Trainer1SentOutTwoPkmn;
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
stringPtr = sText_TwoTrainersSentPkmn;
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
stringPtr = sText_TwoLinkTrainersSentOutPkmn;
else if (gBattleTypeFlags & BATTLE_TYPE_LINK)
stringPtr = sText_LinkTrainerSentOutTwoPkmn;

View File

@@ -59,7 +59,7 @@ struct TrainerBattleParameter
static void DoSafariBattle(void);
static void DoGhostBattle(void);
static void DoStandardWildBattle(void);
static void DoStandardWildBattle(bool32 isDouble);
static void CB2_EndWildBattle(void);
static u8 GetWildBattleTransition(void);
static u8 GetTrainerBattleTransition(void);
@@ -242,16 +242,23 @@ void StartWildBattle(void)
else if (CheckSilphScopeInPokemonTower(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum))
DoGhostBattle();
else
DoStandardWildBattle();
DoStandardWildBattle(FALSE);
}
static void DoStandardWildBattle(void)
void StartDoubleWildBattle(void)
{
DoStandardWildBattle(TRUE);
}
static void DoStandardWildBattle(bool32 isDouble)
{
LockPlayerFieldControls();
FreezeObjectEvents();
StopPlayerAvatar();
gMain.savedCallback = CB2_EndWildBattle;
gBattleTypeFlags = 0;
if (isDouble)
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE;
CreateBattleStartTask(GetWildBattleTransition(), 0);
IncrementGameStat(GAME_STAT_TOTAL_BATTLES);
IncrementGameStat(GAME_STAT_WILD_BATTLES);

View File

@@ -366,22 +366,28 @@ void HandleAction_UseItem(void)
bool8 TryRunFromBattle(u8 battler)
{
bool8 effect = FALSE;
bool32 effect = FALSE;
u8 holdEffect;
u8 speedVar;
if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY)
if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER)
holdEffect = gEnigmaBerries[battler].holdEffect;
else
holdEffect = ItemId_GetHoldEffect(gBattleMons[battler].item);
gPotentialItemEffectBattler = battler;
if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)
{
gLastUsedItem = gBattleMons[battler].item;
gProtectStructs[battler].fleeType = FLEE_ITEM;
effect++;
}
else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY)
else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
{
effect++;
}
else if (GetBattlerAbility(battler) == ABILITY_RUN_AWAY)
{
gLastUsedAbility = ABILITY_RUN_AWAY;
gProtectStructs[battler].fleeType = FLEE_ABILITY;
@@ -394,27 +400,30 @@ bool8 TryRunFromBattle(u8 battler)
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
u8 runningFromBattler = BATTLE_OPPOSITE(battler);
if (!IsBattlerAlive(runningFromBattler))
runningFromBattler |= BIT_FLANK;
if (gBattleMons[battler].speed < gBattleMons[runningFromBattler].speed)
{
if (gBattleMons[battler].speed < gBattleMons[BATTLE_OPPOSITE(battler)].speed)
{
speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
else // same speed or faster
{
speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[runningFromBattler].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
}
else // same speed or faster
{
effect++;
}
++gBattleStruct->runTries;
gBattleStruct->runTries++;
}
if (effect != 0)
{
gCurrentTurnActionNumber = gBattlersCount;
gBattleOutcome = B_OUTCOME_RAN;
}
return effect;
}

View File

@@ -6325,10 +6325,10 @@ void ChooseMonForWirelessMinigame(void)
static u8 GetPartyLayoutFromBattleType(void)
{
if (IsDoubleBattle() == FALSE)
return PARTY_LAYOUT_SINGLE;
if (IsMultiBattle() == TRUE)
return PARTY_LAYOUT_MULTI;
if (!IsDoubleBattle() || gPlayerPartyCount == 1)
return PARTY_LAYOUT_SINGLE;
return PARTY_LAYOUT_DOUBLE;
}
@@ -6578,12 +6578,12 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba
{
j = 1;
partyIndexes[0] = gBattlerPartyIndexes[leftBattler];
for (i = 0; i < PARTY_SIZE; ++i)
for (i = 0; i < PARTY_SIZE; i++)
{
if (i != partyIndexes[0])
{
partyIndexes[j] = i;
++j;
j++;
}
}
}
@@ -6592,16 +6592,16 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba
j = 2;
partyIndexes[0] = gBattlerPartyIndexes[leftBattler];
partyIndexes[1] = gBattlerPartyIndexes[rightBattler];
for (i = 0; i < PARTY_SIZE; ++i)
for (i = 0; i < PARTY_SIZE; i++)
{
if (i != partyIndexes[0] && i != partyIndexes[1])
{
partyIndexes[j] = i;
++j;
j++;
}
}
}
for (i = 0; i < 3; ++i)
for (i = 0; i < 3; i++)
partyBattleOrder[i] = (partyIndexes[0 + (i * 2)] << 4) | partyIndexes[1 + (i * 2)];
}

View File

@@ -672,8 +672,10 @@ static void SpriteCB_BallThrow_Shake(struct Sprite *sprite)
#define tCryTaskSpecies data[0]
#define tCryTaskPan data[1]
#define tCryTaskWantedCry data[2]
#define tCryTaskMonPtr1 data[3]
#define tCryTaskMonPtr2 data[4]
#define tCryTaskBattler data[3]
#define tCryTaskMonSpriteId data[4]
#define tCryTaskMonPtr1 data[5]
#define tCryTaskMonPtr2 data[6]
#define tCryTaskFrames data[10]
#define tCryTaskState data[15]
@@ -682,15 +684,15 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
u8 wantedCry = gTasks[taskId].tCryTaskWantedCry;
s8 pan = gTasks[taskId].tCryTaskPan;
u16 species = gTasks[taskId].tCryTaskSpecies;
u8 battlerId = gTasks[taskId].tCryTaskBattler;
u8 monSpriteId = gTasks[taskId].tCryTaskMonSpriteId;
struct Pokemon *mon = (void *)(u32)((gTasks[taskId].tCryTaskMonPtr1 << 16) | (u16)(gTasks[taskId].tCryTaskMonPtr2));
switch (gTasks[taskId].tCryTaskState)
{
case 0:
default:
if (gTasks[taskId].data[8] < 3)
gTasks[taskId].data[8]++;
else
if (gSprites[monSpriteId].affineAnimEnded)
gTasks[taskId].tCryTaskState = wantedCry + 1;
break;
case 1:
@@ -699,7 +701,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
PlayCry_ByMode(species, pan, CRY_MODE_NORMAL);
else
PlayCry_ByMode(species, pan, CRY_MODE_WEAK);
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE;
DestroyTask(taskId);
break;
case 2:
@@ -716,6 +718,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
else
PlayCry_ReleaseDouble(species, pan, CRY_MODE_WEAK_DOUBLES);
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE;
DestroyTask(taskId);
}
else
@@ -755,6 +758,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
else
PlayCry_ReleaseDouble(species, pan, CRY_MODE_WEAK);
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE;
DestroyTask(taskId);
break;
}
@@ -773,7 +777,7 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
if (gMain.inBattle)
{
struct Pokemon *mon;
struct Pokemon *mon, *illusionMon;
u16 species;
s8 pan;
u16 wantedCryCase;
@@ -812,10 +816,20 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
else
wantedCryCase = 2;
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = TRUE;
taskId = CreateTask(Task_PlayCryWhenReleasedFromBall, 3);
gTasks[taskId].tCryTaskSpecies = species;
illusionMon = GetIllusionMonPtr(battlerId);
if (illusionMon != NULL)
gTasks[taskId].tCryTaskSpecies = GetMonData(illusionMon, MON_DATA_SPECIES);
else
gTasks[taskId].tCryTaskSpecies = GetMonData(mon, MON_DATA_SPECIES);
gTasks[taskId].tCryTaskPan = pan;
gTasks[taskId].tCryTaskWantedCry = wantedCryCase;
gTasks[taskId].tCryTaskBattler = battlerId;
gTasks[taskId].tCryTaskMonSpriteId = gBattlerSpriteIds[sprite->sBattler];
gTasks[taskId].tCryTaskMonPtr1 = (u32)(mon) >> 16;
gTasks[taskId].tCryTaskMonPtr2 = (u32)(mon);
gTasks[taskId].tCryTaskState = 0;
@@ -829,6 +843,8 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
#undef tCryTaskSpecies
#undef tCryTaskPan
#undef tCryTaskWantedCry
#undef tCryTaskBattler
#undef tCryTaskMonSpriteId
#undef tCryTaskMonPtr1
#undef tCryTaskMonPtr2
#undef tCryTaskFrames

View File

@@ -5317,13 +5317,6 @@ u16 SpeciesToPokedexNum(u16 species)
return species > 0 ? species : 0xFFFF;
}
void ClearBattleMonForms(void)
{
int i;
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
gBattleMonForms[i] = 0;
}
static u16 GetBattleBGM(void)
{
if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON)

View File

@@ -236,7 +236,7 @@ static void CreateBattlerSprite(u8 battler)
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy;
gSprites[gBattlerSpriteIds[battler]].data[0] = battler;
gSprites[gBattlerSpriteIds[battler]].data[2] = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], gBattleMonForms[battler]);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0);
}
else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && battler == B_POSITION_PLAYER_LEFT)
{
@@ -270,7 +270,7 @@ static void CreateBattlerSprite(u8 battler)
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy;
gSprites[gBattlerSpriteIds[battler]].data[0] = battler;
gSprites[gBattlerSpriteIds[battler]].data[2] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], gBattleMonForms[battler]);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0);
}
gSprites[gBattlerSpriteIds[battler]].invisible = gBattleSpritesDataPtr->battlerData[battler].invisible;
}
@@ -306,9 +306,10 @@ static void CreateHealthboxSprite(u8 battler)
if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_HP) == 0)
SetHealthboxSpriteInvisible(healthboxSpriteId);
}
else if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_HP) == 0)
{
SetHealthboxSpriteInvisible(healthboxSpriteId);
else if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
{
if (!IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[battler]]))
SetHealthboxSpriteInvisible(healthboxSpriteId);
}
}
}

View File

@@ -1179,7 +1179,7 @@ s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing)
return width;
}
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str, int a3, int a4, int a5, int a6, int a7)
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str)
{
u8 shadowColor;
u8 *strLocal;

View File

@@ -13,6 +13,7 @@
#include "script.h"
#include "link.h"
#include "quest_log.h"
#include "safari_zone.h"
#include "constants/maps.h"
#include "constants/abilities.h"
#include "constants/items.h"
@@ -394,7 +395,17 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior)
// try a regular wild land encounter
if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL) == TRUE)
{
StartWildBattle();
if (TryDoDoubleWildBattle())
{
struct Pokemon mon1 = gEnemyParty[0];
TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE);
gEnemyParty[1] = mon1;
StartDoubleWildBattle();
}
else
{
StartWildBattle();
}
return TRUE;
}
else
@@ -432,7 +443,17 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior)
if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE)
{
gIsSurfingEncounter = TRUE;
StartWildBattle();
if (TryDoDoubleWildBattle())
{
struct Pokemon mon1 = gEnemyParty[0];
TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_KEEN_EYE);
gEnemyParty[1] = mon1;
StartDoubleWildBattle();
}
else
{
StartWildBattle();
}
return TRUE;
}
else
@@ -786,3 +807,15 @@ static void AddToWildEncounterRateBuff(u8 encounterRate)
else
sWildEncounterData.encounterRateBuff = 0;
}
bool8 TryDoDoubleWildBattle(void)
{
if (GetSafariZoneFlag()
|| (B_DOUBLE_WILD_REQUIRE_2_MONS == TRUE && GetMonsStateToDoubles() != PLAYER_HAS_TWO_USABLE_MONS))
return FALSE;
else if (B_FLAG_FORCE_DOUBLE_WILD != 0 && FlagGet(B_FLAG_FORCE_DOUBLE_WILD))
return TRUE;
else if (B_DOUBLE_WILD_CHANCE != 0 && ((Random() % 100) + 1 <= B_DOUBLE_WILD_CHANCE))
return TRUE;
return FALSE;
}