From 03989d07b2804cebb2cc6aee0c6e1e9c78a078a6 Mon Sep 17 00:00:00 2001 From: Xiaphear <xiaphearix@gmail.com> Date: Mon, 11 Mar 2024 18:18:49 +0100 Subject: [PATCH] Added Wring Out. Attempted Healing Wish ( WIP ) --- src/data/move.ts | 101 +++++++++++++++++++++++++++++++++++++++++++++-- src/phases.ts | 18 +++++++-- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 1fa806179dd..e575bf9b5da 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -607,6 +607,35 @@ export class HealAttr extends MoveEffectAttr { } } +export class SacrificialFullRestoreAttr extends SacrificialAttr { + constructor() { + super(); + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) + return false; + + // We don't know which party member will be chosen, so pick the highest max HP in the party + const maxPartyMemberHp = user.scene.getParty().map(p => p.getMaxHp()).reduce((maxHp: integer, hp: integer) => Math.max(hp, maxHp), 0); + + console.log(maxPartyMemberHp); + + user.scene.pushPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(), + maxPartyMemberHp, getPokemonMessage(user, '\'s Healing Wish\nwas granted!'), true, false, false, true)); + + return true; + } + + getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { + return -20; + } + + getCondition(): MoveConditionFunc { + return (user, target, move) => user.scene.getParty().filter(p => p.isActive()).length > user.scene.currentBattle.getBattlerCount(); + } +} + export abstract class WeatherHealAttr extends HealAttr { constructor() { super(0.5); @@ -827,6 +856,52 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { } } +export class RemoveHeldItemAttr extends MoveEffectAttr { + private chance: number; + + constructor(chance: number) { + super(false, MoveEffectTrigger.HIT); + this.chance = chance; + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> { + return new Promise<boolean>(resolve => { + const rand = Phaser.Math.RND.realInRange(0, 1); + if (rand >= this.chance) + return resolve(false); + const heldItems = this.getTargetHeldItems(target).filter(i => i.getTransferrable(false)); + if (heldItems.length) { + const highestItemTier = heldItems.map(m => m.type.getOrInferTier()).reduce((highestTier, tier) => Math.max(tier, highestTier), 0); + const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier() === highestItemTier); + const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; + user.scene.tryTransferHeldItemModifier(stolenItem, user, false, false).then(success => { + if (success) + user.scene.queueMessage(getPokemonMessage(user, ` knocked off\n${target.name}'s ${stolenItem.type.name}!`)); + resolve(success); + }); + return; + } + + resolve(false); + }); + } + + getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] { + return target.scene.findModifiers(m => m instanceof PokemonHeldItemModifier + && (m as PokemonHeldItemModifier).pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[]; + } + + getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { + const heldItems = this.getTargetHeldItems(target); + return heldItems.length ? 5 : 0; + } + + getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { + const heldItems = this.getTargetHeldItems(target); + return heldItems.length ? -5 : 0; + } +} + export class HealStatusEffectAttr extends MoveEffectAttr { private effects: StatusEffect[]; @@ -2084,6 +2159,25 @@ export class CopyMoveAttr extends OverrideMoveEffectAttr { } } +export class ReducePPMoveAttr extends OverrideMoveEffectAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + //const lastMove = target.getLastXMoves().find(() => true); + const lastMove = user.scene.currentBattle.lastMove; + + const moveTargets = getMoveTargets(user, lastMove); + if (!moveTargets.targets.length) + return false; + + const targets = moveTargets.multiple || moveTargets.targets.length === 1 + ? moveTargets.targets + : moveTargets.targets.indexOf(target.getBattlerIndex()) > -1 + ? [ target.getBattlerIndex() ] + : [ moveTargets.targets[user.randSeedInt(moveTargets.targets.length)] ]; + + return true; + } +} + // TODO: Review this const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => { const targetMoves = target.getMoveHistory().filter(m => !m.virtual); @@ -3230,8 +3324,8 @@ export function initMoves() { new AttackMove(Moves.GYRO_BALL, "Gyro Ball", Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 5, -1, "The user tackles the target with a high-speed spin. The slower the user compared to the target, the greater the move's power.", -1, 0, 4) .attr(BattleStatRatioPowerAttr, Stat.SPD, true) .ballBombMove(), - new SelfStatusMove(Moves.HEALING_WISH, "Healing Wish", Type.PSYCHIC, -1, 10, -1, "The user faints. In return, the Pokémon taking its place will have its HP restored and status conditions cured.", -1, 0, 4) - .attr(SacrificialAttr), + new SelfStatusMove(Moves.HEALING_WISH, "Healing Wish (N)", Type.PSYCHIC, -1, 10, -1, "The user faints. In return, the Pokémon taking its place will have its HP restored and status conditions cured.", -1, 0, 4) + .attr(SacrificialFullRestoreAttr), new AttackMove(Moves.BRINE, "Brine", Type.WATER, MoveCategory.SPECIAL, 65, 100, 10, -1, "If the target's HP is half or less, this attack will hit with double the power.", -1, 0, 4) .attr(MovePowerMultiplierAttr, (user, target, move) => target.getHpRatio() < 0.5 ? 2 : 1), new AttackMove(Moves.NATURAL_GIFT, "Natural Gift (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, "The user draws power to attack by using its held Berry. The Berry determines the move's type and power.", -1, 0, 4) @@ -3264,7 +3358,8 @@ export function initMoves() { .makesContact(), new StatusMove(Moves.HEAL_BLOCK, "Heal Block (N)", Type.PSYCHIC, 100, 15, -1, "For five turns, the user prevents the opposing team from using any moves, Abilities, or held items that recover HP.", -1, 0, 4) .target(MoveTarget.ALL_NEAR_ENEMIES), - new AttackMove(Moves.WRING_OUT, "Wring Out (N)", Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 5, -1, "The user powerfully wrings the target. The more HP the target has, the greater the move's power.", -1, 0, 4) + new AttackMove(Moves.WRING_OUT, "Wring Out", Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 5, -1, "The user powerfully wrings the target. The more HP the target has, the greater the move's power.", -1, 0, 4) + .attr(OpponentHighHpPowerAttr) .makesContact(), new SelfStatusMove(Moves.POWER_TRICK, "Power Trick (N)", Type.PSYCHIC, -1, 10, -1, "The user employs its psychic power to switch its Attack stat with its Defense stat.", -1, 0, 4), new StatusMove(Moves.GASTRO_ACID, "Gastro Acid (N)", Type.POISON, 100, 10, -1, "The user hurls up its stomach acids on the target. The fluid eliminates the effect of the target's Ability.", -1, 0, 4), diff --git a/src/phases.ts b/src/phases.ts index 54141e0e44e..5fb87a91cc6 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -3318,15 +3318,17 @@ export class PokemonHealPhase extends CommonAnimPhase { private showFullHpMessage: boolean; private skipAnim: boolean; private revive: boolean; + private healStatus: boolean; - constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string, showFullHpMessage: boolean, skipAnim?: boolean, revive?: boolean) { + constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string, showFullHpMessage: boolean, skipAnim: boolean = false, revive: boolean = false, healStatus: boolean = false) { super(scene, battlerIndex, undefined, CommonAnim.HEALTH_UP); this.hpHealed = hpHealed; this.message = message; this.showFullHpMessage = showFullHpMessage; - this.skipAnim = !!skipAnim; - this.revive = !!revive; + this.skipAnim = skipAnim; + this.revive = revive; + this.healStatus = healStatus; } start() { @@ -3346,6 +3348,9 @@ export class PokemonHealPhase extends CommonAnimPhase { const fullHp = pokemon.getHpRatio() >= 1; + const hasMessage = !!this.message; + let lastStatusEffect = StatusEffect.NONE; + if (!fullHp) { const hpRestoreMultiplier = new Utils.IntegerHolder(1); if (!this.revive) @@ -3359,6 +3364,10 @@ export class PokemonHealPhase extends CommonAnimPhase { if (healAmount.value > this.scene.gameData.gameStats.highestHeal) this.scene.gameData.gameStats.highestHeal = healAmount.value; } + if (this.healStatus && !this.revive && pokemon.status) { + lastStatusEffect = pokemon.status.effect; + pokemon.resetStatus(); + } pokemon.updateInfo().then(() => super.end()); } else if (this.showFullHpMessage) this.message = getPokemonMessage(pokemon, `'s\nHP is full!`); @@ -3366,6 +3375,9 @@ export class PokemonHealPhase extends CommonAnimPhase { if (this.message) this.scene.queueMessage(this.message); + if (this.healStatus && lastStatusEffect && !hasMessage) + this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectHealText(lastStatusEffect))); + if (fullHp) super.end(); }