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

Add Fillet Away + Belly Drum tweaks #3616

Merged
merged 24 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion asm/macros/battle_script.inc
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,7 @@
.byte 0xbb
.endm

.macro maxattackhalvehp failInstr:req
.macro halvehp failInstr:req
.byte 0xbc
.4byte \failInstr
.endm
Expand Down
41 changes: 40 additions & 1 deletion data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,41 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectBrickBreak @ EFFECT_RAGING_BULL
.4byte BattleScript_EffectHit @ EFFECT_RAGE_FIST
.4byte BattleScript_EffectDoodle @ EFFECT_DOODLE
.4byte BattleScript_EffectFilletAway @ EFFECT_FILLET_AWAY

BattleScript_EffectFilletAway:
kittenchilly marked this conversation as resolved.
Show resolved Hide resolved
attackcanceler
attackstring
ppreduce
jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_FilletAwayTryAttack
jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_FilletAwayTryAttack
jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_ButItFailed
BattleScript_FilletAwayTryAttack::
halvehp BattleScript_ButItFailed
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
attackanimation
waitanimation
setbyte sSTAT_ANIM_PLAYED, FALSE
playstatchangeanimation BS_ATTACKER, BIT_ATK | BIT_SPATK | BIT_SPEED, STAT_CHANGE_BY_TWO
setstatchanger STAT_ATK, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_FilletAwayTrySpAtk
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_FilletAwayTrySpAtk::
setstatchanger STAT_SPATK, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_FilletAwayTrySpeed
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_FilletAwayTrySpeed::
setstatchanger STAT_SPEED, 2, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_FilletAwayEnd
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_FilletAwayEnd::
bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
goto BattleScript_MoveEnd

BattleScript_EffectDoodle:
attackcanceler
Expand Down Expand Up @@ -5343,12 +5378,16 @@ BattleScript_EffectBellyDrum::
attackcanceler
kittenchilly marked this conversation as resolved.
Show resolved Hide resolved
attackstring
ppreduce
maxattackhalvehp BattleScript_ButItFailed
jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed
halvehp BattleScript_ButItFailed
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
attackanimation
waitanimation
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
playstatchangeanimation BS_ATTACKER, BIT_ATK, STAT_CHANGE_BY_TWO
setstatchanger STAT_ATK, MAX_STAT_STAGE, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_MoveEnd
printstring STRINGID_PKMNCUTHPMAXEDATTACK
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
Expand Down
3 changes: 2 additions & 1 deletion include/constants/battle_move_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@
#define EFFECT_RAGING_BULL 411
#define EFFECT_RAGE_FIST 412
#define EFFECT_DOODLE 413
#define EFFECT_FILLET_AWAY 414

#define NUM_BATTLE_MOVE_EFFECTS 414
#define NUM_BATTLE_MOVE_EFFECTS 415

#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H
18 changes: 11 additions & 7 deletions src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static u32 GetWildAiFlags(void)
static u32 GetAiFlags(u16 trainerId)
{
u32 flags = 0;

if (!(gBattleTypeFlags & BATTLE_TYPE_HAS_AI) && !IsWildMonSmart())
return 0;
if (trainerId == 0xFFFF)
Expand All @@ -167,26 +167,26 @@ static u32 GetAiFlags(u16 trainerId)
else
flags = gTrainers[trainerId].aiFlags;
}

if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
flags |= AI_FLAG_DOUBLE_BATTLE;

return flags;
}

void BattleAI_SetupFlags(void)
{
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI

#if DEBUG_OVERWORLD_MENU == TRUE
if (gIsDebugBattle)
{
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags;
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags;
return;
}
}
#endif

if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))
{
// smart wild AI
Expand All @@ -201,7 +201,7 @@ void BattleAI_SetupFlags(void)
else
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT];
}

if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE));
Expand Down Expand Up @@ -1699,6 +1699,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-6);
break;
case EFFECT_BELLY_DRUM:
case EFFECT_FILLET_AWAY:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both Belly Drum and Fillet Away are missing logic for when the stats are already maxed

if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY)
ADJUST_SCORE(-10);
else if (aiData->hpPercents[battlerAtk] <= 60)
Expand Down Expand Up @@ -5043,6 +5044,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_FOCUS_PUNCH:
case EFFECT_REVENGE:
case EFFECT_TEETER_DANCE:
case EFFECT_FILLET_AWAY:
if (Random() & 1)
ADJUST_SCORE(2);
break;
Expand Down Expand Up @@ -5193,6 +5195,7 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_CONVERSION_2:
case EFFECT_SAFEGUARD:
case EFFECT_BELLY_DRUM:
case EFFECT_FILLET_AWAY:
ADJUST_SCORE(-2);
break;
default:
Expand Down Expand Up @@ -5228,6 +5231,7 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_HAIL:
case EFFECT_SNOWSCAPE:
case EFFECT_RAIN_DANCE:
case EFFECT_FILLET_AWAY:
ADJUST_SCORE(-2);
break;
default:
Expand Down
2 changes: 2 additions & 0 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ static const u16 sEncouragedEncoreEffects[] =
EFFECT_WATER_SPORT,
EFFECT_DRAGON_DANCE,
EFFECT_CAMOUFLAGE,
EFFECT_FILLET_AWAY,
};

// Functions
Expand Down Expand Up @@ -2126,6 +2127,7 @@ bool32 IsAttackBoostMoveEffect(u32 effect)
case EFFECT_BELLY_DRUM:
case EFFECT_BULK_UP:
case EFFECT_GROWTH:
case EFFECT_FILLET_AWAY:
return TRUE;
default:
return FALSE;
Expand Down
3 changes: 2 additions & 1 deletion src/battle_dome.c
Original file line number Diff line number Diff line change
Expand Up @@ -4152,6 +4152,7 @@ static bool32 IsDomeComboMoveEffect(u32 effect)
case EFFECT_CHARGE:
case EFFECT_BULK_UP:
case EFFECT_ATTACK_ACCURACY_UP:
case EFFECT_FILLET_AWAY:
// Others
case EFFECT_FOCUS_ENERGY:
case EFFECT_LOCK_ON:
Expand Down Expand Up @@ -4343,7 +4344,7 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
move = gSaveBlock2Ptr->frontier.domePlayerPartyData[i].moves[j];
else
move = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].moves[j];

switch (k)
{
case MOVE_POINTS_COMBO:
Expand Down
13 changes: 5 additions & 8 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ static void Cmd_setsafeguard(void);
static void Cmd_magnitudedamagecalculation(void);
static void Cmd_jumpifnopursuitswitchdmg(void);
static void Cmd_setsunny(void);
static void Cmd_maxattackhalvehp(void);
static void Cmd_halvehp(void);
static void Cmd_copyfoestats(void);
static void Cmd_rapidspinfree(void);
static void Cmd_setdefensecurlbit(void);
Expand Down Expand Up @@ -802,7 +802,7 @@ void (* const gBattleScriptingCommandsTable[])(void) =
Cmd_magnitudedamagecalculation, //0xB9
Cmd_jumpifnopursuitswitchdmg, //0xBA
Cmd_setsunny, //0xBB
Cmd_maxattackhalvehp, //0xBC
Cmd_halvehp, //0xBC
Cmd_copyfoestats, //0xBD
Cmd_rapidspinfree, //0xBE
Cmd_setdefensecurlbit, //0xBF
Expand Down Expand Up @@ -13322,8 +13322,8 @@ static void Cmd_setsunny(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}

// Belly Drum
static void Cmd_maxattackhalvehp(void)
// Belly Drum, Fillet Away
static void Cmd_halvehp(void)
{
CMD_ARGS(const u8 *failInstr);

Expand All @@ -13332,11 +13332,8 @@ static void Cmd_maxattackhalvehp(void)
if (!(GetNonDynamaxMaxHP(gBattlerAttacker) / 2))
halfHp = 1;

// Belly Drum fails if the user's current HP is less than half its maximum, or if the user's Attack is already at +6 (even if the user has Contrary).
if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] < MAX_STAT_STAGE
&& gBattleMons[gBattlerAttacker].hp > halfHp)
if (gBattleMons[gBattlerAttacker].hp > halfHp)
{
gBattleMons[gBattlerAttacker].statStages[STAT_ATK] = MAX_STAT_STAGE;
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
Expand Down
2 changes: 1 addition & 1 deletion src/data/battle_moves.h
Original file line number Diff line number Diff line change
Expand Up @@ -13293,7 +13293,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] =

[MOVE_FILLET_AWAY] =
{
.effect = EFFECT_PLACEHOLDER, // EFFECT_FILLET_AWAY
.effect = EFFECT_FILLET_AWAY,
.power = 0,
.type = TYPE_NORMAL,
.accuracy = 0,
Expand Down
34 changes: 34 additions & 0 deletions test/battle/ability/contrary.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,37 @@ SINGLE_BATTLE_TEST("Contrary raises a stat after using a move which would normal
EXPECT_MUL_EQ(results[1].damage, Q_4_12(2.125), results[0].damage);
}
}

SINGLE_BATTLE_TEST("Contrary lowers a stat after using a move which would normally raise it: Belly Drum", s16 damageBefore, s16 damageAfter)
{
u32 ability;
PARAMETRIZE { ability = ABILITY_CONTRARY; }
PARAMETRIZE { ability = ABILITY_TANGLED_FEET; }
GIVEN {
ASSUME(gBattleMoves[MOVE_BELLY_DRUM].effect == EFFECT_BELLY_DRUM);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SPINDA) { Ability(ability); }
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { MOVE(opponent, MOVE_BELLY_DRUM); }
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
MESSAGE("Foe Spinda used Tackle!");
HP_BAR(player, captureDamage: &results[i].damageBefore);

if (ability == ABILITY_CONTRARY) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Spinda cut its own HP and maximized ATTACK!"); //Message stays the same
}
else {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Spinda cut its own HP and maximized ATTACK!");
}

HP_BAR(player, captureDamage: &results[i].damageAfter);
}
FINALLY {
EXPECT_MUL_EQ(results[0].damageBefore, UQ_4_12(0.25), results[0].damageAfter);
EXPECT_MUL_EQ(results[1].damageBefore, UQ_4_12(4.0), results[1].damageAfter);
}
}
92 changes: 92 additions & 0 deletions test/battle/move_effect/belly_drum.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "global.h"
#include "test/battle.h"

ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_BELLY_DRUM].effect == EFFECT_BELLY_DRUM);
}

SINGLE_BATTLE_TEST("Belly Drum cuts the user's HP in half")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BELLY_DRUM); }
} SCENE {
s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP);
HP_BAR(player, hp: maxHP / 2);
}
}

SINGLE_BATTLE_TEST("Belly Drum maximizes the user's Attack stat", s16 damage)
{
bool32 raiseAttack;
PARAMETRIZE { raiseAttack = FALSE; }
PARAMETRIZE { raiseAttack = TRUE; }
GIVEN {
ASSUME(gBattleMoves[MOVE_TACKLE].category == BATTLE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (raiseAttack) TURN { MOVE(player, MOVE_BELLY_DRUM); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
if (raiseAttack) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BELLY_DRUM, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet cut its own HP and maximized ATTACK!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(4), results[1].damage);
}
}

SINGLE_BATTLE_TEST("Belly Drum fails if user's current HP is half or less than half its maximum")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); HP(50);}
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BELLY_DRUM); }
} SCENE {
MESSAGE("But it failed!");
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BELLY_DRUM, player);
HP_BAR(player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
}
}
}

SINGLE_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SWORDS_DANCE); }
TURN { MOVE(player, MOVE_SWORDS_DANCE); }
TURN { MOVE(player, MOVE_SWORDS_DANCE); }
TURN { MOVE(player, MOVE_BELLY_DRUM); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Attack sharply rose!");

ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Attack sharply rose!");

ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Attack sharply rose!");

MESSAGE("But it failed!");
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BELLY_DRUM, player);
HP_BAR(player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
}
}
}
Loading
Loading