Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Mortal Spin and Population Bomb #3178

Merged
merged 4 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion data/battle_anim_scripts.s
Original file line number Diff line number Diff line change
Expand Up @@ -14883,7 +14883,6 @@ Move_CORROSIVE_GAS::
clearmonbg ANIM_ATTACKER
end


@Credits to Skeli
Move_COACHING::
playsewithpan SE_M_TAIL_WHIP, SOUND_PAN_ATTACKER
Expand Down
17 changes: 14 additions & 3 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,18 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectSpinOut @ EFFECT_SPIN_OUT
.4byte BattleScript_EffectMakeItRain @ EFFECT_MAKE_IT_RAIN
.4byte BattleScript_EffectCorrosiveGas @ EFFECT_CORROSIVE_GAS

.4byte BattleScript_EffectHit @ EFFECT_POPULATION_BOMB
.4byte BattleScript_EffectMortalSpin @ EFFECT_MORTAL_SPIN

BattleScript_EffectMortalSpin:
call BattleScript_EffectHit_Ret
rapidspinfree
AsparagusEduardo marked this conversation as resolved.
Show resolved Hide resolved
setmoveeffect MOVE_EFFECT_POISON
seteffectwithchance
tryfaintmon BS_TARGET
moveendall
end

BattleScript_EffectCorrosiveGas:
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
Expand All @@ -452,7 +463,7 @@ BattleScript_EffectCorrosiveGas:
printstring STRINGID_PKMNITEMMELTED
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd

BattleScript_CorrosiveGasFail:
pause B_WAIT_TIME_SHORT
orhalfword gMoveResultFlags, MOVE_RESULT_FAILED
Expand Down Expand Up @@ -7787,7 +7798,7 @@ BattleScript_WishMegaEvolution::
BattleScript_PrimalReversion::
call BattleScript_PrimalReversionRet
end2

BattleScript_PrimalReversionRestoreAttacker::
call BattleScript_PrimalReversionRet
copybyte gBattlerAttacker, sSAVED_BATTLER
Expand Down
4 changes: 3 additions & 1 deletion include/constants/battle_move_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,9 @@
#define EFFECT_SPIN_OUT 407
#define EFFECT_MAKE_IT_RAIN 408
#define EFFECT_CORROSIVE_GAS 409
#define EFFECT_POPULATION_BOMB 410
#define EFFECT_MORTAL_SPIN 411

#define NUM_BATTLE_MOVE_EFFECTS 410
#define NUM_BATTLE_MOVE_EFFECTS 412

#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H
2 changes: 2 additions & 0 deletions src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3571,6 +3571,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
case EFFECT_TOXIC:
case EFFECT_POISON:
case EFFECT_BARB_BARRAGE:
case EFFECT_MORTAL_SPIN:
IncreasePoisonScore(battlerAtk, battlerDef, move, &score);
break;
case EFFECT_LIGHT_SCREEN:
Expand Down Expand Up @@ -4246,6 +4247,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
}
break;
case MOVE_RAPID_SPIN:
case MOVE_MORTAL_SPIN:
if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED)
score += 3;
break;
Expand Down
2 changes: 1 addition & 1 deletion src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *typeEffectiveness,
}

// Handle other multi-strike moves
if (gBattleMoves[move].strikeCount > 1)
if (gBattleMoves[move].strikeCount > 1 && gBattleMoves[move].effect != EFFECT_TRIPLE_KICK)
dmg *= gBattleMoves[move].strikeCount;
else if (move == MOVE_WATER_SHURIKEN && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH)
dmg *= 3;
Expand Down
15 changes: 9 additions & 6 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,8 @@ static void Cmd_accuracycheck(void)

u16 type, move = cmd->move;
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
u16 gBattlerAttackerAbility = GetBattlerAbility(gBattlerAttacker);
u8 gBattlerAttackerHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);

if (move == ACC_CURR_MOVE)
move = gCurrentMove;
Expand All @@ -1761,10 +1763,11 @@ static void Cmd_accuracycheck(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT
|| (gSpecialStatuses[gBattlerAttacker].multiHitOn && (gBattleMoves[move].effect != EFFECT_TRIPLE_KICK
|| GetBattlerAbility(gBattlerAttacker) == ABILITY_SKILL_LINK)))
|| (gSpecialStatuses[gBattlerAttacker].multiHitOn
&& (gBattlerAttackerAbility == ABILITY_SKILL_LINK || gBattlerAttackerHoldEffect == HOLD_EFFECT_LOADED_DICE
|| !(gBattleMoves[move].effect == EFFECT_TRIPLE_KICK || gBattleMoves[move].effect == EFFECT_POPULATION_BOMB))))
{
// No acc checks for second hit of Parental Bond or multi hit moves, except Triple Kick/Triple Axel
// No acc checks for second hit of Parental Bond or multi hit moves, except Triple Kick/Triple Axel/Population Bomb
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
Expand All @@ -1781,16 +1784,16 @@ static void Cmd_accuracycheck(void)
gBattlerAttacker,
gBattlerTarget,
move,
GetBattlerAbility(gBattlerAttacker),
gBattlerAttackerAbility,
GetBattlerAbility(gBattlerTarget),
GetBattlerHoldEffect(gBattlerAttacker, TRUE),
gBattlerAttackerHoldEffect,
GetBattlerHoldEffect(gBattlerTarget, TRUE)
);

if (!RandomPercentage(RNG_ACCURACY, accuracy))
{
gMoveResultFlags |= MOVE_RESULT_MISSED;
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY)
if (gBattlerAttackerHoldEffect == HOLD_EFFECT_BLUNDER_POLICY)
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks

if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
Expand Down
16 changes: 9 additions & 7 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -3742,13 +3742,15 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
}
else if (gBattleMoves[gCurrentMove].strikeCount > 1)
{
gMultiHitCounter = gBattleMoves[gCurrentMove].strikeCount;
PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0)
}
else if (gBattleMoves[gCurrentMove].effect == EFFECT_TRIPLE_KICK)
{
gMultiHitCounter = 3;
PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0)
if (gBattleMoves[gCurrentMove].effect == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE)
{
gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 10);
}
else
{
gMultiHitCounter = gBattleMoves[gCurrentMove].strikeCount;
PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0)
}
}
#if B_BEAT_UP >= GEN_5
else if (gBattleMoves[gCurrentMove].effect == EFFECT_BEAT_UP)
Expand Down
9 changes: 6 additions & 3 deletions src/data/battle_moves.h
Original file line number Diff line number Diff line change
Expand Up @@ -2886,6 +2886,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] =
.split = SPLIT_PHYSICAL,
.zMoveEffect = Z_EFFECT_NONE,
.makesContact = TRUE,
.strikeCount = 3,
},

[MOVE_THIEF] =
Expand Down Expand Up @@ -12357,6 +12358,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] =
.split = SPLIT_PHYSICAL,
.zMoveEffect = Z_EFFECT_NONE,
.makesContact = TRUE,
.strikeCount = 3,
},

[MOVE_DUAL_WINGBEAT] =
Expand Down Expand Up @@ -13152,7 +13154,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] =

[MOVE_POPULATION_BOMB] =
{
.effect = EFFECT_PLACEHOLDER, // EFFECT_MULTI_HIT maybe?
.effect = EFFECT_POPULATION_BOMB,
.power = 20,
.type = TYPE_NORMAL,
.accuracy = 90,
Expand All @@ -13165,6 +13167,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] =
.makesContact = TRUE,
.slicingMove = TRUE,
.metronomeBanned = TRUE,
.strikeCount = 10,
},

[MOVE_ICE_SPINNER] =
Expand Down Expand Up @@ -13246,12 +13249,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] =

[MOVE_MORTAL_SPIN] =
{
.effect = EFFECT_PLACEHOLDER, // EFFECT_MORTAL_SPIN
.effect = EFFECT_MORTAL_SPIN,
.power = 30,
.type = TYPE_POISON,
.accuracy = 100,
.pp = 15,
.secondaryEffectChance = 0,
.secondaryEffectChance = 100,
.target = MOVE_TARGET_BOTH,
.priority = 0,
.split = SPLIT_PHYSICAL,
Expand Down
24 changes: 24 additions & 0 deletions test/move_effect_mortal_spin.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "global.h"
#include "test_battle.h"

ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_MORTAL_SPIN].effect == EFFECT_MORTAL_SPIN);
}

SINGLE_BATTLE_TEST("Mortal Spin blows away hazards and poisons foe")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_STEALTH_ROCK); MOVE(player, MOVE_MORTAL_SPIN); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MORTAL_SPIN, player);
MESSAGE("Wobbuffet blew away Stealth Rock!");
MESSAGE("Foe Wobbuffet was poisoned!");
STATUS_ICON(opponent, poison: TRUE);
}
}

135 changes: 135 additions & 0 deletions test/move_effect_multi_hit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "global.h"
#include "test_battle.h"

ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT);
}

SINGLE_BATTLE_TEST("Multi hit Moves hit the maximum amount with Skill Link")
{
PASSES_RANDOMLY(100, 100, RNG_HITS);

GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SKILL_LINK); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BULLET_SEED); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
MESSAGE("Hit 5 time(s)!");
}
}

SINGLE_BATTLE_TEST("Multi hit Moves hit twice 35 Percent of the time")
{
PASSES_RANDOMLY(35, 100, RNG_HITS);

GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BULLET_SEED); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
MESSAGE("Hit 2 time(s)!");
}
}

SINGLE_BATTLE_TEST("Multi hit Moves hit thrice 35 Percent of the time")
{
PASSES_RANDOMLY(35, 100, RNG_HITS);

GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BULLET_SEED); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
MESSAGE("Hit 3 time(s)!");
}
}

SINGLE_BATTLE_TEST("Multi hit Moves hit four times 35 Percent of the time")
{
PASSES_RANDOMLY(15, 100, RNG_HITS);

GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BULLET_SEED); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
MESSAGE("Hit 4 time(s)!");
}
}

SINGLE_BATTLE_TEST("Multi hit Moves hit four times 35 Percent of the time")
{
PASSES_RANDOMLY(15, 100, RNG_HITS);

GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BULLET_SEED); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
MESSAGE("Hit 5 time(s)!");
}
}

SINGLE_BATTLE_TEST("Multi hit Moves hit at least four times with Loaded Dice")
{
PASSES_RANDOMLY(50, 100, RNG_LOADED_DICE);

GIVEN {
ASSUME(gItems[ITEM_LOADED_DICE].holdEffect == HOLD_EFFECT_LOADED_DICE);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LOADED_DICE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BULLET_SEED); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
MESSAGE("Hit 4 time(s)!");
}
}

SINGLE_BATTLE_TEST("Multi hit Moves hit five times 50 Percent of the time with Loaded Dice")
{
PASSES_RANDOMLY(50, 100, RNG_LOADED_DICE);

GIVEN {
ASSUME(gItems[ITEM_LOADED_DICE].holdEffect == HOLD_EFFECT_LOADED_DICE);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LOADED_DICE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BULLET_SEED); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
MESSAGE("Hit 5 time(s)!");
}
}
29 changes: 29 additions & 0 deletions test/move_effect_population_bomb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "global.h"
#include "test_battle.h"

SINGLE_BATTLE_TEST("Population Bomb can hit ten times")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_POPULATION_BOMB].strikeCount == 10);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_POPULATION_BOMB); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POPULATION_BOMB, player);
MESSAGE("Hit 10 time(s)!");
}
}

TO_DO_BATTLE_TEST("Accuracy for Population Bomb is checked independently for each hit")
TO_DO_BATTLE_TEST("Accuracy for Population Bomb is only checked for the first hit with Skill Link")
TO_DO_BATTLE_TEST("Accuracy for Population Bomb is only checked for the first hit with Loaded Dice")
Loading