[Bug] Primal weather no longer persists if last mon dies to indirect damage (#3492)

* Fixed Delta Stream remaining active when last mon dies to indirect damage

* Rebasing changes

* Linting fix

* Combined if statements

* Changed params to optional

* Added unit test

* Apply suggestions from code review

* Fix test and remove `.js` from import

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
Taylor Le Lievre 2024-09-09 12:59:58 -04:00 committed by GitHub
parent 11d912bad8
commit 8df7422e8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 28 additions and 11 deletions

View File

@ -3923,7 +3923,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
} }
export class PostFaintAbAttr extends AbAttr { export class PostFaintAbAttr extends AbAttr {
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
return false; return false;
} }
} }
@ -3974,7 +3974,7 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr {
* @param args N/A * @param args N/A
* @returns {boolean} Returns true if the weather clears, otherwise false. * @returns {boolean} Returns true if the weather clears, otherwise false.
*/ */
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
const weatherType = pokemon.scene.arena.weather?.weatherType; const weatherType = pokemon.scene.arena.weather?.weatherType;
let turnOffWeather = false; let turnOffWeather = false;
@ -4022,8 +4022,8 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
this.damageRatio = damageRatio; this.damageRatio = damageRatio;
} }
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { if (move !== undefined && attacker !== undefined && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { //If the mon didn't die to indirect damage
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
pokemon.scene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated)); pokemon.scene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated));
if (cancelled.value || attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { if (cancelled.value || attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
@ -4052,8 +4052,8 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
super (); super ();
} }
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
if (!simulated) { if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage
const damage = pokemon.turnData.attacksReceived[0].damage; const damage = pokemon.turnData.attacksReceived[0].damage;
attacker.damageAndUpdate((damage), HitResult.OTHER); attacker.damageAndUpdate((damage), HitResult.OTHER);
attacker.turnData.damageTaken += damage; attacker.turnData.damageTaken += damage;
@ -4711,7 +4711,7 @@ export function applyPostBattleAbAttrs(attrType: Constructor<PostBattleAbAttr>,
} }
export function applyPostFaintAbAttrs(attrType: Constructor<PostFaintAbAttr>, export function applyPostFaintAbAttrs(attrType: Constructor<PostFaintAbAttr>,
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, simulated: boolean = false, ...args: any[]): Promise<void> { pokemon: Pokemon, attacker?: Pokemon, move?: Move, hitResult?: HitResult, simulated: boolean = false, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<PostFaintAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated); return applyAbAttrsInternal<PostFaintAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated);
} }

View File

@ -65,6 +65,8 @@ export class FaintPhase extends PokemonPhase {
if (pokemon.turnData?.attacksReceived?.length) { if (pokemon.turnData?.attacksReceived?.length) {
const lastAttack = pokemon.turnData.attacksReceived[0]; const lastAttack = pokemon.turnData.attacksReceived[0];
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct? applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct?
} else { //If killed by indirect damage, apply post-faint abilities without providing a last move
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon);
} }
const alivePlayField = this.scene.getField(true); const alivePlayField = this.scene.getField(true);

View File

@ -1,4 +1,5 @@
import { allMoves } from "#app/data/move"; import { allMoves } from "#app/data/move";
import { StatusEffect } from "#app/enums/status-effect";
import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { TurnStartPhase } from "#app/phases/turn-start-phase";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
@ -33,7 +34,7 @@ describe("Weather - Strong Winds", () => {
it("electric type move is not very effective on Rayquaza", async () => { it("electric type move is not very effective on Rayquaza", async () => {
game.override.enemySpecies(Species.RAYQUAZA); game.override.enemySpecies(Species.RAYQUAZA);
await game.startBattle([Species.PIKACHU]); await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -44,7 +45,7 @@ describe("Weather - Strong Winds", () => {
}); });
it("electric type move is neutral for flying type pokemon", async () => { it("electric type move is neutral for flying type pokemon", async () => {
await game.startBattle([Species.PIKACHU]); await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -55,7 +56,7 @@ describe("Weather - Strong Winds", () => {
}); });
it("ice type move is neutral for flying type pokemon", async () => { it("ice type move is neutral for flying type pokemon", async () => {
await game.startBattle([Species.PIKACHU]); await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -66,7 +67,7 @@ describe("Weather - Strong Winds", () => {
}); });
it("rock type move is neutral for flying type pokemon", async () => { it("rock type move is neutral for flying type pokemon", async () => {
await game.startBattle([Species.PIKACHU]); await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -75,4 +76,18 @@ describe("Weather - Strong Winds", () => {
await game.phaseInterceptor.to(TurnStartPhase); await game.phaseInterceptor.to(TurnStartPhase);
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1); expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1);
}); });
it("weather goes away when last trainer pokemon dies to indirect damage", async () => {
game.override.enemyStatusEffect(StatusEffect.POISON);
await game.classicMode.startBattle([Species.MAGIKARP]);
const enemy = game.scene.getEnemyPokemon()!;
enemy.hp = 1;
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.arena.weather?.weatherType).toBeUndefined();
});
}); });