From 56c9564e7aadf45a41e9fcf3ef3a68024a26f7c8 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Fri, 17 Feb 2023 11:28:46 +0100 Subject: [PATCH] 8th gen Howl's effect (#2700) * Howl gen8 effect --- data/battle_scripts_1.s | 38 +++++++++++++ include/constants/battle_move_effects.h | 3 +- include/constants/battle_script_commands.h | 1 + src/battle_util.c | 3 + src/data/battle_moves.h | 3 +- test/move_effect_attack_up_user_ally.c | 65 ++++++++++++++++++++++ test/test_battle.h | 14 ++--- 7 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 test/move_effect_attack_up_user_ally.c diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 33af9f16e7..12b32c3f14 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -416,6 +416,44 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectSpecialAttackUpHit @ EFFECT_SPECIAL_ATTACK_UP_HIT .4byte BattleScript_EffectVictoryDance @ EFFECT_VICTORY_DANCE .4byte BattleScript_EffectTeatime @ EFFECT_TEATIME + .4byte BattleScript_EffectAttackUpUserAlly @ EFFECT_ATTACK_UP_USER_ALLY + +BattleScript_EffectAttackUpUserAlly: + jumpifnoally BS_ATTACKER, BattleScript_EffectAttackUp + attackcanceler + attackstring + ppreduce + jumpifstat BS_ATTACKER, CMP_NOT_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_EffectAttackUpUserAlly_Works + jumpifstat BS_ATTACKER_PARTNER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed +BattleScript_EffectAttackUpUserAlly_Works: + attackanimation + waitanimation + setstatchanger STAT_ATK, 1, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_EffectAttackUpUserAlly_TryAlly + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectAttackUpUserAllyUser_PrintString + setgraphicalstatchangevalues + playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 +BattleScript_EffectAttackUpUserAllyUser_PrintString: + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_EffectAttackUpUserAlly_TryAlly: + setallytonexttarget BattleScript_EffectAttackUpUserAlly_TryAlly_ +BattleScript_EffectAttackUpUserAlly_End: + goto BattleScript_MoveEnd +BattleScript_EffectAttackUpUserAlly_TryAlly_: + setstatchanger STAT_ATK, 1, FALSE + statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_EffectAttackUpUserAlly_End + jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectAttackUpUserAlly_AllyAnim + pause B_WAIT_TIME_SHORTEST + printstring STRINGID_TARGETSTATWONTGOHIGHER + waitmessage B_WAIT_TIME_LONG + goto BattleScript_EffectAttackUpUserAlly_End +BattleScript_EffectAttackUpUserAlly_AllyAnim: + setgraphicalstatchangevalues + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG + goto BattleScript_EffectAttackUpUserAlly_End BattleScript_EffectTeatime:: attackcanceler diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 2cf8d2f9c3..beab881512 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -397,7 +397,8 @@ #define EFFECT_SPECIAL_ATTACK_UP_HIT 391 #define EFFECT_VICTORY_DANCE 392 #define EFFECT_TEATIME 393 +#define EFFECT_ATTACK_UP_USER_ALLY 394 // Howl 8th Gen -#define NUM_BATTLE_MOVE_EFFECTS 394 +#define NUM_BATTLE_MOVE_EFFECTS 395 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 9351213946..68e927d75f 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -74,6 +74,7 @@ #define BS_PLAYER2 13 // for Cmd_updatestatusicon #define BS_OPPONENT2 14 #define BS_ABILITY_BATTLER 15 +#define BS_ATTACKER_PARTNER 16 // Cmd_accuracycheck #define NO_ACC_CALC_CHECK_LOCK_ON 0xFFFF diff --git a/src/battle_util.c b/src/battle_util.c index 8d350553de..4bded150b0 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1287,6 +1287,9 @@ u8 GetBattlerForBattleScript(u8 caseId) case BS_ATTACKER: ret = gBattlerAttacker; break; + case BS_ATTACKER_PARTNER: + ret = BATTLE_PARTNER(gBattlerAttacker); + break; case BS_EFFECT_BATTLER: ret = gEffectBattler; break; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index eed91d524c..997e7f4b34 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -6073,10 +6073,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = { #if B_UPDATED_MOVE_DATA >= GEN_8 .flags = FLAG_SNATCH_AFFECTED | FLAG_SOUND, + .effect = EFFECT_ATTACK_UP_USER_ALLY, #else .flags = FLAG_SNATCH_AFFECTED, + .effect = EFFECT_ATTACK_UP, #endif - .effect = EFFECT_ATTACK_UP, .power = 0, .type = TYPE_NORMAL, .accuracy = 0, diff --git a/test/move_effect_attack_up_user_ally.c b/test/move_effect_attack_up_user_ally.c new file mode 100644 index 0000000000..e98df30d8e --- /dev/null +++ b/test/move_effect_attack_up_user_ally.c @@ -0,0 +1,65 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_HOWL].effect == EFFECT_ATTACK_UP_USER_ALLY); +} + +SINGLE_BATTLE_TEST("Howl raises user's Attack", s16 damage) +{ + bool32 raiseAttack; + PARAMETRIZE { raiseAttack = FALSE; } + PARAMETRIZE { raiseAttack = TRUE; } + GIVEN { + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (raiseAttack) TURN { MOVE(player, MOVE_HOWL); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + if (raiseAttack) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HOWL, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's attack rose!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +DOUBLE_BATTLE_TEST("Howl raises user's and partner's Attack", s16 damageLeft, s16 damageRight) +{ + bool32 raiseAttack; + PARAMETRIZE { raiseAttack = FALSE; } + PARAMETRIZE { raiseAttack = TRUE; } + GIVEN { + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET) { Speed(15); }; + PLAYER(SPECIES_WYNAUT) { Speed(10); }; + OPPONENT(SPECIES_WOBBUFFET) { Speed(13); }; + OPPONENT(SPECIES_WYNAUT) { Speed(12); }; + } WHEN { + if (raiseAttack) TURN { MOVE(playerLeft, MOVE_HOWL); } + TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentRight); } + } SCENE { + if (raiseAttack) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HOWL, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Wobbuffet's attack rose!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Wynaut's attack rose!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &results[i].damageLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); + HP_BAR(opponentRight, captureDamage: &results[i].damageRight); + } FINALLY { + EXPECT_MUL_EQ(results[0].damageLeft, Q_4_12(1.5), results[1].damageLeft); + EXPECT_MUL_EQ(results[0].damageRight, Q_4_12(1.5), results[1].damageRight); + } +} diff --git a/test/test_battle.h b/test/test_battle.h index 8fb1ce6d3e..806e7947e1 100644 --- a/test/test_battle.h +++ b/test/test_battle.h @@ -112,17 +112,17 @@ * NOT STATUS_ICON(opponent, paralysis: TRUE); to say that Oddish was * not paralyzed without specifying the exact outputs which led to that. * - * As a final example, to test that Howl works you might: - * 1. Put a Wobbuffet that knows Howl and Tackle in your party. + * As a final example, to test that Meditate works you might: + * 1. Put a Wobbuffet that knows Meditate and Tackle in your party. * 2. Battle a wild Wobbuffet. * 3. Use Tackle and note the amount the HP bar reduced. * 4. Battle a wild Wobbuffet. - * 5. Use Howl and that that the stat change animation and message play. + * 5. Use Meditate and that the stat change animation and message play. * 6. Use Tackle and check that the HP bar reduced by more than in 3. * * This can be translated to an automated test as follows: * - * SINGLE_BATTLE_TEST("Howl raises Attack", s16 damage) + * SINGLE_BATTLE_TEST("Meditate raises Attack", s16 damage) * { * bool32 raiseAttack; * PARAMETRIZE { raiseAttack = FALSE; } @@ -132,11 +132,11 @@ * PLAYER(SPECIES_WOBBUFFET); * OPPONENT(SPECIES_WOBBUFFET); * } WHEN { - * if (raiseAttack) TURN { MOVE(player, MOVE_HOWL); } // 5. + * if (raiseAttack) TURN { MOVE(player, MOVE_MEDITATE); } // 5. * TURN { MOVE(player, MOVE_TACKLE); } // 3 & 6. * } SCENE { * if (raiseAttack) { - * ANIMATION(ANIM_TYPE_MOVE, MOVE_HOWL, player); + * ANIMATION(ANIM_TYPE_MOVE, MOVE_MEDITATE, player); * ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); // 5. * MESSAGE("Wobbuffet's attack rose!"); // 5. * } @@ -159,7 +159,7 @@ * of the first battle (with a small tolerance to account for rounding). * * You might notice that all the tests check the outputs the player - * could see rather than the internal battle state. e.g. the Howl test + * could see rather than the internal battle state. e.g. the Meditate test * could have used gBattleMons[B_POSITION_OPPONENT_LEFT].hp instead of * using HP_BAR to capture the damage. This is a deliberate choice, by * checking what the player can observe the tests are more robust to