[Bug] Liquid Ooze hurts move user instead of one with ability (#1301)
* Fixing Liquid Ooze to turn move user and not one with the ability as well as converted strength sap to use same logic instead of making it a separate class * Replaced "undefined" with "null" * Updated based on feedback + fix file permissions * Fixing file permission on battler-tags * Adding localization for drain message * Apparently this file is 755 unlike the others * Removed ability for custom message in exchange for getting to pass Pokemon name * Once again changing moves from 644 to 755 like it is in repo right now :) * putting ability back to 755 (why are file permissions all over the place)
This commit is contained in:
parent
b7ecebbc6e
commit
06ba63dd7d
|
@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags";
|
|||
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||
import { Gender } from "./gender";
|
||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
|
||||
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";
|
||||
|
@ -575,10 +575,26 @@ export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr {
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for abilities that make drain moves deal damage to user instead of healing them.
|
||||
* @extends PostDefendAbAttr
|
||||
* @see {@linkcode applyPostDefend}
|
||||
*/
|
||||
export class ReverseDrainAbAttr extends PostDefendAbAttr {
|
||||
/**
|
||||
* Determines if a damage and draining move was used to check if this ability should stop the healing.
|
||||
* Examples include: Absorb, Draining Kiss, Bitter Blade, etc.
|
||||
* Also displays a message to show this ability was activated.
|
||||
* @param pokemon {@linkcode Pokemon} with this ability
|
||||
* @param passive N/A
|
||||
* @param attacker {@linkcode Pokemon} that is attacking this Pokemon
|
||||
* @param move {@linkcode PokemonMove} that is being used
|
||||
* @param hitResult N/A
|
||||
* @args N/A
|
||||
* @returns true if healing should be reversed on a healing move, false otherwise.
|
||||
*/
|
||||
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
||||
if (move.getMove().hasAttr(HitHealAttr) || move.getMove().hasAttr(StrengthSapHealAttr) ) {
|
||||
if (move.getMove().hasAttr(HitHealAttr)) {
|
||||
pokemon.scene.queueMessage(getPokemonMessage(attacker, " sucked up the liquid ooze!"));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -391,7 +391,7 @@ export class SeedTag extends BattlerTag {
|
|||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
|
||||
|
||||
const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1));
|
||||
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr);
|
||||
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
|
||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(),
|
||||
!reverseDrain ? damage : damage * -1,
|
||||
!reverseDrain ? getPokemonMessage(pokemon, "'s health is\nsapped by Leech Seed!") : getPokemonMessage(source, "'s Leech Seed\nsucked up the liquid ooze!"),
|
||||
|
@ -1479,4 +1479,3 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag {
|
|||
tag.loadTag(source);
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
|
|
@ -1201,48 +1201,72 @@ export class BoostHealAttr extends HealAttr {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Heals user as a side effect of a move that hits a target.
|
||||
* Healing is based on {@linkcode healRatio} * the amount of damage dealt or a stat of the target.
|
||||
* @extends MoveEffectAttr
|
||||
* @see {@linkcode apply}
|
||||
* @see {@linkcode getUserBenefitScore}
|
||||
*/
|
||||
export class HitHealAttr extends MoveEffectAttr {
|
||||
private healRatio: number;
|
||||
private message: string;
|
||||
private healStat: Stat;
|
||||
|
||||
constructor(healRatio?: number) {
|
||||
constructor(healRatio?: number, healStat?: Stat) {
|
||||
super(true, MoveEffectTrigger.HIT);
|
||||
|
||||
this.healRatio = healRatio || 0.5;
|
||||
this.healStat = healStat || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Heals the user the determined amount and possibly displays a message about regaining health.
|
||||
* If the target has the {@linkcode ReverseDrainAbAttr}, all healing is instead converted
|
||||
* to damage to the user.
|
||||
* @param user {@linkcode Pokemon} using this move
|
||||
* @param target {@linkcode Pokemon} target of this move
|
||||
* @param move {@linkcode Move} being used
|
||||
* @param args N/A
|
||||
* @returns true if the function succeeds
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const healAmount = Math.max(Math.floor(user.turnData.damageDealt * this.healRatio), 1);
|
||||
const reverseDrain = user.hasAbilityWithAttr(ReverseDrainAbAttr);
|
||||
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
|
||||
!reverseDrain ? healAmount : healAmount * -1,
|
||||
!reverseDrain ? getPokemonMessage(target, " had its\nenergy drained!") : undefined,
|
||||
false, true));
|
||||
let healAmount = 0;
|
||||
let message = "";
|
||||
const reverseDrain = target.hasAbilityWithAttr(ReverseDrainAbAttr, false);
|
||||
if (this.healStat) {
|
||||
// Strength Sap formula
|
||||
healAmount = target.getBattleStat(this.healStat);
|
||||
message = i18next.t("battle:drainMessage", {pokemonName: target.name});
|
||||
} else {
|
||||
// Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc.
|
||||
healAmount = Math.max(Math.floor(user.turnData.damageDealt * this.healRatio), 1);
|
||||
message = i18next.t("battle:regainHealth", {pokemonName: user.name});
|
||||
}
|
||||
if (reverseDrain) {
|
||||
user.turnData.damageTaken += healAmount;
|
||||
healAmount = healAmount * -1;
|
||||
message = null;
|
||||
}
|
||||
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(), healAmount, message, false, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the Enemy AI to rank an attack based on a given user
|
||||
* @param user {@linkcode Pokemon} using this move
|
||||
* @param target {@linkcode Pokemon} target of this move
|
||||
* @param move {@linkcode Move} being used
|
||||
* @returns an integer. Higher means enemy is more likely to use that move.
|
||||
*/
|
||||
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
||||
return Math.floor(Math.max((1 - user.getHpRatio()) - 0.33, 0) * ((move.power / 5) / 4));
|
||||
if (this.healStat) {
|
||||
const healAmount = target.getBattleStat(this.healStat);
|
||||
return Math.floor(Math.max(0, (Math.min(1, (healAmount+user.hp)/user.getMaxHp() - 0.33))) / user.getHpRatio());
|
||||
}
|
||||
return Math.floor(Math.max((1 - user.getHpRatio()) - 0.33, 0) * (move.power / 4));
|
||||
}
|
||||
}
|
||||
|
||||
export class StrengthSapHealAttr extends MoveEffectAttr {
|
||||
constructor() {
|
||||
super(true, MoveEffectTrigger.HIT);
|
||||
}
|
||||
|
||||
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 reverseDrain = user.hasAbilityWithAttr(ReverseDrainAbAttr);
|
||||
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
|
||||
!reverseDrain ? healAmount : healAmount * -1,
|
||||
!reverseDrain ? getPokemonMessage(user, " regained\nhealth!") : undefined,
|
||||
false, true));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Attribute used for moves that change priority in a turn given a condition,
|
||||
* e.g. Grassy Glide
|
||||
|
@ -6918,7 +6942,7 @@ export function initMoves() {
|
|||
.triageMove(),
|
||||
new AttackMove(Moves.HIGH_HORSEPOWER, Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7),
|
||||
new StatusMove(Moves.STRENGTH_SAP, Type.GRASS, 100, 10, 100, 0, 7)
|
||||
.attr(StrengthSapHealAttr)
|
||||
.attr(HitHealAttr, null, Stat.ATK)
|
||||
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
||||
.condition((user, target, move) => target.summonData.battleStats[BattleStat.ATK] > -6)
|
||||
.triageMove(),
|
||||
|
|
|
@ -55,5 +55,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"skipItemQuestion": "Bist du sicher, dass du kein Item nehmen willst?",
|
||||
"notDisabled": "{{pokemonName}}'s {{moveName}} ist\nnicht mehr deaktiviert!",
|
||||
"eggHatching": "Oh?",
|
||||
"ivScannerUseQuestion": "IV-Scanner auf {{pokemonName}} benutzen?"
|
||||
"ivScannerUseQuestion": "IV-Scanner auf {{pokemonName}} benutzen?",
|
||||
"drainMessage": "{{pokemonName}} wurde Energie abgesaugt",
|
||||
"regainHealth": "KP von {{pokemonName}} wurden wieder aufgefrischt!"
|
||||
} as const;
|
||||
|
|
|
@ -55,5 +55,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"notDisabled": "{{pokemonName}}'s {{moveName}} is disabled\nno more!",
|
||||
"skipItemQuestion": "Are you sure you want to skip taking an item?",
|
||||
"eggHatching": "Oh?",
|
||||
"ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?"
|
||||
"ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?",
|
||||
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
|
||||
"regainHealth": "{{pokemonName}} regained\nhealth!"
|
||||
} as const;
|
||||
|
|
|
@ -55,5 +55,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"notDisabled": "¡El movimiento {{moveName}} de {{pokemonName}}\nya no está anulado!",
|
||||
"skipItemQuestion": "¿Estás seguro de que no quieres coger un objeto?",
|
||||
"eggHatching": "¿Y esto?",
|
||||
"ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?"
|
||||
"ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?",
|
||||
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
|
||||
"regainHealth": "{{pokemonName}} regained\nhealth!"
|
||||
} as const;
|
||||
|
|
|
@ -55,5 +55,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"notDisabled": "La capacité {{moveName}}\nde {{pokemonName}} n’est plus sous entrave !",
|
||||
"skipItemQuestion": "Êtes-vous sûr·e de ne pas vouloir prendre d’objet ?",
|
||||
"eggHatching": "Oh ?",
|
||||
"ivScannerUseQuestion": "Utiliser le Scanner d’IV sur {{pokemonName}} ?"
|
||||
"ivScannerUseQuestion": "Utiliser le Scanner d’IV sur {{pokemonName}} ?",
|
||||
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
|
||||
"regainHealth": "{{pokemonName}} regained\nhealth!"
|
||||
} as const;
|
||||
|
|
|
@ -55,5 +55,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"notDisabled": "{{pokemonName}}'s {{moveName}} non è più\ndisabilitata!",
|
||||
"skipItemQuestion": "Sei sicuro di non voler prendere nessun oggetto?",
|
||||
"eggHatching": "Oh!",
|
||||
"ivScannerUseQuestion": "Vuoi usare lo scanner di IV su {{pokemonName}}?"
|
||||
"ivScannerUseQuestion": "Vuoi usare lo scanner di IV su {{pokemonName}}?",
|
||||
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
|
||||
"regainHealth": "{{pokemonName}} regained\nhealth!"
|
||||
} as const;
|
||||
|
|
|
@ -55,5 +55,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"notDisabled": "O movimento {{moveName}}\nnão está mais desabilitado!",
|
||||
"skipItemQuestion": "Tem certeza de que não quer escolher um item?",
|
||||
"eggHatching": "Opa?",
|
||||
"ivScannerUseQuestion": "Quer usar o Scanner de IVs em {{pokemonName}}?"
|
||||
"ivScannerUseQuestion": "Quer usar o Scanner de IVs em {{pokemonName}}?",
|
||||
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
|
||||
"regainHealth": "{{pokemonName}} regained\nhealth!"
|
||||
} as const;
|
||||
|
|
|
@ -55,5 +55,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"notDisabled": "{{moveName}} 不再被禁用!",
|
||||
"skipItemQuestion": "你确定要跳过拾取道具吗?",
|
||||
"eggHatching": "咦?",
|
||||
"ivScannerUseQuestion": "对 {{pokemonName}} 使用个体值扫描仪?"
|
||||
"ivScannerUseQuestion": "对 {{pokemonName}} 使用个体值扫描仪?",
|
||||
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
|
||||
"regainHealth": "{{pokemonName}} regained\nhealth!"
|
||||
} as const;
|
||||
|
|
|
@ -52,5 +52,7 @@ export const battle: SimpleTranslationEntries = {
|
|||
"notDisabled": "{{moveName}} 不再被禁用!",
|
||||
"skipItemQuestion": "你要跳過拾取道具嗎?",
|
||||
"eggHatching": "咦?",
|
||||
"ivScannerUseQuestion": "對 {{pokemonName}} 使用個體值掃描?"
|
||||
"ivScannerUseQuestion": "對 {{pokemonName}} 使用個體值掃描?",
|
||||
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
|
||||
"regainHealth": "{{pokemonName}} regained\nhealth!"
|
||||
} as const;
|
||||
|
|
|
@ -4483,9 +4483,10 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
|||
const fullHp = pokemon.getHpRatio() >= 1;
|
||||
|
||||
const hasMessage = !!this.message;
|
||||
const healOrDamage = (!fullHp || this.hpHealed < 0);
|
||||
let lastStatusEffect = StatusEffect.NONE;
|
||||
|
||||
if (!fullHp || this.hpHealed < 0) {
|
||||
if (healOrDamage) {
|
||||
const hpRestoreMultiplier = new Utils.IntegerHolder(1);
|
||||
if (!this.revive) {
|
||||
this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier);
|
||||
|
@ -4530,7 +4531,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
|||
this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectHealText(lastStatusEffect)));
|
||||
}
|
||||
|
||||
if (fullHp && !lastStatusEffect) {
|
||||
if (!healOrDamage && !lastStatusEffect) {
|
||||
super.end();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue