Adds Raging Bull and various fixes (#3552)

* Adds Raging Bull and various fixes

* fix compiling on abgcc

* syrup bomb anim fix

* sticky syrup anim in link battles

* fix sticky syrup in link battles

* fix battler index

---------

Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
Alex 2023-11-19 17:45:58 +01:00 committed by GitHub
parent b5cb92f0e2
commit 4cb03d4add
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 237 additions and 24 deletions

View File

@ -441,6 +441,7 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectHit @ EFFECT_IVY_CUDGEL
.4byte BattleScript_EffectMaxMove @ EFFECT_MAX_MOVE
.4byte BattleScript_EffectGlaiveRush @ EFFECT_GLAIVE_RUSH
.4byte BattleScript_EffectBrickBreak @ EFFECT_RAGING_BULL
BattleScript_EffectGlaiveRush::
call BattleScript_EffectHit_Ret
@ -450,9 +451,7 @@ BattleScript_EffectGlaiveRush::
BattleScript_EffectSyrupBomb::
setmoveeffect MOVE_EFFECT_SYRUP_BOMB
call BattleScript_EffectHit_Ret
tryfaintmon BS_TARGET
goto BattleScript_MoveEnd
goto BattleScript_EffectHit
BattleScript_SyrupBombActivates::
printstring STRINGID_TARGETCOVEREDINSTICKYCANDYSYRUP

View File

@ -251,7 +251,7 @@ void BtlController_EmitDrawPartyStatusSummary(u32 battler, u32 bufferId, struct
void BtlController_EmitHidePartyStatusSummary(u32 battler, u32 bufferId);
void BtlController_EmitEndBounceEffect(u32 battler, u32 bufferId);
void BtlController_EmitSpriteInvisibility(u32 battler, u32 bufferId, bool8 isInvisible);
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, u16 argument);
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, struct DisableStruct* disableStructPtr, u16 argument);
void BtlController_EmitLinkStandbyMsg(u32 battler, u32 bufferId, u8 mode, bool32 record);
void BtlController_EmitResetActionMoveSelection(u32 battler, u32 bufferId, u8 caseId);
void BtlController_EmitEndLinkBattle(u32 battler, u32 bufferId, u8 battleOutcome);

View File

@ -418,7 +418,8 @@
#define EFFECT_IVY_CUDGEL 412
#define EFFECT_MAX_MOVE 413
#define EFFECT_GLAIVE_RUSH 414
#define EFFECT_RAGING_BULL 415
#define NUM_BATTLE_MOVE_EFFECTS 415
#define NUM_BATTLE_MOVE_EFFECTS 416
#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H

View File

@ -9152,18 +9152,12 @@ void AnimTask_GetWeatherToSet(u8 taskId)
void AnimTask_SyrupBomb(u8 taskId)
{
struct Pokemon *party = GetBattlerParty(gBattleAnimAttacker);
u32 isShiny = IsMonShiny(&party[gBattlerPartyIndexes[gBattleAnimAttacker]]);
gDisableStructs[gBattleAnimTarget].syrupBombIsShiny = isShiny;
gBattleAnimArgs[0] = isShiny;
gBattleAnimArgs[0] = IsMonShiny(&party[gBattlerPartyIndexes[gBattleAnimAttacker]]);
DestroyAnimVisualTask(taskId);
}
void AnimTask_StickySyrup(u8 taskId)
{
if (gDisableStructs[gBattleAnimTarget].syrupBombIsShiny)
gBattleAnimArgs[0] = TRUE;
else
gBattleAnimArgs[0] = FALSE;
gBattleAnimArgs[0] = gAnimDisableStructPtr->syrupBombIsShiny;
DestroyAnimVisualTask(taskId);
}

View File

@ -1508,13 +1508,14 @@ void BtlController_EmitSpriteInvisibility(u32 battler, u32 bufferId, bool8 isInv
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4);
}
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, u16 argument)
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, struct DisableStruct* disableStructPtr, u16 argument)
{
gBattleResources->transferBuffer[0] = CONTROLLER_BATTLEANIMATION;
gBattleResources->transferBuffer[1] = animationId;
gBattleResources->transferBuffer[2] = argument;
gBattleResources->transferBuffer[3] = (argument & 0xFF00) >> 8;
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4);
memcpy(&gBattleResources->transferBuffer[4], disableStructPtr, sizeof(struct DisableStruct));
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4 + sizeof(struct DisableStruct));
}
// mode is a LINK_STANDBY_* constant
@ -3035,6 +3036,8 @@ void BtlController_HandleBattleAnimation(u32 battler, bool32 ignoreSE, bool32 up
u8 animationId = gBattleResources->bufferA[battler][1];
u16 argument = gBattleResources->bufferA[battler][2] | (gBattleResources->bufferA[battler][3] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[battler][4];
if (TryHandleLaunchBattleTableAnimation(battler, battler, battler, animationId, argument))
BattleControllerComplete(battler);
else

View File

@ -5648,6 +5648,13 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk)
else if (gBattleMons[battlerAtk].type3 != TYPE_MYSTERY)
gBattleStruct->dynamicMoveType = gBattleMons[battlerAtk].type3 | F_DYNAMIC_TYPE_2;
}
else if (gBattleMoves[move].effect == EFFECT_RAGING_BULL
&& (gBattleMons[battlerAtk].species == SPECIES_TAUROS_PALDEAN_COMBAT_BREED
|| gBattleMons[battlerAtk].species == SPECIES_TAUROS_PALDEAN_BLAZE_BREED
|| gBattleMons[battlerAtk].species == SPECIES_TAUROS_PALDEAN_AQUA_BREED))
{
gBattleStruct->dynamicMoveType = gBattleMons[battlerAtk].type2 | F_DYNAMIC_TYPE_2;
}
else if (gBattleMoves[move].effect == EFFECT_NATURAL_GIFT)
{
if (ItemId_GetPocket(gBattleMons[battlerAtk].item) == POCKET_BERRIES)

View File

@ -3619,8 +3619,11 @@ void SetMoveEffect(bool32 primary, u32 certain)
case MOVE_EFFECT_SYRUP_BOMB:
if (!(gStatuses4[gEffectBattler] & STATUS4_SYRUP_BOMB))
{
struct Pokemon *party = GetBattlerParty(gBattlerAttacker);
gStatuses4[gEffectBattler] |= STATUS4_SYRUP_BOMB;
gDisableStructs[gBattlerTarget].syrupBombTimer = 3;
gDisableStructs[gEffectBattler].syrupBombTimer = 3;
gDisableStructs[gEffectBattler].syrupBombIsShiny = IsMonShiny(&party[gBattlerPartyIndexes[gBattlerAttacker]]);
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_SyrupBombActivates;
}
@ -4901,7 +4904,7 @@ static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *n
|| animId == B_ANIM_PRIMAL_REVERSION
|| animId == B_ANIM_ULTRA_BURST)
{
BtlController_EmitBattleAnimation(battler, BUFFER_A, animId, *argPtr);
BtlController_EmitBattleAnimation(battler, BUFFER_A, animId, &gDisableStructs[battler], *argPtr);
MarkBattlerForControllerExec(battler);
gBattlescriptCurrInstr = nextInstr;
}
@ -4916,7 +4919,7 @@ static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *n
|| animId == B_ANIM_HAIL_CONTINUES
|| animId == B_ANIM_SNOW_CONTINUES)
{
BtlController_EmitBattleAnimation(battler, BUFFER_A, animId, *argPtr);
BtlController_EmitBattleAnimation(battler, BUFFER_A, animId, &gDisableStructs[battler], *argPtr);
MarkBattlerForControllerExec(battler);
gBattlescriptCurrInstr = nextInstr;
}
@ -4926,7 +4929,7 @@ static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *n
}
else
{
BtlController_EmitBattleAnimation(battler, BUFFER_A, animId, *argPtr);
BtlController_EmitBattleAnimation(battler, BUFFER_A, animId, &gDisableStructs[battler], *argPtr);
MarkBattlerForControllerExec(battler);
gBattlescriptCurrInstr = nextInstr;
}
@ -5091,7 +5094,7 @@ static void Cmd_playstatchangeanimation(void)
}
else if (changeableStatsCount != 0 && !gBattleScripting.statAnimPlayed)
{
BtlController_EmitBattleAnimation(battler, BUFFER_A, B_ANIM_STATS_CHANGE, statAnimId);
BtlController_EmitBattleAnimation(battler, BUFFER_A, B_ANIM_STATS_CHANGE, &gDisableStructs[battler], statAnimId);
MarkBattlerForControllerExec(battler);
if (flags & STAT_CHANGE_MULTIPLE_STATS && changeableStatsCount > 1)
gBattleScripting.statAnimPlayed = TRUE;

View File

@ -4112,7 +4112,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
{
u32 effect = 0;
u32 moveType, move;
u32 side;
u32 i, j;
struct Pokemon *mon;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
return 0;
@ -4700,12 +4702,15 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_ZERO_TO_HERO:
side = GetBattlerSide(battler);
mon = &GetSideParty(side)[gBattlerPartyIndexes[battler]];
if (!gSpecialStatuses[battler].switchInAbilityDone
&& gBattleMons[battler].species == SPECIES_PALAFIN_HERO
&& !gBattleStruct->transformZeroToHero[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)])
&& GetMonData(mon, MON_DATA_SPECIES) == SPECIES_PALAFIN_HERO
&& !gBattleStruct->transformZeroToHero[gBattlerPartyIndexes[battler]][side])
{
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
gBattleStruct->transformZeroToHero[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = TRUE;
gBattleStruct->transformZeroToHero[gBattlerPartyIndexes[battler]][side] = TRUE;
BattleScriptPushCursorAndCallback(BattleScript_ZeroToHeroActivates);
effect++;
}
@ -5258,6 +5263,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_STANCE_CHANGE:
case ABILITY_WONDER_GUARD:
case ABILITY_ZEN_MODE:
case ABILITY_ZERO_TO_HERO:
break;
default:
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD)

View File

@ -13862,7 +13862,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] =
[MOVE_RAGING_BULL] =
{
.effect = EFFECT_PLACEHOLDER, // EFFECT_RAGING_BULL
.effect = EFFECT_RAGING_BULL,
.power = 90,
.type = TYPE_NORMAL,
.accuracy = 100,

View File

@ -123,6 +123,46 @@ SINGLE_BATTLE_TEST("Role Play, Skill Swap, and Entrainment fail if either Pokém
}
}
SINGLE_BATTLE_TEST("Transform doesn't apply the heroic transformation message when copying Palafin")
{
GIVEN {
PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { SWITCH(player, 1); }
TURN { SWITCH(player, 0); MOVE(opponent, MOVE_TRANSFORM); }
} SCENE {
ABILITY_POPUP(player, ABILITY_ZERO_TO_HERO);
MESSAGE("Palafin underwent a heroic transformation!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, opponent);
MESSAGE("Foe Wobbuffet transformed into Palafin!");
NOT ABILITY_POPUP(opponent, ABILITY_ZERO_TO_HERO);
} THEN { EXPECT_EQ(player->species, SPECIES_PALAFIN_HERO); }
}
SINGLE_BATTLE_TEST("Imposter doesn't apply the heroic transformation message when copying Palafin")
{
GIVEN {
PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_DITTO) { Ability(ABILITY_IMPOSTER); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { SWITCH(player, 1); SWITCH(opponent, 1); }
TURN { SWITCH(player, 0); SWITCH(opponent, 0); }
} SCENE {
ABILITY_POPUP(player, ABILITY_ZERO_TO_HERO);
MESSAGE("Palafin underwent a heroic transformation!");
ABILITY_POPUP(opponent, ABILITY_IMPOSTER);
MESSAGE("Foe Ditto transformed into Palafin using Imposter!");
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_ZERO_TO_HERO);
MESSAGE("Foe Ditto underwent a heroic transformation!");
}
} THEN { EXPECT_EQ(player->species, SPECIES_PALAFIN_HERO); }
}
// Write Trace test and move this one to that file (including every other ability that can't be copied)
SINGLE_BATTLE_TEST("Zero to Hero cannot be copied by Trace")
{

View File

@ -0,0 +1,160 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_BRICK_BREAK].effect == EFFECT_BRICK_BREAK);
ASSUME(gBattleMoves[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE);
ASSUME(gBattleMoves[MOVE_LIGHT_SCREEN].effect == EFFECT_LIGHT_SCREEN);
ASSUME(gBattleMoves[MOVE_REFLECT].effect == EFFECT_REFLECT);
ASSUME(gBattleMoves[MOVE_AURORA_VEIL].effect == EFFECT_AURORA_VEIL);
}
SINGLE_BATTLE_TEST("Brick Break removes Light Screen, Reflect and Aurora Veil from the target's side of the field")
{
u16 move;
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
PARAMETRIZE { move = MOVE_REFLECT; }
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SNOWSCAPE); }
TURN { MOVE(opponent, move); MOVE(player, MOVE_BRICK_BREAK); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
MESSAGE("The wall shattered!");
HP_BAR(opponent);
}
}
SINGLE_BATTLE_TEST("Brick Break doesn't remove Light Screen, Reflect and Aurora Veil if the target is immune")
{
u16 move;
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
PARAMETRIZE { move = MOVE_REFLECT; }
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
KNOWN_FAILING;
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GASTLY);
} WHEN {
TURN { MOVE(player, MOVE_SNOWSCAPE); }
TURN { MOVE(opponent, move); MOVE(player, MOVE_BRICK_BREAK); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
MESSAGE("The wall shattered!");
HP_BAR(opponent);
}
}
}
SINGLE_BATTLE_TEST("Brick Break doesn't remove Light Screen, Reflect and Aurora Veil if the target Protected")
{
u16 move;
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
PARAMETRIZE { move = MOVE_REFLECT; }
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
TURN { MOVE(player, MOVE_BRICK_BREAK); MOVE(opponent, MOVE_PROTECT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
MESSAGE("The wall shattered!");
HP_BAR(opponent);
}
}
}
SINGLE_BATTLE_TEST("Brick Break doesn't remove Light Screen, Reflect and Aurora Veil if it misses")
{
u16 move;
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
PARAMETRIZE { move = MOVE_REFLECT; }
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHT_POWDER); }
} WHEN {
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
TURN { MOVE(player, MOVE_BRICK_BREAK, hit: FALSE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
MESSAGE("The wall shattered!");
HP_BAR(opponent);
}
}
}
DOUBLE_BATTLE_TEST("Brick Break can remove Light Screen, Reflect and Aurora Veil on users side")
{
u16 move;
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
PARAMETRIZE { move = MOVE_REFLECT; }
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(opponentLeft, MOVE_SNOWSCAPE);
MOVE(playerLeft, move);
MOVE(playerRight, MOVE_BRICK_BREAK, target: playerLeft);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, playerRight);
MESSAGE("The wall shattered!");
HP_BAR(playerLeft);
}
}
SINGLE_BATTLE_TEST("Move Raging Bull changes it's type depending on the Tauros Form")
{
u16 speciesPlayer;
u16 speciesOpponent;
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_COMBAT_BREED; speciesOpponent = SPECIES_CHARIZARD; }
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_BLAZE_BREED; speciesOpponent = SPECIES_BLASTOISE; }
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_AQUA_BREED; speciesOpponent = SPECIES_VENUSAUR; }
GIVEN {
PLAYER(speciesPlayer);
OPPONENT(speciesOpponent);
} WHEN {
TURN { MOVE(player, MOVE_RAGING_BULL); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, player);
HP_BAR(opponent);
MESSAGE("It's not very effective…");
}
}