Implement some abilities

pull/14/head
Flashfyre 2024-01-16 00:28:03 -05:00
parent 63cb2ae22f
commit 84fe12d83a
5 changed files with 126 additions and 14 deletions

View File

@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, ge
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, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability";
import { Abilities, CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability";
import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
@ -978,6 +978,8 @@ export class SwitchSummonPhase extends SummonPhase {
if (!this.batonPass)
(this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id));
applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, pokemon);
this.scene.ui.showText(this.player ? `Come back, ${pokemon.name}!` : `${this.scene.currentBattle.trainer.getName()}\nwithdrew ${pokemon.name}!`);
this.scene.playSound('pb_rel');
pokemon.hideInfo();

View File

@ -679,6 +679,28 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
}
}
export class PreSwitchOutAbAttr extends AbAttr {
constructor() {
super(true);
}
applyPreSwitchOut(pokemon: Pokemon, args: any[]): boolean | Promise<boolean> {
return false;
}
}
export class PreSwitchOutResetStatusAbAttr extends PreSwitchOutAbAttr {
applyPreSwitchOut(pokemon: Pokemon, args: any[]): boolean | Promise<boolean> {
if (pokemon.status) {
pokemon.resetStatus();
pokemon.updateInfo();
return true;
}
return false;
}
}
export class PreStatChangeAbAttr extends AbAttr {
applyPreStatChange(pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
return false;
@ -991,6 +1013,67 @@ export class MaxMultiHitAbAttr extends AbAttr {
}
}
export class ReduceStatusEffectDurationAbAttr extends AbAttr {
private statusEffect: StatusEffect;
constructor(statusEffect: StatusEffect) {
super(true);
this.statusEffect = statusEffect;
}
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (args[0] === this.statusEffect) {
(args[1] as Utils.IntegerHolder).value = Math.floor((args[1] as Utils.IntegerHolder).value / 2);
return true;
}
return false;
}
}
export class FlinchEffectAbAttr extends AbAttr {
constructor() {
super(true);
}
}
export class FlinchStatChangeAbAttr extends FlinchEffectAbAttr {
private stats: BattleStat[];
private levels: integer;
constructor(stats: BattleStat | BattleStat[], levels: integer) {
super();
this.stats = Array.isArray(stats)
? stats
: [ stats ];
this.levels = levels;
}
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels));
return true;
}
}
export class ReduceBerryUseThresholdAbAttr extends AbAttr {
constructor() {
super(true);
}
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const hpRatio = pokemon.getHpRatio();
if (args[0].value < hpRatio) {
args[0].value *= 2;
return args[0].value >= hpRatio;
}
return false;
}
}
export class WeightMultiplierAbAttr extends AbAttr {
private multiplier: integer;
@ -1108,6 +1191,11 @@ export function applyPostSummonAbAttrs(attrType: { new(...args: any[]): PostSumm
return applyAbAttrsInternal<PostSummonAbAttr>(attrType, pokemon, attr => attr.applyPostSummon(pokemon, args));
}
export function applyPreSwitchOutAbAttrs(attrType: { new(...args: any[]): PreSwitchOutAbAttr },
pokemon: Pokemon, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<PreSwitchOutAbAttr>(attrType, pokemon, attr => attr.applyPreSwitchOut(pokemon, args), false, true);
}
export function applyPreStatChangeAbAttrs(attrType: { new(...args: any[]): PreStatChangeAbAttr },
pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<PreStatChangeAbAttr>(attrType, pokemon, attr => attr.applyPreStatChange(pokemon, stat, cancelled, args));
@ -1523,7 +1611,8 @@ export function initAbilities() {
.attr(SyncEncounterNatureAbAttr),
new Ability(Abilities.CLEAR_BODY, "Clear Body", "Prevents other Pokémon's moves or Abilities from lowering the Pokémon's stats.", 3)
.attr(ProtectStatAbAttr),
new Ability(Abilities.NATURAL_CURE, "Natural Cure (N)", "All status conditions heal when the Pokémon switches out.", 3),
new Ability(Abilities.NATURAL_CURE, "Natural Cure", "All status conditions heal when the Pokémon switches out.", 3)
.attr(PreSwitchOutResetStatusAbAttr),
new Ability(Abilities.LIGHTNING_ROD, "Lightning Rod", "The Pokémon draws in all Electric-type moves. Instead of being hit by Electric-type moves, it boosts its Sp. Atk.", 3)
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPATK, 1),
new Ability(Abilities.SERENE_GRACE, "Serene Grace (N)", "Boosts the likelihood of additional effects occurring when attacking.", 3),
@ -1560,7 +1649,8 @@ export function initAbilities() {
new Ability(Abilities.THICK_FAT, "Thick Fat", "The Pokémon is protected by a layer of thick fat, which halves the damage taken from Fire- and Ice-type moves.", 3)
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.ICE, 0.5),
new Ability(Abilities.EARLY_BIRD, "Early Bird (N)", "The Pokémon awakens from sleep twice as fast as other Pokémon.", 3),
new Ability(Abilities.EARLY_BIRD, "Early Bird", "The Pokémon awakens from sleep twice as fast as other Pokémon.", 3)
.attr(ReduceStatusEffectDurationAbAttr, StatusEffect.SLEEP),
new Ability(Abilities.FLAME_BODY, "Flame Body", "Contact with the Pokémon may burn the attacker.", 3)
.attr(PostDefendContactApplyStatusEffectAbAttr, 30, StatusEffect.BURN),
new Ability(Abilities.RUN_AWAY, "Run Away", "Enables a sure getaway from wild Pokémon.", 3)
@ -1616,11 +1706,13 @@ export function initAbilities() {
new Ability(Abilities.MOTOR_DRIVE, "Motor Drive", "Boosts its Speed stat if hit by an Electric-type move instead of taking damage.", 4)
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPD, 1),
new Ability(Abilities.RIVALRY, "Rivalry (N)", "Becomes competitive and deals more damage to Pokémon of the same gender, but deals less to Pokémon of the opposite gender.", 4),
new Ability(Abilities.STEADFAST, "Steadfast (N)", "The Pokémon's determination boosts the Speed stat each time the Pokémon flinches.", 4),
new Ability(Abilities.STEADFAST, "Steadfast", "The Pokémon's determination boosts the Speed stat each time the Pokémon flinches.", 4)
.attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1),
new Ability(Abilities.SNOW_CLOAK, "Snow Cloak", "Boosts evasiveness in a hailstorm.", 4)
.attr(BattleStatMultiplierAbAttr, BattleStat.EVA, 1.2)
.attr(BlockWeatherDamageAttr, WeatherType.HAIL),
new Ability(Abilities.GLUTTONY, "Gluttony (N)", "Makes the Pokémon eat a held Berry when its HP drops to half or less, which is sooner than usual.", 4),
new Ability(Abilities.GLUTTONY, "Gluttony", "Makes the Pokémon eat a held Berry when its HP drops to half or less, which is sooner than usual.", 4)
.attr(ReduceBerryUseThresholdAbAttr),
new Ability(Abilities.ANGER_POINT, "Anger Point", "The Pokémon is angered when it takes a critical hit, and that maxes its Attack stat.", 4)
.attr(PostDefendCritStatChangeAbAttr, BattleStat.ATK, 6),
new Ability(Abilities.UNBURDEN, "Unburden (N)", "Boosts the Speed stat if the Pokémon's held item is used or lost.", 4),

View File

@ -8,7 +8,7 @@ import * as Utils from "../utils";
import { Moves } from "./enums/moves";
import { ChargeAttr, allMoves } from "./move";
import { Type } from "./type";
import { Abilities } from "./ability";
import { Abilities, FlinchEffectAbAttr, applyAbAttrs } from "./ability";
import { BattlerTagType } from "./enums/battler-tag-type";
export enum BattlerTagLapseType {
@ -123,6 +123,12 @@ export class FlinchedTag extends BattlerTag {
super(BattlerTagType.FLINCHED, BattlerTagLapseType.MOVE, 0, sourceMove);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
applyAbAttrs(FlinchEffectAbAttr, pokemon, null);
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
super.lapse(pokemon, lapseType);

View File

@ -6,7 +6,7 @@ import { BattleStat } from "./battle-stat";
import { BattlerTagType } from "./enums/battler-tag-type";
import { getStatusEffectHealText } from "./status-effect";
import * as Utils from "../utils";
import { DoubleBerryEffectAbAttr, applyAbAttrs } from "./ability";
import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability";
export enum BerryType {
SITRUS,
@ -63,13 +63,23 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
case BerryType.APICOT:
case BerryType.SALAC:
return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25);
const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
return pokemon.getHpRatio() < 0.25 && pokemon.summonData.battleStats[battleStat] < 6;
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
return pokemon.getHpRatio() < threshold.value && pokemon.summonData.battleStats[battleStat] < 6;
};
case BerryType.LANSAT:
return (pokemon: Pokemon) => pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
}
case BerryType.STARF:
return (pokemon: Pokemon) => pokemon.getHpRatio() < 0.25;
return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
return pokemon.getHpRatio() < 0.25;
}
}
}

View File

@ -25,7 +25,7 @@ import { TempBattleStat } from './data/temp-battle-stat';
import { WeakenMoveTypeTag } from './data/arena-tag';
import { ArenaTagType } from "./data/enums/arena-tag-type";
import { Biome } from "./data/enums/biome";
import { Abilities, Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from './data/ability';
import { Abilities, Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from './data/ability';
import PokemonData from './system/pokemon-data';
import { BattlerIndex } from './battle';
import { BattleSpec } from "./enums/battle-spec";
@ -1466,14 +1466,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (cancelled.value)
return false;
let cureTurn: integer;
let cureTurn: Utils.IntegerHolder;
if (effect === StatusEffect.SLEEP) {
cureTurn = this.randSeedIntRange(2, 4);
cureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4));
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, effect, cureTurn);
this.setFrameRate(4);
}
this.status = new Status(effect, 0, cureTurn);
this.status = new Status(effect, 0, cureTurn?.value);
if (effect !== StatusEffect.FAINT)
this.scene.triggerPokemonFormChange(this, SpeciesFormChangeStatusEffectTrigger, true);