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 {
|
||||
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
cancelled.value = false;
|
||||
cancelled.value = 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.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.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.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)
|
||||
|
|
|
@ -9,6 +9,7 @@ import { StatusEffect } from "./status-effect";
|
|||
import { BattlerIndex } from "../battle";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { BlockNonDirectDamageAbAttr, applyAbAttrs } from "./ability";
|
||||
|
||||
export enum ArenaTagSide {
|
||||
BOTH,
|
||||
|
@ -172,12 +173,17 @@ class SpikesTag extends ArenaTrapTag {
|
|||
|
||||
activateTrap(pokemon: Pokemon): boolean {
|
||||
if (pokemon.isGrounded()) {
|
||||
const damageHpRatio = 1 / (10 - 2 * this.layers);
|
||||
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||
|
||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is hurt\nby the spikes!'));
|
||||
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
||||
return true;
|
||||
if (!cancelled.value) {
|
||||
const damageHpRatio = 1 / (10 - 2 * this.layers);
|
||||
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
|
||||
|
||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is hurt\nby the spikes!'));
|
||||
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -293,6 +299,12 @@ class StealthRockTag extends ArenaTrapTag {
|
|||
}
|
||||
|
||||
activateTrap(pokemon: Pokemon): boolean {
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||
|
||||
if (cancelled.value)
|
||||
return false;
|
||||
|
||||
const damageHpRatio = this.getDamageHpRatio(pokemon);
|
||||
|
||||
if (damageHpRatio) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import * as Utils from "../utils";
|
|||
import { Moves } from "./enums/moves";
|
||||
import { ChargeAttr, MoveFlags, allMoves } from "./move";
|
||||
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 { TerrainType } from "./terrain";
|
||||
import { WeatherType } from "./weather";
|
||||
|
@ -280,10 +280,15 @@ export class SeedTag extends BattlerTag {
|
|||
if (ret) {
|
||||
const source = pokemon.getOpponents().find(o => o.getBattlerIndex() === this.sourceIndex);
|
||||
if (source) {
|
||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||
|
||||
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));
|
||||
if (!cancelled.value) {
|
||||
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));
|
||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(), damage, getPokemonMessage(pokemon, '\'s health is\nsapped by Leech Seed!'), false, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,7 +324,11 @@ export class NightmareTag extends BattlerTag {
|
|||
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.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 4));
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||
|
||||
if (!cancelled.value)
|
||||
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 4));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -506,7 +515,11 @@ export abstract class DamagingTrapTag extends TrappedTag {
|
|||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby ${this.getMoveName()}!`));
|
||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, this.commonAnim));
|
||||
|
||||
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 8))
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||
|
||||
if (!cancelled.value)
|
||||
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 8))
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -924,10 +937,15 @@ export class SaltCuredTag extends BattlerTag {
|
|||
if (ret) {
|
||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE));
|
||||
|
||||
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
|
||||
pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||
|
||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by ${this.getMoveName()}!`));
|
||||
if (!cancelled.value) {
|
||||
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.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by ${this.getMoveName()}!`));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -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 { 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 { BattlerIndex } from "../battle";
|
||||
import { Stat } from "./pokemon-stat";
|
||||
|
@ -634,6 +634,10 @@ export class RecoilAttr extends MoveEffectAttr {
|
|||
if (!recoilDamage)
|
||||
return false;
|
||||
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
|
||||
if (cancelled.value)
|
||||
return false;
|
||||
|
||||
user.damageAndUpdate(recoilDamage, HitResult.OTHER, false, true);
|
||||
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 cancelled = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
|
||||
if (cancelled.value)
|
||||
return false;
|
||||
|
||||
const damage = user.damage(Math.floor(user.getMaxHp() / 2));
|
||||
if (damage)
|
||||
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 { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||
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 { getBiomeKey } from "./field/arena";
|
||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||
|
@ -2551,6 +2551,7 @@ export class WeatherEffectPhase extends CommonAnimPhase {
|
|||
const cancelled = new Utils.BooleanHolder(false);
|
||||
|
||||
applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather, cancelled);
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||
|
||||
if (cancelled.value)
|
||||
return;
|
||||
|
@ -2620,24 +2621,32 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
|
|||
const pokemon = this.getPokemon();
|
||||
if (pokemon?.isActive(true) && pokemon.status && pokemon.status.isPostTurn()) {
|
||||
pokemon.status.incrementTurn();
|
||||
this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectActivationText(pokemon.status.effect)));
|
||||
let damage: integer = 0;
|
||||
switch (pokemon.status.effect) {
|
||||
case StatusEffect.POISON:
|
||||
damage = Math.max(pokemon.getMaxHp() >> 3, 1);
|
||||
break;
|
||||
case StatusEffect.TOXIC:
|
||||
damage = Math.max(Math.floor((pokemon.getMaxHp() / 16) * pokemon.status.turnCount), 1);
|
||||
break;
|
||||
case StatusEffect.BURN:
|
||||
damage = Math.max(pokemon.getMaxHp() >> 4, 1);
|
||||
break;
|
||||
}
|
||||
if (damage) {
|
||||
this.scene.damageNumberHandler.add(this.getPokemon(), pokemon.damage(damage));
|
||||
pokemon.updateInfo();
|
||||
}
|
||||
new CommonBattleAnim(CommonAnim.POISON + (pokemon.status.effect - 1), pokemon).play(this.scene, () => this.end());
|
||||
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)));
|
||||
let damage: integer = 0;
|
||||
switch (pokemon.status.effect) {
|
||||
case StatusEffect.POISON:
|
||||
damage = Math.max(pokemon.getMaxHp() >> 3, 1);
|
||||
break;
|
||||
case StatusEffect.TOXIC:
|
||||
damage = Math.max(Math.floor((pokemon.getMaxHp() / 16) * pokemon.status.turnCount), 1);
|
||||
break;
|
||||
case StatusEffect.BURN:
|
||||
damage = Math.max(pokemon.getMaxHp() >> 4, 1);
|
||||
break;
|
||||
}
|
||||
if (damage) {
|
||||
this.scene.damageNumberHandler.add(this.getPokemon(), pokemon.damage(damage));
|
||||
pokemon.updateInfo();
|
||||
}
|
||||
new CommonBattleAnim(CommonAnim.POISON + (pokemon.status.effect - 1), pokemon).play(this.scene, () => this.end());
|
||||
} else
|
||||
this.end();
|
||||
} else
|
||||
this.end();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue