[Bug] Fix strong winds calculation (#2423)
* Fix strong winds calculation * add unit test * Add strong winds effect message * Update src/locales/de/weather.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/es/weather.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/fr/weather.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/it/weather.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/ko/weather.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> --------- Co-authored-by: torranx <torranicles@gmail.com> Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com>
This commit is contained in:
parent
160a5ce5aa
commit
0f510996f0
|
@ -1162,7 +1162,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
return (!cancelled.value ? Number(typeMultiplier.value) : 0) as TypeDamageMultiplier;
|
||||
}
|
||||
|
||||
getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false): TypeDamageMultiplier {
|
||||
/**
|
||||
* Calculates the type effectiveness multiplier for an attack type
|
||||
* @param moveType Type of the move
|
||||
* @param source the Pokemon using the move
|
||||
* @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks)
|
||||
* @param simulated tag to only apply the strong winds effect message when the move is used
|
||||
* @returns a multiplier for the type effectiveness
|
||||
*/
|
||||
getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false, simulated: boolean = true): TypeDamageMultiplier {
|
||||
if (moveType === Type.STELLAR) {
|
||||
return this.isTerastallized() ? 2 : 1;
|
||||
}
|
||||
|
@ -1183,8 +1191,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
}).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
|
||||
|
||||
// Handle strong winds lowering effectiveness of types super effective against pure flying
|
||||
if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && multiplier >= 2 && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
|
||||
if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
|
||||
multiplier /= 2;
|
||||
if (!simulated) {
|
||||
this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!!this.summonData?.tags.find((tag) => tag instanceof TypeImmuneTag && tag.immuneType === moveType)) {
|
||||
|
@ -1739,7 +1750,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const cancelled = new Utils.BooleanHolder(false);
|
||||
const typeless = move.hasAttr(TypelessAttr);
|
||||
const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes(attr.immuneType)))
|
||||
? this.getAttackTypeEffectiveness(move.type, source)
|
||||
? this.getAttackTypeEffectiveness(move.type, source, false, false)
|
||||
: 1);
|
||||
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
|
||||
if (typeless) {
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "Alle Flug-Pokémon werden von rätselhaften Luftströmungen geschützt!",
|
||||
"strongWindsLapseMessage": "Die rätselhafte Luftströmung hält an.",
|
||||
"strongWindsEffectMessage": "Rätselhafte Luftströmungen haben den Angriff abgeschwächt!",
|
||||
"strongWindsClearMessage": "Die rätselhafte Luftströmung hat sich wieder geleget.",
|
||||
};
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "A heavy wind began!",
|
||||
"strongWindsLapseMessage": "The wind blows intensely.",
|
||||
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
|
||||
"strongWindsClearMessage": "The heavy wind stopped."
|
||||
};
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "¡Comenzó un fuerte viento!",
|
||||
"strongWindsLapseMessage": "El viento sopla intensamente.",
|
||||
"strongWindsEffectMessage": "¡Las misteriosas turbulencias atenúan el ataque!",
|
||||
"strongWindsClearMessage": "El fuerte viento cesó."
|
||||
};
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "Un vent mystérieux se lève !",
|
||||
"strongWindsLapseMessage": "Le vent mystérieux souffle violemment !",
|
||||
"strongWindsEffectMessage": "Le courant aérien mystérieux affaiblit l’attaque !",
|
||||
"strongWindsClearMessage": "Le vent mystérieux s’est dissipé…"
|
||||
};
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "È apparsa una corrente d'aria misteriosa!",
|
||||
"strongWindsLapseMessage": "La corrente d'aria soffia intensamente.",
|
||||
"strongWindsEffectMessage": "La corrente misteriosa indebolisce l’attacco!",
|
||||
"strongWindsClearMessage": "La corrente d'aria è cessata."
|
||||
};
|
||||
|
|
|
@ -41,5 +41,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "수수께끼의 난기류가\n비행포켓몬을 지킨다!",
|
||||
"strongWindsLapseMessage": "수수께끼의 난기류가 강렬하게 불고 있다",
|
||||
"strongWindsEffectMessage": "수수께끼의 난기류가 공격을 약하게 만들었다!",
|
||||
"strongWindsClearMessage": "수수께끼의 난기류가 멈췄다!" // 임의번역
|
||||
};
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "Ventos fortes apareceram!",
|
||||
"strongWindsLapseMessage": "Os ventos fortes continuam.",
|
||||
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
|
||||
"strongWindsClearMessage": "Os ventos fortes diminuíram.",
|
||||
};
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "吹起了神秘的乱流!",
|
||||
"strongWindsLapseMessage": "神秘的乱流势头不减。",
|
||||
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
|
||||
"strongWindsClearMessage": "神秘的乱流停止了。"
|
||||
};
|
||||
|
|
|
@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
|
|||
|
||||
"strongWindsStartMessage": "吹起了神秘的亂流!",
|
||||
"strongWindsLapseMessage": "神秘的亂流勢頭不減。",
|
||||
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
|
||||
"strongWindsClearMessage": "神秘的亂流停止了。"
|
||||
};
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import { Species } from "#enums/species";
|
||||
import {
|
||||
TurnStartPhase,
|
||||
} from "#app/phases";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { allMoves } from "#app/data/move.js";
|
||||
|
||||
describe("Weather - Strong Winds", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(10);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.TAILLOW);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.DELTA_STREAM);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.THUNDERBOLT, Moves.ICE_BEAM, Moves.ROCK_SLIDE]);
|
||||
});
|
||||
|
||||
it("electric type move is not very effective on Rayquaza", async () => {
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RAYQUAZA);
|
||||
|
||||
await game.startBattle([Species.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon();
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT));
|
||||
|
||||
await game.phaseInterceptor.to(TurnStartPhase);
|
||||
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.THUNDERBOLT].type, pikachu)).toBe(0.5);
|
||||
});
|
||||
|
||||
it("electric type move is neutral for flying type pokemon", async () => {
|
||||
await game.startBattle([Species.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon();
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT));
|
||||
|
||||
await game.phaseInterceptor.to(TurnStartPhase);
|
||||
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.THUNDERBOLT].type, pikachu)).toBe(1);
|
||||
});
|
||||
|
||||
it("ice type move is neutral for flying type pokemon", async () => {
|
||||
await game.startBattle([Species.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon();
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM));
|
||||
|
||||
await game.phaseInterceptor.to(TurnStartPhase);
|
||||
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ICE_BEAM].type, pikachu)).toBe(1);
|
||||
});
|
||||
|
||||
it("rock type move is neutral for flying type pokemon", async () => {
|
||||
await game.startBattle([Species.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon();
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.ROCK_SLIDE));
|
||||
|
||||
await game.phaseInterceptor.to(TurnStartPhase);
|
||||
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue