Merge branch 'battle_engine' of https://github.com/rh-hideout/pokeemerald-expansion into last_ball

This commit is contained in:
ghoulslash 2021-07-18 11:11:03 -06:00
commit 45d4cee243
14 changed files with 59 additions and 21 deletions

View File

@ -863,6 +863,7 @@ Move_ROOST:
Move_GRAVITY: Move_GRAVITY:
fadetobg BG_COSMIC fadetobg BG_COSMIC
waitbgfadein waitbgfadein
createvisualtask AnimTask_SetAnimTargetToAttackerOpposite, 1
playsewithpan SE_M_TAKE_DOWN, SOUND_PAN_ATTACKER playsewithpan SE_M_TAKE_DOWN, SOUND_PAN_ATTACKER
createvisualtask AnimTask_ShakeAndSinkMon, 5, ANIM_ATTACKER, 2, 0, 96, 30 createvisualtask AnimTask_ShakeAndSinkMon, 5, ANIM_ATTACKER, 2, 0, 96, 30
createvisualtask AnimTask_ShakeAndSinkMon, 5, ANIM_DEF_PARTNER, 2, 0, 96, 30 createvisualtask AnimTask_ShakeAndSinkMon, 5, ANIM_DEF_PARTNER, 2, 0, 96, 30

View File

@ -6258,6 +6258,8 @@ BattleScript_CottonDownActivates::
savetarget savetarget
setbyte gBattlerTarget, 0 setbyte gBattlerTarget, 0
BattleScript_CottonDownLoop: BattleScript_CottonDownLoop:
getbattlerfainted BS_TARGET
jumpifbyte CMP_EQUAL, gBattleCommunication, TRUE, BattleScript_CottonDownLoopIncrement
setstatchanger STAT_SPEED, 1, TRUE setstatchanger STAT_SPEED, 1, TRUE
jumpifbyteequal gBattlerTarget, gEffectBattler, BattleScript_CottonDownLoopIncrement jumpifbyteequal gBattlerTarget, gEffectBattler, BattleScript_CottonDownLoopIncrement
statbuffchange STAT_BUFF_NOT_PROTECT_AFFECTED, BattleScript_CottonDownTargetSpeedCantGoLower statbuffchange STAT_BUFF_NOT_PROTECT_AFFECTED, BattleScript_CottonDownTargetSpeedCantGoLower

View File

@ -36,6 +36,7 @@ u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbil
bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move);
bool32 AI_WeatherHasEffect(void); bool32 AI_WeatherHasEffect(void);
bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits); bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits);
bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags);
bool32 AI_IsBattlerGrounded(u8 battlerId); bool32 AI_IsBattlerGrounded(u8 battlerId);
bool32 HasDamagingMove(u8 battlerId); bool32 HasDamagingMove(u8 battlerId);
bool32 HasDamagingMoveOfType(u8 battlerId, u8 type); bool32 HasDamagingMoveOfType(u8 battlerId, u8 type);

View File

@ -124,7 +124,7 @@ u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId);
u16 GetWishMegaEvolutionSpecies(u16 preEvoSpecies, u16 moveId1, u16 moveId2, u16 moveId3, u16 moveId4); u16 GetWishMegaEvolutionSpecies(u16 preEvoSpecies, u16 moveId1, u16 moveId2, u16 moveId3, u16 moveId4);
bool32 CanMegaEvolve(u8 battlerId); bool32 CanMegaEvolve(u8 battlerId);
void UndoMegaEvolution(u32 monId); void UndoMegaEvolution(u32 monId);
void UndoFormChange(u32 monId, u32 side); void UndoFormChange(u32 monId, u32 side, bool32 isSwitchingOut);
bool32 DoBattlersShareType(u32 battler1, u32 battler2); bool32 DoBattlersShareType(u32 battler1, u32 battler2);
bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId); bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId);
struct Pokemon *GetIllusionMonPtr(u32 battlerId); struct Pokemon *GetIllusionMonPtr(u32 battlerId);

View File

@ -1,6 +1,8 @@
#ifndef GUARD_CONSTANTS_BATTLE_CONFIG_H #ifndef GUARD_CONSTANTS_BATTLE_CONFIG_H
#define GUARD_CONSTANTS_BATTLE_CONFIG_H #define GUARD_CONSTANTS_BATTLE_CONFIG_H
#include "constants/expansion_branches.h"
// Species with peculiar battle effects. // Species with peculiar battle effects.
#ifndef POKEMON_EXPANSION #ifndef POKEMON_EXPANSION
#define SPECIES_DIALGA 0 #define SPECIES_DIALGA 0

View File

@ -0,0 +1,10 @@
#ifndef GUARD_CONSTANTS_EXPANSION_BRANCHES_H
#define GUARD_CONSTANTS_EXPANSION_BRANCHES_H
// Branch defines: Used by other branches to detect each other.
// Each define must be here for each of RHH's branch you have pulled.
// e.g. If you have both the battle_engine and pokemon_expansion branch,
// then both BATTLE_ENGINE and POKEMON_EXPANSION must be defined here.
#define BATTLE_ENGINE
#endif

View File

@ -10,6 +10,7 @@
#include "constants/vars.h" #include "constants/vars.h"
#include "constants/species.h" #include "constants/species.h"
#include "constants/berry.h" #include "constants/berry.h"
#include "constants/expansion_branches.h"
// Prevent cross-jump optimization. // Prevent cross-jump optimization.
#define BLOCK_CROSS_JUMP asm(""); #define BLOCK_CROSS_JUMP asm("");
@ -127,12 +128,6 @@
f; \ f; \
}) })
// Branch defines: Used by other branches to detect each other.
// Each define must be here for each of RHH's branch you have pulled.
// e.g. If you have both the battle_engine and pokemon_expansion branch,
// then both BATTLE_ENGINE and POKEMON_EXPANSION must be defined here.
#define BATTLE_ENGINE
#define ROUND_BITS_TO_BYTES(numBits)(((numBits) / 8) + (((numBits) % 8) ? 1 : 0)) #define ROUND_BITS_TO_BYTES(numBits)(((numBits) / 8) + (((numBits) % 8) ? 1 : 0))
#define DEX_FLAGS_NO (ROUND_BITS_TO_BYTES(NUM_SPECIES)) #define DEX_FLAGS_NO (ROUND_BITS_TO_BYTES(NUM_SPECIES))

View File

@ -721,21 +721,20 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
#endif #endif
// terrain & effect checks // terrain & effect checks
if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) if (AI_IsTerrainAffected(battlerDef, STATUS_FIELD_ELECTRIC_TERRAIN))
{ {
if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN)
RETURN_SCORE_MINUS(20); RETURN_SCORE_MINUS(20);
} }
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) if (AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
{ {
if (IsNonVolatileStatusMoveEffect(moveEffect) || IsConfusionMoveEffect(moveEffect)) if (IsNonVolatileStatusMoveEffect(moveEffect) || IsConfusionMoveEffect(moveEffect))
RETURN_SCORE_MINUS(20); RETURN_SCORE_MINUS(20);
} }
if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) if (AI_IsTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && atkPriority > 0)
{ {
if (atkPriority > 0)
RETURN_SCORE_MINUS(20); RETURN_SCORE_MINUS(20);
} }
} // end check MOVE_TARGET_USER } // end check MOVE_TARGET_USER
@ -1641,11 +1640,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
case EFFECT_TEETER_DANCE: case EFFECT_TEETER_DANCE:
if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|| (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO)
|| (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) || (IsBattlerGrounded(battlerDef) && AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
|| (DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) || (DoesSubstituteBlockMove(battlerAtk, battlerDef, move)))
&& ((gBattleMons[AI_DATA->battlerDefPartner].status2 & STATUS2_CONFUSION) && ((gBattleMons[AI_DATA->battlerDefPartner].status2 & STATUS2_CONFUSION)
|| (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO) || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO)
|| (IsBattlerGrounded(AI_DATA->battlerDefPartner) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) || (IsBattlerGrounded(AI_DATA->battlerDefPartner) && AI_IsTerrainAffected(AI_DATA->battlerDefPartner, STATUS_FIELD_MISTY_TERRAIN))
|| (DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, move)))) || (DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, move))))
{ {
score -= 10; score -= 10;
@ -3836,7 +3835,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
score++; score++;
break; break;
case EFFECT_SAFEGUARD: case EFFECT_SAFEGUARD:
if (!(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) || !IsBattlerGrounded(battlerAtk)) if (!AI_IsTerrainAffected(battlerAtk, STATUS_FIELD_MISTY_TERRAIN) || !IsBattlerGrounded(battlerAtk))
score++; score++;
//if (CountUsablePartyMons(battlerDef) != 0) //if (CountUsablePartyMons(battlerDef) != 0)
//score += 8; //score += 8;

View File

@ -1110,6 +1110,15 @@ u16 AI_GetHoldEffect(u32 battlerId)
return holdEffect; return holdEffect;
} }
bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags)
{
if (gStatuses3[battlerId] & STATUS3_SEMI_INVULNERABLE)
return FALSE;
else if (!(gFieldStatuses & flags))
return FALSE;
return AI_IsBattlerGrounded(battlerId);
}
// different from IsBattlerGrounded in that we don't always know battler's hold effect or ability // different from IsBattlerGrounded in that we don't always know battler's hold effect or ability
bool32 AI_IsBattlerGrounded(u8 battlerId) bool32 AI_IsBattlerGrounded(u8 battlerId)
{ {

View File

@ -321,6 +321,12 @@ static void AnimTask_ShakeMonInPlace_Step(u8 taskId)
void AnimTask_ShakeAndSinkMon(u8 taskId) void AnimTask_ShakeAndSinkMon(u8 taskId)
{ {
u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]); u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
if (spriteId == SPRITE_NONE)
{
DestroyAnimVisualTask(taskId);
return;
}
gSprites[spriteId].pos2.x = gBattleAnimArgs[1]; gSprites[spriteId].pos2.x = gBattleAnimArgs[1];
gTasks[taskId].data[0] = spriteId; gTasks[taskId].data[0] = spriteId;
gTasks[taskId].data[1] = gBattleAnimArgs[1]; gTasks[taskId].data[1] = gBattleAnimArgs[1];

View File

@ -1084,3 +1084,9 @@ void AnimTask_SetInvisible(u8 taskId)
gSprites[spriteId].invisible = gBattleSpritesDataPtr->battlerData[battlerId].invisible = gBattleAnimArgs[1]; gSprites[spriteId].invisible = gBattleSpritesDataPtr->battlerData[battlerId].invisible = gBattleAnimArgs[1];
DestroyAnimVisualTask(taskId); DestroyAnimVisualTask(taskId);
} }
void AnimTask_SetAnimTargetToAttackerOpposite(u8 taskId)
{
gBattleAnimTarget = BATTLE_OPPOSITE(gBattleAnimAttacker);
DestroyAnimVisualTask(taskId);
}

View File

@ -3123,7 +3123,7 @@ void FaintClearSetData(void)
ClearBattlerMoveHistory(gActiveBattler); ClearBattlerMoveHistory(gActiveBattler);
ClearBattlerAbilityHistory(gActiveBattler); ClearBattlerAbilityHistory(gActiveBattler);
ClearBattlerItemEffectHistory(gActiveBattler); ClearBattlerItemEffectHistory(gActiveBattler);
UndoFormChange(gBattlerPartyIndexes[gActiveBattler], GET_BATTLER_SIDE(gActiveBattler)); UndoFormChange(gBattlerPartyIndexes[gActiveBattler], GET_BATTLER_SIDE(gActiveBattler), FALSE);
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]); UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]);
} }
@ -4888,7 +4888,7 @@ static void HandleEndTurn_FinishBattle(void)
for (i = 0; i < PARTY_SIZE; i++) for (i = 0; i < PARTY_SIZE; i++)
{ {
UndoMegaEvolution(i); UndoMegaEvolution(i);
UndoFormChange(i, B_SIDE_PLAYER); UndoFormChange(i, B_SIDE_PLAYER, FALSE);
} }
gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions; gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions;
gCB2_AfterEvolution = BattleMainCB2; gCB2_AfterEvolution = BattleMainCB2;

View File

@ -12098,6 +12098,7 @@ static void Cmd_handleballthrow(void)
{ {
BtlController_EmitBallThrowAnim(0, BALL_3_SHAKES_SUCCESS); BtlController_EmitBallThrowAnim(0, BALL_3_SHAKES_SUCCESS);
MarkBattlerForControllerExec(gActiveBattler); MarkBattlerForControllerExec(gActiveBattler);
UndoFormChange(gBattlerPartyIndexes[gBattlerTarget], GET_BATTLER_SIDE(gBattlerTarget));
gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem); SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
@ -12142,6 +12143,7 @@ static void Cmd_handleballthrow(void)
if (IsCriticalCapture()) if (IsCriticalCapture())
gBattleSpritesDataPtr->animationData->criticalCaptureSuccess = 1; gBattleSpritesDataPtr->animationData->criticalCaptureSuccess = 1;
UndoFormChange(gBattlerPartyIndexes[gBattlerTarget], GET_BATTLER_SIDE(gBattlerTarget));
gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem); SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
if (CalculatePlayerPartyCount() == PARTY_SIZE) if (CalculatePlayerPartyCount() == PARTY_SIZE)

View File

@ -492,7 +492,7 @@ void HandleAction_Switch(void)
if (gBattleResults.playerSwitchesCounter < 255) if (gBattleResults.playerSwitchesCounter < 255)
gBattleResults.playerSwitchesCounter++; gBattleResults.playerSwitchesCounter++;
UndoFormChange(gBattlerPartyIndexes[gBattlerAttacker], GetBattlerSide(gBattlerAttacker)); UndoFormChange(gBattlerPartyIndexes[gBattlerAttacker], GetBattlerSide(gBattlerAttacker), TRUE);
} }
void HandleAction_UseItem(void) void HandleAction_UseItem(void)
@ -8333,14 +8333,14 @@ void UndoMegaEvolution(u32 monId)
} }
} }
void UndoFormChange(u32 monId, u32 side) void UndoFormChange(u32 monId, u32 side, bool32 isSwitchingOut)
{ {
u32 i, currSpecies; u32 i, currSpecies;
struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty;
static const u16 species[][2] = // changed form id, default form id static const u16 species[][2] = // changed form id, default form id
{ {
{SPECIES_AEGISLASH_BLADE, SPECIES_AEGISLASH},
{SPECIES_MIMIKYU_BUSTED, SPECIES_MIMIKYU}, {SPECIES_MIMIKYU_BUSTED, SPECIES_MIMIKYU},
{SPECIES_AEGISLASH_BLADE, SPECIES_AEGISLASH},
{SPECIES_DARMANITAN_ZEN_MODE, SPECIES_DARMANITAN}, {SPECIES_DARMANITAN_ZEN_MODE, SPECIES_DARMANITAN},
{SPECIES_MINIOR, SPECIES_MINIOR_CORE_RED}, {SPECIES_MINIOR, SPECIES_MINIOR_CORE_RED},
{SPECIES_MINIOR_METEOR_BLUE, SPECIES_MINIOR_CORE_BLUE}, {SPECIES_MINIOR_METEOR_BLUE, SPECIES_MINIOR_CORE_BLUE},
@ -8352,8 +8352,13 @@ void UndoFormChange(u32 monId, u32 side)
{SPECIES_WISHIWASHI_SCHOOL, SPECIES_WISHIWASHI}, {SPECIES_WISHIWASHI_SCHOOL, SPECIES_WISHIWASHI},
}; };
if (isSwitchingOut) // Don't revert Mimikyu Busted when switching out
i = 1;
else
i = 0;
currSpecies = GetMonData(&party[monId], MON_DATA_SPECIES, NULL); currSpecies = GetMonData(&party[monId], MON_DATA_SPECIES, NULL);
for (i = 0; i < ARRAY_COUNT(species); i++) for (; i < ARRAY_COUNT(species); i++)
{ {
if (currSpecies == species[i][0]) if (currSpecies == species[i][0])
{ {