merge with be

This commit is contained in:
ghoulslash 2021-09-22 16:26:09 -04:00
commit d738297f24
14 changed files with 175 additions and 74 deletions

View File

@ -7638,6 +7638,7 @@ BattleScript_BerryReduceDmg::
BattleScript_PrintBerryReduceString:: BattleScript_PrintBerryReduceString::
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
printstring STRINGID_BERRYDMGREDUCES printstring STRINGID_BERRYDMGREDUCES
waitmessage B_WAIT_TIME_LONG
return return
BattleScript_BerryCureConfusionEnd2:: BattleScript_BerryCureConfusionEnd2::

View File

@ -185,6 +185,7 @@ extern struct UnusedControllerStruct gUnusedControllerStruct;
void HandleLinkBattleSetup(void); void HandleLinkBattleSetup(void);
void SetUpBattleVarsAndBirchZigzagoon(void); void SetUpBattleVarsAndBirchZigzagoon(void);
void InitBattleControllers(void); void InitBattleControllers(void);
bool32 IsValidForBattle(struct Pokemon *mon);
void TryReceiveLinkBattleData(void); void TryReceiveLinkBattleData(void);
void PrepareBufferDataTransferLink(u8 bufferId, u16 size, u8 *data); void PrepareBufferDataTransferLink(u8 bufferId, u16 size, u8 *data);

View File

@ -13,6 +13,7 @@ struct StatFractions
}; };
s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility); s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility);
s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move);
u8 GetBattlerTurnOrderNum(u8 battlerId); u8 GetBattlerTurnOrderNum(u8 battlerId);
bool32 NoAliveMonsForEitherParty(void); bool32 NoAliveMonsForEitherParty(void);

View File

@ -151,6 +151,7 @@ void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast);
bool32 CompareStat(u8 battlerId, u8 statId, u8 cmpTo, u8 cmpKind); bool32 CompareStat(u8 battlerId, u8 statId, u8 cmpTo, u8 cmpKind);
bool32 TryRoomService(u8 battlerId); bool32 TryRoomService(u8 battlerId);
void BufferStatChange(u8 battlerId, u8 statId, u8 stringId); void BufferStatChange(u8 battlerId, u8 statId, u8 stringId);
void DoBurmyFormChange(u32 monId);
bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef); bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef);
// ability checks // ability checks

View File

@ -37,6 +37,9 @@
#define SPECIES_ZYGARDE 0 // 50% #define SPECIES_ZYGARDE 0 // 50%
#define SPECIES_ZYGARDE_10 10011 // 10 % #define SPECIES_ZYGARDE_10 10011 // 10 %
#define SPECIES_ZYGARDE_COMPLETE 10012 // 100 % #define SPECIES_ZYGARDE_COMPLETE 10012 // 100 %
#define SPECIES_BURMY 0
#define SPECIES_BURMY_SANDY_CLOAK 10013
#define SPECIES_BURMY_TRASH_CLOAK 10014
#endif #endif
// Items with peculiar battle effects. // Items with peculiar battle effects.

View File

@ -711,7 +711,8 @@ static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef)
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
{ {
s32 dmg, moveType; s32 dmg, moveType, critDmg, normalDmg;
s8 critChance;
SaveBattlerData(battlerAtk); SaveBattlerData(battlerAtk);
SaveBattlerData(battlerDef); SaveBattlerData(battlerDef);
@ -722,12 +723,22 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
gBattleStruct->dynamicMoveType = 0; gBattleStruct->dynamicMoveType = 0;
SetTypeBeforeUsingMove(move, battlerAtk); SetTypeBeforeUsingMove(move, battlerAtk);
GET_MOVE_TYPE(move, moveType); GET_MOVE_TYPE(move, moveType);
dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE, FALSE);
critChance = GetInverseCritChance(battlerAtk, battlerDef, move);
normalDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, FALSE, FALSE, FALSE);
critDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, TRUE, FALSE, FALSE);
if(critChance == -1)
dmg = normalDmg;
else
dmg = (critDmg + normalDmg * (critChance - 1)) / critChance;
// handle dynamic move damage // handle dynamic move damage
switch (gBattleMoves[move].effect) switch (gBattleMoves[move].effect)
{ {
case EFFECT_LEVEL_DAMAGE: case EFFECT_LEVEL_DAMAGE:
case EFFECT_PSYWAVE:
//psywave's expected damage is equal to the user's level
dmg = gBattleMons[battlerAtk].level; dmg = gBattleMons[battlerAtk].level;
break; break;
case EFFECT_DRAGON_RAGE: case EFFECT_DRAGON_RAGE:
@ -736,20 +747,11 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
case EFFECT_SONICBOOM: case EFFECT_SONICBOOM:
dmg = 20; dmg = 20;
break; break;
case EFFECT_PSYWAVE:
{
u32 randDamage;
if (B_PSYWAVE_DMG >= GEN_6)
randDamage = (Random() % 101);
else
randDamage = (Random() % 11) * 10;
dmg = gBattleMons[battlerAtk].level * (randDamage + 50) / 100;
}
break;
//case EFFECT_METAL_BURST: //case EFFECT_METAL_BURST:
//case EFFECT_COUNTER: //case EFFECT_COUNTER:
default: default:
dmg *= (100 - (Random() % 10)) / 100; // add random factor //do not add the random factor, it's an average case analysis
//dmg *= (100 - (Random() % 10)) / 100; // add random factor
break; break;
} }

View File

@ -225,12 +225,18 @@ static void Intro_DelayAndEnd(void)
} }
} }
static bool32 TwoIntroMons(u32 battlerId) // Double battle with both player pokemon active.
{
return (IsDoubleBattle() && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[battlerId ^ BIT_FLANK]]));
}
static void Intro_WaitForShinyAnimAndHealthbox(void) static void Intro_WaitForShinyAnimAndHealthbox(void)
{ {
bool8 healthboxAnimDone = FALSE; bool8 healthboxAnimDone = FALSE;
bool8 twoMons; bool8 twoMons;
if (!IsDoubleBattle() || ((IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI) && !BATTLE_TWO_VS_ONE_OPPONENT) || (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))) twoMons = TwoIntroMons(gActiveBattler);
if (!twoMons || ((twoMons && (gBattleTypeFlags & BATTLE_TYPE_MULTI) && !BATTLE_TWO_VS_ONE_OPPONENT) || (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)))
{ {
if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
healthboxAnimDone = TRUE; healthboxAnimDone = TRUE;
@ -292,15 +298,17 @@ static void Intro_TryShinyAnimShowHealthbox(void)
{ {
bool32 bgmRestored = FALSE; bool32 bgmRestored = FALSE;
bool32 battlerAnimsDone = FALSE; bool32 battlerAnimsDone = FALSE;
bool32 twoMons;
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].triedShinyMonAnim if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].finishedShinyMonAnim) && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].finishedShinyMonAnim)
TryShinyAnimation(gActiveBattler, &gEnemyParty[gBattlerPartyIndexes[gActiveBattler]]); TryShinyAnimation(gActiveBattler, &gEnemyParty[gBattlerPartyIndexes[gActiveBattler]]);
twoMons = TwoIntroMons(gActiveBattler);
if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
&& (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT) && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT)
&& IsDoubleBattle() && twoMons
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].triedShinyMonAnim && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].finishedShinyMonAnim) && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].finishedShinyMonAnim)
@ -310,7 +318,7 @@ static void Intro_TryShinyAnimShowHealthbox(void)
{ {
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted) if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted)
{ {
if (IsDoubleBattle() && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT)) if (twoMons && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT))
{ {
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK], &gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], HEALTHBOX_ALL); UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK], &gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], HEALTHBOX_ALL);
StartHealthboxSlideIn(gActiveBattler ^ BIT_FLANK); StartHealthboxSlideIn(gActiveBattler ^ BIT_FLANK);
@ -342,7 +350,7 @@ static void Intro_TryShinyAnimShowHealthbox(void)
bgmRestored = TRUE; bgmRestored = TRUE;
} }
if (!IsDoubleBattle() || (IsDoubleBattle() && gBattleTypeFlags & BATTLE_TYPE_MULTI && !BATTLE_TWO_VS_ONE_OPPONENT)) if (!twoMons || (twoMons && gBattleTypeFlags & BATTLE_TYPE_MULTI && !BATTLE_TWO_VS_ONE_OPPONENT))
{ {
if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) && gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
@ -363,7 +371,7 @@ static void Intro_TryShinyAnimShowHealthbox(void)
if (bgmRestored && battlerAnimsDone) if (bgmRestored && battlerAnimsDone)
{ {
if (IsDoubleBattle() && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT)) if (twoMons && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT))
{ {
DestroySprite(&gSprites[gBattleControllerData[gActiveBattler ^ BIT_FLANK]]); DestroySprite(&gSprites[gBattleControllerData[gActiveBattler ^ BIT_FLANK]]);
SetBattlerShadowSpriteCallback(gActiveBattler ^ BIT_FLANK, GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], MON_DATA_SPECIES)); SetBattlerShadowSpriteCallback(gActiveBattler ^ BIT_FLANK, GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], MON_DATA_SPECIES));
@ -1892,7 +1900,7 @@ static void Task_StartSendOutAnim(u8 taskId)
u8 savedActiveBank = gActiveBattler; u8 savedActiveBank = gActiveBattler;
gActiveBattler = gTasks[taskId].data[0]; gActiveBattler = gTasks[taskId].data[0];
if ((!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI)) && !BATTLE_TWO_VS_ONE_OPPONENT) if ((!TwoIntroMons(gActiveBattler) || (gBattleTypeFlags & BATTLE_TYPE_MULTI)) && !BATTLE_TWO_VS_ONE_OPPONENT)
{ {
gBattleResources->bufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler]; gBattleResources->bufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
StartSendOutAnim(gActiveBattler, FALSE); StartSendOutAnim(gActiveBattler, FALSE);

View File

@ -1034,20 +1034,25 @@ static void Intro_DelayAndEnd(void)
} }
} }
static bool32 TwoIntroMons(u32 battlerId) // Double battle with both player pokemon active.
{
return (IsDoubleBattle() && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[battlerId ^ BIT_FLANK]]));
}
static void Intro_WaitForShinyAnimAndHealthbox(void) static void Intro_WaitForShinyAnimAndHealthbox(void)
{ {
bool8 healthboxAnimDone = FALSE; bool8 healthboxAnimDone = FALSE;
// Check if healthbox has finished sliding in // Check if healthbox has finished sliding in
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI))) if (TwoIntroMons(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{ {
if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK]].callback == SpriteCallbackDummy)
healthboxAnimDone = TRUE; healthboxAnimDone = TRUE;
} }
else else
{ {
if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
&& gSprites[gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK]].callback == SpriteCallbackDummy)
healthboxAnimDone = TRUE; healthboxAnimDone = TRUE;
} }
@ -1065,7 +1070,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(void)
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
if (IsDoubleBattle()) if (TwoIntroMons(gActiveBattler))
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], gActiveBattler ^ BIT_FLANK); HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], gActiveBattler ^ BIT_FLANK);
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].introEndDelay = 3; gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].introEndDelay = 3;
@ -1094,7 +1099,7 @@ static void Intro_TryShinyAnimShowHealthbox(void)
{ {
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted) if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted)
{ {
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) if (TwoIntroMons(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{ {
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK], &gPlayerParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], HEALTHBOX_ALL); UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK], &gPlayerParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], HEALTHBOX_ALL);
StartHealthboxSlideIn(gActiveBattler ^ BIT_FLANK); StartHealthboxSlideIn(gActiveBattler ^ BIT_FLANK);
@ -1125,15 +1130,7 @@ static void Intro_TryShinyAnimShowHealthbox(void)
} }
// Wait for battler anims // Wait for battler anims
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI))) if (TwoIntroMons(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
{
battlerAnimsDone = TRUE;
}
}
else
{ {
if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy && gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy
@ -1143,11 +1140,19 @@ static void Intro_TryShinyAnimShowHealthbox(void)
battlerAnimsDone = TRUE; battlerAnimsDone = TRUE;
} }
} }
else
{
if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
{
battlerAnimsDone = TRUE;
}
}
// Clean up // Clean up
if (bgmRestored && battlerAnimsDone) if (bgmRestored && battlerAnimsDone)
{ {
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) if (TwoIntroMons(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
DestroySprite(&gSprites[gBattleControllerData[gActiveBattler ^ BIT_FLANK]]); DestroySprite(&gSprites[gBattleControllerData[gActiveBattler ^ BIT_FLANK]]);
DestroySprite(&gSprites[gBattleControllerData[gActiveBattler]]); DestroySprite(&gSprites[gBattleControllerData[gActiveBattler]]);
@ -3114,12 +3119,7 @@ static void Task_StartSendOutAnim(u8 taskId)
u8 savedActiveBattler = gActiveBattler; u8 savedActiveBattler = gActiveBattler;
gActiveBattler = gTasks[taskId].tBattlerId; gActiveBattler = gTasks[taskId].tBattlerId;
if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI)) if (TwoIntroMons(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
{
gBattleResources->bufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
StartSendOutAnim(gActiveBattler, FALSE);
}
else
{ {
gBattleResources->bufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler]; gBattleResources->bufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
StartSendOutAnim(gActiveBattler, FALSE); StartSendOutAnim(gActiveBattler, FALSE);
@ -3129,6 +3129,11 @@ static void Task_StartSendOutAnim(u8 taskId)
StartSendOutAnim(gActiveBattler, FALSE); StartSendOutAnim(gActiveBattler, FALSE);
gActiveBattler ^= BIT_FLANK; gActiveBattler ^= BIT_FLANK;
} }
else
{
gBattleResources->bufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
StartSendOutAnim(gActiveBattler, FALSE);
}
gBattlerControllerFuncs[gActiveBattler] = Intro_TryShinyAnimShowHealthbox; gBattlerControllerFuncs[gActiveBattler] = Intro_TryShinyAnimShowHealthbox;
gActiveBattler = savedActiveBattler; gActiveBattler = savedActiveBattler;
DestroyTask(taskId); DestroyTask(taskId);

View File

@ -588,6 +588,14 @@ static void InitLinkBtlControllers(void)
} }
} }
bool32 IsValidForBattle(struct Pokemon *mon)
{
u32 species = GetMonData(mon, MON_DATA_SPECIES2);
return (species != SPECIES_NONE && species != SPECIES_EGG
&& GetMonData(mon, MON_DATA_HP) != 0
&& GetMonData(mon, MON_DATA_IS_EGG) == 0);
}
static void SetBattlePartyIds(void) static void SetBattlePartyIds(void)
{ {
s32 i, j; s32 i, j;
@ -602,10 +610,7 @@ static void SetBattlePartyIds(void)
{ {
if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER) if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER)
{ {
if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0 if (IsValidForBattle(&gPlayerParty[j]))
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES2) != SPECIES_NONE
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES2) != SPECIES_EGG
&& GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG) == 0)
{ {
gBattlerPartyIndexes[i] = j; gBattlerPartyIndexes[i] = j;
break; break;
@ -613,10 +618,7 @@ static void SetBattlePartyIds(void)
} }
else else
{ {
if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0 if (IsValidForBattle(&gEnemyParty[j]))
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_NONE
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_EGG
&& GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG) == 0)
{ {
gBattlerPartyIndexes[i] = j; gBattlerPartyIndexes[i] = j;
break; break;
@ -627,11 +629,7 @@ static void SetBattlePartyIds(void)
{ {
if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER) if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER)
{ {
if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0 if (IsValidForBattle(&gPlayerParty[j]) && gBattlerPartyIndexes[i - 2] != j)
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES) != SPECIES_NONE // Probably a typo by Game Freak. The rest use SPECIES2.
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES2) != SPECIES_EGG
&& GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG) == 0
&& gBattlerPartyIndexes[i - 2] != j)
{ {
gBattlerPartyIndexes[i] = j; gBattlerPartyIndexes[i] = j;
break; break;
@ -639,16 +637,18 @@ static void SetBattlePartyIds(void)
} }
else else
{ {
if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0 if (IsValidForBattle(&gEnemyParty[j]) && gBattlerPartyIndexes[i - 2] != j)
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_NONE
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES2) != SPECIES_EGG
&& GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG) == 0
&& gBattlerPartyIndexes[i - 2] != j)
{ {
gBattlerPartyIndexes[i] = j; gBattlerPartyIndexes[i] = j;
break; break;
} }
} }
// No valid mons were found. Add the empty slot.
if (gBattlerPartyIndexes[i - 2] == 0)
gBattlerPartyIndexes[i] = 1;
else
gBattlerPartyIndexes[i] = 0;
} }
} }
} }

View File

@ -3461,6 +3461,13 @@ static void TryDoEventsBeforeFirstTurn(void)
if (gBattleControllerExecFlags) if (gBattleControllerExecFlags)
return; return;
// Set invalid mons as absent(for example when starting a double battle with only one pokemon).
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].hp == 0 || gBattleMons[i].species == SPECIES_NONE)
gAbsentBattlerFlags |= gBitTable[i];
}
if (gBattleStruct->switchInAbilitiesCounter == 0) if (gBattleStruct->switchInAbilitiesCounter == 0)
{ {
for (i = 0; i < gBattlersCount; i++) for (i = 0; i < gBattlersCount; i++)
@ -4892,6 +4899,7 @@ static void HandleEndTurn_FinishBattle(void)
{ {
UndoMegaEvolution(i); UndoMegaEvolution(i);
UndoFormChange(i, B_SIDE_PLAYER, FALSE); UndoFormChange(i, B_SIDE_PLAYER, FALSE);
DoBurmyFormChange(i);
} }
gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions; gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions;
gCB2_AfterEvolution = BattleMainCB2; gCB2_AfterEvolution = BattleMainCB2;

View File

@ -2579,7 +2579,7 @@ void BufferStringBattle(u16 stringID)
{ {
if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY) if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY)
stringPtr = sText_LegendaryPkmnAppeared; stringPtr = sText_LegendaryPkmnAppeared;
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[gActiveBattler ^ BIT_FLANK]])) // interesting, looks like they had something planned for wild double battles
stringPtr = sText_TwoWildPkmnAppeared; stringPtr = sText_TwoWildPkmnAppeared;
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
stringPtr = sText_WildPkmnAppearedPause; stringPtr = sText_WildPkmnAppearedPause;
@ -2590,7 +2590,7 @@ void BufferStringBattle(u16 stringID)
case STRINGID_INTROSENDOUT: // poke first send-out case STRINGID_INTROSENDOUT: // poke first send-out
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
{ {
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]]))
{ {
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
stringPtr = sText_InGamePartnerSentOutZGoN; stringPtr = sText_InGamePartnerSentOutZGoN;
@ -2608,7 +2608,7 @@ void BufferStringBattle(u16 stringID)
} }
else else
{ {
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]]))
{ {
if (BATTLE_TWO_VS_ONE_OPPONENT) if (BATTLE_TWO_VS_ONE_OPPONENT)
stringPtr = sText_Trainer1SentOutTwoPkmn; stringPtr = sText_Trainer1SentOutTwoPkmn;

View File

@ -1831,6 +1831,15 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi
return critChance; return critChance;
} }
s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move)
{
s32 critChanceIndex = CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE);
if(critChanceIndex < 0)
return -1;
else
return sCriticalHitChance[critChanceIndex];
}
static void Cmd_critcalc(void) static void Cmd_critcalc(void)
{ {
s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);
@ -1979,6 +1988,15 @@ static void Cmd_multihitresultmessage(void)
} }
} }
gBattlescriptCurrInstr++; gBattlescriptCurrInstr++;
// Print berry reducing message after result message.
if (gSpecialStatuses[gBattlerTarget].berryReduced
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
{
gSpecialStatuses[gBattlerTarget].berryReduced = 0;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_PrintBerryReduceString;
}
} }
static void Cmd_attackanimation(void) static void Cmd_attackanimation(void)
@ -11317,7 +11335,7 @@ static void Cmd_setcharge(void)
static void Cmd_callterrainattack(void) // nature power static void Cmd_callterrainattack(void) // nature power
{ {
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
gCurrentMove = sNaturePowerMoves[gBattleTerrain]; gCurrentMove = GetNaturePowerMove();
gBattlerTarget = GetMoveTarget(gCurrentMove, 0); gBattlerTarget = GetMoveTarget(gCurrentMove, 0);
BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]);
gBattlescriptCurrInstr++; gBattlescriptCurrInstr++;
@ -11325,7 +11343,14 @@ static void Cmd_callterrainattack(void) // nature power
u16 GetNaturePowerMove(void) u16 GetNaturePowerMove(void)
{ {
//TODO terrain if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)
return MOVE_MOONBLAST;
else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
return MOVE_THUNDERBOLT;
else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)
return MOVE_ENERGY_BALL;
else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)
return MOVE_PSYCHIC;
return sNaturePowerMoves[gBattleTerrain]; return sNaturePowerMoves[gBattleTerrain];
} }

View File

@ -4060,7 +4060,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
u32 opposingDef = 0, opposingSpDef = 0; u32 opposingDef = 0, opposingSpDef = 0;
opposingBattler = BATTLE_OPPOSITE(battler); opposingBattler = BATTLE_OPPOSITE(battler);
for (i = 0; i < 2; opposingBattler ^= BIT_SIDE, i++) for (i = 0; i < 2; opposingBattler ^= BIT_FLANK, i++)
{ {
if (IsBattlerAlive(opposingBattler)) if (IsBattlerAlive(opposingBattler))
{ {
@ -4084,6 +4084,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
{ {
gBattleMons[battler].statStages[statId]++; gBattleMons[battler].statStages[statId]++;
SET_STATCHANGER(statId, 1, FALSE); SET_STATCHANGER(statId, 1, FALSE);
gBattlerAttacker = battler;
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId); PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
BattleScriptPushCursorAndCallback(BattleScript_AttackerAbilityStatRaiseEnd3); BattleScriptPushCursorAndCallback(BattleScript_AttackerAbilityStatRaiseEnd3);
effect++; effect++;
@ -7810,7 +7811,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b
atkStage = gBattleMons[battlerDef].statStages[STAT_SPATK]; atkStage = gBattleMons[battlerDef].statStages[STAT_SPATK];
} }
} }
if (gBattleMoves[move].effect == EFFECT_BODY_PRESS) else if (gBattleMoves[move].effect == EFFECT_BODY_PRESS)
{ {
atkStat = gBattleMons[battlerAtk].defense; atkStat = gBattleMons[battlerAtk].defense;
atkStage = gBattleMons[battlerAtk].statStages[STAT_DEF]; atkStage = gBattleMons[battlerAtk].statStages[STAT_DEF];
@ -8400,16 +8401,18 @@ static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 bat
modifier = UQ_4_12(1.0); modifier = UQ_4_12(1.0);
} }
if (GetBattlerAbility(battlerDef) == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && gBattleMoves[move].power) if (((GetBattlerAbility(battlerDef) == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0))
|| (GetBattlerAbility(battlerDef) == ABILITY_TELEPATHY && battlerDef == BATTLE_PARTNER(battlerAtk)))
&& gBattleMoves[move].power)
{ {
modifier = UQ_4_12(0.0); modifier = UQ_4_12(0.0);
if (recordAbilities) if (recordAbilities)
{ {
gLastUsedAbility = ABILITY_WONDER_GUARD; gLastUsedAbility = gBattleMons[battlerDef].ability;
gMoveResultFlags |= MOVE_RESULT_MISSED; gMoveResultFlags |= MOVE_RESULT_MISSED;
gLastLandedMoves[battlerDef] = 0; gLastLandedMoves[battlerDef] = 0;
gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_DMG; gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_DMG;
RecordAbilityBattle(battlerDef, ABILITY_WONDER_GUARD); RecordAbilityBattle(battlerDef, gBattleMons[battlerDef].ability);
} }
} }
@ -8763,6 +8766,7 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battlerId)
id = i; id = i;
if (GetMonData(&party[id], MON_DATA_SANITY_HAS_SPECIES) if (GetMonData(&party[id], MON_DATA_SANITY_HAS_SPECIES)
&& GetMonData(&party[id], MON_DATA_HP) && GetMonData(&party[id], MON_DATA_HP)
&& !GetMonData(&party[id], MON_DATA_IS_EGG)
&& &party[id] != mon && &party[id] != mon
&& &party[id] != partnerMon) && &party[id] != partnerMon)
{ {
@ -9190,6 +9194,46 @@ bool32 TryRoomService(u8 battlerId)
} }
} }
void DoBurmyFormChange(u32 monId)
{
u16 newSpecies, currSpecies;
s32 sentIn;
struct Pokemon *party = gPlayerParty;
sentIn = gSentPokesToOpponent[(gBattlerFainted & 2) >> 1];
currSpecies = GetMonData(&party[monId], MON_DATA_SPECIES, NULL);
if ((GET_BASE_SPECIES_ID(currSpecies) == SPECIES_BURMY) && (gBitTable[monId] & sentIn))
{
switch (gBattleTerrain)
{
case BATTLE_TERRAIN_GRASS:
case BATTLE_TERRAIN_LONG_GRASS:
case BATTLE_TERRAIN_POND:
case BATTLE_TERRAIN_MOUNTAIN:
case BATTLE_TERRAIN_PLAIN:
newSpecies = SPECIES_BURMY;
break;
case BATTLE_TERRAIN_CAVE:
case BATTLE_TERRAIN_SAND:
newSpecies = SPECIES_BURMY_SANDY_CLOAK;
break;
case BATTLE_TERRAIN_BUILDING:
newSpecies = SPECIES_BURMY_TRASH_CLOAK;
break;
default: // Don't change form if last battle was water-related
newSpecies = SPECIES_NONE;
break;
}
if (newSpecies != SPECIES_NONE)
{
SetMonData(&party[monId], MON_DATA_SPECIES, &newSpecies);
CalculateMonStats(&party[monId]);
}
}
}
bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef) bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef)
{ {
if (gProtectStructs[battlerPrankster].pranksterElevated if (gProtectStructs[battlerPrankster].pranksterElevated

View File

@ -1393,6 +1393,7 @@ static const struct SearchOptionText sDexSearchTypeOptions[NUMBER_OF_MON_TYPES +
{gText_DexEmptyString, gTypeNames[TYPE_ICE]}, {gText_DexEmptyString, gTypeNames[TYPE_ICE]},
{gText_DexEmptyString, gTypeNames[TYPE_DRAGON]}, {gText_DexEmptyString, gTypeNames[TYPE_DRAGON]},
{gText_DexEmptyString, gTypeNames[TYPE_DARK]}, {gText_DexEmptyString, gTypeNames[TYPE_DARK]},
{gText_DexEmptyString, gTypeNames[TYPE_FAIRY]},
{}, {},
}; };
@ -1427,6 +1428,7 @@ static const u8 sDexSearchTypeIds[NUMBER_OF_MON_TYPES] =
TYPE_ICE, TYPE_ICE,
TYPE_DRAGON, TYPE_DRAGON,
TYPE_DARK, TYPE_DARK,
TYPE_FAIRY,
}; };
// Number pairs are the task data for tracking the cursor pos and scroll offset of each option list // Number pairs are the task data for tracking the cursor pos and scroll offset of each option list