mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-07 16:09:27 +02:00
Cleaned up pokemonHealPhase
+ wrapped inside an object
This commit is contained in:
parent
e760ed9949
commit
90c9c71cd9
@ -748,16 +748,12 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr {
|
|||||||
const { pokemon, cancelled, simulated, passive } = params;
|
const { pokemon, cancelled, simulated, passive } = params;
|
||||||
if (!pokemon.isFullHp() && !simulated) {
|
if (!pokemon.isFullHp() && !simulated) {
|
||||||
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", pokemon.getBattlerIndex(), pokemon.getMaxHp() / 4, {
|
||||||
"PokemonHealPhase",
|
message: i18next.t("abilityTriggers:typeImmunityHeal", {
|
||||||
pokemon.getBattlerIndex(),
|
|
||||||
toDmgValue(pokemon.getMaxHp() / 4),
|
|
||||||
i18next.t("abilityTriggers:typeImmunityHeal", {
|
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
abilityName,
|
abilityName,
|
||||||
}),
|
}),
|
||||||
true,
|
});
|
||||||
);
|
|
||||||
cancelled.value = true; // Suppresses "No Effect" message
|
cancelled.value = true; // Suppresses "No Effect" message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2830,12 +2826,13 @@ export class PostSummonAllyHealAbAttr extends PostSummonAbAttr {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
target.getBattlerIndex(),
|
target.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / this.healRatio),
|
toDmgValue(pokemon.getMaxHp() / this.healRatio),
|
||||||
i18next.t("abilityTriggers:postSummonAllyHeal", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(target),
|
message: i18next.t("abilityTriggers:postSummonAllyHeal", {
|
||||||
pokemonName: pokemon.name,
|
pokemonNameWithAffix: getPokemonNameWithAffix(target),
|
||||||
}),
|
pokemonName: pokemon.name,
|
||||||
true,
|
}),
|
||||||
!this.showAnim,
|
skipAnim: !this.showAnim,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4476,11 +4473,12 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)),
|
toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)),
|
||||||
i18next.t("abilityTriggers:postWeatherLapseHeal", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
message: i18next.t("abilityTriggers:postWeatherLapseHeal", {
|
||||||
abilityName,
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
abilityName,
|
||||||
true,
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4595,8 +4593,12 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / 8),
|
toDmgValue(pokemon.getMaxHp() / 8),
|
||||||
i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }),
|
{
|
||||||
true,
|
message: i18next.t("abilityTriggers:poisonHeal", {
|
||||||
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
|
abilityName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4843,11 +4845,12 @@ export class PostTurnHealAbAttr extends PostTurnAbAttr {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / 16),
|
toDmgValue(pokemon.getMaxHp() / 16),
|
||||||
i18next.t("abilityTriggers:postTurnHeal", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
message: i18next.t("abilityTriggers:postTurnHeal", {
|
||||||
abilityName,
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
abilityName,
|
||||||
true,
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5224,11 +5227,12 @@ export class HealFromBerryUseAbAttr extends AbAttr {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() * this.healPercent),
|
toDmgValue(pokemon.getMaxHp() * this.healPercent),
|
||||||
i18next.t("abilityTriggers:healFromBerryUse", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
message: i18next.t("abilityTriggers:healFromBerryUse", {
|
||||||
abilityName,
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
abilityName,
|
||||||
true,
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1076,18 +1076,16 @@ export class SeedTag extends SerializableBattlerTag {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Damage the target and restore our HP (or take damage in the case of liquid ooze)
|
// Damage the target and restore our HP (or take damage in the case of liquid ooze)
|
||||||
|
// TODO: Liquid ooze should queue a damage anim phase directly
|
||||||
const damage = pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
|
const damage = pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
|
||||||
const reverseDrain = pokemon.hasAbilityWithAttr("ReverseDrainAbAttr", false);
|
const reverseDrain = pokemon.hasAbilityWithAttr("ReverseDrainAbAttr", false);
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", source.getBattlerIndex(), reverseDrain ? -damage : damage, {
|
||||||
"PokemonHealPhase",
|
message: i18next.t(reverseDrain ? "battlerTags:seededLapseShed" : "battlerTags:seededLapse", {
|
||||||
source.getBattlerIndex(),
|
|
||||||
reverseDrain ? -damage : damage,
|
|
||||||
i18next.t(reverseDrain ? "battlerTags:seededLapseShed" : "battlerTags:seededLapse", {
|
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
}),
|
||||||
false,
|
showFullHpMessage: false,
|
||||||
true,
|
skipAnim: true,
|
||||||
);
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1382,10 +1380,11 @@ export class IngrainTag extends TrappedTag {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / 16),
|
toDmgValue(pokemon.getMaxHp() / 16),
|
||||||
i18next.t("battlerTags:ingrainLapse", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
message: i18next.t("battlerTags:ingrainLapse", {
|
||||||
}),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
true,
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1455,11 +1454,12 @@ export class AquaRingTag extends SerializableBattlerTag {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / 16),
|
toDmgValue(pokemon.getMaxHp() / 16),
|
||||||
i18next.t("battlerTags:aquaRingLapse", {
|
{
|
||||||
moveName: this.getMoveName(),
|
message: i18next.t("battlerTags:aquaRingLapse", {
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
moveName: this.getMoveName(),
|
||||||
}),
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
true,
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,16 +73,12 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||||||
{
|
{
|
||||||
const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4));
|
const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4));
|
||||||
applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: hpHealed });
|
applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: hpHealed });
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", consumer.getBattlerIndex(), hpHealed.value, {
|
||||||
"PokemonHealPhase",
|
message: i18next.t("battle:hpHealBerry", {
|
||||||
consumer.getBattlerIndex(),
|
|
||||||
hpHealed.value,
|
|
||||||
i18next.t("battle:hpHealBerry", {
|
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(consumer),
|
pokemonNameWithAffix: getPokemonNameWithAffix(consumer),
|
||||||
berryName: getBerryName(berryType),
|
berryName: getBerryName(berryType),
|
||||||
}),
|
}),
|
||||||
true,
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BerryType.LUM:
|
case BerryType.LUM:
|
||||||
|
@ -1983,7 +1983,13 @@ export class HealAttr extends MoveEffectAttr {
|
|||||||
*/
|
*/
|
||||||
protected addHealPhase(target: Pokemon, healRatio: number) {
|
protected addHealPhase(target: Pokemon, healRatio: number) {
|
||||||
globalScene.phaseManager.unshiftNew("PokemonHealPhase", target.getBattlerIndex(),
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", target.getBattlerIndex(),
|
||||||
toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(target) }), true, !this.showAnim);
|
toDmgValue(target.getMaxHp() * healRatio),
|
||||||
|
{
|
||||||
|
message: i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(target) }),
|
||||||
|
showFullHpMessage: true,
|
||||||
|
skipAnim: !this.showAnim,
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
override getTargetBenefitScore(user: Pokemon, target: Pokemon, _move: Move): number {
|
override getTargetBenefitScore(user: Pokemon, target: Pokemon, _move: Move): number {
|
||||||
@ -2175,16 +2181,19 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr {
|
|||||||
const pm = globalScene.phaseManager;
|
const pm = globalScene.phaseManager;
|
||||||
|
|
||||||
pm.pushPhase(
|
pm.pushPhase(
|
||||||
pm.create("PokemonHealPhase",
|
pm.create(
|
||||||
|
"PokemonHealPhase",
|
||||||
user.getBattlerIndex(),
|
user.getBattlerIndex(),
|
||||||
maxPartyMemberHp,
|
maxPartyMemberHp,
|
||||||
i18next.t(this.moveMessage, { pokemonName: getPokemonNameWithAffix(user) }),
|
{
|
||||||
true,
|
message: i18next.t(this.moveMessage, { pokemonName: getPokemonNameWithAffix(user) }),
|
||||||
false,
|
showFullHpMessage: false,
|
||||||
false,
|
skipAnim: true,
|
||||||
true,
|
healStatus: true,
|
||||||
this.restorePP),
|
fullRestorePP: this.restorePP,
|
||||||
true);
|
}
|
||||||
|
),
|
||||||
|
true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2280,7 +2289,9 @@ export class HitHealAttr extends MoveEffectAttr {
|
|||||||
message = "";
|
message = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
globalScene.phaseManager.unshiftNew("PokemonHealPhase", user.getBattlerIndex(), healAmount, message, false, true);
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", user.getBattlerIndex(), healAmount,
|
||||||
|
{message, showFullHpMessage: false, skipAnim: true}
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4313,7 +4324,8 @@ export class PunishmentPowerAttr extends VariablePowerAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PresentPowerAttr extends VariablePowerAttr {
|
export class PresentPowerAttr extends VariablePowerAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: [NumberHolder]): boolean {
|
||||||
|
const power = args[0]
|
||||||
/**
|
/**
|
||||||
* If this move is multi-hit, and this attribute is applied to any hit
|
* If this move is multi-hit, and this attribute is applied to any hit
|
||||||
* other than the first, this move cannot result in a heal.
|
* other than the first, this move cannot result in a heal.
|
||||||
@ -4322,17 +4334,21 @@ export class PresentPowerAttr extends VariablePowerAttr {
|
|||||||
|
|
||||||
const powerSeed = randSeedInt(firstHit ? 100 : 80);
|
const powerSeed = randSeedInt(firstHit ? 100 : 80);
|
||||||
if (powerSeed <= 40) {
|
if (powerSeed <= 40) {
|
||||||
(args[0] as NumberHolder).value = 40;
|
power.value = 40;
|
||||||
} else if (40 < powerSeed && powerSeed <= 70) {
|
} else if (powerSeed <= 70) {
|
||||||
(args[0] as NumberHolder).value = 80;
|
power.value = 80;
|
||||||
} else if (70 < powerSeed && powerSeed <= 80) {
|
} else if (powerSeed <= 80) {
|
||||||
(args[0] as NumberHolder).value = 120;
|
power.value = 120;
|
||||||
} else if (80 < powerSeed && powerSeed <= 100) {
|
} else if (powerSeed <= 100) {
|
||||||
// If this move is multi-hit, disable all other hits
|
// Disable all other hits and heal the target for 25% max HP
|
||||||
user.turnData.hitCount = 1;
|
user.turnData.hitCount = 1;
|
||||||
user.turnData.hitsLeft = 1;
|
user.turnData.hitsLeft = 1;
|
||||||
globalScene.phaseManager.unshiftNew("PokemonHealPhase", target.getBattlerIndex(),
|
globalScene.phaseManager.unshiftNew(
|
||||||
toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) }), true);
|
"PokemonHealPhase",
|
||||||
|
target.getBattlerIndex(),
|
||||||
|
toDmgValue(target.getMaxHp() / 4),
|
||||||
|
{message: i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) })}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -155,13 +155,12 @@ export class WishTag extends PositionalTag implements WishArgs {
|
|||||||
|
|
||||||
public override trigger(): void {
|
public override trigger(): void {
|
||||||
// TODO: Rename this locales key - wish shows a message on REMOVAL, not addition
|
// TODO: Rename this locales key - wish shows a message on REMOVAL, not addition
|
||||||
globalScene.phaseManager.queueMessage(
|
// TODO: What messages does Wish show when healing a Pokemon at full HP?
|
||||||
i18next.t("arenaTag:wishTagOnAdd", {
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", this.targetIndex, this.healHp, {
|
||||||
|
message: i18next.t("arenaTag:wishTagOnAdd", {
|
||||||
pokemonNameWithAffix: this.pokemonName,
|
pokemonNameWithAffix: this.pokemonName,
|
||||||
}),
|
}),
|
||||||
);
|
});
|
||||||
|
|
||||||
globalScene.phaseManager.unshiftNew("PokemonHealPhase", this.targetIndex, this.healHp, null, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override shouldTrigger(): boolean {
|
public override shouldTrigger(): boolean {
|
||||||
|
@ -1674,11 +1674,12 @@ export class TurnHealModifier extends PokemonHeldItemModifier {
|
|||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount,
|
toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount,
|
||||||
i18next.t("modifier:turnHealApply", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
message: i18next.t("modifier:turnHealApply", {
|
||||||
typeName: this.type.name,
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
typeName: this.type.name,
|
||||||
true,
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1766,16 +1767,16 @@ export class HitHealModifier extends PokemonHeldItemModifier {
|
|||||||
*/
|
*/
|
||||||
override apply(pokemon: Pokemon): boolean {
|
override apply(pokemon: Pokemon): boolean {
|
||||||
if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) {
|
if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) {
|
||||||
// TODO: this shouldn't be undefined AFAIK
|
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew(
|
||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.turnData.totalDamageDealt / 8) * this.stackCount,
|
toDmgValue((pokemon.turnData.totalDamageDealt * this.stackCount) / 8),
|
||||||
i18next.t("modifier:hitHealApply", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
message: i18next.t("modifier:hitHealApply", {
|
||||||
typeName: this.type.name,
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
typeName: this.type.name,
|
||||||
true,
|
}),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1934,20 +1935,22 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
|
|||||||
*/
|
*/
|
||||||
override apply(pokemon: Pokemon): boolean {
|
override apply(pokemon: Pokemon): boolean {
|
||||||
// Restore the Pokemon to half HP
|
// Restore the Pokemon to half HP
|
||||||
|
// TODO: This should not use a phase to revive pokemon
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew(
|
||||||
"PokemonHealPhase",
|
"PokemonHealPhase",
|
||||||
pokemon.getBattlerIndex(),
|
pokemon.getBattlerIndex(),
|
||||||
toDmgValue(pokemon.getMaxHp() / 2),
|
toDmgValue(pokemon.getMaxHp() / 2),
|
||||||
i18next.t("modifier:pokemonInstantReviveApply", {
|
{
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
message: i18next.t("modifier:pokemonInstantReviveApply", {
|
||||||
typeName: this.type.name,
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
typeName: this.type.name,
|
||||||
false,
|
}),
|
||||||
false,
|
revive: true,
|
||||||
true,
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Remove the Pokemon's FAINT status
|
// Remove the Pokemon's FAINT status
|
||||||
|
// TODO: Remove call to `resetStatus` once StatusEffect.FAINT is canned
|
||||||
pokemon.resetStatus(true, false, true, false);
|
pokemon.resetStatus(true, false, true, false);
|
||||||
|
|
||||||
// Reapply Commander on the Pokemon's side of the field, if applicable
|
// Reapply Commander on the Pokemon's side of the field, if applicable
|
||||||
@ -3549,24 +3552,24 @@ export class EnemyTurnHealModifier extends EnemyPersistentModifier {
|
|||||||
* @returns `true` if the {@linkcode Pokemon} was healed
|
* @returns `true` if the {@linkcode Pokemon} was healed
|
||||||
*/
|
*/
|
||||||
override apply(enemyPokemon: Pokemon): boolean {
|
override apply(enemyPokemon: Pokemon): boolean {
|
||||||
if (!enemyPokemon.isFullHp()) {
|
if (enemyPokemon.isFullHp()) {
|
||||||
globalScene.phaseManager.unshiftNew(
|
return false;
|
||||||
"PokemonHealPhase",
|
|
||||||
enemyPokemon.getBattlerIndex(),
|
|
||||||
Math.max(Math.floor(enemyPokemon.getMaxHp() / (100 / this.healPercent)) * this.stackCount, 1),
|
|
||||||
i18next.t("modifier:enemyTurnHealApply", {
|
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(enemyPokemon),
|
|
||||||
}),
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// Prevent healing to full from healing tokens
|
||||||
|
globalScene.phaseManager.unshiftNew(
|
||||||
|
"PokemonHealPhase",
|
||||||
|
enemyPokemon.getBattlerIndex(),
|
||||||
|
(enemyPokemon.getMaxHp() * this.stackCount * this.healPercent) / 100,
|
||||||
|
{
|
||||||
|
message: i18next.t("modifier:enemyTurnHealApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(enemyPokemon),
|
||||||
|
}),
|
||||||
|
preventFullHeal: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMaxStackCount(): number {
|
getMaxStackCount(): number {
|
||||||
|
@ -1,39 +1,81 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import type { HealBlockTag } from "#data/battler-tags";
|
|
||||||
import { getStatusEffectHealText } from "#data/status-effect";
|
import { getStatusEffectHealText } from "#data/status-effect";
|
||||||
import type { BattlerIndex } from "#enums/battler-index";
|
import type { BattlerIndex } from "#enums/battler-index";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { HitResult } from "#enums/hit-result";
|
import { HitResult } from "#enums/hit-result";
|
||||||
import { CommonAnim } from "#enums/move-anims-common";
|
import { CommonAnim } from "#enums/move-anims-common";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
|
||||||
import { HealingBoosterModifier } from "#modifiers/modifier";
|
import { HealingBoosterModifier } from "#modifiers/modifier";
|
||||||
import { CommonAnimPhase } from "#phases/common-anim-phase";
|
import { CommonAnimPhase } from "#phases/common-anim-phase";
|
||||||
import { HealAchv } from "#system/achv";
|
import { HealAchv } from "#system/achv";
|
||||||
import { NumberHolder } from "#utils/common";
|
import { NumberHolder, toDmgValue } from "#utils/common";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export class PokemonHealPhase extends CommonAnimPhase {
|
export class PokemonHealPhase extends CommonAnimPhase {
|
||||||
public readonly phaseName = "PokemonHealPhase";
|
public readonly phaseName = "PokemonHealPhase";
|
||||||
|
|
||||||
|
/** The base amount of HP to heal. */
|
||||||
private hpHealed: number;
|
private hpHealed: number;
|
||||||
private message: string | null;
|
/**
|
||||||
|
* The message to display upon healing the target, or `undefined` to show no message.
|
||||||
|
* Will be overridden by the full HP message if {@linkcode showFullHpMessage} is set to `true`
|
||||||
|
*/
|
||||||
|
private message: string | undefined;
|
||||||
|
/**
|
||||||
|
* Whether to show a failure message upon healing a Pokemon already at full HP.
|
||||||
|
* @defaultValue `true`
|
||||||
|
*/
|
||||||
private showFullHpMessage: boolean;
|
private showFullHpMessage: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to skip showing the healing animation.
|
||||||
|
* @defaultValue `false`
|
||||||
|
*/
|
||||||
private skipAnim: boolean;
|
private skipAnim: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to revive the affected Pokemon in addition to healing.
|
||||||
|
* Revives will not be affected by any Healing Charms.
|
||||||
|
* @todo Remove post modifier rework as revives will not be using phases to heal stuff
|
||||||
|
* @defaultValue `false`
|
||||||
|
*/
|
||||||
private revive: boolean;
|
private revive: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to heal the affected Pokemon's status condition.
|
||||||
|
* @todo This should not be the healing phase's job
|
||||||
|
* @defaultValue `false`
|
||||||
|
*/
|
||||||
private healStatus: boolean;
|
private healStatus: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to prevent fully healing affected Pokemon, leaving them 1 HP below full.
|
||||||
|
* @defaultValue `false`
|
||||||
|
*/
|
||||||
private preventFullHeal: boolean;
|
private preventFullHeal: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to fully restore PP upon healing.
|
||||||
|
* @todo This should not be the healing phase's job
|
||||||
|
* @defaultValue `false`
|
||||||
|
*/
|
||||||
private fullRestorePP: boolean;
|
private fullRestorePP: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
battlerIndex: BattlerIndex,
|
battlerIndex: BattlerIndex,
|
||||||
hpHealed: number,
|
hpHealed: number,
|
||||||
message: string | null,
|
{
|
||||||
showFullHpMessage: boolean,
|
message,
|
||||||
skipAnim = false,
|
showFullHpMessage = true,
|
||||||
revive = false,
|
skipAnim = false,
|
||||||
healStatus = false,
|
revive = false,
|
||||||
preventFullHeal = false,
|
healStatus = false,
|
||||||
fullRestorePP = false,
|
preventFullHeal = false,
|
||||||
|
fullRestorePP = false,
|
||||||
|
}: {
|
||||||
|
message?: string;
|
||||||
|
showFullHpMessage?: boolean;
|
||||||
|
skipAnim?: boolean;
|
||||||
|
revive?: boolean;
|
||||||
|
healStatus?: boolean;
|
||||||
|
preventFullHeal?: boolean;
|
||||||
|
fullRestorePP?: boolean;
|
||||||
|
} = {},
|
||||||
) {
|
) {
|
||||||
super(battlerIndex, undefined, CommonAnim.HEALTH_UP);
|
super(battlerIndex, undefined, CommonAnim.HEALTH_UP);
|
||||||
|
|
||||||
@ -47,89 +89,108 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
|||||||
this.fullRestorePP = fullRestorePP;
|
this.fullRestorePP = fullRestorePP;
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
override start() {
|
||||||
if (!this.skipAnim && (this.revive || this.getPokemon().hp) && !this.getPokemon().isFullHp()) {
|
// Only play animation if not skipped and target is at full HP
|
||||||
|
if (!this.skipAnim && !this.getPokemon().isFullHp()) {
|
||||||
super.start();
|
super.start();
|
||||||
} else {
|
|
||||||
this.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.heal();
|
||||||
|
|
||||||
|
super.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
end() {
|
private heal() {
|
||||||
const pokemon = this.getPokemon();
|
const pokemon = this.getPokemon();
|
||||||
|
|
||||||
if (!pokemon.isOnField() || (!this.revive && !pokemon.isActive())) {
|
// Prevent healing off-field pokemon unless via revives
|
||||||
return super.end();
|
// TODO: Revival effects shouldn't use this phase
|
||||||
|
if (!this.revive && !pokemon.isActive(true)) {
|
||||||
|
super.end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasMessage = !!this.message;
|
// Check for heal block, ending the phase early if healing was prevented
|
||||||
const healOrDamage = !pokemon.isFullHp() || this.hpHealed < 0;
|
const healBlock = pokemon.getTag(BattlerTagType.HEAL_BLOCK);
|
||||||
const healBlock = pokemon.getTag(BattlerTagType.HEAL_BLOCK) as HealBlockTag;
|
|
||||||
let lastStatusEffect = StatusEffect.NONE;
|
|
||||||
|
|
||||||
if (healBlock && this.hpHealed > 0) {
|
if (healBlock && this.hpHealed > 0) {
|
||||||
globalScene.phaseManager.queueMessage(healBlock.onActivation(pokemon));
|
globalScene.phaseManager.queueMessage(healBlock.onActivation(pokemon));
|
||||||
this.message = null;
|
super.end();
|
||||||
return super.end();
|
return;
|
||||||
}
|
}
|
||||||
if (healOrDamage) {
|
|
||||||
const hpRestoreMultiplier = new NumberHolder(1);
|
this.doHealPokemon();
|
||||||
if (!this.revive) {
|
|
||||||
globalScene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier);
|
// Cure status as applicable
|
||||||
}
|
// TODO: This should not be the job of the healing phase
|
||||||
const healAmount = new NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value));
|
if (this.healStatus && pokemon.status) {
|
||||||
if (healAmount.value < 0) {
|
this.message = getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon));
|
||||||
pokemon.damageAndUpdate(healAmount.value * -1, { result: HitResult.INDIRECT });
|
|
||||||
healAmount.value = 0;
|
|
||||||
}
|
|
||||||
// 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()) {
|
|
||||||
healAmount.value = pokemon.getMaxHp() - pokemon.hp - 1;
|
|
||||||
}
|
|
||||||
healAmount.value = pokemon.heal(healAmount.value);
|
|
||||||
if (healAmount.value) {
|
|
||||||
globalScene.damageNumberHandler.add(pokemon, healAmount.value, HitResult.HEAL);
|
|
||||||
}
|
|
||||||
if (pokemon.isPlayer()) {
|
|
||||||
globalScene.validateAchvs(HealAchv, healAmount);
|
|
||||||
if (healAmount.value > globalScene.gameData.gameStats.highestHeal) {
|
|
||||||
globalScene.gameData.gameStats.highestHeal = healAmount.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.healStatus && !this.revive && pokemon.status) {
|
|
||||||
lastStatusEffect = pokemon.status.effect;
|
|
||||||
pokemon.resetStatus();
|
|
||||||
}
|
|
||||||
if (this.fullRestorePP) {
|
|
||||||
for (const move of this.getPokemon().getMoveset()) {
|
|
||||||
if (move) {
|
|
||||||
move.ppUsed = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pokemon.updateInfo().then(() => super.end());
|
|
||||||
} else if (this.healStatus && !this.revive && pokemon.status) {
|
|
||||||
lastStatusEffect = pokemon.status.effect;
|
|
||||||
pokemon.resetStatus();
|
pokemon.resetStatus();
|
||||||
pokemon.updateInfo().then(() => super.end());
|
}
|
||||||
} else if (this.showFullHpMessage) {
|
|
||||||
this.message = i18next.t("battle:hpIsFull", {
|
// Restore PP.
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
// TODO: This should not be the job of the healing phase
|
||||||
|
if (this.fullRestorePP) {
|
||||||
|
pokemon.getMoveset().forEach(m => {
|
||||||
|
m.ppUsed = 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show message, update info boxes and then wrap up.
|
||||||
if (this.message) {
|
if (this.message) {
|
||||||
globalScene.phaseManager.queueMessage(this.message);
|
globalScene.phaseManager.queueMessage(this.message);
|
||||||
}
|
}
|
||||||
|
pokemon.updateInfo().then(() => super.end());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.healStatus && lastStatusEffect && !hasMessage) {
|
/**
|
||||||
globalScene.phaseManager.queueMessage(
|
* Heal the Pokemon affected by this Phase.
|
||||||
getStatusEffectHealText(lastStatusEffect, getPokemonNameWithAffix(pokemon)),
|
*/
|
||||||
);
|
private doHealPokemon(): void {
|
||||||
|
const pokemon = this.getPokemon()!;
|
||||||
|
|
||||||
|
// If we would heal the user past full HP, don't.
|
||||||
|
if (this.hpHealed > 0 && pokemon.isFullHp()) {
|
||||||
|
if (this.showFullHpMessage) {
|
||||||
|
this.message = i18next.t("battle:hpIsFull", {
|
||||||
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!healOrDamage && !lastStatusEffect) {
|
const healAmount = this.getHealAmount();
|
||||||
super.end();
|
|
||||||
|
if (healAmount < 0) {
|
||||||
|
// If Liquid Ooze is active, damage the user for the healing amount, then return.
|
||||||
|
// TODO: Consider refactoring liquid ooze to not use a heal phase to do damage
|
||||||
|
pokemon.damageAndUpdate(-healAmount, { result: HitResult.INDIRECT });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heal the pokemon, then show damage numbers and validate achievements.
|
||||||
|
pokemon.heal(healAmount);
|
||||||
|
globalScene.damageNumberHandler.add(pokemon, healAmount, HitResult.HEAL);
|
||||||
|
if (pokemon.isPlayer()) {
|
||||||
|
globalScene.validateAchvs(HealAchv, healAmount);
|
||||||
|
globalScene.gameData.gameStats.highestHeal = Math.max(globalScene.gameData.gameStats.highestHeal, healAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the amount of HP to be healed during this Phase.
|
||||||
|
* @returns The updated healing amount, rounded down and capped at the Pokemon's maximum HP.
|
||||||
|
* @todo Prevent double rounding from callers
|
||||||
|
*/
|
||||||
|
private getHealAmount(): number {
|
||||||
|
if (this.revive) {
|
||||||
|
return toDmgValue(this.hpHealed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the effect of healing charms for non-revival items before rounding down and capping at max HP
|
||||||
|
// (or 1 below max for healing tokens).
|
||||||
|
// Liquid Ooze damage (being negative) remains uncapped as normal.
|
||||||
|
const healMulti = new NumberHolder(1);
|
||||||
|
globalScene.applyModifiers(HealingBoosterModifier, this.player, healMulti);
|
||||||
|
return toDmgValue(Math.min(this.hpHealed * healMulti.value, this.getPokemon().getMaxHp() - +this.preventFullHeal));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,16 +154,11 @@ export class QuietFormChangePhase extends BattlePhase {
|
|||||||
this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED);
|
this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED);
|
||||||
if (globalScene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon.isEnemy()) {
|
if (globalScene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon.isEnemy()) {
|
||||||
globalScene.playBgm();
|
globalScene.playBgm();
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), {
|
||||||
"PokemonHealPhase",
|
showFullHpMessage: false,
|
||||||
this.pokemon.getBattlerIndex(),
|
healStatus: true,
|
||||||
this.pokemon.getMaxHp(),
|
fullRestorePP: true,
|
||||||
null,
|
});
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
this.pokemon.findAndRemoveTags(() => true);
|
this.pokemon.findAndRemoveTags(() => true);
|
||||||
this.pokemon.bossSegments = 5;
|
this.pokemon.bossSegments = 5;
|
||||||
this.pokemon.bossSegmentIndex = 4;
|
this.pokemon.bossSegmentIndex = 4;
|
||||||
|
@ -35,15 +35,11 @@ export class TurnEndPhase extends FieldPhase {
|
|||||||
globalScene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon);
|
globalScene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon);
|
||||||
|
|
||||||
if (globalScene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) {
|
if (globalScene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) {
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew("PokemonHealPhase", pokemon.getBattlerIndex(), pokemon.getMaxHp() / 16, {
|
||||||
"PokemonHealPhase",
|
message: i18next.t("battle:turnEndHpRestore", {
|
||||||
pokemon.getBattlerIndex(),
|
|
||||||
Math.max(pokemon.getMaxHp() >> 4, 1),
|
|
||||||
i18next.t("battle:turnEndHpRestore", {
|
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
}),
|
||||||
true,
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pokemon.isPlayer()) {
|
if (!pokemon.isPlayer()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user