[Ability] Implement Ice Face (#1755)
* implement ice face ability * remove showing ability bar * fixes * add documentations * move code out of phases.ts * add hardcoded eiscue check, localization * add KO locale * remove unnecessary constructor * use && instead of || to specify ice form on eiscue
This commit is contained in:
parent
ba66f2c916
commit
8d6a0bb0a1
|
@ -59,6 +59,7 @@ import {InputsController} from "./inputs-controller";
|
||||||
import {UiInputs} from "./ui-inputs";
|
import {UiInputs} from "./ui-inputs";
|
||||||
import { MoneyFormat } from "./enums/money-format";
|
import { MoneyFormat } from "./enums/money-format";
|
||||||
import { NewArenaEvent } from "./battle-scene-events";
|
import { NewArenaEvent } from "./battle-scene-events";
|
||||||
|
import { Abilities } from "./data/enums/abilities";
|
||||||
import ArenaFlyout from "./ui/arena-flyout";
|
import ArenaFlyout from "./ui/arena-flyout";
|
||||||
import { EaseType } from "./ui/enums/ease-type";
|
import { EaseType } from "./ui/enums/ease-type";
|
||||||
|
|
||||||
|
@ -1048,6 +1049,12 @@ export default class BattleScene extends SceneBase {
|
||||||
if (resetArenaState) {
|
if (resetArenaState) {
|
||||||
this.arena.removeAllTags();
|
this.arena.removeAllTags();
|
||||||
playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
|
playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
|
||||||
|
|
||||||
|
for (const pokemon of this.getParty()) {
|
||||||
|
if (pokemon.hasAbility(Abilities.ICE_FACE)) {
|
||||||
|
pokemon.formIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.unshiftPhase(new ShowTrainerPhase(this));
|
this.unshiftPhase(new ShowTrainerPhase(this));
|
||||||
}
|
}
|
||||||
for (const pokemon of this.getParty()) {
|
for (const pokemon of this.getParty()) {
|
||||||
|
|
|
@ -3344,6 +3344,48 @@ export class PostSummonStatChangeOnArenaAbAttr extends PostSummonStatChangeAbAtt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies immunity to physical moves.
|
||||||
|
* This is used in Ice Face ability.
|
||||||
|
*/
|
||||||
|
export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
|
||||||
|
/**
|
||||||
|
* Applies the Ice Face pre-defense ability to the Pokémon.
|
||||||
|
* Removes BattlerTagType.ICE_FACE hit by physical attack and is in Ice Face form.
|
||||||
|
*
|
||||||
|
* @param {Pokemon} pokemon - The Pokémon with the Ice Face ability.
|
||||||
|
* @param {boolean} passive - Whether the ability is passive.
|
||||||
|
* @param {Pokemon} attacker - The attacking Pokémon.
|
||||||
|
* @param {PokemonMove} move - The move being used.
|
||||||
|
* @param {Utils.BooleanHolder} cancelled - A holder for whether the move was cancelled.
|
||||||
|
* @param {any[]} args - Additional arguments.
|
||||||
|
* @returns {boolean} - Whether the immunity was applied.
|
||||||
|
*/
|
||||||
|
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
|
const isImmune = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args);
|
||||||
|
|
||||||
|
if (isImmune) {
|
||||||
|
const simulated = args.length > 1 && args[1];
|
||||||
|
if (!simulated) {
|
||||||
|
pokemon.removeTag(BattlerTagType.ICE_FACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isImmune;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message triggered when the Pokémon avoids damage using the Ice Face ability.
|
||||||
|
* @param {Pokemon} pokemon - The Pokémon with the Ice Face ability.
|
||||||
|
* @param {string} abilityName - The name of the ability.
|
||||||
|
* @param {...any} args - Additional arguments.
|
||||||
|
* @returns {string} - The trigger message.
|
||||||
|
*/
|
||||||
|
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||||
|
return i18next.t("abilityTriggers:iceFaceAvoidedDamage", { pokemonName: pokemon.name, abilityName: abilityName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
|
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
|
||||||
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
|
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
|
@ -4330,8 +4372,14 @@ export function initAbilities() {
|
||||||
.attr(UnsuppressableAbilityAbAttr)
|
.attr(UnsuppressableAbilityAbAttr)
|
||||||
.attr(NoTransformAbilityAbAttr)
|
.attr(NoTransformAbilityAbAttr)
|
||||||
.attr(NoFusionAbilityAbAttr)
|
.attr(NoFusionAbilityAbAttr)
|
||||||
.ignorable()
|
// Add BattlerTagType.ICE_FACE if the pokemon is in ice face form
|
||||||
.unimplemented(),
|
.conditionalAttr(pokemon => pokemon.formIndex === 0, PostSummonAddBattlerTagAbAttr, BattlerTagType.ICE_FACE, 0, false)
|
||||||
|
// When summoned with active HAIL or SNOW, add BattlerTagType.ICE_FACE
|
||||||
|
.conditionalAttr(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW), PostSummonAddBattlerTagAbAttr, BattlerTagType.ICE_FACE, 0)
|
||||||
|
// When weather changes to HAIL or SNOW while pokemon is fielded, add BattlerTagType.ICE_FACE
|
||||||
|
.attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.ICE_FACE, 0, WeatherType.HAIL, WeatherType.SNOW)
|
||||||
|
.attr(IceFaceMoveImmunityAbAttr, (target, user, move) => move.getMove().category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE))
|
||||||
|
.ignorable(),
|
||||||
new Ability(Abilities.POWER_SPOT, 8)
|
new Ability(Abilities.POWER_SPOT, 8)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new Ability(Abilities.MIMICRY, 8)
|
new Ability(Abilities.MIMICRY, 8)
|
||||||
|
|
|
@ -15,6 +15,8 @@ import { TerrainType } from "./terrain";
|
||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
import { BattleStat } from "./battle-stat";
|
import { BattleStat } from "./battle-stat";
|
||||||
import { allAbilities } from "./ability";
|
import { allAbilities } from "./ability";
|
||||||
|
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
|
||||||
|
import { Species } from "./enums/species";
|
||||||
|
|
||||||
export enum BattlerTagLapseType {
|
export enum BattlerTagLapseType {
|
||||||
FAINT,
|
FAINT,
|
||||||
|
@ -1354,6 +1356,57 @@ export class CursedTag extends BattlerTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the Ice Face ability's effects.
|
||||||
|
*/
|
||||||
|
export class IceFaceTag extends BattlerTag {
|
||||||
|
constructor(sourceMove: Moves) {
|
||||||
|
super(BattlerTagType.ICE_FACE, BattlerTagLapseType.CUSTOM, 1, sourceMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the Ice Face tag can be added to the Pokémon.
|
||||||
|
* @param {Pokemon} pokemon - The Pokémon to which the tag might be added.
|
||||||
|
* @returns {boolean} - True if the tag can be added, false otherwise.
|
||||||
|
*/
|
||||||
|
canAdd(pokemon: Pokemon): boolean {
|
||||||
|
const weatherType = pokemon.scene.arena.weather?.weatherType;
|
||||||
|
const isWeatherSnowOrHail = weatherType === WeatherType.HAIL || weatherType === WeatherType.SNOW;
|
||||||
|
const isFormIceFace = pokemon.formIndex === 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Hard code Eiscue for now, this is to prevent the game from crashing if fused pokemon has Ice Face
|
||||||
|
if ((pokemon.species.speciesId === Species.EISCUE && isFormIceFace) || isWeatherSnowOrHail) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the Ice Face tag to the Pokémon.
|
||||||
|
* Triggers a form change to Ice Face if the Pokémon is not in its Ice Face form.
|
||||||
|
* @param {Pokemon} pokemon - The Pokémon to which the tag is added.
|
||||||
|
*/
|
||||||
|
onAdd(pokemon: Pokemon): void {
|
||||||
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
|
if (pokemon.formIndex !== 0) {
|
||||||
|
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the Ice Face tag from the Pokémon.
|
||||||
|
* Triggers a form change to Noice when the tag is removed.
|
||||||
|
* @param {Pokemon} pokemon - The Pokémon from which the tag is removed.
|
||||||
|
*/
|
||||||
|
onRemove(pokemon: Pokemon): void {
|
||||||
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
|
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): BattlerTag {
|
export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): BattlerTag {
|
||||||
switch (tagType) {
|
switch (tagType) {
|
||||||
case BattlerTagType.RECHARGING:
|
case BattlerTagType.RECHARGING:
|
||||||
|
@ -1467,6 +1520,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
||||||
return new MinimizeTag();
|
return new MinimizeTag();
|
||||||
case BattlerTagType.DESTINY_BOND:
|
case BattlerTagType.DESTINY_BOND:
|
||||||
return new DestinyBondTag(sourceMove, sourceId);
|
return new DestinyBondTag(sourceMove, sourceId);
|
||||||
|
case BattlerTagType.ICE_FACE:
|
||||||
|
return new IceFaceTag(sourceMove);
|
||||||
case BattlerTagType.NONE:
|
case BattlerTagType.NONE:
|
||||||
default:
|
default:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||||
|
|
|
@ -57,5 +57,6 @@ export enum BattlerTagType {
|
||||||
GROUNDED = "GROUNDED",
|
GROUNDED = "GROUNDED",
|
||||||
MAGNET_RISEN = "MAGNET_RISEN",
|
MAGNET_RISEN = "MAGNET_RISEN",
|
||||||
MINIMIZED = "MINIMIZED",
|
MINIMIZED = "MINIMIZED",
|
||||||
DESTINY_BOND = "DESTINY_BOND"
|
DESTINY_BOND = "DESTINY_BOND",
|
||||||
|
ICE_FACE = "ICE_FACE"
|
||||||
}
|
}
|
||||||
|
|
|
@ -730,6 +730,10 @@ export const pokemonFormChanges: PokemonFormChanges = {
|
||||||
[Species.GALAR_DARMANITAN]: [
|
[Species.GALAR_DARMANITAN]: [
|
||||||
new SpeciesFormChange(Species.GALAR_DARMANITAN, "", "zen", new SpeciesFormChangeManualTrigger(), true),
|
new SpeciesFormChange(Species.GALAR_DARMANITAN, "", "zen", new SpeciesFormChangeManualTrigger(), true),
|
||||||
new SpeciesFormChange(Species.GALAR_DARMANITAN, "zen", "", new SpeciesFormChangeManualTrigger(), true)
|
new SpeciesFormChange(Species.GALAR_DARMANITAN, "zen", "", new SpeciesFormChangeManualTrigger(), true)
|
||||||
|
],
|
||||||
|
[Species.EISCUE]: [
|
||||||
|
new SpeciesFormChange(Species.EISCUE, "", "no-ice", new SpeciesFormChangeManualTrigger(), true),
|
||||||
|
new SpeciesFormChange(Species.EISCUE, "no-ice", "", new SpeciesFormChangeManualTrigger(), true),
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,4 +4,5 @@ export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!",
|
"blockRecoilDamage" : "{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!",
|
||||||
"badDreams": "{{pokemonName}} ist in einem Alptraum gefangen!",
|
"badDreams": "{{pokemonName}} ist in einem Alptraum gefangen!",
|
||||||
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -5,5 +5,6 @@ export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"badDreams": "{{pokemonName}} is tormented!",
|
"badDreams": "{{pokemonName}} is tormented!",
|
||||||
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
||||||
"perishBody": "{{pokemonName}}'s {{abilityName}}\nwill faint both pokemon in 3 turns!",
|
"perishBody": "{{pokemonName}}'s {{abilityName}}\nwill faint both pokemon in 3 turns!",
|
||||||
"poisonHeal": "{{pokemonName}}'s {{abilityName}}\nrestored its HP a little!"
|
"poisonHeal": "{{pokemonName}}'s {{abilityName}}\nrestored its HP a little!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -4,4 +4,5 @@ export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "¡{{abilityName}} de {{pokemonName}}\nlo protegió del daño de retroceso!",
|
"blockRecoilDamage" : "¡{{abilityName}} de {{pokemonName}}\nlo protegió del daño de retroceso!",
|
||||||
"badDreams": "¡{{pokemonName}} está atormentado!",
|
"badDreams": "¡{{pokemonName}} está atormentado!",
|
||||||
"windPowerCharged": "¡{{pokemonName}} se ha cargado de electricidad gracias a {{moveName}}!",
|
"windPowerCharged": "¡{{pokemonName}} se ha cargado de electricidad gracias a {{moveName}}!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -3,5 +3,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
|
||||||
export const abilityTriggers: SimpleTranslationEntries = {
|
export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !",
|
"blockRecoilDamage" : "{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !",
|
||||||
"badDreams": "{{pokemonName}} a le sommeil agité !",
|
"badDreams": "{{pokemonName}} a le sommeil agité !",
|
||||||
"windPowerCharged": "{{pokemonName}} a été touché par la capacité {{moveName}} et se charge en électricité !"
|
"windPowerCharged": "{{pokemonName}} a été touché par la capacité {{moveName}} et se charge en électricité !",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -4,4 +4,5 @@ export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!",
|
"blockRecoilDamage" : "{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!",
|
||||||
"badDreams": "{{pokemonName}} è tormentato!",
|
"badDreams": "{{pokemonName}} è tormentato!",
|
||||||
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -3,4 +3,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
|
||||||
export const abilityTriggers: SimpleTranslationEntries = {
|
export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "{{pokemonName}}[[는]] {{abilityName}} 때문에\n반동 데미지를 받지 않는다!",
|
"blockRecoilDamage" : "{{pokemonName}}[[는]] {{abilityName}} 때문에\n반동 데미지를 받지 않는다!",
|
||||||
"badDreams": "{{pokemonName}}[[는]]\n나이트메어 때문에 시달리고 있다!",
|
"badDreams": "{{pokemonName}}[[는]]\n나이트메어 때문에 시달리고 있다!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -3,5 +3,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
|
||||||
export const abilityTriggers: SimpleTranslationEntries = {
|
export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "{{abilityName}} de {{pokemonName}}\nprotegeu-o do dano de recuo!",
|
"blockRecoilDamage" : "{{abilityName}} de {{pokemonName}}\nprotegeu-o do dano de recuo!",
|
||||||
"badDreams": "{{pokemonName}} está tendo pesadelos!",
|
"badDreams": "{{pokemonName}} está tendo pesadelos!",
|
||||||
"windPowerCharged": "Ser atingido por {{moveName}} carregou {{pokemonName}} com poder!"
|
"windPowerCharged": "Ser atingido por {{moveName}} carregou {{pokemonName}} com poder!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -3,5 +3,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
|
||||||
export const abilityTriggers: SimpleTranslationEntries = {
|
export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力!",
|
"blockRecoilDamage" : "{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力!",
|
||||||
"badDreams": "{{pokemonName}} 被折磨着!",
|
"badDreams": "{{pokemonName}} 被折磨着!",
|
||||||
"windPowerCharged": "受 {{moveName}} 的影响, {{pokemonName}} 提升了能力!"
|
"windPowerCharged": "受 {{moveName}} 的影响, {{pokemonName}} 提升了能力!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -3,5 +3,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
|
||||||
export const abilityTriggers: SimpleTranslationEntries = {
|
export const abilityTriggers: SimpleTranslationEntries = {
|
||||||
"blockRecoilDamage" : "{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力!",
|
"blockRecoilDamage" : "{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力!",
|
||||||
"badDreams": "{{pokemonName}} 被折磨着!",
|
"badDreams": "{{pokemonName}} 被折磨着!",
|
||||||
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!"
|
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
||||||
|
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
Loading…
Reference in New Issue