[Ability] Implement Treasures of Ruin Abilities (#1637)
* Implement Treasures of Ruin abilities * Reformat documentation --------- Co-authored-by: Temps Ray <temps.ray@gmail.com>
This commit is contained in:
parent
1a6b411987
commit
670ea01cb4
|
@ -12,7 +12,7 @@ import { Gender } from "./gender";
|
|||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
|
||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { Stat } from "./pokemon-stat";
|
||||
import { Stat, getStatName } from "./pokemon-stat";
|
||||
import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { TerrainType } from "./terrain";
|
||||
|
@ -1032,6 +1032,52 @@ export class FieldPreventExplosiveMovesAbAttr extends AbAttr {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a BattleStat if the checked Pokemon lacks this ability.
|
||||
* If this ability cannot stack, a BooleanHolder can be used to prevent this from stacking.
|
||||
* @see {@link applyFieldBattleStatMultiplierAbAttrs}
|
||||
* @see {@link applyFieldBattleStat}
|
||||
* @see {@link Utils.BooleanHolder}
|
||||
*/
|
||||
export class FieldMultiplyBattleStatAbAttr extends AbAttr {
|
||||
private stat: Stat;
|
||||
private multiplier: number;
|
||||
private canStack: boolean;
|
||||
|
||||
constructor(stat: Stat, multiplier: number, canStack: boolean = false) {
|
||||
super(false);
|
||||
|
||||
this.stat = stat;
|
||||
this.multiplier = multiplier;
|
||||
this.canStack = canStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* applyFieldBattleStat: Tries to multiply a Pokemon's BattleStat
|
||||
* @param pokemon {@linkcode Pokemon} the Pokemon using this ability
|
||||
* @param passive {@linkcode boolean} unused
|
||||
* @param stat {@linkcode Stat} the type of the checked stat
|
||||
* @param statValue {@linkcode Utils.NumberHolder} the value of the checked stat
|
||||
* @param checkedPokemon {@linkcode Pokemon} the Pokemon this ability is targeting
|
||||
* @param hasApplied {@linkcode Utils.BooleanHolder} whether or not another multiplier has been applied to this stat
|
||||
* @param args {any[]} unused
|
||||
* @returns true if this changed the checked stat, false otherwise.
|
||||
*/
|
||||
applyFieldBattleStat(pokemon: Pokemon, passive: boolean, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, args: any[]): boolean {
|
||||
if (!this.canStack && hasApplied.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.stat === stat && checkedPokemon.getAbilityAttrs(FieldMultiplyBattleStatAbAttr).every(attr => (attr as FieldMultiplyBattleStatAbAttr).stat !== stat)) {
|
||||
statValue.value *= this.multiplier;
|
||||
hasApplied.value = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class MoveTypeChangeAttr extends PreAttackAbAttr {
|
||||
private newType: Type;
|
||||
private powerMultiplier: number;
|
||||
|
@ -3573,6 +3619,21 @@ export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[])
|
|||
return applyAbAttrsInternal<BattleStatMultiplierAbAttr>(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a field Battle Stat multiplier attribute
|
||||
* @param attrType {@linkcode FieldMultiplyBattleStatAbAttr} should always be FieldMultiplyBattleStatAbAttr for the time being
|
||||
* @param pokemon {@linkcode Pokemon} the Pokemon applying this ability
|
||||
* @param stat {@linkcode Stat} the type of the checked stat
|
||||
* @param statValue {@linkcode Utils.NumberHolder} the value of the checked stat
|
||||
* @param checkedPokemon {@linkcode Pokemon} the Pokemon with the checked stat
|
||||
* @param hasApplied {@linkcode Utils.BooleanHolder} whether or not a FieldMultiplyBattleStatAbAttr has already affected this stat
|
||||
* @param args unused
|
||||
*/
|
||||
export function applyFieldBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]): FieldMultiplyBattleStatAbAttr },
|
||||
pokemon: Pokemon, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||
return applyAbAttrsInternal<FieldMultiplyBattleStatAbAttr>(attrType, pokemon, (attr, passive) => attr.applyFieldBattleStat(pokemon, passive, stat, statValue, checkedPokemon, hasApplied, args), args);
|
||||
}
|
||||
|
||||
export function applyPreAttackAbAttrs(attrType: { new(...args: any[]): PreAttackAbAttr },
|
||||
pokemon: Pokemon, defender: Pokemon, move: Move, ...args: any[]): Promise<void> {
|
||||
return applyAbAttrsInternal<PreAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args);
|
||||
|
@ -4596,17 +4657,21 @@ export function initAbilities() {
|
|||
.ignorable()
|
||||
.partial(),
|
||||
new Ability(Abilities.VESSEL_OF_RUIN, 9)
|
||||
.ignorable()
|
||||
.unimplemented(),
|
||||
.attr(FieldMultiplyBattleStatAbAttr, Stat.SPATK, 0.75)
|
||||
.attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Vessel of Ruin lowered the ${getStatName(Stat.SPATK)}\nof all surrounding Pokémon!`))
|
||||
.ignorable(),
|
||||
new Ability(Abilities.SWORD_OF_RUIN, 9)
|
||||
.ignorable()
|
||||
.unimplemented(),
|
||||
.attr(FieldMultiplyBattleStatAbAttr, Stat.DEF, 0.75)
|
||||
.attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Sword of Ruin lowered the ${getStatName(Stat.DEF)}\nof all surrounding Pokémon!`))
|
||||
.ignorable(),
|
||||
new Ability(Abilities.TABLETS_OF_RUIN, 9)
|
||||
.ignorable()
|
||||
.unimplemented(),
|
||||
.attr(FieldMultiplyBattleStatAbAttr, Stat.ATK, 0.75)
|
||||
.attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Tablets of Ruin lowered the ${getStatName(Stat.ATK)}\nof all surrounding Pokémon!`))
|
||||
.ignorable(),
|
||||
new Ability(Abilities.BEADS_OF_RUIN, 9)
|
||||
.ignorable()
|
||||
.unimplemented(),
|
||||
.attr(FieldMultiplyBattleStatAbAttr, Stat.SPDEF, 0.75)
|
||||
.attr(PostSummonMessageAbAttr, (user) => getPokemonMessage(user, `'s Beads of Ruin lowered the ${getStatName(Stat.SPDEF)}\nof all surrounding Pokémon!`))
|
||||
.ignorable(),
|
||||
new Ability(Abilities.ORICHALCUM_PULSE, 9)
|
||||
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SUNNY)
|
||||
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SUNNY)
|
||||
|
|
|
@ -27,7 +27,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, MoveTypeChangeAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr } from "../data/ability";
|
||||
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr } from "../data/ability";
|
||||
import { Abilities } from "#app/data/enums/abilities";
|
||||
import PokemonData from "../system/pokemon-data";
|
||||
import { BattlerIndex } from "../battle";
|
||||
|
@ -656,6 +656,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), battleStat as integer as TempBattleStat, statLevel);
|
||||
}
|
||||
const statValue = new Utils.NumberHolder(this.getStat(stat));
|
||||
const fieldApplied = new Utils.BooleanHolder(false);
|
||||
for (const pokemon of this.scene.getField(true)) {
|
||||
applyFieldBattleStatMultiplierAbAttrs(FieldMultiplyBattleStatAbAttr, pokemon, stat, statValue, this, fieldApplied);
|
||||
if (fieldApplied.value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, battleStat, statValue);
|
||||
let ret = statValue.value * (Math.max(2, 2 + statLevel.value) / Math.max(2, 2 - statLevel.value));
|
||||
switch (stat) {
|
||||
|
@ -951,6 +958,29 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
return allAbilities[starterPassiveAbilities[starterSpeciesId]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all instances of a given ability attribute among abilities this pokemon has.
|
||||
* Accounts for all the various effects which can affect whether an ability will be present or
|
||||
* in effect, and both passive and non-passive.
|
||||
* @param attrType {@linkcode AbAttr} The ability attribute to check for.
|
||||
* @param canApply {@linkcode Boolean} If false, it doesn't check whether the ability is currently active
|
||||
* @param ignoreOverride {@linkcode Boolean} If true, it ignores ability changing effects
|
||||
* @returns {AbAttr[]} A list of all the ability attributes on this ability.
|
||||
*/
|
||||
getAbilityAttrs(attrType: { new(...args: any[]): AbAttr }, canApply: boolean = true, ignoreOverride?: boolean): AbAttr[] {
|
||||
const abilityAttrs: AbAttr[] = [];
|
||||
|
||||
if (!canApply || this.canApplyAbility()) {
|
||||
abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs(attrType));
|
||||
}
|
||||
|
||||
if (!canApply || this.canApplyAbility(true)) {
|
||||
abilityAttrs.push(...this.getPassiveAbility().getAttrs(attrType));
|
||||
}
|
||||
|
||||
return abilityAttrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a pokemon has a passive either from:
|
||||
* - bought with starter candy
|
||||
|
|
Loading…
Reference in New Issue