[Bug] Apply Supreme Overlord only once on summon (#6575)

* Implement supreme overlord as a battler tag

* Make ability a conditionalattr

* Add tag to map

* Update test

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Add edgeCase marker

* Extend from AbilityBattlerTag

* Run biome

---------

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>
This commit is contained in:
Dean 2025-09-19 21:08:02 -07:00 committed by GitHub
parent 16a903b975
commit 405b1d389d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 84 additions and 3 deletions

View File

@ -89,7 +89,8 @@ export type AbilityBattlerTagType =
| BattlerTagType.QUARK_DRIVE
| BattlerTagType.UNBURDEN
| BattlerTagType.SLOW_START
| BattlerTagType.TRUANT;
| BattlerTagType.TRUANT
| BattlerTagType.SUPREME_OVERLORD;
/** Subset of {@linkcode BattlerTagType}s that provide type boosts */
export type TypeBoostTagType = BattlerTagType.FIRE_BOOST | BattlerTagType.CHARGED;

View File

@ -7742,8 +7742,8 @@ export function initAbilities() {
new Ability(AbilityId.SHARPNESS, 9)
.attr(MovePowerBoostAbAttr, (_user, _target, move) => move.hasFlag(MoveFlags.SLICING_MOVE), 1.5),
new Ability(AbilityId.SUPREME_OVERLORD, 9)
.attr(VariableMovePowerBoostAbAttr, (user, _target, _move) => 1 + 0.1 * Math.min(user.isPlayer() ? globalScene.arena.playerFaints : globalScene.currentBattle.enemyFaints, 5))
.partial(), // Should only boost once, on summon
.conditionalAttr((p) => (p.isPlayer() ? globalScene.arena.playerFaints : globalScene.currentBattle.enemyFaints) > 0, PostSummonAddBattlerTagAbAttr, BattlerTagType.SUPREME_OVERLORD, 0, true)
.edgeCase(), // Tag is not tied to ability, so suppression/removal etc will not function until a structure to allow this is implemented
new Ability(AbilityId.COSTAR, 9, -2)
.attr(PostSummonCopyAllyStatsAbAttr),
new Ability(AbilityId.TOXIC_DEBRIS, 9)

View File

@ -3626,6 +3626,41 @@ export class MagicCoatTag extends BattlerTag {
}
}
/**
* Tag associated with {@linkcode AbilityId.SUPREME_OVERLORD}
*/
export class SupremeOverlordTag extends AbilityBattlerTag {
public override readonly tagType = BattlerTagType.SUPREME_OVERLORD;
/** The number of faints at the time the user was sent out */
public readonly faintCount: number;
constructor() {
super(BattlerTagType.SUPREME_OVERLORD, AbilityId.SUPREME_OVERLORD, BattlerTagLapseType.FAINT, 0);
}
public override onAdd(pokemon: Pokemon): boolean {
(this as Mutable<this>).faintCount = Math.min(
pokemon.isPlayer() ? globalScene.arena.playerFaints : globalScene.currentBattle.enemyFaints,
5,
);
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:supremeOverlordOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
);
return true;
}
/**
* @returns The damage multiplier for Supreme Overlord
*/
public getBoost(): number {
return 1 + 0.1 * this.faintCount;
}
public override loadTag(source: BaseBattlerTag & Pick<SupremeOverlordTag, "tagType" | "faintCount">): void {
super.loadTag(source);
(this as Mutable<this>).faintCount = source.faintCount;
}
}
/**
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
* @param sourceId - The ID of the pokemon adding the tag
@ -3826,6 +3861,8 @@ export function getBattlerTag(
return new PsychoShiftTag();
case BattlerTagType.MAGIC_COAT:
return new MagicCoatTag();
case BattlerTagType.SUPREME_OVERLORD:
return new SupremeOverlordTag();
}
}
@ -3960,4 +3997,5 @@ export type BattlerTagTypeMap = {
[BattlerTagType.GRUDGE]: GrudgeTag;
[BattlerTagType.PSYCHO_SHIFT]: PsychoShiftTag;
[BattlerTagType.MAGIC_COAT]: MagicCoatTag;
[BattlerTagType.SUPREME_OVERLORD]: SupremeOverlordTag;
};

View File

@ -18,6 +18,7 @@ import {
ShellTrapTag,
StockpilingTag,
SubstituteTag,
SupremeOverlordTag,
TrappedTag,
TypeBoostTag,
} from "#data/battler-tags";
@ -879,6 +880,8 @@ export abstract class Move implements Localizable {
power.value *= 1.5;
}
power.value *= (source.getTag(BattlerTagType.SUPREME_OVERLORD) as SupremeOverlordTag | undefined)?.getBoost() ?? 1;
return power.value;
}

View File

@ -94,4 +94,5 @@ export enum BattlerTagType {
ENDURE_TOKEN = "ENDURE_TOKEN",
POWDER = "POWDER",
MAGIC_COAT = "MAGIC_COAT",
SUPREME_OVERLORD = "SUPREME_OVERLORD",
}

View File

@ -1,6 +1,7 @@
import { allMoves } from "#data/data-lists";
import { AbilityId } from "#enums/ability-id";
import { BattlerIndex } from "#enums/battler-index";
import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
import type { Move } from "#moves/move";
@ -166,4 +167,41 @@ describe("Abilities - Supreme Overlord", () => {
expect(move.calculateBattlePower).toHaveLastReturnedWith(basePower);
});
it("should not increase in power if ally faints while on the field", async () => {
game.override.battleStyle("double");
await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]);
game.move.select(MoveId.TACKLE, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
game.move.select(MoveId.LUNAR_DANCE, BattlerIndex.PLAYER_2);
await game.setTurnOrder([BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
await game.toEndOfTurn();
expect(game.field.getPlayerPokemon()).not.toHaveBattlerTag(BattlerTagType.SUPREME_OVERLORD);
expect(move.calculateBattlePower).toHaveLastReturnedWith(basePower);
});
it("should persist fainted count through reload", async () => {
// Avoid learning moves
game.override.startingLevel(1000);
await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]);
game.move.select(MoveId.LUNAR_DANCE);
game.doSelectPartyPokemon(1);
await game.toNextTurn();
game.move.select(MoveId.TACKLE);
await game.toEndOfTurn();
expect(move.calculateBattlePower).toHaveLastReturnedWith(basePower * 1.1);
await game.toNextWave();
await game.reload.reloadSession();
expect(game.field.getPlayerPokemon()).toHaveBattlerTag({ tagType: BattlerTagType.SUPREME_OVERLORD, faintCount: 1 });
game.move.select(MoveId.TACKLE);
await game.toEndOfTurn();
expect(move.calculateBattlePower).toHaveLastReturnedWith(basePower * 1.1);
});
});