mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-21 17:12:44 +02:00
Added Crit Boost held items, King's Rock, Focus Band and Quick Claw
This commit is contained in:
parent
955592bdf6
commit
c323375590
@ -42,8 +42,6 @@ import type { AttackTypeBoosterModifierType, ModifierTypeOption } from "#app/mod
|
|||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||||
import {
|
import {
|
||||||
AttackTypeBoosterModifier,
|
|
||||||
BypassSpeedChanceModifier,
|
|
||||||
ContactHeldItemTransferChanceModifier,
|
ContactHeldItemTransferChanceModifier,
|
||||||
GigantamaxAccessModifier,
|
GigantamaxAccessModifier,
|
||||||
MegaEvolutionAccessModifier,
|
MegaEvolutionAccessModifier,
|
||||||
|
@ -92,11 +92,8 @@ import {
|
|||||||
PokemonHeldItemModifier,
|
PokemonHeldItemModifier,
|
||||||
PokemonNatureWeightModifier,
|
PokemonNatureWeightModifier,
|
||||||
ShinyRateBoosterModifier,
|
ShinyRateBoosterModifier,
|
||||||
SurviveDamageModifier,
|
|
||||||
TempStatStageBoosterModifier,
|
TempStatStageBoosterModifier,
|
||||||
TempCritBoosterModifier,
|
TempCritBoosterModifier,
|
||||||
StatBoosterModifier,
|
|
||||||
CritBoosterModifier,
|
|
||||||
PokemonBaseStatFlatModifier,
|
PokemonBaseStatFlatModifier,
|
||||||
PokemonBaseStatTotalModifier,
|
PokemonBaseStatTotalModifier,
|
||||||
PokemonIncrementingStatModifier,
|
PokemonIncrementingStatModifier,
|
||||||
@ -257,6 +254,8 @@ import { timedEventManager } from "#app/global-event-manager";
|
|||||||
import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader";
|
import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader";
|
||||||
import { ResetStatusPhase } from "#app/phases/reset-status-phase";
|
import { ResetStatusPhase } from "#app/phases/reset-status-phase";
|
||||||
import { PokemonItemManager } from "./pokemon-held-item-manager";
|
import { PokemonItemManager } from "./pokemon-held-item-manager";
|
||||||
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
|
||||||
export enum LearnMoveSituation {
|
export enum LearnMoveSituation {
|
||||||
MISC,
|
MISC,
|
||||||
@ -1446,7 +1445,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
getCritStage(source: Pokemon, move: Move): number {
|
getCritStage(source: Pokemon, move: Move): number {
|
||||||
const critStage = new NumberHolder(0);
|
const critStage = new NumberHolder(0);
|
||||||
applyMoveAttrs(HighCritAttr, source, this, move, critStage);
|
applyMoveAttrs(HighCritAttr, source, this, move, critStage);
|
||||||
globalScene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critStage);
|
applyHeldItems(ITEM_EFFECT.CRIT_BOOST, { pokemon: source, critStage: critStage });
|
||||||
globalScene.applyModifiers(TempCritBoosterModifier, source.isPlayer(), critStage);
|
globalScene.applyModifiers(TempCritBoosterModifier, source.isPlayer(), critStage);
|
||||||
applyAbAttrs(BonusCritAbAttr, source, null, false, critStage);
|
applyAbAttrs(BonusCritAbAttr, source, null, false, critStage);
|
||||||
const critBoostTag = source.getTag(CritBoostTag);
|
const critBoostTag = source.getTag(CritBoostTag);
|
||||||
@ -1503,7 +1502,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
): number {
|
): number {
|
||||||
const statValue = new NumberHolder(this.getStat(stat, false));
|
const statValue = new NumberHolder(this.getStat(stat, false));
|
||||||
if (!ignoreHeldItems) {
|
if (!ignoreHeldItems) {
|
||||||
globalScene.applyModifiers(StatBoosterModifier, this.isPlayer(), this, stat, statValue);
|
applyHeldItems(ITEM_EFFECT.STAT_BOOST, { pokemon: this, stat: stat, statValue: statValue });
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Ruin abilities here are never ignored, but they reveal themselves on summon anyway
|
// The Ruin abilities here are never ignored, but they reveal themselves on summon anyway
|
||||||
@ -3995,7 +3994,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
surviveDamage.value = this.lapseTag(BattlerTagType.ENDURE_TOKEN);
|
surviveDamage.value = this.lapseTag(BattlerTagType.ENDURE_TOKEN);
|
||||||
}
|
}
|
||||||
if (!surviveDamage.value) {
|
if (!surviveDamage.value) {
|
||||||
globalScene.applyModifiers(SurviveDamageModifier, this.isPlayer(), this, surviveDamage);
|
applyHeldItems(ITEM_EFFECT.SURVIVE_CHANCE, { pokemon: this, surviveDamage: surviveDamage });
|
||||||
}
|
}
|
||||||
if (surviveDamage.value) {
|
if (surviveDamage.value) {
|
||||||
damage = this.hp - 1;
|
damage = this.hp - 1;
|
||||||
|
@ -4,6 +4,7 @@ import { HeldItemId } from "#enums/held-item-id";
|
|||||||
import type { PokemonType } from "#enums/pokemon-type";
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { Stat, type PermanentStat } from "#enums/stat";
|
import { Stat, type PermanentStat } from "#enums/stat";
|
||||||
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import { ITEM_EFFECT } from "./held-item";
|
import { ITEM_EFFECT } from "./held-item";
|
||||||
import {
|
import {
|
||||||
type ATTACK_TYPE_BOOST_PARAMS,
|
type ATTACK_TYPE_BOOST_PARAMS,
|
||||||
@ -16,7 +17,10 @@ import {
|
|||||||
permanentStatToHeldItem,
|
permanentStatToHeldItem,
|
||||||
} from "./held-items/base-stat-booster";
|
} from "./held-items/base-stat-booster";
|
||||||
import { type BERRY_PARAMS, BerryHeldItem, berryTypeToHeldItem } from "./held-items/berry";
|
import { type BERRY_PARAMS, BerryHeldItem, berryTypeToHeldItem } from "./held-items/berry";
|
||||||
|
import { type BYPASS_SPEED_CHANCE_PARAMS, BypassSpeedChanceHeldItem } from "./held-items/bypass-speed-chance";
|
||||||
|
import { type CRIT_BOOST_PARAMS, CritBoostHeldItem, SpeciesCritBoostHeldItem } from "./held-items/crit-booster";
|
||||||
import { type EXP_BOOST_PARAMS, ExpBoosterHeldItem } from "./held-items/exp-booster";
|
import { type EXP_BOOST_PARAMS, ExpBoosterHeldItem } from "./held-items/exp-booster";
|
||||||
|
import { type FLINCH_CHANCE_PARAMS, FlinchChanceHeldItem } from "./held-items/flinch-chance";
|
||||||
import { type HIT_HEAL_PARAMS, HitHealHeldItem } from "./held-items/hit-heal";
|
import { type HIT_HEAL_PARAMS, HitHealHeldItem } from "./held-items/hit-heal";
|
||||||
import { InstantReviveHeldItem, type INSTANT_REVIVE_PARAMS } from "./held-items/instant-revive";
|
import { InstantReviveHeldItem, type INSTANT_REVIVE_PARAMS } from "./held-items/instant-revive";
|
||||||
import {
|
import {
|
||||||
@ -28,8 +32,9 @@ import {
|
|||||||
SpeciesStatBoostHeldItem,
|
SpeciesStatBoostHeldItem,
|
||||||
type STAT_BOOST_PARAMS,
|
type STAT_BOOST_PARAMS,
|
||||||
} from "./held-items/stat-booster";
|
} from "./held-items/stat-booster";
|
||||||
import type { TURN_END_HEAL_PARAMS } from "./held-items/turn-end-heal";
|
import { type SURVIVE_CHANCE_PARAMS, SurviveChanceHeldItem } from "./held-items/survive-chance";
|
||||||
import { TurnEndHealHeldItem } from "./held-items/turn-end-heal";
|
import { type TURN_END_HEAL_PARAMS, TurnEndHealHeldItem } from "./held-items/turn-end-heal";
|
||||||
|
import { type TURN_END_STATUS_PARAMS, TurnEndStatusHeldItem } from "./held-items/turn-end-status";
|
||||||
|
|
||||||
export const allHeldItems = {};
|
export const allHeldItems = {};
|
||||||
|
|
||||||
@ -55,6 +60,7 @@ export function initHeldItems() {
|
|||||||
allHeldItems[heldItemType] = new AttackTypeBoosterHeldItem(heldItemType, 99, pokemonType, 0.2);
|
allHeldItems[heldItemType] = new AttackTypeBoosterHeldItem(heldItemType, 99, pokemonType, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Items that boost specific stats
|
||||||
allHeldItems[HeldItemId.EVIOLITE] = new EvolutionStatBoostHeldItem(
|
allHeldItems[HeldItemId.EVIOLITE] = new EvolutionStatBoostHeldItem(
|
||||||
HeldItemId.EVIOLITE,
|
HeldItemId.EVIOLITE,
|
||||||
1,
|
1,
|
||||||
@ -86,12 +92,27 @@ export function initHeldItems() {
|
|||||||
SpeciesId.CLAMPERL,
|
SpeciesId.CLAMPERL,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Items that boost the crit rate
|
||||||
|
allHeldItems[HeldItemId.SCOPE_LENS] = new CritBoostHeldItem(HeldItemId.SCOPE_LENS, 1, 1);
|
||||||
|
allHeldItems[HeldItemId.LEEK] = new SpeciesCritBoostHeldItem(HeldItemId.LEEK, 1, 2, [
|
||||||
|
SpeciesId.FARFETCHD,
|
||||||
|
SpeciesId.GALAR_FARFETCHD,
|
||||||
|
SpeciesId.SIRFETCHD,
|
||||||
|
]);
|
||||||
|
|
||||||
allHeldItems[HeldItemId.LUCKY_EGG] = new ExpBoosterHeldItem(HeldItemId.LUCKY_EGG, 99, 40);
|
allHeldItems[HeldItemId.LUCKY_EGG] = new ExpBoosterHeldItem(HeldItemId.LUCKY_EGG, 99, 40);
|
||||||
allHeldItems[HeldItemId.GOLDEN_EGG] = new ExpBoosterHeldItem(HeldItemId.GOLDEN_EGG, 99, 100);
|
allHeldItems[HeldItemId.GOLDEN_EGG] = new ExpBoosterHeldItem(HeldItemId.GOLDEN_EGG, 99, 100);
|
||||||
|
|
||||||
allHeldItems[HeldItemId.LEFTOVERS] = new TurnEndHealHeldItem(HeldItemId.LEFTOVERS, 4);
|
allHeldItems[HeldItemId.LEFTOVERS] = new TurnEndHealHeldItem(HeldItemId.LEFTOVERS, 4);
|
||||||
allHeldItems[HeldItemId.SHELL_BELL] = new HitHealHeldItem(HeldItemId.SHELL_BELL, 4);
|
allHeldItems[HeldItemId.SHELL_BELL] = new HitHealHeldItem(HeldItemId.SHELL_BELL, 4);
|
||||||
|
|
||||||
|
allHeldItems[HeldItemId.FOCUS_BAND] = new SurviveChanceHeldItem(HeldItemId.FOCUS_BAND, 5);
|
||||||
|
allHeldItems[HeldItemId.QUICK_CLAW] = new BypassSpeedChanceHeldItem(HeldItemId.QUICK_CLAW, 3);
|
||||||
|
allHeldItems[HeldItemId.KINGS_ROCK] = new FlinchChanceHeldItem(HeldItemId.KINGS_ROCK, 3, 10);
|
||||||
|
|
||||||
|
allHeldItems[HeldItemId.FLAME_ORB] = new TurnEndStatusHeldItem(HeldItemId.FLAME_ORB, 1, StatusEffect.BURN);
|
||||||
|
allHeldItems[HeldItemId.TOXIC_ORB] = new TurnEndStatusHeldItem(HeldItemId.TOXIC_ORB, 1, StatusEffect.TOXIC);
|
||||||
|
|
||||||
// vitamins
|
// vitamins
|
||||||
for (const [statKey, heldItemType] of Object.entries(permanentStatToHeldItem)) {
|
for (const [statKey, heldItemType] of Object.entries(permanentStatToHeldItem)) {
|
||||||
const stat = Number(statKey) as PermanentStat;
|
const stat = Number(statKey) as PermanentStat;
|
||||||
@ -109,6 +130,11 @@ type APPLY_HELD_ITEMS_PARAMS = {
|
|||||||
[ITEM_EFFECT.BASE_STAT_BOOSTER]: BASE_STAT_BOOSTER_PARAMS;
|
[ITEM_EFFECT.BASE_STAT_BOOSTER]: BASE_STAT_BOOSTER_PARAMS;
|
||||||
[ITEM_EFFECT.INSTANT_REVIVE]: INSTANT_REVIVE_PARAMS;
|
[ITEM_EFFECT.INSTANT_REVIVE]: INSTANT_REVIVE_PARAMS;
|
||||||
[ITEM_EFFECT.STAT_BOOST]: STAT_BOOST_PARAMS;
|
[ITEM_EFFECT.STAT_BOOST]: STAT_BOOST_PARAMS;
|
||||||
|
[ITEM_EFFECT.CRIT_BOOST]: CRIT_BOOST_PARAMS;
|
||||||
|
[ITEM_EFFECT.TURN_END_STATUS]: TURN_END_STATUS_PARAMS;
|
||||||
|
[ITEM_EFFECT.SURVIVE_CHANCE]: SURVIVE_CHANCE_PARAMS;
|
||||||
|
[ITEM_EFFECT.BYPASS_SPEED_CHANCE]: BYPASS_SPEED_CHANCE_PARAMS;
|
||||||
|
[ITEM_EFFECT.FLINCH_CHANCE]: FLINCH_CHANCE_PARAMS;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function applyHeldItems<T extends ITEM_EFFECT>(effect: T, params: APPLY_HELD_ITEMS_PARAMS[T]) {
|
export function applyHeldItems<T extends ITEM_EFFECT>(effect: T, params: APPLY_HELD_ITEMS_PARAMS[T]) {
|
||||||
|
@ -15,6 +15,11 @@ export const ITEM_EFFECT = {
|
|||||||
BASE_STAT_BOOSTER: 7,
|
BASE_STAT_BOOSTER: 7,
|
||||||
INSTANT_REVIVE: 8,
|
INSTANT_REVIVE: 8,
|
||||||
STAT_BOOST: 9,
|
STAT_BOOST: 9,
|
||||||
|
CRIT_BOOST: 10,
|
||||||
|
TURN_END_STATUS: 11,
|
||||||
|
SURVIVE_CHANCE: 12,
|
||||||
|
BYPASS_SPEED_CHANCE: 13,
|
||||||
|
FLINCH_CHANCE: 14,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type ITEM_EFFECT = (typeof ITEM_EFFECT)[keyof typeof ITEM_EFFECT];
|
export type ITEM_EFFECT = (typeof ITEM_EFFECT)[keyof typeof ITEM_EFFECT];
|
||||||
|
62
src/items/held-items/bypass-speed-chance.ts
Normal file
62
src/items/held-items/bypass-speed-chance.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import type { BooleanHolder } from "#app/utils/common";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
import { Command } from "#app/ui/command-ui-handler";
|
||||||
|
|
||||||
|
export interface BYPASS_SPEED_CHANCE_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
doBypassSpeed: BooleanHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, namely Toxic Orb and Flame Orb, that apply a
|
||||||
|
* set {@linkcode StatusEffect} at the end of a turn.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class BypassSpeedChanceHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BYPASS_SPEED_CHANCE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if {@linkcode BypassSpeedChanceModifier} should be applied
|
||||||
|
* @param pokemon the {@linkcode Pokemon} that holds the item
|
||||||
|
* @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed
|
||||||
|
* @returns `true` if {@linkcode BypassSpeedChanceModifier} should be applied
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon?: Pokemon, doBypassSpeed?: BooleanHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, doBypassSpeed) && !!doBypassSpeed;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode BypassSpeedChanceModifier}
|
||||||
|
* @param pokemon the {@linkcode Pokemon} that holds the item
|
||||||
|
* @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed
|
||||||
|
* @returns `true` if {@linkcode BypassSpeedChanceModifier} has been applied
|
||||||
|
*/
|
||||||
|
apply(params: BYPASS_SPEED_CHANCE_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const doBypassSpeed = params.doBypassSpeed;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
if (!doBypassSpeed.value && pokemon.randBattleSeedInt(10) < stackCount) {
|
||||||
|
doBypassSpeed.value = true;
|
||||||
|
const isCommandFight =
|
||||||
|
globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]?.command === Command.FIGHT;
|
||||||
|
|
||||||
|
if (isCommandFight) {
|
||||||
|
globalScene.queueMessage(
|
||||||
|
i18next.t("modifier:bypassSpeedChanceApply", {
|
||||||
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
|
itemName: this.name,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
86
src/items/held-items/crit-booster.ts
Normal file
86
src/items/held-items/crit-booster.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import type { SpeciesId } from "#enums/species-id";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface CRIT_BOOST_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
critStage: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items that apply critical-hit stage boost(s).
|
||||||
|
* using a multiplier.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class CritBoostHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.CRIT_BOOST];
|
||||||
|
|
||||||
|
/** The amount of stages by which the held item increases the current critical-hit stage value */
|
||||||
|
protected stageIncrement: number;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, stageIncrement: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
|
||||||
|
this.stageIncrement = stageIncrement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the current critical-hit stage value by {@linkcode stageIncrement}.
|
||||||
|
* @param _pokemon {@linkcode Pokemon} N/A
|
||||||
|
* @param critStage {@linkcode NumberHolder} that holds the resulting critical-hit level
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: CRIT_BOOST_PARAMS): boolean {
|
||||||
|
params.critStage.value += this.stageIncrement;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items that apply critical-hit stage boost(s)
|
||||||
|
* if the holder is of a specific {@linkcode SpeciesId}.
|
||||||
|
* @extends CritBoosterModifier
|
||||||
|
* @see {@linkcode shouldApply}
|
||||||
|
*/
|
||||||
|
export class SpeciesCritBoostHeldItem extends CritBoostHeldItem {
|
||||||
|
/** The species that the held item's critical-hit stage boost applies to */
|
||||||
|
private species: SpeciesId[];
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, stageIncrement: number, species: SpeciesId[]) {
|
||||||
|
super(type, maxStackCount, stageIncrement);
|
||||||
|
|
||||||
|
this.species = species;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the holder's {@linkcode SpeciesId} (or its fused species) is listed
|
||||||
|
* in {@linkcode species}.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the held item
|
||||||
|
* @param critStage {@linkcode NumberHolder} that holds the resulting critical-hit level
|
||||||
|
* @returns `true` if the critical-hit level can be incremented, false otherwise
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon: Pokemon, critStage: NumberHolder): boolean {
|
||||||
|
// return (
|
||||||
|
// super.shouldApply(pokemon, critStage) &&
|
||||||
|
// (this.species.includes(pokemon.getSpeciesForm(true).speciesId) ||
|
||||||
|
// (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId)))
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
apply(params: CRIT_BOOST_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const fitsSpecies =
|
||||||
|
this.species.includes(pokemon.getSpeciesForm(true).speciesId) ||
|
||||||
|
(pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId));
|
||||||
|
|
||||||
|
if (fitsSpecies) {
|
||||||
|
return super.apply(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { NumberHolder } from "#app/utils/common";
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
import { HeldItemId } from "#enums/held-item-id";
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
import i18next from "i18next";
|
|
||||||
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
export interface EXP_BOOST_PARAMS {
|
export interface EXP_BOOST_PARAMS {
|
||||||
@ -20,22 +19,6 @@ export class ExpBoosterHeldItem extends HeldItem {
|
|||||||
this.boostMultiplier = boostPercent * 0.01;
|
this.boostMultiplier = boostPercent * 0.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name(): string {
|
|
||||||
return this.type === HeldItemId.LUCKY_EGG
|
|
||||||
? i18next.t("modifierType:ModifierType.LUCKY_EGG.name")
|
|
||||||
: i18next.t("modifierType:ModifierType.GOLDEN_EGG.name");
|
|
||||||
}
|
|
||||||
|
|
||||||
get description(): string {
|
|
||||||
return this.type === HeldItemId.LUCKY_EGG
|
|
||||||
? i18next.t("modifierType:ModifierType.LUCKY_EGG.description")
|
|
||||||
: i18next.t("modifierType:ModifierType.GOLDEN_EGG.description");
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon(): string {
|
|
||||||
return this.type === HeldItemId.LUCKY_EGG ? "lucky_egg" : "golden_egg";
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: What do we do with this? Need to look up all the shouldApply
|
// TODO: What do we do with this? Need to look up all the shouldApply
|
||||||
/**
|
/**
|
||||||
* Checks if {@linkcode PokemonExpBoosterModifier} should be applied
|
* Checks if {@linkcode PokemonExpBoosterModifier} should be applied
|
||||||
|
57
src/items/held-items/flinch-chance.ts
Normal file
57
src/items/held-items/flinch-chance.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import type { BooleanHolder } from "#app/utils/common";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
|
export interface FLINCH_CHANCE_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
flinched: BooleanHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, namely Toxic Orb and Flame Orb, that apply a
|
||||||
|
* set {@linkcode StatusEffect} at the end of a turn.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class FlinchChanceHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.FLINCH_CHANCE];
|
||||||
|
private chance: number;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, chance: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
|
||||||
|
this.chance = chance; // 10
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if {@linkcode FlinchChanceModifier} should be applied
|
||||||
|
* @param pokemon the {@linkcode Pokemon} that holds the item
|
||||||
|
* @param flinched {@linkcode BooleanHolder} that is `true` if the pokemon flinched
|
||||||
|
* @returns `true` if {@linkcode FlinchChanceModifier} should be applied
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon?: Pokemon, flinched?: BooleanHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, flinched) && !!flinched;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode FlinchChanceModifier} to randomly flinch targets hit.
|
||||||
|
* @param pokemon - The {@linkcode Pokemon} that holds the item
|
||||||
|
* @param flinched - A {@linkcode BooleanHolder} holding whether the pokemon has flinched
|
||||||
|
* @returns `true` if {@linkcode FlinchChanceModifier} was applied successfully
|
||||||
|
*/
|
||||||
|
apply(params: FLINCH_CHANCE_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const flinched = params.flinched;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
// The check for pokemon.summonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch
|
||||||
|
// TODO: Since summonData is always defined now, we can probably remove this
|
||||||
|
if (pokemon.summonData && !flinched.value && pokemon.randBattleSeedInt(100) < stackCount * this.chance) {
|
||||||
|
flinched.value = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
57
src/items/held-items/survive-chance.ts
Normal file
57
src/items/held-items/survive-chance.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import type { BooleanHolder } from "#app/utils/common";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
|
||||||
|
export interface SURVIVE_CHANCE_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
surviveDamage: BooleanHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, namely Toxic Orb and Flame Orb, that apply a
|
||||||
|
* set {@linkcode StatusEffect} at the end of a turn.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class SurviveChanceHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.SURVIVE_CHANCE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the {@linkcode SurviveDamageModifier} should be applied
|
||||||
|
* @param pokemon the {@linkcode Pokemon} that holds the item
|
||||||
|
* @param surviveDamage {@linkcode BooleanHolder} that holds the survive damage
|
||||||
|
* @returns `true` if the {@linkcode SurviveDamageModifier} should be applied
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon?: Pokemon, surviveDamage?: BooleanHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, surviveDamage) && !!surviveDamage;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode SurviveDamageModifier}
|
||||||
|
* @param pokemon the {@linkcode Pokemon} that holds the item
|
||||||
|
* @param surviveDamage {@linkcode BooleanHolder} that holds the survive damage
|
||||||
|
* @returns `true` if the survive damage has been applied
|
||||||
|
*/
|
||||||
|
apply(params: SURVIVE_CHANCE_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const surviveDamage = params.surviveDamage;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
if (!surviveDamage.value && pokemon.randBattleSeedInt(10) < stackCount) {
|
||||||
|
surviveDamage.value = true;
|
||||||
|
|
||||||
|
globalScene.queueMessage(
|
||||||
|
i18next.t("modifier:surviveDamageApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
typeName: this.name,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
40
src/items/held-items/turn-end-status.ts
Normal file
40
src/items/held-items/turn-end-status.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import type { StatusEffect } from "#enums/status-effect";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
|
export interface TURN_END_STATUS_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, namely Toxic Orb and Flame Orb, that apply a
|
||||||
|
* set {@linkcode StatusEffect} at the end of a turn.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class TurnEndStatusHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.TURN_END_STATUS];
|
||||||
|
/** The status effect to be applied by the held item */
|
||||||
|
private effect: StatusEffect;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, effect: StatusEffect) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
|
||||||
|
this.effect = effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to inflicts the holder with the associated {@linkcode StatusEffect}.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the held item
|
||||||
|
* @returns `true` if the status effect was applied successfully
|
||||||
|
*/
|
||||||
|
apply(params: TURN_END_STATUS_PARAMS): boolean {
|
||||||
|
return params.pokemon.trySetStatus(this.effect, true, undefined, undefined, this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatusEffect(): StatusEffect {
|
||||||
|
return this.effect;
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,6 @@ import { LearnMovePhase, LearnMoveType } from "#app/phases/learn-move-phase";
|
|||||||
import { LevelUpPhase } from "#app/phases/level-up-phase";
|
import { LevelUpPhase } from "#app/phases/level-up-phase";
|
||||||
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
||||||
import type { VoucherType } from "#app/system/voucher";
|
import type { VoucherType } from "#app/system/voucher";
|
||||||
import { Command } from "#app/ui/command-ui-handler";
|
|
||||||
import { addTextObject, TextStyle } from "#app/ui/text";
|
import { addTextObject, TextStyle } from "#app/ui/text";
|
||||||
import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue } from "#app/utils/common";
|
import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue } from "#app/utils/common";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
@ -42,7 +41,6 @@ import {
|
|||||||
getModifierType,
|
getModifierType,
|
||||||
ModifierTypeGenerator,
|
ModifierTypeGenerator,
|
||||||
modifierTypes,
|
modifierTypes,
|
||||||
PokemonHeldItemModifierType,
|
|
||||||
} from "./modifier-type";
|
} from "./modifier-type";
|
||||||
import { Color, ShadowColor } from "#enums/color";
|
import { Color, ShadowColor } from "#enums/color";
|
||||||
import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters";
|
import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters";
|
||||||
@ -1029,438 +1027,6 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifier used for held items that apply critical-hit stage boost(s).
|
|
||||||
* @extends PokemonHeldItemModifier
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
|
||||||
export class CritBoosterModifier extends PokemonHeldItemModifier {
|
|
||||||
/** The amount of stages by which the held item increases the current critical-hit stage value */
|
|
||||||
protected stageIncrement: number;
|
|
||||||
|
|
||||||
constructor(type: ModifierType, pokemonId: number, stageIncrement: number, stackCount?: number) {
|
|
||||||
super(type, pokemonId, stackCount);
|
|
||||||
|
|
||||||
this.stageIncrement = stageIncrement;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new CritBoosterModifier(this.type, this.pokemonId, this.stageIncrement, this.stackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
getArgs(): any[] {
|
|
||||||
return super.getArgs().concat(this.stageIncrement);
|
|
||||||
}
|
|
||||||
|
|
||||||
matchType(modifier: Modifier): boolean {
|
|
||||||
if (modifier instanceof CritBoosterModifier) {
|
|
||||||
return (modifier as CritBoosterModifier).stageIncrement === this.stageIncrement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increases the current critical-hit stage value by {@linkcode stageIncrement}.
|
|
||||||
* @param _pokemon {@linkcode Pokemon} N/A
|
|
||||||
* @param critStage {@linkcode NumberHolder} that holds the resulting critical-hit level
|
|
||||||
* @returns always `true`
|
|
||||||
*/
|
|
||||||
override apply(_pokemon: Pokemon, critStage: NumberHolder): boolean {
|
|
||||||
critStage.value += this.stageIncrement;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifier used for held items that apply critical-hit stage boost(s)
|
|
||||||
* if the holder is of a specific {@linkcode SpeciesId}.
|
|
||||||
* @extends CritBoosterModifier
|
|
||||||
* @see {@linkcode shouldApply}
|
|
||||||
*/
|
|
||||||
export class SpeciesCritBoosterModifier extends CritBoosterModifier {
|
|
||||||
/** The species that the held item's critical-hit stage boost applies to */
|
|
||||||
private species: SpeciesId[];
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
type: ModifierType,
|
|
||||||
pokemonId: number,
|
|
||||||
stageIncrement: number,
|
|
||||||
species: SpeciesId[],
|
|
||||||
stackCount?: number,
|
|
||||||
) {
|
|
||||||
super(type, pokemonId, stageIncrement, stackCount);
|
|
||||||
|
|
||||||
this.species = species;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new SpeciesCritBoosterModifier(
|
|
||||||
this.type,
|
|
||||||
this.pokemonId,
|
|
||||||
this.stageIncrement,
|
|
||||||
this.species,
|
|
||||||
this.stackCount,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getArgs(): any[] {
|
|
||||||
return [...super.getArgs(), this.species];
|
|
||||||
}
|
|
||||||
|
|
||||||
matchType(modifier: Modifier): boolean {
|
|
||||||
return modifier instanceof SpeciesCritBoosterModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the holder's {@linkcode SpeciesId} (or its fused species) is listed
|
|
||||||
* in {@linkcode species}.
|
|
||||||
* @param pokemon {@linkcode Pokemon} that holds the held item
|
|
||||||
* @param critStage {@linkcode NumberHolder} that holds the resulting critical-hit level
|
|
||||||
* @returns `true` if the critical-hit level can be incremented, false otherwise
|
|
||||||
*/
|
|
||||||
override shouldApply(pokemon: Pokemon, critStage: NumberHolder): boolean {
|
|
||||||
return (
|
|
||||||
super.shouldApply(pokemon, critStage) &&
|
|
||||||
(this.species.includes(pokemon.getSpeciesForm(true).speciesId) ||
|
|
||||||
(pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies Specific Type item boosts (e.g., Magnet)
|
|
||||||
*/
|
|
||||||
export class AttackTypeBoosterModifier extends PokemonHeldItemModifier {
|
|
||||||
public moveType: PokemonType;
|
|
||||||
private boostMultiplier: number;
|
|
||||||
|
|
||||||
constructor(type: ModifierType, pokemonId: number, moveType: PokemonType, boostPercent: number, stackCount?: number) {
|
|
||||||
super(type, pokemonId, stackCount);
|
|
||||||
|
|
||||||
this.moveType = moveType;
|
|
||||||
this.boostMultiplier = boostPercent * 0.01;
|
|
||||||
}
|
|
||||||
|
|
||||||
matchType(modifier: Modifier): boolean {
|
|
||||||
if (modifier instanceof AttackTypeBoosterModifier) {
|
|
||||||
const attackTypeBoosterModifier = modifier as AttackTypeBoosterModifier;
|
|
||||||
return (
|
|
||||||
attackTypeBoosterModifier.moveType === this.moveType &&
|
|
||||||
attackTypeBoosterModifier.boostMultiplier === this.boostMultiplier
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new AttackTypeBoosterModifier(
|
|
||||||
this.type,
|
|
||||||
this.pokemonId,
|
|
||||||
this.moveType,
|
|
||||||
this.boostMultiplier * 100,
|
|
||||||
this.stackCount,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getArgs(): any[] {
|
|
||||||
return super.getArgs().concat([this.moveType, this.boostMultiplier * 100]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if {@linkcode AttackTypeBoosterModifier} should be applied
|
|
||||||
* @param pokemon the {@linkcode Pokemon} that holds the held item
|
|
||||||
* @param moveType the {@linkcode PokemonType} of the move being used
|
|
||||||
* @param movePower the {@linkcode NumberHolder} that holds the power of the move
|
|
||||||
* @returns `true` if boosts should be applied to the move.
|
|
||||||
*/
|
|
||||||
override shouldApply(pokemon?: Pokemon, moveType?: PokemonType, movePower?: NumberHolder): boolean {
|
|
||||||
return (
|
|
||||||
super.shouldApply(pokemon, moveType, movePower) &&
|
|
||||||
typeof moveType === "number" &&
|
|
||||||
movePower instanceof NumberHolder &&
|
|
||||||
this.moveType === moveType
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies {@linkcode AttackTypeBoosterModifier}
|
|
||||||
* @param pokemon {@linkcode Pokemon} that holds the held item
|
|
||||||
* @param moveType {@linkcode PokemonType} of the move being used
|
|
||||||
* @param movePower {@linkcode NumberHolder} that holds the power of the move
|
|
||||||
* @returns `true` if boosts have been applied to the move.
|
|
||||||
*/
|
|
||||||
override apply(_pokemon: Pokemon, moveType: PokemonType, movePower: NumberHolder): boolean {
|
|
||||||
if (moveType === this.moveType && movePower.value >= 1) {
|
|
||||||
(movePower as NumberHolder).value = Math.floor(
|
|
||||||
(movePower as NumberHolder).value * (1 + this.getStackCount() * this.boostMultiplier),
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getScoreMultiplier(): number {
|
|
||||||
return 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
|
||||||
return 99;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SurviveDamageModifier extends PokemonHeldItemModifier {
|
|
||||||
matchType(modifier: Modifier): boolean {
|
|
||||||
return modifier instanceof SurviveDamageModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new SurviveDamageModifier(this.type, this.pokemonId, this.stackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the {@linkcode SurviveDamageModifier} should be applied
|
|
||||||
* @param pokemon the {@linkcode Pokemon} that holds the item
|
|
||||||
* @param surviveDamage {@linkcode BooleanHolder} that holds the survive damage
|
|
||||||
* @returns `true` if the {@linkcode SurviveDamageModifier} should be applied
|
|
||||||
*/
|
|
||||||
override shouldApply(pokemon?: Pokemon, surviveDamage?: BooleanHolder): boolean {
|
|
||||||
return super.shouldApply(pokemon, surviveDamage) && !!surviveDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies {@linkcode SurviveDamageModifier}
|
|
||||||
* @param pokemon the {@linkcode Pokemon} that holds the item
|
|
||||||
* @param surviveDamage {@linkcode BooleanHolder} that holds the survive damage
|
|
||||||
* @returns `true` if the survive damage has been applied
|
|
||||||
*/
|
|
||||||
override apply(pokemon: Pokemon, surviveDamage: BooleanHolder): boolean {
|
|
||||||
if (!surviveDamage.value && pokemon.randBattleSeedInt(10) < this.getStackCount()) {
|
|
||||||
surviveDamage.value = true;
|
|
||||||
|
|
||||||
globalScene.queueMessage(
|
|
||||||
i18next.t("modifier:surviveDamageApply", {
|
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
|
||||||
typeName: this.type.name,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BypassSpeedChanceModifier extends PokemonHeldItemModifier {
|
|
||||||
matchType(modifier: Modifier) {
|
|
||||||
return modifier instanceof BypassSpeedChanceModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new BypassSpeedChanceModifier(this.type, this.pokemonId, this.stackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if {@linkcode BypassSpeedChanceModifier} should be applied
|
|
||||||
* @param pokemon the {@linkcode Pokemon} that holds the item
|
|
||||||
* @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed
|
|
||||||
* @returns `true` if {@linkcode BypassSpeedChanceModifier} should be applied
|
|
||||||
*/
|
|
||||||
override shouldApply(pokemon?: Pokemon, doBypassSpeed?: BooleanHolder): boolean {
|
|
||||||
return super.shouldApply(pokemon, doBypassSpeed) && !!doBypassSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies {@linkcode BypassSpeedChanceModifier}
|
|
||||||
* @param pokemon the {@linkcode Pokemon} that holds the item
|
|
||||||
* @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed
|
|
||||||
* @returns `true` if {@linkcode BypassSpeedChanceModifier} has been applied
|
|
||||||
*/
|
|
||||||
override apply(pokemon: Pokemon, doBypassSpeed: BooleanHolder): boolean {
|
|
||||||
if (!doBypassSpeed.value && pokemon.randBattleSeedInt(10) < this.getStackCount()) {
|
|
||||||
doBypassSpeed.value = true;
|
|
||||||
const isCommandFight =
|
|
||||||
globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]?.command === Command.FIGHT;
|
|
||||||
const hasQuickClaw = this.type instanceof PokemonHeldItemModifierType && this.type.id === "QUICK_CLAW";
|
|
||||||
|
|
||||||
if (isCommandFight && hasQuickClaw) {
|
|
||||||
globalScene.queueMessage(
|
|
||||||
i18next.t("modifier:bypassSpeedChanceApply", {
|
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
|
||||||
itemName: i18next.t("modifierType:ModifierType.QUICK_CLAW.name"),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class for Pokemon held items like King's Rock
|
|
||||||
* Because King's Rock can be stacked in PokeRogue, unlike mainline, it does not receive a boost from AbilityId.SERENE_GRACE
|
|
||||||
*/
|
|
||||||
export class FlinchChanceModifier extends PokemonHeldItemModifier {
|
|
||||||
private chance: number;
|
|
||||||
constructor(type: ModifierType, pokemonId: number, stackCount?: number) {
|
|
||||||
super(type, pokemonId, stackCount);
|
|
||||||
|
|
||||||
this.chance = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
matchType(modifier: Modifier) {
|
|
||||||
return modifier instanceof FlinchChanceModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new FlinchChanceModifier(this.type, this.pokemonId, this.stackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if {@linkcode FlinchChanceModifier} should be applied
|
|
||||||
* @param pokemon the {@linkcode Pokemon} that holds the item
|
|
||||||
* @param flinched {@linkcode BooleanHolder} that is `true` if the pokemon flinched
|
|
||||||
* @returns `true` if {@linkcode FlinchChanceModifier} should be applied
|
|
||||||
*/
|
|
||||||
override shouldApply(pokemon?: Pokemon, flinched?: BooleanHolder): boolean {
|
|
||||||
return super.shouldApply(pokemon, flinched) && !!flinched;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies {@linkcode FlinchChanceModifier} to randomly flinch targets hit.
|
|
||||||
* @param pokemon - The {@linkcode Pokemon} that holds the item
|
|
||||||
* @param flinched - A {@linkcode BooleanHolder} holding whether the pokemon has flinched
|
|
||||||
* @returns `true` if {@linkcode FlinchChanceModifier} was applied successfully
|
|
||||||
*/
|
|
||||||
override apply(pokemon: Pokemon, flinched: BooleanHolder): boolean {
|
|
||||||
// The check for pokemon.summonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch
|
|
||||||
// TODO: Since summonData is always defined now, we can probably remove this
|
|
||||||
if (pokemon.summonData && !flinched.value && pokemon.randBattleSeedInt(100) < this.getStackCount() * this.chance) {
|
|
||||||
flinched.value = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TurnHealModifier extends PokemonHeldItemModifier {
|
|
||||||
matchType(modifier: Modifier) {
|
|
||||||
return modifier instanceof TurnHealModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new TurnHealModifier(this.type, this.pokemonId, this.stackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies {@linkcode TurnHealModifier}
|
|
||||||
* @param pokemon The {@linkcode Pokemon} that holds the item
|
|
||||||
* @returns `true` if the {@linkcode Pokemon} was healed
|
|
||||||
*/
|
|
||||||
override apply(pokemon: Pokemon): boolean {
|
|
||||||
if (!pokemon.isFullHp()) {
|
|
||||||
globalScene.unshiftPhase(
|
|
||||||
new PokemonHealPhase(
|
|
||||||
pokemon.getBattlerIndex(),
|
|
||||||
toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount,
|
|
||||||
i18next.t("modifier:turnHealApply", {
|
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
|
||||||
typeName: this.type.name,
|
|
||||||
}),
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifier used for held items, namely Toxic Orb and Flame Orb, that apply a
|
|
||||||
* set {@linkcode StatusEffect} at the end of a turn.
|
|
||||||
* @extends PokemonHeldItemModifier
|
|
||||||
* @see {@linkcode apply}
|
|
||||||
*/
|
|
||||||
export class TurnStatusEffectModifier extends PokemonHeldItemModifier {
|
|
||||||
/** The status effect to be applied by the held item */
|
|
||||||
private effect: StatusEffect;
|
|
||||||
|
|
||||||
constructor(type: ModifierType, pokemonId: number, stackCount?: number) {
|
|
||||||
super(type, pokemonId, stackCount);
|
|
||||||
|
|
||||||
switch (type.id) {
|
|
||||||
case "TOXIC_ORB":
|
|
||||||
this.effect = StatusEffect.TOXIC;
|
|
||||||
break;
|
|
||||||
case "FLAME_ORB":
|
|
||||||
this.effect = StatusEffect.BURN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if {@linkcode modifier} is an instance of this class,
|
|
||||||
* intentionally ignoring potentially different {@linkcode effect}s
|
|
||||||
* to prevent held item stockpiling since the item obtained first
|
|
||||||
* would be the only item able to {@linkcode apply} successfully.
|
|
||||||
* @override
|
|
||||||
* @param modifier {@linkcode Modifier} being type tested
|
|
||||||
* @return `true` if {@linkcode modifier} is an instance of
|
|
||||||
* TurnStatusEffectModifier, false otherwise
|
|
||||||
*/
|
|
||||||
matchType(modifier: Modifier): boolean {
|
|
||||||
return modifier instanceof TurnStatusEffectModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new TurnStatusEffectModifier(this.type, this.pokemonId, this.stackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to inflicts the holder with the associated {@linkcode StatusEffect}.
|
|
||||||
* @param pokemon {@linkcode Pokemon} that holds the held item
|
|
||||||
* @returns `true` if the status effect was applied successfully
|
|
||||||
*/
|
|
||||||
override apply(pokemon: Pokemon): boolean {
|
|
||||||
return pokemon.trySetStatus(this.effect, true, undefined, undefined, this.type.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
getStatusEffect(): StatusEffect {
|
|
||||||
return this.effect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HitHealModifier extends PokemonHeldItemModifier {
|
export class HitHealModifier extends PokemonHeldItemModifier {
|
||||||
matchType(modifier: Modifier) {
|
matchType(modifier: Modifier) {
|
||||||
return modifier instanceof HitHealModifier;
|
return modifier instanceof HitHealModifier;
|
||||||
|
@ -57,8 +57,6 @@ import {
|
|||||||
DamageMoneyRewardModifier,
|
DamageMoneyRewardModifier,
|
||||||
EnemyAttackStatusEffectChanceModifier,
|
EnemyAttackStatusEffectChanceModifier,
|
||||||
EnemyEndureChanceModifier,
|
EnemyEndureChanceModifier,
|
||||||
FlinchChanceModifier,
|
|
||||||
HitHealModifier,
|
|
||||||
PokemonMultiHitModifier,
|
PokemonMultiHitModifier,
|
||||||
} from "#app/modifier/modifier";
|
} from "#app/modifier/modifier";
|
||||||
import { PokemonPhase } from "#app/phases/pokemon-phase";
|
import { PokemonPhase } from "#app/phases/pokemon-phase";
|
||||||
@ -456,7 +454,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
|
|
||||||
if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && !this.move.hitsSubstitute(user, target)) {
|
if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && !this.move.hitsSubstitute(user, target)) {
|
||||||
const flinched = new BooleanHolder(false);
|
const flinched = new BooleanHolder(false);
|
||||||
globalScene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched);
|
applyHeldItems(ITEM_EFFECT.FLINCH_CHANCE, { pokemon: user, flinched: flinched });
|
||||||
if (flinched.value) {
|
if (flinched.value) {
|
||||||
target.addTag(BattlerTagType.FLINCHED, undefined, this.move.id, user.id);
|
target.addTag(BattlerTagType.FLINCHED, undefined, this.move.id, user.id);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import { getPokemonNameWithAffix } from "#app/messages";
|
|||||||
import {
|
import {
|
||||||
EnemyTurnHealModifier,
|
EnemyTurnHealModifier,
|
||||||
EnemyStatusEffectHealChanceModifier,
|
EnemyStatusEffectHealChanceModifier,
|
||||||
TurnStatusEffectModifier,
|
|
||||||
TurnHeldItemTransferModifier,
|
TurnHeldItemTransferModifier,
|
||||||
} from "#app/modifier/modifier";
|
} from "#app/modifier/modifier";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
@ -55,7 +54,7 @@ export class TurnEndPhase extends FieldPhase {
|
|||||||
applyPostTurnAbAttrs(PostTurnAbAttr, pokemon);
|
applyPostTurnAbAttrs(PostTurnAbAttr, pokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
globalScene.applyModifiers(TurnStatusEffectModifier, pokemon.isPlayer(), pokemon);
|
applyHeldItems(ITEM_EFFECT.TURN_END_STATUS, { pokemon: pokemon });
|
||||||
globalScene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon);
|
globalScene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon);
|
||||||
|
|
||||||
pokemon.tempSummonData.turnCount++;
|
pokemon.tempSummonData.turnCount++;
|
||||||
|
@ -5,7 +5,6 @@ import { AbilityId } from "#enums/ability-id";
|
|||||||
import { Stat } from "#app/enums/stat";
|
import { Stat } from "#app/enums/stat";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
import { BypassSpeedChanceModifier } from "#app/modifier/modifier";
|
|
||||||
import { Command } from "#app/ui/command-ui-handler";
|
import { Command } from "#app/ui/command-ui-handler";
|
||||||
import { randSeedShuffle, BooleanHolder } from "#app/utils/common";
|
import { randSeedShuffle, BooleanHolder } from "#app/utils/common";
|
||||||
import { AttemptCapturePhase } from "./attempt-capture-phase";
|
import { AttemptCapturePhase } from "./attempt-capture-phase";
|
||||||
@ -23,6 +22,8 @@ import { TrickRoomTag } from "#app/data/arena-tag";
|
|||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { TeraPhase } from "./tera-phase";
|
import { TeraPhase } from "./tera-phase";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
export class TurnStartPhase extends FieldPhase {
|
export class TurnStartPhase extends FieldPhase {
|
||||||
public readonly phaseName = "TurnStartPhase";
|
public readonly phaseName = "TurnStartPhase";
|
||||||
@ -80,7 +81,7 @@ export class TurnStartPhase extends FieldPhase {
|
|||||||
applyAbAttrs(BypassSpeedChanceAbAttr, p, null, false, bypassSpeed);
|
applyAbAttrs(BypassSpeedChanceAbAttr, p, null, false, bypassSpeed);
|
||||||
applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, false, bypassSpeed, canCheckHeldItems);
|
applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, false, bypassSpeed, canCheckHeldItems);
|
||||||
if (canCheckHeldItems.value) {
|
if (canCheckHeldItems.value) {
|
||||||
globalScene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed);
|
applyHeldItems(ITEM_EFFECT.BYPASS_SPEED_CHANCE, { pokemon: p, doBypassSpeed: bypassSpeed });
|
||||||
}
|
}
|
||||||
battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed;
|
battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed;
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user