diff --git a/asm/macros/event.inc b/asm/macros/event.inc index 1a4f65dfe..184fa8db1 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -2039,15 +2039,15 @@ @ The rest of the arguments are the stat change values to each stat. @ For example, giving the first opponent +1 to atk and -2 to speed would be: settotemboost B_POSITION_OPPONENT_LEFT, 1, 0, -2 .macro settotemboost battler:req, atk=0,def=0,speed=0,spatk=0,spdef=0,acc=0,evas=0 - setvar VAR_0x8000, \battler - setvar VAR_0x8001, \atk - setvar VAR_0x8002, \def - setvar VAR_0x8003, \speed - setvar VAR_0x8004, \spatk - setvar VAR_0x8005, \spdef - setvar VAR_0x8006, \acc - setvar VAR_0x8007, \evas - special SetTotemBoost + callnative ScriptSetTotemBoost + .2byte \battler + .2byte \atk + .2byte \def + .2byte \speed + .2byte \spatk + .2byte \spdef + .2byte \acc + .2byte \evas .endm @ useful totem boost macros diff --git a/src/battle_main.c b/src/battle_main.c index 2b2aebb52..4055df31f 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -35,6 +35,7 @@ #include "roamer.h" #include "safari_zone.h" #include "scanline_effect.h" +#include "script.h" #include "strings.h" #include "task.h" #include "test_runner.h" @@ -1659,6 +1660,7 @@ void FreeRestoreBattleData(void) FreeMonSpritesGfx(); FreeBattleSpritesData(); FreeBattleResources(); + ResetDynamicAiFunc(); } void CB2_QuitRecordedBattle(void) @@ -4217,9 +4219,9 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect) speed *= 2; else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0) speed /= 2; - else if (ability == ABILITY_PROTOSYNTHESIS && (gBattleWeather & B_WEATHER_SUN || gBattleStruct->boosterEnergyActivates & (1u << battler))) + else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battler))) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; - else if (ability == ABILITY_QUARK_DRIVE && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler))) + else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler))) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; // stat stages @@ -4599,6 +4601,9 @@ static void TurnValuesCleanUp(bool8 var0) if (gDisableStructs[i].substituteHP == 0) gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; + if (!(gStatuses3[i] & STATUS3_COMMANDER)) + gBattleStruct->commandingDondozo &= ~(1u << i); + gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF; } @@ -4607,6 +4612,7 @@ static void TurnValuesCleanUp(bool8 var0) gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; + gBattleStruct->usedEjectItem = 0; gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller } @@ -4670,15 +4676,15 @@ static bool32 TryDoMoveEffectsBeforeMoves(void) { gBattleStruct->focusPunchBattlers |= 1u << battlers[i]; gBattlerAttacker = battlers[i]; - switch (gChosenMoveByBattler[gBattlerAttacker]) + switch (gMovesInfo[gChosenMoveByBattler[gBattlerAttacker]].effect) { - case MOVE_FOCUS_PUNCH: + case EFFECT_FOCUS_PUNCH: BattleScriptExecute(BattleScript_FocusPunchSetUp); return TRUE; - case MOVE_BEAK_BLAST: + case EFFECT_BEAK_BLAST: BattleScriptExecute(BattleScript_BeakBlastSetUp); return TRUE; - case MOVE_SHELL_TRAP: + case EFFECT_SHELL_TRAP: BattleScriptExecute(BattleScript_ShellTrapSetUp); return TRUE; } @@ -5054,14 +5060,21 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) { gBattleMainFunc = ReturnFromBattleToOverworld; } + } - FreeAllWindowBuffers(); - if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + FreeAllWindowBuffers(); + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + // To account for Battle Factory and Slateport Battle Tent, enemy parties are zeroed out in the facilitites respective src/xxx.c files + // The ZeroEnemyPartyMons() call happens in SaveXXXChallenge function (eg. SaveFactoryChallenge) + if (!(gBattleTypeFlags & BATTLE_TYPE_FRONTIER)) { - FreeMonSpritesGfx(); - FreeBattleSpritesData(); - FreeBattleResources(); + ZeroEnemyPartyMons(); } + ResetDynamicAiFunc(); + FreeMonSpritesGfx(); + FreeBattleSpritesData(); + FreeBattleResources(); } } @@ -5071,22 +5084,29 @@ static void TryEvolvePokemon(void) for (i = 0; i < PARTY_SIZE; i++) { - if (!(sTriedEvolving & gBitTable[i])) + if (!(sTriedEvolving & (1u << i))) { u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, NULL); - sTriedEvolving |= gBitTable[i]; + bool32 evoModeNormal = TRUE; + sTriedEvolving |= 1u << i; - if (species == SPECIES_NONE && (gLeveledUpInBattle & gBitTable[i])) - { - gLeveledUpInBattle &= ~(gBitTable[i]); - species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_NORMAL, gLeveledUpInBattle, NULL); + if (species == SPECIES_NONE && (gLeveledUpInBattle & (1u << i))) + { + gLeveledUpInBattle &= ~(1u << i); + species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_ONLY, gLeveledUpInBattle, NULL); + } + + if (species == SPECIES_NONE) + { + species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_CANT_STOP, ITEM_NONE, NULL); + evoModeNormal = FALSE; } if (species != SPECIES_NONE) { FreeAllWindowBuffers(); gBattleMainFunc = WaitForEvoSceneToFinish; - EvolutionScene(&gPlayerParty[i], species, TRUE, i); + EvolutionScene(&gPlayerParty[i], species, evoModeNormal, i); return; } } @@ -5457,21 +5477,20 @@ void SetTypeBeforeUsingMove(u32 move, u32 battler) } } -// special to set a field's totem boost(s) -// inputs: -// var8000: battler -// var8001 - var8007: stat changes -void SetTotemBoost(void) +// Queues stat boosts for a given battler for totem battles +void ScriptSetTotemBoost(struct ScriptContext *ctx) { - u32 battler = gSpecialVar_0x8000; + u32 battler = VarGet(ScriptReadHalfword(ctx)); + u32 stat; u32 i; for (i = 0; i < (NUM_BATTLE_STATS - 1); i++) { - if (*(&gSpecialVar_0x8001 + i)) + stat = VarGet(ScriptReadHalfword(ctx)); + if (stat) { gQueuedStatBoosts[battler].stats |= (1 << i); - gQueuedStatBoosts[battler].statChanges[i] = *(&gSpecialVar_0x8001 + i); + gQueuedStatBoosts[battler].statChanges[i] = stat; gQueuedStatBoosts[battler].stats |= 0x80; // used as a flag for the "totem flared to life" script } } diff --git a/src/battle_util.c b/src/battle_util.c index 12dbe3b9d..a2315308b 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3241,6 +3241,18 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) } gBattleStruct->atkCancellerTracker++; break; + case CANCELLER_GHOST: // GHOST in pokemon tower + if (IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags)) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + gBattlescriptCurrInstr = BattleScript_TooScaredToMove; + else + gBattlescriptCurrInstr = BattleScript_GhostGetOutGetOut; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + effect = 1; + } + gBattleStruct->atkCancellerTracker++; + break; case CANCELLER_IN_LOVE: // infatuation if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) {