Implement Magic Guard ability
parent
b9b7afb3ee
commit
f95f3ff30e
|
@ -977,9 +977,16 @@ export class BlockCritAbAttr extends AbAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class BlockNonDirectDamageAbAttr extends AbAttr {
|
||||||
|
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
|
cancelled.value = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class BlockOneHitKOAbAttr extends AbAttr {
|
export class BlockOneHitKOAbAttr extends AbAttr {
|
||||||
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
cancelled.value = false;
|
cancelled.value = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2200,7 +2207,8 @@ export function initAbilities() {
|
||||||
new Ability(Abilities.QUICK_FEET, "Quick Feet (N)", "Boosts the Speed stat if the Pokémon has a status condition.", 4),
|
new Ability(Abilities.QUICK_FEET, "Quick Feet (N)", "Boosts the Speed stat if the Pokémon has a status condition.", 4),
|
||||||
new Ability(Abilities.NORMALIZE, "Normalize (N)", "All the Pokémon's moves become Normal type. The power of those moves is boosted a little.", 4),
|
new Ability(Abilities.NORMALIZE, "Normalize (N)", "All the Pokémon's moves become Normal type. The power of those moves is boosted a little.", 4),
|
||||||
new Ability(Abilities.SNIPER, "Sniper (N)", "Powers up moves if they become critical hits when attacking.", 4),
|
new Ability(Abilities.SNIPER, "Sniper (N)", "Powers up moves if they become critical hits when attacking.", 4),
|
||||||
new Ability(Abilities.MAGIC_GUARD, "Magic Guard (N)", "The Pokémon only takes damage from attacks.", 4),
|
new Ability(Abilities.MAGIC_GUARD, "Magic Guard", "The Pokémon only takes damage from attacks.", 4)
|
||||||
|
.attr(BlockNonDirectDamageAbAttr),
|
||||||
new Ability(Abilities.NO_GUARD, "No Guard (N)", "The Pokémon employs no-guard tactics to ensure incoming and outgoing attacks always land.", 4),
|
new Ability(Abilities.NO_GUARD, "No Guard (N)", "The Pokémon employs no-guard tactics to ensure incoming and outgoing attacks always land.", 4),
|
||||||
new Ability(Abilities.STALL, "Stall (N)", "The Pokémon moves after all other Pokémon do.", 4),
|
new Ability(Abilities.STALL, "Stall (N)", "The Pokémon moves after all other Pokémon do.", 4),
|
||||||
new Ability(Abilities.TECHNICIAN, "Technician", "Powers up the Pokémon's weaker moves.", 4)
|
new Ability(Abilities.TECHNICIAN, "Technician", "Powers up the Pokémon's weaker moves.", 4)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { StatusEffect } from "./status-effect";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { Moves } from "./enums/moves";
|
import { Moves } from "./enums/moves";
|
||||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||||
|
import { BlockNonDirectDamageAbAttr, applyAbAttrs } from "./ability";
|
||||||
|
|
||||||
export enum ArenaTagSide {
|
export enum ArenaTagSide {
|
||||||
BOTH,
|
BOTH,
|
||||||
|
@ -172,6 +173,10 @@ class SpikesTag extends ArenaTrapTag {
|
||||||
|
|
||||||
activateTrap(pokemon: Pokemon): boolean {
|
activateTrap(pokemon: Pokemon): boolean {
|
||||||
if (pokemon.isGrounded()) {
|
if (pokemon.isGrounded()) {
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
|
if (!cancelled.value) {
|
||||||
const damageHpRatio = 1 / (10 - 2 * this.layers);
|
const damageHpRatio = 1 / (10 - 2 * this.layers);
|
||||||
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
|
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
|
||||||
|
|
||||||
|
@ -179,6 +184,7 @@ class SpikesTag extends ArenaTrapTag {
|
||||||
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -293,6 +299,12 @@ class StealthRockTag extends ArenaTrapTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
activateTrap(pokemon: Pokemon): boolean {
|
activateTrap(pokemon: Pokemon): boolean {
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
|
if (cancelled.value)
|
||||||
|
return false;
|
||||||
|
|
||||||
const damageHpRatio = this.getDamageHpRatio(pokemon);
|
const damageHpRatio = this.getDamageHpRatio(pokemon);
|
||||||
|
|
||||||
if (damageHpRatio) {
|
if (damageHpRatio) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import * as Utils from "../utils";
|
||||||
import { Moves } from "./enums/moves";
|
import { Moves } from "./enums/moves";
|
||||||
import { ChargeAttr, MoveFlags, allMoves } from "./move";
|
import { ChargeAttr, MoveFlags, allMoves } from "./move";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import { Abilities, FlinchEffectAbAttr, applyAbAttrs } from "./ability";
|
import { Abilities, BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, applyAbAttrs } from "./ability";
|
||||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||||
import { TerrainType } from "./terrain";
|
import { TerrainType } from "./terrain";
|
||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
|
@ -280,12 +280,17 @@ export class SeedTag extends BattlerTag {
|
||||||
if (ret) {
|
if (ret) {
|
||||||
const source = pokemon.getOpponents().find(o => o.getBattlerIndex() === this.sourceIndex);
|
const source = pokemon.getOpponents().find(o => o.getBattlerIndex() === this.sourceIndex);
|
||||||
if (source) {
|
if (source) {
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
|
if (!cancelled.value) {
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
|
||||||
|
|
||||||
const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1));
|
const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1));
|
||||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(), damage, getPokemonMessage(pokemon, '\'s health is\nsapped by Leech Seed!'), false, true));
|
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(), damage, getPokemonMessage(pokemon, '\'s health is\nsapped by Leech Seed!'), false, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -319,6 +324,10 @@ export class NightmareTag extends BattlerTag {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is locked\nin a Nightmare!'));
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is locked\nin a Nightmare!'));
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE)); // TODO: Update animation type
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE)); // TODO: Update animation type
|
||||||
|
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
|
if (!cancelled.value)
|
||||||
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 4));
|
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,6 +515,10 @@ export abstract class DamagingTrapTag extends TrappedTag {
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby ${this.getMoveName()}!`));
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby ${this.getMoveName()}!`));
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, this.commonAnim));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, this.commonAnim));
|
||||||
|
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
|
if (!cancelled.value)
|
||||||
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 8))
|
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,11 +937,16 @@ export class SaltCuredTag extends BattlerTag {
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE));
|
||||||
|
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
|
if (!cancelled.value) {
|
||||||
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
|
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
|
||||||
pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
|
pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
|
||||||
|
|
||||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by ${this.getMoveName()}!`));
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by ${this.getMoveName()}!`));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import * as Utils from "../utils";
|
||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||||
import { Abilities, ProtectAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs } from "./ability";
|
import { Abilities, ProtectAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr } from "./ability";
|
||||||
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
|
@ -634,6 +634,10 @@ export class RecoilAttr extends MoveEffectAttr {
|
||||||
if (!recoilDamage)
|
if (!recoilDamage)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
|
||||||
|
if (cancelled.value)
|
||||||
|
return false;
|
||||||
|
|
||||||
user.damageAndUpdate(recoilDamage, HitResult.OTHER, false, true);
|
user.damageAndUpdate(recoilDamage, HitResult.OTHER, false, true);
|
||||||
user.scene.queueMessage(getPokemonMessage(user, ' is hit\nwith recoil!'));
|
user.scene.queueMessage(getPokemonMessage(user, ' is hit\nwith recoil!'));
|
||||||
|
|
||||||
|
@ -1825,6 +1829,11 @@ export class MissEffectAttr extends MoveAttr {
|
||||||
}
|
}
|
||||||
|
|
||||||
const halveHpMissEffectFunc = (user: Pokemon, move: Move) => {
|
const halveHpMissEffectFunc = (user: Pokemon, move: Move) => {
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
|
||||||
|
if (cancelled.value)
|
||||||
|
return false;
|
||||||
|
|
||||||
const damage = user.damage(Math.floor(user.getMaxHp() / 2));
|
const damage = user.damage(Math.floor(user.getMaxHp() / 2));
|
||||||
if (damage)
|
if (damage)
|
||||||
user.scene.damageNumberHandler.add(user, damage, HitResult.OTHER);
|
user.scene.damageNumberHandler.add(user, damage, HitResult.OTHER);
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
|
||||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||||
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||||
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
||||||
import { Abilities, CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "./data/ability";
|
import { Abilities, CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr } from "./data/ability";
|
||||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||||
import { getBiomeKey } from "./field/arena";
|
import { getBiomeKey } from "./field/arena";
|
||||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||||
|
@ -2551,6 +2551,7 @@ export class WeatherEffectPhase extends CommonAnimPhase {
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
|
||||||
applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather, cancelled);
|
applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather, cancelled);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
if (cancelled.value)
|
if (cancelled.value)
|
||||||
return;
|
return;
|
||||||
|
@ -2620,6 +2621,12 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
|
||||||
const pokemon = this.getPokemon();
|
const pokemon = this.getPokemon();
|
||||||
if (pokemon?.isActive(true) && pokemon.status && pokemon.status.isPostTurn()) {
|
if (pokemon?.isActive(true) && pokemon.status && pokemon.status.isPostTurn()) {
|
||||||
pokemon.status.incrementTurn();
|
pokemon.status.incrementTurn();
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
|
console.log(cancelled.value)
|
||||||
|
|
||||||
|
if (!cancelled.value) {
|
||||||
this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectActivationText(pokemon.status.effect)));
|
this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectActivationText(pokemon.status.effect)));
|
||||||
let damage: integer = 0;
|
let damage: integer = 0;
|
||||||
switch (pokemon.status.effect) {
|
switch (pokemon.status.effect) {
|
||||||
|
@ -2640,6 +2647,8 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
|
||||||
new CommonBattleAnim(CommonAnim.POISON + (pokemon.status.effect - 1), pokemon).play(this.scene, () => this.end());
|
new CommonBattleAnim(CommonAnim.POISON + (pokemon.status.effect - 1), pokemon).play(this.scene, () => this.end());
|
||||||
} else
|
} else
|
||||||
this.end();
|
this.end();
|
||||||
|
} else
|
||||||
|
this.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue