pull/502/merge
PaulBeslin 2024-05-10 16:15:28 +02:00 committed by GitHub
commit 535969ecba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 30 additions and 28 deletions

View File

@ -549,8 +549,9 @@ export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr {
export class ReverseDrainAbAttr extends PostDefendAbAttr { export class ReverseDrainAbAttr extends PostDefendAbAttr {
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (!!move.getMove().getAttrs(HitHealAttr).length || !!move.getMove().getAttrs(StrengthSapHealAttr).length ) { const isDrain = args.some(arg => typeof arg === 'object' && 'seedDrain' in arg && !!arg['seedDrain']);
pokemon.scene.queueMessage(getPokemonMessage(attacker, ` sucked up the liquid ooze!`)); if (!!move.getMove().getAttrs(HitHealAttr).length || !!move.getMove().getAttrs(StrengthSapHealAttr).length || isDrain) {
pokemon.scene.queueMessage(getPokemonMessage(attacker, ' sucked up the liquid ooze!'));
return true; return true;
} }
return false; return false;
@ -2942,7 +2943,8 @@ export function initAbilities() {
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.DEF, 1.5) .conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.DEF, 1.5)
.ignorable(), .ignorable(),
new Ability(Abilities.LIQUID_OOZE, 3) new Ability(Abilities.LIQUID_OOZE, 3)
.attr(ReverseDrainAbAttr), .attr(ReverseDrainAbAttr)
.bypassFaint(),
new Ability(Abilities.OVERGROW, 3) new Ability(Abilities.OVERGROW, 3)
.attr(LowHpMoveTypePowerBoostAbAttr, Type.GRASS), .attr(LowHpMoveTypePowerBoostAbAttr, Type.GRASS),
new Ability(Abilities.BLAZE, 3) new Ability(Abilities.BLAZE, 3)

View File

@ -8,7 +8,7 @@ import * as Utils from "../utils";
import { Moves } from "./enums/moves"; import { Moves } from "./enums/moves";
import { ChargeAttr, MoveFlags, allMoves } from "./move"; import { ChargeAttr, MoveFlags, allMoves } from "./move";
import { Type } from "./type"; import { Type } from "./type";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability"; import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs, applyPostDefendAbAttrs } from "./ability";
import { Abilities } from "./enums/abilities"; import { Abilities } from "./enums/abilities";
import { BattlerTagType } from "./enums/battler-tag-type"; import { BattlerTagType } from "./enums/battler-tag-type";
import { TerrainType } from "./terrain"; import { TerrainType } from "./terrain";
@ -305,6 +305,7 @@ export class InfatuatedTag extends BattlerTag {
export class SeedTag extends BattlerTag { export class SeedTag extends BattlerTag {
private sourceIndex: integer; private sourceIndex: integer;
private sourceMove: Moves;
constructor(sourceId: integer) { constructor(sourceId: integer) {
super(BattlerTagType.SEEDED, BattlerTagLapseType.TURN_END, 1, Moves.LEECH_SEED, sourceId); super(BattlerTagType.SEEDED, BattlerTagLapseType.TURN_END, 1, Moves.LEECH_SEED, sourceId);
@ -327,7 +328,9 @@ export class SeedTag extends BattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' was seeded!')); pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' was seeded!'));
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex(); const source = pokemon.scene.getPokemonById(this.sourceId);
this.sourceIndex = source.getBattlerIndex();
this.sourceMove = source.getLastXMoves(1).shift().move;
} }
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
@ -342,12 +345,11 @@ export class SeedTag extends BattlerTag {
if (!cancelled.value) { if (!cancelled.value) {
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED)); pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
const move = source.getMoveset().find(m => m.moveId === this.sourceMove);
const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1)); const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1));
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr); pokemon.scene.queueMessage(getPokemonMessage(pokemon, `'s health is\nsapped by ${move.getName()}!`));
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(), pokemon.drain(source, damage, '');
!reverseDrain ? damage : damage * -1, applyPostDefendAbAttrs(ReverseDrainAbAttr, pokemon, source, move, HitResult.STATUS, { seedDrain: true });
!reverseDrain ? getPokemonMessage(pokemon, '\'s health is\nsapped by Leech Seed!') : getPokemonMessage(source, '\'s Leech Seed\nsucked up the liquid ooze!'),
false, true));
} }
} }
} }

View File

@ -973,12 +973,7 @@ export class HitHealAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const healAmount = Math.max(Math.floor(user.turnData.damageDealt * this.healRatio), 1); const healAmount = Math.max(Math.floor(user.turnData.damageDealt * this.healRatio), 1);
const reverseDrain = user.hasAbilityWithAttr(ReverseDrainAbAttr); target.drain(user, healAmount, getPokemonMessage(target, ' had its\nenergy drained!'));
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
!reverseDrain ? healAmount : healAmount * -1,
!reverseDrain ? getPokemonMessage(target, ` had its\nenergy drained!`) : undefined,
false, true));
if (reverseDrain) user.turnData.damageTaken += healAmount;
return true; return true;
} }
@ -994,11 +989,7 @@ export class StrengthSapHealAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const healAmount = target.stats[Stat.ATK] * (Math.max(2, 2 + target.summonData.battleStats[BattleStat.ATK]) / Math.max(2, 2 - target.summonData.battleStats[BattleStat.ATK])); const healAmount = target.stats[Stat.ATK] * (Math.max(2, 2 + target.summonData.battleStats[BattleStat.ATK]) / Math.max(2, 2 - target.summonData.battleStats[BattleStat.ATK]));
const reverseDrain = user.hasAbilityWithAttr(ReverseDrainAbAttr); target.drain(user, healAmount, getPokemonMessage(target, ' regained\nhealth!'));
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
!reverseDrain ? healAmount : healAmount * -1,
!reverseDrain ? getPokemonMessage(user, ` regained\nhealth!`) : undefined,
false, true));
return true; return true;
} }
} }

View File

@ -17,7 +17,7 @@ import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims';
import { Status, StatusEffect, getRandomStatus } from '../data/status-effect'; import { Status, StatusEffect, getRandomStatus } from '../data/status-effect';
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions'; import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions';
import { reverseCompatibleTms, tmSpecies } from '../data/tms'; import { reverseCompatibleTms, tmSpecies } from '../data/tms';
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases'; import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from '../phases';
import { BattleStat } from '../data/battle-stat'; import { BattleStat } from '../data/battle-stat';
import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, getBattlerTag } from '../data/battler-tags'; import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, getBattlerTag } from '../data/battler-tags';
import { BattlerTagType } from "../data/enums/battler-tag-type"; import { BattlerTagType } from "../data/enums/battler-tag-type";
@ -27,7 +27,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag'; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
import { ArenaTagType } from "../data/enums/arena-tag-type"; import { ArenaTagType } from "../data/enums/arena-tag-type";
import { Biome } from "../data/enums/biome"; import { Biome } from "../data/enums/biome";
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr } from '../data/ability'; import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, ReverseDrainAbAttr } from '../data/ability';
import { Abilities } from "#app/data/enums/abilities"; import { Abilities } from "#app/data/enums/abilities";
import PokemonData from '../system/pokemon-data'; import PokemonData from '../system/pokemon-data';
import Battle, { BattlerIndex } from '../battle'; import Battle, { BattlerIndex } from '../battle';
@ -2341,6 +2341,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.battleInfo?.destroy(); this.battleInfo?.destroy();
super.destroy(); super.destroy();
} }
/** Heals the source Pokemon of the given amount, or damages it if this Pokemon has a ReverseDrainAbAttr ability. */
drain(source: Pokemon, amount: number, healMessage: string): void {
const reverseDrain = this.hasAbilityWithAttr(ReverseDrainAbAttr);
if (reverseDrain) {
source.damageAndUpdate(amount);
source.turnData.damageTaken += amount;
}
else
source.scene.unshiftPhase(new PokemonHealPhase(source.scene, source.getBattlerIndex(), amount, healMessage, false, true));
}
} }
export default interface Pokemon { export default interface Pokemon {

View File

@ -3990,15 +3990,11 @@ export class PokemonHealPhase extends CommonAnimPhase {
const hasMessage = !!this.message; const hasMessage = !!this.message;
let lastStatusEffect = StatusEffect.NONE; let lastStatusEffect = StatusEffect.NONE;
if (!fullHp || this.hpHealed < 0) { if (!fullHp) {
const hpRestoreMultiplier = new Utils.IntegerHolder(1); const hpRestoreMultiplier = new Utils.IntegerHolder(1);
if (!this.revive) if (!this.revive)
this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier); this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier);
const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value)); const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value));
if (healAmount.value < 0) {
pokemon.damageAndUpdate(healAmount.value * -1, HitResult.HEAL);
healAmount.value = 0;
}
// Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock) // Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock)
if (this.preventFullHeal && pokemon.hp + healAmount.value >= pokemon.getMaxHp()) if (this.preventFullHeal && pokemon.hp + healAmount.value >= pokemon.getMaxHp())
healAmount.value = (pokemon.getMaxHp() - pokemon.hp) - 1; healAmount.value = (pokemon.getMaxHp() - pokemon.hp) - 1;