Fix mold breaker + implement neutralising gas
parent
3a64a8390a
commit
453c5644aa
|
@ -2034,14 +2034,36 @@ export class SyncEncounterNatureAbAttr extends AbAttr {
|
|||
}
|
||||
|
||||
export class MoveAbilityBypassAbAttr extends AbAttr {
|
||||
private moveIgnoreFunc: (pokemon: Pokemon, move: Move) => boolean;
|
||||
|
||||
constructor(moveIgnoreFunc?: (pokemon: Pokemon, move: Move) => boolean) {
|
||||
super(false);
|
||||
|
||||
this.moveIgnoreFunc = moveIgnoreFunc || ((pokemon, move) => true);
|
||||
}
|
||||
|
||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
if (this.moveIgnoreFunc(pokemon, (args[0] as Move))) {
|
||||
cancelled.value = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class SuppressFieldAbilitiesAbAttr extends AbAttr {
|
||||
constructor() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
const ability = (args[0] as Ability);
|
||||
if (!ability.hasAttr(UnsuppressableAbilityAbAttr) && !ability.hasAttr(SuppressFieldAbilitiesAbAttr)) {
|
||||
cancelled.value = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class UncopiableAbilityAbAttr extends AbAttr {
|
||||
|
@ -2912,7 +2934,8 @@ export function initAbilities() {
|
|||
.attr(PostDefendAbilitySwapAbAttr)
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.GORILLA_TACTICS, "Gorilla Tactics (N)", "Boosts the Pokémon's Attack stat but only allows the use of the first selected move.", 8),
|
||||
new Ability(Abilities.NEUTRALIZING_GAS, "Neutralizing Gas (N)", "If the Pokémon with Neutralizing Gas is in the battle, the effects of all Pokémon's Abilities will be nullified or will not be triggered.", 8)
|
||||
new Ability(Abilities.NEUTRALIZING_GAS, "Neutralizing Gas (P)", "If the Pokémon with Neutralizing Gas is in the battle, the effects of all Pokémon's Abilities will be nullified or will not be triggered.", 8)
|
||||
.attr(SuppressFieldAbilitiesAbAttr)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr),
|
||||
|
@ -3028,7 +3051,8 @@ export function initAbilities() {
|
|||
new Ability(Abilities.EARTH_EATER, "Earth Eater", "If hit by a Ground-type move, the Pokémon has its HP restored instead of taking damage.", 9)
|
||||
.attr(TypeImmunityHealAbAttr, Type.GROUND)
|
||||
.ignorable(),
|
||||
new Ability(Abilities.MYCELIUM_MIGHT, "Mycelium Might (N)", "The Pokémon will always act more slowly when using status moves, but these moves will be unimpeded by the Ability of the target.", 9),
|
||||
new Ability(Abilities.MYCELIUM_MIGHT, "Mycelium Might (P)", "The Pokémon will always act more slowly when using status moves, but these moves will be unimpeded by the Ability of the target.", 9)
|
||||
.attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS),
|
||||
new Ability(Abilities.MINDS_EYE, "Mind's Eye (N)", "The Pokémon ignores changes to opponents' evasiveness, its accuracy can't be lowered, and it can hit Ghost types with Normal- and Fighting-type moves.", 9)
|
||||
.ignorable(),
|
||||
new Ability(Abilities.SUPERSWEET_SYRUP, "Supersweet Syrup (N)", "A sickly sweet scent spreads across the field the first time the Pokémon enters a battle, lowering the evasiveness of opposing Pokémon.", 9),
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as Utils from "../utils";
|
|||
import { WeatherType } from "./weather";
|
||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr } from "./ability";
|
||||
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr } from "./ability";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { allAbilities } from './ability';
|
||||
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||
|
@ -68,7 +68,8 @@ export enum MoveFlags {
|
|||
POWDER_MOVE = 2048,
|
||||
DANCE_MOVE = 4096,
|
||||
WIND_MOVE = 8192,
|
||||
TRIAGE_MOVE = 16384
|
||||
TRIAGE_MOVE = 16384,
|
||||
IGNORE_ABILITIES = 32768
|
||||
}
|
||||
|
||||
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
||||
|
@ -286,12 +287,24 @@ export default class Move {
|
|||
return this;
|
||||
}
|
||||
|
||||
ignoresAbilities(ignoresAbilities?: boolean): this {
|
||||
this.setFlag(MoveFlags.IGNORE_ABILITIES, ignoresAbilities);
|
||||
return this;
|
||||
}
|
||||
|
||||
checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean {
|
||||
switch (flag) {
|
||||
case MoveFlags.MAKES_CONTACT:
|
||||
if (user.hasAbilityWithAttr(IgnoreContactAbAttr))
|
||||
return false;
|
||||
break;
|
||||
case MoveFlags.IGNORE_ABILITIES:
|
||||
if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
|
||||
const abilityEffectsIgnored = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, this);
|
||||
if (abilityEffectsIgnored.value)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return !!(this.flags & flag);
|
||||
|
@ -5405,8 +5418,10 @@ export function initMoves() {
|
|||
new AttackMove(Moves.SPECTRAL_THIEF, Type.GHOST, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 7)
|
||||
.partial(),
|
||||
new AttackMove(Moves.SUNSTEEL_STRIKE, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 7)
|
||||
.ignoresAbilities()
|
||||
.partial(),
|
||||
new AttackMove(Moves.MOONGEIST_BEAM, Type.GHOST, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
||||
.ignoresAbilities()
|
||||
.partial(),
|
||||
new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, 100, 0, 7)
|
||||
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
||||
|
@ -5429,15 +5444,16 @@ export function initMoves() {
|
|||
.partial(),
|
||||
new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
||||
.attr(PhotonGeyserCategoryAttr)
|
||||
.ignoresAbilities()
|
||||
.partial(),
|
||||
/* Unused */
|
||||
new AttackMove(Moves.LIGHT_THAT_BURNS_THE_SKY, Type.PSYCHIC, MoveCategory.SPECIAL, 200, -1, 1, -1, 0, 7)
|
||||
.attr(PhotonGeyserCategoryAttr)
|
||||
.partial(),
|
||||
.ignoresAbilities(),
|
||||
new AttackMove(Moves.SEARING_SUNRAZE_SMASH, Type.STEEL, MoveCategory.PHYSICAL, 200, -1, 1, -1, 0, 7)
|
||||
.partial(),
|
||||
.ignoresAbilities(),
|
||||
new AttackMove(Moves.MENACING_MOONRAZE_MAELSTROM, Type.GHOST, MoveCategory.SPECIAL, 200, -1, 1, -1, 0, 7)
|
||||
.partial(),
|
||||
.ignoresAbilities(),
|
||||
new AttackMove(Moves.LETS_SNUGGLE_FOREVER, Type.FAIRY, MoveCategory.PHYSICAL, 190, -1, 1, -1, 0, 7)
|
||||
.partial(),
|
||||
new AttackMove(Moves.SPLINTERED_STORMSHARDS, Type.ROCK, MoveCategory.PHYSICAL, 190, -1, 1, -1, 0, 7)
|
||||
|
|
|
@ -25,7 +25,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
|
|||
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
|
||||
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
||||
import { Biome } from "../data/enums/biome";
|
||||
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability';
|
||||
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr } from '../data/ability';
|
||||
import { Abilities } from "#app/data/enums/abilities";
|
||||
import PokemonData from '../system/pokemon-data';
|
||||
import Battle, { BattlerIndex } from '../battle';
|
||||
|
@ -740,8 +740,21 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
if (passive && !this.hasPassive())
|
||||
return false;
|
||||
const ability = (!passive ? this.getAbility() : this.getPassiveAbility());
|
||||
if (ability.isIgnorable && this.scene.arena.ignoreAbilities)
|
||||
if (this.scene?.arena.ignoreAbilities && ability.isIgnorable)
|
||||
return false;
|
||||
if (this.summonData?.abilitySuppressed && !ability.hasAttr(UnsuppressableAbilityAbAttr))
|
||||
return false;
|
||||
if (this.isOnField() && !ability.hasAttr(SuppressFieldAbilitiesAbAttr)) {
|
||||
const suppressed = new Utils.BooleanHolder(false);
|
||||
this.scene.getField(true).map(p => {
|
||||
if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility())
|
||||
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, suppressed, [ability]));
|
||||
if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true))
|
||||
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, suppressed, [ability]));
|
||||
});
|
||||
if (suppressed.value)
|
||||
return false;
|
||||
}
|
||||
return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this));
|
||||
}
|
||||
|
||||
|
@ -2829,6 +2842,7 @@ export class PokemonSummonData {
|
|||
public disabledMove: Moves = Moves.NONE;
|
||||
public disabledTurns: integer = 0;
|
||||
public tags: BattlerTag[] = [];
|
||||
public abilitySuppressed: boolean = false;
|
||||
|
||||
public speciesForm: PokemonSpeciesForm;
|
||||
public fusionSpeciesForm: PokemonSpeciesForm;
|
||||
|
|
|
@ -2141,10 +2141,8 @@ export class MovePhase extends BattlePhase {
|
|||
}
|
||||
|
||||
if (!this.followUp) {
|
||||
const abilityEffectsIgnored = new Utils.BooleanHolder(false);
|
||||
this.scene.getField(true).map(p => applyAbAttrs(MoveAbilityBypassAbAttr, p, abilityEffectsIgnored));
|
||||
if (abilityEffectsIgnored.value)
|
||||
this.scene.arena.setIgnoreAbilities(true);
|
||||
if (this.move.getMove().checkFlag(MoveFlags.IGNORE_ABILITIES, this.pokemon, null))
|
||||
this.scene.arena.setIgnoreAbilities();
|
||||
} else {
|
||||
this.pokemon.turnData.hitsLeft = undefined;
|
||||
this.pokemon.turnData.hitCount = undefined;
|
||||
|
|
Loading…
Reference in New Issue