Last Respects effect + Fixed Supreme Overlord (#4151)

* Last Respects effect + Fixed Supreme Overlord

* Fixed ability pop-up happening when there's no fainted party members

* Fixed Supreme Overlord counting faints during the battle instead of fainted party

* Removed invalid test.

* Converted GetSupremeOverlordModifier to an inline function

* Created inline functions to obtain faint counters

* Fixed erroneous implemenation and tests
This commit is contained in:
Eduardo Quezada D'Ottone 2024-02-10 06:58:41 -03:00 committed by GitHub
parent 5496115f92
commit af95a09961
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 187 additions and 28 deletions

View file

@ -748,7 +748,6 @@ struct BattleStruct
u8 storedHealingWish:4; // Each battler as a bit.
u8 storedLunarDance:4; // Each battler as a bit.
u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies.
uq4_12_t supremeOverlordModifier[MAX_BATTLERS_COUNT];
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
u8 trainerSlideFirstCriticalHitMsgState:2;
@ -769,6 +768,7 @@ struct BattleStruct
u8 transformZeroToHero[NUM_BATTLE_SIDES];
u8 stickySyrupdBy[MAX_BATTLERS_COUNT];
u8 abilityActivated[NUM_BATTLE_SIDES];
u8 supremeOverlordCounter[MAX_BATTLERS_COUNT];
};
// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,

View file

@ -349,6 +349,7 @@ enum {
EFFECT_SHED_TAIL,
EFFECT_UPPER_HAND,
EFFECT_DRAGON_CHEER,
EFFECT_LAST_RESPECTS,
NUM_BATTLE_MOVE_EFFECTS,
};

View file

@ -3234,6 +3234,7 @@ const u8* FaintClearSetData(u32 battler)
{
s32 i;
const u8 *result = NULL;
u8 battlerSide = GetBattlerSide(battler);
for (i = 0; i < NUM_BATTLE_STATS; i++)
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
@ -3320,7 +3321,7 @@ const u8* FaintClearSetData(u32 battler)
for (i = 0; i < gBattlersCount; i++)
{
if (i != battler && GetBattlerSide(i) != GetBattlerSide(battler))
if (i != battler && GetBattlerSide(i) != battlerSide)
gBattleStruct->lastTakenMove[i] = MOVE_NONE;
gBattleStruct->lastTakenMoveFrom[i][battler] = 0;

View file

@ -60,7 +60,6 @@ static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler);
static u32 GetFlingPowerFromItemId(u32 itemId);
static void SetRandomMultiHitCounter();
static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item);
static uq4_12_t GetSupremeOverlordModifier(u32 battler);
static bool32 CanBeInfinitelyConfused(u32 battler);
extern const u8 *const gBattlescriptsForRunningByItem[];
@ -3946,25 +3945,20 @@ bool32 ChangeTypeBasedOnTerrain(u32 battler)
return TRUE;
}
// Supreme Overlord adds a damage boost for each fainted ally.
// The first ally adds a x1.2 boost, and subsequent allies add an extra x0.1 boost each.
static uq4_12_t GetSupremeOverlordModifier(u32 battler)
static inline u8 GetSideFaintCounter(u32 side)
{
u32 i;
struct Pokemon *party = GetBattlerParty(battler);
uq4_12_t modifier = UQ_4_12(1.0);
bool32 appliedFirstBoost = FALSE;
return (side == B_SIDE_PLAYER) ? gBattleResults.playerFaintCounter : gBattleResults.opponentFaintCounter;
}
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE
&& !GetMonData(&party[i], MON_DATA_IS_EGG)
&& GetMonData(&party[i], MON_DATA_HP) == 0)
modifier += (!appliedFirstBoost) ? UQ_4_12(0.2) : UQ_4_12(0.1);
appliedFirstBoost = TRUE;
}
static inline u8 GetBattlerSideFaintCounter(u32 battler)
{
return GetSideFaintCounter(GetBattlerSide(battler));
}
return modifier;
// Supreme Overlord adds a x0.1 damage boost for each fainted ally.
static inline uq4_12_t GetSupremeOverlordModifier(u32 battler)
{
return UQ_4_12(1.0) + (UQ_4_12(0.1) * gBattleStruct->supremeOverlordCounter[battler]);
}
static inline bool32 HadMoreThanHalfHpNowHasLess(u32 battler)
@ -4599,12 +4593,15 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_SUPREME_OVERLORD:
if (!gSpecialStatuses[battler].switchInAbilityDone && CountUsablePartyMons(battler) < PARTY_SIZE)
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
gBattleStruct->supremeOverlordModifier[battler] = GetSupremeOverlordModifier(battler);
BattleScriptPushCursorAndCallback(BattleScript_SupremeOverlordActivates);
effect++;
gBattleStruct->supremeOverlordCounter[battler] = min(5, GetBattlerSideFaintCounter(battler));
if (gBattleStruct->supremeOverlordCounter[battler] > 0)
{
BattleScriptPushCursorAndCallback(BattleScript_SupremeOverlordActivates);
effect++;
}
}
break;
case ABILITY_COSTAR:
@ -8662,6 +8659,9 @@ static inline u32 CalcMoveBasePower(u32 move, u32 battlerAtk, u32 battlerDef, u3
if (RandomPercentage(RNG_FICKLE_BEAM, 30))
basePower *= 2;
break;
case EFFECT_LAST_RESPECTS:
basePower += (basePower * min(100, GetBattlerSideFaintCounter(battlerAtk)));
break;
}
// Move-specific base power changes
@ -8888,7 +8888,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
modifier = uq4_12_multiply(modifier, UQ_4_12(1.5));
break;
case ABILITY_SUPREME_OVERLORD:
modifier = uq4_12_multiply(modifier, gBattleStruct->supremeOverlordModifier[battlerAtk]);
modifier = uq4_12_multiply(modifier, GetSupremeOverlordModifier(battlerAtk));
break;
}

View file

@ -2214,4 +2214,10 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleTvScore = 1,
.encourageEncore = TRUE,
},
[EFFECT_LAST_RESPECTS] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
};

View file

@ -18634,7 +18634,6 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.target = MOVE_TARGET_SELECTED,
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.metronomeBanned = TRUE, // Only since it isn't implemented yet
.forcePressure = TRUE,
},
@ -18686,7 +18685,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.description = COMPOUND_STRING(
"This move deals more damage\n"
"for each defeated ally."),
.effect = EFFECT_PLACEHOLDER, // EFFECT_LAST_RESPECTS
.effect = EFFECT_LAST_RESPECTS,
.power = 50,
.type = TYPE_GHOST,
.accuracy = 100,
@ -18694,7 +18693,6 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.target = MOVE_TARGET_SELECTED,
.priority = 0,
.category = DAMAGE_CATEGORY_PHYSICAL,
.metronomeBanned = TRUE, // Only since it isn't implemented yet
},
[MOVE_LUMINA_CRASH] =
@ -18851,7 +18849,6 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.priority = 0,
.category = DAMAGE_CATEGORY_PHYSICAL,
.makesContact = TRUE,
.metronomeBanned = TRUE, // Only since it isn't implemented yet
},
[MOVE_REVIVAL_BLESSING] =

View file

@ -0,0 +1,87 @@
#include "global.h"
#include "test/battle.h"
DOUBLE_BATTLE_TEST("Supreme Overlord boosts Attack by an additive 10% per fainted mon on the side", s16 damage)
{
bool32 switchMon = 0;
PARAMETRIZE { switchMon = FALSE; }
PARAMETRIZE { switchMon = TRUE; }
GIVEN {
PLAYER(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); }
PLAYER(SPECIES_PAWNIARD);
PLAYER(SPECIES_PAWNIARD);
PLAYER(SPECIES_PAWNIARD);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (switchMon)
TURN { SWITCH(playerLeft, 3); }
TURN { MOVE(playerRight, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerRight, 2); }
if (switchMon)
TURN { SWITCH(playerLeft, 0); }
TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.1), results[1].damage);
}
}
DOUBLE_BATTLE_TEST("Supreme Overlord's boost caps at a 1.5x multipler", s16 damage)
{
u32 faintCount = 0;
PARAMETRIZE { faintCount = 5; }
PARAMETRIZE { faintCount = 6; }
GIVEN {
PLAYER(SPECIES_PAWNIARD);
PLAYER(SPECIES_PAWNIARD);
PLAYER(SPECIES_PAWNIARD);
PLAYER(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerLeft, 2); }
TURN { MOVE(playerLeft, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerLeft, 0); USE_ITEM(playerRight, ITEM_REVIVE, 0); }
TURN { MOVE(playerLeft, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerLeft, 2); USE_ITEM(playerRight, ITEM_REVIVE, 2); }
TURN { MOVE(playerLeft, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerLeft, 0); USE_ITEM(playerRight, ITEM_REVIVE, 0); }
TURN { MOVE(playerLeft, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerLeft, 2); USE_ITEM(playerRight, ITEM_REVIVE, 2); }
if (faintCount == 6)
TURN { MOVE(playerLeft, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerLeft, 0); USE_ITEM(playerRight, ITEM_REVIVE, 0); }
TURN { SWITCH(playerRight, 3); }
TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
HP_BAR(opponentLeft, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
}
}
SINGLE_BATTLE_TEST("Supreme Overlord does not boost attack if party members are already fainted at the start of the battle", s16 damage)
{
u32 fainted = 0;
PARAMETRIZE { fainted = FALSE; }
PARAMETRIZE { fainted = TRUE; }
GIVEN {
PLAYER(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); }
PLAYER(SPECIES_PAWNIARD) { HP(fainted ? 0 : 1); }
PLAYER(SPECIES_PAWNIARD) { HP(fainted ? 0 : 1); }
PLAYER(SPECIES_PAWNIARD) { HP(fainted ? 0 : 1); }
PLAYER(SPECIES_PAWNIARD) { HP(fainted ? 0 : 1); }
PLAYER(SPECIES_PAWNIARD) { HP(fainted ? 0 : 1); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, target: opponent); }
} SCENE {
NONE_OF {
ABILITY_POPUP(player, ABILITY_SUPREME_OVERLORD);
MESSAGE("Kingambit gained strength from the fallen!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
}
}

View file

@ -0,0 +1,67 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_LAST_RESPECTS].effect == EFFECT_LAST_RESPECTS);
}
SINGLE_BATTLE_TEST("Last Respects power is multiplied by the amount of fainted mon in the user's side - Player", s16 damage)
{
u32 j = 0, faintCount = 0;
PARAMETRIZE { faintCount = 0; }
PARAMETRIZE { faintCount = 1; }
PARAMETRIZE { faintCount = 2; }
GIVEN {
PLAYER(SPECIES_GOLEM); // Not Wobbuffet to omit type effectiveness
PLAYER(SPECIES_GEODUDE);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LEPPA_BERRY); Moves(MOVE_RECYCLE, MOVE_NONE, MOVE_NONE, MOVE_NONE); }
} WHEN {
for (j = 0; j < faintCount; j++)
{
TURN { MOVE(opponent, MOVE_RECYCLE); SWITCH(player, 1); }
TURN { MOVE(opponent, MOVE_RECYCLE); MOVE(player, MOVE_MEMENTO); SEND_OUT(player, 0); }
TURN { MOVE(opponent, MOVE_RECYCLE); USE_ITEM(player, ITEM_REVIVE, partyIndex: 1); }
}
TURN {
MOVE(opponent, MOVE_RECYCLE);
MOVE(player, MOVE_LAST_RESPECTS);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_LAST_RESPECTS, player);
HP_BAR(opponent, captureDamage: &results[j].damage);
} THEN {
if (faintCount > 0)
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.0 + faintCount), results[faintCount].damage);
}
}
SINGLE_BATTLE_TEST("Last Respects power is multiplied by the amount of fainted mon in the user's side - Opponent", s16 damage)
{
u32 j = 0, faintCount = 0;
PARAMETRIZE { faintCount = 0; }
PARAMETRIZE { faintCount = 1; }
PARAMETRIZE { faintCount = 2; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LEPPA_BERRY); Moves(MOVE_RECYCLE, MOVE_NONE, MOVE_NONE, MOVE_NONE); }
OPPONENT(SPECIES_GOLEM); // Not Wobbuffet to omit type effectiveness
OPPONENT(SPECIES_GEODUDE);
} WHEN {
for (j = 0; j < faintCount; j++)
{
TURN { MOVE(player, MOVE_RECYCLE); SWITCH(opponent, 1); }
TURN { MOVE(player, MOVE_RECYCLE); MOVE(opponent, MOVE_MEMENTO); SEND_OUT(opponent, 0); }
TURN { MOVE(player, MOVE_RECYCLE); USE_ITEM(opponent, ITEM_REVIVE, partyIndex: 1); }
}
TURN {
MOVE(player, MOVE_RECYCLE);
MOVE(opponent, MOVE_LAST_RESPECTS);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_LAST_RESPECTS, opponent);
HP_BAR(player, captureDamage: &results[j].damage);
} THEN {
if (faintCount > 0)
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.0 + faintCount), results[faintCount].damage);
}
}