Implement some abilities

pull/12/head
Flashfyre 2023-12-10 22:29:13 -05:00
parent 67f816cff4
commit 552bda9840
4 changed files with 74 additions and 35 deletions

View File

@ -2785,7 +2785,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier); this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier);
const healAmount = new Utils.NumberHolder(this.hpHealed * hpRestoreMultiplier.value); const healAmount = new Utils.NumberHolder(this.hpHealed * hpRestoreMultiplier.value);
pokemon.heal(healAmount.value); pokemon.heal(healAmount.value);
this.scene.validateAchvs(HealAchv, healAmount) this.scene.validateAchvs(HealAchv, healAmount);
pokemon.updateInfo().then(() => super.end()); pokemon.updateInfo().then(() => super.end());
} else if (this.showFullHpMessage) } else if (this.showFullHpMessage)
this.message = getPokemonMessage(pokemon, `'s\nHP is full!`); this.message = getPokemonMessage(pokemon, `'s\nHP is full!`);

View File

@ -291,7 +291,7 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
} }
applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (move.getMove().hasFlag(MoveFlags.MAKES_CONTACT) && Utils.randInt(100) < this.chance && !pokemon.status) { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && Utils.randInt(100) < this.chance && !pokemon.status) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[Utils.randInt(this.effects.length)]; const effect = this.effects.length === 1 ? this.effects[0] : this.effects[Utils.randInt(this.effects.length)];
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, attacker.getBattlerIndex(), effect)); pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, attacker.getBattlerIndex(), effect));
} }
@ -314,7 +314,7 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
} }
applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (move.getMove().hasFlag(MoveFlags.MAKES_CONTACT) && Utils.randInt(100) < this.chance) if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && Utils.randInt(100) < this.chance)
return attacker.addTag(this.tagType, this.turnCount, move.moveId, pokemon.id); return attacker.addTag(this.tagType, this.turnCount, move.moveId, pokemon.id);
return false; return false;
@ -637,6 +637,8 @@ export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
export class BlockCritAbAttr extends AbAttr { } export class BlockCritAbAttr extends AbAttr { }
export class IgnoreContactAbAttr extends AbAttr { }
export class PreWeatherEffectAbAttr extends AbAttr { export class PreWeatherEffectAbAttr extends AbAttr {
applyPreWeatherEffect(pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreWeatherEffect(pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean {
return false; return false;
@ -681,19 +683,6 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr {
} }
} }
export class PostTurnAbAttr extends AbAttr {
applyPostTurn(pokemon: Pokemon, args: any[]) {
return false;
}
}
export class PostTurnSpeedBoostAbAttr extends PostTurnAbAttr {
applyPostTurn(pokemon: Pokemon, args: any[]): boolean {
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.SPD ], 1));
return true;
}
}
function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition { function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
if (pokemon.scene.arena.weather?.isEffectSuppressed(pokemon.scene)) if (pokemon.scene.arena.weather?.isEffectSuppressed(pokemon.scene))
@ -703,19 +692,6 @@ function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
}; };
} }
export class PostTurnHealAbAttr extends PostTurnAbAttr {
applyPostTurn(pokemon: Pokemon, args: any[]): boolean {
if (pokemon.getHpRatio() < 1) {
const scene = pokemon.scene;
scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(),
Math.max(Math.floor(pokemon.getMaxHp() / 16), 1), getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nrestored its HP a little!`), true));
return true;
}
return false;
}
}
export class PostWeatherLapseAbAttr extends AbAttr { export class PostWeatherLapseAbAttr extends AbAttr {
protected weatherTypes: WeatherType[]; protected weatherTypes: WeatherType[];
@ -777,6 +753,32 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
} }
} }
export class PostTurnAbAttr extends AbAttr {
applyPostTurn(pokemon: Pokemon, args: any[]) {
return false;
}
}
export class PostTurnSpeedBoostAbAttr extends PostTurnAbAttr {
applyPostTurn(pokemon: Pokemon, args: any[]): boolean {
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.SPD ], 1));
return true;
}
}
export class PostTurnHealAbAttr extends PostTurnAbAttr {
applyPostTurn(pokemon: Pokemon, args: any[]): boolean {
if (pokemon.getHpRatio() < 1) {
const scene = pokemon.scene;
scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(),
Math.max(Math.floor(pokemon.getMaxHp() / 16), 1), getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nrestored its HP a little!`), true));
return true;
}
return false;
}
}
export class StatChangeMultiplierAbAttr extends AbAttr { export class StatChangeMultiplierAbAttr extends AbAttr {
private multiplier: integer; private multiplier: integer;
@ -810,6 +812,22 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr {
} }
} }
export class WeightMultiplierAbAttr extends AbAttr {
private multiplier: integer;
constructor(multiplier: integer) {
super(true);
this.multiplier = multiplier;
}
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value *= this.multiplier;
return true;
}
}
export function applyAbAttrs(attrType: { new(...args: any[]): AbAttr }, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): void { export function applyAbAttrs(attrType: { new(...args: any[]): AbAttr }, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): void {
if (!pokemon.canApplyAbility()) if (!pokemon.canApplyAbility())
return; return;
@ -1712,8 +1730,10 @@ export function initAbilities() {
new Ability(Abilities.HEALER, "Healer (N)", "Sometimes heals an ally's status condition.", 5), new Ability(Abilities.HEALER, "Healer (N)", "Sometimes heals an ally's status condition.", 5),
new Ability(Abilities.FRIEND_GUARD, "Friend Guard (N)", "Reduces damage done to allies.", 5), new Ability(Abilities.FRIEND_GUARD, "Friend Guard (N)", "Reduces damage done to allies.", 5),
new Ability(Abilities.WEAK_ARMOR, "Weak Armor (N)", "Physical attacks to the Pokémon lower its Defense\nstat but sharply raise its Speed stat.", 5), new Ability(Abilities.WEAK_ARMOR, "Weak Armor (N)", "Physical attacks to the Pokémon lower its Defense\nstat but sharply raise its Speed stat.", 5),
new Ability(Abilities.HEAVY_METAL, "Heavy Metal (N)", "Doubles the Pokémon's weight.", 5), new Ability(Abilities.HEAVY_METAL, "Heavy Metal", "Doubles the Pokémon's weight.", 5)
new Ability(Abilities.LIGHT_METAL, "Light Metal (N)", "Halves the Pokémon's weight.", 5), .attr(WeightMultiplierAbAttr, 2),
new Ability(Abilities.LIGHT_METAL, "Light Metal", "Halves the Pokémon's weight.", 5)
.attr(WeightMultiplierAbAttr, 0.5),
new Ability(Abilities.MULTISCALE, "Multiscale (N)", "Reduces the amount of damage the Pokémon takes\nwhile its HP is full.", 5), new Ability(Abilities.MULTISCALE, "Multiscale (N)", "Reduces the amount of damage the Pokémon takes\nwhile its HP is full.", 5),
new Ability(Abilities.TOXIC_BOOST, "Toxic Boost (N)", "Powers up physical attacks when the Pokémon\nis poisoned.", 5), new Ability(Abilities.TOXIC_BOOST, "Toxic Boost (N)", "Powers up physical attacks when the Pokémon\nis poisoned.", 5),
new Ability(Abilities.FLARE_BOOST, "Flare Boost (N)", "Powers up special attacks when the Pokémon\nis burned.", 5), new Ability(Abilities.FLARE_BOOST, "Flare Boost (N)", "Powers up special attacks when the Pokémon\nis burned.", 5),
@ -1794,7 +1814,8 @@ export function initAbilities() {
new Ability(Abilities.SLUSH_RUSH, "Slush Rush (N)", "Boosts the Pokémon's Speed stat in a hailstorm.", 7) new Ability(Abilities.SLUSH_RUSH, "Slush Rush (N)", "Boosts the Pokémon's Speed stat in a hailstorm.", 7)
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2) .attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
.condition(getWeatherCondition(WeatherType.HAIL)), .condition(getWeatherCondition(WeatherType.HAIL)),
new Ability(Abilities.LONG_REACH, "Long Reach (N)", "The Pokémon uses its moves without making contact\nwith the target.", 7), new Ability(Abilities.LONG_REACH, "Long Reach", "The Pokémon uses its moves without making contact\nwith the target.", 7)
.attr(IgnoreContactAbAttr),
new Ability(Abilities.LIQUID_VOICE, "Liquid Voice (N)", "All sound-based moves become Water-type moves.", 7), new Ability(Abilities.LIQUID_VOICE, "Liquid Voice (N)", "All sound-based moves become Water-type moves.", 7),
new Ability(Abilities.TRIAGE, "Triage (N)", "Gives priority to a healing move.", 7), new Ability(Abilities.TRIAGE, "Triage (N)", "Gives priority to a healing move.", 7),
new Ability(Abilities.GALVANIZE, "Galvanize (N)", "Normal-type moves become Electric-type moves.\nThe power of those moves is boosted a little.", 7), new Ability(Abilities.GALVANIZE, "Galvanize (N)", "Normal-type moves become Electric-type moves.\nThe power of those moves is boosted a little.", 7),

View File

@ -9,7 +9,7 @@ import { Type } from "./type";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { WeatherType } from "./weather"; import { WeatherType } from "./weather";
import { ArenaTagType, ArenaTrapTag } from "./arena-tag"; import { ArenaTagType, ArenaTrapTag } from "./arena-tag";
import { Abilities, BlockRecoilDamageAttr, applyAbAttrs } from "./ability"; import { Abilities, BlockRecoilDamageAttr, IgnoreContactAbAttr, applyAbAttrs } 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";
@ -172,6 +172,17 @@ export default class Move {
return this; return this;
} }
checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean {
switch (flag) {
case MoveFlags.MAKES_CONTACT:
if (user.getAbility().hasAttr(IgnoreContactAbAttr))
return false;
break;
}
return !!(this.flags & flag);
}
applyConditions(user: Pokemon, target: Pokemon, move: Move): boolean { applyConditions(user: Pokemon, target: Pokemon, move: Move): boolean {
for (let condition of this.conditions) { for (let condition of this.conditions) {
if (!condition(user, target, move)) if (!condition(user, target, move))
@ -1933,7 +1944,7 @@ export class WeightPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const power = args[0] as Utils.NumberHolder; const power = args[0] as Utils.NumberHolder;
const targetWeight = target.species.weight; const targetWeight = target.getWeight();
const weightThresholds = [ 10, 25, 50, 100, 200 ]; const weightThresholds = [ 10, 25, 50, 100, 200 ];
let w = 0; let w = 0;

View File

@ -22,7 +22,7 @@ import { WeatherType } from './data/weather';
import { TempBattleStat } from './data/temp-battle-stat'; import { TempBattleStat } from './data/temp-battle-stat';
import { ArenaTagType, WeakenMoveTypeTag } from './data/arena-tag'; import { ArenaTagType, WeakenMoveTypeTag } from './data/arena-tag';
import { Biome } from './data/biome'; import { Biome } from './data/biome';
import { Abilities, Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, IgnoreOpponentStatChangesAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from './data/ability'; import { Abilities, Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, IgnoreOpponentStatChangesAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from './data/ability';
import PokemonData from './system/pokemon-data'; import PokemonData from './system/pokemon-data';
import { BattlerIndex } from './battle'; import { BattlerIndex } from './battle';
import { Mode } from './ui/ui'; import { Mode } from './ui/ui';
@ -582,6 +582,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.hp && !this.getAbility().conditions.find(condition => !condition(this)); return this.hp && !this.getAbility().conditions.find(condition => !condition(this));
} }
getWeight(): number {
const weight = new Utils.NumberHolder(this.species.weight);
// This will trigger the ability overlay so only call this function when necessary
applyAbAttrs(WeightMultiplierAbAttr, this, null, weight);
return weight.value;
}
getAttackMoveEffectiveness(moveType: Type): TypeDamageMultiplier { getAttackMoveEffectiveness(moveType: Type): TypeDamageMultiplier {
const types = this.getTypes(); const types = this.getTypes();
return getTypeDamageMultiplier(moveType, types[0]) * (types.length > 1 ? getTypeDamageMultiplier(moveType, types[1]) : 1) as TypeDamageMultiplier; return getTypeDamageMultiplier(moveType, types[0]) * (types.length > 1 ? getTypeDamageMultiplier(moveType, types[1]) : 1) as TypeDamageMultiplier;