mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-21 09:02:47 +02:00
Merge c992508dc3
into 4b70fab608
This commit is contained in:
commit
ca053c9e8c
@ -20,7 +20,7 @@ import {
|
|||||||
type Constructor,
|
type Constructor,
|
||||||
} from "#app/utils/common";
|
} from "#app/utils/common";
|
||||||
import { deepMergeSpriteData } from "#app/utils/data";
|
import { deepMergeSpriteData } from "#app/utils/data";
|
||||||
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
import type { Modifier, ModifierPredicate } from "./modifier/modifier";
|
||||||
import {
|
import {
|
||||||
ConsumableModifier,
|
ConsumableModifier,
|
||||||
ConsumablePokemonModifier,
|
ConsumablePokemonModifier,
|
||||||
@ -29,14 +29,9 @@ import {
|
|||||||
ExpShareModifier,
|
ExpShareModifier,
|
||||||
FusePokemonModifier,
|
FusePokemonModifier,
|
||||||
HealingBoosterModifier,
|
HealingBoosterModifier,
|
||||||
ModifierBar,
|
|
||||||
MultipleParticipantExpBonusModifier,
|
MultipleParticipantExpBonusModifier,
|
||||||
PersistentModifier,
|
PersistentModifier,
|
||||||
PokemonExpBoosterModifier,
|
|
||||||
PokemonFormChangeItemModifier,
|
|
||||||
PokemonHeldItemModifier,
|
|
||||||
PokemonHpRestoreModifier,
|
PokemonHpRestoreModifier,
|
||||||
PokemonIncrementingStatModifier,
|
|
||||||
RememberMoveModifier,
|
RememberMoveModifier,
|
||||||
} from "./modifier/modifier";
|
} from "./modifier/modifier";
|
||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
@ -56,16 +51,12 @@ import { allMoves } from "./data/data-lists";
|
|||||||
import { MusicPreference } from "#app/system/settings/settings";
|
import { MusicPreference } from "#app/system/settings/settings";
|
||||||
import {
|
import {
|
||||||
getDefaultModifierTypeForTier,
|
getDefaultModifierTypeForTier,
|
||||||
getEnemyModifierTypesForWave,
|
|
||||||
getLuckString,
|
getLuckString,
|
||||||
getLuckTextTint,
|
getLuckTextTint,
|
||||||
getPartyLuckValue,
|
getPartyLuckValue,
|
||||||
PokemonHeldItemModifierType,
|
|
||||||
} from "#app/modifier/modifier-type";
|
} from "#app/modifier/modifier-type";
|
||||||
import { getModifierType } from "./utils/modifier-utils";
|
|
||||||
import { modifierTypes } from "./data/data-lists";
|
|
||||||
import { getModifierPoolForType } from "./utils/modifier-utils";
|
import { getModifierPoolForType } from "./utils/modifier-utils";
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
import { HeldItemPoolType, ModifierPoolType } from "#enums/modifier-pool-type";
|
||||||
import AbilityBar from "#app/ui/ability-bar";
|
import AbilityBar from "#app/ui/ability-bar";
|
||||||
import { applyAbAttrs, applyPostBattleInitAbAttrs, applyPostItemLostAbAttrs } from "./data/abilities/apply-ab-attrs";
|
import { applyAbAttrs, applyPostBattleInitAbAttrs, applyPostItemLostAbAttrs } from "./data/abilities/apply-ab-attrs";
|
||||||
import { allAbilities } from "./data/data-lists";
|
import { allAbilities } from "./data/data-lists";
|
||||||
@ -88,7 +79,7 @@ import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
|||||||
import PokeballTray from "#app/ui/pokeball-tray";
|
import PokeballTray from "#app/ui/pokeball-tray";
|
||||||
import InvertPostFX from "#app/pipelines/invert";
|
import InvertPostFX from "#app/pipelines/invert";
|
||||||
import type { Achv } from "#app/system/achv";
|
import type { Achv } from "#app/system/achv";
|
||||||
import { achvs, ModifierAchv, MoneyAchv } from "#app/system/achv";
|
import { achvs, HeldItemAchv, ModifierAchv, MoneyAchv } from "#app/system/achv";
|
||||||
import type { Voucher } from "#app/system/voucher";
|
import type { Voucher } from "#app/system/voucher";
|
||||||
import { vouchers } from "#app/system/voucher";
|
import { vouchers } from "#app/system/voucher";
|
||||||
import { Gender } from "#app/data/gender";
|
import { Gender } from "#app/data/gender";
|
||||||
@ -101,6 +92,7 @@ import type { SpeciesFormChangeTrigger } from "./data/pokemon-forms/form-change-
|
|||||||
import { pokemonFormChanges } from "#app/data/pokemon-forms";
|
import { pokemonFormChanges } from "#app/data/pokemon-forms";
|
||||||
import { SpeciesFormChangeTimeOfDayTrigger } from "./data/pokemon-forms/form-change-triggers";
|
import { SpeciesFormChangeTimeOfDayTrigger } from "./data/pokemon-forms/form-change-triggers";
|
||||||
import { SpeciesFormChangeManualTrigger } from "./data/pokemon-forms/form-change-triggers";
|
import { SpeciesFormChangeManualTrigger } from "./data/pokemon-forms/form-change-triggers";
|
||||||
|
import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms/form-change-triggers";
|
||||||
import { FormChangeItem } from "#enums/form-change-item";
|
import { FormChangeItem } from "#enums/form-change-item";
|
||||||
import { getTypeRgb } from "#app/data/type";
|
import { getTypeRgb } from "#app/data/type";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
@ -148,7 +140,6 @@ import {
|
|||||||
import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
|
import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import type HeldModifierConfig from "#app/@types/held-modifier-config";
|
|
||||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||||
import { ExpGainsSpeed } from "#enums/exp-gains-speed";
|
import { ExpGainsSpeed } from "#enums/exp-gains-speed";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
@ -160,7 +151,13 @@ import { hasExpSprite } from "./sprites/sprite-utils";
|
|||||||
import { timedEventManager } from "./global-event-manager";
|
import { timedEventManager } from "./global-event-manager";
|
||||||
import { starterColors } from "./global-vars/starter-colors";
|
import { starterColors } from "./global-vars/starter-colors";
|
||||||
import { startingWave } from "./starting-wave";
|
import { startingWave } from "./starting-wave";
|
||||||
|
import { ModifierBar } from "./modifier/modifier-bar";
|
||||||
|
import { allHeldItems, applyHeldItems } from "./items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "./items/held-item";
|
||||||
import { PhaseManager } from "./phase-manager";
|
import { PhaseManager } from "./phase-manager";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { assignEnemyHeldItemsForWave, assignItemsFromConfiguration } from "./items/held-item-pool";
|
||||||
|
import type { HeldItemConfiguration } from "./items/held-item-data-types";
|
||||||
|
|
||||||
const DEBUG_RNG = false;
|
const DEBUG_RNG = false;
|
||||||
|
|
||||||
@ -909,6 +906,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
variant?: Variant,
|
variant?: Variant,
|
||||||
ivs?: number[],
|
ivs?: number[],
|
||||||
nature?: Nature,
|
nature?: Nature,
|
||||||
|
heldItemConfig?: HeldItemConfiguration,
|
||||||
dataSource?: Pokemon | PokemonData,
|
dataSource?: Pokemon | PokemonData,
|
||||||
postProcess?: (playerPokemon: PlayerPokemon) => void,
|
postProcess?: (playerPokemon: PlayerPokemon) => void,
|
||||||
): PlayerPokemon {
|
): PlayerPokemon {
|
||||||
@ -928,6 +926,9 @@ export default class BattleScene extends SceneBase {
|
|||||||
postProcess(pokemon);
|
postProcess(pokemon);
|
||||||
}
|
}
|
||||||
pokemon.init();
|
pokemon.init();
|
||||||
|
if (heldItemConfig) {
|
||||||
|
assignItemsFromConfiguration(heldItemConfig, pokemon);
|
||||||
|
}
|
||||||
return pokemon;
|
return pokemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -937,6 +938,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
trainerSlot: TrainerSlot,
|
trainerSlot: TrainerSlot,
|
||||||
boss = false,
|
boss = false,
|
||||||
shinyLock = false,
|
shinyLock = false,
|
||||||
|
heldItemConfig?: HeldItemConfiguration,
|
||||||
dataSource?: PokemonData,
|
dataSource?: PokemonData,
|
||||||
postProcess?: (enemyPokemon: EnemyPokemon) => void,
|
postProcess?: (enemyPokemon: EnemyPokemon) => void,
|
||||||
): EnemyPokemon {
|
): EnemyPokemon {
|
||||||
@ -978,6 +980,9 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pokemon.init();
|
pokemon.init();
|
||||||
|
if (heldItemConfig) {
|
||||||
|
assignItemsFromConfiguration(heldItemConfig, pokemon);
|
||||||
|
}
|
||||||
return pokemon;
|
return pokemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2053,7 +2058,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateUIPositions(): void {
|
updateUIPositions(): void {
|
||||||
const enemyModifierCount = this.enemyModifiers.filter(m => m.isIconVisible()).length;
|
const enemyModifierCount = this.enemyModifierBar.totalVisibleLength;
|
||||||
const biomeWaveTextHeight = this.biomeWaveText.getBottomLeft().y - this.biomeWaveText.getTopLeft().y;
|
const biomeWaveTextHeight = this.biomeWaveText.getBottomLeft().y - this.biomeWaveText.getTopLeft().y;
|
||||||
this.biomeWaveText.setY(
|
this.biomeWaveText.setY(
|
||||||
-(this.game.canvas.height / 6) +
|
-(this.game.canvas.height / 6) +
|
||||||
@ -2085,9 +2090,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
enemy.getSpeciesForm().getBaseExp() *
|
enemy.getSpeciesForm().getBaseExp() *
|
||||||
(enemy.level / this.getMaxExpLevel()) *
|
(enemy.level / this.getMaxExpLevel()) *
|
||||||
((enemy.ivs.reduce((iv: number, total: number) => (total += iv), 0) / 93) * 0.2 + 0.8);
|
((enemy.ivs.reduce((iv: number, total: number) => (total += iv), 0) / 93) * 0.2 + 0.8);
|
||||||
this.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemy.id, false).map(
|
enemy.getHeldItems().map(m => (scoreIncrease *= allHeldItems[m].getScoreMultiplier()));
|
||||||
m => (scoreIncrease *= (m as PokemonHeldItemModifier).getScoreMultiplier()),
|
|
||||||
);
|
|
||||||
if (enemy.isBoss()) {
|
if (enemy.isBoss()) {
|
||||||
scoreIncrease *= Math.sqrt(enemy.bossSegments);
|
scoreIncrease *= Math.sqrt(enemy.bossSegments);
|
||||||
}
|
}
|
||||||
@ -2618,15 +2621,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
let success = false;
|
let success = false;
|
||||||
const soundName = modifier.type.soundName;
|
const soundName = modifier.type.soundName;
|
||||||
this.validateAchvs(ModifierAchv, modifier);
|
this.validateAchvs(ModifierAchv, modifier);
|
||||||
const modifiersToRemove: PersistentModifier[] = [];
|
|
||||||
if (modifier instanceof PersistentModifier) {
|
if (modifier instanceof PersistentModifier) {
|
||||||
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual)) {
|
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual)) {
|
||||||
if (modifier instanceof PokemonFormChangeItemModifier) {
|
|
||||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
|
||||||
if (pokemon) {
|
|
||||||
success = modifier.apply(pokemon, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (playSound && !this.sound.get(soundName)) {
|
if (playSound && !this.sound.get(soundName)) {
|
||||||
this.playSound(soundName);
|
this.playSound(soundName);
|
||||||
}
|
}
|
||||||
@ -2644,12 +2640,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant);
|
return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const rm of modifiersToRemove) {
|
|
||||||
this.removeModifier(rm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ignoreUpdate && !virtual) {
|
if (!ignoreUpdate && !virtual) {
|
||||||
this.updateModifiers(true, instant);
|
this.updateModifiers(true);
|
||||||
}
|
}
|
||||||
} else if (modifier instanceof ConsumableModifier) {
|
} else if (modifier instanceof ConsumableModifier) {
|
||||||
if (playSound && !this.sound.get(soundName)) {
|
if (playSound && !this.sound.get(soundName)) {
|
||||||
@ -2693,35 +2685,51 @@ export default class BattleScene extends SceneBase {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
addEnemyModifier(modifier: PersistentModifier, ignoreUpdate?: boolean, instant?: boolean): Promise<void> {
|
addEnemyModifier(modifier: PersistentModifier, ignoreUpdate?: boolean) {
|
||||||
return new Promise(resolve => {
|
(modifier as PersistentModifier).add(this.enemyModifiers, false);
|
||||||
const modifiersToRemove: PersistentModifier[] = [];
|
if (!ignoreUpdate) {
|
||||||
if ((modifier as PersistentModifier).add(this.enemyModifiers, false)) {
|
this.updateModifiers(false);
|
||||||
if (modifier instanceof PokemonFormChangeItemModifier) {
|
}
|
||||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
}
|
||||||
if (pokemon) {
|
|
||||||
modifier.apply(pokemon, true);
|
addHeldItem(heldItemId: HeldItemId, pokemon: Pokemon, amount = 1, playSound?: boolean, ignoreUpdate?: boolean) {
|
||||||
}
|
pokemon.heldItemManager.add(heldItemId, amount);
|
||||||
}
|
if (!ignoreUpdate) {
|
||||||
for (const rm of modifiersToRemove) {
|
this.updateModifiers(pokemon.isPlayer());
|
||||||
this.removeModifier(rm, true);
|
}
|
||||||
}
|
const soundName = allHeldItems[heldItemId].soundName;
|
||||||
}
|
if (playSound && !this.sound.get(soundName)) {
|
||||||
if (!ignoreUpdate) {
|
this.playSound(soundName);
|
||||||
this.updateModifiers(false, instant);
|
}
|
||||||
resolve();
|
|
||||||
} else {
|
if (pokemon.isPlayer()) {
|
||||||
resolve();
|
this.validateAchvs(HeldItemAchv, pokemon);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
addFormChangeItem(itemId: FormChangeItem, pokemon: Pokemon, ignoreUpdate?: boolean) {
|
||||||
|
if (pokemon.heldItemManager.hasFormChangeItem(itemId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pokemon.heldItemManager.addFormChangeItem(itemId);
|
||||||
|
|
||||||
|
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeItemTrigger);
|
||||||
|
|
||||||
|
pokemon.heldItemManager.toggleActive(itemId);
|
||||||
|
|
||||||
|
if (!ignoreUpdate) {
|
||||||
|
this.updateModifiers(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to transfer a held item to another pokemon.
|
* Try to transfer a held item from source to target.
|
||||||
* If the recepient already has the maximum amount allowed for this item, the transfer is cancelled.
|
* If the recepient already has the maximum amount allowed for this item, the transfer is cancelled.
|
||||||
* The quantity to transfer is automatically capped at how much the recepient can take before reaching the maximum stack size for the item.
|
* The quantity to transfer is automatically capped at how much the recepient can take before reaching the maximum stack size for the item.
|
||||||
* A transfer that moves a quantity smaller than what is specified in the transferQuantity parameter is still considered successful.
|
* A transfer that moves a quantity smaller than what is specified in the transferQuantity parameter is still considered successful.
|
||||||
* @param itemModifier {@linkcode PokemonHeldItemModifier} item to transfer (represents the whole stack)
|
* @param heldItemId {@linkcode HeldItemId} item to transfer
|
||||||
|
* @param source {@linkcode Pokemon} giver in this transfer
|
||||||
* @param target {@linkcode Pokemon} recepient in this transfer
|
* @param target {@linkcode Pokemon} recepient in this transfer
|
||||||
* @param playSound `true` to play a sound when transferring the item
|
* @param playSound `true` to play a sound when transferring the item
|
||||||
* @param transferQuantity How many items of the stack to transfer. Optional, defaults to `1`
|
* @param transferQuantity How many items of the stack to transfer. Optional, defaults to `1`
|
||||||
@ -2730,16 +2738,15 @@ export default class BattleScene extends SceneBase {
|
|||||||
* @param itemLost If `true`, treat the item's current holder as losing the item (for now, this simply enables Unburden). Default is `true`.
|
* @param itemLost If `true`, treat the item's current holder as losing the item (for now, this simply enables Unburden). Default is `true`.
|
||||||
* @returns `true` if the transfer was successful
|
* @returns `true` if the transfer was successful
|
||||||
*/
|
*/
|
||||||
tryTransferHeldItemModifier(
|
tryTransferHeldItem(
|
||||||
itemModifier: PokemonHeldItemModifier,
|
heldItemId: HeldItemId,
|
||||||
|
source: Pokemon,
|
||||||
target: Pokemon,
|
target: Pokemon,
|
||||||
playSound: boolean,
|
playSound: boolean,
|
||||||
transferQuantity = 1,
|
transferQuantity = 1,
|
||||||
instant?: boolean,
|
|
||||||
ignoreUpdate?: boolean,
|
ignoreUpdate?: boolean,
|
||||||
itemLost = true,
|
itemLost = true,
|
||||||
): boolean {
|
): boolean {
|
||||||
const source = itemModifier.pokemonId ? itemModifier.getPokemon() : null;
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
|
|
||||||
if (source && source.isPlayer() !== target.isPlayer()) {
|
if (source && source.isPlayer() !== target.isPlayer()) {
|
||||||
@ -2750,65 +2757,39 @@ export default class BattleScene extends SceneBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier;
|
const itemStack = source.heldItemManager.getStack(heldItemId);
|
||||||
newItemModifier.pokemonId = target.id;
|
const matchingItemStack = target.heldItemManager.getStack(heldItemId);
|
||||||
const matchingModifier = this.findModifier(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.matchType(itemModifier) && m.pokemonId === target.id,
|
|
||||||
target.isPlayer(),
|
|
||||||
) as PokemonHeldItemModifier;
|
|
||||||
|
|
||||||
if (matchingModifier) {
|
const maxStackCount = allHeldItems[heldItemId].getMaxStackCount();
|
||||||
const maxStackCount = matchingModifier.getMaxStackCount();
|
if (matchingItemStack >= maxStackCount) {
|
||||||
if (matchingModifier.stackCount >= maxStackCount) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
const countTaken = Math.min(transferQuantity, itemStack, maxStackCount - matchingItemStack);
|
||||||
const countTaken = Math.min(
|
|
||||||
transferQuantity,
|
const itemSpecs = source.heldItemManager.getItemSpecs(heldItemId);
|
||||||
itemModifier.stackCount,
|
if (!itemSpecs) {
|
||||||
maxStackCount - matchingModifier.stackCount,
|
return false;
|
||||||
);
|
}
|
||||||
itemModifier.stackCount -= countTaken;
|
source.heldItemManager.remove(heldItemId, countTaken);
|
||||||
newItemModifier.stackCount = matchingModifier.stackCount + countTaken;
|
target.heldItemManager.add(itemSpecs);
|
||||||
} else {
|
|
||||||
const countTaken = Math.min(transferQuantity, itemModifier.stackCount);
|
if (source.heldItemManager.getStack(heldItemId) === 0 && itemLost) {
|
||||||
itemModifier.stackCount -= countTaken;
|
applyPostItemLostAbAttrs("PostItemLostAbAttr", source, false);
|
||||||
newItemModifier.stackCount = countTaken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeOld = itemModifier.stackCount === 0;
|
if (source.isPlayer() !== target.isPlayer() && !ignoreUpdate) {
|
||||||
|
this.updateModifiers(source.isPlayer());
|
||||||
if (!removeOld || !source || this.removeModifier(itemModifier, source.isEnemy())) {
|
|
||||||
const addModifier = () => {
|
|
||||||
if (!matchingModifier || this.removeModifier(matchingModifier, target.isEnemy())) {
|
|
||||||
if (target.isPlayer()) {
|
|
||||||
this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant);
|
|
||||||
if (source && itemLost) {
|
|
||||||
applyPostItemLostAbAttrs("PostItemLostAbAttr", source, false);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
this.addEnemyModifier(newItemModifier, ignoreUpdate, instant);
|
|
||||||
if (source && itemLost) {
|
|
||||||
applyPostItemLostAbAttrs("PostItemLostAbAttr", source, false);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
if (source && source.isPlayer() !== target.isPlayer() && !ignoreUpdate) {
|
|
||||||
this.updateModifiers(source.isPlayer(), instant);
|
|
||||||
addModifier();
|
|
||||||
} else {
|
|
||||||
addModifier();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
const soundName = allHeldItems[heldItemId].soundName;
|
||||||
|
if (playSound && !this.sound.get(soundName)) {
|
||||||
|
this.playSound(soundName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean {
|
canTransferHeldItem(heldItemId: HeldItemId, source: Pokemon, target: Pokemon, transferQuantity = 1): boolean {
|
||||||
const mod = itemModifier.clone() as PokemonHeldItemModifier;
|
|
||||||
const source = mod.pokemonId ? mod.getPokemon() : null;
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
|
|
||||||
if (source && source.isPlayer() !== target.isPlayer()) {
|
if (source && source.isPlayer() !== target.isPlayer()) {
|
||||||
@ -2819,43 +2800,19 @@ export default class BattleScene extends SceneBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const matchingModifier = this.findModifier(
|
const itemStack = source.heldItemManager.getStack(heldItemId);
|
||||||
m => m instanceof PokemonHeldItemModifier && m.matchType(mod) && m.pokemonId === target.id,
|
const matchingItemStack = target.heldItemManager.getStack(heldItemId);
|
||||||
target.isPlayer(),
|
|
||||||
) as PokemonHeldItemModifier;
|
|
||||||
|
|
||||||
if (matchingModifier) {
|
const maxStackCount = allHeldItems[heldItemId].getMaxStackCount();
|
||||||
const maxStackCount = matchingModifier.getMaxStackCount();
|
if (matchingItemStack >= maxStackCount) {
|
||||||
if (matchingModifier.stackCount >= maxStackCount) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const countTaken = Math.min(transferQuantity, mod.stackCount, maxStackCount - matchingModifier.stackCount);
|
|
||||||
mod.stackCount -= countTaken;
|
|
||||||
} else {
|
|
||||||
const countTaken = Math.min(transferQuantity, mod.stackCount);
|
|
||||||
mod.stackCount -= countTaken;
|
|
||||||
}
|
}
|
||||||
|
const countTaken = Math.min(transferQuantity, itemStack, maxStackCount - matchingItemStack);
|
||||||
|
|
||||||
const removeOld = mod.stackCount === 0;
|
return countTaken > 0;
|
||||||
|
|
||||||
return !removeOld || !source || this.hasModifier(itemModifier, !source.isPlayer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removePartyMemberModifiers(partyMemberIndex: number): Promise<void> {
|
generateEnemyModifiers(heldItemConfigs?: HeldItemConfiguration[]): Promise<void> {
|
||||||
return new Promise(resolve => {
|
|
||||||
const pokemonId = this.getPlayerParty()[partyMemberIndex].id;
|
|
||||||
const modifiersToRemove = this.modifiers.filter(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === pokemonId,
|
|
||||||
);
|
|
||||||
for (const m of modifiersToRemove) {
|
|
||||||
this.modifiers.splice(this.modifiers.indexOf(m), 1);
|
|
||||||
}
|
|
||||||
this.updateModifiers();
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
generateEnemyModifiers(heldModifiersConfigs?: HeldModifierConfig[][]): Promise<void> {
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
|
if (this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
|
||||||
return resolve();
|
return resolve();
|
||||||
@ -2872,24 +2829,13 @@ export default class BattleScene extends SceneBase {
|
|||||||
if (this.currentBattle.trainer) {
|
if (this.currentBattle.trainer) {
|
||||||
const modifiers = this.currentBattle.trainer.genModifiers(party);
|
const modifiers = this.currentBattle.trainer.genModifiers(party);
|
||||||
for (const modifier of modifiers) {
|
for (const modifier of modifiers) {
|
||||||
this.addEnemyModifier(modifier, true, true);
|
this.addEnemyModifier(modifier, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
party.forEach((enemyPokemon: EnemyPokemon, i: number) => {
|
party.forEach((enemyPokemon: EnemyPokemon, i: number) => {
|
||||||
if (heldModifiersConfigs && i < heldModifiersConfigs.length && heldModifiersConfigs[i]) {
|
if (heldItemConfigs && i < heldItemConfigs.length && heldItemConfigs[i]) {
|
||||||
for (const mt of heldModifiersConfigs[i]) {
|
assignItemsFromConfiguration(heldItemConfigs[i], enemyPokemon);
|
||||||
let modifier: PokemonHeldItemModifier;
|
|
||||||
if (mt.modifier instanceof PokemonHeldItemModifierType) {
|
|
||||||
modifier = mt.modifier.newModifier(enemyPokemon);
|
|
||||||
} else {
|
|
||||||
modifier = mt.modifier as PokemonHeldItemModifier;
|
|
||||||
modifier.pokemonId = enemyPokemon.id;
|
|
||||||
}
|
|
||||||
modifier.stackCount = mt.stackCount ?? 1;
|
|
||||||
modifier.isTransferable = mt.isTransferable ?? modifier.isTransferable;
|
|
||||||
this.addEnemyModifier(modifier, true);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const isBoss =
|
const isBoss =
|
||||||
enemyPokemon.isBoss() ||
|
enemyPokemon.isBoss() ||
|
||||||
@ -2910,13 +2856,13 @@ export default class BattleScene extends SceneBase {
|
|||||||
if (isBoss) {
|
if (isBoss) {
|
||||||
count = Math.max(count, Math.floor(chances / 2));
|
count = Math.max(count, Math.floor(chances / 2));
|
||||||
}
|
}
|
||||||
getEnemyModifierTypesForWave(
|
assignEnemyHeldItemsForWave(
|
||||||
difficultyWaveIndex,
|
difficultyWaveIndex,
|
||||||
count,
|
count,
|
||||||
[enemyPokemon],
|
enemyPokemon,
|
||||||
this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD,
|
this.currentBattle.battleType === BattleType.TRAINER ? HeldItemPoolType.TRAINER : HeldItemPoolType.WILD,
|
||||||
upgradeChance,
|
upgradeChance,
|
||||||
).map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false));
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -2937,50 +2883,21 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.updateUIPositions();
|
this.updateUIPositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all modifiers from enemy pokemon of {@linkcode PokemonHeldItemModifier} type
|
|
||||||
* @param pokemon - If specified, only removes held items from that {@linkcode Pokemon}
|
|
||||||
*/
|
|
||||||
clearEnemyHeldItemModifiers(pokemon?: Pokemon): void {
|
|
||||||
const modifiersToRemove = this.enemyModifiers.filter(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && (!pokemon || m.getPokemon() === pokemon),
|
|
||||||
);
|
|
||||||
for (const m of modifiersToRemove) {
|
|
||||||
this.enemyModifiers.splice(this.enemyModifiers.indexOf(m), 1);
|
|
||||||
}
|
|
||||||
this.updateModifiers(false);
|
|
||||||
this.updateUIPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
setModifiersVisible(visible: boolean) {
|
setModifiersVisible(visible: boolean) {
|
||||||
[this.modifierBar, this.enemyModifierBar].map(m => m.setVisible(visible));
|
[this.modifierBar, this.enemyModifierBar].map(m => m.setVisible(visible));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Document this
|
// TODO: Document this
|
||||||
updateModifiers(player = true, instant?: boolean): void {
|
updateModifiers(player = true, showHeldItems = true): void {
|
||||||
const modifiers = player ? this.modifiers : (this.enemyModifiers as PersistentModifier[]);
|
const modifiers = player ? this.modifiers : (this.enemyModifiers as PersistentModifier[]);
|
||||||
for (let m = 0; m < modifiers.length; m++) {
|
|
||||||
const modifier = modifiers[m];
|
|
||||||
if (
|
|
||||||
modifier instanceof PokemonHeldItemModifier &&
|
|
||||||
!this.getPokemonById((modifier as PokemonHeldItemModifier).pokemonId)
|
|
||||||
) {
|
|
||||||
modifiers.splice(m--, 1);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
modifier instanceof PokemonHeldItemModifier &&
|
|
||||||
!isNullOrUndefined(modifier.getSpecies()) &&
|
|
||||||
!this.getPokemonById(modifier.pokemonId)?.hasSpecies(modifier.getSpecies()!)
|
|
||||||
) {
|
|
||||||
modifiers.splice(m--, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const modifier of modifiers) {
|
for (const modifier of modifiers) {
|
||||||
if (modifier instanceof PersistentModifier) {
|
if (modifier instanceof PersistentModifier) {
|
||||||
(modifier as PersistentModifier).virtualStackCount = 0;
|
(modifier as PersistentModifier).virtualStackCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Removing modifiers with a stack count of 0, if they somehow got to this point
|
||||||
const modifiersClone = modifiers.slice(0);
|
const modifiersClone = modifiers.slice(0);
|
||||||
for (const modifier of modifiersClone) {
|
for (const modifier of modifiersClone) {
|
||||||
if (!modifier.getStackCount()) {
|
if (!modifier.getStackCount()) {
|
||||||
@ -2988,14 +2905,24 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updatePartyForModifiers(player ? this.getPlayerParty() : this.getEnemyParty(), instant);
|
this.updateParty(player ? this.getPlayerParty() : this.getEnemyParty(), true);
|
||||||
(player ? this.modifierBar : this.enemyModifierBar).updateModifiers(modifiers);
|
|
||||||
|
const pokemonA = player ? this.getPlayerParty()[0] : this.getEnemyParty()[0];
|
||||||
|
|
||||||
|
const bar = player ? this.modifierBar : this.enemyModifierBar;
|
||||||
|
|
||||||
|
if (showHeldItems) {
|
||||||
|
bar.updateModifiers(modifiers, pokemonA);
|
||||||
|
} else {
|
||||||
|
bar.updateModifiers(modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
if (!player) {
|
if (!player) {
|
||||||
this.updateUIPositions();
|
this.updateUIPositions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePartyForModifiers(party: Pokemon[], instant?: boolean): Promise<void> {
|
updateParty(party: Pokemon[], instant?: boolean): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
Promise.allSettled(
|
Promise.allSettled(
|
||||||
party.map(p => {
|
party.map(p => {
|
||||||
@ -3024,12 +2951,6 @@ export default class BattleScene extends SceneBase {
|
|||||||
const modifierIndex = modifiers.indexOf(modifier);
|
const modifierIndex = modifiers.indexOf(modifier);
|
||||||
if (modifierIndex > -1) {
|
if (modifierIndex > -1) {
|
||||||
modifiers.splice(modifierIndex, 1);
|
modifiers.splice(modifierIndex, 1);
|
||||||
if (modifier instanceof PokemonFormChangeItemModifier) {
|
|
||||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
|
||||||
if (pokemon) {
|
|
||||||
modifier.apply(pokemon, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3172,22 +3093,17 @@ export default class BattleScene extends SceneBase {
|
|||||||
let matchingFormChange: SpeciesFormChange | null;
|
let matchingFormChange: SpeciesFormChange | null;
|
||||||
if (pokemon.species.speciesId === SpeciesId.NECROZMA && matchingFormChangeOpts.length > 1) {
|
if (pokemon.species.speciesId === SpeciesId.NECROZMA && matchingFormChangeOpts.length > 1) {
|
||||||
// Ultra Necrozma is changing its form back, so we need to figure out into which form it devolves.
|
// Ultra Necrozma is changing its form back, so we need to figure out into which form it devolves.
|
||||||
const formChangeItemModifiers = (
|
const activeFormChangeItems = pokemon.heldItemManager.getActiveFormChangeItems();
|
||||||
this.findModifiers(
|
|
||||||
m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id,
|
|
||||||
) as PokemonFormChangeItemModifier[]
|
|
||||||
)
|
|
||||||
.filter(m => m.active)
|
|
||||||
.map(m => m.formChangeItem);
|
|
||||||
|
|
||||||
matchingFormChange = formChangeItemModifiers.includes(FormChangeItem.N_LUNARIZER)
|
matchingFormChange = activeFormChangeItems.includes(FormChangeItem.N_LUNARIZER)
|
||||||
? matchingFormChangeOpts[0]
|
? matchingFormChangeOpts[0]
|
||||||
: formChangeItemModifiers.includes(FormChangeItem.N_SOLARIZER)
|
: activeFormChangeItems.includes(FormChangeItem.N_SOLARIZER)
|
||||||
? matchingFormChangeOpts[1]
|
? matchingFormChangeOpts[1]
|
||||||
: null;
|
: null;
|
||||||
} else {
|
} else {
|
||||||
matchingFormChange = matchingFormChangeOpts[0];
|
matchingFormChange = matchingFormChangeOpts[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchingFormChange) {
|
if (matchingFormChange) {
|
||||||
let phase: Phase;
|
let phase: Phase;
|
||||||
if (pokemon.isPlayer() && !matchingFormChange.quiet) {
|
if (pokemon.isPlayer() && !matchingFormChange.quiet) {
|
||||||
@ -3317,11 +3233,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
pokemon.species.name,
|
pokemon.species.name,
|
||||||
undefined,
|
undefined,
|
||||||
() => {
|
() => {
|
||||||
const finalBossMBH = getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(
|
pokemon.heldItemManager.add(HeldItemId.MINI_BLACK_HOLE);
|
||||||
pokemon,
|
|
||||||
) as TurnHeldItemTransferModifier;
|
|
||||||
finalBossMBH.setTransferrableFalse();
|
|
||||||
this.addEnemyModifier(finalBossMBH, false, true);
|
|
||||||
pokemon.generateAndPopulateMoveset(1);
|
pokemon.generateAndPopulateMoveset(1);
|
||||||
this.setFieldScale(0.75);
|
this.setFieldScale(0.75);
|
||||||
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
|
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
|
||||||
@ -3385,10 +3297,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
const participated = participantIds.has(pId);
|
const participated = participantIds.has(pId);
|
||||||
if (participated && pokemonDefeated) {
|
if (participated && pokemonDefeated) {
|
||||||
partyMember.addFriendship(FRIENDSHIP_GAIN_FROM_BATTLE);
|
partyMember.addFriendship(FRIENDSHIP_GAIN_FROM_BATTLE);
|
||||||
const machoBraceModifier = partyMember.getHeldItems().find(m => m instanceof PokemonIncrementingStatModifier);
|
const hasMachoBrace = partyMember.heldItemManager.hasItem(HeldItemId.MACHO_BRACE);
|
||||||
if (machoBraceModifier && machoBraceModifier.stackCount < machoBraceModifier.getMaxStackCount()) {
|
if (hasMachoBrace) {
|
||||||
machoBraceModifier.stackCount++;
|
partyMember.heldItemManager.add(HeldItemId.MACHO_BRACE);
|
||||||
this.updateModifiers(true, true);
|
this.updateModifiers(true);
|
||||||
partyMember.updateInfo();
|
partyMember.updateInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3415,7 +3327,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE;
|
expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE;
|
||||||
}
|
}
|
||||||
const pokemonExp = new NumberHolder(expValue * expMultiplier);
|
const pokemonExp = new NumberHolder(expValue * expMultiplier);
|
||||||
this.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp);
|
applyHeldItems(ITEM_EFFECT.EXP_BOOSTER, { pokemon: partyMember, expAmount: pokemonExp });
|
||||||
partyMemberExp.push(Math.floor(pokemonExp.value));
|
partyMemberExp.push(Math.floor(pokemonExp.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
import Trainer from "./field/trainer";
|
import Trainer from "./field/trainer";
|
||||||
import { TrainerVariant } from "#enums/trainer-variant";
|
import { TrainerVariant } from "#enums/trainer-variant";
|
||||||
import type { GameMode } from "./game-mode";
|
import type { GameMode } from "./game-mode";
|
||||||
import { MoneyMultiplierModifier, type PokemonHeldItemModifier } from "./modifier/modifier";
|
import { MoneyMultiplierModifier } from "./modifier/modifier";
|
||||||
import type { PokeballType } from "#enums/pokeball";
|
import type { PokeballType } from "#enums/pokeball";
|
||||||
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
||||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||||
@ -30,10 +30,11 @@ import i18next from "#app/plugins/i18n";
|
|||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||||
import type { CustomModifierSettings } from "#app/modifier/modifier-type";
|
import type { CustomModifierSettings } from "#app/modifier/modifier-type";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { BattleType } from "#enums/battle-type";
|
import { BattleType } from "#enums/battle-type";
|
||||||
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
import { BattlerIndex } from "#enums/battler-index";
|
import { BattlerIndex } from "#enums/battler-index";
|
||||||
|
|
||||||
export interface TurnCommand {
|
export interface TurnCommand {
|
||||||
@ -71,7 +72,7 @@ export default class Battle {
|
|||||||
public turnCommands: TurnCommands;
|
public turnCommands: TurnCommands;
|
||||||
public playerParticipantIds: Set<number> = new Set<number>();
|
public playerParticipantIds: Set<number> = new Set<number>();
|
||||||
public battleScore = 0;
|
public battleScore = 0;
|
||||||
public postBattleLoot: PokemonHeldItemModifier[] = [];
|
public postBattleLoot: HeldItemId[] = [];
|
||||||
public escapeAttempts = 0;
|
public escapeAttempts = 0;
|
||||||
public lastMove: MoveId;
|
public lastMove: MoveId;
|
||||||
public battleSeed: string = randomString(16, true);
|
public battleSeed: string = randomString(16, true);
|
||||||
@ -170,19 +171,7 @@ export default class Battle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
|
addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
|
||||||
this.postBattleLoot.push(
|
this.postBattleLoot.push(...enemyPokemon.getHeldItems());
|
||||||
...globalScene
|
|
||||||
.findModifiers(
|
|
||||||
m => m.is("PokemonHeldItemModifier") && m.pokemonId === enemyPokemon.id && m.isTransferable,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map(i => {
|
|
||||||
const ret = i as PokemonHeldItemModifier;
|
|
||||||
//@ts-ignore - this is awful to fix/change
|
|
||||||
ret.pokemonId = null;
|
|
||||||
return ret;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pickUpScatteredMoney(): void {
|
pickUpScatteredMoney(): void {
|
||||||
@ -604,7 +593,7 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
|
guaranteedModifierTiers: [RewardTier.ULTRA, RewardTier.GREAT, RewardTier.GREAT],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
}),
|
}),
|
||||||
[ClassicFixedBossWaves.EVIL_GRUNT_1]: new FixedBattleConfig()
|
[ClassicFixedBossWaves.EVIL_GRUNT_1]: new FixedBattleConfig()
|
||||||
@ -636,7 +625,7 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
|
guaranteedModifierTiers: [RewardTier.ULTRA, RewardTier.ULTRA, RewardTier.GREAT, RewardTier.GREAT],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
}),
|
}),
|
||||||
[ClassicFixedBossWaves.EVIL_GRUNT_2]: new FixedBattleConfig()
|
[ClassicFixedBossWaves.EVIL_GRUNT_2]: new FixedBattleConfig()
|
||||||
@ -709,7 +698,7 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA],
|
guaranteedModifierTiers: [RewardTier.ULTRA, RewardTier.ULTRA, RewardTier.ULTRA, RewardTier.ULTRA],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
}),
|
}),
|
||||||
[ClassicFixedBossWaves.EVIL_GRUNT_4]: new FixedBattleConfig()
|
[ClassicFixedBossWaves.EVIL_GRUNT_4]: new FixedBattleConfig()
|
||||||
@ -772,11 +761,11 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
)
|
)
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [
|
guaranteedModifierTiers: [
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
],
|
],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
}),
|
}),
|
||||||
@ -791,11 +780,11 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
)
|
)
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [
|
guaranteedModifierTiers: [
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
],
|
],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
}),
|
}),
|
||||||
@ -818,12 +807,12 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
)
|
)
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [
|
guaranteedModifierTiers: [
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
],
|
],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
}),
|
}),
|
||||||
@ -922,12 +911,12 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
)
|
)
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [
|
guaranteedModifierTiers: [
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.GREAT,
|
RewardTier.GREAT,
|
||||||
ModifierTier.GREAT,
|
RewardTier.GREAT,
|
||||||
],
|
],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
}),
|
}),
|
||||||
|
@ -22,7 +22,6 @@ import { Gender } from "#app/data/gender";
|
|||||||
import { applyMoveAttrs } from "../moves/apply-attrs";
|
import { applyMoveAttrs } from "../moves/apply-attrs";
|
||||||
import { allMoves } from "../data-lists";
|
import { allMoves } from "../data-lists";
|
||||||
import { ArenaTagSide } from "#enums/arena-tag-side";
|
import { ArenaTagSide } from "#enums/arena-tag-side";
|
||||||
import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { TerrainType } from "#app/data/terrain";
|
import { TerrainType } from "#app/data/terrain";
|
||||||
import { pokemonFormChanges } from "../pokemon-forms";
|
import { pokemonFormChanges } from "../pokemon-forms";
|
||||||
import {
|
import {
|
||||||
@ -31,7 +30,6 @@ import {
|
|||||||
} from "../pokemon-forms/form-change-triggers";
|
} from "../pokemon-forms/form-change-triggers";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { Command } from "#enums/command";
|
import { Command } from "#enums/command";
|
||||||
import { BerryModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { getPokeballName } from "#app/data/pokeball";
|
import { getPokeballName } from "#app/data/pokeball";
|
||||||
import { BattleType } from "#enums/battle-type";
|
import { BattleType } from "#enums/battle-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -79,6 +77,9 @@ import type { BattlerIndex } from "#enums/battler-index";
|
|||||||
import type Move from "#app/data/moves/move";
|
import type Move from "#app/data/moves/move";
|
||||||
import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag";
|
import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag";
|
||||||
import type { Constructor } from "#app/utils/common";
|
import type { Constructor } from "#app/utils/common";
|
||||||
|
import { HeldItemCategoryId, HeldItemId, isItemInCategory } from "#enums/held-item-id";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { berryTypeToHeldItem } from "#app/items/held-items/berry";
|
||||||
import type { Localizable } from "#app/@types/locales";
|
import type { Localizable } from "#app/@types/locales";
|
||||||
import { applyAbAttrs } from "./apply-ab-attrs";
|
import { applyAbAttrs } from "./apply-ab-attrs";
|
||||||
|
|
||||||
@ -2759,7 +2760,7 @@ export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr {
|
|||||||
|
|
||||||
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
||||||
private stealCondition: PokemonAttackCondition | null;
|
private stealCondition: PokemonAttackCondition | null;
|
||||||
private stolenItem?: PokemonHeldItemModifier;
|
private stolenItem?: HeldItemId;
|
||||||
|
|
||||||
constructor(stealCondition?: PokemonAttackCondition) {
|
constructor(stealCondition?: PokemonAttackCondition) {
|
||||||
super();
|
super();
|
||||||
@ -2782,11 +2783,11 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
|||||||
hitResult < HitResult.NO_EFFECT &&
|
hitResult < HitResult.NO_EFFECT &&
|
||||||
(!this.stealCondition || this.stealCondition(pokemon, defender, move))
|
(!this.stealCondition || this.stealCondition(pokemon, defender, move))
|
||||||
) {
|
) {
|
||||||
const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferable);
|
const heldItems = defender.heldItemManager.getTransferableHeldItems();
|
||||||
if (heldItems.length) {
|
if (heldItems.length) {
|
||||||
// Ensure that the stolen item in testing is the same as when the effect is applied
|
// Ensure that the stolen item in testing is the same as when the effect is applied
|
||||||
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
||||||
if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) {
|
if (globalScene.canTransferHeldItem(this.stolenItem, defender, pokemon)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2804,28 +2805,21 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
|||||||
_hitResult: HitResult,
|
_hitResult: HitResult,
|
||||||
_args: any[],
|
_args: any[],
|
||||||
): void {
|
): void {
|
||||||
const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferable);
|
const heldItems = defender.heldItemManager.getTransferableHeldItems();
|
||||||
if (!this.stolenItem) {
|
if (!this.stolenItem) {
|
||||||
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
||||||
}
|
}
|
||||||
if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) {
|
if (globalScene.tryTransferHeldItem(this.stolenItem, defender, pokemon, false)) {
|
||||||
globalScene.phaseManager.queueMessage(
|
globalScene.phaseManager.queueMessage(
|
||||||
i18next.t("abilityTriggers:postAttackStealHeldItem", {
|
i18next.t("abilityTriggers:postAttackStealHeldItem", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
defenderName: defender.name,
|
defenderName: defender.name,
|
||||||
stolenItemType: this.stolenItem.type.name,
|
stolenItemType: allHeldItems[this.stolenItem].name,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.stolenItem = undefined;
|
this.stolenItem = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
|
|
||||||
return globalScene.findModifiers(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === target.id,
|
|
||||||
target.isPlayer(),
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
||||||
@ -2946,7 +2940,7 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
|
|||||||
|
|
||||||
export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
||||||
private condition?: PokemonDefendCondition;
|
private condition?: PokemonDefendCondition;
|
||||||
private stolenItem?: PokemonHeldItemModifier;
|
private stolenItem?: HeldItemId;
|
||||||
|
|
||||||
constructor(condition?: PokemonDefendCondition) {
|
constructor(condition?: PokemonDefendCondition) {
|
||||||
super();
|
super();
|
||||||
@ -2964,10 +2958,10 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
|||||||
_args: any[],
|
_args: any[],
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!simulated && hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move))) {
|
if (!simulated && hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move))) {
|
||||||
const heldItems = this.getTargetHeldItems(attacker).filter(i => i.isTransferable);
|
const heldItems = attacker.heldItemManager.getTransferableHeldItems();
|
||||||
if (heldItems.length) {
|
if (heldItems.length) {
|
||||||
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
||||||
if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) {
|
if (globalScene.canTransferHeldItem(this.stolenItem, attacker, pokemon)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2984,28 +2978,21 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
|||||||
_hitResult: HitResult,
|
_hitResult: HitResult,
|
||||||
_args: any[],
|
_args: any[],
|
||||||
): void {
|
): void {
|
||||||
const heldItems = this.getTargetHeldItems(attacker).filter(i => i.isTransferable);
|
const heldItems = attacker.heldItemManager.getTransferableHeldItems();
|
||||||
if (!this.stolenItem) {
|
if (!this.stolenItem) {
|
||||||
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
|
||||||
}
|
}
|
||||||
if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) {
|
if (globalScene.tryTransferHeldItem(this.stolenItem, attacker, pokemon, false)) {
|
||||||
globalScene.phaseManager.queueMessage(
|
globalScene.phaseManager.queueMessage(
|
||||||
i18next.t("abilityTriggers:postDefendStealHeldItem", {
|
i18next.t("abilityTriggers:postDefendStealHeldItem", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
attackerName: attacker.name,
|
attackerName: attacker.name,
|
||||||
stolenItemType: this.stolenItem.type.name,
|
stolenItemType: allHeldItems[this.stolenItem].name,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.stolenItem = undefined;
|
this.stolenItem = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
|
|
||||||
return globalScene.findModifiers(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === target.id,
|
|
||||||
target.isPlayer(),
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -5643,10 +5630,14 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr {
|
|||||||
override canApplyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean {
|
override canApplyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean {
|
||||||
// Ensure we have at least 1 recoverable berry (at least 1 berry in berriesEaten is not capped)
|
// Ensure we have at least 1 recoverable berry (at least 1 berry in berriesEaten is not capped)
|
||||||
const cappedBerries = new Set(
|
const cappedBerries = new Set(
|
||||||
globalScene
|
pokemon
|
||||||
.getModifiers(BerryModifier, pokemon.isPlayer())
|
.getHeldItems()
|
||||||
.filter(bm => bm.pokemonId === pokemon.id && bm.getCountUnderMax() < 1)
|
.filter(
|
||||||
.map(bm => bm.berryType),
|
bm =>
|
||||||
|
isItemInCategory(bm, HeldItemCategoryId.BERRY) &&
|
||||||
|
pokemon.heldItemManager.getStack(bm) < allHeldItems[bm].maxStackCount,
|
||||||
|
)
|
||||||
|
.map(bm => allHeldItems[bm].berryType),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.berriesUnderCap = pokemon.battleData.berriesEaten.filter(bt => !cappedBerries.has(bt));
|
this.berriesUnderCap = pokemon.battleData.berriesEaten.filter(bt => !cappedBerries.has(bt));
|
||||||
@ -5676,30 +5667,15 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr {
|
|||||||
const randomIdx = randSeedInt(this.berriesUnderCap.length);
|
const randomIdx = randSeedInt(this.berriesUnderCap.length);
|
||||||
const chosenBerryType = this.berriesUnderCap[randomIdx];
|
const chosenBerryType = this.berriesUnderCap[randomIdx];
|
||||||
pokemon.battleData.berriesEaten.splice(randomIdx, 1); // Remove berry from memory
|
pokemon.battleData.berriesEaten.splice(randomIdx, 1); // Remove berry from memory
|
||||||
const chosenBerry = new BerryModifierType(chosenBerryType);
|
const chosenBerry = berryTypeToHeldItem[chosenBerryType];
|
||||||
|
|
||||||
// Add the randomly chosen berry or update the existing one
|
pokemon.heldItemManager.add(chosenBerry);
|
||||||
const berryModifier = globalScene.findModifier(
|
|
||||||
m => m instanceof BerryModifier && m.berryType === chosenBerryType && m.pokemonId === pokemon.id,
|
|
||||||
pokemon.isPlayer(),
|
|
||||||
) as BerryModifier | undefined;
|
|
||||||
|
|
||||||
if (berryModifier) {
|
|
||||||
berryModifier.stackCount++;
|
|
||||||
} else {
|
|
||||||
const newBerry = new BerryModifier(chosenBerry, pokemon.id, chosenBerryType, 1);
|
|
||||||
if (pokemon.isPlayer()) {
|
|
||||||
globalScene.addModifier(newBerry);
|
|
||||||
} else {
|
|
||||||
globalScene.addEnemyModifier(newBerry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
globalScene.updateModifiers(pokemon.isPlayer());
|
globalScene.updateModifiers(pokemon.isPlayer());
|
||||||
globalScene.phaseManager.queueMessage(
|
globalScene.phaseManager.queueMessage(
|
||||||
i18next.t("abilityTriggers:postTurnLootCreateEatenBerry", {
|
i18next.t("abilityTriggers:postTurnLootCreateEatenBerry", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
berryName: chosenBerry.name,
|
berryName: allHeldItems[chosenBerry].name,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
@ -5748,8 +5724,7 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr {
|
|||||||
// This doesn't count as "eating" a berry (for unnerve/stuff cheeks/unburden) as no item is consumed.
|
// This doesn't count as "eating" a berry (for unnerve/stuff cheeks/unburden) as no item is consumed.
|
||||||
for (const berryType of pokemon.summonData.berriesEatenLast) {
|
for (const berryType of pokemon.summonData.berriesEatenLast) {
|
||||||
getBerryEffectFunc(berryType)(pokemon);
|
getBerryEffectFunc(berryType)(pokemon);
|
||||||
const bMod = new BerryModifier(new BerryModifierType(berryType), pokemon.id, berryType, 1);
|
globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(pokemon, berryType)); // trigger message
|
||||||
globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(bMod)); // trigger message
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// uncomment to make cheek pouch work with cud chew
|
// uncomment to make cheek pouch work with cud chew
|
||||||
@ -6417,13 +6392,13 @@ export class PostBattleAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PostBattleLootAbAttr extends PostBattleAbAttr {
|
export class PostBattleLootAbAttr extends PostBattleAbAttr {
|
||||||
private randItem?: PokemonHeldItemModifier;
|
private randItem?: HeldItemId;
|
||||||
|
|
||||||
override canApplyPostBattle(pokemon: Pokemon, _passive: boolean, simulated: boolean, args: any[]): boolean {
|
override canApplyPostBattle(pokemon: Pokemon, _passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||||
const postBattleLoot = globalScene.currentBattle.postBattleLoot;
|
const postBattleLoot = globalScene.currentBattle.postBattleLoot;
|
||||||
if (!simulated && postBattleLoot.length && args[0]) {
|
if (!simulated && postBattleLoot.length && args[0]) {
|
||||||
this.randItem = randSeedItem(postBattleLoot);
|
this.randItem = randSeedItem(postBattleLoot);
|
||||||
return globalScene.canTransferHeldItemModifier(this.randItem, pokemon, 1);
|
return pokemon.heldItemManager.getStack(this.randItem) < allHeldItems[this.randItem].maxStackCount;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -6437,12 +6412,12 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
|
|||||||
this.randItem = randSeedItem(postBattleLoot);
|
this.randItem = randSeedItem(postBattleLoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalScene.tryTransferHeldItemModifier(this.randItem, pokemon, true, 1, true, undefined, false)) {
|
if (pokemon.heldItemManager.add(this.randItem)) {
|
||||||
postBattleLoot.splice(postBattleLoot.indexOf(this.randItem), 1);
|
postBattleLoot.splice(postBattleLoot.indexOf(this.randItem), 1);
|
||||||
globalScene.phaseManager.queueMessage(
|
globalScene.phaseManager.queueMessage(
|
||||||
i18next.t("abilityTriggers:postBattleLoot", {
|
i18next.t("abilityTriggers:postBattleLoot", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
itemName: this.randItem.type.name,
|
itemName: allHeldItems[this.randItem].name,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -7457,8 +7432,6 @@ class ForceSwitchOutHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!allyPokemon?.isActive(true)) {
|
if (!allyPokemon?.isActive(true)) {
|
||||||
globalScene.clearEnemyHeldItemModifiers();
|
|
||||||
|
|
||||||
if (switchOutTarget.hp) {
|
if (switchOutTarget.hp) {
|
||||||
globalScene.phaseManager.pushNew("BattleEndPhase", false);
|
globalScene.phaseManager.pushNew("BattleEndPhase", false);
|
||||||
|
|
||||||
@ -7542,11 +7515,9 @@ class ForceSwitchOutHelper {
|
|||||||
* @returns The amount of health recovered by Shell Bell.
|
* @returns The amount of health recovered by Shell Bell.
|
||||||
*/
|
*/
|
||||||
function calculateShellBellRecovery(pokemon: Pokemon): number {
|
function calculateShellBellRecovery(pokemon: Pokemon): number {
|
||||||
const shellBellModifier = pokemon.getHeldItems().find(m => m instanceof HitHealModifier);
|
// Returns 0 if no Shell Bell is present
|
||||||
if (shellBellModifier) {
|
const shellBellStack = pokemon.heldItemManager.getStack(HeldItemId.SHELL_BELL);
|
||||||
return toDmgValue(pokemon.turnData.totalDamageDealt / 8) * shellBellModifier.stackCount;
|
return toDmgValue(pokemon.turnData.totalDamageDealt / 8) * shellBellStack;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,11 +11,11 @@ import { MoveId } from "#enums/move-id";
|
|||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||||
import { TimeOfDay } from "#enums/time-of-day";
|
import { TimeOfDay } from "#enums/time-of-day";
|
||||||
import type { SpeciesStatBoosterItem, SpeciesStatBoosterModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { speciesStarterCosts } from "./starters";
|
import { speciesStarterCosts } from "./starters";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { allMoves } from "#app/data/data-lists";
|
import { allMoves } from "#app/data/data-lists";
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
export enum SpeciesWildEvolutionDelay {
|
export enum SpeciesWildEvolutionDelay {
|
||||||
NONE,
|
NONE,
|
||||||
@ -110,7 +110,7 @@ type EvolutionConditionData =
|
|||||||
{key: typeof EvoCondKey.GENDER, gender: Gender} |
|
{key: typeof EvoCondKey.GENDER, gender: Gender} |
|
||||||
{key: typeof EvoCondKey.MOVE_TYPE | typeof EvoCondKey.PARTY_TYPE, pkmnType: PokemonType} |
|
{key: typeof EvoCondKey.MOVE_TYPE | typeof EvoCondKey.PARTY_TYPE, pkmnType: PokemonType} |
|
||||||
{key: typeof EvoCondKey.SPECIES_CAUGHT, speciesCaught: SpeciesId} |
|
{key: typeof EvoCondKey.SPECIES_CAUGHT, speciesCaught: SpeciesId} |
|
||||||
{key: typeof EvoCondKey.HELD_ITEM, itemKey: SpeciesStatBoosterItem} |
|
{key: typeof EvoCondKey.HELD_ITEM, itemKey: HeldItemId} |
|
||||||
{key: typeof EvoCondKey.NATURE, nature: Nature[]} |
|
{key: typeof EvoCondKey.NATURE, nature: Nature[]} |
|
||||||
{key: typeof EvoCondKey.WEATHER, weather: WeatherType[]} |
|
{key: typeof EvoCondKey.WEATHER, weather: WeatherType[]} |
|
||||||
{key: typeof EvoCondKey.TYROGUE, move: TyrogueMove} |
|
{key: typeof EvoCondKey.TYROGUE, move: TyrogueMove} |
|
||||||
@ -201,7 +201,7 @@ export class SpeciesEvolutionCondition {
|
|||||||
case EvoCondKey.SPECIES_CAUGHT:
|
case EvoCondKey.SPECIES_CAUGHT:
|
||||||
return !!globalScene.gameData.dexData[cond.speciesCaught].caughtAttr;
|
return !!globalScene.gameData.dexData[cond.speciesCaught].caughtAttr;
|
||||||
case EvoCondKey.HELD_ITEM:
|
case EvoCondKey.HELD_ITEM:
|
||||||
return pokemon.getHeldItems().some(m => m.is("SpeciesStatBoosterModifier") && (m.type as SpeciesStatBoosterModifierType).key === cond.itemKey)
|
return pokemon.heldItemManager.hasItem(cond.itemKey);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1765,8 +1765,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(SpeciesId.DUSKNOIR, 1, EvolutionItem.REAPER_CLOTH, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(SpeciesId.DUSKNOIR, 1, EvolutionItem.REAPER_CLOTH, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[SpeciesId.CLAMPERL]: [
|
[SpeciesId.CLAMPERL]: [
|
||||||
new SpeciesEvolution(SpeciesId.HUNTAIL, 1, EvolutionItem.LINKING_CORD, {key: EvoCondKey.HELD_ITEM, itemKey: "DEEP_SEA_TOOTH"}, SpeciesWildEvolutionDelay.VERY_LONG),
|
new SpeciesEvolution(SpeciesId.HUNTAIL, 1, EvolutionItem.LINKING_CORD, {key: EvoCondKey.HELD_ITEM, itemKey: HeldItemId.DEEP_SEA_TOOTH}, SpeciesWildEvolutionDelay.VERY_LONG),
|
||||||
new SpeciesEvolution(SpeciesId.GOREBYSS, 1, EvolutionItem.LINKING_CORD, {key: EvoCondKey.HELD_ITEM, itemKey: "DEEP_SEA_SCALE"}, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(SpeciesId.GOREBYSS, 1, EvolutionItem.LINKING_CORD, {key: EvoCondKey.HELD_ITEM, itemKey: HeldItemId.DEEP_SEA_SCALE}, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[SpeciesId.BOLDORE]: [
|
[SpeciesId.BOLDORE]: [
|
||||||
new SpeciesEvolution(SpeciesId.GIGALITH, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(SpeciesId.GIGALITH, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
|
|
||||||
@ -68591,324 +68591,324 @@ function transposeTmSpecies(): SpeciesTmMoves {
|
|||||||
export const speciesTmMoves: SpeciesTmMoves = transposeTmSpecies();
|
export const speciesTmMoves: SpeciesTmMoves = transposeTmSpecies();
|
||||||
|
|
||||||
interface TmPoolTiers {
|
interface TmPoolTiers {
|
||||||
[key: number]: ModifierTier
|
[key: number]: RewardTier
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tmPoolTiers: TmPoolTiers = {
|
export const tmPoolTiers: TmPoolTiers = {
|
||||||
[MoveId.MEGA_PUNCH]: ModifierTier.GREAT,
|
[MoveId.MEGA_PUNCH]: RewardTier.GREAT,
|
||||||
[MoveId.PAY_DAY]: ModifierTier.ULTRA,
|
[MoveId.PAY_DAY]: RewardTier.ULTRA,
|
||||||
[MoveId.FIRE_PUNCH]: ModifierTier.GREAT,
|
[MoveId.FIRE_PUNCH]: RewardTier.GREAT,
|
||||||
[MoveId.ICE_PUNCH]: ModifierTier.GREAT,
|
[MoveId.ICE_PUNCH]: RewardTier.GREAT,
|
||||||
[MoveId.THUNDER_PUNCH]: ModifierTier.GREAT,
|
[MoveId.THUNDER_PUNCH]: RewardTier.GREAT,
|
||||||
[MoveId.SWORDS_DANCE]: ModifierTier.COMMON,
|
[MoveId.SWORDS_DANCE]: RewardTier.COMMON,
|
||||||
[MoveId.CUT]: ModifierTier.COMMON,
|
[MoveId.CUT]: RewardTier.COMMON,
|
||||||
[MoveId.FLY]: ModifierTier.COMMON,
|
[MoveId.FLY]: RewardTier.COMMON,
|
||||||
[MoveId.MEGA_KICK]: ModifierTier.GREAT,
|
[MoveId.MEGA_KICK]: RewardTier.GREAT,
|
||||||
[MoveId.BODY_SLAM]: ModifierTier.GREAT,
|
[MoveId.BODY_SLAM]: RewardTier.GREAT,
|
||||||
[MoveId.TAKE_DOWN]: ModifierTier.GREAT,
|
[MoveId.TAKE_DOWN]: RewardTier.GREAT,
|
||||||
[MoveId.DOUBLE_EDGE]: ModifierTier.ULTRA,
|
[MoveId.DOUBLE_EDGE]: RewardTier.ULTRA,
|
||||||
[MoveId.PIN_MISSILE]: ModifierTier.COMMON,
|
[MoveId.PIN_MISSILE]: RewardTier.COMMON,
|
||||||
[MoveId.ROAR]: ModifierTier.COMMON,
|
[MoveId.ROAR]: RewardTier.COMMON,
|
||||||
[MoveId.FLAMETHROWER]: ModifierTier.ULTRA,
|
[MoveId.FLAMETHROWER]: RewardTier.ULTRA,
|
||||||
[MoveId.HYDRO_PUMP]: ModifierTier.ULTRA,
|
[MoveId.HYDRO_PUMP]: RewardTier.ULTRA,
|
||||||
[MoveId.SURF]: ModifierTier.ULTRA,
|
[MoveId.SURF]: RewardTier.ULTRA,
|
||||||
[MoveId.ICE_BEAM]: ModifierTier.ULTRA,
|
[MoveId.ICE_BEAM]: RewardTier.ULTRA,
|
||||||
[MoveId.BLIZZARD]: ModifierTier.ULTRA,
|
[MoveId.BLIZZARD]: RewardTier.ULTRA,
|
||||||
[MoveId.PSYBEAM]: ModifierTier.GREAT,
|
[MoveId.PSYBEAM]: RewardTier.GREAT,
|
||||||
[MoveId.HYPER_BEAM]: ModifierTier.ULTRA,
|
[MoveId.HYPER_BEAM]: RewardTier.ULTRA,
|
||||||
[MoveId.LOW_KICK]: ModifierTier.COMMON,
|
[MoveId.LOW_KICK]: RewardTier.COMMON,
|
||||||
[MoveId.COUNTER]: ModifierTier.COMMON,
|
[MoveId.COUNTER]: RewardTier.COMMON,
|
||||||
[MoveId.STRENGTH]: ModifierTier.GREAT,
|
[MoveId.STRENGTH]: RewardTier.GREAT,
|
||||||
[MoveId.SOLAR_BEAM]: ModifierTier.ULTRA,
|
[MoveId.SOLAR_BEAM]: RewardTier.ULTRA,
|
||||||
[MoveId.FIRE_SPIN]: ModifierTier.COMMON,
|
[MoveId.FIRE_SPIN]: RewardTier.COMMON,
|
||||||
[MoveId.THUNDERBOLT]: ModifierTier.ULTRA,
|
[MoveId.THUNDERBOLT]: RewardTier.ULTRA,
|
||||||
[MoveId.THUNDER_WAVE]: ModifierTier.COMMON,
|
[MoveId.THUNDER_WAVE]: RewardTier.COMMON,
|
||||||
[MoveId.THUNDER]: ModifierTier.ULTRA,
|
[MoveId.THUNDER]: RewardTier.ULTRA,
|
||||||
[MoveId.EARTHQUAKE]: ModifierTier.ULTRA,
|
[MoveId.EARTHQUAKE]: RewardTier.ULTRA,
|
||||||
[MoveId.DIG]: ModifierTier.GREAT,
|
[MoveId.DIG]: RewardTier.GREAT,
|
||||||
[MoveId.TOXIC]: ModifierTier.GREAT,
|
[MoveId.TOXIC]: RewardTier.GREAT,
|
||||||
[MoveId.PSYCHIC]: ModifierTier.ULTRA,
|
[MoveId.PSYCHIC]: RewardTier.ULTRA,
|
||||||
[MoveId.AGILITY]: ModifierTier.COMMON,
|
[MoveId.AGILITY]: RewardTier.COMMON,
|
||||||
[MoveId.NIGHT_SHADE]: ModifierTier.COMMON,
|
[MoveId.NIGHT_SHADE]: RewardTier.COMMON,
|
||||||
[MoveId.SCREECH]: ModifierTier.COMMON,
|
[MoveId.SCREECH]: RewardTier.COMMON,
|
||||||
[MoveId.DOUBLE_TEAM]: ModifierTier.COMMON,
|
[MoveId.DOUBLE_TEAM]: RewardTier.COMMON,
|
||||||
[MoveId.CONFUSE_RAY]: ModifierTier.COMMON,
|
[MoveId.CONFUSE_RAY]: RewardTier.COMMON,
|
||||||
[MoveId.LIGHT_SCREEN]: ModifierTier.COMMON,
|
[MoveId.LIGHT_SCREEN]: RewardTier.COMMON,
|
||||||
[MoveId.HAZE]: ModifierTier.COMMON,
|
[MoveId.HAZE]: RewardTier.COMMON,
|
||||||
[MoveId.REFLECT]: ModifierTier.COMMON,
|
[MoveId.REFLECT]: RewardTier.COMMON,
|
||||||
[MoveId.FOCUS_ENERGY]: ModifierTier.COMMON,
|
[MoveId.FOCUS_ENERGY]: RewardTier.COMMON,
|
||||||
[MoveId.METRONOME]: ModifierTier.COMMON,
|
[MoveId.METRONOME]: RewardTier.COMMON,
|
||||||
[MoveId.SELF_DESTRUCT]: ModifierTier.GREAT,
|
[MoveId.SELF_DESTRUCT]: RewardTier.GREAT,
|
||||||
[MoveId.FIRE_BLAST]: ModifierTier.ULTRA,
|
[MoveId.FIRE_BLAST]: RewardTier.ULTRA,
|
||||||
[MoveId.WATERFALL]: ModifierTier.GREAT,
|
[MoveId.WATERFALL]: RewardTier.GREAT,
|
||||||
[MoveId.SWIFT]: ModifierTier.COMMON,
|
[MoveId.SWIFT]: RewardTier.COMMON,
|
||||||
[MoveId.AMNESIA]: ModifierTier.COMMON,
|
[MoveId.AMNESIA]: RewardTier.COMMON,
|
||||||
[MoveId.DREAM_EATER]: ModifierTier.GREAT,
|
[MoveId.DREAM_EATER]: RewardTier.GREAT,
|
||||||
[MoveId.LEECH_LIFE]: ModifierTier.ULTRA,
|
[MoveId.LEECH_LIFE]: RewardTier.ULTRA,
|
||||||
[MoveId.FLASH]: ModifierTier.COMMON,
|
[MoveId.FLASH]: RewardTier.COMMON,
|
||||||
[MoveId.EXPLOSION]: ModifierTier.GREAT,
|
[MoveId.EXPLOSION]: RewardTier.GREAT,
|
||||||
[MoveId.REST]: ModifierTier.COMMON,
|
[MoveId.REST]: RewardTier.COMMON,
|
||||||
[MoveId.ROCK_SLIDE]: ModifierTier.GREAT,
|
[MoveId.ROCK_SLIDE]: RewardTier.GREAT,
|
||||||
[MoveId.TRI_ATTACK]: ModifierTier.ULTRA,
|
[MoveId.TRI_ATTACK]: RewardTier.ULTRA,
|
||||||
[MoveId.SUPER_FANG]: ModifierTier.COMMON,
|
[MoveId.SUPER_FANG]: RewardTier.COMMON,
|
||||||
[MoveId.SUBSTITUTE]: ModifierTier.COMMON,
|
[MoveId.SUBSTITUTE]: RewardTier.COMMON,
|
||||||
[MoveId.THIEF]: ModifierTier.GREAT,
|
[MoveId.THIEF]: RewardTier.GREAT,
|
||||||
[MoveId.SNORE]: ModifierTier.COMMON,
|
[MoveId.SNORE]: RewardTier.COMMON,
|
||||||
[MoveId.CURSE]: ModifierTier.COMMON,
|
[MoveId.CURSE]: RewardTier.COMMON,
|
||||||
[MoveId.REVERSAL]: ModifierTier.COMMON,
|
[MoveId.REVERSAL]: RewardTier.COMMON,
|
||||||
[MoveId.SPITE]: ModifierTier.COMMON,
|
[MoveId.SPITE]: RewardTier.COMMON,
|
||||||
[MoveId.PROTECT]: ModifierTier.COMMON,
|
[MoveId.PROTECT]: RewardTier.COMMON,
|
||||||
[MoveId.SCARY_FACE]: ModifierTier.COMMON,
|
[MoveId.SCARY_FACE]: RewardTier.COMMON,
|
||||||
[MoveId.SLUDGE_BOMB]: ModifierTier.GREAT,
|
[MoveId.SLUDGE_BOMB]: RewardTier.GREAT,
|
||||||
[MoveId.MUD_SLAP]: ModifierTier.COMMON,
|
[MoveId.MUD_SLAP]: RewardTier.COMMON,
|
||||||
[MoveId.SPIKES]: ModifierTier.COMMON,
|
[MoveId.SPIKES]: RewardTier.COMMON,
|
||||||
[MoveId.ICY_WIND]: ModifierTier.GREAT,
|
[MoveId.ICY_WIND]: RewardTier.GREAT,
|
||||||
[MoveId.OUTRAGE]: ModifierTier.ULTRA,
|
[MoveId.OUTRAGE]: RewardTier.ULTRA,
|
||||||
[MoveId.SANDSTORM]: ModifierTier.COMMON,
|
[MoveId.SANDSTORM]: RewardTier.COMMON,
|
||||||
[MoveId.GIGA_DRAIN]: ModifierTier.ULTRA,
|
[MoveId.GIGA_DRAIN]: RewardTier.ULTRA,
|
||||||
[MoveId.ENDURE]: ModifierTier.COMMON,
|
[MoveId.ENDURE]: RewardTier.COMMON,
|
||||||
[MoveId.CHARM]: ModifierTier.COMMON,
|
[MoveId.CHARM]: RewardTier.COMMON,
|
||||||
[MoveId.FALSE_SWIPE]: ModifierTier.COMMON,
|
[MoveId.FALSE_SWIPE]: RewardTier.COMMON,
|
||||||
[MoveId.SWAGGER]: ModifierTier.COMMON,
|
[MoveId.SWAGGER]: RewardTier.COMMON,
|
||||||
[MoveId.STEEL_WING]: ModifierTier.GREAT,
|
[MoveId.STEEL_WING]: RewardTier.GREAT,
|
||||||
[MoveId.ATTRACT]: ModifierTier.COMMON,
|
[MoveId.ATTRACT]: RewardTier.COMMON,
|
||||||
[MoveId.SLEEP_TALK]: ModifierTier.COMMON,
|
[MoveId.SLEEP_TALK]: RewardTier.COMMON,
|
||||||
[MoveId.HEAL_BELL]: ModifierTier.COMMON,
|
[MoveId.HEAL_BELL]: RewardTier.COMMON,
|
||||||
[MoveId.RETURN]: ModifierTier.ULTRA,
|
[MoveId.RETURN]: RewardTier.ULTRA,
|
||||||
[MoveId.FRUSTRATION]: ModifierTier.COMMON,
|
[MoveId.FRUSTRATION]: RewardTier.COMMON,
|
||||||
[MoveId.SAFEGUARD]: ModifierTier.COMMON,
|
[MoveId.SAFEGUARD]: RewardTier.COMMON,
|
||||||
[MoveId.PAIN_SPLIT]: ModifierTier.COMMON,
|
[MoveId.PAIN_SPLIT]: RewardTier.COMMON,
|
||||||
[MoveId.MEGAHORN]: ModifierTier.ULTRA,
|
[MoveId.MEGAHORN]: RewardTier.ULTRA,
|
||||||
[MoveId.BATON_PASS]: ModifierTier.COMMON,
|
[MoveId.BATON_PASS]: RewardTier.COMMON,
|
||||||
[MoveId.ENCORE]: ModifierTier.COMMON,
|
[MoveId.ENCORE]: RewardTier.COMMON,
|
||||||
[MoveId.IRON_TAIL]: ModifierTier.GREAT,
|
[MoveId.IRON_TAIL]: RewardTier.GREAT,
|
||||||
[MoveId.METAL_CLAW]: ModifierTier.COMMON,
|
[MoveId.METAL_CLAW]: RewardTier.COMMON,
|
||||||
[MoveId.SYNTHESIS]: ModifierTier.GREAT,
|
[MoveId.SYNTHESIS]: RewardTier.GREAT,
|
||||||
[MoveId.HIDDEN_POWER]: ModifierTier.GREAT,
|
[MoveId.HIDDEN_POWER]: RewardTier.GREAT,
|
||||||
[MoveId.RAIN_DANCE]: ModifierTier.COMMON,
|
[MoveId.RAIN_DANCE]: RewardTier.COMMON,
|
||||||
[MoveId.SUNNY_DAY]: ModifierTier.COMMON,
|
[MoveId.SUNNY_DAY]: RewardTier.COMMON,
|
||||||
[MoveId.CRUNCH]: ModifierTier.GREAT,
|
[MoveId.CRUNCH]: RewardTier.GREAT,
|
||||||
[MoveId.PSYCH_UP]: ModifierTier.COMMON,
|
[MoveId.PSYCH_UP]: RewardTier.COMMON,
|
||||||
[MoveId.SHADOW_BALL]: ModifierTier.ULTRA,
|
[MoveId.SHADOW_BALL]: RewardTier.ULTRA,
|
||||||
[MoveId.FUTURE_SIGHT]: ModifierTier.GREAT,
|
[MoveId.FUTURE_SIGHT]: RewardTier.GREAT,
|
||||||
[MoveId.ROCK_SMASH]: ModifierTier.COMMON,
|
[MoveId.ROCK_SMASH]: RewardTier.COMMON,
|
||||||
[MoveId.WHIRLPOOL]: ModifierTier.COMMON,
|
[MoveId.WHIRLPOOL]: RewardTier.COMMON,
|
||||||
[MoveId.BEAT_UP]: ModifierTier.COMMON,
|
[MoveId.BEAT_UP]: RewardTier.COMMON,
|
||||||
[MoveId.UPROAR]: ModifierTier.GREAT,
|
[MoveId.UPROAR]: RewardTier.GREAT,
|
||||||
[MoveId.HEAT_WAVE]: ModifierTier.ULTRA,
|
[MoveId.HEAT_WAVE]: RewardTier.ULTRA,
|
||||||
[MoveId.HAIL]: ModifierTier.COMMON,
|
[MoveId.HAIL]: RewardTier.COMMON,
|
||||||
[MoveId.TORMENT]: ModifierTier.COMMON,
|
[MoveId.TORMENT]: RewardTier.COMMON,
|
||||||
[MoveId.WILL_O_WISP]: ModifierTier.COMMON,
|
[MoveId.WILL_O_WISP]: RewardTier.COMMON,
|
||||||
[MoveId.FACADE]: ModifierTier.GREAT,
|
[MoveId.FACADE]: RewardTier.GREAT,
|
||||||
[MoveId.FOCUS_PUNCH]: ModifierTier.COMMON,
|
[MoveId.FOCUS_PUNCH]: RewardTier.COMMON,
|
||||||
[MoveId.NATURE_POWER]: ModifierTier.COMMON,
|
[MoveId.NATURE_POWER]: RewardTier.COMMON,
|
||||||
[MoveId.CHARGE]: ModifierTier.COMMON,
|
[MoveId.CHARGE]: RewardTier.COMMON,
|
||||||
[MoveId.TAUNT]: ModifierTier.COMMON,
|
[MoveId.TAUNT]: RewardTier.COMMON,
|
||||||
[MoveId.HELPING_HAND]: ModifierTier.COMMON,
|
[MoveId.HELPING_HAND]: RewardTier.COMMON,
|
||||||
[MoveId.TRICK]: ModifierTier.COMMON,
|
[MoveId.TRICK]: RewardTier.COMMON,
|
||||||
[MoveId.SUPERPOWER]: ModifierTier.ULTRA,
|
[MoveId.SUPERPOWER]: RewardTier.ULTRA,
|
||||||
[MoveId.RECYCLE]: ModifierTier.COMMON,
|
[MoveId.RECYCLE]: RewardTier.COMMON,
|
||||||
[MoveId.REVENGE]: ModifierTier.GREAT,
|
[MoveId.REVENGE]: RewardTier.GREAT,
|
||||||
[MoveId.BRICK_BREAK]: ModifierTier.GREAT,
|
[MoveId.BRICK_BREAK]: RewardTier.GREAT,
|
||||||
[MoveId.KNOCK_OFF]: ModifierTier.GREAT,
|
[MoveId.KNOCK_OFF]: RewardTier.GREAT,
|
||||||
[MoveId.ENDEAVOR]: ModifierTier.COMMON,
|
[MoveId.ENDEAVOR]: RewardTier.COMMON,
|
||||||
[MoveId.SKILL_SWAP]: ModifierTier.COMMON,
|
[MoveId.SKILL_SWAP]: RewardTier.COMMON,
|
||||||
[MoveId.IMPRISON]: ModifierTier.COMMON,
|
[MoveId.IMPRISON]: RewardTier.COMMON,
|
||||||
[MoveId.SECRET_POWER]: ModifierTier.COMMON,
|
[MoveId.SECRET_POWER]: RewardTier.COMMON,
|
||||||
[MoveId.DIVE]: ModifierTier.GREAT,
|
[MoveId.DIVE]: RewardTier.GREAT,
|
||||||
[MoveId.FEATHER_DANCE]: ModifierTier.COMMON,
|
[MoveId.FEATHER_DANCE]: RewardTier.COMMON,
|
||||||
[MoveId.BLAZE_KICK]: ModifierTier.GREAT,
|
[MoveId.BLAZE_KICK]: RewardTier.GREAT,
|
||||||
[MoveId.HYPER_VOICE]: ModifierTier.ULTRA,
|
[MoveId.HYPER_VOICE]: RewardTier.ULTRA,
|
||||||
[MoveId.BLAST_BURN]: ModifierTier.ULTRA,
|
[MoveId.BLAST_BURN]: RewardTier.ULTRA,
|
||||||
[MoveId.HYDRO_CANNON]: ModifierTier.ULTRA,
|
[MoveId.HYDRO_CANNON]: RewardTier.ULTRA,
|
||||||
[MoveId.WEATHER_BALL]: ModifierTier.COMMON,
|
[MoveId.WEATHER_BALL]: RewardTier.COMMON,
|
||||||
[MoveId.FAKE_TEARS]: ModifierTier.COMMON,
|
[MoveId.FAKE_TEARS]: RewardTier.COMMON,
|
||||||
[MoveId.AIR_CUTTER]: ModifierTier.GREAT,
|
[MoveId.AIR_CUTTER]: RewardTier.GREAT,
|
||||||
[MoveId.OVERHEAT]: ModifierTier.ULTRA,
|
[MoveId.OVERHEAT]: RewardTier.ULTRA,
|
||||||
[MoveId.ROCK_TOMB]: ModifierTier.GREAT,
|
[MoveId.ROCK_TOMB]: RewardTier.GREAT,
|
||||||
[MoveId.METAL_SOUND]: ModifierTier.COMMON,
|
[MoveId.METAL_SOUND]: RewardTier.COMMON,
|
||||||
[MoveId.COSMIC_POWER]: ModifierTier.COMMON,
|
[MoveId.COSMIC_POWER]: RewardTier.COMMON,
|
||||||
[MoveId.SIGNAL_BEAM]: ModifierTier.GREAT,
|
[MoveId.SIGNAL_BEAM]: RewardTier.GREAT,
|
||||||
[MoveId.SAND_TOMB]: ModifierTier.COMMON,
|
[MoveId.SAND_TOMB]: RewardTier.COMMON,
|
||||||
[MoveId.MUDDY_WATER]: ModifierTier.GREAT,
|
[MoveId.MUDDY_WATER]: RewardTier.GREAT,
|
||||||
[MoveId.BULLET_SEED]: ModifierTier.GREAT,
|
[MoveId.BULLET_SEED]: RewardTier.GREAT,
|
||||||
[MoveId.AERIAL_ACE]: ModifierTier.GREAT,
|
[MoveId.AERIAL_ACE]: RewardTier.GREAT,
|
||||||
[MoveId.ICICLE_SPEAR]: ModifierTier.GREAT,
|
[MoveId.ICICLE_SPEAR]: RewardTier.GREAT,
|
||||||
[MoveId.IRON_DEFENSE]: ModifierTier.GREAT,
|
[MoveId.IRON_DEFENSE]: RewardTier.GREAT,
|
||||||
[MoveId.DRAGON_CLAW]: ModifierTier.ULTRA,
|
[MoveId.DRAGON_CLAW]: RewardTier.ULTRA,
|
||||||
[MoveId.FRENZY_PLANT]: ModifierTier.ULTRA,
|
[MoveId.FRENZY_PLANT]: RewardTier.ULTRA,
|
||||||
[MoveId.BULK_UP]: ModifierTier.COMMON,
|
[MoveId.BULK_UP]: RewardTier.COMMON,
|
||||||
[MoveId.BOUNCE]: ModifierTier.GREAT,
|
[MoveId.BOUNCE]: RewardTier.GREAT,
|
||||||
[MoveId.MUD_SHOT]: ModifierTier.GREAT,
|
[MoveId.MUD_SHOT]: RewardTier.GREAT,
|
||||||
[MoveId.POISON_TAIL]: ModifierTier.GREAT,
|
[MoveId.POISON_TAIL]: RewardTier.GREAT,
|
||||||
[MoveId.COVET]: ModifierTier.GREAT,
|
[MoveId.COVET]: RewardTier.GREAT,
|
||||||
[MoveId.MAGICAL_LEAF]: ModifierTier.GREAT,
|
[MoveId.MAGICAL_LEAF]: RewardTier.GREAT,
|
||||||
[MoveId.CALM_MIND]: ModifierTier.GREAT,
|
[MoveId.CALM_MIND]: RewardTier.GREAT,
|
||||||
[MoveId.LEAF_BLADE]: ModifierTier.ULTRA,
|
[MoveId.LEAF_BLADE]: RewardTier.ULTRA,
|
||||||
[MoveId.DRAGON_DANCE]: ModifierTier.GREAT,
|
[MoveId.DRAGON_DANCE]: RewardTier.GREAT,
|
||||||
[MoveId.ROCK_BLAST]: ModifierTier.GREAT,
|
[MoveId.ROCK_BLAST]: RewardTier.GREAT,
|
||||||
[MoveId.WATER_PULSE]: ModifierTier.GREAT,
|
[MoveId.WATER_PULSE]: RewardTier.GREAT,
|
||||||
[MoveId.ROOST]: ModifierTier.GREAT,
|
[MoveId.ROOST]: RewardTier.GREAT,
|
||||||
[MoveId.GRAVITY]: ModifierTier.COMMON,
|
[MoveId.GRAVITY]: RewardTier.COMMON,
|
||||||
[MoveId.GYRO_BALL]: ModifierTier.COMMON,
|
[MoveId.GYRO_BALL]: RewardTier.COMMON,
|
||||||
[MoveId.BRINE]: ModifierTier.GREAT,
|
[MoveId.BRINE]: RewardTier.GREAT,
|
||||||
[MoveId.PLUCK]: ModifierTier.GREAT,
|
[MoveId.PLUCK]: RewardTier.GREAT,
|
||||||
[MoveId.TAILWIND]: ModifierTier.GREAT,
|
[MoveId.TAILWIND]: RewardTier.GREAT,
|
||||||
[MoveId.U_TURN]: ModifierTier.GREAT,
|
[MoveId.U_TURN]: RewardTier.GREAT,
|
||||||
[MoveId.CLOSE_COMBAT]: ModifierTier.ULTRA,
|
[MoveId.CLOSE_COMBAT]: RewardTier.ULTRA,
|
||||||
[MoveId.PAYBACK]: ModifierTier.COMMON,
|
[MoveId.PAYBACK]: RewardTier.COMMON,
|
||||||
[MoveId.ASSURANCE]: ModifierTier.COMMON,
|
[MoveId.ASSURANCE]: RewardTier.COMMON,
|
||||||
[MoveId.EMBARGO]: ModifierTier.COMMON,
|
[MoveId.EMBARGO]: RewardTier.COMMON,
|
||||||
[MoveId.FLING]: ModifierTier.COMMON,
|
[MoveId.FLING]: RewardTier.COMMON,
|
||||||
[MoveId.GASTRO_ACID]: ModifierTier.GREAT,
|
[MoveId.GASTRO_ACID]: RewardTier.GREAT,
|
||||||
[MoveId.POWER_SWAP]: ModifierTier.COMMON,
|
[MoveId.POWER_SWAP]: RewardTier.COMMON,
|
||||||
[MoveId.GUARD_SWAP]: ModifierTier.COMMON,
|
[MoveId.GUARD_SWAP]: RewardTier.COMMON,
|
||||||
[MoveId.WORRY_SEED]: ModifierTier.GREAT,
|
[MoveId.WORRY_SEED]: RewardTier.GREAT,
|
||||||
[MoveId.TOXIC_SPIKES]: ModifierTier.GREAT,
|
[MoveId.TOXIC_SPIKES]: RewardTier.GREAT,
|
||||||
[MoveId.FLARE_BLITZ]: ModifierTier.ULTRA,
|
[MoveId.FLARE_BLITZ]: RewardTier.ULTRA,
|
||||||
[MoveId.AURA_SPHERE]: ModifierTier.GREAT,
|
[MoveId.AURA_SPHERE]: RewardTier.GREAT,
|
||||||
[MoveId.ROCK_POLISH]: ModifierTier.COMMON,
|
[MoveId.ROCK_POLISH]: RewardTier.COMMON,
|
||||||
[MoveId.POISON_JAB]: ModifierTier.GREAT,
|
[MoveId.POISON_JAB]: RewardTier.GREAT,
|
||||||
[MoveId.DARK_PULSE]: ModifierTier.GREAT,
|
[MoveId.DARK_PULSE]: RewardTier.GREAT,
|
||||||
[MoveId.AQUA_TAIL]: ModifierTier.GREAT,
|
[MoveId.AQUA_TAIL]: RewardTier.GREAT,
|
||||||
[MoveId.SEED_BOMB]: ModifierTier.GREAT,
|
[MoveId.SEED_BOMB]: RewardTier.GREAT,
|
||||||
[MoveId.AIR_SLASH]: ModifierTier.GREAT,
|
[MoveId.AIR_SLASH]: RewardTier.GREAT,
|
||||||
[MoveId.X_SCISSOR]: ModifierTier.GREAT,
|
[MoveId.X_SCISSOR]: RewardTier.GREAT,
|
||||||
[MoveId.BUG_BUZZ]: ModifierTier.GREAT,
|
[MoveId.BUG_BUZZ]: RewardTier.GREAT,
|
||||||
[MoveId.DRAGON_PULSE]: ModifierTier.GREAT,
|
[MoveId.DRAGON_PULSE]: RewardTier.GREAT,
|
||||||
[MoveId.POWER_GEM]: ModifierTier.GREAT,
|
[MoveId.POWER_GEM]: RewardTier.GREAT,
|
||||||
[MoveId.DRAIN_PUNCH]: ModifierTier.GREAT,
|
[MoveId.DRAIN_PUNCH]: RewardTier.GREAT,
|
||||||
[MoveId.VACUUM_WAVE]: ModifierTier.COMMON,
|
[MoveId.VACUUM_WAVE]: RewardTier.COMMON,
|
||||||
[MoveId.FOCUS_BLAST]: ModifierTier.GREAT,
|
[MoveId.FOCUS_BLAST]: RewardTier.GREAT,
|
||||||
[MoveId.ENERGY_BALL]: ModifierTier.GREAT,
|
[MoveId.ENERGY_BALL]: RewardTier.GREAT,
|
||||||
[MoveId.BRAVE_BIRD]: ModifierTier.ULTRA,
|
[MoveId.BRAVE_BIRD]: RewardTier.ULTRA,
|
||||||
[MoveId.EARTH_POWER]: ModifierTier.ULTRA,
|
[MoveId.EARTH_POWER]: RewardTier.ULTRA,
|
||||||
[MoveId.GIGA_IMPACT]: ModifierTier.GREAT,
|
[MoveId.GIGA_IMPACT]: RewardTier.GREAT,
|
||||||
[MoveId.NASTY_PLOT]: ModifierTier.COMMON,
|
[MoveId.NASTY_PLOT]: RewardTier.COMMON,
|
||||||
[MoveId.AVALANCHE]: ModifierTier.GREAT,
|
[MoveId.AVALANCHE]: RewardTier.GREAT,
|
||||||
[MoveId.SHADOW_CLAW]: ModifierTier.GREAT,
|
[MoveId.SHADOW_CLAW]: RewardTier.GREAT,
|
||||||
[MoveId.THUNDER_FANG]: ModifierTier.GREAT,
|
[MoveId.THUNDER_FANG]: RewardTier.GREAT,
|
||||||
[MoveId.ICE_FANG]: ModifierTier.GREAT,
|
[MoveId.ICE_FANG]: RewardTier.GREAT,
|
||||||
[MoveId.FIRE_FANG]: ModifierTier.GREAT,
|
[MoveId.FIRE_FANG]: RewardTier.GREAT,
|
||||||
[MoveId.PSYCHO_CUT]: ModifierTier.GREAT,
|
[MoveId.PSYCHO_CUT]: RewardTier.GREAT,
|
||||||
[MoveId.ZEN_HEADBUTT]: ModifierTier.GREAT,
|
[MoveId.ZEN_HEADBUTT]: RewardTier.GREAT,
|
||||||
[MoveId.FLASH_CANNON]: ModifierTier.GREAT,
|
[MoveId.FLASH_CANNON]: RewardTier.GREAT,
|
||||||
[MoveId.ROCK_CLIMB]: ModifierTier.GREAT,
|
[MoveId.ROCK_CLIMB]: RewardTier.GREAT,
|
||||||
[MoveId.DEFOG]: ModifierTier.COMMON,
|
[MoveId.DEFOG]: RewardTier.COMMON,
|
||||||
[MoveId.TRICK_ROOM]: ModifierTier.COMMON,
|
[MoveId.TRICK_ROOM]: RewardTier.COMMON,
|
||||||
[MoveId.DRACO_METEOR]: ModifierTier.ULTRA,
|
[MoveId.DRACO_METEOR]: RewardTier.ULTRA,
|
||||||
[MoveId.LEAF_STORM]: ModifierTier.ULTRA,
|
[MoveId.LEAF_STORM]: RewardTier.ULTRA,
|
||||||
[MoveId.POWER_WHIP]: ModifierTier.ULTRA,
|
[MoveId.POWER_WHIP]: RewardTier.ULTRA,
|
||||||
[MoveId.CROSS_POISON]: ModifierTier.GREAT,
|
[MoveId.CROSS_POISON]: RewardTier.GREAT,
|
||||||
[MoveId.GUNK_SHOT]: ModifierTier.ULTRA,
|
[MoveId.GUNK_SHOT]: RewardTier.ULTRA,
|
||||||
[MoveId.IRON_HEAD]: ModifierTier.GREAT,
|
[MoveId.IRON_HEAD]: RewardTier.GREAT,
|
||||||
[MoveId.STONE_EDGE]: ModifierTier.ULTRA,
|
[MoveId.STONE_EDGE]: RewardTier.ULTRA,
|
||||||
[MoveId.STEALTH_ROCK]: ModifierTier.COMMON,
|
[MoveId.STEALTH_ROCK]: RewardTier.COMMON,
|
||||||
[MoveId.GRASS_KNOT]: ModifierTier.ULTRA,
|
[MoveId.GRASS_KNOT]: RewardTier.ULTRA,
|
||||||
[MoveId.BUG_BITE]: ModifierTier.GREAT,
|
[MoveId.BUG_BITE]: RewardTier.GREAT,
|
||||||
[MoveId.CHARGE_BEAM]: ModifierTier.GREAT,
|
[MoveId.CHARGE_BEAM]: RewardTier.GREAT,
|
||||||
[MoveId.HONE_CLAWS]: ModifierTier.COMMON,
|
[MoveId.HONE_CLAWS]: RewardTier.COMMON,
|
||||||
[MoveId.WONDER_ROOM]: ModifierTier.COMMON,
|
[MoveId.WONDER_ROOM]: RewardTier.COMMON,
|
||||||
[MoveId.PSYSHOCK]: ModifierTier.GREAT,
|
[MoveId.PSYSHOCK]: RewardTier.GREAT,
|
||||||
[MoveId.VENOSHOCK]: ModifierTier.GREAT,
|
[MoveId.VENOSHOCK]: RewardTier.GREAT,
|
||||||
[MoveId.MAGIC_ROOM]: ModifierTier.COMMON,
|
[MoveId.MAGIC_ROOM]: RewardTier.COMMON,
|
||||||
[MoveId.SMACK_DOWN]: ModifierTier.COMMON,
|
[MoveId.SMACK_DOWN]: RewardTier.COMMON,
|
||||||
[MoveId.SLUDGE_WAVE]: ModifierTier.GREAT,
|
[MoveId.SLUDGE_WAVE]: RewardTier.GREAT,
|
||||||
[MoveId.HEAVY_SLAM]: ModifierTier.GREAT,
|
[MoveId.HEAVY_SLAM]: RewardTier.GREAT,
|
||||||
[MoveId.ELECTRO_BALL]: ModifierTier.GREAT,
|
[MoveId.ELECTRO_BALL]: RewardTier.GREAT,
|
||||||
[MoveId.FLAME_CHARGE]: ModifierTier.GREAT,
|
[MoveId.FLAME_CHARGE]: RewardTier.GREAT,
|
||||||
[MoveId.LOW_SWEEP]: ModifierTier.GREAT,
|
[MoveId.LOW_SWEEP]: RewardTier.GREAT,
|
||||||
[MoveId.ACID_SPRAY]: ModifierTier.COMMON,
|
[MoveId.ACID_SPRAY]: RewardTier.COMMON,
|
||||||
[MoveId.FOUL_PLAY]: ModifierTier.ULTRA,
|
[MoveId.FOUL_PLAY]: RewardTier.ULTRA,
|
||||||
[MoveId.ROUND]: ModifierTier.COMMON,
|
[MoveId.ROUND]: RewardTier.COMMON,
|
||||||
[MoveId.ECHOED_VOICE]: ModifierTier.COMMON,
|
[MoveId.ECHOED_VOICE]: RewardTier.COMMON,
|
||||||
[MoveId.STORED_POWER]: ModifierTier.COMMON,
|
[MoveId.STORED_POWER]: RewardTier.COMMON,
|
||||||
[MoveId.ALLY_SWITCH]: ModifierTier.COMMON,
|
[MoveId.ALLY_SWITCH]: RewardTier.COMMON,
|
||||||
[MoveId.SCALD]: ModifierTier.GREAT,
|
[MoveId.SCALD]: RewardTier.GREAT,
|
||||||
[MoveId.HEX]: ModifierTier.GREAT,
|
[MoveId.HEX]: RewardTier.GREAT,
|
||||||
[MoveId.SKY_DROP]: ModifierTier.GREAT,
|
[MoveId.SKY_DROP]: RewardTier.GREAT,
|
||||||
[MoveId.INCINERATE]: ModifierTier.GREAT,
|
[MoveId.INCINERATE]: RewardTier.GREAT,
|
||||||
[MoveId.QUASH]: ModifierTier.COMMON,
|
[MoveId.QUASH]: RewardTier.COMMON,
|
||||||
[MoveId.ACROBATICS]: ModifierTier.GREAT,
|
[MoveId.ACROBATICS]: RewardTier.GREAT,
|
||||||
[MoveId.RETALIATE]: ModifierTier.GREAT,
|
[MoveId.RETALIATE]: RewardTier.GREAT,
|
||||||
[MoveId.WATER_PLEDGE]: ModifierTier.GREAT,
|
[MoveId.WATER_PLEDGE]: RewardTier.GREAT,
|
||||||
[MoveId.FIRE_PLEDGE]: ModifierTier.GREAT,
|
[MoveId.FIRE_PLEDGE]: RewardTier.GREAT,
|
||||||
[MoveId.GRASS_PLEDGE]: ModifierTier.GREAT,
|
[MoveId.GRASS_PLEDGE]: RewardTier.GREAT,
|
||||||
[MoveId.VOLT_SWITCH]: ModifierTier.GREAT,
|
[MoveId.VOLT_SWITCH]: RewardTier.GREAT,
|
||||||
[MoveId.STRUGGLE_BUG]: ModifierTier.COMMON,
|
[MoveId.STRUGGLE_BUG]: RewardTier.COMMON,
|
||||||
[MoveId.BULLDOZE]: ModifierTier.GREAT,
|
[MoveId.BULLDOZE]: RewardTier.GREAT,
|
||||||
[MoveId.FROST_BREATH]: ModifierTier.GREAT,
|
[MoveId.FROST_BREATH]: RewardTier.GREAT,
|
||||||
[MoveId.DRAGON_TAIL]: ModifierTier.GREAT,
|
[MoveId.DRAGON_TAIL]: RewardTier.GREAT,
|
||||||
[MoveId.WORK_UP]: ModifierTier.COMMON,
|
[MoveId.WORK_UP]: RewardTier.COMMON,
|
||||||
[MoveId.ELECTROWEB]: ModifierTier.GREAT,
|
[MoveId.ELECTROWEB]: RewardTier.GREAT,
|
||||||
[MoveId.WILD_CHARGE]: ModifierTier.GREAT,
|
[MoveId.WILD_CHARGE]: RewardTier.GREAT,
|
||||||
[MoveId.DRILL_RUN]: ModifierTier.GREAT,
|
[MoveId.DRILL_RUN]: RewardTier.GREAT,
|
||||||
[MoveId.RAZOR_SHELL]: ModifierTier.GREAT,
|
[MoveId.RAZOR_SHELL]: RewardTier.GREAT,
|
||||||
[MoveId.HEAT_CRASH]: ModifierTier.GREAT,
|
[MoveId.HEAT_CRASH]: RewardTier.GREAT,
|
||||||
[MoveId.TAIL_SLAP]: ModifierTier.GREAT,
|
[MoveId.TAIL_SLAP]: RewardTier.GREAT,
|
||||||
[MoveId.HURRICANE]: ModifierTier.ULTRA,
|
[MoveId.HURRICANE]: RewardTier.ULTRA,
|
||||||
[MoveId.SNARL]: ModifierTier.COMMON,
|
[MoveId.SNARL]: RewardTier.COMMON,
|
||||||
[MoveId.PHANTOM_FORCE]: ModifierTier.ULTRA,
|
[MoveId.PHANTOM_FORCE]: RewardTier.ULTRA,
|
||||||
[MoveId.PETAL_BLIZZARD]: ModifierTier.GREAT,
|
[MoveId.PETAL_BLIZZARD]: RewardTier.GREAT,
|
||||||
[MoveId.DISARMING_VOICE]: ModifierTier.GREAT,
|
[MoveId.DISARMING_VOICE]: RewardTier.GREAT,
|
||||||
[MoveId.DRAINING_KISS]: ModifierTier.GREAT,
|
[MoveId.DRAINING_KISS]: RewardTier.GREAT,
|
||||||
[MoveId.GRASSY_TERRAIN]: ModifierTier.COMMON,
|
[MoveId.GRASSY_TERRAIN]: RewardTier.COMMON,
|
||||||
[MoveId.MISTY_TERRAIN]: ModifierTier.COMMON,
|
[MoveId.MISTY_TERRAIN]: RewardTier.COMMON,
|
||||||
[MoveId.PLAY_ROUGH]: ModifierTier.GREAT,
|
[MoveId.PLAY_ROUGH]: RewardTier.GREAT,
|
||||||
[MoveId.CONFIDE]: ModifierTier.COMMON,
|
[MoveId.CONFIDE]: RewardTier.COMMON,
|
||||||
[MoveId.MYSTICAL_FIRE]: ModifierTier.GREAT,
|
[MoveId.MYSTICAL_FIRE]: RewardTier.GREAT,
|
||||||
[MoveId.EERIE_IMPULSE]: ModifierTier.COMMON,
|
[MoveId.EERIE_IMPULSE]: RewardTier.COMMON,
|
||||||
[MoveId.VENOM_DRENCH]: ModifierTier.COMMON,
|
[MoveId.VENOM_DRENCH]: RewardTier.COMMON,
|
||||||
[MoveId.ELECTRIC_TERRAIN]: ModifierTier.COMMON,
|
[MoveId.ELECTRIC_TERRAIN]: RewardTier.COMMON,
|
||||||
[MoveId.DAZZLING_GLEAM]: ModifierTier.ULTRA,
|
[MoveId.DAZZLING_GLEAM]: RewardTier.ULTRA,
|
||||||
[MoveId.INFESTATION]: ModifierTier.COMMON,
|
[MoveId.INFESTATION]: RewardTier.COMMON,
|
||||||
[MoveId.POWER_UP_PUNCH]: ModifierTier.GREAT,
|
[MoveId.POWER_UP_PUNCH]: RewardTier.GREAT,
|
||||||
[MoveId.DARKEST_LARIAT]: ModifierTier.GREAT,
|
[MoveId.DARKEST_LARIAT]: RewardTier.GREAT,
|
||||||
[MoveId.HIGH_HORSEPOWER]: ModifierTier.ULTRA,
|
[MoveId.HIGH_HORSEPOWER]: RewardTier.ULTRA,
|
||||||
[MoveId.SOLAR_BLADE]: ModifierTier.GREAT,
|
[MoveId.SOLAR_BLADE]: RewardTier.GREAT,
|
||||||
[MoveId.THROAT_CHOP]: ModifierTier.GREAT,
|
[MoveId.THROAT_CHOP]: RewardTier.GREAT,
|
||||||
[MoveId.POLLEN_PUFF]: ModifierTier.GREAT,
|
[MoveId.POLLEN_PUFF]: RewardTier.GREAT,
|
||||||
[MoveId.PSYCHIC_TERRAIN]: ModifierTier.COMMON,
|
[MoveId.PSYCHIC_TERRAIN]: RewardTier.COMMON,
|
||||||
[MoveId.LUNGE]: ModifierTier.GREAT,
|
[MoveId.LUNGE]: RewardTier.GREAT,
|
||||||
[MoveId.SPEED_SWAP]: ModifierTier.COMMON,
|
[MoveId.SPEED_SWAP]: RewardTier.COMMON,
|
||||||
[MoveId.SMART_STRIKE]: ModifierTier.GREAT,
|
[MoveId.SMART_STRIKE]: RewardTier.GREAT,
|
||||||
[MoveId.BRUTAL_SWING]: ModifierTier.GREAT,
|
[MoveId.BRUTAL_SWING]: RewardTier.GREAT,
|
||||||
[MoveId.AURORA_VEIL]: ModifierTier.COMMON,
|
[MoveId.AURORA_VEIL]: RewardTier.COMMON,
|
||||||
[MoveId.PSYCHIC_FANGS]: ModifierTier.GREAT,
|
[MoveId.PSYCHIC_FANGS]: RewardTier.GREAT,
|
||||||
[MoveId.STOMPING_TANTRUM]: ModifierTier.GREAT,
|
[MoveId.STOMPING_TANTRUM]: RewardTier.GREAT,
|
||||||
[MoveId.LIQUIDATION]: ModifierTier.ULTRA,
|
[MoveId.LIQUIDATION]: RewardTier.ULTRA,
|
||||||
[MoveId.BODY_PRESS]: ModifierTier.ULTRA,
|
[MoveId.BODY_PRESS]: RewardTier.ULTRA,
|
||||||
[MoveId.BREAKING_SWIPE]: ModifierTier.GREAT,
|
[MoveId.BREAKING_SWIPE]: RewardTier.GREAT,
|
||||||
[MoveId.STEEL_BEAM]: ModifierTier.ULTRA,
|
[MoveId.STEEL_BEAM]: RewardTier.ULTRA,
|
||||||
[MoveId.EXPANDING_FORCE]: ModifierTier.GREAT,
|
[MoveId.EXPANDING_FORCE]: RewardTier.GREAT,
|
||||||
[MoveId.STEEL_ROLLER]: ModifierTier.COMMON,
|
[MoveId.STEEL_ROLLER]: RewardTier.COMMON,
|
||||||
[MoveId.SCALE_SHOT]: ModifierTier.ULTRA,
|
[MoveId.SCALE_SHOT]: RewardTier.ULTRA,
|
||||||
[MoveId.METEOR_BEAM]: ModifierTier.GREAT,
|
[MoveId.METEOR_BEAM]: RewardTier.GREAT,
|
||||||
[MoveId.MISTY_EXPLOSION]: ModifierTier.COMMON,
|
[MoveId.MISTY_EXPLOSION]: RewardTier.COMMON,
|
||||||
[MoveId.GRASSY_GLIDE]: ModifierTier.COMMON,
|
[MoveId.GRASSY_GLIDE]: RewardTier.COMMON,
|
||||||
[MoveId.RISING_VOLTAGE]: ModifierTier.COMMON,
|
[MoveId.RISING_VOLTAGE]: RewardTier.COMMON,
|
||||||
[MoveId.TERRAIN_PULSE]: ModifierTier.COMMON,
|
[MoveId.TERRAIN_PULSE]: RewardTier.COMMON,
|
||||||
[MoveId.SKITTER_SMACK]: ModifierTier.GREAT,
|
[MoveId.SKITTER_SMACK]: RewardTier.GREAT,
|
||||||
[MoveId.BURNING_JEALOUSY]: ModifierTier.GREAT,
|
[MoveId.BURNING_JEALOUSY]: RewardTier.GREAT,
|
||||||
[MoveId.LASH_OUT]: ModifierTier.GREAT,
|
[MoveId.LASH_OUT]: RewardTier.GREAT,
|
||||||
[MoveId.POLTERGEIST]: ModifierTier.ULTRA,
|
[MoveId.POLTERGEIST]: RewardTier.ULTRA,
|
||||||
[MoveId.CORROSIVE_GAS]: ModifierTier.COMMON,
|
[MoveId.CORROSIVE_GAS]: RewardTier.COMMON,
|
||||||
[MoveId.COACHING]: ModifierTier.COMMON,
|
[MoveId.COACHING]: RewardTier.COMMON,
|
||||||
[MoveId.FLIP_TURN]: ModifierTier.COMMON,
|
[MoveId.FLIP_TURN]: RewardTier.COMMON,
|
||||||
[MoveId.TRIPLE_AXEL]: ModifierTier.COMMON,
|
[MoveId.TRIPLE_AXEL]: RewardTier.COMMON,
|
||||||
[MoveId.DUAL_WINGBEAT]: ModifierTier.COMMON,
|
[MoveId.DUAL_WINGBEAT]: RewardTier.COMMON,
|
||||||
[MoveId.SCORCHING_SANDS]: ModifierTier.GREAT,
|
[MoveId.SCORCHING_SANDS]: RewardTier.GREAT,
|
||||||
[MoveId.TERA_BLAST]: ModifierTier.GREAT,
|
[MoveId.TERA_BLAST]: RewardTier.GREAT,
|
||||||
[MoveId.ICE_SPINNER]: ModifierTier.GREAT,
|
[MoveId.ICE_SPINNER]: RewardTier.GREAT,
|
||||||
[MoveId.SNOWSCAPE]: ModifierTier.COMMON,
|
[MoveId.SNOWSCAPE]: RewardTier.COMMON,
|
||||||
[MoveId.POUNCE]: ModifierTier.COMMON,
|
[MoveId.POUNCE]: RewardTier.COMMON,
|
||||||
[MoveId.TRAILBLAZE]: ModifierTier.COMMON,
|
[MoveId.TRAILBLAZE]: RewardTier.COMMON,
|
||||||
[MoveId.CHILLING_WATER]: ModifierTier.COMMON,
|
[MoveId.CHILLING_WATER]: RewardTier.COMMON,
|
||||||
[MoveId.HARD_PRESS]: ModifierTier.GREAT,
|
[MoveId.HARD_PRESS]: RewardTier.GREAT,
|
||||||
[MoveId.DRAGON_CHEER]: ModifierTier.COMMON,
|
[MoveId.DRAGON_CHEER]: RewardTier.COMMON,
|
||||||
[MoveId.ALLURING_VOICE]: ModifierTier.GREAT,
|
[MoveId.ALLURING_VOICE]: RewardTier.GREAT,
|
||||||
[MoveId.TEMPER_FLARE]: ModifierTier.GREAT,
|
[MoveId.TEMPER_FLARE]: RewardTier.GREAT,
|
||||||
[MoveId.SUPERCELL_SLAM]: ModifierTier.GREAT,
|
[MoveId.SUPERCELL_SLAM]: RewardTier.GREAT,
|
||||||
[MoveId.PSYCHIC_NOISE]: ModifierTier.GREAT,
|
[MoveId.PSYCHIC_NOISE]: RewardTier.GREAT,
|
||||||
[MoveId.UPPER_HAND]: ModifierTier.COMMON,
|
[MoveId.UPPER_HAND]: RewardTier.COMMON,
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ import { TrainerType } from "#enums/trainer-type";
|
|||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import type { MoveId } from "#enums/move-id";
|
import type { MoveId } from "#enums/move-id";
|
||||||
import { TypeColor, TypeShadow } from "#enums/color";
|
import { TypeColor, TypeShadow } from "#enums/color";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { pokemonFormChanges } from "./pokemon-forms";
|
import { pokemonFormChanges } from "./pokemon-forms";
|
||||||
import { pokemonEvolutions } from "./balance/pokemon-evolutions";
|
import { pokemonEvolutions } from "./balance/pokemon-evolutions";
|
||||||
@ -459,11 +459,11 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
.setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
|
.setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [
|
guaranteedModifierTiers: [
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
],
|
],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
});
|
});
|
||||||
@ -476,12 +476,12 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
.setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
|
.setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
|
||||||
.setCustomModifierRewards({
|
.setCustomModifierRewards({
|
||||||
guaranteedModifierTiers: [
|
guaranteedModifierTiers: [
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
],
|
],
|
||||||
allowLuckUpgrades: false,
|
allowLuckUpgrades: false,
|
||||||
});
|
});
|
||||||
|
@ -41,11 +41,6 @@ import {
|
|||||||
} from "../abilities/apply-ab-attrs";
|
} from "../abilities/apply-ab-attrs";
|
||||||
import { allAbilities, allMoves } from "../data-lists";
|
import { allAbilities, allMoves } from "../data-lists";
|
||||||
import {
|
import {
|
||||||
AttackTypeBoosterModifier,
|
|
||||||
BerryModifier,
|
|
||||||
PokemonHeldItemModifier,
|
|
||||||
PokemonMoveAccuracyBoosterModifier,
|
|
||||||
PokemonMultiHitModifier,
|
|
||||||
PreserveBerryModifier,
|
PreserveBerryModifier,
|
||||||
} from "../../modifier/modifier";
|
} from "../../modifier/modifier";
|
||||||
import type { BattlerIndex } from "#enums/battler-index";
|
import type { BattlerIndex } from "#enums/battler-index";
|
||||||
@ -89,6 +84,10 @@ import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
|
|||||||
import { MultiHitType } from "#enums/MultiHitType";
|
import { MultiHitType } from "#enums/MultiHitType";
|
||||||
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves, invalidSketchMoves } from "./invalid-moves";
|
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves, invalidSketchMoves } from "./invalid-moves";
|
||||||
import { isVirtual, MoveUseMode } from "#enums/move-use-mode";
|
import { isVirtual, MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
import { allHeldItems, applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { berryTypeToHeldItem } from "#app/items/held-items/berry";
|
||||||
|
import { HeldItemCategoryId, HeldItemId, isItemInCategory } from "#enums/held-item-id";
|
||||||
import { ChargingMove, MoveAttrMap, MoveAttrString, MoveKindString, MoveClassMap } from "#app/@types/move-types";
|
import { ChargingMove, MoveAttrMap, MoveAttrString, MoveKindString, MoveClassMap } from "#app/@types/move-types";
|
||||||
import { applyMoveAttrs } from "./apply-attrs";
|
import { applyMoveAttrs } from "./apply-attrs";
|
||||||
import { frenzyMissFunc, getMoveTargets } from "./move-utils";
|
import { frenzyMissFunc, getMoveTargets } from "./move-utils";
|
||||||
@ -771,7 +770,7 @@ export default abstract class Move implements Localizable {
|
|||||||
const isOhko = this.hasAttr("OneHitKOAccuracyAttr");
|
const isOhko = this.hasAttr("OneHitKOAccuracyAttr");
|
||||||
|
|
||||||
if (!isOhko) {
|
if (!isOhko) {
|
||||||
globalScene.applyModifiers(PokemonMoveAccuracyBoosterModifier, user.isPlayer(), user, moveAccuracy);
|
applyHeldItems(ITEM_EFFECT.ACCURACY_BOOSTER, { pokemon: user, moveAccuracy: moveAccuracy });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalScene.arena.weather?.weatherType === WeatherType.FOG) {
|
if (globalScene.arena.weather?.weatherType === WeatherType.FOG) {
|
||||||
@ -808,7 +807,7 @@ export default abstract class Move implements Localizable {
|
|||||||
applyPreAttackAbAttrs("MoveTypeChangeAbAttr", source, target, this, true, typeChangeHolder, typeChangeMovePowerMultiplier);
|
applyPreAttackAbAttrs("MoveTypeChangeAbAttr", source, target, this, true, typeChangeHolder, typeChangeMovePowerMultiplier);
|
||||||
|
|
||||||
const sourceTeraType = source.getTeraType();
|
const sourceTeraType = source.getTeraType();
|
||||||
if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr("MultiHitAttr") && !globalScene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
|
if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr("MultiHitAttr") && !source.heldItemManager.hasItem(HeldItemId.MULTI_LENS)) {
|
||||||
power.value = 60;
|
power.value = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -844,7 +843,11 @@ export default abstract class Move implements Localizable {
|
|||||||
|
|
||||||
if (!this.hasAttr("TypelessAttr")) {
|
if (!this.hasAttr("TypelessAttr")) {
|
||||||
globalScene.arena.applyTags(WeakenMoveTypeTag, simulated, typeChangeHolder.value, power);
|
globalScene.arena.applyTags(WeakenMoveTypeTag, simulated, typeChangeHolder.value, power);
|
||||||
globalScene.applyModifiers(AttackTypeBoosterModifier, source.isPlayer(), source, typeChangeHolder.value, power);
|
applyHeldItems(ITEM_EFFECT.ATTACK_TYPE_BOOST, {
|
||||||
|
pokemon: source,
|
||||||
|
moveType: typeChangeHolder.value,
|
||||||
|
movePower: power,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.getTag(HelpingHandTag)) {
|
if (source.getTag(HelpingHandTag)) {
|
||||||
@ -907,7 +910,7 @@ export default abstract class Move implements Localizable {
|
|||||||
* Returns `true` if this move can be given additional strikes
|
* Returns `true` if this move can be given additional strikes
|
||||||
* by enhancing effects.
|
* by enhancing effects.
|
||||||
* Currently used for {@link https://bulbapedia.bulbagarden.net/wiki/Parental_Bond_(Ability) | Parental Bond}
|
* Currently used for {@link https://bulbapedia.bulbagarden.net/wiki/Parental_Bond_(Ability) | Parental Bond}
|
||||||
* and {@linkcode PokemonMultiHitModifier | Multi-Lens}.
|
* and {@linkcode MultiHitHeldItem | Multi-Lens}.
|
||||||
* @param user The {@linkcode Pokemon} using the move
|
* @param user The {@linkcode Pokemon} using the move
|
||||||
* @param restrictSpread `true` if the enhancing effect
|
* @param restrictSpread `true` if the enhancing effect
|
||||||
* should not affect multi-target moves (default `false`)
|
* should not affect multi-target moves (default `false`)
|
||||||
@ -1558,7 +1561,7 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr {
|
|||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
// first, determine if the hit is coming from multi lens or not
|
// first, determine if the hit is coming from multi lens or not
|
||||||
const lensCount = user.getHeldItems().find(i => i instanceof PokemonMultiHitModifier)?.getStackCount() ?? 0;
|
const lensCount = user.heldItemManager.getStack(HeldItemId.MULTI_LENS);
|
||||||
if (lensCount <= 0) {
|
if (lensCount <= 0) {
|
||||||
// no multi lenses; we can just halve the target's hp and call it a day
|
// no multi lenses; we can just halve the target's hp and call it a day
|
||||||
(args[0] as NumberHolder).value = toDmgValue(target.hp / 2);
|
(args[0] as NumberHolder).value = toDmgValue(target.hp / 2);
|
||||||
@ -2612,35 +2615,33 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const heldItems = this.getTargetHeldItems(target).filter((i) => i.isTransferable);
|
const heldItems = target.heldItemManager.getTransferableHeldItems();
|
||||||
if (!heldItems.length) {
|
if (!heldItems.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD;
|
const stolenItem = heldItems[user.randBattleSeedInt(heldItems.length)];
|
||||||
const highestItemTier = heldItems.map((m) => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is the bang after tier correct?
|
|
||||||
const tierHeldItems = heldItems.filter((m) => m.type.getOrInferTier(poolType) === highestItemTier);
|
if (!globalScene.tryTransferHeldItem(stolenItem, target, user, false)) {
|
||||||
const stolenItem = tierHeldItems[user.randBattleSeedInt(tierHeldItems.length)];
|
|
||||||
if (!globalScene.tryTransferHeldItemModifier(stolenItem, user, false)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:stoleItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name }));
|
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:stoleItem",
|
||||||
|
{ pokemonName: getPokemonNameWithAffix(user),
|
||||||
|
targetName: getPokemonNameWithAffix(target),
|
||||||
|
itemName: allHeldItems[stolenItem].name
|
||||||
|
}
|
||||||
|
));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
|
|
||||||
return globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier
|
|
||||||
&& m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[];
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
const heldItems = this.getTargetHeldItems(target);
|
const heldItems = target.heldItemManager.getTransferableHeldItems();
|
||||||
return heldItems.length ? 5 : 0;
|
return heldItems.length ? 5 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
const heldItems = this.getTargetHeldItems(target);
|
const heldItems = target.heldItemManager.getTransferableHeldItems();
|
||||||
return heldItems.length ? -5 : 0;
|
return heldItems.length ? -5 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2686,10 +2687,10 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
// Considers entire transferrable item pool by default (Knock Off).
|
// Considers entire transferrable item pool by default (Knock Off).
|
||||||
// Otherwise only consider berries (Incinerate).
|
// Otherwise only consider berries (Incinerate).
|
||||||
let heldItems = this.getTargetHeldItems(target).filter(i => i.isTransferable);
|
let heldItems = target.heldItemManager.getTransferableHeldItems();
|
||||||
|
|
||||||
if (this.berriesOnly) {
|
if (this.berriesOnly) {
|
||||||
heldItems = heldItems.filter(m => m instanceof BerryModifier && m.pokemonId === target.id, target.isPlayer());
|
heldItems = heldItems.filter(m => m in Object.values(berryTypeToHeldItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!heldItems.length) {
|
if (!heldItems.length) {
|
||||||
@ -2703,26 +2704,23 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
|||||||
globalScene.updateModifiers(target.isPlayer());
|
globalScene.updateModifiers(target.isPlayer());
|
||||||
|
|
||||||
if (this.berriesOnly) {
|
if (this.berriesOnly) {
|
||||||
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:incineratedItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name }));
|
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:incineratedItem",
|
||||||
|
{ pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: allHeldItems[removedItem].name }));
|
||||||
} else {
|
} else {
|
||||||
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:knockedOffItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name }));
|
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:knockedOffItem",
|
||||||
|
{ pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: allHeldItems[removedItem].name }));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
|
|
||||||
return globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier
|
|
||||||
&& m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[];
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
const heldItems = this.getTargetHeldItems(target);
|
const heldItems = target.getHeldItems();
|
||||||
return heldItems.length ? 5 : 0;
|
return heldItems.length ? 5 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
const heldItems = this.getTargetHeldItems(target);
|
const heldItems = target.getHeldItems();
|
||||||
return heldItems.length ? -5 : 0;
|
return heldItems.length ? -5 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2731,7 +2729,7 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
|||||||
* Attribute that causes targets of the move to eat a berry. Used for Teatime, Stuff Cheeks
|
* Attribute that causes targets of the move to eat a berry. Used for Teatime, Stuff Cheeks
|
||||||
*/
|
*/
|
||||||
export class EatBerryAttr extends MoveEffectAttr {
|
export class EatBerryAttr extends MoveEffectAttr {
|
||||||
protected chosenBerry: BerryModifier;
|
protected chosenBerry: HeldItemId;
|
||||||
constructor(selfTarget: boolean) {
|
constructor(selfTarget: boolean) {
|
||||||
super(selfTarget);
|
super(selfTarget);
|
||||||
}
|
}
|
||||||
@ -2771,9 +2769,8 @@ export class EatBerryAttr extends MoveEffectAttr {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetHeldBerries(target: Pokemon): BerryModifier[] {
|
getTargetHeldBerries(target: Pokemon): HeldItemId[] {
|
||||||
return globalScene.findModifiers(m => m instanceof BerryModifier
|
return target.getHeldItems().filter(m => isItemInCategory(m, HeldItemCategoryId.BERRY));
|
||||||
&& (m as BerryModifier).pokemonId === target.id, target.isPlayer()) as BerryModifier[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reduceBerryModifier(target: Pokemon) {
|
reduceBerryModifier(target: Pokemon) {
|
||||||
@ -2794,10 +2791,10 @@ export class EatBerryAttr extends MoveEffectAttr {
|
|||||||
*/
|
*/
|
||||||
protected eatBerry(consumer: Pokemon, berryOwner: Pokemon = consumer, updateHarvest = consumer === berryOwner) {
|
protected eatBerry(consumer: Pokemon, berryOwner: Pokemon = consumer, updateHarvest = consumer === berryOwner) {
|
||||||
// consumer eats berry, owner triggers unburden and similar effects
|
// consumer eats berry, owner triggers unburden and similar effects
|
||||||
getBerryEffectFunc(this.chosenBerry.berryType)(consumer);
|
getBerryEffectFunc(allHeldItems[this.chosenBerry].berryType)(consumer);
|
||||||
applyPostItemLostAbAttrs("PostItemLostAbAttr", berryOwner, false);
|
applyPostItemLostAbAttrs("PostItemLostAbAttr", berryOwner, false);
|
||||||
applyAbAttrs("HealFromBerryUseAbAttr", consumer, new BooleanHolder(false));
|
applyAbAttrs("HealFromBerryUseAbAttr", consumer, new BooleanHolder(false));
|
||||||
consumer.recordEatenBerry(this.chosenBerry.berryType, updateHarvest);
|
consumer.recordEatenBerry(allHeldItems[this.chosenBerry].berryType, updateHarvest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2836,7 +2833,7 @@ export class StealEatBerryAttr extends EatBerryAttr {
|
|||||||
// pick a random berry and eat it
|
// pick a random berry and eat it
|
||||||
this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)];
|
this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)];
|
||||||
applyPostItemLostAbAttrs("PostItemLostAbAttr", target, false);
|
applyPostItemLostAbAttrs("PostItemLostAbAttr", target, false);
|
||||||
const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name });
|
const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: allHeldItems[this.chosenBerry].name });
|
||||||
globalScene.phaseManager.queueMessage(message);
|
globalScene.phaseManager.queueMessage(message);
|
||||||
this.reduceBerryModifier(target);
|
this.reduceBerryModifier(target);
|
||||||
this.eatBerry(user, target);
|
this.eatBerry(user, target);
|
||||||
@ -6415,9 +6412,6 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear out enemy held item modifiers of the switch out target
|
|
||||||
globalScene.clearEnemyHeldItemModifiers(switchOutTarget);
|
|
||||||
|
|
||||||
if (!allyPokemon?.isActive(true) && switchOutTarget.hp) {
|
if (!allyPokemon?.isActive(true) && switchOutTarget.hp) {
|
||||||
globalScene.phaseManager.pushNew("BattleEndPhase", false);
|
globalScene.phaseManager.pushNew("BattleEndPhase", false);
|
||||||
|
|
||||||
@ -8008,14 +8002,14 @@ const failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Po
|
|||||||
|
|
||||||
const failIfGhostTypeCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => !target.isOfType(PokemonType.GHOST);
|
const failIfGhostTypeCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => !target.isOfType(PokemonType.GHOST);
|
||||||
|
|
||||||
const failIfNoTargetHeldItemsCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.getHeldItems().filter(i => i.isTransferable)?.length > 0;
|
const failIfNoTargetHeldItemsCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.heldItemManager.getTransferableHeldItems().length > 0;
|
||||||
|
|
||||||
const attackedByItemMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
const attackedByItemMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
||||||
const heldItems = target.getHeldItems().filter(i => i.isTransferable);
|
const heldItems = target.heldItemManager.getTransferableHeldItems();
|
||||||
if (heldItems.length === 0) {
|
if (heldItems.length === 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const itemName = heldItems[0]?.type?.name ?? "item";
|
const itemName = allHeldItems[heldItems[0]].name ?? "item";
|
||||||
const message: string = i18next.t("moveTriggers:attackedByItem", { pokemonName: getPokemonNameWithAffix(target), itemName: itemName });
|
const message: string = i18next.t("moveTriggers:attackedByItem", { pokemonName: getPokemonNameWithAffix(target), itemName: itemName });
|
||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
@ -9310,7 +9304,7 @@ export function initMoves() {
|
|||||||
.condition((user, target, move) => !target.status && !target.isSafeguarded(user))
|
.condition((user, target, move) => !target.status && !target.isSafeguarded(user))
|
||||||
.reflectable(),
|
.reflectable(),
|
||||||
new AttackMove(MoveId.KNOCK_OFF, PokemonType.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3)
|
new AttackMove(MoveId.KNOCK_OFF, PokemonType.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getHeldItems().filter(i => i.isTransferable).length > 0 ? 1.5 : 1)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.heldItemManager.getTransferableHeldItems().length > 0 ? 1.5 : 1)
|
||||||
.attr(RemoveHeldItemAttr, false)
|
.attr(RemoveHeldItemAttr, false)
|
||||||
.edgeCase(),
|
.edgeCase(),
|
||||||
// Should not be able to remove held item if user faints due to Rough Skin, Iron Barbs, etc.
|
// Should not be able to remove held item if user faints due to Rough Skin, Iron Barbs, etc.
|
||||||
@ -10032,7 +10026,7 @@ export function initMoves() {
|
|||||||
.condition((user, target, move) => !target.turnData.acted)
|
.condition((user, target, move) => !target.turnData.acted)
|
||||||
.attr(ForceLastAttr),
|
.attr(ForceLastAttr),
|
||||||
new AttackMove(MoveId.ACROBATICS, PokemonType.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5)
|
new AttackMove(MoveId.ACROBATICS, PokemonType.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.getHeldItems().filter(i => i.isTransferable).reduce((v, m) => v + m.stackCount, 0))),
|
.attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.heldItemManager.getTransferableHeldItems().reduce((v, m) => v + user.heldItemManager.getStack(m), 0))),
|
||||||
new StatusMove(MoveId.REFLECT_TYPE, PokemonType.NORMAL, -1, 15, -1, 0, 5)
|
new StatusMove(MoveId.REFLECT_TYPE, PokemonType.NORMAL, -1, 15, -1, 0, 5)
|
||||||
.ignoresSubstitute()
|
.ignoresSubstitute()
|
||||||
.attr(CopyTypeAttr),
|
.attr(CopyTypeAttr),
|
||||||
@ -10781,7 +10775,7 @@ export function initMoves() {
|
|||||||
.attr(EatBerryAttr, true)
|
.attr(EatBerryAttr, true)
|
||||||
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true)
|
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true)
|
||||||
.condition((user) => {
|
.condition((user) => {
|
||||||
const userBerries = globalScene.findModifiers(m => m instanceof BerryModifier, user.isPlayer());
|
const userBerries = user.getHeldItems().filter(m => isItemInCategory(m, HeldItemCategoryId.BERRY));
|
||||||
return userBerries.length > 0;
|
return userBerries.length > 0;
|
||||||
})
|
})
|
||||||
.edgeCase(), // Stuff Cheeks should not be selectable when the user does not have a berry, see wiki
|
.edgeCase(), // Stuff Cheeks should not be selectable when the user does not have a berry, see wiki
|
||||||
|
@ -19,7 +19,7 @@ import i18next from "i18next";
|
|||||||
import type { IEggOptions } from "#app/data/egg";
|
import type { IEggOptions } from "#app/data/egg";
|
||||||
import { EggSourceType } from "#enums/egg-source-types";
|
import { EggSourceType } from "#enums/egg-source-types";
|
||||||
import { EggTier } from "#enums/egg-type";
|
import { EggTier } from "#enums/egg-type";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
setEncounterRewards(
|
setEncounterRewards(
|
||||||
{
|
{
|
||||||
guaranteedModifierTypeFuncs: [modifierTypes.SACRED_ASH],
|
guaranteedModifierTypeFuncs: [modifierTypes.SACRED_ASH],
|
||||||
guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA],
|
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ULTRA],
|
||||||
fillRemaining: true,
|
fillRemaining: true,
|
||||||
},
|
},
|
||||||
[eggOptions],
|
[eggOptions],
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
generateModifierType,
|
getPartyBerries,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
setEncounterRewards,
|
setEncounterRewards,
|
||||||
@ -9,40 +9,47 @@ import {
|
|||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { EnemyPokemon } from "#app/field/pokemon";
|
import { EnemyPokemon } from "#app/field/pokemon";
|
||||||
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
||||||
import type { BerryModifierType, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import { PersistentModifierRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
|
||||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { BerryModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { randInt } from "#app/utils/common";
|
import { randInt } from "#app/utils/common";
|
||||||
import { BattlerIndex } from "#enums/battler-index";
|
import { BattlerIndex } from "#enums/battler-index";
|
||||||
import {
|
import { catchPokemon, getHighestLevelPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
applyModifierTypeToPlayerPokemon,
|
|
||||||
catchPokemon,
|
|
||||||
getHighestLevelPlayerPokemon,
|
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
|
||||||
import { TrainerSlot } from "#enums/trainer-slot";
|
import { TrainerSlot } from "#enums/trainer-slot";
|
||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import type HeldModifierConfig from "#app/@types/held-modifier-config";
|
|
||||||
import type { BerryType } from "#enums/berry-type";
|
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
import type { HeldItemConfiguration } from "#app/items/held-item-data-types";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { HeldItemRequirement } from "../mystery-encounter-requirements";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
const namespace = "mysteryEncounters/absoluteAvarice";
|
const namespace = "mysteryEncounters/absoluteAvarice";
|
||||||
|
|
||||||
|
function berrySprite(spriteKey: string, x: number, y: number): MysteryEncounterSpriteConfig {
|
||||||
|
return {
|
||||||
|
spriteKey: spriteKey,
|
||||||
|
fileRoot: "items",
|
||||||
|
isItem: true,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
hidden: true,
|
||||||
|
disableAnimation: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Absolute Avarice encounter.
|
* Absolute Avarice encounter.
|
||||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3805 | GitHub Issue #3805}
|
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3805 | GitHub Issue #3805}
|
||||||
@ -53,7 +60,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
)
|
)
|
||||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||||
.withSceneWaveRangeRequirement(20, 180)
|
.withSceneWaveRangeRequirement(20, 180)
|
||||||
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 6)) // Must have at least 6 berries to spawn
|
.withSceneRequirement(new HeldItemRequirement(HeldItemCategoryId.BERRY, 6)) // Must have at least 6 berries to spawn
|
||||||
.withFleeAllowed(false)
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
@ -74,105 +81,17 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
repeat: true,
|
repeat: true,
|
||||||
x: -5,
|
x: -5,
|
||||||
},
|
},
|
||||||
{
|
berrySprite("lum_berry", 7, -14),
|
||||||
spriteKey: "lum_berry",
|
berrySprite("salac_berry", 2, 4),
|
||||||
fileRoot: "items",
|
berrySprite("lansat_berry", 32, 5),
|
||||||
isItem: true,
|
berrySprite("liechi_berry", 6, -5),
|
||||||
x: 7,
|
berrySprite("sitrus_berry", 7, 8),
|
||||||
y: -14,
|
berrySprite("enigma_berry", 26, -4),
|
||||||
hidden: true,
|
berrySprite("leppa_berry", 16, -27),
|
||||||
disableAnimation: true,
|
berrySprite("petaya_berry", 30, -17),
|
||||||
},
|
berrySprite("ganlon_berry", 16, -11),
|
||||||
{
|
berrySprite("apicot_berry", 14, -2),
|
||||||
spriteKey: "salac_berry",
|
berrySprite("starf_berry", 18, 9),
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 2,
|
|
||||||
y: 4,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "lansat_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 32,
|
|
||||||
y: 5,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "liechi_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 6,
|
|
||||||
y: -5,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "sitrus_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 7,
|
|
||||||
y: 8,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "enigma_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 26,
|
|
||||||
y: -4,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "leppa_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 16,
|
|
||||||
y: -27,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "petaya_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 30,
|
|
||||||
y: -17,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "ganlon_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 16,
|
|
||||||
y: -11,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "apicot_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 14,
|
|
||||||
y: -2,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "starf_berry",
|
|
||||||
fileRoot: "items",
|
|
||||||
isItem: true,
|
|
||||||
x: 18,
|
|
||||||
y: 9,
|
|
||||||
hidden: true,
|
|
||||||
disableAnimation: true,
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
.withHideWildIntroMessage(true)
|
.withHideWildIntroMessage(true)
|
||||||
.withAutoHideIntroVisuals(false)
|
.withAutoHideIntroVisuals(false)
|
||||||
@ -191,35 +110,17 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
globalScene.loadSe("PRSFX- Bug Bite", "battle_anims", "PRSFX- Bug Bite.wav");
|
globalScene.loadSe("PRSFX- Bug Bite", "battle_anims", "PRSFX- Bug Bite.wav");
|
||||||
globalScene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
|
globalScene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
|
||||||
|
|
||||||
// Get all player berry items, remove from party, and store reference
|
// Get all berries in party, with references to the pokemon
|
||||||
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
const berryItems = getPartyBerries();
|
||||||
|
|
||||||
// Sort berries by party member ID to more easily re-add later if necessary
|
encounter.misc.berryItemsMap = berryItems;
|
||||||
const berryItemsMap = new Map<number, BerryModifier[]>();
|
|
||||||
globalScene.getPlayerParty().forEach(pokemon => {
|
// Adds stolen berries to the Greedent item configuration
|
||||||
const pokemonBerries = berryItems.filter(b => b.pokemonId === pokemon.id);
|
const bossHeldItemConfig: HeldItemConfiguration = [];
|
||||||
if (pokemonBerries?.length > 0) {
|
berryItems.forEach(map => {
|
||||||
berryItemsMap.set(pokemon.id, pokemonBerries);
|
bossHeldItemConfig.push({ entry: map.item, count: 1 });
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
encounter.misc = { berryItemsMap };
|
|
||||||
|
|
||||||
// Generates copies of the stolen berries to put on the Greedent
|
|
||||||
const bossModifierConfigs: HeldModifierConfig[] = [];
|
|
||||||
berryItems.forEach(berryMod => {
|
|
||||||
// Can't define stack count on a ModifierType, have to just create separate instances for each stack
|
|
||||||
// Overflow berries will be "lost" on the boss, but it's un-catchable anyway
|
|
||||||
for (let i = 0; i < berryMod.stackCount; i++) {
|
|
||||||
const modifierType = generateModifierType(modifierTypes.BERRY, [
|
|
||||||
berryMod.berryType,
|
|
||||||
]) as PokemonHeldItemModifierType;
|
|
||||||
bossModifierConfigs.push({ modifier: modifierType });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Do NOT remove the real berries yet or else it will be persisted in the session data
|
|
||||||
|
|
||||||
// +1 SpDef below wave 50, SpDef and Speed otherwise
|
// +1 SpDef below wave 50, SpDef and Speed otherwise
|
||||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] =
|
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] =
|
||||||
globalScene.currentBattle.waveIndex < 50 ? [Stat.SPDEF] : [Stat.SPDEF, Stat.SPD];
|
globalScene.currentBattle.waveIndex < 50 ? [Stat.SPDEF] : [Stat.SPDEF, Stat.SPD];
|
||||||
@ -234,7 +135,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
bossSegments: 3,
|
bossSegments: 3,
|
||||||
shiny: false, // Shiny lock because of consistency issues between the different options
|
shiny: false, // Shiny lock because of consistency issues between the different options
|
||||||
moveSet: [MoveId.THRASH, MoveId.CRUNCH, MoveId.BODY_PRESS, MoveId.SLACK_OFF],
|
moveSet: [MoveId.THRASH, MoveId.CRUNCH, MoveId.BODY_PRESS, MoveId.SLACK_OFF],
|
||||||
modifierConfigs: bossModifierConfigs,
|
heldItemConfig: bossHeldItemConfig,
|
||||||
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||||
queueEncounterMessage(`${namespace}:option.1.boss_enraged`);
|
queueEncounterMessage(`${namespace}:option.1.boss_enraged`);
|
||||||
@ -261,9 +162,9 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
|
|
||||||
// Remove the berries from the party
|
// Remove the berries from the party
|
||||||
// Session has been safely saved at this point, so data won't be lost
|
// Session has been safely saved at this point, so data won't be lost
|
||||||
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
const berryItems = getPartyBerries();
|
||||||
berryItems.forEach(berryMod => {
|
berryItems.forEach(map => {
|
||||||
globalScene.removeModifier(berryMod);
|
map.pokemon.heldItemManager.remove(map.item);
|
||||||
});
|
});
|
||||||
|
|
||||||
globalScene.updateModifiers(true);
|
globalScene.updateModifiers(true);
|
||||||
@ -286,19 +187,14 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
|
|
||||||
// Provides 1x Reviver Seed to each party member at end of battle
|
// Provides 1x Reviver Seed to each party member at end of battle
|
||||||
const revSeed = generateModifierType(modifierTypes.REVIVER_SEED);
|
|
||||||
encounter.setDialogueToken(
|
encounter.setDialogueToken(
|
||||||
"foodReward",
|
"foodReward",
|
||||||
revSeed?.name ?? i18next.t("modifierType:ModifierType.REVIVER_SEED.name"),
|
allHeldItems[HeldItemId.REVIVER_SEED].name ?? i18next.t("modifierType:ModifierType.REVIVER_SEED.name"),
|
||||||
);
|
);
|
||||||
const givePartyPokemonReviverSeeds = () => {
|
const givePartyPokemonReviverSeeds = () => {
|
||||||
const party = globalScene.getPlayerParty();
|
const party = globalScene.getPlayerParty();
|
||||||
party.forEach(p => {
|
party.forEach(p => {
|
||||||
const heldItems = p.getHeldItems();
|
p.heldItemManager.add(HeldItemId.REVIVER_SEED);
|
||||||
if (revSeed && !heldItems.some(item => item instanceof PokemonInstantReviveModifier)) {
|
|
||||||
const seedModifier = revSeed.newModifier(p);
|
|
||||||
globalScene.addModifier(seedModifier, false, false, false, true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
queueEncounterMessage(`${namespace}:option.1.food_stash`);
|
queueEncounterMessage(`${namespace}:option.1.food_stash`);
|
||||||
};
|
};
|
||||||
@ -334,19 +230,16 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
// Returns 2/5 of the berries stolen to each Pokemon
|
// Returns 2/5 of the berries stolen to each Pokemon
|
||||||
const party = globalScene.getPlayerParty();
|
const party = globalScene.getPlayerParty();
|
||||||
party.forEach(pokemon => {
|
party.forEach(pokemon => {
|
||||||
const stolenBerries: BerryModifier[] = berryMap.get(pokemon.id);
|
// TODO: is this check legal?
|
||||||
const berryTypesAsArray: BerryType[] = [];
|
const stolenBerries = berryMap.filter(map => map.pokemon === pokemon);
|
||||||
stolenBerries?.forEach(bMod => berryTypesAsArray.push(...new Array(bMod.stackCount).fill(bMod.berryType)));
|
const returnedBerryCount = Math.floor(((stolenBerries.length ?? 0) * 2) / 5);
|
||||||
const returnedBerryCount = Math.floor(((berryTypesAsArray.length ?? 0) * 2) / 5);
|
|
||||||
|
|
||||||
if (returnedBerryCount > 0) {
|
if (returnedBerryCount > 0) {
|
||||||
for (let i = 0; i < returnedBerryCount; i++) {
|
for (let i = 0; i < returnedBerryCount; i++) {
|
||||||
// Shuffle remaining berry types and pop
|
// Shuffle remaining berry types and pop
|
||||||
Phaser.Math.RND.shuffle(berryTypesAsArray);
|
Phaser.Math.RND.shuffle(stolenBerries);
|
||||||
const randBerryType = berryTypesAsArray.pop();
|
const randBerryType = stolenBerries.pop();
|
||||||
|
pokemon.heldItemManager.add(randBerryType);
|
||||||
const berryModType = generateModifierType(modifierTypes.BERRY, [randBerryType]) as BerryModifierType;
|
|
||||||
applyModifierTypeToPlayerPokemon(pokemon, berryModType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
generateModifierType,
|
|
||||||
generateModifierTypeOption,
|
generateModifierTypeOption,
|
||||||
getRandomEncounterSpecies,
|
getRandomEncounterSpecies,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
@ -11,7 +10,7 @@ import {
|
|||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { BerryModifierType, ModifierTypeOption } from "#app/modifier/modifier-type";
|
import type { ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||||
import { regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
import { regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
||||||
@ -26,18 +25,17 @@ import { getPokemonNameWithAffix } from "#app/messages";
|
|||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import {
|
import {
|
||||||
applyModifierTypeToPlayerPokemon,
|
|
||||||
getEncounterPokemonLevelForWave,
|
getEncounterPokemonLevelForWave,
|
||||||
getHighestStatPlayerPokemon,
|
getHighestStatPlayerPokemon,
|
||||||
getSpriteKeysFromPokemon,
|
getSpriteKeysFromPokemon,
|
||||||
STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER,
|
STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import { BerryModifier } from "#app/modifier/modifier";
|
|
||||||
import i18next from "#app/plugins/i18n";
|
import i18next from "#app/plugins/i18n";
|
||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
import { berryTypeToHeldItem } from "#app/items/held-items/berry";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/berriesAbound";
|
const namespace = "mysteryEncounters/berriesAbound";
|
||||||
@ -312,35 +310,17 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
|
|
||||||
function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
|
function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
|
||||||
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !Number.isNaN(Number(s))).length) as BerryType;
|
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !Number.isNaN(Number(s))).length) as BerryType;
|
||||||
const berry = generateModifierType(modifierTypes.BERRY, [berryType]) as BerryModifierType;
|
const berry = berryTypeToHeldItem[berryType];
|
||||||
|
|
||||||
const party = globalScene.getPlayerParty();
|
const party = globalScene.getPlayerParty();
|
||||||
|
|
||||||
// Will try to apply to prioritized pokemon first, then do normal application method if it fails
|
// Will give the berry to a Pokemon, starting from the prioritized one
|
||||||
if (prioritizedPokemon) {
|
if (prioritizedPokemon?.heldItemManager.add(berry)) {
|
||||||
const heldBerriesOfType = globalScene.findModifier(
|
return;
|
||||||
m =>
|
|
||||||
m instanceof BerryModifier &&
|
|
||||||
m.pokemonId === prioritizedPokemon.id &&
|
|
||||||
(m as BerryModifier).berryType === berryType,
|
|
||||||
true,
|
|
||||||
) as BerryModifier;
|
|
||||||
|
|
||||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount()) {
|
|
||||||
applyModifierTypeToPlayerPokemon(prioritizedPokemon, berry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over the party until berry was successfully given
|
|
||||||
for (const pokemon of party) {
|
for (const pokemon of party) {
|
||||||
const heldBerriesOfType = globalScene.findModifier(
|
if (pokemon.heldItemManager.add(berry)) {
|
||||||
m => m instanceof BerryModifier && m.pokemonId === pokemon.id && (m as BerryModifier).berryType === berryType,
|
|
||||||
true,
|
|
||||||
) as BerryModifier;
|
|
||||||
|
|
||||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount()) {
|
|
||||||
applyModifierTypeToPlayerPokemon(pokemon, berry);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
generateModifierType,
|
|
||||||
generateModifierTypeOption,
|
generateModifierTypeOption,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
@ -31,28 +30,22 @@ import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"
|
|||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import {
|
import {
|
||||||
AttackTypeBoosterHeldItemTypeRequirement,
|
|
||||||
CombinationPokemonRequirement,
|
CombinationPokemonRequirement,
|
||||||
HeldItemRequirement,
|
HeldItemRequirement,
|
||||||
TypeRequirement,
|
TypeRequirement,
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import type { AttackTypeBoosterModifierType, ModifierTypeOption } from "#app/modifier/modifier-type";
|
import type { ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
import { GigantamaxAccessModifier, MegaEvolutionAccessModifier } from "#app/modifier/modifier";
|
||||||
import {
|
|
||||||
AttackTypeBoosterModifier,
|
|
||||||
BypassSpeedChanceModifier,
|
|
||||||
ContactHeldItemTransferChanceModifier,
|
|
||||||
GigantamaxAccessModifier,
|
|
||||||
MegaEvolutionAccessModifier,
|
|
||||||
} from "#app/modifier/modifier";
|
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
||||||
import { allMoves } from "#app/data/data-lists";
|
import { allMoves } from "#app/data/data-lists";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/bugTypeSuperfan";
|
const namespace = "mysteryEncounters/bugTypeSuperfan";
|
||||||
@ -143,6 +136,8 @@ const POOL_3_POKEMON: { species: SpeciesId; formIndex?: number }[] = [
|
|||||||
|
|
||||||
const POOL_4_POKEMON = [SpeciesId.GENESECT, SpeciesId.SLITHER_WING, SpeciesId.BUZZWOLE, SpeciesId.PHEROMOSA];
|
const POOL_4_POKEMON = [SpeciesId.GENESECT, SpeciesId.SLITHER_WING, SpeciesId.BUZZWOLE, SpeciesId.PHEROMOSA];
|
||||||
|
|
||||||
|
const REQUIRED_ITEMS = [HeldItemId.QUICK_CLAW, HeldItemId.GRIP_CLAW, HeldItemId.SILVER_POWDER];
|
||||||
|
|
||||||
const PHYSICAL_TUTOR_MOVES = [
|
const PHYSICAL_TUTOR_MOVES = [
|
||||||
MoveId.MEGAHORN,
|
MoveId.MEGAHORN,
|
||||||
MoveId.ATTACK_ORDER,
|
MoveId.ATTACK_ORDER,
|
||||||
@ -186,8 +181,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
.withPrimaryPokemonRequirement(
|
.withPrimaryPokemonRequirement(
|
||||||
CombinationPokemonRequirement.Some(
|
CombinationPokemonRequirement.Some(
|
||||||
// Must have at least 1 Bug type on team, OR have a bug item somewhere on the team
|
// Must have at least 1 Bug type on team, OR have a bug item somewhere on the team
|
||||||
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1),
|
new HeldItemRequirement(REQUIRED_ITEMS, 1),
|
||||||
new AttackTypeBoosterHeldItemTypeRequirement(PokemonType.BUG, 1),
|
|
||||||
new TypeRequirement(PokemonType.BUG, false, 1),
|
new TypeRequirement(PokemonType.BUG, false, 1),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -259,13 +253,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const requiredItems = [
|
const requiredItemString = REQUIRED_ITEMS.map(m => allHeldItems[m].name ?? "unknown").join("/");
|
||||||
generateModifierType(modifierTypes.QUICK_CLAW),
|
|
||||||
generateModifierType(modifierTypes.GRIP_CLAW),
|
|
||||||
generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [PokemonType.BUG]),
|
|
||||||
];
|
|
||||||
|
|
||||||
const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/");
|
|
||||||
encounter.setDialogueToken("requiredBugItems", requiredItemString);
|
encounter.setDialogueToken("requiredBugItems", requiredItemString);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -415,8 +403,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
.withPrimaryPokemonRequirement(
|
.withPrimaryPokemonRequirement(
|
||||||
CombinationPokemonRequirement.Some(
|
CombinationPokemonRequirement.Some(
|
||||||
// Meets one or both of the below reqs
|
// Meets one or both of the below reqs
|
||||||
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1),
|
new HeldItemRequirement(REQUIRED_ITEMS, 1),
|
||||||
new AttackTypeBoosterHeldItemTypeRequirement(PokemonType.BUG, 1),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.withDialogue({
|
.withDialogue({
|
||||||
@ -439,25 +426,19 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
|
|
||||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||||
// Get Pokemon held items and filter for valid ones
|
// Get Pokemon held items and filter for valid ones
|
||||||
const validItems = pokemon.getHeldItems().filter(item => {
|
const validItems = pokemon.heldItemManager.getTransferableHeldItems().filter(item => {
|
||||||
return (
|
item in REQUIRED_ITEMS;
|
||||||
(item instanceof BypassSpeedChanceModifier ||
|
|
||||||
item instanceof ContactHeldItemTransferChanceModifier ||
|
|
||||||
(item instanceof AttackTypeBoosterModifier &&
|
|
||||||
(item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)) &&
|
|
||||||
item.isTransferable
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return validItems.map((modifier: PokemonHeldItemModifier) => {
|
return validItems.map((item: HeldItemId) => {
|
||||||
const option: OptionSelectItem = {
|
const option: OptionSelectItem = {
|
||||||
label: modifier.type.name,
|
label: allHeldItems[item].name,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
// Pokemon and item selected
|
// Pokemon and item selected
|
||||||
encounter.setDialogueToken("selectedItem", modifier.type.name);
|
encounter.setDialogueToken("selectedItem", allHeldItems[item].name);
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
chosenPokemon: pokemon,
|
chosenPokemon: pokemon,
|
||||||
chosenModifier: modifier,
|
chosenItem: item,
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -469,12 +450,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
const selectableFilter = (pokemon: Pokemon) => {
|
const selectableFilter = (pokemon: Pokemon) => {
|
||||||
// If pokemon has valid item, it can be selected
|
// If pokemon has valid item, it can be selected
|
||||||
const hasValidItem = pokemon.getHeldItems().some(item => {
|
const hasValidItem = pokemon.getHeldItems().some(item => {
|
||||||
return (
|
item in REQUIRED_ITEMS;
|
||||||
item instanceof BypassSpeedChanceModifier ||
|
|
||||||
item instanceof ContactHeldItemTransferChanceModifier ||
|
|
||||||
(item instanceof AttackTypeBoosterModifier &&
|
|
||||||
(item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
if (!hasValidItem) {
|
if (!hasValidItem) {
|
||||||
return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null;
|
return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null;
|
||||||
@ -491,10 +467,10 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
||||||
|
|
||||||
chosenPokemon.loseHeldItem(modifier, false);
|
chosenPokemon.loseHeldItem(modifier, false);
|
||||||
globalScene.updateModifiers(true, true);
|
globalScene.updateModifiers(true);
|
||||||
|
|
||||||
const bugNet = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
|
const bugNet = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
|
||||||
bugNet.type.tier = ModifierTier.ROGUE;
|
bugNet.type.tier = RewardTier.ROGUE;
|
||||||
|
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTypeOptions: [bugNet],
|
guaranteedModifierTypeOptions: [bugNet],
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
generateModifierType,
|
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
loadCustomMovesForEncounter,
|
loadCustomMovesForEncounter,
|
||||||
@ -11,9 +10,7 @@ import {
|
|||||||
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
||||||
import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
||||||
import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -24,10 +21,7 @@ import { SpeciesId } from "#enums/species-id";
|
|||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
import {
|
import { applyAbilityOverrideToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
applyAbilityOverrideToPokemon,
|
|
||||||
applyModifierTypeToPlayerPokemon,
|
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
@ -38,8 +32,6 @@ import i18next from "i18next";
|
|||||||
import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
||||||
import { BerryModifier } from "#app/modifier/modifier";
|
|
||||||
import { BerryType } from "#enums/berry-type";
|
|
||||||
import { BattlerIndex } from "#enums/battler-index";
|
import { BattlerIndex } from "#enums/battler-index";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
||||||
@ -49,7 +41,10 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
|||||||
import { EncounterAnim } from "#enums/encounter-anims";
|
import { EncounterAnim } from "#enums/encounter-anims";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
import { allAbilities, modifierTypes } from "#app/data/data-lists";
|
import { allAbilities } from "#app/data/data-lists";
|
||||||
|
import { HeldItemCategoryId, HeldItemId, isItemInCategory } from "#enums/held-item-id";
|
||||||
|
import { getHeldItemTier } from "#app/items/held-item-tiers";
|
||||||
|
import { assignItemsFromConfiguration } from "#app/items/held-item-pool";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/clowningAround";
|
const namespace = "mysteryEncounters/clowningAround";
|
||||||
@ -283,16 +278,16 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
|
|||||||
|
|
||||||
const party = globalScene.getPlayerParty();
|
const party = globalScene.getPlayerParty();
|
||||||
let mostHeldItemsPokemon = party[0];
|
let mostHeldItemsPokemon = party[0];
|
||||||
let count = mostHeldItemsPokemon
|
let count = mostHeldItemsPokemon.heldItemManager
|
||||||
.getHeldItems()
|
.getTransferableHeldItems()
|
||||||
.filter(m => m.isTransferable && !(m instanceof BerryModifier))
|
.filter(m => !isItemInCategory(m, HeldItemCategoryId.BERRY))
|
||||||
.reduce((v, m) => v + m.stackCount, 0);
|
.reduce((v, m) => v + mostHeldItemsPokemon.heldItemManager.getStack(m), 0);
|
||||||
|
|
||||||
for (const pokemon of party) {
|
for (const pokemon of party) {
|
||||||
const nextCount = pokemon
|
const nextCount = pokemon.heldItemManager
|
||||||
.getHeldItems()
|
.getTransferableHeldItems()
|
||||||
.filter(m => m.isTransferable && !(m instanceof BerryModifier))
|
.filter(m => !isItemInCategory(m, HeldItemCategoryId.BERRY))
|
||||||
.reduce((v, m) => v + m.stackCount, 0);
|
.reduce((v, m) => v + pokemon.heldItemManager.getStack(m), 0);
|
||||||
if (nextCount > count) {
|
if (nextCount > count) {
|
||||||
mostHeldItemsPokemon = pokemon;
|
mostHeldItemsPokemon = pokemon;
|
||||||
count = nextCount;
|
count = nextCount;
|
||||||
@ -301,16 +296,31 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
|
|||||||
|
|
||||||
encounter.setDialogueToken("switchPokemon", mostHeldItemsPokemon.getNameToRender());
|
encounter.setDialogueToken("switchPokemon", mostHeldItemsPokemon.getNameToRender());
|
||||||
|
|
||||||
const items = mostHeldItemsPokemon.getHeldItems();
|
const items = mostHeldItemsPokemon.heldItemManager
|
||||||
|
.getTransferableHeldItems()
|
||||||
|
.filter(m => !isItemInCategory(m, HeldItemCategoryId.BERRY));
|
||||||
|
|
||||||
// Shuffles Berries (if they have any)
|
// Shuffles Berries (if they have any)
|
||||||
|
const oldBerries = mostHeldItemsPokemon.heldItemManager
|
||||||
|
.getHeldItems()
|
||||||
|
.filter(m => isItemInCategory(m, HeldItemCategoryId.BERRY));
|
||||||
|
|
||||||
let numBerries = 0;
|
let numBerries = 0;
|
||||||
for (const m of items.filter(m => m instanceof BerryModifier)) {
|
for (const berry of oldBerries) {
|
||||||
numBerries += m.stackCount;
|
const stack = mostHeldItemsPokemon.heldItemManager.getStack(berry);
|
||||||
globalScene.removeModifier(m);
|
numBerries += stack;
|
||||||
|
mostHeldItemsPokemon.heldItemManager.remove(berry, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
generateItemsOfTier(mostHeldItemsPokemon, numBerries, "Berries");
|
assignItemsFromConfiguration(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
entry: HeldItemCategoryId.BERRY,
|
||||||
|
count: numBerries,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mostHeldItemsPokemon,
|
||||||
|
);
|
||||||
|
|
||||||
// Shuffle Transferable held items in the same tier (only shuffles Ultra and Rogue atm)
|
// Shuffle Transferable held items in the same tier (only shuffles Ultra and Rogue atm)
|
||||||
// For the purpose of this ME, Soothe Bells and Lucky Eggs are counted as Ultra tier
|
// For the purpose of this ME, Soothe Bells and Lucky Eggs are counted as Ultra tier
|
||||||
@ -318,20 +328,36 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
|
|||||||
let numUltra = 0;
|
let numUltra = 0;
|
||||||
let numRogue = 0;
|
let numRogue = 0;
|
||||||
|
|
||||||
for (const m of items.filter(m => m.isTransferable && !(m instanceof BerryModifier))) {
|
for (const m of items) {
|
||||||
const type = m.type.withTierFromPool(ModifierPoolType.PLAYER, party);
|
const tier = getHeldItemTier(m) ?? RewardTier.ULTRA;
|
||||||
const tier = type.tier ?? ModifierTier.ULTRA;
|
const stack = mostHeldItemsPokemon.heldItemManager.getStack(m);
|
||||||
if (type.id === "GOLDEN_EGG" || tier === ModifierTier.ROGUE) {
|
if (tier === RewardTier.ROGUE) {
|
||||||
numRogue += m.stackCount;
|
numRogue += stack;
|
||||||
globalScene.removeModifier(m);
|
} else if (tier === RewardTier.ULTRA) {
|
||||||
} else if (type.id === "LUCKY_EGG" || type.id === "SOOTHE_BELL" || tier === ModifierTier.ULTRA) {
|
numUltra += stack;
|
||||||
numUltra += m.stackCount;
|
|
||||||
globalScene.removeModifier(m);
|
|
||||||
}
|
}
|
||||||
|
mostHeldItemsPokemon.heldItemManager.remove(m, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
generateItemsOfTier(mostHeldItemsPokemon, numUltra, ModifierTier.ULTRA);
|
assignItemsFromConfiguration(
|
||||||
generateItemsOfTier(mostHeldItemsPokemon, numRogue, ModifierTier.ROGUE);
|
[
|
||||||
|
{
|
||||||
|
entry: ultraPool,
|
||||||
|
count: numUltra,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mostHeldItemsPokemon,
|
||||||
|
);
|
||||||
|
|
||||||
|
assignItemsFromConfiguration(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
entry: roguePool,
|
||||||
|
count: numRogue,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mostHeldItemsPokemon,
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.withOptionPhase(async () => {
|
.withOptionPhase(async () => {
|
||||||
leaveEncounterWithoutBattle(true);
|
leaveEncounterWithoutBattle(true);
|
||||||
@ -487,68 +513,21 @@ function onYesAbilitySwap(resolve) {
|
|||||||
selectPokemonForOption(onPokemonSelected, onPokemonNotSelected);
|
selectPokemonForOption(onPokemonSelected, onPokemonNotSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateItemsOfTier(pokemon: PlayerPokemon, numItems: number, tier: ModifierTier | "Berries") {
|
const ultraPool = [
|
||||||
// These pools have to be defined at runtime so that modifierTypes exist
|
{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 1 },
|
||||||
// Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon
|
{ entry: HeldItemId.REVIVER_SEED, weight: 1 },
|
||||||
// This is to prevent "over-generating" a random item of a certain type during item swaps
|
{ entry: HeldItemId.GOLDEN_PUNCH, weight: 1 },
|
||||||
const ultraPool = [
|
{ entry: HeldItemId.QUICK_CLAW, weight: 1 },
|
||||||
[modifierTypes.REVIVER_SEED, 1],
|
{ entry: HeldItemId.WIDE_LENS, weight: 1 },
|
||||||
[modifierTypes.GOLDEN_PUNCH, 5],
|
];
|
||||||
[modifierTypes.ATTACK_TYPE_BOOSTER, 99],
|
|
||||||
[modifierTypes.QUICK_CLAW, 3],
|
|
||||||
[modifierTypes.WIDE_LENS, 3],
|
|
||||||
];
|
|
||||||
|
|
||||||
const roguePool = [
|
const roguePool = [
|
||||||
[modifierTypes.LEFTOVERS, 4],
|
{ entry: HeldItemId.LEFTOVERS, weight: 1 },
|
||||||
[modifierTypes.SHELL_BELL, 4],
|
{ entry: HeldItemId.SHELL_BELL, weight: 1 },
|
||||||
[modifierTypes.SOUL_DEW, 10],
|
{ entry: HeldItemId.SOUL_DEW, weight: 1 },
|
||||||
[modifierTypes.SCOPE_LENS, 1],
|
{ entry: HeldItemId.SCOPE_LENS, weight: 1 },
|
||||||
[modifierTypes.BATON, 1],
|
{ entry: HeldItemId.BATON, weight: 1 },
|
||||||
[modifierTypes.FOCUS_BAND, 5],
|
{ entry: HeldItemId.FOCUS_BAND, weight: 1 },
|
||||||
[modifierTypes.KINGS_ROCK, 3],
|
{ entry: HeldItemId.KINGS_ROCK, weight: 1 },
|
||||||
[modifierTypes.GRIP_CLAW, 5],
|
{ entry: HeldItemId.GRIP_CLAW, weight: 1 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const berryPool = [
|
|
||||||
[BerryType.APICOT, 3],
|
|
||||||
[BerryType.ENIGMA, 2],
|
|
||||||
[BerryType.GANLON, 3],
|
|
||||||
[BerryType.LANSAT, 3],
|
|
||||||
[BerryType.LEPPA, 2],
|
|
||||||
[BerryType.LIECHI, 3],
|
|
||||||
[BerryType.LUM, 2],
|
|
||||||
[BerryType.PETAYA, 3],
|
|
||||||
[BerryType.SALAC, 2],
|
|
||||||
[BerryType.SITRUS, 2],
|
|
||||||
[BerryType.STARF, 3],
|
|
||||||
];
|
|
||||||
|
|
||||||
let pool: any[];
|
|
||||||
if (tier === "Berries") {
|
|
||||||
pool = berryPool;
|
|
||||||
} else {
|
|
||||||
pool = tier === ModifierTier.ULTRA ? ultraPool : roguePool;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < numItems; i++) {
|
|
||||||
if (pool.length === 0) {
|
|
||||||
// Stop generating new items if somehow runs out of items to spawn
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const randIndex = randSeedInt(pool.length);
|
|
||||||
const newItemType = pool[randIndex];
|
|
||||||
let newMod: PokemonHeldItemModifierType;
|
|
||||||
if (tier === "Berries") {
|
|
||||||
newMod = generateModifierType(modifierTypes.BERRY, [newItemType[0]]) as PokemonHeldItemModifierType;
|
|
||||||
} else {
|
|
||||||
newMod = generateModifierType(newItemType[0]) as PokemonHeldItemModifierType;
|
|
||||||
}
|
|
||||||
applyModifierTypeToPlayerPokemon(pokemon, newMod);
|
|
||||||
// Decrement max stacks and remove from pool if at max
|
|
||||||
newItemType[1]--;
|
|
||||||
if (newItemType[1] <= 0) {
|
|
||||||
pool.splice(randIndex, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -16,10 +16,9 @@ import {
|
|||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
|
import type { HeldItemConfiguration } from "#app/items/held-item-data-types";
|
||||||
|
|
||||||
/** i18n namespace for encounter */
|
/** i18n namespace for encounter */
|
||||||
const namespace = "mysteryEncounters/darkDeal";
|
const namespace = "mysteryEncounters/darkDeal";
|
||||||
@ -149,7 +148,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
|
|||||||
const removedPokemon = getRandomPlayerPokemon(true, false, true);
|
const removedPokemon = getRandomPlayerPokemon(true, false, true);
|
||||||
|
|
||||||
// Get all the pokemon's held items
|
// Get all the pokemon's held items
|
||||||
const modifiers = removedPokemon.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier));
|
const itemConfig = removedPokemon.heldItemManager.generateHeldItemConfiguration();
|
||||||
globalScene.removePokemonFromPlayerParty(removedPokemon);
|
globalScene.removePokemonFromPlayerParty(removedPokemon);
|
||||||
|
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
@ -158,7 +157,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
|
|||||||
// Store removed pokemon types
|
// Store removed pokemon types
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
removedTypes: removedPokemon.getTypes(),
|
removedTypes: removedPokemon.getTypes(),
|
||||||
modifiers,
|
itemConfig: itemConfig,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.withOptionPhase(async () => {
|
.withOptionPhase(async () => {
|
||||||
@ -176,7 +175,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
|
|||||||
bossTypes = singleTypeChallenges.map(c => (c.value - 1) as PokemonType);
|
bossTypes = singleTypeChallenges.map(c => (c.value - 1) as PokemonType);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bossModifiers: PokemonHeldItemModifier[] = encounter.misc.modifiers;
|
const bossItemConfig: HeldItemConfiguration = encounter.misc.itemConfig;
|
||||||
// Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+
|
// Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+
|
||||||
const roll = randSeedInt(100);
|
const roll = randSeedInt(100);
|
||||||
const starterTier: number | [number, number] = roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [9, 10];
|
const starterTier: number | [number, number] = roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [9, 10];
|
||||||
@ -184,12 +183,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
|
|||||||
const pokemonConfig: EnemyPokemonConfig = {
|
const pokemonConfig: EnemyPokemonConfig = {
|
||||||
species: bossSpecies,
|
species: bossSpecies,
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
modifierConfigs: bossModifiers.map(m => {
|
heldItemConfig: bossItemConfig,
|
||||||
return {
|
|
||||||
modifier: m,
|
|
||||||
stackCount: m.getStackCount(),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
if (!isNullOrUndefined(bossSpecies.forms) && bossSpecies.forms.length > 0) {
|
if (!isNullOrUndefined(bossSpecies.forms) && bossSpecies.forms.length > 0) {
|
||||||
pokemonConfig.formIndex = 0;
|
pokemonConfig.formIndex = 0;
|
||||||
|
@ -14,20 +14,16 @@ import {
|
|||||||
selectPokemonForOption,
|
selectPokemonForOption,
|
||||||
updatePlayerMoney,
|
updatePlayerMoney,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import type { PokemonHeldItemModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
|
||||||
import {
|
import {
|
||||||
BerryModifier,
|
|
||||||
HealingBoosterModifier,
|
HealingBoosterModifier,
|
||||||
LevelIncrementBoosterModifier,
|
LevelIncrementBoosterModifier,
|
||||||
MoneyMultiplierModifier,
|
MoneyMultiplierModifier,
|
||||||
PreserveBerryModifier,
|
PreserveBerryModifier,
|
||||||
} from "#app/modifier/modifier";
|
} from "#app/modifier/modifier";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import i18next from "#app/plugins/i18n";
|
import i18next from "#app/plugins/i18n";
|
||||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
@ -37,24 +33,34 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { timedEventManager } from "#app/global-event-manager";
|
import { timedEventManager } from "#app/global-event-manager";
|
||||||
|
import { HeldItemCategoryId, HeldItemId, isItemInCategory } from "#enums/held-item-id";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
const namespace = "mysteryEncounters/delibirdy";
|
const namespace = "mysteryEncounters/delibirdy";
|
||||||
|
|
||||||
/** Berries only */
|
/** Berries only */
|
||||||
const OPTION_2_ALLOWED_MODIFIERS = ["BerryModifier", "PokemonInstantReviveModifier"];
|
const OPTION_2_ALLOWED_MODIFIERS = [HeldItemCategoryId.BERRY, HeldItemId.REVIVER_SEED];
|
||||||
|
|
||||||
/** Disallowed items are berries, Reviver Seeds, and Vitamins (form change items and fusion items are not PokemonHeldItemModifiers) */
|
/** Disallowed items are berries, Reviver Seeds, and Vitamins (form change items and fusion items are not PokemonHeldItemModifiers) */
|
||||||
const OPTION_3_DISALLOWED_MODIFIERS = [
|
const OPTION_3_DISALLOWED_MODIFIERS = [HeldItemCategoryId.BERRY, HeldItemId.REVIVER_SEED];
|
||||||
"BerryModifier",
|
|
||||||
"PokemonInstantReviveModifier",
|
|
||||||
"TerastallizeModifier",
|
|
||||||
"PokemonBaseStatModifier",
|
|
||||||
"PokemonBaseStatTotalModifier",
|
|
||||||
];
|
|
||||||
|
|
||||||
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2;
|
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2;
|
||||||
|
|
||||||
|
async function backupOption() {
|
||||||
|
globalScene.getPlayerPokemon()?.heldItemManager.add(HeldItemId.SHELL_BELL);
|
||||||
|
globalScene.playSound("item_fanfare");
|
||||||
|
await showEncounterText(
|
||||||
|
i18next.t("battle:rewardGain", {
|
||||||
|
modifierName: allHeldItems[HeldItemId.SHELL_BELL].name,
|
||||||
|
}),
|
||||||
|
null,
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
doEventReward();
|
||||||
|
}
|
||||||
|
|
||||||
const doEventReward = () => {
|
const doEventReward = () => {
|
||||||
const event_buff = timedEventManager.getDelibirdyBuff();
|
const event_buff = timedEventManager.getDelibirdyBuff();
|
||||||
if (event_buff.length > 0) {
|
if (event_buff.length > 0) {
|
||||||
@ -169,16 +175,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||||||
|
|
||||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
backupOption();
|
||||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerPokemon()!, shellBell);
|
|
||||||
globalScene.playSound("item_fanfare");
|
|
||||||
await showEncounterText(
|
|
||||||
i18next.t("battle:rewardGain", { modifierName: shellBell.name }),
|
|
||||||
null,
|
|
||||||
undefined,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
doEventReward();
|
|
||||||
} else {
|
} else {
|
||||||
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.AMULET_COIN);
|
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.AMULET_COIN);
|
||||||
doEventReward();
|
doEventReward();
|
||||||
@ -205,19 +202,17 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||||
// Get Pokemon held items and filter for valid ones
|
// Get Pokemon held items and filter for valid ones
|
||||||
const validItems = pokemon.getHeldItems().filter(it => {
|
const validItems = pokemon.heldItemManager.filterRequestedItems(OPTION_2_ALLOWED_MODIFIERS, true);
|
||||||
return OPTION_2_ALLOWED_MODIFIERS.some(heldItem => it.constructor.name === heldItem) && it.isTransferable;
|
|
||||||
});
|
|
||||||
|
|
||||||
return validItems.map((modifier: PokemonHeldItemModifier) => {
|
return validItems.map((item: HeldItemId) => {
|
||||||
const option: OptionSelectItem = {
|
const option: OptionSelectItem = {
|
||||||
label: modifier.type.name,
|
label: allHeldItems[item].name,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
// Pokemon and item selected
|
// Pokemon and item selected
|
||||||
encounter.setDialogueToken("chosenItem", modifier.type.name);
|
encounter.setDialogueToken("chosenItem", allHeldItems[item].name);
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
chosenPokemon: pokemon,
|
chosenPokemon: pokemon,
|
||||||
chosenModifier: modifier,
|
chosenItem: item,
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -240,11 +235,11 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||||||
})
|
})
|
||||||
.withOptionPhase(async () => {
|
.withOptionPhase(async () => {
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const modifier: BerryModifier | PokemonInstantReviveModifier = encounter.misc.chosenModifier;
|
const chosenItem: HeldItemId = encounter.misc.chosenItem;
|
||||||
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
||||||
|
|
||||||
// Give the player a Candy Jar if they gave a Berry, and a Berry Pouch for Reviver Seed
|
// Give the player a Candy Jar if they gave a Berry, and a Berry Pouch for Reviver Seed
|
||||||
if (modifier instanceof BerryModifier) {
|
if (isItemInCategory(chosenItem, HeldItemCategoryId.BERRY)) {
|
||||||
// Check if the player has max stacks of that Candy Jar already
|
// Check if the player has max stacks of that Candy Jar already
|
||||||
const existing = globalScene.findModifier(
|
const existing = globalScene.findModifier(
|
||||||
m => m instanceof LevelIncrementBoosterModifier,
|
m => m instanceof LevelIncrementBoosterModifier,
|
||||||
@ -252,18 +247,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||||||
|
|
||||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
backupOption();
|
||||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerPokemon()!, shellBell);
|
|
||||||
globalScene.playSound("item_fanfare");
|
|
||||||
await showEncounterText(
|
|
||||||
i18next.t("battle:rewardGain", {
|
|
||||||
modifierName: shellBell.name,
|
|
||||||
}),
|
|
||||||
null,
|
|
||||||
undefined,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
doEventReward();
|
|
||||||
} else {
|
} else {
|
||||||
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.CANDY_JAR);
|
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.CANDY_JAR);
|
||||||
doEventReward();
|
doEventReward();
|
||||||
@ -274,25 +258,14 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||||||
|
|
||||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
backupOption();
|
||||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerPokemon()!, shellBell);
|
|
||||||
globalScene.playSound("item_fanfare");
|
|
||||||
await showEncounterText(
|
|
||||||
i18next.t("battle:rewardGain", {
|
|
||||||
modifierName: shellBell.name,
|
|
||||||
}),
|
|
||||||
null,
|
|
||||||
undefined,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
doEventReward();
|
|
||||||
} else {
|
} else {
|
||||||
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.BERRY_POUCH);
|
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.BERRY_POUCH);
|
||||||
doEventReward();
|
doEventReward();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chosenPokemon.loseHeldItem(modifier, false);
|
chosenPokemon.loseHeldItem(chosenItem, false);
|
||||||
|
|
||||||
leaveEncounterWithoutBattle(true);
|
leaveEncounterWithoutBattle(true);
|
||||||
})
|
})
|
||||||
@ -315,21 +288,17 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||||
// Get Pokemon held items and filter for valid ones
|
// Get Pokemon held items and filter for valid ones
|
||||||
const validItems = pokemon.getHeldItems().filter(it => {
|
const validItems = pokemon.heldItemManager.filterRequestedItems(OPTION_3_DISALLOWED_MODIFIERS, true, true);
|
||||||
return (
|
|
||||||
!OPTION_3_DISALLOWED_MODIFIERS.some(heldItem => it.constructor.name === heldItem) && it.isTransferable
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return validItems.map((modifier: PokemonHeldItemModifier) => {
|
return validItems.map((item: HeldItemId) => {
|
||||||
const option: OptionSelectItem = {
|
const option: OptionSelectItem = {
|
||||||
label: modifier.type.name,
|
label: allHeldItems[item].name,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
// Pokemon and item selected
|
// Pokemon and item selected
|
||||||
encounter.setDialogueToken("chosenItem", modifier.type.name);
|
encounter.setDialogueToken("chosenItem", allHeldItems[item].name);
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
chosenPokemon: pokemon,
|
chosenPokemon: pokemon,
|
||||||
chosenModifier: modifier,
|
chosenItem: item,
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -360,16 +329,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||||||
|
|
||||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
||||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
backupOption();
|
||||||
await applyModifierTypeToPlayerPokemon(globalScene.getPlayerParty()[0], shellBell);
|
|
||||||
globalScene.playSound("item_fanfare");
|
|
||||||
await showEncounterText(
|
|
||||||
i18next.t("battle:rewardGain", { modifierName: shellBell.name }),
|
|
||||||
null,
|
|
||||||
undefined,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
doEventReward();
|
|
||||||
} else {
|
} else {
|
||||||
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.HEALING_CHARM);
|
globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.HEALING_CHARM);
|
||||||
doEventReward();
|
doEventReward();
|
||||||
|
@ -7,9 +7,7 @@ import {
|
|||||||
setEncounterExp,
|
setEncounterExp,
|
||||||
setEncounterRewards,
|
setEncounterRewards,
|
||||||
transitionMysteryEncounterIntroVisuals,
|
transitionMysteryEncounterIntroVisuals,
|
||||||
generateModifierType,
|
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
@ -35,7 +33,6 @@ import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encoun
|
|||||||
import {
|
import {
|
||||||
applyAbilityOverrideToPokemon,
|
applyAbilityOverrideToPokemon,
|
||||||
applyDamageToPokemon,
|
applyDamageToPokemon,
|
||||||
applyModifierTypeToPlayerPokemon,
|
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
@ -45,8 +42,11 @@ import { AbilityId } from "#enums/ability-id";
|
|||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||||
|
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { getNewHeldItemFromCategory } from "#app/items/held-item-pool";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
import { allAbilities, modifierTypes } from "#app/data/data-lists";
|
import { allAbilities } from "#app/data/data-lists";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/fieryFallout";
|
const namespace = "mysteryEncounters/fieryFallout";
|
||||||
@ -302,16 +302,14 @@ function giveLeadPokemonAttackTypeBoostItem() {
|
|||||||
const leadPokemon = globalScene.getPlayerParty()?.[0];
|
const leadPokemon = globalScene.getPlayerParty()?.[0];
|
||||||
if (leadPokemon) {
|
if (leadPokemon) {
|
||||||
// Generate type booster held item, default to Charcoal if item fails to generate
|
// Generate type booster held item, default to Charcoal if item fails to generate
|
||||||
let boosterModifierType = generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER) as AttackTypeBoosterModifierType;
|
let item = getNewHeldItemFromCategory(HeldItemCategoryId.TYPE_ATTACK_BOOSTER, leadPokemon);
|
||||||
if (!boosterModifierType) {
|
if (!item) {
|
||||||
boosterModifierType = generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [
|
item = HeldItemId.CHARCOAL;
|
||||||
PokemonType.FIRE,
|
|
||||||
]) as AttackTypeBoosterModifierType;
|
|
||||||
}
|
}
|
||||||
applyModifierTypeToPlayerPokemon(leadPokemon, boosterModifierType);
|
leadPokemon.heldItemManager.add(item);
|
||||||
|
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
encounter.setDialogueToken("itemName", boosterModifierType.name);
|
encounter.setDialogueToken("itemName", allHeldItems[item].name);
|
||||||
encounter.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
|
encounter.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
|
||||||
queueEncounterMessage(`${namespace}:found_item`);
|
queueEncounterMessage(`${namespace}:found_item`);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import type { ModifierTypeOption } from "#app/modifier/modifier-type";
|
import type { ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||||
import { getPlayerModifierTypeOptions, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
import { getPlayerModifierTypeOptions, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
||||||
@ -89,12 +89,12 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
// Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER
|
// Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER
|
||||||
const tier =
|
const tier =
|
||||||
globalScene.currentBattle.waveIndex > 160
|
globalScene.currentBattle.waveIndex > 160
|
||||||
? ModifierTier.MASTER
|
? RewardTier.MASTER
|
||||||
: globalScene.currentBattle.waveIndex > 120
|
: globalScene.currentBattle.waveIndex > 120
|
||||||
? ModifierTier.ROGUE
|
? RewardTier.ROGUE
|
||||||
: globalScene.currentBattle.waveIndex > 40
|
: globalScene.currentBattle.waveIndex > 40
|
||||||
? ModifierTier.ULTRA
|
? RewardTier.ULTRA
|
||||||
: ModifierTier.GREAT;
|
: RewardTier.GREAT;
|
||||||
regenerateModifierPoolThresholds(globalScene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
|
regenerateModifierPoolThresholds(globalScene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
|
||||||
let item: ModifierTypeOption | null = null;
|
let item: ModifierTypeOption | null = null;
|
||||||
// TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward
|
// TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward
|
||||||
|
@ -4,7 +4,6 @@ import {
|
|||||||
setEncounterRewards,
|
setEncounterRewards,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { TrainerSlot } from "#enums/trainer-slot";
|
import { TrainerSlot } from "#enums/trainer-slot";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
|
||||||
import { MusicPreference } from "#app/system/settings/settings";
|
import { MusicPreference } from "#app/system/settings/settings";
|
||||||
import type { ModifierTypeOption } from "#app/modifier/modifier-type";
|
import type { ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||||
import { getPlayerModifierTypeOptions, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
import { getPlayerModifierTypeOptions, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||||
@ -33,13 +32,7 @@ import type { PlayerPokemon } from "#app/field/pokemon";
|
|||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { EnemyPokemon } from "#app/field/pokemon";
|
import { EnemyPokemon } from "#app/field/pokemon";
|
||||||
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
import { HiddenAbilityRateBoosterModifier, ShinyRateBoosterModifier } from "#app/modifier/modifier";
|
||||||
import {
|
|
||||||
HiddenAbilityRateBoosterModifier,
|
|
||||||
PokemonFormChangeItemModifier,
|
|
||||||
ShinyRateBoosterModifier,
|
|
||||||
SpeciesStatBoosterModifier,
|
|
||||||
} from "#app/modifier/modifier";
|
|
||||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
@ -53,6 +46,10 @@ import type { PokeballType } from "#enums/pokeball";
|
|||||||
import { doShinySparkleAnim } from "#app/field/anims";
|
import { doShinySparkleAnim } from "#app/field/anims";
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import { timedEventManager } from "#app/global-event-manager";
|
import { timedEventManager } from "#app/global-event-manager";
|
||||||
|
import { HeldItemCategoryId, type HeldItemId, isItemInCategory } from "#enums/held-item-id";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
|
import { getHeldItemTier } from "#app/items/held-item-tiers";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/globalTradeSystem";
|
const namespace = "mysteryEncounters/globalTradeSystem";
|
||||||
@ -215,9 +212,9 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
||||||
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
||||||
const modifiers = tradedPokemon
|
const heldItemConfig = tradedPokemon.heldItemManager
|
||||||
.getHeldItems()
|
.generateHeldItemConfiguration()
|
||||||
.filter(m => !(m instanceof PokemonFormChangeItemModifier) && !(m instanceof SpeciesStatBoosterModifier));
|
.filter(ic => !isItemInCategory(ic.entry as HeldItemId, HeldItemCategoryId.SPECIES_STAT_BOOSTER));
|
||||||
|
|
||||||
// Generate a trainer name
|
// Generate a trainer name
|
||||||
const traderName = generateRandomTraderName();
|
const traderName = generateRandomTraderName();
|
||||||
@ -241,16 +238,12 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
dataSource.variant,
|
dataSource.variant,
|
||||||
dataSource.ivs,
|
dataSource.ivs,
|
||||||
dataSource.nature,
|
dataSource.nature,
|
||||||
|
heldItemConfig,
|
||||||
dataSource,
|
dataSource,
|
||||||
);
|
);
|
||||||
globalScene.getPlayerParty().push(newPlayerPokemon);
|
globalScene.getPlayerParty().push(newPlayerPokemon);
|
||||||
await newPlayerPokemon.loadAssets();
|
await newPlayerPokemon.loadAssets();
|
||||||
|
|
||||||
for (const mod of modifiers) {
|
|
||||||
mod.pokemonId = newPlayerPokemon.id;
|
|
||||||
globalScene.addModifier(mod, true, false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the trade animation
|
// Show the trade animation
|
||||||
await showTradeBackground();
|
await showTradeBackground();
|
||||||
await doPokemonTradeSequence(tradedPokemon, newPlayerPokemon);
|
await doPokemonTradeSequence(tradedPokemon, newPlayerPokemon);
|
||||||
@ -336,9 +329,9 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
const tradedPokemon: PlayerPokemon = encounter.misc.tradedPokemon;
|
||||||
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
const receivedPokemonData: EnemyPokemon = encounter.misc.receivedPokemon;
|
||||||
const modifiers = tradedPokemon
|
const heldItemConfig = tradedPokemon.heldItemManager
|
||||||
.getHeldItems()
|
.generateHeldItemConfiguration()
|
||||||
.filter(m => !(m instanceof PokemonFormChangeItemModifier) && !(m instanceof SpeciesStatBoosterModifier));
|
.filter(ic => !isItemInCategory(ic.entry as HeldItemId, HeldItemCategoryId.SPECIES_STAT_BOOSTER));
|
||||||
|
|
||||||
// Generate a trainer name
|
// Generate a trainer name
|
||||||
const traderName = generateRandomTraderName();
|
const traderName = generateRandomTraderName();
|
||||||
@ -361,16 +354,12 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
dataSource.variant,
|
dataSource.variant,
|
||||||
dataSource.ivs,
|
dataSource.ivs,
|
||||||
dataSource.nature,
|
dataSource.nature,
|
||||||
|
heldItemConfig,
|
||||||
dataSource,
|
dataSource,
|
||||||
);
|
);
|
||||||
globalScene.getPlayerParty().push(newPlayerPokemon);
|
globalScene.getPlayerParty().push(newPlayerPokemon);
|
||||||
await newPlayerPokemon.loadAssets();
|
await newPlayerPokemon.loadAssets();
|
||||||
|
|
||||||
for (const mod of modifiers) {
|
|
||||||
mod.pokemonId = newPlayerPokemon.id;
|
|
||||||
globalScene.addModifier(mod, true, false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the trade animation
|
// Show the trade animation
|
||||||
await showTradeBackground();
|
await showTradeBackground();
|
||||||
await doPokemonTradeSequence(tradedPokemon, newPlayerPokemon);
|
await doPokemonTradeSequence(tradedPokemon, newPlayerPokemon);
|
||||||
@ -395,17 +384,15 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||||
// Get Pokemon held items and filter for valid ones
|
// Get Pokemon held items and filter for valid ones
|
||||||
const validItems = pokemon.getHeldItems().filter(it => {
|
const validItems = pokemon.heldItemManager.getTransferableHeldItems();
|
||||||
return it.isTransferable;
|
|
||||||
});
|
|
||||||
|
|
||||||
return validItems.map((modifier: PokemonHeldItemModifier) => {
|
return validItems.map((id: HeldItemId) => {
|
||||||
const option: OptionSelectItem = {
|
const option: OptionSelectItem = {
|
||||||
label: modifier.type.name,
|
label: allHeldItems[id].name,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
// Pokemon and item selected
|
// Pokemon and item selected
|
||||||
encounter.setDialogueToken("chosenItem", modifier.type.name);
|
encounter.setDialogueToken("chosenItem", allHeldItems[id].name);
|
||||||
encounter.misc.chosenModifier = modifier;
|
encounter.misc.chosenHeldItem = id;
|
||||||
encounter.misc.chosenPokemon = pokemon;
|
encounter.misc.chosenPokemon = pokemon;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -416,10 +403,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
|
|
||||||
const selectableFilter = (pokemon: Pokemon) => {
|
const selectableFilter = (pokemon: Pokemon) => {
|
||||||
// If pokemon has items to trade
|
// If pokemon has items to trade
|
||||||
const meetsReqs =
|
const meetsReqs = pokemon.heldItemManager.getTransferableHeldItems().length > 0;
|
||||||
pokemon.getHeldItems().filter(it => {
|
|
||||||
return it.isTransferable;
|
|
||||||
}).length > 0;
|
|
||||||
if (!meetsReqs) {
|
if (!meetsReqs) {
|
||||||
return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null;
|
return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null;
|
||||||
}
|
}
|
||||||
@ -431,23 +415,15 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
})
|
})
|
||||||
.withOptionPhase(async () => {
|
.withOptionPhase(async () => {
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const modifier = encounter.misc.chosenModifier as PokemonHeldItemModifier;
|
const heldItemId = encounter.misc.chosenHeldItem as HeldItemId;
|
||||||
const party = globalScene.getPlayerParty();
|
const party = globalScene.getPlayerParty();
|
||||||
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
|
||||||
|
|
||||||
// Check tier of the traded item, the received item will be one tier up
|
// Check tier of the traded item, the received item will be one tier up
|
||||||
const type = modifier.type.withTierFromPool(ModifierPoolType.PLAYER, party);
|
let tier = getHeldItemTier(heldItemId) ?? RewardTier.GREAT;
|
||||||
let tier = type.tier ?? ModifierTier.GREAT;
|
|
||||||
// Eggs and White Herb are not in the pool
|
|
||||||
if (type.id === "WHITE_HERB") {
|
|
||||||
tier = ModifierTier.GREAT;
|
|
||||||
} else if (type.id === "LUCKY_EGG") {
|
|
||||||
tier = ModifierTier.ULTRA;
|
|
||||||
} else if (type.id === "GOLDEN_EGG") {
|
|
||||||
tier = ModifierTier.ROGUE;
|
|
||||||
}
|
|
||||||
// Increment tier by 1
|
// Increment tier by 1
|
||||||
if (tier < ModifierTier.MASTER) {
|
if (tier < RewardTier.MASTER) {
|
||||||
tier++;
|
tier++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,8 +443,8 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
fillRemaining: false,
|
fillRemaining: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
chosenPokemon.loseHeldItem(modifier, false);
|
chosenPokemon.heldItemManager.remove(heldItemId);
|
||||||
await globalScene.updateModifiers(true, true);
|
await globalScene.updateModifiers(true);
|
||||||
|
|
||||||
// Generate a trainer name
|
// Generate a trainer name
|
||||||
const traderName = generateRandomTraderName();
|
const traderName = generateRandomTraderName();
|
||||||
|
@ -7,7 +7,7 @@ import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
|||||||
import { trainerPartyTemplates } from "#app/data/trainers/TrainerPartyTemplate";
|
import { trainerPartyTemplates } from "#app/data/trainers/TrainerPartyTemplate";
|
||||||
import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
||||||
import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
@ -176,7 +176,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
|
|||||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
|
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
|
||||||
|
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
|
guaranteedModifierTiers: [RewardTier.ULTRA, RewardTier.ULTRA, RewardTier.GREAT, RewardTier.GREAT],
|
||||||
fillRemaining: true,
|
fillRemaining: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
|
|||||||
encounter.expMultiplier = 0.9;
|
encounter.expMultiplier = 0.9;
|
||||||
|
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT],
|
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ROGUE, RewardTier.ULTRA, RewardTier.GREAT],
|
||||||
fillRemaining: true,
|
fillRemaining: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { randSeedInt } from "#app/utils/common";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
@ -144,7 +144,7 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT) {
|
if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT) {
|
||||||
// Choose between 2 COMMON / 2 GREAT tier items (20%)
|
// Choose between 2 COMMON / 2 GREAT tier items (20%)
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.GREAT],
|
guaranteedModifierTiers: [RewardTier.COMMON, RewardTier.COMMON, RewardTier.GREAT, RewardTier.GREAT],
|
||||||
});
|
});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(`${namespace}:option.1.normal`);
|
queueEncounterMessage(`${namespace}:option.1.normal`);
|
||||||
@ -152,7 +152,7 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT) {
|
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT) {
|
||||||
// Choose between 3 ULTRA tier items (30%)
|
// Choose between 3 ULTRA tier items (30%)
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA],
|
guaranteedModifierTiers: [RewardTier.ULTRA, RewardTier.ULTRA, RewardTier.ULTRA],
|
||||||
});
|
});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(`${namespace}:option.1.good`);
|
queueEncounterMessage(`${namespace}:option.1.good`);
|
||||||
@ -160,7 +160,7 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) {
|
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) {
|
||||||
// Choose between 2 ROGUE tier items (10%)
|
// Choose between 2 ROGUE tier items (10%)
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE],
|
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ROGUE],
|
||||||
});
|
});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(`${namespace}:option.1.great`);
|
queueEncounterMessage(`${namespace}:option.1.great`);
|
||||||
@ -171,7 +171,7 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
) {
|
) {
|
||||||
// Choose 1 MASTER tier item (5%)
|
// Choose 1 MASTER tier item (5%)
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.MASTER],
|
guaranteedModifierTiers: [RewardTier.MASTER],
|
||||||
});
|
});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(`${namespace}:option.1.amazing`);
|
queueEncounterMessage(`${namespace}:option.1.amazing`);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
generateModifierType,
|
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
selectPokemonForOption,
|
selectPokemonForOption,
|
||||||
setEncounterExp,
|
setEncounterExp,
|
||||||
@ -7,7 +6,6 @@ import {
|
|||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
|
||||||
import { randSeedInt } from "#app/utils/common";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
@ -19,7 +17,6 @@ import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter
|
|||||||
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import {
|
import {
|
||||||
applyDamageToPokemon,
|
applyDamageToPokemon,
|
||||||
applyModifierTypeToPlayerPokemon,
|
|
||||||
isPokemonValidForEncounterOptionSelection,
|
isPokemonValidForEncounterOptionSelection,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
@ -28,6 +25,8 @@ import type { Nature } from "#enums/nature";
|
|||||||
import { getNatureName } from "#app/data/nature";
|
import { getNatureName } from "#app/data/nature";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { getNewVitaminHeldItem } from "#app/items/held-item-pool";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
const namespace = "mysteryEncounters/shadyVitaminDealer";
|
const namespace = "mysteryEncounters/shadyVitaminDealer";
|
||||||
@ -97,15 +96,12 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
// Update money
|
// Update money
|
||||||
updatePlayerMoney(-(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
|
updatePlayerMoney(-(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
|
||||||
// Calculate modifiers and dialogue tokens
|
// Calculate modifiers and dialogue tokens
|
||||||
const modifiers = [
|
const items = [getNewVitaminHeldItem(), getNewVitaminHeldItem()];
|
||||||
generateModifierType(modifierTypes.BASE_STAT_BOOSTER)!,
|
encounter.setDialogueToken("boost1", allHeldItems[items[0]].name);
|
||||||
generateModifierType(modifierTypes.BASE_STAT_BOOSTER)!,
|
encounter.setDialogueToken("boost2", allHeldItems[items[1]].name);
|
||||||
];
|
|
||||||
encounter.setDialogueToken("boost1", modifiers[0].name);
|
|
||||||
encounter.setDialogueToken("boost2", modifiers[1].name);
|
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
chosenPokemon: pokemon,
|
chosenPokemon: pokemon,
|
||||||
modifiers: modifiers,
|
items: items,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,10 +128,10 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
// Choose Cheap Option
|
// Choose Cheap Option
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const chosenPokemon = encounter.misc.chosenPokemon;
|
const chosenPokemon = encounter.misc.chosenPokemon;
|
||||||
const modifiers = encounter.misc.modifiers;
|
const items = encounter.misc.items;
|
||||||
|
|
||||||
for (const modType of modifiers) {
|
for (const item of items) {
|
||||||
await applyModifierTypeToPlayerPokemon(chosenPokemon, modType);
|
chosenPokemon.heldItemManager.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveEncounterWithoutBattle(true);
|
leaveEncounterWithoutBattle(true);
|
||||||
@ -180,15 +176,12 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
// Update money
|
// Update money
|
||||||
updatePlayerMoney(-(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney);
|
updatePlayerMoney(-(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney);
|
||||||
// Calculate modifiers and dialogue tokens
|
// Calculate modifiers and dialogue tokens
|
||||||
const modifiers = [
|
const items = [getNewVitaminHeldItem(), getNewVitaminHeldItem()];
|
||||||
generateModifierType(modifierTypes.BASE_STAT_BOOSTER)!,
|
encounter.setDialogueToken("boost1", allHeldItems[items[0]].name);
|
||||||
generateModifierType(modifierTypes.BASE_STAT_BOOSTER)!,
|
encounter.setDialogueToken("boost2", allHeldItems[items[1]].name);
|
||||||
];
|
|
||||||
encounter.setDialogueToken("boost1", modifiers[0].name);
|
|
||||||
encounter.setDialogueToken("boost2", modifiers[1].name);
|
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
chosenPokemon: pokemon,
|
chosenPokemon: pokemon,
|
||||||
modifiers: modifiers,
|
items: items,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -203,10 +196,10 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
// Choose Expensive Option
|
// Choose Expensive Option
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
const chosenPokemon = encounter.misc.chosenPokemon;
|
const chosenPokemon = encounter.misc.chosenPokemon;
|
||||||
const modifiers = encounter.misc.modifiers;
|
const items = encounter.misc.items;
|
||||||
|
|
||||||
for (const modType of modifiers) {
|
for (const item of items) {
|
||||||
await applyModifierTypeToPlayerPokemon(chosenPokemon, modType);
|
chosenPokemon.heldItemManager.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveEncounterWithoutBattle(true);
|
leaveEncounterWithoutBattle(true);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
@ -11,7 +10,6 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
|
|||||||
import { MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
import { MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||||
import type { EnemyPartyConfig, EnemyPokemonConfig } from "../utils/encounter-phase-utils";
|
import type { EnemyPartyConfig, EnemyPokemonConfig } from "../utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
generateModifierType,
|
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
loadCustomMovesForEncounter,
|
loadCustomMovesForEncounter,
|
||||||
@ -27,10 +25,9 @@ import { AiType } from "#enums/ai-type";
|
|||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { BerryType } from "#enums/berry-type";
|
|
||||||
import { Stat } from "#enums/stat";
|
|
||||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
import { randSeedInt } from "#app/utils/common";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
|
||||||
/** i18n namespace for the encounter */
|
/** i18n namespace for the encounter */
|
||||||
@ -78,24 +75,12 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
|
|||||||
status: [StatusEffect.SLEEP, 6], // Extra turns on timer for Snorlax's start of fight moves
|
status: [StatusEffect.SLEEP, 6], // Extra turns on timer for Snorlax's start of fight moves
|
||||||
nature: Nature.DOCILE,
|
nature: Nature.DOCILE,
|
||||||
moveSet: [MoveId.BODY_SLAM, MoveId.CRUNCH, MoveId.SLEEP_TALK, MoveId.REST],
|
moveSet: [MoveId.BODY_SLAM, MoveId.CRUNCH, MoveId.SLEEP_TALK, MoveId.REST],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.SITRUS_BERRY, count: 1 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.ENIGMA_BERRY, count: 1 },
|
||||||
},
|
{ entry: HeldItemId.HP_UP, count: 1 },
|
||||||
{
|
{ entry: HeldItemId.SOOTHE_BELL, count: randSeedInt(2, 0) },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.LUCKY_EGG, count: randSeedInt(2, 0) },
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.SOOTHE_BELL) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: randSeedInt(2, 0),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.LUCKY_EGG) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: randSeedInt(2, 0),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }),
|
customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }),
|
||||||
aiType: AiType.SMART, // Required to ensure Snorlax uses Sleep Talk while it is asleep
|
aiType: AiType.SMART, // Required to ensure Snorlax uses Sleep Talk while it is asleep
|
||||||
|
@ -5,9 +5,7 @@ import {
|
|||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
setEncounterRewards,
|
setEncounterRewards,
|
||||||
transitionMysteryEncounterIntroVisuals,
|
transitionMysteryEncounterIntroVisuals,
|
||||||
generateModifierType,
|
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -23,11 +21,11 @@ import { modifyPlayerPokemonBST } from "#app/data/mystery-encounters/utils/encou
|
|||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { BattlerIndex } from "#enums/battler-index";
|
import { BattlerIndex } from "#enums/battler-index";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { BerryType } from "#enums/berry-type";
|
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
@ -95,23 +93,12 @@ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder
|
|||||||
customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }),
|
customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }),
|
||||||
nature: Nature.HARDY,
|
nature: Nature.HARDY,
|
||||||
moveSet: [MoveId.INFESTATION, MoveId.SALT_CURE, MoveId.GASTRO_ACID, MoveId.HEAL_ORDER],
|
moveSet: [MoveId.INFESTATION, MoveId.SALT_CURE, MoveId.GASTRO_ACID, MoveId.HEAL_ORDER],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.SITRUS_BERRY, count: 1 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.ENIGMA_BERRY, count: 1 },
|
||||||
},
|
{ entry: HeldItemId.APICOT_BERRY, count: 1 },
|
||||||
{
|
{ entry: HeldItemId.GANLON_BERRY, count: 1 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.LUM_BERRY, count: 2 },
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
generateModifierType,
|
|
||||||
generateModifierTypeOption,
|
generateModifierTypeOption,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
setEncounterRewards,
|
setEncounterRewards,
|
||||||
transitionMysteryEncounterIntroVisuals,
|
transitionMysteryEncounterIntroVisuals,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
@ -20,17 +17,18 @@ import { AbilityId } from "#enums/ability-id";
|
|||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
|
||||||
import { BerryType } from "#enums/berry-type";
|
|
||||||
import { Stat } from "#enums/stat";
|
|
||||||
import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms/form-change-triggers";
|
import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms/form-change-triggers";
|
||||||
import { applyPostBattleInitAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
import { applyPostBattleInitAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
|
//TODO: make all items unstealable
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/theWinstrateChallenge";
|
const namespace = "mysteryEncounters/theWinstrateChallenge";
|
||||||
@ -166,7 +164,7 @@ async function spawnNextTrainerOrEndEncounter() {
|
|||||||
await showEncounterDialogue(`${namespace}:victory_2`, `${namespace}:speaker`);
|
await showEncounterDialogue(`${namespace}:victory_2`, `${namespace}:speaker`);
|
||||||
globalScene.ui.clearText(); // Clears "Winstrate" title from screen as rewards get animated in
|
globalScene.ui.clearText(); // Clears "Winstrate" title from screen as rewards get animated in
|
||||||
const machoBrace = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE)!;
|
const machoBrace = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE)!;
|
||||||
machoBrace.type.tier = ModifierTier.MASTER;
|
machoBrace.type.tier = RewardTier.MASTER;
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTypeOptions: [machoBrace],
|
guaranteedModifierTypeOptions: [machoBrace],
|
||||||
fillRemaining: false,
|
fillRemaining: false,
|
||||||
@ -258,16 +256,9 @@ function getVictorTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 0, // Guts
|
abilityIndex: 0, // Guts
|
||||||
nature: Nature.ADAMANT,
|
nature: Nature.ADAMANT,
|
||||||
moveSet: [MoveId.FACADE, MoveId.BRAVE_BIRD, MoveId.PROTECT, MoveId.QUICK_ATTACK],
|
moveSet: [MoveId.FACADE, MoveId.BRAVE_BIRD, MoveId.PROTECT, MoveId.QUICK_ATTACK],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.FLAME_ORB, count: 1 },
|
||||||
modifier: generateModifierType(modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.FOCUS_BAND, count: 2 },
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.FOCUS_BAND) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -276,16 +267,9 @@ function getVictorTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 1, // Guts
|
abilityIndex: 1, // Guts
|
||||||
nature: Nature.ADAMANT,
|
nature: Nature.ADAMANT,
|
||||||
moveSet: [MoveId.FACADE, MoveId.OBSTRUCT, MoveId.NIGHT_SLASH, MoveId.FIRE_PUNCH],
|
moveSet: [MoveId.FACADE, MoveId.OBSTRUCT, MoveId.NIGHT_SLASH, MoveId.FIRE_PUNCH],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.FLAME_ORB, count: 1 },
|
||||||
modifier: generateModifierType(modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.LEFTOVERS, count: 2 },
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.LEFTOVERS) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -302,16 +286,9 @@ function getVictoriaTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 0, // Natural Cure
|
abilityIndex: 0, // Natural Cure
|
||||||
nature: Nature.CALM,
|
nature: Nature.CALM,
|
||||||
moveSet: [MoveId.SYNTHESIS, MoveId.SLUDGE_BOMB, MoveId.GIGA_DRAIN, MoveId.SLEEP_POWDER],
|
moveSet: [MoveId.SYNTHESIS, MoveId.SLUDGE_BOMB, MoveId.GIGA_DRAIN, MoveId.SLEEP_POWDER],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.SOUL_DEW, count: 1 },
|
||||||
modifier: generateModifierType(modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.QUICK_CLAW, count: 2 },
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -320,21 +297,9 @@ function getVictoriaTrainerConfig(): EnemyPartyConfig {
|
|||||||
formIndex: 1,
|
formIndex: 1,
|
||||||
nature: Nature.TIMID,
|
nature: Nature.TIMID,
|
||||||
moveSet: [MoveId.PSYSHOCK, MoveId.MOONBLAST, MoveId.SHADOW_BALL, MoveId.WILL_O_WISP],
|
moveSet: [MoveId.PSYSHOCK, MoveId.MOONBLAST, MoveId.SHADOW_BALL, MoveId.WILL_O_WISP],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.TWISTED_SPOON, count: 1 },
|
||||||
modifier: generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [
|
{ entry: HeldItemId.FAIRY_FEATHER, count: 1 },
|
||||||
PokemonType.PSYCHIC,
|
|
||||||
]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 1,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [
|
|
||||||
PokemonType.FAIRY,
|
|
||||||
]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 1,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -351,17 +316,9 @@ function getViviTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 3, // Lightning Rod
|
abilityIndex: 3, // Lightning Rod
|
||||||
nature: Nature.ADAMANT,
|
nature: Nature.ADAMANT,
|
||||||
moveSet: [MoveId.WATERFALL, MoveId.MEGAHORN, MoveId.KNOCK_OFF, MoveId.REST],
|
moveSet: [MoveId.WATERFALL, MoveId.MEGAHORN, MoveId.KNOCK_OFF, MoveId.REST],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.LUM_BERRY, count: 2 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.HP_UP, count: 4 },
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 4,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -370,16 +327,9 @@ function getViviTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 1, // Poison Heal
|
abilityIndex: 1, // Poison Heal
|
||||||
nature: Nature.JOLLY,
|
nature: Nature.JOLLY,
|
||||||
moveSet: [MoveId.SPORE, MoveId.SWORDS_DANCE, MoveId.SEED_BOMB, MoveId.DRAIN_PUNCH],
|
moveSet: [MoveId.SPORE, MoveId.SWORDS_DANCE, MoveId.SEED_BOMB, MoveId.DRAIN_PUNCH],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.HP_UP, count: 4 },
|
||||||
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.TOXIC_ORB, count: 1 },
|
||||||
stackCount: 4,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.TOXIC_ORB) as PokemonHeldItemModifierType,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -388,13 +338,7 @@ function getViviTrainerConfig(): EnemyPartyConfig {
|
|||||||
formIndex: 1,
|
formIndex: 1,
|
||||||
nature: Nature.CALM,
|
nature: Nature.CALM,
|
||||||
moveSet: [MoveId.EARTH_POWER, MoveId.FIRE_BLAST, MoveId.YAWN, MoveId.PROTECT],
|
moveSet: [MoveId.EARTH_POWER, MoveId.FIRE_BLAST, MoveId.YAWN, MoveId.PROTECT],
|
||||||
modifierConfigs: [
|
heldItemConfig: [{ entry: HeldItemId.QUICK_CLAW, count: 3 }],
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 3,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -410,12 +354,7 @@ function getVickyTrainerConfig(): EnemyPartyConfig {
|
|||||||
formIndex: 1,
|
formIndex: 1,
|
||||||
nature: Nature.IMPISH,
|
nature: Nature.IMPISH,
|
||||||
moveSet: [MoveId.AXE_KICK, MoveId.ICE_PUNCH, MoveId.ZEN_HEADBUTT, MoveId.BULLET_PUNCH],
|
moveSet: [MoveId.AXE_KICK, MoveId.ICE_PUNCH, MoveId.ZEN_HEADBUTT, MoveId.BULLET_PUNCH],
|
||||||
modifierConfigs: [
|
heldItemConfig: [{ entry: HeldItemId.SHELL_BELL, count: 1 }],
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -431,13 +370,7 @@ function getVitoTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 0, // Soundproof
|
abilityIndex: 0, // Soundproof
|
||||||
nature: Nature.MODEST,
|
nature: Nature.MODEST,
|
||||||
moveSet: [MoveId.THUNDERBOLT, MoveId.GIGA_DRAIN, MoveId.FOUL_PLAY, MoveId.THUNDER_WAVE],
|
moveSet: [MoveId.THUNDERBOLT, MoveId.GIGA_DRAIN, MoveId.FOUL_PLAY, MoveId.THUNDER_WAVE],
|
||||||
modifierConfigs: [
|
heldItemConfig: [{ entry: HeldItemId.ZINC, count: 2 }],
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER, [Stat.SPD]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
species: getPokemonSpecies(SpeciesId.SWALOT),
|
species: getPokemonSpecies(SpeciesId.SWALOT),
|
||||||
@ -445,51 +378,18 @@ function getVitoTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 2, // Gluttony
|
abilityIndex: 2, // Gluttony
|
||||||
nature: Nature.QUIET,
|
nature: Nature.QUIET,
|
||||||
moveSet: [MoveId.SLUDGE_BOMB, MoveId.GIGA_DRAIN, MoveId.ICE_BEAM, MoveId.EARTHQUAKE],
|
moveSet: [MoveId.SLUDGE_BOMB, MoveId.GIGA_DRAIN, MoveId.ICE_BEAM, MoveId.EARTHQUAKE],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemId.SITRUS_BERRY, count: 2 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.APICOT_BERRY, count: 2 },
|
||||||
stackCount: 2,
|
{ entry: HeldItemId.GANLON_BERRY, count: 2 },
|
||||||
},
|
{ entry: HeldItemId.STARF_BERRY, count: 2 },
|
||||||
{
|
{ entry: HeldItemId.SALAC_BERRY, count: 2 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.LUM_BERRY, count: 2 },
|
||||||
stackCount: 2,
|
{ entry: HeldItemId.LANSAT_BERRY, count: 2 },
|
||||||
},
|
{ entry: HeldItemId.LIECHI_BERRY, count: 2 },
|
||||||
{
|
{ entry: HeldItemId.PETAYA_BERRY, count: 2 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.ENIGMA_BERRY, count: 2 },
|
||||||
stackCount: 2,
|
{ entry: HeldItemId.LEPPA_BERRY, count: 2 },
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.STARF]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SALAC]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.LANSAT]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.LIECHI]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.PETAYA]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY, [BerryType.LEPPA]) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -498,13 +398,7 @@ function getVitoTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 2, // Tangled Feet
|
abilityIndex: 2, // Tangled Feet
|
||||||
nature: Nature.JOLLY,
|
nature: Nature.JOLLY,
|
||||||
moveSet: [MoveId.DRILL_PECK, MoveId.QUICK_ATTACK, MoveId.THRASH, MoveId.KNOCK_OFF],
|
moveSet: [MoveId.DRILL_PECK, MoveId.QUICK_ATTACK, MoveId.THRASH, MoveId.KNOCK_OFF],
|
||||||
modifierConfigs: [
|
heldItemConfig: [{ entry: HeldItemId.KINGS_ROCK, count: 2 }],
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.KINGS_ROCK) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
species: getPokemonSpecies(SpeciesId.ALAKAZAM),
|
species: getPokemonSpecies(SpeciesId.ALAKAZAM),
|
||||||
@ -512,13 +406,7 @@ function getVitoTrainerConfig(): EnemyPartyConfig {
|
|||||||
formIndex: 1,
|
formIndex: 1,
|
||||||
nature: Nature.BOLD,
|
nature: Nature.BOLD,
|
||||||
moveSet: [MoveId.PSYCHIC, MoveId.SHADOW_BALL, MoveId.FOCUS_BLAST, MoveId.THUNDERBOLT],
|
moveSet: [MoveId.PSYCHIC, MoveId.SHADOW_BALL, MoveId.FOCUS_BLAST, MoveId.THUNDERBOLT],
|
||||||
modifierConfigs: [
|
heldItemConfig: [{ entry: HeldItemId.WIDE_LENS, count: 2 }],
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.WIDE_LENS) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
species: getPokemonSpecies(SpeciesId.DARMANITAN),
|
species: getPokemonSpecies(SpeciesId.DARMANITAN),
|
||||||
@ -526,13 +414,7 @@ function getVitoTrainerConfig(): EnemyPartyConfig {
|
|||||||
abilityIndex: 0, // Sheer Force
|
abilityIndex: 0, // Sheer Force
|
||||||
nature: Nature.IMPISH,
|
nature: Nature.IMPISH,
|
||||||
moveSet: [MoveId.EARTHQUAKE, MoveId.U_TURN, MoveId.FLARE_BLITZ, MoveId.ROCK_SLIDE],
|
moveSet: [MoveId.EARTHQUAKE, MoveId.U_TURN, MoveId.FLARE_BLITZ, MoveId.ROCK_SLIDE],
|
||||||
modifierConfigs: [
|
heldItemConfig: [{ entry: HeldItemId.QUICK_CLAW, count: 2 }],
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: 2,
|
|
||||||
isTransferable: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,6 @@ import { getNatureName } from "#app/data/nature";
|
|||||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { AbilityAttr } from "#enums/ability-attr";
|
import { AbilityAttr } from "#enums/ability-attr";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
@ -25,7 +24,6 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
|
|||||||
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import type HeldModifierConfig from "#app/@types/held-modifier-config";
|
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { getStatKey } from "#enums/stat";
|
import { getStatKey } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
@ -102,8 +100,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
// Spawn light training session with chosen pokemon
|
// Spawn light training session with chosen pokemon
|
||||||
// Every 50 waves, add +1 boss segment, capping at 5
|
// Every 50 waves, add +1 boss segment, capping at 5
|
||||||
const segments = Math.min(2 + Math.floor(globalScene.currentBattle.waveIndex / 50), 5);
|
const segments = Math.min(2 + Math.floor(globalScene.currentBattle.waveIndex / 50), 5);
|
||||||
const modifiers = new ModifiersHolder();
|
const config = getEnemyConfig(playerPokemon, segments);
|
||||||
const config = getEnemyConfig(playerPokemon, segments, modifiers);
|
|
||||||
globalScene.removePokemonFromPlayerParty(playerPokemon, false);
|
globalScene.removePokemonFromPlayerParty(playerPokemon, false);
|
||||||
|
|
||||||
const onBeforeRewardsPhase = () => {
|
const onBeforeRewardsPhase = () => {
|
||||||
@ -152,12 +149,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
globalScene.gameData.setPokemonCaught(playerPokemon, false);
|
globalScene.gameData.setPokemonCaught(playerPokemon, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add pokemon and mods back
|
// Make held items show up again
|
||||||
globalScene.getPlayerParty().push(playerPokemon);
|
|
||||||
for (const mod of modifiers.value) {
|
|
||||||
mod.pokemonId = playerPokemon.id;
|
|
||||||
globalScene.addModifier(mod, true, false, false, true);
|
|
||||||
}
|
|
||||||
globalScene.updateModifiers(true);
|
globalScene.updateModifiers(true);
|
||||||
queueEncounterMessage(`${namespace}:option.1.finished`);
|
queueEncounterMessage(`${namespace}:option.1.finished`);
|
||||||
};
|
};
|
||||||
@ -218,8 +210,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
// Spawn medium training session with chosen pokemon
|
// Spawn medium training session with chosen pokemon
|
||||||
// Every 40 waves, add +1 boss segment, capping at 6
|
// Every 40 waves, add +1 boss segment, capping at 6
|
||||||
const segments = Math.min(2 + Math.floor(globalScene.currentBattle.waveIndex / 40), 6);
|
const segments = Math.min(2 + Math.floor(globalScene.currentBattle.waveIndex / 40), 6);
|
||||||
const modifiers = new ModifiersHolder();
|
const config = getEnemyConfig(playerPokemon, segments);
|
||||||
const config = getEnemyConfig(playerPokemon, segments, modifiers);
|
|
||||||
globalScene.removePokemonFromPlayerParty(playerPokemon, false);
|
globalScene.removePokemonFromPlayerParty(playerPokemon, false);
|
||||||
|
|
||||||
const onBeforeRewardsPhase = () => {
|
const onBeforeRewardsPhase = () => {
|
||||||
@ -228,12 +219,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
playerPokemon.setCustomNature(encounter.misc.chosenNature);
|
playerPokemon.setCustomNature(encounter.misc.chosenNature);
|
||||||
globalScene.gameData.unlockSpeciesNature(playerPokemon.species, encounter.misc.chosenNature);
|
globalScene.gameData.unlockSpeciesNature(playerPokemon.species, encounter.misc.chosenNature);
|
||||||
|
|
||||||
// Add pokemon and modifiers back
|
// Make held items show up again
|
||||||
globalScene.getPlayerParty().push(playerPokemon);
|
|
||||||
for (const mod of modifiers.value) {
|
|
||||||
mod.pokemonId = playerPokemon.id;
|
|
||||||
globalScene.addModifier(mod, true, false, false, true);
|
|
||||||
}
|
|
||||||
globalScene.updateModifiers(true);
|
globalScene.updateModifiers(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -309,8 +295,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
// Every 30 waves, add +1 boss segment, capping at 6
|
// Every 30 waves, add +1 boss segment, capping at 6
|
||||||
// Also starts with +1 to all stats
|
// Also starts with +1 to all stats
|
||||||
const segments = Math.min(2 + Math.floor(globalScene.currentBattle.waveIndex / 30), 6);
|
const segments = Math.min(2 + Math.floor(globalScene.currentBattle.waveIndex / 30), 6);
|
||||||
const modifiers = new ModifiersHolder();
|
const config = getEnemyConfig(playerPokemon, segments);
|
||||||
const config = getEnemyConfig(playerPokemon, segments, modifiers);
|
|
||||||
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
|
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
|
||||||
globalScene.removePokemonFromPlayerParty(playerPokemon, false);
|
globalScene.removePokemonFromPlayerParty(playerPokemon, false);
|
||||||
|
|
||||||
@ -341,12 +326,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
playerPokemon.calculateStats();
|
playerPokemon.calculateStats();
|
||||||
globalScene.gameData.setPokemonCaught(playerPokemon, false);
|
globalScene.gameData.setPokemonCaught(playerPokemon, false);
|
||||||
|
|
||||||
// Add pokemon and mods back
|
// Make held items show up again
|
||||||
globalScene.getPlayerParty().push(playerPokemon);
|
|
||||||
for (const mod of modifiers.value) {
|
|
||||||
mod.pokemonId = playerPokemon.id;
|
|
||||||
globalScene.addModifier(mod, true, false, false, true);
|
|
||||||
}
|
|
||||||
globalScene.updateModifiers(true);
|
globalScene.updateModifiers(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -374,18 +354,12 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
function getEnemyConfig(playerPokemon: PlayerPokemon, segments: number, modifiers: ModifiersHolder): EnemyPartyConfig {
|
function getEnemyConfig(playerPokemon: PlayerPokemon, segments: number): EnemyPartyConfig {
|
||||||
playerPokemon.resetSummonData();
|
playerPokemon.resetSummonData();
|
||||||
|
|
||||||
// Passes modifiers by reference
|
// Passes modifiers by reference
|
||||||
modifiers.value = playerPokemon.getHeldItems();
|
// TODO: fix various things, like make enemy items untransferable, make sure form change items can come back
|
||||||
const modifierConfigs = modifiers.value.map(mod => {
|
const config = playerPokemon.heldItemManager.generateHeldItemConfiguration();
|
||||||
return {
|
|
||||||
modifier: mod.clone(),
|
|
||||||
isTransferable: false,
|
|
||||||
stackCount: mod.stackCount,
|
|
||||||
};
|
|
||||||
}) as HeldModifierConfig[];
|
|
||||||
|
|
||||||
const data = new PokemonData(playerPokemon);
|
const data = new PokemonData(playerPokemon);
|
||||||
return {
|
return {
|
||||||
@ -397,12 +371,8 @@ function getEnemyConfig(playerPokemon: PlayerPokemon, segments: number, modifier
|
|||||||
formIndex: playerPokemon.formIndex,
|
formIndex: playerPokemon.formIndex,
|
||||||
level: playerPokemon.level,
|
level: playerPokemon.level,
|
||||||
dataSource: data,
|
dataSource: data,
|
||||||
modifierConfigs: modifierConfigs,
|
heldItemConfig: config,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModifiersHolder {
|
|
||||||
public value: PokemonHeldItemModifier[] = [];
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type { EnemyPartyConfig, EnemyPokemonConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig, EnemyPokemonConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
|
assignItemToFirstFreePokemon,
|
||||||
generateModifierType,
|
generateModifierType,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
@ -7,7 +8,6 @@ import {
|
|||||||
setEncounterRewards,
|
setEncounterRewards,
|
||||||
transitionMysteryEncounterIntroVisuals,
|
transitionMysteryEncounterIntroVisuals,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -17,11 +17,9 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
|
|||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { HitHealModifier, PokemonHeldItemModifier, TurnHealModifier } from "#app/modifier/modifier";
|
|
||||||
import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
|
||||||
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import i18next from "#app/plugins/i18n";
|
import i18next from "#app/plugins/i18n";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { BattlerIndex } from "#enums/battler-index";
|
import { BattlerIndex } from "#enums/battler-index";
|
||||||
@ -29,6 +27,8 @@ import { PokemonMove } from "#app/data/moves/pokemon-move";
|
|||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { randSeedInt } from "#app/utils/common";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
const namespace = "mysteryEncounters/trashToTreasure";
|
const namespace = "mysteryEncounters/trashToTreasure";
|
||||||
@ -83,41 +83,13 @@ export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
formIndex: 1, // Gmax
|
formIndex: 1, // Gmax
|
||||||
bossSegmentModifier: 1, // +1 Segment from normal
|
bossSegmentModifier: 1, // +1 Segment from normal
|
||||||
moveSet: [MoveId.GUNK_SHOT, MoveId.STOMPING_TANTRUM, MoveId.HAMMER_ARM, MoveId.PAYBACK],
|
moveSet: [MoveId.GUNK_SHOT, MoveId.STOMPING_TANTRUM, MoveId.HAMMER_ARM, MoveId.PAYBACK],
|
||||||
modifierConfigs: [
|
heldItemConfig: [
|
||||||
{
|
{ entry: HeldItemCategoryId.BERRY, count: 4 },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY) as PokemonHeldItemModifierType,
|
{ entry: HeldItemCategoryId.BASE_STAT_BOOST, count: 2 },
|
||||||
},
|
{ entry: HeldItemId.TOXIC_ORB, count: randSeedInt(2, 0) },
|
||||||
{
|
{ entry: HeldItemId.SOOTHE_BELL, count: randSeedInt(2, 1) },
|
||||||
modifier: generateModifierType(modifierTypes.BERRY) as PokemonHeldItemModifierType,
|
{ entry: HeldItemId.LUCKY_EGG, count: randSeedInt(3, 1) },
|
||||||
},
|
{ entry: HeldItemId.GOLDEN_EGG, count: randSeedInt(2, 0) },
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY) as PokemonHeldItemModifierType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BERRY) as PokemonHeldItemModifierType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER) as PokemonHeldItemModifierType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER) as PokemonHeldItemModifierType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.TOXIC_ORB) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: randSeedInt(2, 0),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.SOOTHE_BELL) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: randSeedInt(2, 1),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.LUCKY_EGG) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: randSeedInt(3, 1),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
modifier: generateModifierType(modifierTypes.GOLDEN_EGG) as PokemonHeldItemModifierType,
|
|
||||||
stackCount: randSeedInt(2, 0),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
@ -200,7 +172,7 @@ export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
|
|
||||||
setEncounterRewards({
|
setEncounterRewards({
|
||||||
guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT],
|
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ROGUE, RewardTier.ULTRA, RewardTier.GREAT],
|
||||||
fillRemaining: true,
|
fillRemaining: true,
|
||||||
});
|
});
|
||||||
encounter.startOfBattleEffects.push(
|
encounter.startOfBattleEffects.push(
|
||||||
@ -224,44 +196,18 @@ export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
async function tryApplyDigRewardItems() {
|
async function tryApplyDigRewardItems() {
|
||||||
const shellBell = generateModifierType(modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
|
||||||
const leftovers = generateModifierType(modifierTypes.LEFTOVERS) as PokemonHeldItemModifierType;
|
|
||||||
|
|
||||||
const party = globalScene.getPlayerParty();
|
const party = globalScene.getPlayerParty();
|
||||||
|
|
||||||
// Iterate over the party until an item was successfully given
|
|
||||||
// First leftovers
|
// First leftovers
|
||||||
for (const pokemon of party) {
|
assignItemToFirstFreePokemon(HeldItemId.LEFTOVERS, party);
|
||||||
const heldItems = globalScene.findModifiers(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
|
|
||||||
true,
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
const existingLeftovers = heldItems.find(m => m instanceof TurnHealModifier) as TurnHealModifier;
|
|
||||||
|
|
||||||
if (!existingLeftovers || existingLeftovers.getStackCount() < existingLeftovers.getMaxStackCount()) {
|
|
||||||
await applyModifierTypeToPlayerPokemon(pokemon, leftovers);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second leftovers
|
// Second leftovers
|
||||||
for (const pokemon of party) {
|
assignItemToFirstFreePokemon(HeldItemId.LEFTOVERS, party);
|
||||||
const heldItems = globalScene.findModifiers(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
|
|
||||||
true,
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
const existingLeftovers = heldItems.find(m => m instanceof TurnHealModifier) as TurnHealModifier;
|
|
||||||
|
|
||||||
if (!existingLeftovers || existingLeftovers.getStackCount() < existingLeftovers.getMaxStackCount()) {
|
|
||||||
await applyModifierTypeToPlayerPokemon(pokemon, leftovers);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
globalScene.playSound("item_fanfare");
|
globalScene.playSound("item_fanfare");
|
||||||
await showEncounterText(
|
await showEncounterText(
|
||||||
i18next.t("battle:rewardGainCount", {
|
i18next.t("battle:rewardGainCount", {
|
||||||
modifierName: leftovers.name,
|
modifierName: allHeldItems[HeldItemId.LEFTOVERS].name,
|
||||||
count: 2,
|
count: 2,
|
||||||
}),
|
}),
|
||||||
null,
|
null,
|
||||||
@ -270,23 +216,12 @@ async function tryApplyDigRewardItems() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Only Shell bell
|
// Only Shell bell
|
||||||
for (const pokemon of party) {
|
assignItemToFirstFreePokemon(HeldItemId.SHELL_BELL, party);
|
||||||
const heldItems = globalScene.findModifiers(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
|
|
||||||
true,
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
const existingShellBell = heldItems.find(m => m instanceof HitHealModifier) as HitHealModifier;
|
|
||||||
|
|
||||||
if (!existingShellBell || existingShellBell.getStackCount() < existingShellBell.getMaxStackCount()) {
|
|
||||||
await applyModifierTypeToPlayerPokemon(pokemon, shellBell);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
globalScene.playSound("item_fanfare");
|
globalScene.playSound("item_fanfare");
|
||||||
await showEncounterText(
|
await showEncounterText(
|
||||||
i18next.t("battle:rewardGainCount", {
|
i18next.t("battle:rewardGainCount", {
|
||||||
modifierName: shellBell.name,
|
modifierName: allHeldItems[HeldItemId.SHELL_BELL].name,
|
||||||
count: 1,
|
count: 1,
|
||||||
}),
|
}),
|
||||||
null,
|
null,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
|
getPartyBerries,
|
||||||
getRandomEncounterSpecies,
|
getRandomEncounterSpecies,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
@ -15,10 +16,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import {
|
import { HeldItemRequirement, MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||||
MoveRequirement,
|
|
||||||
PersistentModifierRequirement,
|
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import {
|
import {
|
||||||
@ -33,10 +31,11 @@ import { BattlerIndex } from "#enums/battler-index";
|
|||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { BerryModifier } from "#app/modifier/modifier";
|
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { MoveUseMode } from "#enums/move-use-mode";
|
import { MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
import type { PokemonItemMap } from "#app/items/held-item-data-types";
|
||||||
|
import { HeldItemCategoryId } from "#enums/held-item-id";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/uncommonBreed";
|
const namespace = "mysteryEncounters/uncommonBreed";
|
||||||
@ -191,7 +190,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
)
|
)
|
||||||
.withOption(
|
.withOption(
|
||||||
MysteryEncounterOptionBuilder.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
|
MysteryEncounterOptionBuilder.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||||
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
|
.withSceneRequirement(new HeldItemRequirement(HeldItemCategoryId.BERRY, 4)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
|
||||||
.withDialogue({
|
.withDialogue({
|
||||||
buttonLabel: `${namespace}:option.2.label`,
|
buttonLabel: `${namespace}:option.2.label`,
|
||||||
buttonTooltip: `${namespace}:option.2.tooltip`,
|
buttonTooltip: `${namespace}:option.2.tooltip`,
|
||||||
@ -207,19 +206,18 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
|
|
||||||
// Remove 4 random berries from player's party
|
// Remove 4 random berries from player's party
|
||||||
// Get all player berry items, remove from party, and store reference
|
// Get all player berry items, remove from party, and store reference
|
||||||
const berryItems: BerryModifier[] = globalScene.findModifiers(
|
|
||||||
m => m instanceof BerryModifier,
|
const berryMap = getPartyBerries();
|
||||||
) as BerryModifier[];
|
const stolenBerryMap: PokemonItemMap[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < 4; i++) {
|
for (let i = 0; i < 4; i++) {
|
||||||
const index = randSeedInt(berryItems.length);
|
const index = randSeedInt(berryMap.length);
|
||||||
const randBerry = berryItems[index];
|
const randBerry = berryMap[index];
|
||||||
randBerry.stackCount--;
|
randBerry.pokemon.heldItemManager.remove(randBerry.item);
|
||||||
if (randBerry.stackCount === 0) {
|
stolenBerryMap.push(randBerry);
|
||||||
globalScene.removeModifier(randBerry);
|
berryMap.splice(index, 1);
|
||||||
berryItems.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
await globalScene.updateModifiers(true, true);
|
await globalScene.updateModifiers(true);
|
||||||
|
|
||||||
// Pokemon joins the team, with 2 egg moves
|
// Pokemon joins the team, with 2 egg moves
|
||||||
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
||||||
|
@ -7,7 +7,6 @@ import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-en
|
|||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import type { EnemyPartyConfig, EnemyPokemonConfig } from "../utils/encounter-phase-utils";
|
import type { EnemyPartyConfig, EnemyPokemonConfig } from "../utils/encounter-phase-utils";
|
||||||
import {
|
import {
|
||||||
generateModifierType,
|
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
setEncounterRewards,
|
setEncounterRewards,
|
||||||
@ -21,11 +20,9 @@ import { NumberHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#
|
|||||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { allSpecies } from "#app/data/data-lists";
|
import { allSpecies } from "#app/data/data-lists";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
import { HiddenAbilityRateBoosterModifier } from "#app/modifier/modifier";
|
||||||
import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv";
|
||||||
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import i18next from "#app/plugins/i18n";
|
import i18next from "#app/plugins/i18n";
|
||||||
import {
|
import {
|
||||||
@ -35,15 +32,17 @@ import {
|
|||||||
import { getLevelTotalExp } from "#app/data/exp";
|
import { getLevelTotalExp } from "#app/data/exp";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { PlayerGender } from "#enums/player-gender";
|
import { PlayerGender } from "#enums/player-gender";
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import type HeldModifierConfig from "#app/@types/held-modifier-config";
|
|
||||||
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
||||||
import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
|
import type { HeldItemConfiguration, HeldItemSpecs } from "#app/items/held-item-data-types";
|
||||||
|
import { assignItemsFromConfiguration } from "#app/items/held-item-pool";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
/** i18n namespace for encounter */
|
/** i18n namespace for encounter */
|
||||||
const namespace = "mysteryEncounters/weirdDream";
|
const namespace = "mysteryEncounters/weirdDream";
|
||||||
@ -265,24 +264,20 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
|
|||||||
dataSource.player = false;
|
dataSource.player = false;
|
||||||
|
|
||||||
// Copy held items to new pokemon
|
// Copy held items to new pokemon
|
||||||
const newPokemonHeldItemConfigs: HeldModifierConfig[] = [];
|
// TODO: Make items untransferable
|
||||||
for (const item of transformation.heldItems) {
|
const newPokemonHeldItemConfig = transformation.heldItems;
|
||||||
newPokemonHeldItemConfigs.push({
|
|
||||||
modifier: item.clone() as PokemonHeldItemModifier,
|
|
||||||
stackCount: item.getStackCount(),
|
|
||||||
isTransferable: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Any pokemon that is below 570 BST gets +20 permanent BST to 3 stats
|
// Any pokemon that is below 570 BST gets +20 permanent BST to 3 stats
|
||||||
if (shouldGetOldGateau(newPokemon)) {
|
if (shouldGetOldGateau(newPokemon)) {
|
||||||
const stats = getOldGateauBoostedStats(newPokemon);
|
const stats = getOldGateauBoostedStats(newPokemon);
|
||||||
newPokemonHeldItemConfigs.push({
|
const gateauItem = {
|
||||||
modifier: generateModifierType(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU, [
|
id: HeldItemId.OLD_GATEAU,
|
||||||
OLD_GATEAU_STATS_UP,
|
stack: 1,
|
||||||
stats,
|
data: { statModifier: OLD_GATEAU_STATS_UP, stats: stats },
|
||||||
]) as PokemonHeldItemModifierType,
|
} as HeldItemSpecs;
|
||||||
stackCount: 1,
|
newPokemonHeldItemConfig.push({
|
||||||
isTransferable: false,
|
entry: gateauItem,
|
||||||
|
count: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +286,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
|
|||||||
isBoss: newPokemon.getSpeciesForm().getBaseStatTotal() > NON_LEGENDARY_BST_THRESHOLD,
|
isBoss: newPokemon.getSpeciesForm().getBaseStatTotal() > NON_LEGENDARY_BST_THRESHOLD,
|
||||||
level: previousPokemon.level,
|
level: previousPokemon.level,
|
||||||
dataSource: dataSource,
|
dataSource: dataSource,
|
||||||
modifierConfigs: newPokemonHeldItemConfigs,
|
heldItemConfig: newPokemonHeldItemConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
enemyPokemonConfigs.push(enemyConfig);
|
enemyPokemonConfigs.push(enemyConfig);
|
||||||
@ -323,12 +318,12 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
|
|||||||
setEncounterRewards(
|
setEncounterRewards(
|
||||||
{
|
{
|
||||||
guaranteedModifierTiers: [
|
guaranteedModifierTiers: [
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ROGUE,
|
RewardTier.ROGUE,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.ULTRA,
|
RewardTier.ULTRA,
|
||||||
ModifierTier.GREAT,
|
RewardTier.GREAT,
|
||||||
ModifierTier.GREAT,
|
RewardTier.GREAT,
|
||||||
],
|
],
|
||||||
fillRemaining: false,
|
fillRemaining: false,
|
||||||
},
|
},
|
||||||
@ -372,7 +367,7 @@ interface PokemonTransformation {
|
|||||||
previousPokemon: PlayerPokemon;
|
previousPokemon: PlayerPokemon;
|
||||||
newSpecies: PokemonSpecies;
|
newSpecies: PokemonSpecies;
|
||||||
newPokemon: PlayerPokemon;
|
newPokemon: PlayerPokemon;
|
||||||
heldItems: PokemonHeldItemModifier[];
|
heldItems: HeldItemConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTeamTransformations(): PokemonTransformation[] {
|
function getTeamTransformations(): PokemonTransformation[] {
|
||||||
@ -397,9 +392,7 @@ function getTeamTransformations(): PokemonTransformation[] {
|
|||||||
for (let i = 0; i < numPokemon; i++) {
|
for (let i = 0; i < numPokemon; i++) {
|
||||||
const removed = removedPokemon[i];
|
const removed = removedPokemon[i];
|
||||||
const index = pokemonTransformations.findIndex(p => p.previousPokemon.id === removed.id);
|
const index = pokemonTransformations.findIndex(p => p.previousPokemon.id === removed.id);
|
||||||
pokemonTransformations[index].heldItems = removed
|
pokemonTransformations[index].heldItems = removed.heldItemManager.generateHeldItemConfiguration();
|
||||||
.getHeldItems()
|
|
||||||
.filter(m => !(m instanceof PokemonFormChangeItemModifier));
|
|
||||||
|
|
||||||
const bst = removed.getSpeciesForm().getBaseStatTotal();
|
const bst = removed.getSpeciesForm().getBaseStatTotal();
|
||||||
let newBstRange: [number, number];
|
let newBstRange: [number, number];
|
||||||
@ -455,22 +448,22 @@ async function doNewTeamPostProcess(transformations: PokemonTransformation[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy old items to new pokemon
|
// Copy old items to new pokemon
|
||||||
for (const item of transformation.heldItems) {
|
const heldItemConfiguration = transformation.heldItems;
|
||||||
item.pokemonId = newPokemon.id;
|
|
||||||
globalScene.addModifier(item, false, false, false, true);
|
|
||||||
}
|
|
||||||
// Any pokemon that is below 570 BST gets +20 permanent BST to 3 stats
|
// Any pokemon that is below 570 BST gets +20 permanent BST to 3 stats
|
||||||
if (shouldGetOldGateau(newPokemon)) {
|
if (shouldGetOldGateau(newPokemon)) {
|
||||||
const stats = getOldGateauBoostedStats(newPokemon);
|
const stats = getOldGateauBoostedStats(newPokemon);
|
||||||
const modType = modifierTypes
|
const gateauItem = {
|
||||||
.MYSTERY_ENCOUNTER_OLD_GATEAU()
|
id: HeldItemId.OLD_GATEAU,
|
||||||
.generateType(globalScene.getPlayerParty(), [OLD_GATEAU_STATS_UP, stats])
|
stack: 1,
|
||||||
?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU);
|
data: { statModifier: OLD_GATEAU_STATS_UP, stats: stats },
|
||||||
const modifier = modType?.newModifier(newPokemon);
|
} as HeldItemSpecs;
|
||||||
if (modifier) {
|
heldItemConfiguration.push({
|
||||||
globalScene.addModifier(modifier, false, false, false, true);
|
entry: gateauItem,
|
||||||
}
|
count: 1,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
assignItemsFromConfiguration(heldItemConfiguration, newPokemon);
|
||||||
|
|
||||||
newPokemon.calculateStats();
|
newPokemon.calculateStats();
|
||||||
await newPokemon.updateInfo();
|
await newPokemon.updateInfo();
|
||||||
|
@ -8,14 +8,14 @@ import { StatusEffect } from "#enums/status-effect";
|
|||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import { AttackTypeBoosterModifier } from "#app/modifier/modifier";
|
|
||||||
import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { coerceArray, isNullOrUndefined } from "#app/utils/common";
|
import { coerceArray, isNullOrUndefined } from "#app/utils/common";
|
||||||
import type { AbilityId } from "#enums/ability-id";
|
import type { AbilityId } from "#enums/ability-id";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { TimeOfDay } from "#enums/time-of-day";
|
import { TimeOfDay } from "#enums/time-of-day";
|
||||||
|
import type { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
export interface EncounterRequirement {
|
export interface EncounterRequirement {
|
||||||
meetsRequirement(): boolean; // Boolean to see if a requirement is met
|
meetsRequirement(): boolean; // Boolean to see if a requirement is met
|
||||||
@ -351,39 +351,6 @@ export class PartySizeRequirement extends EncounterSceneRequirement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PersistentModifierRequirement extends EncounterSceneRequirement {
|
|
||||||
requiredHeldItemModifiers: string[];
|
|
||||||
minNumberOfItems: number;
|
|
||||||
|
|
||||||
constructor(heldItem: string | string[], minNumberOfItems = 1) {
|
|
||||||
super();
|
|
||||||
this.minNumberOfItems = minNumberOfItems;
|
|
||||||
this.requiredHeldItemModifiers = coerceArray(heldItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
override meetsRequirement(): boolean {
|
|
||||||
const partyPokemon = globalScene.getPlayerParty();
|
|
||||||
if (isNullOrUndefined(partyPokemon) || this.requiredHeldItemModifiers?.length < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let modifierCount = 0;
|
|
||||||
for (const modifier of this.requiredHeldItemModifiers) {
|
|
||||||
const matchingMods = globalScene.findModifiers(m => m.constructor.name === modifier);
|
|
||||||
if (matchingMods?.length > 0) {
|
|
||||||
for (const matchingMod of matchingMods) {
|
|
||||||
modifierCount += matchingMod.stackCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return modifierCount >= this.minNumberOfItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
override getDialogueToken(_pokemon?: PlayerPokemon): [string, string] {
|
|
||||||
return ["requiredItem", this.requiredHeldItemModifiers[0]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MoneyRequirement extends EncounterSceneRequirement {
|
export class MoneyRequirement extends EncounterSceneRequirement {
|
||||||
requiredMoney: number; // Static value
|
requiredMoney: number; // Static value
|
||||||
scalingMultiplier: number; // Calculates required money based off wave index
|
scalingMultiplier: number; // Calculates required money based off wave index
|
||||||
@ -833,72 +800,13 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class HeldItemRequirement extends EncounterPokemonRequirement {
|
export class HeldItemRequirement extends EncounterPokemonRequirement {
|
||||||
requiredHeldItemModifiers: string[];
|
requiredHeldItems: HeldItemId[] | HeldItemCategoryId[];
|
||||||
minNumberOfPokemon: number;
|
|
||||||
invertQuery: boolean;
|
|
||||||
requireTransferable: boolean;
|
|
||||||
|
|
||||||
constructor(heldItem: string | string[], minNumberOfPokemon = 1, invertQuery = false, requireTransferable = true) {
|
|
||||||
super();
|
|
||||||
this.minNumberOfPokemon = minNumberOfPokemon;
|
|
||||||
this.invertQuery = invertQuery;
|
|
||||||
this.requiredHeldItemModifiers = coerceArray(heldItem);
|
|
||||||
this.requireTransferable = requireTransferable;
|
|
||||||
}
|
|
||||||
|
|
||||||
override meetsRequirement(): boolean {
|
|
||||||
const partyPokemon = globalScene.getPlayerParty();
|
|
||||||
if (isNullOrUndefined(partyPokemon)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
|
|
||||||
}
|
|
||||||
|
|
||||||
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
|
|
||||||
if (!this.invertQuery) {
|
|
||||||
return partyPokemon.filter(pokemon =>
|
|
||||||
this.requiredHeldItemModifiers.some(heldItem => {
|
|
||||||
return pokemon.getHeldItems().some(it => {
|
|
||||||
return it.constructor.name === heldItem && (!this.requireTransferable || it.isTransferable);
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// for an inverted query, we only want to get the pokemon that have any held items that are NOT in requiredHeldItemModifiers
|
|
||||||
// E.g. functions as a blacklist
|
|
||||||
return partyPokemon.filter(
|
|
||||||
pokemon =>
|
|
||||||
pokemon.getHeldItems().filter(it => {
|
|
||||||
return (
|
|
||||||
!this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) &&
|
|
||||||
(!this.requireTransferable || it.isTransferable)
|
|
||||||
);
|
|
||||||
}).length > 0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
|
|
||||||
const requiredItems = pokemon?.getHeldItems().filter(it => {
|
|
||||||
return (
|
|
||||||
this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) &&
|
|
||||||
(!this.requireTransferable || it.isTransferable)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (requiredItems && requiredItems.length > 0) {
|
|
||||||
return ["heldItem", requiredItems[0].type.name];
|
|
||||||
}
|
|
||||||
return ["heldItem", ""];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRequirement {
|
|
||||||
requiredHeldItemTypes: PokemonType[];
|
|
||||||
minNumberOfPokemon: number;
|
minNumberOfPokemon: number;
|
||||||
invertQuery: boolean;
|
invertQuery: boolean;
|
||||||
requireTransferable: boolean;
|
requireTransferable: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
heldItemTypes: PokemonType | PokemonType[],
|
heldItem: HeldItemId | HeldItemId[] | HeldItemCategoryId | HeldItemCategoryId[],
|
||||||
minNumberOfPokemon = 1,
|
minNumberOfPokemon = 1,
|
||||||
invertQuery = false,
|
invertQuery = false,
|
||||||
requireTransferable = true,
|
requireTransferable = true,
|
||||||
@ -906,7 +814,7 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
|
|||||||
super();
|
super();
|
||||||
this.minNumberOfPokemon = minNumberOfPokemon;
|
this.minNumberOfPokemon = minNumberOfPokemon;
|
||||||
this.invertQuery = invertQuery;
|
this.invertQuery = invertQuery;
|
||||||
this.requiredHeldItemTypes = coerceArray(heldItemTypes);
|
this.requiredHeldItems = coerceArray(heldItem);
|
||||||
this.requireTransferable = requireTransferable;
|
this.requireTransferable = requireTransferable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -921,14 +829,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
|
|||||||
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
|
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
|
||||||
if (!this.invertQuery) {
|
if (!this.invertQuery) {
|
||||||
return partyPokemon.filter(pokemon =>
|
return partyPokemon.filter(pokemon =>
|
||||||
this.requiredHeldItemTypes.some(heldItemType => {
|
this.requiredHeldItems.some(heldItem => {
|
||||||
return pokemon.getHeldItems().some(it => {
|
(pokemon.heldItemManager.hasItem(heldItem) || pokemon.heldItemManager.hasItemCategory(heldItem)) &&
|
||||||
return (
|
(!this.requireTransferable || allHeldItems[heldItem].isTransferable);
|
||||||
it instanceof AttackTypeBoosterModifier &&
|
|
||||||
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
|
|
||||||
(!this.requireTransferable || it.isTransferable)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -936,30 +839,24 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
|
|||||||
// E.g. functions as a blacklist
|
// E.g. functions as a blacklist
|
||||||
return partyPokemon.filter(
|
return partyPokemon.filter(
|
||||||
pokemon =>
|
pokemon =>
|
||||||
pokemon.getHeldItems().filter(it => {
|
pokemon.getHeldItems().filter(item => {
|
||||||
return !this.requiredHeldItemTypes.some(
|
return (
|
||||||
heldItemType =>
|
!this.requiredHeldItems.some(heldItem => item === heldItem) &&
|
||||||
it instanceof AttackTypeBoosterModifier &&
|
(!this.requireTransferable || allHeldItems[item].isTransferable)
|
||||||
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
|
|
||||||
(!this.requireTransferable || it.isTransferable),
|
|
||||||
);
|
);
|
||||||
}).length > 0,
|
}).length > 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
|
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
|
||||||
const requiredItems = pokemon?.getHeldItems().filter(it => {
|
const requiredItems = pokemon?.getHeldItems().filter(item => {
|
||||||
return (
|
return (
|
||||||
this.requiredHeldItemTypes.some(
|
this.requiredHeldItems.some(heldItem => item === heldItem) &&
|
||||||
heldItemType =>
|
(!this.requireTransferable || allHeldItems[item].isTransferable)
|
||||||
it instanceof AttackTypeBoosterModifier &&
|
|
||||||
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType,
|
|
||||||
) &&
|
|
||||||
(!this.requireTransferable || it.isTransferable)
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (requiredItems && requiredItems.length > 0) {
|
if (requiredItems && requiredItems.length > 0) {
|
||||||
return ["heldItem", requiredItems[0].type.name];
|
return ["heldItem", allHeldItems[requiredItems[0]].name];
|
||||||
}
|
}
|
||||||
return ["heldItem", ""];
|
return ["heldItem", ""];
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,6 @@ import type PokemonSpecies from "#app/data/pokemon-species";
|
|||||||
import type { IEggOptions } from "#app/data/egg";
|
import type { IEggOptions } from "#app/data/egg";
|
||||||
import { Egg } from "#app/data/egg";
|
import { Egg } from "#app/data/egg";
|
||||||
import type { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import type { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
import type HeldModifierConfig from "#app/@types/held-modifier-config";
|
|
||||||
import type { Variant } from "#app/sprites/variant";
|
import type { Variant } from "#app/sprites/variant";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -53,6 +52,9 @@ import { PokemonType } from "#enums/pokemon-type";
|
|||||||
import { getNatureName } from "#app/data/nature";
|
import { getNatureName } from "#app/data/nature";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { timedEventManager } from "#app/global-event-manager";
|
import { timedEventManager } from "#app/global-event-manager";
|
||||||
|
import type { HeldItemConfiguration, PokemonItemMap } from "#app/items/held-item-data-types";
|
||||||
|
import { HeldItemCategoryId, type HeldItemId, isItemInCategory } from "#enums/held-item-id";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Animates exclamation sprite over trainer's head at start of encounter
|
* Animates exclamation sprite over trainer's head at start of encounter
|
||||||
@ -102,7 +104,7 @@ export interface EnemyPokemonConfig {
|
|||||||
/** Can set just the status, or pass a timer on the status turns */
|
/** Can set just the status, or pass a timer on the status turns */
|
||||||
status?: StatusEffect | [StatusEffect, number];
|
status?: StatusEffect | [StatusEffect, number];
|
||||||
mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
|
mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
|
||||||
modifierConfigs?: HeldModifierConfig[];
|
heldItemConfig?: HeldItemConfiguration;
|
||||||
tags?: BattlerTagType[];
|
tags?: BattlerTagType[];
|
||||||
dataSource?: PokemonData;
|
dataSource?: PokemonData;
|
||||||
tera?: PokemonType;
|
tera?: PokemonType;
|
||||||
@ -434,8 +436,8 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
|
|||||||
battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD,
|
battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD,
|
||||||
);
|
);
|
||||||
const customModifierTypes = partyConfig?.pokemonConfigs
|
const customModifierTypes = partyConfig?.pokemonConfigs
|
||||||
?.filter(config => config?.modifierConfigs)
|
?.filter(config => config?.heldItemConfig)
|
||||||
.map(config => config.modifierConfigs!);
|
.map(config => config.heldItemConfig!);
|
||||||
globalScene.generateEnemyModifiers(customModifierTypes);
|
globalScene.generateEnemyModifiers(customModifierTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1305,3 +1307,29 @@ export function calculateRareSpawnAggregateStats(luckValue: number) {
|
|||||||
|
|
||||||
console.log(stats);
|
console.log(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate over the party until an item is successfully given
|
||||||
|
export function assignItemToFirstFreePokemon(item: HeldItemId, party: Pokemon[]): void {
|
||||||
|
for (const pokemon of party) {
|
||||||
|
const stack = pokemon.heldItemManager.getStack(item);
|
||||||
|
if (stack < allHeldItems[item].getMaxStackCount()) {
|
||||||
|
pokemon.heldItemManager.add(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an item map of berries to pokemon, storing each berry separately (splitting up stacks)
|
||||||
|
export function getPartyBerries(): PokemonItemMap[] {
|
||||||
|
const pokemonItems: PokemonItemMap[] = [];
|
||||||
|
globalScene.getPlayerParty().forEach(pokemon => {
|
||||||
|
const berries = pokemon.getHeldItems().filter(item => isItemInCategory(item, HeldItemCategoryId.BERRY));
|
||||||
|
berries.forEach(berryId => {
|
||||||
|
const berryStack = pokemon.heldItemManager.getStack(berryId);
|
||||||
|
for (let i = 1; i <= berryStack; i++) {
|
||||||
|
pokemonItems.push({ item: berryId, pokemon: pokemon });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return pokemonItems;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
|
import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
|
||||||
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
||||||
import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import {
|
import {
|
||||||
@ -28,7 +27,6 @@ import {
|
|||||||
showEncounterText,
|
showEncounterText,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { Gender } from "#app/data/gender";
|
import { Gender } from "#app/data/gender";
|
||||||
import type { PermanentStat } from "#enums/stat";
|
import type { PermanentStat } from "#enums/stat";
|
||||||
@ -37,6 +35,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
|||||||
import type { AbilityId } from "#enums/ability-id";
|
import type { AbilityId } from "#enums/ability-id";
|
||||||
import type { PokeballType } from "#enums/pokeball";
|
import type { PokeballType } from "#enums/pokeball";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
/** Will give +1 level every 10 waves */
|
/** Will give +1 level every 10 waves */
|
||||||
export const STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER = 1;
|
export const STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER = 1;
|
||||||
@ -387,40 +386,11 @@ export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: numb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export function applyHeldItemWithFallback(pokemon: Pokemon, item: HeldItemId, fallbackItem?: HeldItemId) {
|
||||||
* Will attempt to add a new modifier to a Pokemon.
|
const added = pokemon.heldItemManager.add(item);
|
||||||
* If the Pokemon already has max stacks of that item, it will instead apply 'fallbackModifierType', if specified.
|
if (!added && fallbackItem) {
|
||||||
* @param scene
|
pokemon.heldItemManager.add(fallbackItem);
|
||||||
* @param pokemon
|
|
||||||
* @param modType
|
|
||||||
* @param fallbackModifierType
|
|
||||||
*/
|
|
||||||
export async function applyModifierTypeToPlayerPokemon(
|
|
||||||
pokemon: PlayerPokemon,
|
|
||||||
modType: PokemonHeldItemModifierType,
|
|
||||||
fallbackModifierType?: PokemonHeldItemModifierType,
|
|
||||||
) {
|
|
||||||
// Check if the Pokemon has max stacks of that item already
|
|
||||||
const modifier = modType.newModifier(pokemon);
|
|
||||||
const existing = globalScene.findModifier(
|
|
||||||
m =>
|
|
||||||
m instanceof PokemonHeldItemModifier &&
|
|
||||||
m.type.id === modType.id &&
|
|
||||||
m.pokemonId === pokemon.id &&
|
|
||||||
m.matchType(modifier),
|
|
||||||
) as PokemonHeldItemModifier;
|
|
||||||
|
|
||||||
// At max stacks
|
|
||||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
|
|
||||||
if (!fallbackModifierType) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply fallback
|
|
||||||
return applyModifierTypeToPlayerPokemon(pokemon, fallbackModifierType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
globalScene.addModifier(modifier, false, false, false, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -687,20 +657,10 @@ export async function catchPokemon(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const addToParty = (slotIndex?: number) => {
|
const addToParty = (slotIndex?: number) => {
|
||||||
const newPokemon = pokemon.addToParty(pokeballType, slotIndex);
|
pokemon.addToParty(pokeballType, slotIndex);
|
||||||
const modifiers = globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier, false);
|
|
||||||
if (globalScene.getPlayerParty().filter(p => p.isShiny()).length === 6) {
|
if (globalScene.getPlayerParty().filter(p => p.isShiny()).length === 6) {
|
||||||
globalScene.validateAchv(achvs.SHINY_PARTY);
|
globalScene.validateAchv(achvs.SHINY_PARTY);
|
||||||
}
|
}
|
||||||
Promise.all(modifiers.map(m => globalScene.addModifier(m, true))).then(() => {
|
|
||||||
globalScene.updateModifiers(true);
|
|
||||||
removePokemon();
|
|
||||||
if (newPokemon) {
|
|
||||||
newPokemon.loadAssets().then(end);
|
|
||||||
} else {
|
|
||||||
end();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
Promise.all([pokemon.hideInfo(), globalScene.gameData.setPokemonCaught(pokemon)]).then(() => {
|
Promise.all([pokemon.hideInfo(), globalScene.gameData.setPokemonCaught(pokemon)]).then(() => {
|
||||||
if (globalScene.getPlayerParty().length === 6) {
|
if (globalScene.getPlayerParty().length === 6) {
|
||||||
|
@ -25,6 +25,11 @@ import {
|
|||||||
type SpeciesFormChangeTrigger,
|
type SpeciesFormChangeTrigger,
|
||||||
SpeciesFormChangeWeatherTrigger,
|
SpeciesFormChangeWeatherTrigger,
|
||||||
} from "./pokemon-forms/form-change-triggers";
|
} from "./pokemon-forms/form-change-triggers";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export function formChangeItemName(id: FormChangeItem) {
|
||||||
|
return i18next.t(`modifierType:FormChangeItem.${FormChangeItem[id]}`);
|
||||||
|
}
|
||||||
|
|
||||||
export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean;
|
export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean;
|
||||||
export type SpeciesFormChangeConditionEnforceFunc = (p: Pokemon) => void;
|
export type SpeciesFormChangeConditionEnforceFunc = (p: Pokemon) => void;
|
||||||
|
@ -3,7 +3,6 @@ import { coerceArray, type Constructor } from "#app/utils/common";
|
|||||||
import type { TimeOfDay } from "#enums/time-of-day";
|
import type { TimeOfDay } from "#enums/time-of-day";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { SpeciesFormChange } from "#app/data/pokemon-forms";
|
import type { SpeciesFormChange } from "#app/data/pokemon-forms";
|
||||||
import type { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { FormChangeItem } from "#enums/form-change-item";
|
import { FormChangeItem } from "#enums/form-change-item";
|
||||||
@ -77,16 +76,11 @@ export class SpeciesFormChangeItemTrigger extends SpeciesFormChangeTrigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canChange(pokemon: Pokemon): boolean {
|
canChange(pokemon: Pokemon): boolean {
|
||||||
return !!globalScene.findModifier(r => {
|
const matchItem = pokemon.heldItemManager.formChangeItems[this.item];
|
||||||
// Assume that if m has the `formChangeItem` property, then it is a PokemonFormChangeItemModifier
|
if (!matchItem) {
|
||||||
const m = r as PokemonFormChangeItemModifier;
|
return false;
|
||||||
return (
|
}
|
||||||
"formChangeItem" in m &&
|
return matchItem.active === this.active;
|
||||||
m.pokemonId === pokemon.id &&
|
|
||||||
m.formChangeItem === this.item &&
|
|
||||||
m.active === this.active
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,6 +1004,7 @@ export function getRandomPartyMemberFunc(
|
|||||||
undefined,
|
undefined,
|
||||||
false,
|
false,
|
||||||
undefined,
|
undefined,
|
||||||
|
undefined,
|
||||||
postProcess,
|
postProcess,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -1028,7 +1029,16 @@ function getSpeciesFilterRandomPartyMemberFunc(
|
|||||||
.getTrainerSpeciesForLevel(level, true, strength, waveIndex),
|
.getTrainerSpeciesForLevel(level, true, strength, waveIndex),
|
||||||
);
|
);
|
||||||
|
|
||||||
return globalScene.addEnemyPokemon(species, level, trainerSlot, undefined, false, undefined, postProcess);
|
return globalScene.addEnemyPokemon(
|
||||||
|
species,
|
||||||
|
level,
|
||||||
|
trainerSlot,
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
postProcess,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
145
src/enums/held-item-id.ts
Normal file
145
src/enums/held-item-id.ts
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
export const HeldItemId = {
|
||||||
|
NONE: 0x0000,
|
||||||
|
|
||||||
|
// Berries
|
||||||
|
SITRUS_BERRY: 0x0101,
|
||||||
|
LUM_BERRY: 0x0102,
|
||||||
|
ENIGMA_BERRY: 0x0103,
|
||||||
|
LIECHI_BERRY: 0x0104,
|
||||||
|
GANLON_BERRY: 0x0105,
|
||||||
|
PETAYA_BERRY: 0x0106,
|
||||||
|
APICOT_BERRY: 0x0107,
|
||||||
|
SALAC_BERRY: 0x0108,
|
||||||
|
LANSAT_BERRY: 0x0109,
|
||||||
|
STARF_BERRY: 0x010A,
|
||||||
|
LEPPA_BERRY: 0x010B,
|
||||||
|
|
||||||
|
// Other items that are consumed
|
||||||
|
REVIVER_SEED: 0x0201,
|
||||||
|
WHITE_HERB: 0x0202,
|
||||||
|
|
||||||
|
// Type Boosters
|
||||||
|
SILK_SCARF: 0x0301,
|
||||||
|
BLACK_BELT: 0x0302,
|
||||||
|
SHARP_BEAK: 0x0303,
|
||||||
|
POISON_BARB: 0x0304,
|
||||||
|
SOFT_SAND: 0x0305,
|
||||||
|
HARD_STONE: 0x0306,
|
||||||
|
SILVER_POWDER: 0x0307,
|
||||||
|
SPELL_TAG: 0x0308,
|
||||||
|
METAL_COAT: 0x0309,
|
||||||
|
CHARCOAL: 0x030A,
|
||||||
|
MYSTIC_WATER: 0x030B,
|
||||||
|
MIRACLE_SEED: 0x030C,
|
||||||
|
MAGNET: 0x030D,
|
||||||
|
TWISTED_SPOON: 0x030E,
|
||||||
|
NEVER_MELT_ICE: 0x030F,
|
||||||
|
DRAGON_FANG: 0x0310,
|
||||||
|
BLACK_GLASSES: 0x0311,
|
||||||
|
FAIRY_FEATHER: 0x0312,
|
||||||
|
|
||||||
|
// Species Stat Boosters
|
||||||
|
LIGHT_BALL: 0x0401,
|
||||||
|
THICK_CLUB: 0x0402,
|
||||||
|
METAL_POWDER: 0x0403,
|
||||||
|
QUICK_POWDER: 0x0404,
|
||||||
|
DEEP_SEA_SCALE: 0x0405,
|
||||||
|
DEEP_SEA_TOOTH: 0x0406,
|
||||||
|
|
||||||
|
// Crit Boosters
|
||||||
|
SCOPE_LENS: 0x0501,
|
||||||
|
LEEK: 0x0502,
|
||||||
|
|
||||||
|
// Items increasing gains
|
||||||
|
LUCKY_EGG: 0x0601,
|
||||||
|
GOLDEN_EGG: 0x0602,
|
||||||
|
SOOTHE_BELL: 0x0603,
|
||||||
|
|
||||||
|
// Unique items
|
||||||
|
FOCUS_BAND: 0x0701,
|
||||||
|
QUICK_CLAW: 0x0702,
|
||||||
|
KINGS_ROCK: 0x0703,
|
||||||
|
LEFTOVERS: 0x0704,
|
||||||
|
SHELL_BELL: 0x0705,
|
||||||
|
MYSTICAL_ROCK: 0x0706,
|
||||||
|
WIDE_LENS: 0x0707,
|
||||||
|
MULTI_LENS: 0x0708,
|
||||||
|
GOLDEN_PUNCH: 0x0709,
|
||||||
|
GRIP_CLAW: 0x070A,
|
||||||
|
TOXIC_ORB: 0x070B,
|
||||||
|
FLAME_ORB: 0x070C,
|
||||||
|
SOUL_DEW: 0x070D,
|
||||||
|
BATON: 0x070E,
|
||||||
|
MINI_BLACK_HOLE: 0x070F,
|
||||||
|
EVIOLITE: 0x0710,
|
||||||
|
|
||||||
|
// Vitamins
|
||||||
|
HP_UP: 0x0801,
|
||||||
|
PROTEIN: 0x0802,
|
||||||
|
IRON: 0x0803,
|
||||||
|
CALCIUM: 0x0804,
|
||||||
|
ZINC: 0x0805,
|
||||||
|
CARBOS: 0x0806,
|
||||||
|
|
||||||
|
// Other stat boosting items
|
||||||
|
SHUCKLE_JUICE: 0x0907,
|
||||||
|
OLD_GATEAU: 0x0908,
|
||||||
|
MACHO_BRACE: 0x0909,
|
||||||
|
|
||||||
|
// Evo trackers
|
||||||
|
GIMMIGHOUL_EVO_TRACKER: 0x0A01,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeldItemId = (typeof HeldItemId)[keyof typeof HeldItemId];
|
||||||
|
|
||||||
|
type HeldItemName = keyof typeof HeldItemId;
|
||||||
|
type HeldItemValue = typeof HeldItemId[HeldItemName];
|
||||||
|
|
||||||
|
// Use a type-safe reducer to force number keys and values
|
||||||
|
export const HeldItemNames: Record<HeldItemValue, HeldItemName> = Object.entries(HeldItemId).reduce(
|
||||||
|
(acc, [key, value]) => {
|
||||||
|
acc[value as HeldItemValue] = key as HeldItemName;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<HeldItemValue, HeldItemName>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
export const HeldItemCategoryId = {
|
||||||
|
NONE: 0x0000,
|
||||||
|
BERRY: 0x0100,
|
||||||
|
CONSUMABLE: 0x0200,
|
||||||
|
TYPE_ATTACK_BOOSTER: 0x0300,
|
||||||
|
SPECIES_STAT_BOOSTER: 0x0400,
|
||||||
|
CRIT_BOOSTER: 0x0500,
|
||||||
|
GAIN_INCREASE: 0x0600,
|
||||||
|
UNIQUE: 0x0700,
|
||||||
|
VITAMIN: 0x0800,
|
||||||
|
BASE_STAT_BOOST: 0x0900,
|
||||||
|
EVO_TRACKER: 0x0A00,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeldItemCategoryId = (typeof HeldItemCategoryId)[keyof typeof HeldItemCategoryId];
|
||||||
|
|
||||||
|
const ITEM_CATEGORY_MASK = 0xFF00
|
||||||
|
|
||||||
|
export function getHeldItemCategory(itemId: HeldItemId): HeldItemCategoryId {
|
||||||
|
return itemId & ITEM_CATEGORY_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCategoryId(categoryId: HeldItemCategoryId): boolean {
|
||||||
|
return (categoryId & ITEM_CATEGORY_MASK) === categoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isItemInCategory(itemId: HeldItemId, category: HeldItemCategoryId): boolean {
|
||||||
|
return getHeldItemCategory(itemId) === category;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isItemInRequested(
|
||||||
|
itemId: HeldItemId,
|
||||||
|
requestedItems: (HeldItemCategoryId | HeldItemId)[]
|
||||||
|
): boolean {
|
||||||
|
return requestedItems.some(entry => {
|
||||||
|
itemId === entry || (itemId & ITEM_CATEGORY_MASK) === entry
|
||||||
|
});
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
export enum ModifierPoolType {
|
export enum ModifierPoolType {
|
||||||
PLAYER,
|
PLAYER,
|
||||||
|
ENEMY_BUFF,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum HeldItemPoolType {
|
||||||
WILD,
|
WILD,
|
||||||
TRAINER,
|
TRAINER,
|
||||||
ENEMY_BUFF,
|
DAILY_STARTER,
|
||||||
DAILY_STARTER
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export enum ModifierTier {
|
export enum RewardTier {
|
||||||
COMMON,
|
COMMON,
|
||||||
GREAT,
|
GREAT,
|
||||||
ULTRA,
|
ULTRA,
|
@ -1,5 +1,6 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { BerryType } from "#enums/berry-type";
|
||||||
import type Move from "../data/moves/move";
|
import type Move from "../data/moves/move";
|
||||||
import type { BerryModifier } from "../modifier/modifier";
|
|
||||||
|
|
||||||
/** Alias for all {@linkcode BattleScene} events */
|
/** Alias for all {@linkcode BattleScene} events */
|
||||||
export enum BattleSceneEventType {
|
export enum BattleSceneEventType {
|
||||||
@ -81,12 +82,13 @@ export class MoveUsedEvent extends Event {
|
|||||||
* @extends Event
|
* @extends Event
|
||||||
*/
|
*/
|
||||||
export class BerryUsedEvent extends Event {
|
export class BerryUsedEvent extends Event {
|
||||||
/** The {@linkcode BerryModifier} being used */
|
/** The {@linkcode BerryType} being used */
|
||||||
public berryModifier: BerryModifier;
|
public pokemon: Pokemon;
|
||||||
constructor(berry: BerryModifier) {
|
public berryType: BerryType;
|
||||||
|
constructor(pokemon: Pokemon, berryType: BerryType) {
|
||||||
super(BattleSceneEventType.BERRY_USED);
|
super(BattleSceneEventType.BERRY_USED);
|
||||||
|
this.pokemon = pokemon;
|
||||||
this.berryModifier = berry;
|
this.berryType = berryType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,8 @@ import {
|
|||||||
SpeciesFormChangeWeatherTrigger,
|
SpeciesFormChangeWeatherTrigger,
|
||||||
} from "#app/data/pokemon-forms/form-change-triggers";
|
} from "#app/data/pokemon-forms/form-change-triggers";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import { FieldEffectModifier } from "#app/modifier/modifier";
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
|
||||||
export class Arena {
|
export class Arena {
|
||||||
public biomeType: BiomeId;
|
public biomeType: BiomeId;
|
||||||
@ -344,7 +345,7 @@ export class Arena {
|
|||||||
|
|
||||||
if (!isNullOrUndefined(user)) {
|
if (!isNullOrUndefined(user)) {
|
||||||
weatherDuration.value = 5;
|
weatherDuration.value = 5;
|
||||||
globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, weatherDuration);
|
applyHeldItems(ITEM_EFFECT.FIELD_EFFECT, { pokemon: user, fieldDuration: weatherDuration });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.weather = weather ? new Weather(weather, weatherDuration.value) : null;
|
this.weather = weather ? new Weather(weather, weatherDuration.value) : null;
|
||||||
@ -431,7 +432,7 @@ export class Arena {
|
|||||||
|
|
||||||
if (!isNullOrUndefined(user)) {
|
if (!isNullOrUndefined(user)) {
|
||||||
terrainDuration.value = 5;
|
terrainDuration.value = 5;
|
||||||
globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, terrainDuration);
|
applyHeldItems(ITEM_EFFECT.FIELD_EFFECT, { pokemon: user, fieldDuration: terrainDuration });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.terrain = terrain ? new Terrain(terrain, terrainDuration.value) : null;
|
this.terrain = terrain ? new Terrain(terrain, terrainDuration.value) : null;
|
||||||
|
190
src/field/pokemon-held-item-manager.ts
Normal file
190
src/field/pokemon-held-item-manager.ts
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { isItemInCategory, isItemInRequested, type HeldItemCategoryId, type HeldItemId } from "#app/enums/held-item-id";
|
||||||
|
import type { FormChangeItem } from "#enums/form-change-item";
|
||||||
|
import {
|
||||||
|
type HeldItemConfiguration,
|
||||||
|
isHeldItemSpecs,
|
||||||
|
type HeldItemDataMap,
|
||||||
|
type HeldItemSpecs,
|
||||||
|
} from "#app/items/held-item-data-types";
|
||||||
|
|
||||||
|
interface FormChangeItemProperties {
|
||||||
|
active: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormChangeItemPropertyMap = {
|
||||||
|
[key in FormChangeItem]?: FormChangeItemProperties;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PokemonItemManager {
|
||||||
|
public heldItems: HeldItemDataMap;
|
||||||
|
public formChangeItems: FormChangeItemPropertyMap;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.heldItems = {};
|
||||||
|
this.formChangeItems = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getItemSpecs(id: HeldItemId): HeldItemSpecs | undefined {
|
||||||
|
const item = this.heldItems[id];
|
||||||
|
if (item) {
|
||||||
|
const itemSpecs: HeldItemSpecs = {
|
||||||
|
...item,
|
||||||
|
id,
|
||||||
|
};
|
||||||
|
return itemSpecs;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateHeldItemConfiguration(restrictedIds?: HeldItemId[]): HeldItemConfiguration {
|
||||||
|
const config: HeldItemConfiguration = [];
|
||||||
|
for (const [k, item] of Object.entries(this.heldItems)) {
|
||||||
|
const id = Number(k);
|
||||||
|
if (item && (!restrictedIds || id in restrictedIds)) {
|
||||||
|
const specs: HeldItemSpecs = { ...item, id };
|
||||||
|
config.push({ entry: specs, count: 1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHeldItems(): number[] {
|
||||||
|
return Object.keys(this.heldItems).map(k => Number(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransferableHeldItems(): number[] {
|
||||||
|
return Object.keys(this.heldItems)
|
||||||
|
.filter(k => allHeldItems[k].isTransferable)
|
||||||
|
.map(k => Number(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
getStealableHeldItems(): number[] {
|
||||||
|
return Object.keys(this.heldItems)
|
||||||
|
.filter(k => allHeldItems[k].isStealable)
|
||||||
|
.map(k => Number(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
getSuppressableHeldItems(): number[] {
|
||||||
|
return Object.keys(this.heldItems)
|
||||||
|
.filter(k => allHeldItems[k].isSuppressable)
|
||||||
|
.map(k => Number(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
hasItem(itemType: HeldItemId): boolean {
|
||||||
|
return itemType in this.heldItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasItemCategory(categoryId: HeldItemCategoryId): boolean {
|
||||||
|
return Object.keys(this.heldItems).some(id => isItemInCategory(Number(id), categoryId));
|
||||||
|
}
|
||||||
|
|
||||||
|
getStack(itemType: HeldItemId): number {
|
||||||
|
const item = this.heldItems[itemType];
|
||||||
|
return item ? item.stack : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isMaxStack(itemType: HeldItemId): boolean {
|
||||||
|
const item = this.heldItems[itemType];
|
||||||
|
return item ? item.stack >= allHeldItems[itemType].getMaxStackCount() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideItems(newItems: HeldItemDataMap) {
|
||||||
|
this.heldItems = newItems;
|
||||||
|
// The following is to allow randomly generated item configs to have stack 0
|
||||||
|
for (const [item, properties] of Object.entries(this.heldItems)) {
|
||||||
|
if (!properties || properties.stack <= 0) {
|
||||||
|
delete this.heldItems[item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(itemType: HeldItemId | HeldItemSpecs, addStack = 1): boolean {
|
||||||
|
if (isHeldItemSpecs(itemType)) {
|
||||||
|
return this.addItemWithSpecs(itemType);
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxStack = allHeldItems[itemType].getMaxStackCount();
|
||||||
|
const item = this.heldItems[itemType];
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
// TODO: We may want an error message of some kind instead
|
||||||
|
if (item.stack < maxStack) {
|
||||||
|
item.stack = Math.min(item.stack + addStack, maxStack);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.heldItems[itemType] = { stack: Math.min(addStack, maxStack) };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
addItemWithSpecs(itemSpecs: HeldItemSpecs): boolean {
|
||||||
|
const id = itemSpecs.id;
|
||||||
|
const maxStack = allHeldItems[id].getMaxStackCount();
|
||||||
|
const item = this.heldItems[id];
|
||||||
|
|
||||||
|
const tempStack = item?.stack ?? 0;
|
||||||
|
|
||||||
|
this.heldItems[id] = itemSpecs;
|
||||||
|
this.heldItems[id].stack = Math.min(itemSpecs.stack + tempStack, maxStack);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(itemType: HeldItemId, removeStack = 1, all = false) {
|
||||||
|
const item = this.heldItems[itemType];
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
item.stack -= removeStack;
|
||||||
|
|
||||||
|
if (all || item.stack <= 0) {
|
||||||
|
delete this.heldItems[itemType];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterRequestedItems(requestedItems: (HeldItemCategoryId | HeldItemId)[], transferableOnly = true, exclude = false) {
|
||||||
|
const currentItems = transferableOnly ? this.getTransferableHeldItems() : this.getHeldItems();
|
||||||
|
return currentItems.filter(it => !exclude && isItemInRequested(it, requestedItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
addFormChangeItem(id: FormChangeItem) {
|
||||||
|
if (!(id in this.formChangeItems)) {
|
||||||
|
this.formChangeItems[id] = { active: false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasFormChangeItem(id: FormChangeItem): boolean {
|
||||||
|
return id in this.formChangeItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasActiveFormChangeItem(id: FormChangeItem): boolean {
|
||||||
|
const item = this.formChangeItems[id];
|
||||||
|
if (item) {
|
||||||
|
return item.active;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormChangeItems(): FormChangeItem[] {
|
||||||
|
return Object.keys(this.formChangeItems).map(k => Number(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
getActiveFormChangeItems(): FormChangeItem[] {
|
||||||
|
return this.getFormChangeItems().filter(m => this.formChangeItems[m]?.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleActive(id: FormChangeItem) {
|
||||||
|
const item = this.formChangeItems[id];
|
||||||
|
if (item) {
|
||||||
|
item.active = !item.active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearItems() {
|
||||||
|
this.heldItems = {};
|
||||||
|
this.formChangeItems = {};
|
||||||
|
}
|
||||||
|
}
|
@ -56,21 +56,9 @@ import {
|
|||||||
EnemyDamageReducerModifier,
|
EnemyDamageReducerModifier,
|
||||||
EnemyFusionChanceModifier,
|
EnemyFusionChanceModifier,
|
||||||
HiddenAbilityRateBoosterModifier,
|
HiddenAbilityRateBoosterModifier,
|
||||||
BaseStatModifier,
|
|
||||||
PokemonFriendshipBoosterModifier,
|
|
||||||
PokemonHeldItemModifier,
|
|
||||||
PokemonNatureWeightModifier,
|
|
||||||
ShinyRateBoosterModifier,
|
ShinyRateBoosterModifier,
|
||||||
SurviveDamageModifier,
|
|
||||||
TempStatStageBoosterModifier,
|
TempStatStageBoosterModifier,
|
||||||
TempCritBoosterModifier,
|
TempCritBoosterModifier,
|
||||||
StatBoosterModifier,
|
|
||||||
CritBoosterModifier,
|
|
||||||
PokemonBaseStatFlatModifier,
|
|
||||||
PokemonBaseStatTotalModifier,
|
|
||||||
PokemonIncrementingStatModifier,
|
|
||||||
EvoTrackerModifier,
|
|
||||||
PokemonMultiHitModifier,
|
|
||||||
} from "#app/modifier/modifier";
|
} from "#app/modifier/modifier";
|
||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import { Gender } from "#app/data/gender";
|
import { Gender } from "#app/data/gender";
|
||||||
@ -151,7 +139,7 @@ import type { TrainerSlot } from "#enums/trainer-slot";
|
|||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { speciesEggMoves } from "#app/data/balance/egg-moves";
|
import { speciesEggMoves } from "#app/data/balance/egg-moves";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { applyChallenges } from "#app/data/challenge";
|
import { applyChallenges } from "#app/data/challenge";
|
||||||
import { ChallengeType } from "#enums/challenge-type";
|
import { ChallengeType } from "#enums/challenge-type";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
@ -182,6 +170,10 @@ import { doShinySparkleAnim } from "#app/field/anims";
|
|||||||
import { MoveFlags } from "#enums/MoveFlags";
|
import { MoveFlags } from "#enums/MoveFlags";
|
||||||
import { timedEventManager } from "#app/global-event-manager";
|
import { timedEventManager } from "#app/global-event-manager";
|
||||||
import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader";
|
import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader";
|
||||||
|
import { PokemonItemManager } from "./pokemon-held-item-manager";
|
||||||
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
import { isVirtual, isIgnorePP, MoveUseMode } from "#enums/move-use-mode";
|
import { isVirtual, isIgnorePP, MoveUseMode } from "#enums/move-use-mode";
|
||||||
import { FieldPosition } from "#enums/field-position";
|
import { FieldPosition } from "#enums/field-position";
|
||||||
import { LearnMoveSituation } from "#enums/learn-move-situation";
|
import { LearnMoveSituation } from "#enums/learn-move-situation";
|
||||||
@ -303,6 +295,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
private shinySparkle: Phaser.GameObjects.Sprite;
|
private shinySparkle: Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
|
public heldItemManager: PokemonItemManager;
|
||||||
|
|
||||||
// TODO: Rework this eventually
|
// TODO: Rework this eventually
|
||||||
constructor(
|
constructor(
|
||||||
x: number,
|
x: number,
|
||||||
@ -345,6 +339,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.exp = dataSource?.exp || getLevelTotalExp(this.level, species.growthRate);
|
this.exp = dataSource?.exp || getLevelTotalExp(this.level, species.growthRate);
|
||||||
this.levelExp = dataSource?.levelExp || 0;
|
this.levelExp = dataSource?.levelExp || 0;
|
||||||
|
|
||||||
|
this.heldItemManager = new PokemonItemManager();
|
||||||
|
|
||||||
if (dataSource) {
|
if (dataSource) {
|
||||||
this.id = dataSource.id;
|
this.id = dataSource.id;
|
||||||
this.hp = dataSource.hp;
|
this.hp = dataSource.hp;
|
||||||
@ -1125,14 +1121,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.setScale(this.getSpriteScale());
|
this.setScale(this.getSpriteScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeldItems(): PokemonHeldItemModifier[] {
|
getHeldItems(): HeldItemId[] {
|
||||||
if (!globalScene) {
|
return this.heldItemManager.getHeldItems();
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return globalScene.findModifiers(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === this.id,
|
|
||||||
this.isPlayer(),
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScale(): void {
|
updateScale(): void {
|
||||||
@ -1362,7 +1352,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);
|
||||||
@ -1417,7 +1407,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
|
||||||
@ -1519,7 +1509,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const statHolder = new NumberHolder(Math.floor((2 * baseStats[s] + this.ivs[s]) * this.level * 0.01));
|
const statHolder = new NumberHolder(Math.floor((2 * baseStats[s] + this.ivs[s]) * this.level * 0.01));
|
||||||
if (s === Stat.HP) {
|
if (s === Stat.HP) {
|
||||||
statHolder.value = statHolder.value + this.level + 10;
|
statHolder.value = statHolder.value + this.level + 10;
|
||||||
globalScene.applyModifier(PokemonIncrementingStatModifier, this.isPlayer(), this, s, statHolder);
|
applyHeldItems(ITEM_EFFECT.INCREMENTING_STAT, { pokemon: this, stat: s, statHolder: statHolder });
|
||||||
if (this.hasAbility(AbilityId.WONDER_GUARD, false, true)) {
|
if (this.hasAbility(AbilityId.WONDER_GUARD, false, true)) {
|
||||||
statHolder.value = 1;
|
statHolder.value = 1;
|
||||||
}
|
}
|
||||||
@ -1534,14 +1524,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
} else {
|
} else {
|
||||||
statHolder.value += 5;
|
statHolder.value += 5;
|
||||||
const natureStatMultiplier = new NumberHolder(getNatureStatMultiplier(this.getNature(), s));
|
const natureStatMultiplier = new NumberHolder(getNatureStatMultiplier(this.getNature(), s));
|
||||||
globalScene.applyModifier(PokemonNatureWeightModifier, this.isPlayer(), this, natureStatMultiplier);
|
applyHeldItems(ITEM_EFFECT.NATURE_WEIGHT_BOOSTER, { pokemon: this, multiplier: natureStatMultiplier });
|
||||||
if (natureStatMultiplier.value !== 1) {
|
if (natureStatMultiplier.value !== 1) {
|
||||||
statHolder.value = Math.max(
|
statHolder.value = Math.max(
|
||||||
Math[natureStatMultiplier.value > 1 ? "ceil" : "floor"](statHolder.value * natureStatMultiplier.value),
|
Math[natureStatMultiplier.value > 1 ? "ceil" : "floor"](statHolder.value * natureStatMultiplier.value),
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
globalScene.applyModifier(PokemonIncrementingStatModifier, this.isPlayer(), this, s, statHolder);
|
applyHeldItems(ITEM_EFFECT.INCREMENTING_STAT, { pokemon: this, stat: s, statHolder: statHolder });
|
||||||
}
|
}
|
||||||
|
|
||||||
statHolder.value = Phaser.Math.Clamp(statHolder.value, 1, Number.MAX_SAFE_INTEGER);
|
statHolder.value = Phaser.Math.Clamp(statHolder.value, 1, Number.MAX_SAFE_INTEGER);
|
||||||
@ -1554,9 +1544,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const baseStats = this.getSpeciesForm(true).baseStats.slice(0);
|
const baseStats = this.getSpeciesForm(true).baseStats.slice(0);
|
||||||
applyChallenges(ChallengeType.FLIP_STAT, this, baseStats);
|
applyChallenges(ChallengeType.FLIP_STAT, this, baseStats);
|
||||||
// Shuckle Juice
|
// Shuckle Juice
|
||||||
globalScene.applyModifiers(PokemonBaseStatTotalModifier, this.isPlayer(), this, baseStats);
|
applyHeldItems(ITEM_EFFECT.BASE_STAT_TOTAL, { pokemon: this, baseStats: baseStats });
|
||||||
// Old Gateau
|
// Old Gateau
|
||||||
globalScene.applyModifiers(PokemonBaseStatFlatModifier, this.isPlayer(), this, baseStats);
|
applyHeldItems(ITEM_EFFECT.BASE_STAT_FLAT, { pokemon: this, baseStats: baseStats });
|
||||||
if (this.isFusion()) {
|
if (this.isFusion()) {
|
||||||
const fusionBaseStats = this.getFusionSpeciesForm(true).baseStats;
|
const fusionBaseStats = this.getFusionSpeciesForm(true).baseStats;
|
||||||
applyChallenges(ChallengeType.FLIP_STAT, this, fusionBaseStats);
|
applyChallenges(ChallengeType.FLIP_STAT, this, fusionBaseStats);
|
||||||
@ -1570,7 +1560,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Vitamins
|
// Vitamins
|
||||||
globalScene.applyModifiers(BaseStatModifier, this.isPlayer(), this, baseStats);
|
applyHeldItems(ITEM_EFFECT.BASE_STAT_BOOSTER, { pokemon: this, baseStats: baseStats });
|
||||||
|
|
||||||
return baseStats;
|
return baseStats;
|
||||||
}
|
}
|
||||||
@ -2987,11 +2977,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compatible && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) {
|
if (compatible && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) {
|
||||||
if (tmPoolTiers[moveId] === ModifierTier.COMMON && this.level >= 15) {
|
if (tmPoolTiers[moveId] === RewardTier.COMMON && this.level >= 15) {
|
||||||
movePool.push([moveId, 4]);
|
movePool.push([moveId, 4]);
|
||||||
} else if (tmPoolTiers[moveId] === ModifierTier.GREAT && this.level >= 30) {
|
} else if (tmPoolTiers[moveId] === RewardTier.GREAT && this.level >= 30) {
|
||||||
movePool.push([moveId, 8]);
|
movePool.push([moveId, 8]);
|
||||||
} else if (tmPoolTiers[moveId] === ModifierTier.ULTRA && this.level >= 50) {
|
} else if (tmPoolTiers[moveId] === RewardTier.ULTRA && this.level >= 50) {
|
||||||
movePool.push([moveId, 14]);
|
movePool.push([moveId, 14]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3647,14 +3637,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs("FixedDamageAttr", source, this, move, fixedDamage);
|
applyMoveAttrs("FixedDamageAttr", source, this, move, fixedDamage);
|
||||||
if (fixedDamage.value) {
|
if (fixedDamage.value) {
|
||||||
const multiLensMultiplier = new NumberHolder(1);
|
const multiLensMultiplier = new NumberHolder(1);
|
||||||
globalScene.applyModifiers(
|
applyHeldItems(ITEM_EFFECT.MULTI_HIT, {
|
||||||
PokemonMultiHitModifier,
|
pokemon: source,
|
||||||
source.isPlayer(),
|
moveId: move.id,
|
||||||
source,
|
damageMultiplier: multiLensMultiplier,
|
||||||
move.id,
|
});
|
||||||
null,
|
|
||||||
multiLensMultiplier,
|
|
||||||
);
|
|
||||||
fixedDamage.value = toDmgValue(fixedDamage.value * multiLensMultiplier.value);
|
fixedDamage.value = toDmgValue(fixedDamage.value * multiLensMultiplier.value);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -3698,14 +3685,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
/** Multiplier for moves enhanced by Multi-Lens and/or Parental Bond */
|
/** Multiplier for moves enhanced by Multi-Lens and/or Parental Bond */
|
||||||
const multiStrikeEnhancementMultiplier = new NumberHolder(1);
|
const multiStrikeEnhancementMultiplier = new NumberHolder(1);
|
||||||
globalScene.applyModifiers(
|
applyHeldItems(ITEM_EFFECT.MULTI_HIT, {
|
||||||
PokemonMultiHitModifier,
|
pokemon: source,
|
||||||
source.isPlayer(),
|
moveId: move.id,
|
||||||
source,
|
damageMultiplier: multiStrikeEnhancementMultiplier,
|
||||||
move.id,
|
});
|
||||||
null,
|
|
||||||
multiStrikeEnhancementMultiplier,
|
|
||||||
);
|
|
||||||
if (!ignoreSourceAbility) {
|
if (!ignoreSourceAbility) {
|
||||||
applyPreAttackAbAttrs(
|
applyPreAttackAbAttrs(
|
||||||
"AddSecondStrikeAbAttr",
|
"AddSecondStrikeAbAttr",
|
||||||
@ -3920,7 +3904,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;
|
||||||
@ -4356,7 +4340,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.setScale(this.getSpriteScale());
|
this.setScale(this.getSpriteScale());
|
||||||
this.loadAssets().then(() => {
|
this.loadAssets().then(() => {
|
||||||
this.calculateStats();
|
this.calculateStats();
|
||||||
globalScene.updateModifiers(this.isPlayer(), true);
|
globalScene.updateModifiers(this.isPlayer());
|
||||||
Promise.all([this.updateInfo(), globalScene.updateFieldScale()]).then(() => resolve());
|
Promise.all([this.updateInfo(), globalScene.updateFieldScale()]).then(() => resolve());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -5441,15 +5425,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* @param forBattle If `false`, do not trigger in-battle effects (such as Unburden) from losing the item. For example, set this to `false` if the Pokemon is giving away the held item for a Mystery Encounter. Default is `true`.
|
* @param forBattle If `false`, do not trigger in-battle effects (such as Unburden) from losing the item. For example, set this to `false` if the Pokemon is giving away the held item for a Mystery Encounter. Default is `true`.
|
||||||
* @returns `true` if the item was removed successfully, `false` otherwise.
|
* @returns `true` if the item was removed successfully, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
public loseHeldItem(heldItem: PokemonHeldItemModifier, forBattle = true): boolean {
|
public loseHeldItem(heldItemId: HeldItemId, forBattle = true): boolean {
|
||||||
if (heldItem.pokemonId !== -1 && heldItem.pokemonId !== this.id) {
|
if (!this.heldItemManager.hasItem(heldItemId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
heldItem.stackCount--;
|
this.heldItemManager.remove(heldItemId);
|
||||||
if (heldItem.stackCount <= 0) {
|
|
||||||
globalScene.removeModifier(heldItem, this.isEnemy());
|
|
||||||
}
|
|
||||||
if (forBattle) {
|
if (forBattle) {
|
||||||
applyPostItemLostAbAttrs("PostItemLostAbAttr", this, false);
|
applyPostItemLostAbAttrs("PostItemLostAbAttr", this, false);
|
||||||
}
|
}
|
||||||
@ -5640,7 +5622,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
fusionStarterSpeciesId ? globalScene.gameData.starterData[fusionStarterSpeciesId] : null,
|
fusionStarterSpeciesId ? globalScene.gameData.starterData[fusionStarterSpeciesId] : null,
|
||||||
].filter(d => !!d);
|
].filter(d => !!d);
|
||||||
const amount = new NumberHolder(friendship);
|
const amount = new NumberHolder(friendship);
|
||||||
globalScene.applyModifier(PokemonFriendshipBoosterModifier, true, this, amount);
|
applyHeldItems(ITEM_EFFECT.FRIENDSHIP_BOOSTER, { pokemon: this, friendship: amount });
|
||||||
const candyFriendshipMultiplier = globalScene.gameMode.isClassic
|
const candyFriendshipMultiplier = globalScene.gameMode.isClassic
|
||||||
? timedEventManager.getClassicFriendshipMultiplier()
|
? timedEventManager.getClassicFriendshipMultiplier()
|
||||||
: 1;
|
: 1;
|
||||||
@ -5794,9 +5776,9 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (preEvolution.speciesId === SpeciesId.GIMMIGHOUL) {
|
if (preEvolution.speciesId === SpeciesId.GIMMIGHOUL) {
|
||||||
const evotracker = this.getHeldItems().filter(m => m instanceof EvoTrackerModifier)[0] ?? null;
|
const evotracker = this.heldItemManager.hasItem(HeldItemId.GIMMIGHOUL_EVO_TRACKER);
|
||||||
if (evotracker) {
|
if (evotracker) {
|
||||||
globalScene.removeModifier(evotracker);
|
this.heldItemManager.remove(HeldItemId.GIMMIGHOUL_EVO_TRACKER, 0, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!globalScene.gameMode.isDaily || this.metBiome > -1) {
|
if (!globalScene.gameMode.isDaily || this.metBiome > -1) {
|
||||||
@ -5849,14 +5831,10 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
|
|
||||||
globalScene.getPlayerParty().push(newPokemon);
|
globalScene.getPlayerParty().push(newPokemon);
|
||||||
newPokemon.evolve(!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution), evoSpecies);
|
newPokemon.evolve(!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution), evoSpecies);
|
||||||
const modifiers = globalScene.findModifiers(
|
//TODO: This currently does not consider any values associated with the items e.g. disabled
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === this.id,
|
const heldItems = this.getHeldItems();
|
||||||
true,
|
heldItems.forEach(item => {
|
||||||
) as PokemonHeldItemModifier[];
|
newPokemon.heldItemManager.add(item, this.heldItemManager.getStack(item));
|
||||||
modifiers.forEach(m => {
|
|
||||||
const clonedModifier = m.clone() as PokemonHeldItemModifier;
|
|
||||||
clonedModifier.pokemonId = newPokemon.id;
|
|
||||||
globalScene.addModifier(clonedModifier, true);
|
|
||||||
});
|
});
|
||||||
globalScene.updateModifiers(true);
|
globalScene.updateModifiers(true);
|
||||||
}
|
}
|
||||||
@ -5903,7 +5881,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
const updateAndResolve = () => {
|
const updateAndResolve = () => {
|
||||||
this.loadAssets().then(() => {
|
this.loadAssets().then(() => {
|
||||||
this.calculateStats();
|
this.calculateStats();
|
||||||
globalScene.updateModifiers(true, true);
|
globalScene.updateModifiers(true);
|
||||||
this.updateInfo(true).then(() => resolve());
|
this.updateInfo(true).then(() => resolve());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -5969,15 +5947,11 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// combine the two mons' held items
|
// combine the two mons' held items
|
||||||
const fusedPartyMemberHeldModifiers = globalScene.findModifiers(
|
const fusedPartyMemberHeldItems = pokemon.getHeldItems();
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
|
for (const item of fusedPartyMemberHeldItems) {
|
||||||
true,
|
globalScene.tryTransferHeldItem(item, pokemon, this, false, pokemon.heldItemManager.getStack(item), true, false);
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
for (const modifier of fusedPartyMemberHeldModifiers) {
|
|
||||||
globalScene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), true, true, false);
|
|
||||||
}
|
}
|
||||||
globalScene.updateModifiers(true, true);
|
globalScene.updateModifiers(true);
|
||||||
globalScene.removePartyMemberModifiers(fusedPartyMemberIndex);
|
|
||||||
globalScene.getPlayerParty().splice(fusedPartyMemberIndex, 1)[0];
|
globalScene.getPlayerParty().splice(fusedPartyMemberIndex, 1)[0];
|
||||||
const newPartyMemberIndex = globalScene.getPlayerParty().indexOf(this);
|
const newPartyMemberIndex = globalScene.getPlayerParty().indexOf(this);
|
||||||
pokemon
|
pokemon
|
||||||
|
212
src/items/all-held-items.ts
Normal file
212
src/items/all-held-items.ts
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
import { getEnumValues } from "#app/utils/common";
|
||||||
|
import { BerryType } from "#enums/berry-type";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
|
import { SpeciesId } from "#enums/species-id";
|
||||||
|
import { Stat, type PermanentStat } from "#enums/stat";
|
||||||
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
|
import { ITEM_EFFECT } from "./held-item";
|
||||||
|
import { type ACCURACY_BOOST_PARAMS, AccuracyBoosterHeldItem } from "./held-items/accuracy-booster";
|
||||||
|
import {
|
||||||
|
type ATTACK_TYPE_BOOST_PARAMS,
|
||||||
|
AttackTypeBoosterHeldItem,
|
||||||
|
attackTypeToHeldItem,
|
||||||
|
} from "./held-items/attack-type-booster";
|
||||||
|
import {
|
||||||
|
type BASE_STAT_BOOSTER_PARAMS,
|
||||||
|
BaseStatBoosterHeldItem,
|
||||||
|
permanentStatToHeldItem,
|
||||||
|
} from "./held-items/base-stat-booster";
|
||||||
|
import { type BASE_STAT_FLAT_PARAMS, BaseStatFlatHeldItem } from "./held-items/base-stat-flat";
|
||||||
|
import { type BASE_STAT_TOTAL_PARAMS, BaseStatTotalHeldItem } from "./held-items/base-stat-total";
|
||||||
|
import { type BATON_PARAMS, BatonHeldItem } from "./held-items/baton";
|
||||||
|
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 DAMAGE_MONEY_REWARD_PARAMS, DamageMoneyRewardHeldItem } from "./held-items/damage-money-reward";
|
||||||
|
import { type EVO_TRACKER_PARAMS, GimmighoulEvoTrackerHeldItem } from "./held-items/evo-tracker";
|
||||||
|
import { type EXP_BOOST_PARAMS, ExpBoosterHeldItem } from "./held-items/exp-booster";
|
||||||
|
import { type FIELD_EFFECT_PARAMS, FieldEffectHeldItem } from "./held-items/field-effect";
|
||||||
|
import { type FLINCH_CHANCE_PARAMS, FlinchChanceHeldItem } from "./held-items/flinch-chance";
|
||||||
|
import { type FRIENDSHIP_BOOST_PARAMS, FriendshipBoosterHeldItem } from "./held-items/friendship-booster";
|
||||||
|
import { type HIT_HEAL_PARAMS, HitHealHeldItem } from "./held-items/hit-heal";
|
||||||
|
import { type INCREMENTING_STAT_PARAMS, IncrementingStatHeldItem } from "./held-items/incrementing-stat";
|
||||||
|
import { InstantReviveHeldItem, type INSTANT_REVIVE_PARAMS } from "./held-items/instant-revive";
|
||||||
|
import {
|
||||||
|
ContactItemStealChanceHeldItem,
|
||||||
|
type ITEM_STEAL_PARAMS,
|
||||||
|
TurnEndItemStealHeldItem,
|
||||||
|
} from "./held-items/item-steal";
|
||||||
|
import { type MULTI_HIT_PARAMS, MultiHitHeldItem } from "./held-items/multi-hit";
|
||||||
|
import { type NATURE_WEIGHT_BOOST_PARAMS, NatureWeightBoosterHeldItem } from "./held-items/nature-weight-booster";
|
||||||
|
import {
|
||||||
|
ResetNegativeStatStageHeldItem,
|
||||||
|
type RESET_NEGATIVE_STAT_STAGE_PARAMS,
|
||||||
|
} from "./held-items/reset-negative-stat-stage";
|
||||||
|
import {
|
||||||
|
EvolutionStatBoostHeldItem,
|
||||||
|
SpeciesStatBoostHeldItem,
|
||||||
|
type STAT_BOOST_PARAMS,
|
||||||
|
} from "./held-items/stat-booster";
|
||||||
|
import { type SURVIVE_CHANCE_PARAMS, SurviveChanceHeldItem } from "./held-items/survive-chance";
|
||||||
|
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 function initHeldItems() {
|
||||||
|
for (const berry of getEnumValues(BerryType)) {
|
||||||
|
let maxStackCount: number;
|
||||||
|
if ([BerryType.LUM, BerryType.LEPPA, BerryType.SITRUS, BerryType.ENIGMA].includes(berry)) {
|
||||||
|
maxStackCount = 2;
|
||||||
|
} else {
|
||||||
|
maxStackCount = 3;
|
||||||
|
}
|
||||||
|
const berryId = berryTypeToHeldItem[berry];
|
||||||
|
allHeldItems[berryId] = new BerryHeldItem(berry, maxStackCount);
|
||||||
|
}
|
||||||
|
console.log(allHeldItems);
|
||||||
|
|
||||||
|
allHeldItems[HeldItemId.REVIVER_SEED] = new InstantReviveHeldItem(HeldItemId.REVIVER_SEED, 1);
|
||||||
|
allHeldItems[HeldItemId.WHITE_HERB] = new ResetNegativeStatStageHeldItem(HeldItemId.WHITE_HERB, 2);
|
||||||
|
|
||||||
|
// SILK_SCARF, BLACK_BELT, etc...
|
||||||
|
for (const [typeKey, heldItemType] of Object.entries(attackTypeToHeldItem)) {
|
||||||
|
const pokemonType = Number(typeKey) as PokemonType;
|
||||||
|
allHeldItems[heldItemType] = new AttackTypeBoosterHeldItem(heldItemType, 99, pokemonType, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items that boost specific stats
|
||||||
|
allHeldItems[HeldItemId.EVIOLITE] = new EvolutionStatBoostHeldItem(
|
||||||
|
HeldItemId.EVIOLITE,
|
||||||
|
1,
|
||||||
|
[Stat.DEF, Stat.SPDEF],
|
||||||
|
1.5,
|
||||||
|
);
|
||||||
|
allHeldItems[HeldItemId.LIGHT_BALL] = new SpeciesStatBoostHeldItem(
|
||||||
|
HeldItemId.LIGHT_BALL,
|
||||||
|
1,
|
||||||
|
[Stat.ATK, Stat.SPATK],
|
||||||
|
2,
|
||||||
|
[SpeciesId.PIKACHU],
|
||||||
|
);
|
||||||
|
allHeldItems[HeldItemId.THICK_CLUB] = new SpeciesStatBoostHeldItem(HeldItemId.LIGHT_BALL, 1, [Stat.ATK], 2, [
|
||||||
|
SpeciesId.CUBONE,
|
||||||
|
SpeciesId.MAROWAK,
|
||||||
|
SpeciesId.ALOLA_MAROWAK,
|
||||||
|
]);
|
||||||
|
allHeldItems[HeldItemId.METAL_POWDER] = new SpeciesStatBoostHeldItem(HeldItemId.LIGHT_BALL, 1, [Stat.DEF], 2, [
|
||||||
|
SpeciesId.DITTO,
|
||||||
|
]);
|
||||||
|
allHeldItems[HeldItemId.QUICK_POWDER] = new SpeciesStatBoostHeldItem(HeldItemId.LIGHT_BALL, 1, [Stat.SPD], 2, [
|
||||||
|
SpeciesId.DITTO,
|
||||||
|
]);
|
||||||
|
allHeldItems[HeldItemId.DEEP_SEA_SCALE] = new SpeciesStatBoostHeldItem(HeldItemId.LIGHT_BALL, 1, [Stat.SPDEF], 2, [
|
||||||
|
SpeciesId.CLAMPERL,
|
||||||
|
]);
|
||||||
|
allHeldItems[HeldItemId.DEEP_SEA_TOOTH] = new SpeciesStatBoostHeldItem(HeldItemId.LIGHT_BALL, 1, [Stat.SPATK], 2, [
|
||||||
|
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.GOLDEN_EGG] = new ExpBoosterHeldItem(HeldItemId.GOLDEN_EGG, 99, 100);
|
||||||
|
allHeldItems[HeldItemId.SOOTHE_BELL] = new FriendshipBoosterHeldItem(HeldItemId.SOOTHE_BELL, 3);
|
||||||
|
|
||||||
|
allHeldItems[HeldItemId.LEFTOVERS] = new TurnEndHealHeldItem(HeldItemId.LEFTOVERS, 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.MYSTICAL_ROCK] = new FieldEffectHeldItem(HeldItemId.MYSTICAL_ROCK, 2);
|
||||||
|
allHeldItems[HeldItemId.SOUL_DEW] = new NatureWeightBoosterHeldItem(HeldItemId.SOUL_DEW, 10);
|
||||||
|
allHeldItems[HeldItemId.WIDE_LENS] = new AccuracyBoosterHeldItem(HeldItemId.WIDE_LENS, 3, 5);
|
||||||
|
allHeldItems[HeldItemId.MULTI_LENS] = new MultiHitHeldItem(HeldItemId.MULTI_LENS, 2);
|
||||||
|
allHeldItems[HeldItemId.GOLDEN_PUNCH] = new DamageMoneyRewardHeldItem(HeldItemId.GOLDEN_PUNCH, 5);
|
||||||
|
allHeldItems[HeldItemId.BATON] = new BatonHeldItem(HeldItemId.BATON, 1);
|
||||||
|
allHeldItems[HeldItemId.GRIP_CLAW] = new ContactItemStealChanceHeldItem(HeldItemId.GRIP_CLAW, 5, 10);
|
||||||
|
allHeldItems[HeldItemId.MINI_BLACK_HOLE] = new TurnEndItemStealHeldItem(HeldItemId.MINI_BLACK_HOLE, 1)
|
||||||
|
.unstealable()
|
||||||
|
.untransferable();
|
||||||
|
|
||||||
|
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
|
||||||
|
for (const [statKey, heldItemType] of Object.entries(permanentStatToHeldItem)) {
|
||||||
|
const stat = Number(statKey) as PermanentStat;
|
||||||
|
allHeldItems[heldItemType] = new BaseStatBoosterHeldItem(heldItemType, 30, stat)
|
||||||
|
.unstealable()
|
||||||
|
.untransferable()
|
||||||
|
.unsuppressable();
|
||||||
|
}
|
||||||
|
|
||||||
|
allHeldItems[HeldItemId.SHUCKLE_JUICE] = new BaseStatTotalHeldItem(HeldItemId.SHUCKLE_JUICE, 1)
|
||||||
|
.unstealable()
|
||||||
|
.untransferable()
|
||||||
|
.unsuppressable();
|
||||||
|
allHeldItems[HeldItemId.OLD_GATEAU] = new BaseStatFlatHeldItem(HeldItemId.OLD_GATEAU, 1)
|
||||||
|
.unstealable()
|
||||||
|
.untransferable()
|
||||||
|
.unsuppressable();
|
||||||
|
allHeldItems[HeldItemId.MACHO_BRACE] = new IncrementingStatHeldItem(HeldItemId.MACHO_BRACE, 50)
|
||||||
|
.unstealable()
|
||||||
|
.untransferable()
|
||||||
|
.unsuppressable();
|
||||||
|
|
||||||
|
allHeldItems[HeldItemId.GIMMIGHOUL_EVO_TRACKER] = new GimmighoulEvoTrackerHeldItem(
|
||||||
|
HeldItemId.GIMMIGHOUL_EVO_TRACKER,
|
||||||
|
999,
|
||||||
|
SpeciesId.GIMMIGHOUL,
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
type APPLY_HELD_ITEMS_PARAMS = {
|
||||||
|
[ITEM_EFFECT.ATTACK_TYPE_BOOST]: ATTACK_TYPE_BOOST_PARAMS;
|
||||||
|
[ITEM_EFFECT.TURN_END_HEAL]: TURN_END_HEAL_PARAMS;
|
||||||
|
[ITEM_EFFECT.HIT_HEAL]: HIT_HEAL_PARAMS;
|
||||||
|
[ITEM_EFFECT.RESET_NEGATIVE_STAT_STAGE]: RESET_NEGATIVE_STAT_STAGE_PARAMS;
|
||||||
|
[ITEM_EFFECT.EXP_BOOSTER]: EXP_BOOST_PARAMS;
|
||||||
|
[ITEM_EFFECT.BERRY]: BERRY_PARAMS;
|
||||||
|
[ITEM_EFFECT.BASE_STAT_BOOSTER]: BASE_STAT_BOOSTER_PARAMS;
|
||||||
|
[ITEM_EFFECT.INSTANT_REVIVE]: INSTANT_REVIVE_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;
|
||||||
|
[ITEM_EFFECT.FIELD_EFFECT]: FIELD_EFFECT_PARAMS;
|
||||||
|
[ITEM_EFFECT.FRIENDSHIP_BOOSTER]: FRIENDSHIP_BOOST_PARAMS;
|
||||||
|
[ITEM_EFFECT.NATURE_WEIGHT_BOOSTER]: NATURE_WEIGHT_BOOST_PARAMS;
|
||||||
|
[ITEM_EFFECT.ACCURACY_BOOSTER]: ACCURACY_BOOST_PARAMS;
|
||||||
|
[ITEM_EFFECT.MULTI_HIT]: MULTI_HIT_PARAMS;
|
||||||
|
[ITEM_EFFECT.DAMAGE_MONEY_REWARD]: DAMAGE_MONEY_REWARD_PARAMS;
|
||||||
|
[ITEM_EFFECT.BATON]: BATON_PARAMS;
|
||||||
|
[ITEM_EFFECT.CONTACT_ITEM_STEAL_CHANCE]: ITEM_STEAL_PARAMS;
|
||||||
|
[ITEM_EFFECT.TURN_END_ITEM_STEAL]: ITEM_STEAL_PARAMS;
|
||||||
|
[ITEM_EFFECT.BASE_STAT_TOTAL]: BASE_STAT_TOTAL_PARAMS;
|
||||||
|
[ITEM_EFFECT.BASE_STAT_FLAT]: BASE_STAT_FLAT_PARAMS;
|
||||||
|
[ITEM_EFFECT.INCREMENTING_STAT]: INCREMENTING_STAT_PARAMS;
|
||||||
|
[ITEM_EFFECT.EVO_TRACKER]: EVO_TRACKER_PARAMS;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function applyHeldItems<T extends ITEM_EFFECT>(effect: T, params: APPLY_HELD_ITEMS_PARAMS[T]) {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
if (pokemon) {
|
||||||
|
for (const item of Object.keys(pokemon.heldItemManager.heldItems)) {
|
||||||
|
if (allHeldItems[item].effects.includes(effect)) {
|
||||||
|
allHeldItems[item].apply(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
src/items/held-item-data-types.ts
Normal file
77
src/items/held-item-data-types.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import type { RewardTier } from "#enums/reward-tier";
|
||||||
|
import type { Stat } from "#enums/stat";
|
||||||
|
|
||||||
|
export interface BASE_STAT_TOTAL_DATA {
|
||||||
|
statModifier: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BASE_STAT_FLAT_DATA {
|
||||||
|
statModifier: number;
|
||||||
|
stats: Stat[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HeldItemExtraData = BASE_STAT_TOTAL_DATA | BASE_STAT_FLAT_DATA;
|
||||||
|
|
||||||
|
export type HeldItemData = {
|
||||||
|
stack: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
unstealable?: boolean;
|
||||||
|
cooldown?: number;
|
||||||
|
data?: HeldItemExtraData;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeldItemDataMap = {
|
||||||
|
[key in HeldItemId]?: HeldItemData;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeldItemSpecs = HeldItemData & {
|
||||||
|
id: HeldItemId;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHeldItemSpecs(entry: any): entry is HeldItemSpecs {
|
||||||
|
return typeof entry.id === "number" && "stack" in entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HeldItemWeights = {
|
||||||
|
[key in HeldItemId]?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeldItemWeightFunc = (party: Pokemon[]) => number;
|
||||||
|
|
||||||
|
export type HeldItemCategoryEntry = HeldItemData & {
|
||||||
|
id: HeldItemCategoryId;
|
||||||
|
customWeights?: HeldItemWeights;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHeldItemCategoryEntry(entry: any): entry is HeldItemCategoryEntry {
|
||||||
|
return isHeldItemCategoryEntry(entry.id) && "customWeights" in entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
type HeldItemPoolEntry = {
|
||||||
|
entry: HeldItemId | HeldItemCategoryId | HeldItemCategoryEntry | HeldItemSpecs;
|
||||||
|
weight: number | HeldItemWeightFunc;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeldItemPool = HeldItemPoolEntry[];
|
||||||
|
|
||||||
|
export function isHeldItemPool(value: any): value is HeldItemPool {
|
||||||
|
return Array.isArray(value) && value.every(entry => "entry" in entry && "weight" in entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HeldItemTieredPool = {
|
||||||
|
[key in RewardTier]?: HeldItemPool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type HeldItemConfigurationEntry = {
|
||||||
|
entry: HeldItemId | HeldItemCategoryId | HeldItemCategoryEntry | HeldItemSpecs | HeldItemPool;
|
||||||
|
count?: number | (() => number);
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeldItemConfiguration = HeldItemConfigurationEntry[];
|
||||||
|
|
||||||
|
export type PokemonItemMap = {
|
||||||
|
item: HeldItemId;
|
||||||
|
pokemon: Pokemon;
|
||||||
|
};
|
320
src/items/held-item-pool.ts
Normal file
320
src/items/held-item-pool.ts
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { coerceArray, getEnumValues, randSeedFloat, randSeedInt } from "#app/utils/common";
|
||||||
|
import { BerryType } from "#enums/berry-type";
|
||||||
|
import { HeldItemCategoryId, HeldItemId, HeldItemNames, isCategoryId } from "#enums/held-item-id";
|
||||||
|
import { HeldItemPoolType } from "#enums/modifier-pool-type";
|
||||||
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
|
import { PERMANENT_STATS } from "#enums/stat";
|
||||||
|
import { allHeldItems } from "./all-held-items";
|
||||||
|
import {
|
||||||
|
type HeldItemConfiguration,
|
||||||
|
type HeldItemPool,
|
||||||
|
type HeldItemSpecs,
|
||||||
|
type HeldItemTieredPool,
|
||||||
|
type HeldItemWeights,
|
||||||
|
isHeldItemCategoryEntry,
|
||||||
|
isHeldItemPool,
|
||||||
|
isHeldItemSpecs,
|
||||||
|
} from "./held-item-data-types";
|
||||||
|
import { attackTypeToHeldItem } from "./held-items/attack-type-booster";
|
||||||
|
import { permanentStatToHeldItem } from "./held-items/base-stat-booster";
|
||||||
|
import { berryTypeToHeldItem } from "./held-items/berry";
|
||||||
|
|
||||||
|
export const wildHeldItemPool: HeldItemTieredPool = {};
|
||||||
|
|
||||||
|
export const trainerHeldItemPool: HeldItemTieredPool = {};
|
||||||
|
|
||||||
|
export const dailyStarterHeldItemPool: HeldItemTieredPool = {};
|
||||||
|
|
||||||
|
export function assignDailyRunStarterHeldItems(party: PlayerPokemon[]) {
|
||||||
|
for (const p of party) {
|
||||||
|
for (let m = 0; m < 3; m++) {
|
||||||
|
const tierValue = randSeedInt(64);
|
||||||
|
|
||||||
|
const tier = getDailyRewardTier(tierValue);
|
||||||
|
|
||||||
|
const item = getNewHeldItemFromPool(
|
||||||
|
getHeldItemPool(HeldItemPoolType.DAILY_STARTER)[tier] as HeldItemPool,
|
||||||
|
p,
|
||||||
|
party,
|
||||||
|
);
|
||||||
|
p.heldItemManager.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDailyRewardTier(tierValue: number): RewardTier {
|
||||||
|
if (tierValue > 25) {
|
||||||
|
return RewardTier.COMMON;
|
||||||
|
}
|
||||||
|
if (tierValue > 12) {
|
||||||
|
return RewardTier.GREAT;
|
||||||
|
}
|
||||||
|
if (tierValue > 4) {
|
||||||
|
return RewardTier.ULTRA;
|
||||||
|
}
|
||||||
|
if (tierValue > 0) {
|
||||||
|
return RewardTier.ROGUE;
|
||||||
|
}
|
||||||
|
return RewardTier.MASTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeldItemPool(poolType: HeldItemPoolType): HeldItemTieredPool {
|
||||||
|
let pool: HeldItemTieredPool;
|
||||||
|
switch (poolType) {
|
||||||
|
case HeldItemPoolType.WILD:
|
||||||
|
pool = wildHeldItemPool;
|
||||||
|
break;
|
||||||
|
case HeldItemPoolType.TRAINER:
|
||||||
|
pool = trainerHeldItemPool;
|
||||||
|
break;
|
||||||
|
case HeldItemPoolType.DAILY_STARTER:
|
||||||
|
pool = dailyStarterHeldItemPool;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add proper documentation to this function (once it fully works...)
|
||||||
|
export function assignEnemyHeldItemsForWave(
|
||||||
|
waveIndex: number,
|
||||||
|
count: number,
|
||||||
|
enemy: EnemyPokemon,
|
||||||
|
poolType: HeldItemPoolType.WILD | HeldItemPoolType.TRAINER,
|
||||||
|
upgradeChance = 0,
|
||||||
|
): void {
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
const item = getNewHeldItemFromTieredPool(
|
||||||
|
getHeldItemPool(poolType),
|
||||||
|
enemy,
|
||||||
|
upgradeChance && !randSeedInt(upgradeChance) ? 1 : 0,
|
||||||
|
);
|
||||||
|
enemy.heldItemManager.add(item);
|
||||||
|
}
|
||||||
|
if (!(waveIndex % 1000)) {
|
||||||
|
enemy.heldItemManager.add(HeldItemId.MINI_BLACK_HOLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomTier(): RewardTier {
|
||||||
|
const tierValue = randSeedInt(1024);
|
||||||
|
|
||||||
|
if (tierValue > 255) {
|
||||||
|
return RewardTier.COMMON;
|
||||||
|
}
|
||||||
|
if (tierValue > 60) {
|
||||||
|
return RewardTier.GREAT;
|
||||||
|
}
|
||||||
|
if (tierValue > 12) {
|
||||||
|
return RewardTier.ULTRA;
|
||||||
|
}
|
||||||
|
if (tierValue) {
|
||||||
|
return RewardTier.ROGUE;
|
||||||
|
}
|
||||||
|
return RewardTier.MASTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
function determineEnemyPoolTier(pool: HeldItemTieredPool, upgradeCount?: number): RewardTier {
|
||||||
|
let tier = getRandomTier();
|
||||||
|
|
||||||
|
if (!upgradeCount) {
|
||||||
|
upgradeCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tier += upgradeCount;
|
||||||
|
while (tier && !pool[tier]?.length) {
|
||||||
|
tier--;
|
||||||
|
if (upgradeCount) {
|
||||||
|
upgradeCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tier;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNewHeldItemFromTieredPool(
|
||||||
|
pool: HeldItemTieredPool,
|
||||||
|
pokemon: Pokemon,
|
||||||
|
upgradeCount: number,
|
||||||
|
): HeldItemId | HeldItemSpecs {
|
||||||
|
const tier = determineEnemyPoolTier(pool, upgradeCount);
|
||||||
|
const tierPool = pool[tier];
|
||||||
|
|
||||||
|
return getNewHeldItemFromPool(tierPool!, pokemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickWeightedIndex(weights: number[]): number {
|
||||||
|
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
|
||||||
|
|
||||||
|
if (totalWeight <= 0) {
|
||||||
|
throw new Error("Total weight must be greater than 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let r = randSeedFloat() * totalWeight;
|
||||||
|
|
||||||
|
for (let i = 0; i < weights.length; i++) {
|
||||||
|
if (r < weights[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
r -= weights[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; // TODO: Change to something more appropriate
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNewVitaminHeldItem(customWeights: HeldItemWeights = {}, target?: Pokemon): HeldItemId {
|
||||||
|
const items = PERMANENT_STATS.map(s => permanentStatToHeldItem[s]);
|
||||||
|
const weights = items.map(t => (target?.heldItemManager.isMaxStack(t) ? 0 : (customWeights[t] ?? 1)));
|
||||||
|
return items[pickWeightedIndex(weights)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNewBerryHeldItem(customWeights: HeldItemWeights = {}, target?: Pokemon): HeldItemId {
|
||||||
|
const berryTypes = getEnumValues(BerryType);
|
||||||
|
const items = berryTypes.map(b => berryTypeToHeldItem[b]);
|
||||||
|
|
||||||
|
const weights = items.map(t =>
|
||||||
|
target?.heldItemManager.isMaxStack(t)
|
||||||
|
? 0
|
||||||
|
: (customWeights[t] ??
|
||||||
|
(t === HeldItemId.SITRUS_BERRY || t === HeldItemId.LUM_BERRY || t === HeldItemId.LEPPA_BERRY))
|
||||||
|
? 2
|
||||||
|
: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
return items[pickWeightedIndex(weights)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNewAttackTypeBoosterHeldItem(
|
||||||
|
pokemon: Pokemon | Pokemon[],
|
||||||
|
customWeights: HeldItemWeights = {},
|
||||||
|
target?: Pokemon,
|
||||||
|
): HeldItemId | null {
|
||||||
|
const party = coerceArray(pokemon);
|
||||||
|
|
||||||
|
// TODO: make this consider moves or abilities that change types
|
||||||
|
const attackMoveTypes = party.flatMap(p =>
|
||||||
|
p
|
||||||
|
.getMoveset()
|
||||||
|
.filter(m => m.getMove().is("AttackMove"))
|
||||||
|
.map(m => m.getMove().type),
|
||||||
|
);
|
||||||
|
if (!attackMoveTypes.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attackMoveTypeWeights = attackMoveTypes.reduce((map, type) => {
|
||||||
|
const current = map.get(type) ?? 0;
|
||||||
|
if (current < 3) {
|
||||||
|
map.set(type, current + 1);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}, new Map<PokemonType, number>());
|
||||||
|
|
||||||
|
const types = Array.from(attackMoveTypeWeights.keys());
|
||||||
|
|
||||||
|
const weights = types.map(type =>
|
||||||
|
target?.heldItemManager.isMaxStack(attackTypeToHeldItem[type])
|
||||||
|
? 0
|
||||||
|
: (customWeights[attackTypeToHeldItem[type]] ?? attackMoveTypeWeights.get(type)!),
|
||||||
|
);
|
||||||
|
|
||||||
|
const type = types[pickWeightedIndex(weights)];
|
||||||
|
return attackTypeToHeldItem[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNewHeldItemFromCategory(
|
||||||
|
id: HeldItemCategoryId,
|
||||||
|
pokemon: Pokemon | Pokemon[],
|
||||||
|
customWeights: HeldItemWeights = {},
|
||||||
|
target?: Pokemon,
|
||||||
|
): HeldItemId | null {
|
||||||
|
if (id === HeldItemCategoryId.BERRY) {
|
||||||
|
return getNewBerryHeldItem(customWeights, target);
|
||||||
|
}
|
||||||
|
if (id === HeldItemCategoryId.VITAMIN) {
|
||||||
|
return getNewVitaminHeldItem(customWeights, target);
|
||||||
|
}
|
||||||
|
if (id === HeldItemCategoryId.TYPE_ATTACK_BOOSTER) {
|
||||||
|
return getNewAttackTypeBoosterHeldItem(pokemon, customWeights, target);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPoolWeights(pool: HeldItemPool, pokemon: Pokemon): number[] {
|
||||||
|
return pool.map(p => {
|
||||||
|
let weight = typeof p.weight === "function" ? p.weight(coerceArray(pokemon)) : p.weight;
|
||||||
|
|
||||||
|
if (typeof p.entry === "number" && !isCategoryId(p.entry)) {
|
||||||
|
const itemId = p.entry as HeldItemId;
|
||||||
|
console.log("ITEM ID: ", itemId, HeldItemNames[itemId]);
|
||||||
|
console.log(allHeldItems[itemId]);
|
||||||
|
|
||||||
|
if (pokemon.heldItemManager.getStack(itemId) >= allHeldItems[itemId].getMaxStackCount()) {
|
||||||
|
weight = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return weight;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNewHeldItemFromPool(pool: HeldItemPool, pokemon: Pokemon, party?: Pokemon[]): HeldItemId | HeldItemSpecs {
|
||||||
|
const weights = getPoolWeights(pool, pokemon);
|
||||||
|
|
||||||
|
const entry = pool[pickWeightedIndex(weights)].entry;
|
||||||
|
|
||||||
|
if (typeof entry === "number") {
|
||||||
|
if (isCategoryId(entry)) {
|
||||||
|
return getNewHeldItemFromCategory(entry, party ?? pokemon, {}, pokemon) as HeldItemId;
|
||||||
|
}
|
||||||
|
return entry as HeldItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHeldItemCategoryEntry(entry)) {
|
||||||
|
return getNewHeldItemFromCategory(entry.id, party ?? pokemon, entry?.customWeights, pokemon) as HeldItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry as HeldItemSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assignItemsFromCategory(id: HeldItemCategoryId, pokemon: Pokemon, count: number) {
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
const newItem = getNewHeldItemFromCategory(id, pokemon, {}, pokemon);
|
||||||
|
if (newItem) {
|
||||||
|
pokemon.heldItemManager.add(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assignItemsFromConfiguration(config: HeldItemConfiguration, pokemon: Pokemon) {
|
||||||
|
config.forEach(item => {
|
||||||
|
const { entry, count } = item;
|
||||||
|
const actualCount = typeof count === "function" ? count() : (count ?? 1);
|
||||||
|
|
||||||
|
if (typeof entry === "number") {
|
||||||
|
if (isCategoryId(entry)) {
|
||||||
|
assignItemsFromCategory(entry, pokemon, actualCount);
|
||||||
|
}
|
||||||
|
pokemon.heldItemManager.add(entry, actualCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHeldItemSpecs(entry)) {
|
||||||
|
pokemon.heldItemManager.add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHeldItemCategoryEntry(entry)) {
|
||||||
|
assignItemsFromCategory(entry.id, pokemon, actualCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHeldItemPool(entry)) {
|
||||||
|
for (let i = 1; i <= actualCount; i++) {
|
||||||
|
const newItem = getNewHeldItemFromPool(entry, pokemon);
|
||||||
|
if (newItem) {
|
||||||
|
pokemon.heldItemManager.add(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
47
src/items/held-item-tiers.ts
Normal file
47
src/items/held-item-tiers.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { getHeldItemCategory, HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
|
|
||||||
|
export const heldItemTiers = {
|
||||||
|
[HeldItemCategoryId.BERRY]: RewardTier.COMMON,
|
||||||
|
|
||||||
|
[HeldItemCategoryId.BASE_STAT_BOOST]: RewardTier.GREAT,
|
||||||
|
[HeldItemId.WHITE_HERB]: RewardTier.GREAT,
|
||||||
|
[HeldItemId.METAL_POWDER]: RewardTier.GREAT,
|
||||||
|
[HeldItemId.QUICK_POWDER]: RewardTier.GREAT,
|
||||||
|
[HeldItemId.DEEP_SEA_SCALE]: RewardTier.GREAT,
|
||||||
|
[HeldItemId.DEEP_SEA_TOOTH]: RewardTier.GREAT,
|
||||||
|
[HeldItemId.SOOTHE_BELL]: RewardTier.GREAT,
|
||||||
|
|
||||||
|
[HeldItemCategoryId.TYPE_ATTACK_BOOSTER]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.REVIVER_SEED]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.LIGHT_BALL]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.EVIOLITE]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.QUICK_CLAW]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.MYSTICAL_ROCK]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.WIDE_LENS]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.GOLDEN_PUNCH]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.TOXIC_ORB]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.FLAME_ORB]: RewardTier.ULTRA,
|
||||||
|
[HeldItemId.LUCKY_EGG]: RewardTier.ULTRA,
|
||||||
|
|
||||||
|
[HeldItemId.FOCUS_BAND]: RewardTier.ROGUE,
|
||||||
|
[HeldItemId.KINGS_ROCK]: RewardTier.ROGUE,
|
||||||
|
[HeldItemId.LEFTOVERS]: RewardTier.ROGUE,
|
||||||
|
[HeldItemId.SHELL_BELL]: RewardTier.ROGUE,
|
||||||
|
[HeldItemId.GRIP_CLAW]: RewardTier.ROGUE,
|
||||||
|
[HeldItemId.SOUL_DEW]: RewardTier.ROGUE,
|
||||||
|
[HeldItemId.BATON]: RewardTier.ROGUE,
|
||||||
|
[HeldItemId.GOLDEN_EGG]: RewardTier.ULTRA,
|
||||||
|
|
||||||
|
[HeldItemId.MINI_BLACK_HOLE]: RewardTier.MASTER,
|
||||||
|
[HeldItemId.MULTI_LENS]: RewardTier.MASTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getHeldItemTier(item: HeldItemId): RewardTier | undefined {
|
||||||
|
let tier = heldItemTiers[item];
|
||||||
|
if (!tier) {
|
||||||
|
const category = getHeldItemCategory(item);
|
||||||
|
tier = heldItemTiers[category];
|
||||||
|
}
|
||||||
|
return tier;
|
||||||
|
}
|
163
src/items/held-item.ts
Normal file
163
src/items/held-item.ts
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import { applyPostItemLostAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { HeldItemNames, type HeldItemId } from "#enums/held-item-id";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export const ITEM_EFFECT = {
|
||||||
|
ATTACK_TYPE_BOOST: 1,
|
||||||
|
TURN_END_HEAL: 2,
|
||||||
|
HIT_HEAL: 3,
|
||||||
|
RESET_NEGATIVE_STAT_STAGE: 4,
|
||||||
|
EXP_BOOSTER: 5,
|
||||||
|
// Should we actually distinguish different berry effects?
|
||||||
|
BERRY: 6,
|
||||||
|
BASE_STAT_BOOSTER: 7,
|
||||||
|
INSTANT_REVIVE: 8,
|
||||||
|
STAT_BOOST: 9,
|
||||||
|
CRIT_BOOST: 10,
|
||||||
|
TURN_END_STATUS: 11,
|
||||||
|
SURVIVE_CHANCE: 12,
|
||||||
|
BYPASS_SPEED_CHANCE: 13,
|
||||||
|
FLINCH_CHANCE: 14,
|
||||||
|
FIELD_EFFECT: 15,
|
||||||
|
FRIENDSHIP_BOOSTER: 16,
|
||||||
|
NATURE_WEIGHT_BOOSTER: 17,
|
||||||
|
ACCURACY_BOOSTER: 18,
|
||||||
|
MULTI_HIT: 19,
|
||||||
|
DAMAGE_MONEY_REWARD: 20,
|
||||||
|
BATON: 21,
|
||||||
|
TURN_END_ITEM_STEAL: 22,
|
||||||
|
CONTACT_ITEM_STEAL_CHANCE: 23,
|
||||||
|
EVO_TRACKER: 40,
|
||||||
|
BASE_STAT_TOTAL: 50,
|
||||||
|
BASE_STAT_FLAT: 51,
|
||||||
|
INCREMENTING_STAT: 52,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ITEM_EFFECT = (typeof ITEM_EFFECT)[keyof typeof ITEM_EFFECT];
|
||||||
|
|
||||||
|
export class HeldItem {
|
||||||
|
// public pokemonId: number;
|
||||||
|
public type: HeldItemId;
|
||||||
|
public maxStackCount: number;
|
||||||
|
public isTransferable = true;
|
||||||
|
public isStealable = true;
|
||||||
|
public isSuppressable = true;
|
||||||
|
|
||||||
|
//TODO: If this is actually never changed by any subclass, perhaps it should not be here
|
||||||
|
public soundName = "se/restore";
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1) {
|
||||||
|
this.type = type;
|
||||||
|
this.maxStackCount = maxStackCount;
|
||||||
|
|
||||||
|
this.isTransferable = true;
|
||||||
|
this.isStealable = true;
|
||||||
|
this.isSuppressable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t(`modifierType:ModifierType.${HeldItemNames[this.type]}.name`) + " (new)";
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t(`modifierType:ModifierType.${HeldItemNames[this.type]}.description`);
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return `${HeldItemNames[this.type]?.toLowerCase()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Aren't these fine as just properties to set in the subclass definition?
|
||||||
|
untransferable(): HeldItem {
|
||||||
|
this.isTransferable = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
unstealable(): HeldItem {
|
||||||
|
this.isStealable = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsuppressable(): HeldItem {
|
||||||
|
this.isSuppressable = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMaxStackCount(): number {
|
||||||
|
return this.maxStackCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
createSummaryIcon(pokemon: Pokemon): Phaser.GameObjects.Container {
|
||||||
|
const container = globalScene.add.container(0, 0);
|
||||||
|
|
||||||
|
const item = globalScene.add.sprite(0, 12, "items").setFrame(this.iconName).setOrigin(0, 0.5);
|
||||||
|
container.add(item);
|
||||||
|
|
||||||
|
const stackText = this.getIconStackText(pokemon);
|
||||||
|
if (stackText) {
|
||||||
|
container.add(stackText);
|
||||||
|
}
|
||||||
|
|
||||||
|
container.setScale(0.5);
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
createPokemonIcon(pokemon: Pokemon): Phaser.GameObjects.Container {
|
||||||
|
const container = globalScene.add.container(0, 0);
|
||||||
|
|
||||||
|
const pokemonIcon = globalScene.addPokemonIcon(pokemon, -2, 10, 0, 0.5, undefined, true);
|
||||||
|
container.add(pokemonIcon);
|
||||||
|
container.setName(pokemon.id.toString());
|
||||||
|
|
||||||
|
const item = globalScene.add
|
||||||
|
.sprite(16, 16, "items")
|
||||||
|
.setScale(0.5)
|
||||||
|
.setOrigin(0, 0.5)
|
||||||
|
.setTexture("items", this.iconName);
|
||||||
|
container.add(item);
|
||||||
|
|
||||||
|
const stackText = this.getIconStackText(pokemon);
|
||||||
|
if (stackText) {
|
||||||
|
container.add(stackText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIconStackText(pokemon: Pokemon): Phaser.GameObjects.BitmapText | null {
|
||||||
|
if (this.getMaxStackCount() === 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
const text = globalScene.add.bitmapText(10, 15, "item-count", stackCount.toString(), 11);
|
||||||
|
text.letterSpacing = -0.5;
|
||||||
|
if (stackCount >= this.getMaxStackCount()) {
|
||||||
|
text.setTint(0xf89890);
|
||||||
|
}
|
||||||
|
text.setOrigin(0);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
getScoreMultiplier(): number {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ConsumableHeldItem extends HeldItem {
|
||||||
|
// Sometimes berries are not eaten, some stuff may not proc unburden...
|
||||||
|
consume(pokemon: Pokemon, isPlayer: boolean, remove = true, unburden = true): void {
|
||||||
|
if (remove) {
|
||||||
|
pokemon.heldItemManager.remove(this.type, 1);
|
||||||
|
// TODO: Turn this into updateItemBar or something
|
||||||
|
globalScene.updateModifiers(isPlayer);
|
||||||
|
}
|
||||||
|
if (unburden) {
|
||||||
|
applyPostItemLostAbAttrs("PostItemLostAbAttr", pokemon, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/items/held-items/accuracy-booster.ts
Normal file
47
src/items/held-items/accuracy-booster.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface ACCURACY_BOOST_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
moveAccuracy: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AccuracyBoosterHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.ACCURACY_BOOSTER];
|
||||||
|
|
||||||
|
private accuracyAmount: number;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, accuracy: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
this.accuracyAmount = accuracy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if {@linkcode PokemonMoveAccuracyBoosterModifier} should be applied
|
||||||
|
* @param pokemon The {@linkcode Pokemon} to apply the move accuracy boost to
|
||||||
|
* @param moveAccuracy {@linkcode NumberHolder} holding the move accuracy boost
|
||||||
|
* @returns `true` if {@linkcode PokemonMoveAccuracyBoosterModifier} should be applied
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon?: Pokemon, moveAccuracy?: NumberHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, moveAccuracy) && !!moveAccuracy;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode PokemonMoveAccuracyBoosterModifier}
|
||||||
|
* @param _pokemon The {@linkcode Pokemon} to apply the move accuracy boost to
|
||||||
|
* @param moveAccuracy {@linkcode NumberHolder} holding the move accuracy boost
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: ACCURACY_BOOST_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const moveAccuracy = params.moveAccuracy;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
moveAccuracy.value = moveAccuracy.value + this.accuracyAmount * stackCount;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
77
src/items/held-items/attack-type-booster.ts
Normal file
77
src/items/held-items/attack-type-booster.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { HeldItemNames, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
|
||||||
|
export interface ATTACK_TYPE_BOOST_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The resolved type of the move */
|
||||||
|
moveType: PokemonType;
|
||||||
|
/** Holder for the damage value */
|
||||||
|
movePower: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AttackTypeToHeldItemMap {
|
||||||
|
[key: number]: HeldItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const attackTypeToHeldItem: AttackTypeToHeldItemMap = {
|
||||||
|
[PokemonType.NORMAL]: HeldItemId.SILK_SCARF,
|
||||||
|
[PokemonType.FIGHTING]: HeldItemId.BLACK_BELT,
|
||||||
|
[PokemonType.FLYING]: HeldItemId.SHARP_BEAK,
|
||||||
|
[PokemonType.POISON]: HeldItemId.POISON_BARB,
|
||||||
|
[PokemonType.GROUND]: HeldItemId.SOFT_SAND,
|
||||||
|
[PokemonType.ROCK]: HeldItemId.HARD_STONE,
|
||||||
|
[PokemonType.BUG]: HeldItemId.SILVER_POWDER,
|
||||||
|
[PokemonType.GHOST]: HeldItemId.SPELL_TAG,
|
||||||
|
[PokemonType.STEEL]: HeldItemId.METAL_COAT,
|
||||||
|
[PokemonType.FIRE]: HeldItemId.CHARCOAL,
|
||||||
|
[PokemonType.WATER]: HeldItemId.MYSTIC_WATER,
|
||||||
|
[PokemonType.GRASS]: HeldItemId.MIRACLE_SEED,
|
||||||
|
[PokemonType.ELECTRIC]: HeldItemId.MAGNET,
|
||||||
|
[PokemonType.PSYCHIC]: HeldItemId.TWISTED_SPOON,
|
||||||
|
[PokemonType.ICE]: HeldItemId.NEVER_MELT_ICE,
|
||||||
|
[PokemonType.DRAGON]: HeldItemId.DRAGON_FANG,
|
||||||
|
[PokemonType.DARK]: HeldItemId.BLACK_GLASSES,
|
||||||
|
[PokemonType.FAIRY]: HeldItemId.FAIRY_FEATHER,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class AttackTypeBoosterHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.TURN_END_HEAL];
|
||||||
|
public moveType: PokemonType;
|
||||||
|
public powerBoost: number;
|
||||||
|
|
||||||
|
// This constructor may need a revision
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, moveType: PokemonType, powerBoost: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
this.moveType = moveType;
|
||||||
|
this.powerBoost = powerBoost;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return i18next.t(`modifierType:AttackTypeBoosterItem.${HeldItemNames[this.type]?.toLowerCase()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.AttackTypeBoosterModifierType.description", {
|
||||||
|
moveType: i18next.t(`pokemonInfo:Type.${PokemonType[this.moveType]}`),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getIcon(): string {
|
||||||
|
return `${HeldItemNames[this.type]?.toLowerCase()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(params: ATTACK_TYPE_BOOST_PARAMS): void {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const moveType = params.moveType;
|
||||||
|
const movePower = params.movePower;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
if (moveType === this.moveType && movePower.value >= 1) {
|
||||||
|
movePower.value = Math.floor(movePower.value * (1 + stackCount * this.powerBoost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
src/items/held-items/base-stat-booster.ts
Normal file
81
src/items/held-items/base-stat-booster.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { getStatKey, type PermanentStat, Stat } from "#enums/stat";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface BASE_STAT_BOOSTER_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
baseStats: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PermanentStatToHeldItemMap {
|
||||||
|
[key: number]: HeldItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const permanentStatToHeldItem: PermanentStatToHeldItemMap = {
|
||||||
|
[Stat.HP]: HeldItemId.HP_UP,
|
||||||
|
[Stat.ATK]: HeldItemId.PROTEIN,
|
||||||
|
[Stat.DEF]: HeldItemId.IRON,
|
||||||
|
[Stat.SPATK]: HeldItemId.CALCIUM,
|
||||||
|
[Stat.SPDEF]: HeldItemId.ZINC,
|
||||||
|
[Stat.SPD]: HeldItemId.CARBOS,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const statBoostItems: Record<PermanentStat, string> = {
|
||||||
|
[Stat.HP]: "hp_up",
|
||||||
|
[Stat.ATK]: "protein",
|
||||||
|
[Stat.DEF]: "iron",
|
||||||
|
[Stat.SPATK]: "calcium",
|
||||||
|
[Stat.SPDEF]: "zinc",
|
||||||
|
[Stat.SPD]: "carbos",
|
||||||
|
};
|
||||||
|
|
||||||
|
export class BaseStatBoosterHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BASE_STAT_BOOSTER];
|
||||||
|
public stat: PermanentStat;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, stat: PermanentStat) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
this.stat = stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t(`modifierType:BaseStatBoosterItem.${statBoostItems[this.stat]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.BaseStatBoosterModifierType.description", {
|
||||||
|
stat: i18next.t(getStatKey(this.stat)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return statBoostItems[this.stat];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if {@linkcode BaseStatModifier} should be applied to the specified {@linkcode Pokemon}.
|
||||||
|
* @param _pokemon the {@linkcode Pokemon} to be modified
|
||||||
|
* @param baseStats the base stats of the {@linkcode Pokemon}
|
||||||
|
* @returns `true` if the {@linkcode Pokemon} should be modified
|
||||||
|
*/
|
||||||
|
// override shouldApply(_pokemon?: Pokemon, baseStats?: number[]): boolean {
|
||||||
|
// return super.shouldApply(_pokemon, baseStats) && Array.isArray(baseStats);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the {@linkcode BaseStatModifier} to the specified {@linkcode Pokemon}.
|
||||||
|
* @param _pokemon the {@linkcode Pokemon} to be modified
|
||||||
|
* @param baseStats the base stats of the {@linkcode Pokemon}
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: BASE_STAT_BOOSTER_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
const baseStats = params.baseStats;
|
||||||
|
baseStats[this.stat] = Math.floor(baseStats[this.stat] * (1 + stackCount * 0.1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
67
src/items/held-items/base-stat-flat.ts
Normal file
67
src/items/held-items/base-stat-flat.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
import { getStatKey } from "#enums/stat";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export interface BASE_STAT_FLAT_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
baseStats: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used by Old Gateau item
|
||||||
|
*/
|
||||||
|
export class BaseStatFlatHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BASE_STAT_FLAT];
|
||||||
|
public isTransferable = false;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.PokemonBaseStatFlatModifierType.description", {
|
||||||
|
stats: this.stats.map(stat => i18next.t(getStatKey(stat))).join("/"),
|
||||||
|
statValue: this.statModifier,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the {@linkcode PokemonBaseStatFlatModifier} should be applied to the {@linkcode Pokemon}.
|
||||||
|
* @param pokemon The {@linkcode Pokemon} that holds the item
|
||||||
|
* @param baseStats The base stats of the {@linkcode Pokemon}
|
||||||
|
* @returns `true` if the {@linkcode PokemonBaseStatFlatModifier} should be applied
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon?: Pokemon, baseStats?: number[]): boolean {
|
||||||
|
// return super.shouldApply(pokemon, baseStats) && Array.isArray(baseStats);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the {@linkcode PokemonBaseStatFlatModifier}
|
||||||
|
* @param _pokemon The {@linkcode Pokemon} that holds the item
|
||||||
|
* @param baseStats The base stats of the {@linkcode Pokemon}
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: BASE_STAT_FLAT_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const itemData = pokemon.heldItemManager.heldItems[this.type]?.data as BASE_STAT_FLAT_DATA;
|
||||||
|
if (!itemData) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const statModifier = itemData.statModifier;
|
||||||
|
const stats = itemData.stats;
|
||||||
|
const baseStats = params.baseStats;
|
||||||
|
// Modifies the passed in baseStats[] array by a flat value, only if the stat is specified in this.stats
|
||||||
|
baseStats.forEach((v, i) => {
|
||||||
|
if (stats.includes(i)) {
|
||||||
|
const newVal = Math.floor(v + statModifier);
|
||||||
|
baseStats[i] = Math.min(Math.max(newVal, 1), 999999);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
78
src/items/held-items/base-stat-total.ts
Normal file
78
src/items/held-items/base-stat-total.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
import type { BASE_STAT_TOTAL_DATA } from "../held-item-data";
|
||||||
|
|
||||||
|
export interface BASE_STAT_TOTAL_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
baseStats: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used by Shuckle Juice item
|
||||||
|
*/
|
||||||
|
export class BaseStatTotalHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BASE_STAT_TOTAL];
|
||||||
|
public isTransferable = false;
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.MYSTERY_ENCOUNTER_SHUCKLE_JUICE") + " (new)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: where is this description shown?
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.PokemonBaseStatTotalModifierType.description", {
|
||||||
|
increaseDecrease: i18next.t(
|
||||||
|
this.statModifier >= 0
|
||||||
|
? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.increase"
|
||||||
|
: "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.decrease",
|
||||||
|
),
|
||||||
|
blessCurse: i18next.t(
|
||||||
|
this.statModifier >= 0
|
||||||
|
? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.blessed"
|
||||||
|
: "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.cursed",
|
||||||
|
),
|
||||||
|
statValue: this.statModifier,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return "berry_juice";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if {@linkcode PokemonBaseStatTotalModifier} should be applied to the specified {@linkcode Pokemon}.
|
||||||
|
* @param pokemon the {@linkcode Pokemon} to be modified
|
||||||
|
* @param baseStats the base stats of the {@linkcode Pokemon}
|
||||||
|
* @returns `true` if the {@linkcode Pokemon} should be modified
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon?: Pokemon, baseStats?: number[]): boolean {
|
||||||
|
// return super.shouldApply(pokemon, baseStats) && Array.isArray(baseStats);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the {@linkcode PokemonBaseStatTotalModifier}
|
||||||
|
* @param _pokemon the {@linkcode Pokemon} to be modified
|
||||||
|
* @param baseStats the base stats of the {@linkcode Pokemon}
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: BASE_STAT_TOTAL_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const itemData = pokemon.heldItemManager.heldItems[this.type]?.data as BASE_STAT_TOTAL_DATA;
|
||||||
|
if (!itemData) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const statModifier = itemData.statModifier;
|
||||||
|
const baseStats = params.baseStats;
|
||||||
|
// Modifies the passed in baseStats[] array
|
||||||
|
baseStats.forEach((v, i) => {
|
||||||
|
// HP is affected by half as much as other stats
|
||||||
|
const newVal = i === 0 ? Math.floor(v + statModifier / 2) : Math.floor(v + statModifier);
|
||||||
|
baseStats[i] = Math.min(Math.max(newVal, 1), 999999);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
22
src/items/held-items/baton.ts
Normal file
22
src/items/held-items/baton.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface BATON_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
expAmount: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BatonHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BATON];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode SwitchEffectTransferModifier}
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
96
src/items/held-items/berry.ts
Normal file
96
src/items/held-items/berry.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { getBerryEffectDescription, getBerryEffectFunc, getBerryName, getBerryPredicate } from "#app/data/berry";
|
||||||
|
import { BerryUsedEvent } from "#app/events/battle-scene";
|
||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { ConsumableHeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { PreserveBerryModifier } from "#app/modifier/modifier";
|
||||||
|
import { BooleanHolder } from "#app/utils/common";
|
||||||
|
import { BerryType } from "#enums/berry-type";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
|
interface BerryTypeToHeldItemMap {
|
||||||
|
[key: number]: HeldItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const berryTypeToHeldItem: BerryTypeToHeldItemMap = {
|
||||||
|
[BerryType.SITRUS]: HeldItemId.SITRUS_BERRY,
|
||||||
|
[BerryType.LUM]: HeldItemId.LUM_BERRY,
|
||||||
|
[BerryType.ENIGMA]: HeldItemId.ENIGMA_BERRY,
|
||||||
|
[BerryType.LIECHI]: HeldItemId.LIECHI_BERRY,
|
||||||
|
[BerryType.GANLON]: HeldItemId.GANLON_BERRY,
|
||||||
|
[BerryType.PETAYA]: HeldItemId.PETAYA_BERRY,
|
||||||
|
[BerryType.APICOT]: HeldItemId.APICOT_BERRY,
|
||||||
|
[BerryType.SALAC]: HeldItemId.SALAC_BERRY,
|
||||||
|
[BerryType.LANSAT]: HeldItemId.LANSAT_BERRY,
|
||||||
|
[BerryType.STARF]: HeldItemId.STARF_BERRY,
|
||||||
|
[BerryType.LEPPA]: HeldItemId.LEPPA_BERRY,
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface BERRY_PARAMS {
|
||||||
|
/** The pokemon with the berry */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe split up into subclasses?
|
||||||
|
export class BerryHeldItem extends ConsumableHeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BERRY];
|
||||||
|
public berryType: BerryType;
|
||||||
|
|
||||||
|
constructor(berryType: BerryType, maxStackCount = 1) {
|
||||||
|
const type = berryTypeToHeldItem[berryType];
|
||||||
|
super(type, maxStackCount);
|
||||||
|
|
||||||
|
this.berryType = berryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return getBerryName(this.berryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return getBerryEffectDescription(this.berryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return `${BerryType[this.berryType].toLowerCase()}_berry`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if {@linkcode BerryModifier} should be applied
|
||||||
|
* @param pokemon The {@linkcode Pokemon} that holds the berry
|
||||||
|
* @returns `true` if {@linkcode BerryModifier} should be applied
|
||||||
|
*/
|
||||||
|
shouldApply(pokemon: Pokemon): boolean {
|
||||||
|
return getBerryPredicate(this.berryType)(pokemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode BerryHeldItem}
|
||||||
|
* @param pokemon The {@linkcode Pokemon} that holds the berry
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: BERRY_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
|
||||||
|
if (!this.shouldApply(pokemon)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const preserve = new BooleanHolder(false);
|
||||||
|
globalScene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve);
|
||||||
|
const consumed = !preserve.value;
|
||||||
|
|
||||||
|
// munch the berry and trigger unburden-like effects
|
||||||
|
getBerryEffectFunc(this.berryType)(pokemon);
|
||||||
|
this.consume(pokemon, pokemon.isPlayer(), consumed);
|
||||||
|
|
||||||
|
// TODO: Update this method to work with held items
|
||||||
|
// Update berry eaten trackers for Belch, Harvest, Cud Chew, etc.
|
||||||
|
// Don't recover it if we proc berry pouch (no item duplication)
|
||||||
|
pokemon.recordEatenBerry(this.berryType, consumed);
|
||||||
|
|
||||||
|
globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(pokemon, this.berryType));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
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 "#enums/command";
|
||||||
|
|
||||||
|
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.phaseManager.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;
|
||||||
|
}
|
||||||
|
}
|
33
src/items/held-items/damage-money-reward.ts
Normal file
33
src/items/held-items/damage-money-reward.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { MoneyMultiplierModifier } from "#app/modifier/modifier";
|
||||||
|
import { NumberHolder } from "#app/utils/common";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface DAMAGE_MONEY_REWARD_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
damage: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DamageMoneyRewardHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.DAMAGE_MONEY_REWARD];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode DamageMoneyRewardModifier}
|
||||||
|
* @param pokemon The {@linkcode Pokemon} attacking
|
||||||
|
* @param multiplier {@linkcode NumberHolder} holding the multiplier value
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: DAMAGE_MONEY_REWARD_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const damage = params.damage;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
const moneyAmount = new NumberHolder(Math.floor(damage * (0.5 * stackCount)));
|
||||||
|
globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount);
|
||||||
|
globalScene.addMoney(moneyAmount.value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
82
src/items/held-items/evo-tracker.ts
Normal file
82
src/items/held-items/evo-tracker.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import type { SpeciesId } from "#enums/species-id";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface EVO_TRACKER_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
multiplier: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Possibly replace with this
|
||||||
|
export interface EVO_TRACKER_DATA {
|
||||||
|
evoCounter: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EvoTrackerHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.EVO_TRACKER];
|
||||||
|
|
||||||
|
protected species: SpeciesId;
|
||||||
|
protected required: number;
|
||||||
|
public isTransferable = false;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, species: SpeciesId, required: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
this.species = species;
|
||||||
|
this.required = required;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the {@linkcode EvoTrackerModifier}
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIconStackText(pokemon: Pokemon): Phaser.GameObjects.BitmapText | null {
|
||||||
|
const stackCount = this.getStackCount(pokemon);
|
||||||
|
|
||||||
|
const text = globalScene.add.bitmapText(10, 15, "item-count", stackCount.toString(), 11);
|
||||||
|
text.letterSpacing = -0.5;
|
||||||
|
if (stackCount >= this.required) {
|
||||||
|
text.setTint(0xf89890);
|
||||||
|
}
|
||||||
|
text.setOrigin(0, 0);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
getStackCount(_pokemon: Pokemon): number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GimmighoulEvoTrackerHeldItem extends EvoTrackerHeldItem {
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.EVOLUTION_TRACKER_GIMMIGHOUL.name");
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.EVOLUTION_TRACKER_GIMMIGHOUL.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return "relic_gold";
|
||||||
|
}
|
||||||
|
|
||||||
|
getStackCount(pokemon: Pokemon): number {
|
||||||
|
const stackCount =
|
||||||
|
pokemon.evoCounter +
|
||||||
|
pokemon.heldItemManager.getStack(HeldItemId.GOLDEN_PUNCH) +
|
||||||
|
globalScene.findModifiers(
|
||||||
|
m => m.is("MoneyMultiplierModifier") || m.is("ExtraModifierModifier") || m.is("TempExtraModifierModifier"),
|
||||||
|
).length;
|
||||||
|
return stackCount;
|
||||||
|
}
|
||||||
|
}
|
56
src/items/held-items/exp-booster.ts
Normal file
56
src/items/held-items/exp-booster.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface EXP_BOOST_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
expAmount: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExpBoosterHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.EXP_BOOSTER];
|
||||||
|
private boostPercent: number;
|
||||||
|
private boostMultiplier: number;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, boostPercent: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
this.boostPercent = boostPercent;
|
||||||
|
this.boostMultiplier = boostPercent * 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.PokemonExpBoosterModifierType.description", {
|
||||||
|
boostPercent: this.boostPercent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: What do we do with this? Need to look up all the shouldApply
|
||||||
|
/**
|
||||||
|
* Checks if {@linkcode PokemonExpBoosterModifier} should be applied
|
||||||
|
* @param pokemon The {@linkcode Pokemon} to apply the exp boost to
|
||||||
|
* @param boost {@linkcode NumberHolder} holding the exp boost value
|
||||||
|
* @returns `true` if {@linkcode PokemonExpBoosterModifier} should be applied
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon: Pokemon, boost: NumberHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, boost) && !!boost;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode PokemonExpBoosterModifier}
|
||||||
|
* @param _pokemon The {@linkcode Pokemon} to apply the exp boost to
|
||||||
|
* @param boost {@linkcode NumberHolder} holding the exp boost value
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: EXP_BOOST_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const expAmount = params.expAmount;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
expAmount.value = Math.floor(expAmount.value * (1 + stackCount * this.boostMultiplier));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
33
src/items/held-items/field-effect.ts
Normal file
33
src/items/held-items/field-effect.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
|
||||||
|
export interface FIELD_EFFECT_PARAMS {
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The pokemon with the item */
|
||||||
|
fieldDuration: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, namely Mystical Rock, that extend the
|
||||||
|
* duration of weather and terrain effects.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class FieldEffectHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.FIELD_EFFECT];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides two more turns per stack to any weather or terrain effect caused
|
||||||
|
* by the holder.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the held item
|
||||||
|
* @param fieldDuration {@linkcode NumberHolder} that stores the current field effect duration
|
||||||
|
* @returns `true` if the field effect extension was applied successfully
|
||||||
|
*/
|
||||||
|
apply(params: FIELD_EFFECT_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
params.fieldDuration.value += 2 * stackCount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
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;
|
||||||
|
}
|
||||||
|
}
|
34
src/items/held-items/friendship-booster.ts
Normal file
34
src/items/held-items/friendship-booster.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface FRIENDSHIP_BOOST_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
friendship: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FriendshipBoosterHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.FRIENDSHIP_BOOSTER];
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.PokemonFriendshipBoosterModifierType.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode PokemonFriendshipBoosterModifier}
|
||||||
|
* @param _pokemon The {@linkcode Pokemon} to apply the friendship boost to
|
||||||
|
* @param friendship {@linkcode NumberHolder} holding the friendship boost value
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: FRIENDSHIP_BOOST_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const friendship = params.friendship;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
friendship.value = Math.floor(friendship.value * (1 + 0.5 * stackCount));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
53
src/items/held-items/hit-heal.ts
Normal file
53
src/items/held-items/hit-heal.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
||||||
|
import { toDmgValue } from "#app/utils/common";
|
||||||
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
|
||||||
|
export interface HIT_HEAL_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HitHealHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.TURN_END_HEAL];
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.SHELL_BELL.name");
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.SHELL_BELL.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return "shell_bell";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode HitHealModifier}
|
||||||
|
* @param pokemon The {@linkcode Pokemon} that holds the item
|
||||||
|
* @returns `true` if the {@linkcode Pokemon} was healed
|
||||||
|
*/
|
||||||
|
apply(params: HIT_HEAL_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) {
|
||||||
|
// TODO: this shouldn't be undefined AFAIK
|
||||||
|
globalScene.unshiftPhase(
|
||||||
|
new PokemonHealPhase(
|
||||||
|
pokemon.getBattlerIndex(),
|
||||||
|
toDmgValue(pokemon.turnData.totalDamageDealt / 8) * stackCount,
|
||||||
|
i18next.t("modifier:hitHealApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
typeName: this.name,
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
70
src/items/held-items/incrementing-stat.ts
Normal file
70
src/items/held-items/incrementing-stat.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export interface INCREMENTING_STAT_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
stat: Stat;
|
||||||
|
statHolder: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used by Macho Brace item
|
||||||
|
*/
|
||||||
|
export class IncrementingStatHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.INCREMENTING_STAT];
|
||||||
|
public isTransferable = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the {@linkcode PokemonIncrementingStatModifier} should be applied to the {@linkcode Pokemon}.
|
||||||
|
* @param pokemon The {@linkcode Pokemon} that holds the item
|
||||||
|
* @param stat The affected {@linkcode Stat}
|
||||||
|
* @param statHolder The {@linkcode NumberHolder} that holds the stat
|
||||||
|
* @returns `true` if the {@linkcode PokemonBaseStatFlatModifier} should be applied
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon?: Pokemon, stat?: Stat, statHolder?: NumberHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, stat, statHolder) && !!statHolder;
|
||||||
|
// }
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE.name") + " (new)";
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the {@linkcode PokemonIncrementingStatModifier}
|
||||||
|
* @param _pokemon The {@linkcode Pokemon} that holds the item
|
||||||
|
* @param stat The affected {@linkcode Stat}
|
||||||
|
* @param statHolder The {@linkcode NumberHolder} that holds the stat
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: INCREMENTING_STAT_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
const statHolder = params.statHolder;
|
||||||
|
|
||||||
|
// Modifies the passed in stat number holder by +2 per stack for HP, +1 per stack for other stats
|
||||||
|
// If the Macho Brace is at max stacks (50), adds additional 10% to total HP and 5% to other stats
|
||||||
|
const isHp = params.stat === Stat.HP;
|
||||||
|
|
||||||
|
if (isHp) {
|
||||||
|
statHolder.value += 2 * stackCount;
|
||||||
|
if (stackCount === this.maxStackCount) {
|
||||||
|
statHolder.value = Math.floor(statHolder.value * 1.1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
statHolder.value += stackCount;
|
||||||
|
if (stackCount === this.maxStackCount) {
|
||||||
|
statHolder.value = Math.floor(statHolder.value * 1.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
68
src/items/held-items/instant-revive.ts
Normal file
68
src/items/held-items/instant-revive.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { ConsumableHeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
||||||
|
import { toDmgValue } from "#app/utils/common";
|
||||||
|
import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
|
|
||||||
|
export interface INSTANT_REVIVE_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, namely White Herb, that restore adverse stat
|
||||||
|
* stages in battle.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class InstantReviveHeldItem extends ConsumableHeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.INSTANT_REVIVE];
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.REVIVER_SEED.name");
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.REVIVER_SEED.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return "reviver_seed";
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Goes through the holder's stat stages and, if any are negative, resets that
|
||||||
|
* stat stage back to 0.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the item
|
||||||
|
* @returns `true` if any stat stages were reset, false otherwise
|
||||||
|
*/
|
||||||
|
apply(params: INSTANT_REVIVE_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
// Restore the Pokemon to half HP
|
||||||
|
globalScene.phaseManager.unshiftPhase(
|
||||||
|
new PokemonHealPhase(
|
||||||
|
pokemon.getBattlerIndex(),
|
||||||
|
toDmgValue(pokemon.getMaxHp() / 2),
|
||||||
|
i18next.t("modifier:pokemonInstantReviveApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
typeName: this.name,
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove the Pokemon's FAINT status
|
||||||
|
pokemon.resetStatus(true, false, true, false);
|
||||||
|
|
||||||
|
// Reapply Commander on the Pokemon's side of the field, if applicable
|
||||||
|
const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
|
||||||
|
for (const p of field) {
|
||||||
|
applyAbAttrs("CommanderAbAttr", p, null, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
167
src/items/held-items/item-steal.ts
Normal file
167
src/items/held-items/item-steal.ts
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import Pokemon from "#app/field/pokemon";
|
||||||
|
import { randSeedFloat } from "#app/utils/common";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
import { allHeldItems } from "../all-held-items";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
|
||||||
|
export interface ITEM_STEAL_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The pokemon to steal from (optional) */
|
||||||
|
target?: Pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructor(type: HeldItemId, maxStackCount = 1, boostPercent: number) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for held items that steal other Pokemon's items.
|
||||||
|
* @see {@linkcode TurnEndItemStealHeldItem}
|
||||||
|
* @see {@linkcode ContactItemStealChanceHeldItem}
|
||||||
|
*/
|
||||||
|
export abstract class ItemTransferHeldItem extends HeldItem {
|
||||||
|
/**
|
||||||
|
* Steals an item, chosen randomly, from a set of target Pokemon.
|
||||||
|
* @param pokemon The {@linkcode Pokemon} holding this item
|
||||||
|
* @param target The {@linkcode Pokemon} to steal from (optional)
|
||||||
|
* @param _args N/A
|
||||||
|
* @returns `true` if an item was stolen; false otherwise.
|
||||||
|
*/
|
||||||
|
apply(params: ITEM_STEAL_PARAMS): boolean {
|
||||||
|
const opponents = this.getTargets(params);
|
||||||
|
|
||||||
|
if (!opponents.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
//TODO: Simplify this logic here
|
||||||
|
const targetPokemon = opponents[pokemon.randBattleSeedInt(opponents.length)];
|
||||||
|
|
||||||
|
const transferredItemCount = this.getTransferredItemCount(params);
|
||||||
|
if (!transferredItemCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Change this logic to use held items
|
||||||
|
const transferredModifierTypes: HeldItemId[] = [];
|
||||||
|
const heldItems = targetPokemon.heldItemManager.getTransferableHeldItems();
|
||||||
|
|
||||||
|
for (let i = 0; i < transferredItemCount; i++) {
|
||||||
|
if (!heldItems.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const randItemIndex = pokemon.randBattleSeedInt(heldItems.length);
|
||||||
|
const randItem = heldItems[randItemIndex];
|
||||||
|
// TODO: Fix this after updating the various methods in battle-scene.ts
|
||||||
|
if (globalScene.tryTransferHeldItem(randItem, targetPokemon, pokemon, false)) {
|
||||||
|
transferredModifierTypes.push(randItem);
|
||||||
|
heldItems.splice(randItemIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const mt of transferredModifierTypes) {
|
||||||
|
globalScene.phaseManager.queueMessage(this.getTransferMessage(params, mt));
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!transferredModifierTypes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract getTargets(params: ITEM_STEAL_PARAMS): Pokemon[];
|
||||||
|
|
||||||
|
abstract getTransferredItemCount(params: ITEM_STEAL_PARAMS): number;
|
||||||
|
|
||||||
|
abstract getTransferMessage(params: ITEM_STEAL_PARAMS, itemId: HeldItemId): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier for held items that steal items from the enemy at the end of
|
||||||
|
* each turn.
|
||||||
|
* @see {@linkcode modifierTypes[MINI_BLACK_HOLE]}
|
||||||
|
*/
|
||||||
|
export class TurnEndItemStealHeldItem extends ItemTransferHeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.TURN_END_ITEM_STEAL];
|
||||||
|
isTransferable = true;
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.TurnHeldItemTransferModifierType.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the targets to transfer items from when this applies.
|
||||||
|
* @param pokemon the {@linkcode Pokemon} holding this item
|
||||||
|
* @param _args N/A
|
||||||
|
* @returns the opponents of the source {@linkcode Pokemon}
|
||||||
|
*/
|
||||||
|
getTargets(params: ITEM_STEAL_PARAMS): Pokemon[] {
|
||||||
|
return params.pokemon instanceof Pokemon ? params.pokemon.getOpponents() : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransferredItemCount(_params: ITEM_STEAL_PARAMS): number {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransferMessage(params: ITEM_STEAL_PARAMS, itemId: HeldItemId): string {
|
||||||
|
return i18next.t("modifier:turnHeldItemTransferApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(params.target),
|
||||||
|
itemName: allHeldItems[itemId].name,
|
||||||
|
pokemonName: params.pokemon.getNameToRender(),
|
||||||
|
typeName: this.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setTransferrableFalse(): void {
|
||||||
|
this.isTransferable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier for held items that add a chance to steal items from the target of a
|
||||||
|
* successful attack.
|
||||||
|
* @see {@linkcode modifierTypes[GRIP_CLAW]}
|
||||||
|
* @see {@linkcode HeldItemTransferModifier}
|
||||||
|
*/
|
||||||
|
export class ContactItemStealChanceHeldItem extends ItemTransferHeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.CONTACT_ITEM_STEAL_CHANCE];
|
||||||
|
public readonly chancePercent: number;
|
||||||
|
public readonly chance: number;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, chancePercent: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
|
||||||
|
this.chancePercent = chancePercent;
|
||||||
|
this.chance = chancePercent / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.ContactHeldItemTransferChanceModifierType.description", {
|
||||||
|
chancePercent: this.chancePercent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the target to steal items from when this applies.
|
||||||
|
* @param _holderPokemon The {@linkcode Pokemon} holding this item
|
||||||
|
* @param targetPokemon The {@linkcode Pokemon} the holder is targeting with an attack
|
||||||
|
* @returns The target {@linkcode Pokemon} as array for further use in `apply` implementations
|
||||||
|
*/
|
||||||
|
getTargets(params: ITEM_STEAL_PARAMS): Pokemon[] {
|
||||||
|
return params.target ? [params.target] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransferredItemCount(params: ITEM_STEAL_PARAMS): number {
|
||||||
|
const stackCount = params.pokemon.heldItemManager.getStack(this.type);
|
||||||
|
return randSeedFloat() <= this.chance * stackCount ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransferMessage(params: ITEM_STEAL_PARAMS, itemId: HeldItemId): string {
|
||||||
|
return i18next.t("modifier:contactHeldItemTransferApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(params.target),
|
||||||
|
itemName: allHeldItems[itemId].name,
|
||||||
|
pokemonName: params.pokemon.getNameToRender(),
|
||||||
|
typeName: this.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
89
src/items/held-items/multi-hit.ts
Normal file
89
src/items/held-items/multi-hit.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { isNullOrUndefined, type NumberHolder } from "#app/utils/common";
|
||||||
|
import type { MoveId } from "#enums/move-id";
|
||||||
|
import { allMoves } from "#app/data/data-lists";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export interface MULTI_HIT_PARAMS {
|
||||||
|
pokemon: Pokemon;
|
||||||
|
moveId: MoveId;
|
||||||
|
count?: NumberHolder;
|
||||||
|
damageMultiplier?: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 MultiHitHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.MULTI_HIT];
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.PokemonMultiHitModifierType.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each stack, converts 25 percent of attack damage into an additional strike.
|
||||||
|
* @param pokemon The {@linkcode Pokemon} using the move
|
||||||
|
* @param moveId The {@linkcode MoveId | identifier} for the move being used
|
||||||
|
* @param count {@linkcode NumberHolder} holding the move's hit count for this turn
|
||||||
|
* @param damageMultiplier {@linkcode NumberHolder} holding a damage multiplier applied to a strike of this move
|
||||||
|
* @returns always `true`
|
||||||
|
*/
|
||||||
|
apply(params: MULTI_HIT_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const move = allMoves[params.moveId];
|
||||||
|
/**
|
||||||
|
* The move must meet Parental Bond's restrictions for this item
|
||||||
|
* to apply. This means
|
||||||
|
* - Only attacks are boosted
|
||||||
|
* - Multi-strike moves, charge moves, and self-sacrificial moves are not boosted
|
||||||
|
* (though Multi-Lens can still affect moves boosted by Parental Bond)
|
||||||
|
* - Multi-target moves are not boosted *unless* they can only hit a single Pokemon
|
||||||
|
* - Fling, Uproar, Rollout, Ice Ball, and Endeavor are not boosted
|
||||||
|
*/
|
||||||
|
if (!move.canBeMultiStrikeEnhanced(pokemon)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNullOrUndefined(params.count)) {
|
||||||
|
return this.applyHitCountBoost(pokemon, params.count);
|
||||||
|
}
|
||||||
|
if (!isNullOrUndefined(params.damageMultiplier)) {
|
||||||
|
return this.applyDamageModifier(pokemon, params.damageMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds strikes to a move equal to the number of stacked Multi-Lenses */
|
||||||
|
private applyHitCountBoost(pokemon: Pokemon, count: NumberHolder): boolean {
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
count.value += stackCount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If applied to the first hit of a move, sets the damage multiplier
|
||||||
|
* equal to (1 - the number of stacked Multi-Lenses).
|
||||||
|
* Additional strikes beyond that are given a 0.25x damage multiplier
|
||||||
|
*/
|
||||||
|
private applyDamageModifier(pokemon: Pokemon, damageMultiplier: NumberHolder): boolean {
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
if (pokemon.turnData.hitsLeft === pokemon.turnData.hitCount) {
|
||||||
|
// Reduce first hit by 25% for each stack count
|
||||||
|
damageMultiplier.value *= 1 - 0.25 * stackCount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pokemon.turnData.hitCount - pokemon.turnData.hitsLeft !== stackCount + 1) {
|
||||||
|
// Deal 25% damage for each remaining Multi Lens hit
|
||||||
|
damageMultiplier.value *= 0.25;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// An extra hit not caused by Multi Lens -- assume it is Parental Bond
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
32
src/items/held-items/nature-weight-booster.ts
Normal file
32
src/items/held-items/nature-weight-booster.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface NATURE_WEIGHT_BOOST_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** The amount of exp to gain */
|
||||||
|
multiplier: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NatureWeightBoosterHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.NATURE_WEIGHT_BOOSTER];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies {@linkcode PokemonNatureWeightModifier}
|
||||||
|
* @param _pokemon The {@linkcode Pokemon} to apply the nature weight to
|
||||||
|
* @param multiplier {@linkcode NumberHolder} holding the nature weight
|
||||||
|
* @returns `true` if multiplier was applied
|
||||||
|
*/
|
||||||
|
apply(params: NATURE_WEIGHT_BOOST_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const multiplier = params.multiplier;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
if (multiplier.value !== 1) {
|
||||||
|
multiplier.value += 0.1 * stackCount * (multiplier.value > 1 ? 1 : -1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
66
src/items/held-items/reset-negative-stat-stage.ts
Normal file
66
src/items/held-items/reset-negative-stat-stage.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { BATTLE_STATS } from "#enums/stat";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { ConsumableHeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
|
||||||
|
export interface RESET_NEGATIVE_STAT_STAGE_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
/** Whether the move was used by a player pokemon */
|
||||||
|
isPlayer: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, namely White Herb, that restore adverse stat
|
||||||
|
* stages in battle.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class ResetNegativeStatStageHeldItem extends ConsumableHeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.RESET_NEGATIVE_STAT_STAGE];
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.WHITE_HERB.name");
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string {
|
||||||
|
return i18next.t("modifierType:ModifierType.WHITE_HERB.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconName(): string {
|
||||||
|
return "white_herb";
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Goes through the holder's stat stages and, if any are negative, resets that
|
||||||
|
* stat stage back to 0.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the item
|
||||||
|
* @returns `true` if any stat stages were reset, false otherwise
|
||||||
|
*/
|
||||||
|
apply(params: RESET_NEGATIVE_STAT_STAGE_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const isPlayer = params.isPlayer;
|
||||||
|
let statRestored = false;
|
||||||
|
|
||||||
|
for (const s of BATTLE_STATS) {
|
||||||
|
if (pokemon.getStatStage(s) < 0) {
|
||||||
|
pokemon.setStatStage(s, 0);
|
||||||
|
statRestored = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statRestored) {
|
||||||
|
globalScene.phaseManager.queueMessage(
|
||||||
|
i18next.t("modifier:resetNegativeStatStageApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
typeName: this.name,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.consume(pokemon, isPlayer, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statRestored;
|
||||||
|
}
|
||||||
|
}
|
191
src/items/held-items/stat-booster.ts
Normal file
191
src/items/held-items/stat-booster.ts
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import type { NumberHolder } from "#app/utils/common";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import type { SpeciesId } from "#enums/species-id";
|
||||||
|
import type { Stat } from "#enums/stat";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||||
|
|
||||||
|
export interface STAT_BOOST_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
stat: Stat;
|
||||||
|
statValue: NumberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items that Applies {@linkcode Stat} boost(s)
|
||||||
|
* using a multiplier.
|
||||||
|
* @extends PokemonHeldItemModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class StatBoostHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.STAT_BOOST];
|
||||||
|
/** The stats that the held item boosts */
|
||||||
|
protected stats: Stat[];
|
||||||
|
/** The multiplier used to increase the relevant stat(s) */
|
||||||
|
protected multiplier: number;
|
||||||
|
|
||||||
|
constructor(type: HeldItemId, maxStackCount = 1, stats: Stat[], multiplier: number) {
|
||||||
|
super(type, maxStackCount);
|
||||||
|
|
||||||
|
this.stats = stats;
|
||||||
|
this.multiplier = multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the incoming stat is listed in {@linkcode stats}
|
||||||
|
* @param _pokemon the {@linkcode Pokemon} that holds the item
|
||||||
|
* @param _stat the {@linkcode Stat} to be boosted
|
||||||
|
* @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat
|
||||||
|
* @returns `true` if the stat could be boosted, false otherwise
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, stat, statValue) && this.stats.includes(stat);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boosts the incoming stat by a {@linkcode multiplier} if the stat is listed
|
||||||
|
* in {@linkcode stats}.
|
||||||
|
* @param _pokemon the {@linkcode Pokemon} that holds the item
|
||||||
|
* @param _stat the {@linkcode Stat} to be boosted
|
||||||
|
* @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat
|
||||||
|
* @returns `true` if the stat boost applies successfully, false otherwise
|
||||||
|
* @see shouldApply
|
||||||
|
*/
|
||||||
|
apply(params: STAT_BOOST_PARAMS): boolean {
|
||||||
|
params.statValue.value *= this.multiplier;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items, specifically Eviolite, that apply
|
||||||
|
* {@linkcode Stat} boost(s) using a multiplier if the holder can evolve.
|
||||||
|
* @extends StatBoosterModifier
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class EvolutionStatBoostHeldItem extends StatBoostHeldItem {
|
||||||
|
/**
|
||||||
|
* Checks if the stat boosts can apply and if the holder is not currently
|
||||||
|
* Gigantamax'd.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the held item
|
||||||
|
* @param stat {@linkcode Stat} The {@linkcode Stat} to be boosted
|
||||||
|
* @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat
|
||||||
|
* @returns `true` if the stat boosts can be applied, false otherwise
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean {
|
||||||
|
// return super.shouldApply(pokemon, stat, statValue) && !pokemon.isMax();
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boosts the incoming stat value by a {@linkcode EvolutionStatBoosterModifier.multiplier} if the holder
|
||||||
|
* can evolve. Note that, if the holder is a fusion, they will receive
|
||||||
|
* only half of the boost if either of the fused members are fully
|
||||||
|
* evolved. However, if they are both unevolved, the full boost
|
||||||
|
* will apply.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the item
|
||||||
|
* @param _stat {@linkcode Stat} The {@linkcode Stat} to be boosted
|
||||||
|
* @param statValue{@linkcode NumberHolder} that holds the resulting value of the stat
|
||||||
|
* @returns `true` if the stat boost applies successfully, false otherwise
|
||||||
|
* @see shouldApply
|
||||||
|
*/
|
||||||
|
override apply(params: STAT_BOOST_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const isUnevolved = pokemon.getSpeciesForm(true).speciesId in pokemonEvolutions;
|
||||||
|
|
||||||
|
if (pokemon.isFusion() && pokemon.getFusionSpeciesForm(true).speciesId in pokemonEvolutions !== isUnevolved) {
|
||||||
|
// Half boost applied if pokemon is fused and either part of fusion is fully evolved
|
||||||
|
params.statValue.value *= 1 + (this.multiplier - 1) / 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isUnevolved) {
|
||||||
|
// Full boost applied if holder is unfused and unevolved or, if fused, both parts of fusion are unevolved
|
||||||
|
return super.apply(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SpeciesStatBoosterItemId =
|
||||||
|
| typeof HeldItemId.LIGHT_BALL
|
||||||
|
| typeof HeldItemId.THICK_CLUB
|
||||||
|
| typeof HeldItemId.METAL_POWDER
|
||||||
|
| typeof HeldItemId.QUICK_POWDER
|
||||||
|
| typeof HeldItemId.DEEP_SEA_SCALE
|
||||||
|
| typeof HeldItemId.DEEP_SEA_TOOTH;
|
||||||
|
|
||||||
|
export const SPECIES_STAT_BOOSTER_ITEMS: SpeciesStatBoosterItemId[] = [
|
||||||
|
HeldItemId.LIGHT_BALL,
|
||||||
|
HeldItemId.THICK_CLUB,
|
||||||
|
HeldItemId.METAL_POWDER,
|
||||||
|
HeldItemId.QUICK_POWDER,
|
||||||
|
HeldItemId.DEEP_SEA_SCALE,
|
||||||
|
HeldItemId.DEEP_SEA_TOOTH,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifier used for held items that Applies {@linkcode Stat} boost(s) using a
|
||||||
|
* multiplier if the holder is of a specific {@linkcode SpeciesId}.
|
||||||
|
* @extends StatBoostHeldItem
|
||||||
|
* @see {@linkcode apply}
|
||||||
|
*/
|
||||||
|
export class SpeciesStatBoostHeldItem extends StatBoostHeldItem {
|
||||||
|
/** The species that the held item's stat boost(s) apply to */
|
||||||
|
private species: SpeciesId[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
type: SpeciesStatBoosterItemId,
|
||||||
|
maxStackCount = 1,
|
||||||
|
stats: Stat[],
|
||||||
|
multiplier: number,
|
||||||
|
species: SpeciesId[],
|
||||||
|
) {
|
||||||
|
super(type, maxStackCount, stats, multiplier);
|
||||||
|
this.species = species;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the incoming stat is listed in {@linkcode stats} and if the holder's {@linkcode SpeciesId}
|
||||||
|
* (or its fused species) is listed in {@linkcode species}.
|
||||||
|
* @param pokemon {@linkcode Pokemon} that holds the item
|
||||||
|
* @param stat {@linkcode Stat} being checked at the time
|
||||||
|
* @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat
|
||||||
|
* @returns `true` if the stat could be boosted, false otherwise
|
||||||
|
*/
|
||||||
|
// override shouldApply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean {
|
||||||
|
// return (
|
||||||
|
// super.shouldApply(pokemon, stat, statValue) &&
|
||||||
|
// (this.species.includes(pokemon.getSpeciesForm(true).speciesId) ||
|
||||||
|
// (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId)))
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
apply(params: STAT_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if either parameter is included in the corresponding lists
|
||||||
|
* @param speciesId {@linkcode SpeciesId} being checked
|
||||||
|
* @param stat {@linkcode Stat} being checked
|
||||||
|
* @returns `true` if both parameters are in {@linkcode species} and {@linkcode stats} respectively, false otherwise
|
||||||
|
*/
|
||||||
|
contains(speciesId: SpeciesId, stat: Stat): boolean {
|
||||||
|
return this.species.includes(speciesId) && this.stats.includes(stat);
|
||||||
|
}
|
||||||
|
}
|
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.phaseManager.queueMessage(
|
||||||
|
i18next.t("modifier:surviveDamageApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
typeName: this.name,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
36
src/items/held-items/turn-end-heal.ts
Normal file
36
src/items/held-items/turn-end-heal.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { HeldItem, ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
||||||
|
import { toDmgValue } from "#app/utils/common";
|
||||||
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
|
||||||
|
export interface TURN_END_HEAL_PARAMS {
|
||||||
|
/** The pokemon with the item */
|
||||||
|
pokemon: Pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnEndHealHeldItem extends HeldItem {
|
||||||
|
public effects: ITEM_EFFECT[] = [ITEM_EFFECT.TURN_END_HEAL];
|
||||||
|
|
||||||
|
apply(params: TURN_END_HEAL_PARAMS): boolean {
|
||||||
|
const pokemon = params.pokemon;
|
||||||
|
const stackCount = pokemon.heldItemManager.getStack(this.type);
|
||||||
|
if (pokemon.isFullHp()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
globalScene.phaseManager.unshiftPhase(
|
||||||
|
new PokemonHealPhase(
|
||||||
|
pokemon.getBattlerIndex(),
|
||||||
|
toDmgValue(pokemon.getMaxHp() / 16) * stackCount,
|
||||||
|
i18next.t("modifier:turnHealApply", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
|
typeName: this.name,
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
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;
|
||||||
|
}
|
||||||
|
}
|
80
src/items/init-held-item-pools.ts
Normal file
80
src/items/init-held-item-pools.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
|
import { dailyStarterHeldItemPool, trainerHeldItemPool, wildHeldItemPool } from "./held-item-pool";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the wild held item pool
|
||||||
|
*/
|
||||||
|
function initWildHeldItemPool() {
|
||||||
|
wildHeldItemPool[RewardTier.COMMON] = [{ entry: HeldItemCategoryId.BERRY, weight: 1 }];
|
||||||
|
wildHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 }];
|
||||||
|
wildHeldItemPool[RewardTier.ULTRA] = [
|
||||||
|
{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 },
|
||||||
|
{ entry: HeldItemId.WHITE_HERB, weight: 0 },
|
||||||
|
];
|
||||||
|
wildHeldItemPool[RewardTier.ROGUE] = [{ entry: HeldItemId.LUCKY_EGG, weight: 4 }];
|
||||||
|
wildHeldItemPool[RewardTier.MASTER] = [{ entry: HeldItemId.GOLDEN_EGG, weight: 1 }];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the trainer pokemon held item pool
|
||||||
|
*/
|
||||||
|
function initTrainerHeldItemPool() {
|
||||||
|
trainerHeldItemPool[RewardTier.COMMON] = [
|
||||||
|
{ entry: HeldItemCategoryId.BERRY, weight: 8 },
|
||||||
|
{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 3 },
|
||||||
|
];
|
||||||
|
trainerHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 3 }];
|
||||||
|
trainerHeldItemPool[RewardTier.ULTRA] = [
|
||||||
|
{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 10 },
|
||||||
|
{ entry: HeldItemId.WHITE_HERB, weight: 0 },
|
||||||
|
];
|
||||||
|
trainerHeldItemPool[RewardTier.ROGUE] = [
|
||||||
|
{ entry: HeldItemId.FOCUS_BAND, weight: 2 },
|
||||||
|
{ entry: HeldItemId.LUCKY_EGG, weight: 4 },
|
||||||
|
{ entry: HeldItemId.QUICK_CLAW, weight: 1 },
|
||||||
|
{ entry: HeldItemId.GRIP_CLAW, weight: 1 },
|
||||||
|
{ entry: HeldItemId.WIDE_LENS, weight: 1 },
|
||||||
|
];
|
||||||
|
trainerHeldItemPool[RewardTier.MASTER] = [
|
||||||
|
{ entry: HeldItemId.KINGS_ROCK, weight: 1 },
|
||||||
|
{ entry: HeldItemId.LEFTOVERS, weight: 1 },
|
||||||
|
{ entry: HeldItemId.SHELL_BELL, weight: 1 },
|
||||||
|
{ entry: HeldItemId.SCOPE_LENS, weight: 1 },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the daily starter held item pool
|
||||||
|
*/
|
||||||
|
function initDailyStarterModifierPool() {
|
||||||
|
dailyStarterHeldItemPool[RewardTier.COMMON] = [
|
||||||
|
{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 },
|
||||||
|
{ entry: HeldItemCategoryId.BERRY, weight: 3 },
|
||||||
|
];
|
||||||
|
dailyStarterHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 }];
|
||||||
|
dailyStarterHeldItemPool[RewardTier.ULTRA] = [
|
||||||
|
{ entry: HeldItemId.REVIVER_SEED, weight: 4 },
|
||||||
|
{ entry: HeldItemId.SOOTHE_BELL, weight: 1 },
|
||||||
|
{ entry: HeldItemId.SOUL_DEW, weight: 1 },
|
||||||
|
{ entry: HeldItemId.GOLDEN_PUNCH, weight: 1 },
|
||||||
|
];
|
||||||
|
dailyStarterHeldItemPool[RewardTier.ROGUE] = [
|
||||||
|
{ entry: HeldItemId.GRIP_CLAW, weight: 5 },
|
||||||
|
{ entry: HeldItemId.BATON, weight: 2 },
|
||||||
|
{ entry: HeldItemId.FOCUS_BAND, weight: 5 },
|
||||||
|
{ entry: HeldItemId.QUICK_CLAW, weight: 3 },
|
||||||
|
{ entry: HeldItemId.KINGS_ROCK, weight: 3 },
|
||||||
|
];
|
||||||
|
dailyStarterHeldItemPool[RewardTier.MASTER] = [
|
||||||
|
{ entry: HeldItemId.LEFTOVERS, weight: 1 },
|
||||||
|
{ entry: HeldItemId.SHELL_BELL, weight: 1 },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initHeldItemPools() {
|
||||||
|
// Default held item pools for specific scenarios
|
||||||
|
initWildHeldItemPool();
|
||||||
|
initTrainerHeldItemPool();
|
||||||
|
initDailyStarterModifierPool();
|
||||||
|
}
|
@ -21,8 +21,10 @@ import { initVouchers } from "#app/system/voucher";
|
|||||||
import { BiomeId } from "#enums/biome-id";
|
import { BiomeId } from "#enums/biome-id";
|
||||||
import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters";
|
import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
import { timedEventManager } from "./global-event-manager";
|
import { timedEventManager } from "./global-event-manager";
|
||||||
|
import { initHeldItems } from "./items/all-held-items";
|
||||||
import { initModifierPools } from "./modifier/init-modifier-pools";
|
import { initModifierPools } from "./modifier/init-modifier-pools";
|
||||||
import { initModifierTypes } from "./modifier/modifier-type";
|
import { initModifierTypes } from "./modifier/modifier-type";
|
||||||
|
import { initHeldItemPools } from "./items/init-held-item-pools";
|
||||||
|
|
||||||
export class LoadingScene extends SceneBase {
|
export class LoadingScene extends SceneBase {
|
||||||
public static readonly KEY = "loading";
|
public static readonly KEY = "loading";
|
||||||
@ -367,6 +369,7 @@ export class LoadingScene extends SceneBase {
|
|||||||
|
|
||||||
initModifierTypes();
|
initModifierTypes();
|
||||||
initModifierPools();
|
initModifierPools();
|
||||||
|
initHeldItemPools();
|
||||||
|
|
||||||
initAchievements();
|
initAchievements();
|
||||||
initVouchers();
|
initVouchers();
|
||||||
@ -380,6 +383,7 @@ export class LoadingScene extends SceneBase {
|
|||||||
initSpecies();
|
initSpecies();
|
||||||
initMoves();
|
initMoves();
|
||||||
initAbilities();
|
initAbilities();
|
||||||
|
initHeldItems();
|
||||||
initChallenges();
|
initChallenges();
|
||||||
initMysteryEncounters();
|
initMysteryEncounters();
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,12 @@
|
|||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import {
|
import { enemyBuffModifierPool, modifierPool } from "#app/modifier/modifier-pools";
|
||||||
dailyStarterModifierPool,
|
|
||||||
enemyBuffModifierPool,
|
|
||||||
modifierPool,
|
|
||||||
trainerModifierPool,
|
|
||||||
wildModifierPool,
|
|
||||||
} from "#app/modifier/modifier-pools";
|
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { DoubleBattleChanceBoosterModifier, SpeciesCritBoosterModifier, TurnStatusEffectModifier } from "./modifier";
|
import { DoubleBattleChanceBoosterModifier } from "./modifier";
|
||||||
import { WeightedModifierType } from "./modifier-type";
|
import { WeightedModifierType } from "./modifier-type";
|
||||||
import { ModifierTier } from "../enums/modifier-tier";
|
import { RewardTier } from "#app/enums/reward-tier";
|
||||||
import type { WeightedModifierTypeWeightFunc } from "#app/@types/modifier-types";
|
import type { WeightedModifierTypeWeightFunc } from "#app/@types/modifier-types";
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import { BerryModifier } from "./modifier";
|
|
||||||
import { BerryType } from "#enums/berry-type";
|
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
import { timedEventManager } from "#app/global-event-manager";
|
import { timedEventManager } from "#app/global-event-manager";
|
||||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||||
@ -26,41 +18,14 @@ import { AbilityId } from "#enums/ability-id";
|
|||||||
import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
|
import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
|
||||||
// biome-ignore lint/correctness/noUnusedImports: This is used in a tsdoc comment
|
// biome-ignore lint/correctness/noUnusedImports: This is used in a tsdoc comment
|
||||||
import type { initModifierTypes } from "./modifier-type";
|
import type { initModifierTypes } from "./modifier-type";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
/**
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
* Initialize the wild modifier pool
|
|
||||||
*/
|
|
||||||
function initWildModifierPool() {
|
|
||||||
wildModifierPool[ModifierTier.COMMON] = [new WeightedModifierType(modifierTypes.BERRY, 1)].map(m => {
|
|
||||||
m.setTier(ModifierTier.COMMON);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
wildModifierPool[ModifierTier.GREAT] = [new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 1)].map(m => {
|
|
||||||
m.setTier(ModifierTier.GREAT);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
wildModifierPool[ModifierTier.ULTRA] = [
|
|
||||||
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 10),
|
|
||||||
new WeightedModifierType(modifierTypes.WHITE_HERB, 0),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.ULTRA);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
wildModifierPool[ModifierTier.ROGUE] = [new WeightedModifierType(modifierTypes.LUCKY_EGG, 4)].map(m => {
|
|
||||||
m.setTier(ModifierTier.ROGUE);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
wildModifierPool[ModifierTier.MASTER] = [new WeightedModifierType(modifierTypes.GOLDEN_EGG, 1)].map(m => {
|
|
||||||
m.setTier(ModifierTier.MASTER);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the common modifier pool
|
* Initialize the common modifier pool
|
||||||
*/
|
*/
|
||||||
function initCommonModifierPool() {
|
function initCommonModifierPool() {
|
||||||
modifierPool[ModifierTier.COMMON] = [
|
modifierPool[RewardTier.COMMON] = [
|
||||||
new WeightedModifierType(modifierTypes.POKEBALL, () => (hasMaximumBalls(PokeballType.POKEBALL) ? 0 : 6), 6),
|
new WeightedModifierType(modifierTypes.POKEBALL, () => (hasMaximumBalls(PokeballType.POKEBALL) ? 0 : 6), 6),
|
||||||
new WeightedModifierType(modifierTypes.RARE_CANDY, 2),
|
new WeightedModifierType(modifierTypes.RARE_CANDY, 2),
|
||||||
new WeightedModifierType(
|
new WeightedModifierType(
|
||||||
@ -92,7 +57,7 @@ function initCommonModifierPool() {
|
|||||||
party.filter(
|
party.filter(
|
||||||
p =>
|
p =>
|
||||||
p.hp &&
|
p.hp &&
|
||||||
!p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
|
!p.heldItemManager.hasItem(HeldItemId.LEPPA_BERRY) &&
|
||||||
p
|
p
|
||||||
.getMoveset()
|
.getMoveset()
|
||||||
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
||||||
@ -111,7 +76,7 @@ function initCommonModifierPool() {
|
|||||||
party.filter(
|
party.filter(
|
||||||
p =>
|
p =>
|
||||||
p.hp &&
|
p.hp &&
|
||||||
!p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
|
!p.heldItemManager.hasItem(HeldItemId.LEPPA_BERRY) &&
|
||||||
p
|
p
|
||||||
.getMoveset()
|
.getMoveset()
|
||||||
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
||||||
@ -128,7 +93,7 @@ function initCommonModifierPool() {
|
|||||||
new WeightedModifierType(modifierTypes.BERRY, 2),
|
new WeightedModifierType(modifierTypes.BERRY, 2),
|
||||||
new WeightedModifierType(modifierTypes.TM_COMMON, 2),
|
new WeightedModifierType(modifierTypes.TM_COMMON, 2),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.COMMON);
|
m.setTier(RewardTier.COMMON);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -137,7 +102,7 @@ function initCommonModifierPool() {
|
|||||||
* Initialize the Great modifier pool
|
* Initialize the Great modifier pool
|
||||||
*/
|
*/
|
||||||
function initGreatModifierPool() {
|
function initGreatModifierPool() {
|
||||||
modifierPool[ModifierTier.GREAT] = [
|
modifierPool[RewardTier.GREAT] = [
|
||||||
new WeightedModifierType(modifierTypes.GREAT_BALL, () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), 6),
|
new WeightedModifierType(modifierTypes.GREAT_BALL, () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), 6),
|
||||||
new WeightedModifierType(modifierTypes.PP_UP, 2),
|
new WeightedModifierType(modifierTypes.PP_UP, 2),
|
||||||
new WeightedModifierType(
|
new WeightedModifierType(
|
||||||
@ -148,12 +113,10 @@ function initGreatModifierPool() {
|
|||||||
p =>
|
p =>
|
||||||
p.hp &&
|
p.hp &&
|
||||||
!!p.status &&
|
!!p.status &&
|
||||||
!p.getHeldItems().some(i => {
|
!p
|
||||||
if (i instanceof TurnStatusEffectModifier) {
|
.getHeldItems()
|
||||||
return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect;
|
.filter(i => i in [HeldItemId.TOXIC_ORB, HeldItemId.FLAME_ORB])
|
||||||
}
|
.some(i => allHeldItems[i].effect === p.status?.effect),
|
||||||
return false;
|
|
||||||
}),
|
|
||||||
).length,
|
).length,
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
@ -214,12 +177,10 @@ function initGreatModifierPool() {
|
|||||||
p =>
|
p =>
|
||||||
p.hp &&
|
p.hp &&
|
||||||
!!p.status &&
|
!!p.status &&
|
||||||
!p.getHeldItems().some(i => {
|
!p
|
||||||
if (i instanceof TurnStatusEffectModifier) {
|
.getHeldItems()
|
||||||
return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect;
|
.filter(i => i in [HeldItemId.TOXIC_ORB, HeldItemId.FLAME_ORB])
|
||||||
}
|
.some(i => allHeldItems[i].effect === p.status?.effect),
|
||||||
return false;
|
|
||||||
}),
|
|
||||||
).length,
|
).length,
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
@ -239,7 +200,7 @@ function initGreatModifierPool() {
|
|||||||
party.filter(
|
party.filter(
|
||||||
p =>
|
p =>
|
||||||
p.hp &&
|
p.hp &&
|
||||||
!p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
|
!p.heldItemManager.hasItem(HeldItemId.LEPPA_BERRY) &&
|
||||||
p
|
p
|
||||||
.getMoveset()
|
.getMoveset()
|
||||||
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
||||||
@ -258,7 +219,7 @@ function initGreatModifierPool() {
|
|||||||
party.filter(
|
party.filter(
|
||||||
p =>
|
p =>
|
||||||
p.hp &&
|
p.hp &&
|
||||||
!p.getHeldItems().some(m => m instanceof BerryModifier && m.berryType === BerryType.LEPPA) &&
|
!p.heldItemManager.hasItem(HeldItemId.LEPPA_BERRY) &&
|
||||||
p
|
p
|
||||||
.getMoveset()
|
.getMoveset()
|
||||||
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
.filter(m => m.ppUsed && m.getMovePp() - m.ppUsed <= 5 && m.ppUsed > Math.floor(m.getMovePp() / 2))
|
||||||
@ -331,7 +292,7 @@ function initGreatModifierPool() {
|
|||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.GREAT);
|
m.setTier(RewardTier.GREAT);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -340,7 +301,7 @@ function initGreatModifierPool() {
|
|||||||
* Initialize the Ultra modifier pool
|
* Initialize the Ultra modifier pool
|
||||||
*/
|
*/
|
||||||
function initUltraModifierPool() {
|
function initUltraModifierPool() {
|
||||||
modifierPool[ModifierTier.ULTRA] = [
|
modifierPool[RewardTier.ULTRA] = [
|
||||||
new WeightedModifierType(modifierTypes.ULTRA_BALL, () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), 15),
|
new WeightedModifierType(modifierTypes.ULTRA_BALL, () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), 15),
|
||||||
new WeightedModifierType(modifierTypes.MAX_LURE, lureWeightFunc(30, 4)),
|
new WeightedModifierType(modifierTypes.MAX_LURE, lureWeightFunc(30, 4)),
|
||||||
new WeightedModifierType(modifierTypes.BIG_NUGGET, skipInLastClassicWaveOrDefault(12)),
|
new WeightedModifierType(modifierTypes.BIG_NUGGET, skipInLastClassicWaveOrDefault(12)),
|
||||||
@ -368,7 +329,7 @@ function initUltraModifierPool() {
|
|||||||
(p.isFusion() && p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))
|
(p.isFusion() && p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))
|
||||||
) {
|
) {
|
||||||
// Check if Pokemon is already holding an Eviolite
|
// Check if Pokemon is already holding an Eviolite
|
||||||
return !p.getHeldItems().some(i => i.type.id === "EVIOLITE");
|
return !p.heldItemManager.hasItem(HeldItemId.EVIOLITE);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
@ -385,7 +346,7 @@ function initUltraModifierPool() {
|
|||||||
// If a party member doesn't already have a Leek and is one of the relevant species, Leek can appear
|
// If a party member doesn't already have a Leek and is one of the relevant species, Leek can appear
|
||||||
return party.some(
|
return party.some(
|
||||||
p =>
|
p =>
|
||||||
!p.getHeldItems().some(i => i instanceof SpeciesCritBoosterModifier) &&
|
!p.heldItemManager.hasItem(HeldItemId.LEEK) &&
|
||||||
(checkedSpecies.includes(p.getSpeciesForm(true).speciesId) ||
|
(checkedSpecies.includes(p.getSpeciesForm(true).speciesId) ||
|
||||||
(p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId))),
|
(p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId))),
|
||||||
)
|
)
|
||||||
@ -398,7 +359,7 @@ function initUltraModifierPool() {
|
|||||||
modifierTypes.TOXIC_ORB,
|
modifierTypes.TOXIC_ORB,
|
||||||
(party: Pokemon[]) => {
|
(party: Pokemon[]) => {
|
||||||
return party.some(p => {
|
return party.some(p => {
|
||||||
const isHoldingOrb = p.getHeldItems().some(i => i.type.id === "FLAME_ORB" || i.type.id === "TOXIC_ORB");
|
const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]);
|
||||||
|
|
||||||
if (!isHoldingOrb) {
|
if (!isHoldingOrb) {
|
||||||
const moveset = p
|
const moveset = p
|
||||||
@ -444,7 +405,7 @@ function initUltraModifierPool() {
|
|||||||
modifierTypes.FLAME_ORB,
|
modifierTypes.FLAME_ORB,
|
||||||
(party: Pokemon[]) => {
|
(party: Pokemon[]) => {
|
||||||
return party.some(p => {
|
return party.some(p => {
|
||||||
const isHoldingOrb = p.getHeldItems().some(i => i.type.id === "FLAME_ORB" || i.type.id === "TOXIC_ORB");
|
const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]);
|
||||||
|
|
||||||
if (!isHoldingOrb) {
|
if (!isHoldingOrb) {
|
||||||
const moveset = p
|
const moveset = p
|
||||||
@ -490,13 +451,8 @@ function initUltraModifierPool() {
|
|||||||
modifierTypes.MYSTICAL_ROCK,
|
modifierTypes.MYSTICAL_ROCK,
|
||||||
(party: Pokemon[]) => {
|
(party: Pokemon[]) => {
|
||||||
return party.some(p => {
|
return party.some(p => {
|
||||||
let isHoldingMax = false;
|
const stack = p.heldItemManager.getStack(HeldItemId.MYSTICAL_ROCK);
|
||||||
for (const i of p.getHeldItems()) {
|
const isHoldingMax = stack === allHeldItems[HeldItemId.MYSTICAL_ROCK].maxStackCount;
|
||||||
if (i.type.id === "MYSTICAL_ROCK") {
|
|
||||||
isHoldingMax = i.getStackCount() === i.getMaxStackCount();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isHoldingMax) {
|
if (!isHoldingMax) {
|
||||||
const moveset = p.getMoveset(true).map(m => m.moveId);
|
const moveset = p.getMoveset(true).map(m => m.moveId);
|
||||||
@ -558,13 +514,13 @@ function initUltraModifierPool() {
|
|||||||
new WeightedModifierType(modifierTypes.QUICK_CLAW, 3),
|
new WeightedModifierType(modifierTypes.QUICK_CLAW, 3),
|
||||||
new WeightedModifierType(modifierTypes.WIDE_LENS, 7),
|
new WeightedModifierType(modifierTypes.WIDE_LENS, 7),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.ULTRA);
|
m.setTier(RewardTier.ULTRA);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initRogueModifierPool() {
|
function initRogueModifierPool() {
|
||||||
modifierPool[ModifierTier.ROGUE] = [
|
modifierPool[RewardTier.ROGUE] = [
|
||||||
new WeightedModifierType(modifierTypes.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16),
|
new WeightedModifierType(modifierTypes.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16),
|
||||||
new WeightedModifierType(modifierTypes.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)),
|
new WeightedModifierType(modifierTypes.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)),
|
||||||
new WeightedModifierType(modifierTypes.LEFTOVERS, 3),
|
new WeightedModifierType(modifierTypes.LEFTOVERS, 3),
|
||||||
@ -602,7 +558,7 @@ function initRogueModifierPool() {
|
|||||||
3,
|
3,
|
||||||
),
|
),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.ROGUE);
|
m.setTier(RewardTier.ROGUE);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -611,7 +567,7 @@ function initRogueModifierPool() {
|
|||||||
* Initialize the Master modifier pool
|
* Initialize the Master modifier pool
|
||||||
*/
|
*/
|
||||||
function initMasterModifierPool() {
|
function initMasterModifierPool() {
|
||||||
modifierPool[ModifierTier.MASTER] = [
|
modifierPool[RewardTier.MASTER] = [
|
||||||
new WeightedModifierType(modifierTypes.MASTER_BALL, () => (hasMaximumBalls(PokeballType.MASTER_BALL) ? 0 : 24), 24),
|
new WeightedModifierType(modifierTypes.MASTER_BALL, () => (hasMaximumBalls(PokeballType.MASTER_BALL) ? 0 : 24), 24),
|
||||||
new WeightedModifierType(modifierTypes.SHINY_CHARM, 14),
|
new WeightedModifierType(modifierTypes.SHINY_CHARM, 14),
|
||||||
new WeightedModifierType(modifierTypes.HEALING_CHARM, 18),
|
new WeightedModifierType(modifierTypes.HEALING_CHARM, 18),
|
||||||
@ -644,47 +600,7 @@ function initMasterModifierPool() {
|
|||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.MASTER);
|
m.setTier(RewardTier.MASTER);
|
||||||
return m;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initTrainerModifierPool() {
|
|
||||||
trainerModifierPool[ModifierTier.COMMON] = [
|
|
||||||
new WeightedModifierType(modifierTypes.BERRY, 8),
|
|
||||||
new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.COMMON);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
trainerModifierPool[ModifierTier.GREAT] = [new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3)].map(m => {
|
|
||||||
m.setTier(ModifierTier.GREAT);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
trainerModifierPool[ModifierTier.ULTRA] = [
|
|
||||||
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 10),
|
|
||||||
new WeightedModifierType(modifierTypes.WHITE_HERB, 0),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.ULTRA);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
trainerModifierPool[ModifierTier.ROGUE] = [
|
|
||||||
new WeightedModifierType(modifierTypes.FOCUS_BAND, 2),
|
|
||||||
new WeightedModifierType(modifierTypes.LUCKY_EGG, 4),
|
|
||||||
new WeightedModifierType(modifierTypes.QUICK_CLAW, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.GRIP_CLAW, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.WIDE_LENS, 1),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.ROGUE);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
trainerModifierPool[ModifierTier.MASTER] = [
|
|
||||||
new WeightedModifierType(modifierTypes.KINGS_ROCK, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.LEFTOVERS, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.SHELL_BELL, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.SCOPE_LENS, 1),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.MASTER);
|
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -693,7 +609,7 @@ function initTrainerModifierPool() {
|
|||||||
* Initialize the enemy buff modifier pool
|
* Initialize the enemy buff modifier pool
|
||||||
*/
|
*/
|
||||||
function initEnemyBuffModifierPool() {
|
function initEnemyBuffModifierPool() {
|
||||||
enemyBuffModifierPool[ModifierTier.COMMON] = [
|
enemyBuffModifierPool[RewardTier.COMMON] = [
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 9),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 9),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 9),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 9),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_POISON_CHANCE, 3),
|
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_POISON_CHANCE, 3),
|
||||||
@ -703,20 +619,20 @@ function initEnemyBuffModifierPool() {
|
|||||||
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 4),
|
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 4),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1),
|
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.COMMON);
|
m.setTier(RewardTier.COMMON);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
enemyBuffModifierPool[ModifierTier.GREAT] = [
|
enemyBuffModifierPool[RewardTier.GREAT] = [
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 5),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 5),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 5),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 5),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1),
|
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.GREAT);
|
m.setTier(RewardTier.GREAT);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
enemyBuffModifierPool[ModifierTier.ULTRA] = [
|
enemyBuffModifierPool[RewardTier.ULTRA] = [
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 10),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 10),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_HEAL, 10),
|
new WeightedModifierType(modifierTypes.ENEMY_HEAL, 10),
|
||||||
@ -724,60 +640,15 @@ function initEnemyBuffModifierPool() {
|
|||||||
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 10),
|
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 5),
|
||||||
].map(m => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.ULTRA);
|
m.setTier(RewardTier.ULTRA);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
enemyBuffModifierPool[ModifierTier.ROGUE] = [].map((m: WeightedModifierType) => {
|
enemyBuffModifierPool[RewardTier.ROGUE] = [].map((m: WeightedModifierType) => {
|
||||||
m.setTier(ModifierTier.ROGUE);
|
m.setTier(RewardTier.ROGUE);
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
enemyBuffModifierPool[ModifierTier.MASTER] = [].map((m: WeightedModifierType) => {
|
enemyBuffModifierPool[RewardTier.MASTER] = [].map((m: WeightedModifierType) => {
|
||||||
m.setTier(ModifierTier.MASTER);
|
m.setTier(RewardTier.MASTER);
|
||||||
return m;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the daily starter modifier pool
|
|
||||||
*/
|
|
||||||
function initDailyStarterModifierPool() {
|
|
||||||
dailyStarterModifierPool[ModifierTier.COMMON] = [
|
|
||||||
new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.BERRY, 3),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.COMMON);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
dailyStarterModifierPool[ModifierTier.GREAT] = [new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 5)].map(
|
|
||||||
m => {
|
|
||||||
m.setTier(ModifierTier.GREAT);
|
|
||||||
return m;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
dailyStarterModifierPool[ModifierTier.ULTRA] = [
|
|
||||||
new WeightedModifierType(modifierTypes.REVIVER_SEED, 4),
|
|
||||||
new WeightedModifierType(modifierTypes.SOOTHE_BELL, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.SOUL_DEW, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.GOLDEN_PUNCH, 1),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.ULTRA);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
dailyStarterModifierPool[ModifierTier.ROGUE] = [
|
|
||||||
new WeightedModifierType(modifierTypes.GRIP_CLAW, 5),
|
|
||||||
new WeightedModifierType(modifierTypes.BATON, 2),
|
|
||||||
new WeightedModifierType(modifierTypes.FOCUS_BAND, 5),
|
|
||||||
new WeightedModifierType(modifierTypes.QUICK_CLAW, 3),
|
|
||||||
new WeightedModifierType(modifierTypes.KINGS_ROCK, 3),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.ROGUE);
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
dailyStarterModifierPool[ModifierTier.MASTER] = [
|
|
||||||
new WeightedModifierType(modifierTypes.LEFTOVERS, 1),
|
|
||||||
new WeightedModifierType(modifierTypes.SHELL_BELL, 1),
|
|
||||||
].map(m => {
|
|
||||||
m.setTier(ModifierTier.MASTER);
|
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -795,10 +666,7 @@ export function initModifierPools() {
|
|||||||
initMasterModifierPool();
|
initMasterModifierPool();
|
||||||
|
|
||||||
// Modifier pools for specific scenarios
|
// Modifier pools for specific scenarios
|
||||||
initWildModifierPool();
|
|
||||||
initTrainerModifierPool();
|
|
||||||
initEnemyBuffModifierPool();
|
initEnemyBuffModifierPool();
|
||||||
initDailyStarterModifierPool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
137
src/modifier/modifier-bar.ts
Normal file
137
src/modifier/modifier-bar.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import { formChangeItemName } from "#app/data/pokemon-forms";
|
||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
import type { FormChangeItem } from "#enums/form-change-item";
|
||||||
|
import type { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import type { Modifier, PersistentModifier } from "./modifier";
|
||||||
|
|
||||||
|
const iconOverflowIndex = 24;
|
||||||
|
|
||||||
|
export const modifierSortFunc = (a: Modifier, b: Modifier): number => {
|
||||||
|
const itemNameMatch = a.type.name.localeCompare(b.type.name);
|
||||||
|
const typeNameMatch = a.constructor.name.localeCompare(b.constructor.name);
|
||||||
|
|
||||||
|
//Then sort by item type
|
||||||
|
if (typeNameMatch === 0) {
|
||||||
|
return itemNameMatch;
|
||||||
|
//Finally sort by item name
|
||||||
|
}
|
||||||
|
return typeNameMatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO: revisit this function
|
||||||
|
export const heldItemSortFunc = (a: HeldItemId, b: HeldItemId): number => {
|
||||||
|
const itemNameMatch = allHeldItems[a].name.localeCompare(allHeldItems[b].name);
|
||||||
|
const itemIdMatch = a - b;
|
||||||
|
|
||||||
|
if (itemIdMatch === 0) {
|
||||||
|
return itemNameMatch;
|
||||||
|
//Finally sort by item name
|
||||||
|
}
|
||||||
|
return itemIdMatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const formChangeItemSortFunc = (a: FormChangeItem, b: FormChangeItem): number => {
|
||||||
|
const nameA = formChangeItemName(a);
|
||||||
|
const nameB = formChangeItemName(b);
|
||||||
|
const itemNameMatch = nameA.localeCompare(nameB);
|
||||||
|
const itemIdMatch = a - b;
|
||||||
|
|
||||||
|
if (itemIdMatch === 0) {
|
||||||
|
return itemNameMatch;
|
||||||
|
//Finally sort by item name
|
||||||
|
}
|
||||||
|
return itemIdMatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ModifierBar extends Phaser.GameObjects.Container {
|
||||||
|
private player: boolean;
|
||||||
|
private modifierCache: (PersistentModifier | HeldItemId)[];
|
||||||
|
public totalVisibleLength = 0;
|
||||||
|
|
||||||
|
constructor(enemy?: boolean) {
|
||||||
|
super(globalScene, 1 + (enemy ? 302 : 0), 2);
|
||||||
|
|
||||||
|
this.player = !enemy;
|
||||||
|
this.setScale(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to update content displayed in {@linkcode ModifierBar}
|
||||||
|
* @param {PersistentModifier[]} modifiers - The list of modifiers to be displayed in the {@linkcode ModifierBar}
|
||||||
|
* @param {boolean} hideHeldItems - If set to "true", only modifiers not assigned to a Pokémon are displayed
|
||||||
|
*/
|
||||||
|
updateModifiers(modifiers: PersistentModifier[], pokemonA?: Pokemon, pokemonB?: Pokemon) {
|
||||||
|
this.removeAll(true);
|
||||||
|
|
||||||
|
const sortedVisibleModifiers = modifiers.filter(m => m.isIconVisible()).sort(modifierSortFunc);
|
||||||
|
|
||||||
|
const heldItemsA = pokemonA ? pokemonA.getHeldItems().sort(heldItemSortFunc) : [];
|
||||||
|
const heldItemsB = pokemonB ? pokemonB.getHeldItems().sort(heldItemSortFunc) : [];
|
||||||
|
|
||||||
|
this.totalVisibleLength = sortedVisibleModifiers.length + heldItemsA.length + heldItemsB.length;
|
||||||
|
|
||||||
|
let iconCount = 0;
|
||||||
|
sortedVisibleModifiers.forEach(modifier => {
|
||||||
|
const icon = modifier.getIcon();
|
||||||
|
iconCount += 1;
|
||||||
|
this.addIcon(icon, iconCount, modifier.type.name, modifier.type.getDescription());
|
||||||
|
});
|
||||||
|
|
||||||
|
heldItemsA.forEach(item => {
|
||||||
|
const icon = allHeldItems[item].createPokemonIcon(pokemonA);
|
||||||
|
iconCount += 1;
|
||||||
|
this.addIcon(icon, iconCount, allHeldItems[item].name, allHeldItems[item].description);
|
||||||
|
});
|
||||||
|
|
||||||
|
heldItemsB.forEach(item => {
|
||||||
|
const icon = allHeldItems[item].createPokemonIcon(pokemonB);
|
||||||
|
iconCount += 1;
|
||||||
|
this.addIcon(icon, iconCount, allHeldItems[item].name, allHeldItems[item].description);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const icon of this.getAll()) {
|
||||||
|
this.sendToBack(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.modifierCache = (modifiers as (PersistentModifier | HeldItemId)[]).concat(heldItemsA).concat(heldItemsB);
|
||||||
|
}
|
||||||
|
|
||||||
|
addIcon(icon: Phaser.GameObjects.Container, i: number, name: string, description: string) {
|
||||||
|
if (i >= iconOverflowIndex) {
|
||||||
|
icon.setVisible(false);
|
||||||
|
}
|
||||||
|
this.add(icon);
|
||||||
|
this.setModifierIconPosition(icon, this.totalVisibleLength);
|
||||||
|
icon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 32, 24), Phaser.Geom.Rectangle.Contains);
|
||||||
|
icon.on("pointerover", () => {
|
||||||
|
globalScene.ui.showTooltip(name, description);
|
||||||
|
if (this.modifierCache && this.modifierCache.length > iconOverflowIndex) {
|
||||||
|
this.updateModifierOverflowVisibility(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
icon.on("pointerout", () => {
|
||||||
|
globalScene.ui.hideTooltip();
|
||||||
|
if (this.modifierCache && this.modifierCache.length > iconOverflowIndex) {
|
||||||
|
this.updateModifierOverflowVisibility(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateModifierOverflowVisibility(ignoreLimit: boolean) {
|
||||||
|
const modifierIcons = this.getAll().reverse();
|
||||||
|
for (const modifier of modifierIcons.map(m => m as Phaser.GameObjects.Container).slice(iconOverflowIndex)) {
|
||||||
|
modifier.setVisible(ignoreLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setModifierIconPosition(icon: Phaser.GameObjects.Container, modifierCount: number) {
|
||||||
|
const rowIcons: number = 12 + 6 * Math.max(Math.ceil(Math.min(modifierCount, 24) / 12) - 2, 0);
|
||||||
|
|
||||||
|
const x = ((this.getIndex(icon) % rowIcons) * 26) / (rowIcons / 12);
|
||||||
|
const y = Math.floor(this.getIndex(icon) / rowIcons) * 20;
|
||||||
|
|
||||||
|
icon.setPosition(this.player ? x : -x, y);
|
||||||
|
}
|
||||||
|
}
|
@ -7,10 +7,6 @@ import type { ModifierPool } from "#app/@types/modifier-types";
|
|||||||
|
|
||||||
export const modifierPool: ModifierPool = {};
|
export const modifierPool: ModifierPool = {};
|
||||||
|
|
||||||
export const wildModifierPool: ModifierPool = {};
|
|
||||||
|
|
||||||
export const trainerModifierPool: ModifierPool = {};
|
|
||||||
|
|
||||||
export const enemyBuffModifierPool: ModifierPool = {};
|
export const enemyBuffModifierPool: ModifierPool = {};
|
||||||
|
|
||||||
export const dailyStarterModifierPool: ModifierPool = {};
|
export const dailyStarterModifierPool: ModifierPool = {};
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,7 @@ import { TimeOfDay } from "#enums/time-of-day";
|
|||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import { VariantTier } from "#enums/variant-tier";
|
import { VariantTier } from "#enums/variant-tier";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
|
import { HeldItemConfiguration } from "./items/held-item-data-types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This comment block exists to prevent IDEs from automatically removing unused imports
|
* This comment block exists to prevent IDEs from automatically removing unused imports
|
||||||
@ -255,9 +256,9 @@ class DefaultOverrides {
|
|||||||
readonly OPP_MODIFIER_OVERRIDE: ModifierOverride[] = [];
|
readonly OPP_MODIFIER_OVERRIDE: ModifierOverride[] = [];
|
||||||
|
|
||||||
/** Override array of {@linkcode ModifierOverride}s used to provide held items to first party member when starting a new game. */
|
/** Override array of {@linkcode ModifierOverride}s used to provide held items to first party member when starting a new game. */
|
||||||
readonly STARTING_HELD_ITEMS_OVERRIDE: ModifierOverride[] = [];
|
readonly STARTING_HELD_ITEMS_OVERRIDE: HeldItemConfiguration = [];
|
||||||
/** Override array of {@linkcode ModifierOverride}s used to provide held items to enemies on spawn. */
|
/** Override array of {@linkcode ModifierOverride}s used to provide held items to enemies on spawn. */
|
||||||
readonly OPP_HELD_ITEMS_OVERRIDE: ModifierOverride[] = [];
|
readonly OPP_HELD_ITEMS_OVERRIDE: HeldItemConfiguration = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override array of {@linkcode ModifierOverride}s used to replace the generated item rolls after a wave.
|
* Override array of {@linkcode ModifierOverride}s used to replace the generated item rolls after a wave.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { RewardTier } from "#enums/reward-tier";
|
||||||
import { regenerateModifierPoolThresholds, getEnemyBuffModifierForWave } from "#app/modifier/modifier-type";
|
import { regenerateModifierPoolThresholds, getEnemyBuffModifierForWave } from "#app/modifier/modifier-type";
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
||||||
import { EnemyPersistentModifier } from "#app/modifier/modifier";
|
import { EnemyPersistentModifier } from "#app/modifier/modifier";
|
||||||
@ -11,11 +11,7 @@ export class AddEnemyBuffModifierPhase extends Phase {
|
|||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
const waveIndex = globalScene.currentBattle.waveIndex;
|
const waveIndex = globalScene.currentBattle.waveIndex;
|
||||||
const tier = !(waveIndex % 1000)
|
const tier = !(waveIndex % 1000) ? RewardTier.ULTRA : !(waveIndex % 250) ? RewardTier.GREAT : RewardTier.COMMON;
|
||||||
? ModifierTier.ULTRA
|
|
||||||
: !(waveIndex % 250)
|
|
||||||
? ModifierTier.GREAT
|
|
||||||
: ModifierTier.COMMON;
|
|
||||||
|
|
||||||
regenerateModifierPoolThresholds(globalScene.getEnemyParty(), ModifierPoolType.ENEMY_BUFF);
|
regenerateModifierPoolThresholds(globalScene.getEnemyParty(), ModifierPoolType.ENEMY_BUFF);
|
||||||
|
|
||||||
@ -27,10 +23,9 @@ export class AddEnemyBuffModifierPhase extends Phase {
|
|||||||
globalScene.findModifiers(m => m instanceof EnemyPersistentModifier, false),
|
globalScene.findModifiers(m => m instanceof EnemyPersistentModifier, false),
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
globalScene.updateModifiers(false, true);
|
globalScene.updateModifiers(false);
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
|
|||||||
import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims";
|
import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims";
|
||||||
import type { EnemyPokemon } from "#app/field/pokemon";
|
import type { EnemyPokemon } from "#app/field/pokemon";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { PokemonPhase } from "#app/phases/pokemon-phase";
|
import { PokemonPhase } from "#app/phases/pokemon-phase";
|
||||||
import { achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv";
|
||||||
import type { PartyOption } from "#app/ui/party-ui-handler";
|
import type { PartyOption } from "#app/ui/party-ui-handler";
|
||||||
@ -255,6 +254,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
|||||||
}),
|
}),
|
||||||
null,
|
null,
|
||||||
() => {
|
() => {
|
||||||
|
const heldItemConfig = pokemon.heldItemManager.generateHeldItemConfiguration();
|
||||||
const end = () => {
|
const end = () => {
|
||||||
globalScene.phaseManager.unshiftNew("VictoryPhase", this.battlerIndex);
|
globalScene.phaseManager.unshiftNew("VictoryPhase", this.battlerIndex);
|
||||||
globalScene.pokemonInfoContainer.hide();
|
globalScene.pokemonInfoContainer.hide();
|
||||||
@ -265,24 +265,20 @@ export class AttemptCapturePhase extends PokemonPhase {
|
|||||||
globalScene.addFaintedEnemyScore(pokemon);
|
globalScene.addFaintedEnemyScore(pokemon);
|
||||||
pokemon.hp = 0;
|
pokemon.hp = 0;
|
||||||
pokemon.trySetStatus(StatusEffect.FAINT);
|
pokemon.trySetStatus(StatusEffect.FAINT);
|
||||||
globalScene.clearEnemyHeldItemModifiers();
|
|
||||||
pokemon.leaveField(true, true, true);
|
pokemon.leaveField(true, true, true);
|
||||||
};
|
};
|
||||||
const addToParty = (slotIndex?: number) => {
|
const addToParty = (slotIndex?: number) => {
|
||||||
const newPokemon = pokemon.addToParty(this.pokeballType, slotIndex);
|
const newPokemon = pokemon.addToParty(this.pokeballType, slotIndex);
|
||||||
const modifiers = globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier, false);
|
|
||||||
if (globalScene.getPlayerParty().filter(p => p.isShiny()).length === PLAYER_PARTY_MAX_SIZE) {
|
if (globalScene.getPlayerParty().filter(p => p.isShiny()).length === PLAYER_PARTY_MAX_SIZE) {
|
||||||
globalScene.validateAchv(achvs.SHINY_PARTY);
|
globalScene.validateAchv(achvs.SHINY_PARTY);
|
||||||
}
|
}
|
||||||
Promise.all(modifiers.map(m => globalScene.addModifier(m, true))).then(() => {
|
globalScene.updateModifiers(true);
|
||||||
globalScene.updateModifiers(true);
|
removePokemon();
|
||||||
removePokemon();
|
if (newPokemon) {
|
||||||
if (newPokemon) {
|
newPokemon.loadAssets().then(end);
|
||||||
newPokemon.loadAssets().then(end);
|
} else {
|
||||||
} else {
|
end();
|
||||||
end();
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
Promise.all([pokemon.hideInfo(), globalScene.gameData.setPokemonCaught(pokemon)]).then(() => {
|
Promise.all([pokemon.hideInfo(), globalScene.gameData.setPokemonCaught(pokemon)]).then(() => {
|
||||||
if (globalScene.getPlayerParty().length === PLAYER_PARTY_MAX_SIZE) {
|
if (globalScene.getPlayerParty().length === PLAYER_PARTY_MAX_SIZE) {
|
||||||
@ -307,6 +303,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
|||||||
pokemon.variant,
|
pokemon.variant,
|
||||||
pokemon.ivs,
|
pokemon.ivs,
|
||||||
pokemon.nature,
|
pokemon.nature,
|
||||||
|
heldItemConfig,
|
||||||
pokemon,
|
pokemon,
|
||||||
);
|
);
|
||||||
globalScene.ui.setMode(
|
globalScene.ui.setMode(
|
||||||
|
@ -43,8 +43,6 @@ export class AttemptRunPhase extends PokemonPhase {
|
|||||||
enemyField.forEach(enemyPokemon => enemyPokemon.destroy()),
|
enemyField.forEach(enemyPokemon => enemyPokemon.destroy()),
|
||||||
});
|
});
|
||||||
|
|
||||||
globalScene.clearEnemyHeldItemModifiers();
|
|
||||||
|
|
||||||
// biome-ignore lint/complexity/noForEach: TODO
|
// biome-ignore lint/complexity/noForEach: TODO
|
||||||
enemyField.forEach(enemyPokemon => {
|
enemyField.forEach(enemyPokemon => {
|
||||||
enemyPokemon.hideInfo().then(() => enemyPokemon.destroy());
|
enemyPokemon.hideInfo().then(() => enemyPokemon.destroy());
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { applyPostBattleAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
import { applyPostBattleAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
import { LapsingPersistentModifier, LapsingPokemonHeldItemModifier } from "#app/modifier/modifier";
|
import { LapsingPersistentModifier } from "#app/modifier/modifier";
|
||||||
import { BattlePhase } from "./battle-phase";
|
import { BattlePhase } from "./battle-phase";
|
||||||
|
|
||||||
export class BattleEndPhase extends BattlePhase {
|
export class BattleEndPhase extends BattlePhase {
|
||||||
@ -72,7 +72,6 @@ export class BattleEndPhase extends BattlePhase {
|
|||||||
globalScene.currentBattle.pickUpScatteredMoney();
|
globalScene.currentBattle.pickUpScatteredMoney();
|
||||||
}
|
}
|
||||||
|
|
||||||
globalScene.clearEnemyHeldItemModifiers();
|
|
||||||
for (const p of globalScene.getEnemyParty()) {
|
for (const p of globalScene.getEnemyParty()) {
|
||||||
try {
|
try {
|
||||||
p.destroy();
|
p.destroy();
|
||||||
@ -82,13 +81,10 @@ export class BattleEndPhase extends BattlePhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lapsingModifiers = globalScene.findModifiers(
|
const lapsingModifiers = globalScene.findModifiers(
|
||||||
m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier,
|
m => m instanceof LapsingPersistentModifier,
|
||||||
) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[];
|
) as LapsingPersistentModifier[];
|
||||||
for (const m of lapsingModifiers) {
|
for (const m of lapsingModifiers) {
|
||||||
const args: any[] = [];
|
const args: any[] = [];
|
||||||
if (m instanceof LapsingPokemonHeldItemModifier) {
|
|
||||||
args.push(globalScene.getPokemonById(m.pokemonId));
|
|
||||||
}
|
|
||||||
if (!m.lapse(...args)) {
|
if (!m.lapse(...args)) {
|
||||||
globalScene.removeModifier(m);
|
globalScene.removeModifier(m);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
import { CommonAnim } from "#enums/move-anims-common";
|
import { CommonAnim } from "#enums/move-anims-common";
|
||||||
import { BerryUsedEvent } from "#app/events/battle-scene";
|
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { BerryModifier } from "#app/modifier/modifier";
|
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { BooleanHolder } from "#app/utils/common";
|
import { BooleanHolder } from "#app/utils/common";
|
||||||
import { FieldPhase } from "./field-phase";
|
import { FieldPhase } from "./field-phase";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { allHeldItems, applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
import { HeldItemCategoryId, isItemInCategory } from "#enums/held-item-id";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The phase after attacks where the pokemon eat berries.
|
* The phase after attacks where the pokemon eat berries.
|
||||||
@ -31,10 +32,9 @@ export class BerryPhase extends FieldPhase {
|
|||||||
* @param pokemon - The {@linkcode Pokemon} to check
|
* @param pokemon - The {@linkcode Pokemon} to check
|
||||||
*/
|
*/
|
||||||
eatBerries(pokemon: Pokemon): void {
|
eatBerries(pokemon: Pokemon): void {
|
||||||
const hasUsableBerry = !!globalScene.findModifier(
|
const hasUsableBerry = pokemon.getHeldItems().some(m => {
|
||||||
m => m instanceof BerryModifier && m.shouldApply(pokemon),
|
return isItemInCategory(m, HeldItemCategoryId.BERRY) && allHeldItems[m].shouldApply(pokemon);
|
||||||
pokemon.isPlayer(),
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if (!hasUsableBerry) {
|
if (!hasUsableBerry) {
|
||||||
return;
|
return;
|
||||||
@ -59,14 +59,7 @@ export class BerryPhase extends FieldPhase {
|
|||||||
CommonAnim.USE_ITEM,
|
CommonAnim.USE_ITEM,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const berryModifier of globalScene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) {
|
applyHeldItems(ITEM_EFFECT.BERRY, { pokemon: pokemon });
|
||||||
// No need to track berries being eaten; already done inside applyModifiers
|
|
||||||
if (berryModifier.consumed) {
|
|
||||||
berryModifier.consumed = false;
|
|
||||||
pokemon.loseHeldItem(berryModifier);
|
|
||||||
}
|
|
||||||
globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier));
|
|
||||||
}
|
|
||||||
globalScene.updateModifiers(pokemon.isPlayer());
|
globalScene.updateModifiers(pokemon.isPlayer());
|
||||||
|
|
||||||
// AbilityId.CHEEK_POUCH only works once per round of nom noms
|
// AbilityId.CHEEK_POUCH only works once per round of nom noms
|
||||||
|
@ -14,9 +14,7 @@ import { EncounterPhaseEvent } from "#app/events/battle-scene";
|
|||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { FieldPosition } from "#enums/field-position";
|
import { FieldPosition } from "#enums/field-position";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { BoostBugSpawnModifier, IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier";
|
import { BoostBugSpawnModifier, IvScannerModifier } from "#app/modifier/modifier";
|
||||||
import { regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { BattlePhase } from "#app/phases/battle-phase";
|
import { BattlePhase } from "#app/phases/battle-phase";
|
||||||
import { achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv";
|
||||||
@ -271,10 +269,6 @@ export class EncounterPhase extends BattlePhase {
|
|||||||
|
|
||||||
if (!this.loaded && battle.battleType !== BattleType.MYSTERY_ENCOUNTER) {
|
if (!this.loaded && battle.battleType !== BattleType.MYSTERY_ENCOUNTER) {
|
||||||
// generate modifiers for MEs, overriding prior ones as applicable
|
// generate modifiers for MEs, overriding prior ones as applicable
|
||||||
regenerateModifierPoolThresholds(
|
|
||||||
globalScene.getEnemyField(),
|
|
||||||
battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD,
|
|
||||||
);
|
|
||||||
globalScene.generateEnemyModifiers();
|
globalScene.generateEnemyModifiers();
|
||||||
overrideModifiers(false);
|
overrideModifiers(false);
|
||||||
|
|
||||||
@ -543,22 +537,6 @@ export class EncounterPhase extends BattlePhase {
|
|||||||
if (enemyPokemon.isShiny(true)) {
|
if (enemyPokemon.isShiny(true)) {
|
||||||
globalScene.phaseManager.unshiftNew("ShinySparklePhase", BattlerIndex.ENEMY + e);
|
globalScene.phaseManager.unshiftNew("ShinySparklePhase", BattlerIndex.ENEMY + e);
|
||||||
}
|
}
|
||||||
/** This sets Eternatus' held item to be untransferrable, preventing it from being stolen */
|
|
||||||
if (
|
|
||||||
enemyPokemon.species.speciesId === SpeciesId.ETERNATUS &&
|
|
||||||
(globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex) ||
|
|
||||||
globalScene.gameMode.isEndlessMajorBoss(globalScene.currentBattle.waveIndex))
|
|
||||||
) {
|
|
||||||
const enemyMBH = globalScene.findModifier(
|
|
||||||
m => m instanceof TurnHeldItemTransferModifier,
|
|
||||||
false,
|
|
||||||
) as TurnHeldItemTransferModifier;
|
|
||||||
if (enemyMBH) {
|
|
||||||
globalScene.removeModifier(enemyMBH, true);
|
|
||||||
enemyMBH.setTransferrableFalse();
|
|
||||||
globalScene.addEnemyModifier(enemyMBH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (![BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
|
if (![BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
|
||||||
|
@ -18,13 +18,14 @@ import { PokemonMove } from "#app/data/moves/pokemon-move";
|
|||||||
import { HitResult } from "#enums/hit-result";
|
import { HitResult } from "#enums/hit-result";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
|
||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { PokemonPhase } from "./pokemon-phase";
|
import { PokemonPhase } from "./pokemon-phase";
|
||||||
import { isNullOrUndefined } from "#app/utils/common";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters";
|
import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
|
||||||
export class FaintPhase extends PokemonPhase {
|
export class FaintPhase extends PokemonPhase {
|
||||||
public readonly phaseName = "FaintPhase";
|
public readonly phaseName = "FaintPhase";
|
||||||
@ -58,17 +59,7 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
faintPokemon.resetSummonData();
|
faintPokemon.resetSummonData();
|
||||||
|
|
||||||
if (!this.preventInstantRevive) {
|
if (!this.preventInstantRevive) {
|
||||||
const instantReviveModifier = globalScene.applyModifier(
|
applyHeldItems(ITEM_EFFECT.INSTANT_REVIVE, { pokemon: faintPokemon });
|
||||||
PokemonInstantReviveModifier,
|
|
||||||
this.player,
|
|
||||||
faintPokemon,
|
|
||||||
) as PokemonInstantReviveModifier;
|
|
||||||
|
|
||||||
if (instantReviveModifier) {
|
|
||||||
faintPokemon.loseHeldItem(instantReviveModifier);
|
|
||||||
globalScene.updateModifiers(this.player);
|
|
||||||
return this.end();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,15 +33,7 @@ import type Pokemon from "#app/field/pokemon";
|
|||||||
import { MoveResult } from "#enums/move-result";
|
import { MoveResult } from "#enums/move-result";
|
||||||
import { HitResult } from "#enums/hit-result";
|
import { HitResult } from "#enums/hit-result";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import {
|
import { EnemyAttackStatusEffectChanceModifier, EnemyEndureChanceModifier } from "#app/modifier/modifier";
|
||||||
ContactHeldItemTransferChanceModifier,
|
|
||||||
DamageMoneyRewardModifier,
|
|
||||||
EnemyAttackStatusEffectChanceModifier,
|
|
||||||
EnemyEndureChanceModifier,
|
|
||||||
FlinchChanceModifier,
|
|
||||||
HitHealModifier,
|
|
||||||
PokemonMultiHitModifier,
|
|
||||||
} from "#app/modifier/modifier";
|
|
||||||
import { PokemonPhase } from "#app/phases/pokemon-phase";
|
import { PokemonPhase } from "#app/phases/pokemon-phase";
|
||||||
import { BooleanHolder, isNullOrUndefined, NumberHolder } from "#app/utils/common";
|
import { BooleanHolder, isNullOrUndefined, NumberHolder } from "#app/utils/common";
|
||||||
import type { nil } from "#app/utils/common";
|
import type { nil } from "#app/utils/common";
|
||||||
@ -54,6 +46,8 @@ import { HitCheckResult } from "#enums/hit-check-result";
|
|||||||
import type Move from "#app/data/moves/move";
|
import type Move from "#app/data/moves/move";
|
||||||
import { isFieldTargeted } from "#app/data/moves/move-utils";
|
import { isFieldTargeted } from "#app/data/moves/move-utils";
|
||||||
import { DamageAchv } from "#app/system/achv";
|
import { DamageAchv } from "#app/system/achv";
|
||||||
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
import { isVirtual, isReflected, MoveUseMode } from "#enums/move-use-mode";
|
import { isVirtual, isReflected, MoveUseMode } from "#enums/move-use-mode";
|
||||||
|
|
||||||
export type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier];
|
export type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier];
|
||||||
@ -324,7 +318,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
// If Parental Bond is applicable, add another hit
|
// If Parental Bond is applicable, add another hit
|
||||||
applyPreAttackAbAttrs("AddSecondStrikeAbAttr", user, null, move, false, hitCount, null);
|
applyPreAttackAbAttrs("AddSecondStrikeAbAttr", user, null, move, false, hitCount, null);
|
||||||
// If Multi-Lens is applicable, add hits equal to the number of held Multi-Lenses
|
// If Multi-Lens is applicable, add hits equal to the number of held Multi-Lenses
|
||||||
globalScene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, move.id, hitCount);
|
applyHeldItems(ITEM_EFFECT.MULTI_HIT, { pokemon: user, moveId: move.id, count: hitCount });
|
||||||
// Set the user's relevant turnData fields to reflect the final hit count
|
// Set the user's relevant turnData fields to reflect the final hit count
|
||||||
user.turnData.hitCount = hitCount.value;
|
user.turnData.hitCount = hitCount.value;
|
||||||
user.turnData.hitsLeft = hitCount.value;
|
user.turnData.hitsLeft = hitCount.value;
|
||||||
@ -424,7 +418,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
globalScene.phaseManager.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal }));
|
globalScene.phaseManager.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal }));
|
||||||
}
|
}
|
||||||
|
|
||||||
globalScene.applyModifiers(HitHealModifier, this.player, user);
|
applyHeldItems(ITEM_EFFECT.HIT_HEAL, { pokemon: user });
|
||||||
this.getTargets().forEach(target => {
|
this.getTargets().forEach(target => {
|
||||||
target.turnData.moveEffectiveness = null;
|
target.turnData.moveEffectiveness = null;
|
||||||
});
|
});
|
||||||
@ -460,7 +454,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
!this.move.hitsSubstitute(user, target)
|
!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);
|
||||||
}
|
}
|
||||||
@ -905,7 +899,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (user.isPlayer() && target.isEnemy()) {
|
if (user.isPlayer() && target.isEnemy()) {
|
||||||
globalScene.applyModifiers(DamageMoneyRewardModifier, true, user, new NumberHolder(damage));
|
applyHeldItems(ITEM_EFFECT.DAMAGE_MONEY_REWARD, { pokemon: user, damage: damage });
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1011,7 +1005,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
|
|
||||||
// Apply Grip Claw's chance to steal an item from the target
|
// Apply Grip Claw's chance to steal an item from the target
|
||||||
if (this.move.is("AttackMove")) {
|
if (this.move.is("AttackMove")) {
|
||||||
globalScene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target);
|
applyHeldItems(ITEM_EFFECT.CONTACT_ITEM_STEAL_CHANCE, { pokemon: user, target: target });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type { ModifierTier } from "#enums/modifier-tier";
|
import type { RewardTier } from "#enums/reward-tier";
|
||||||
import type { ModifierTypeOption, ModifierType } from "#app/modifier/modifier-type";
|
import type { ModifierTypeOption, ModifierType } from "#app/modifier/modifier-type";
|
||||||
import {
|
import {
|
||||||
regenerateModifierPoolThresholds,
|
regenerateModifierPoolThresholds,
|
||||||
@ -12,15 +12,11 @@ import {
|
|||||||
PokemonPpRestoreModifierType,
|
PokemonPpRestoreModifierType,
|
||||||
PokemonPpUpModifierType,
|
PokemonPpUpModifierType,
|
||||||
getPlayerModifierTypeOptions,
|
getPlayerModifierTypeOptions,
|
||||||
|
HeldItemReward,
|
||||||
} from "#app/modifier/modifier-type";
|
} from "#app/modifier/modifier-type";
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
||||||
import type { Modifier } from "#app/modifier/modifier";
|
import type { Modifier } from "#app/modifier/modifier";
|
||||||
import {
|
import { ExtraModifierModifier, HealShopCostModifier, TempExtraModifierModifier } from "#app/modifier/modifier";
|
||||||
ExtraModifierModifier,
|
|
||||||
HealShopCostModifier,
|
|
||||||
PokemonHeldItemModifier,
|
|
||||||
TempExtraModifierModifier,
|
|
||||||
} from "#app/modifier/modifier";
|
|
||||||
import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||||
import { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
|
import { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
|
||||||
import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler";
|
import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler";
|
||||||
@ -36,7 +32,7 @@ export type ModifierSelectCallback = (rowCursor: number, cursor: number) => bool
|
|||||||
export class SelectModifierPhase extends BattlePhase {
|
export class SelectModifierPhase extends BattlePhase {
|
||||||
public readonly phaseName = "SelectModifierPhase";
|
public readonly phaseName = "SelectModifierPhase";
|
||||||
private rerollCount: number;
|
private rerollCount: number;
|
||||||
private modifierTiers?: ModifierTier[];
|
private modifierTiers?: RewardTier[];
|
||||||
private customModifierSettings?: CustomModifierSettings;
|
private customModifierSettings?: CustomModifierSettings;
|
||||||
private isCopy: boolean;
|
private isCopy: boolean;
|
||||||
|
|
||||||
@ -44,7 +40,7 @@ export class SelectModifierPhase extends BattlePhase {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
rerollCount = 0,
|
rerollCount = 0,
|
||||||
modifierTiers?: ModifierTier[],
|
modifierTiers?: RewardTier[],
|
||||||
customModifierSettings?: CustomModifierSettings,
|
customModifierSettings?: CustomModifierSettings,
|
||||||
isCopy = false,
|
isCopy = false,
|
||||||
) {
|
) {
|
||||||
@ -172,7 +168,9 @@ export class SelectModifierPhase extends BattlePhase {
|
|||||||
modifierSelectCallback: ModifierSelectCallback,
|
modifierSelectCallback: ModifierSelectCallback,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (modifierType instanceof PokemonModifierType) {
|
if (modifierType instanceof PokemonModifierType) {
|
||||||
if (modifierType instanceof FusePokemonModifierType) {
|
if (modifierType instanceof HeldItemReward) {
|
||||||
|
this.openGiveHeldItemMenu(modifierType, modifierSelectCallback);
|
||||||
|
} else if (modifierType instanceof FusePokemonModifierType) {
|
||||||
this.openFusionMenu(modifierType, cost, modifierSelectCallback);
|
this.openFusionMenu(modifierType, cost, modifierSelectCallback);
|
||||||
} else {
|
} else {
|
||||||
this.openModifierMenu(modifierType, cost, modifierSelectCallback);
|
this.openModifierMenu(modifierType, cost, modifierSelectCallback);
|
||||||
@ -194,7 +192,7 @@ export class SelectModifierPhase extends BattlePhase {
|
|||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew(
|
||||||
"SelectModifierPhase",
|
"SelectModifierPhase",
|
||||||
this.rerollCount + 1,
|
this.rerollCount + 1,
|
||||||
this.typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[],
|
this.typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as RewardTier[],
|
||||||
);
|
);
|
||||||
globalScene.ui.clearText();
|
globalScene.ui.clearText();
|
||||||
globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end());
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end());
|
||||||
@ -222,17 +220,15 @@ export class SelectModifierPhase extends BattlePhase {
|
|||||||
fromSlotIndex !== toSlotIndex &&
|
fromSlotIndex !== toSlotIndex &&
|
||||||
itemIndex > -1
|
itemIndex > -1
|
||||||
) {
|
) {
|
||||||
const itemModifiers = globalScene.findModifiers(
|
const items = party[fromSlotIndex].heldItemManager.getTransferableHeldItems();
|
||||||
m => m instanceof PokemonHeldItemModifier && m.isTransferable && m.pokemonId === party[fromSlotIndex].id,
|
const item = items[itemIndex];
|
||||||
) as PokemonHeldItemModifier[];
|
globalScene.tryTransferHeldItem(
|
||||||
const itemModifier = itemModifiers[itemIndex];
|
item,
|
||||||
globalScene.tryTransferHeldItemModifier(
|
party[fromSlotIndex],
|
||||||
itemModifier,
|
|
||||||
party[toSlotIndex],
|
party[toSlotIndex],
|
||||||
true,
|
true,
|
||||||
itemQuantity,
|
itemQuantity,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -372,6 +368,29 @@ export class SelectModifierPhase extends BattlePhase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private openGiveHeldItemMenu(reward, modifierSelectCallback) {
|
||||||
|
const party = globalScene.getPlayerParty();
|
||||||
|
const partyUiMode = PartyUiMode.MODIFIER;
|
||||||
|
globalScene.ui.setModeWithoutClear(
|
||||||
|
UiMode.PARTY,
|
||||||
|
partyUiMode,
|
||||||
|
-1,
|
||||||
|
(slotIndex: number, _option: PartyOption) => {
|
||||||
|
if (slotIndex < 6) {
|
||||||
|
globalScene.ui.setMode(UiMode.MODIFIER_SELECT, this.isPlayer()).then(() => {
|
||||||
|
reward.apply(party[slotIndex]);
|
||||||
|
globalScene.ui.clearText();
|
||||||
|
globalScene.ui.setMode(UiMode.MESSAGE);
|
||||||
|
super.end();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.resetModifierSelect(modifierSelectCallback);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reward.selectFilter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Function that determines how many reward slots are available
|
// Function that determines how many reward slots are available
|
||||||
private getModifierCount(): number {
|
private getModifierCount(): number {
|
||||||
const modifierCountHolder = new NumberHolder(3);
|
const modifierCountHolder = new NumberHolder(3);
|
||||||
|
@ -10,7 +10,6 @@ import { ArenaTagSide } from "#enums/arena-tag-side";
|
|||||||
import type { ArenaTag } from "#app/data/arena-tag";
|
import type { ArenaTag } from "#app/data/arena-tag";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { ResetNegativeStatStageModifier } from "#app/modifier/modifier";
|
|
||||||
import { handleTutorial, Tutorial } from "#app/tutorial";
|
import { handleTutorial, Tutorial } from "#app/tutorial";
|
||||||
import { NumberHolder, BooleanHolder, isNullOrUndefined } from "#app/utils/common";
|
import { NumberHolder, BooleanHolder, isNullOrUndefined } from "#app/utils/common";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
@ -18,6 +17,8 @@ import { PokemonPhase } from "./pokemon-phase";
|
|||||||
import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat";
|
import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat";
|
||||||
import { OctolockTag } from "#app/data/battler-tags";
|
import { OctolockTag } from "#app/data/battler-tags";
|
||||||
import { ArenaTagType } from "#app/enums/arena-tag-type";
|
import { ArenaTagType } from "#app/enums/arena-tag-type";
|
||||||
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
|
||||||
export type StatStageChangeCallback = (
|
export type StatStageChangeCallback = (
|
||||||
target: Pokemon | null,
|
target: Pokemon | null,
|
||||||
@ -240,16 +241,7 @@ export class StatStageChangePhase extends PokemonPhase {
|
|||||||
);
|
);
|
||||||
if (!existingPhase?.is("StatStageChangePhase")) {
|
if (!existingPhase?.is("StatStageChangePhase")) {
|
||||||
// Apply White Herb if needed
|
// Apply White Herb if needed
|
||||||
const whiteHerb = globalScene.applyModifier(
|
applyHeldItems(ITEM_EFFECT.RESET_NEGATIVE_STAT_STAGE, { pokemon: pokemon, isPlayer: this.player });
|
||||||
ResetNegativeStatStageModifier,
|
|
||||||
this.player,
|
|
||||||
pokemon,
|
|
||||||
) as ResetNegativeStatStageModifier;
|
|
||||||
// If the White Herb was applied, consume it
|
|
||||||
if (whiteHerb) {
|
|
||||||
pokemon.loseHeldItem(whiteHerb);
|
|
||||||
globalScene.updateModifiers(this.player);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
|
@ -6,12 +6,12 @@ import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms/form-cha
|
|||||||
import { TrainerSlot } from "#enums/trainer-slot";
|
import { TrainerSlot } from "#enums/trainer-slot";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { SwitchEffectTransferModifier } from "#app/modifier/modifier";
|
|
||||||
import { Command } from "#enums/command";
|
import { Command } from "#enums/command";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { SummonPhase } from "./summon-phase";
|
import { SummonPhase } from "./summon-phase";
|
||||||
import { SubstituteTag } from "#app/data/battler-tags";
|
import { SubstituteTag } from "#app/data/battler-tags";
|
||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
|
||||||
export class SwitchSummonPhase extends SummonPhase {
|
export class SwitchSummonPhase extends SummonPhase {
|
||||||
public readonly phaseName: "SwitchSummonPhase" | "ReturnPhase" = "SwitchSummonPhase";
|
public readonly phaseName: "SwitchSummonPhase" | "ReturnPhase" = "SwitchSummonPhase";
|
||||||
@ -138,29 +138,11 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// If the recipient pokemon lacks a baton, give our baton to it during the swap
|
// If the recipient pokemon lacks a baton, give our baton to it during the swap
|
||||||
if (
|
if (!switchedInPokemon.heldItemManager.hasItem(HeldItemId.BATON)) {
|
||||||
!globalScene.findModifier(
|
const batonPassModifier = this.lastPokemon.heldItemManager.hasItem(HeldItemId.BATON);
|
||||||
m =>
|
|
||||||
m instanceof SwitchEffectTransferModifier &&
|
|
||||||
(m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const batonPassModifier = globalScene.findModifier(
|
|
||||||
m =>
|
|
||||||
m instanceof SwitchEffectTransferModifier &&
|
|
||||||
(m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id,
|
|
||||||
) as SwitchEffectTransferModifier;
|
|
||||||
|
|
||||||
if (batonPassModifier) {
|
if (batonPassModifier) {
|
||||||
globalScene.tryTransferHeldItemModifier(
|
globalScene.tryTransferHeldItem(HeldItemId.BATON, this.lastPokemon, switchedInPokemon, false);
|
||||||
batonPassModifier,
|
|
||||||
switchedInPokemon,
|
|
||||||
false,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,7 @@ import { getBiomeKey } from "#app/field/arena";
|
|||||||
import { GameMode, getGameMode } from "#app/game-mode";
|
import { GameMode, getGameMode } from "#app/game-mode";
|
||||||
import { GameModes } from "#enums/game-modes";
|
import { GameModes } from "#enums/game-modes";
|
||||||
import type { Modifier } from "#app/modifier/modifier";
|
import type { Modifier } from "#app/modifier/modifier";
|
||||||
import { getDailyRunStarterModifiers, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
|
||||||
import { Phase } from "#app/phase";
|
import { Phase } from "#app/phase";
|
||||||
import type { SessionSaveData } from "#app/system/game-data";
|
import type { SessionSaveData } from "#app/system/game-data";
|
||||||
import { Unlockables } from "#enums/unlockables";
|
import { Unlockables } from "#enums/unlockables";
|
||||||
@ -20,6 +18,7 @@ import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#app/utils/c
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
|
import { assignDailyRunStarterHeldItems } from "#app/items/held-item-pool";
|
||||||
|
|
||||||
export class TitlePhase extends Phase {
|
export class TitlePhase extends Phase {
|
||||||
public readonly phaseName = "TitlePhase";
|
public readonly phaseName = "TitlePhase";
|
||||||
@ -238,8 +237,6 @@ export class TitlePhase extends Phase {
|
|||||||
loadPokemonAssets.push(starterPokemon.loadAssets());
|
loadPokemonAssets.push(starterPokemon.loadAssets());
|
||||||
}
|
}
|
||||||
|
|
||||||
regenerateModifierPoolThresholds(party, ModifierPoolType.DAILY_STARTER);
|
|
||||||
|
|
||||||
const modifiers: Modifier[] = Array(3)
|
const modifiers: Modifier[] = Array(3)
|
||||||
.fill(null)
|
.fill(null)
|
||||||
.map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier())
|
.map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier())
|
||||||
@ -249,13 +246,14 @@ export class TitlePhase extends Phase {
|
|||||||
.map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier()),
|
.map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier()),
|
||||||
)
|
)
|
||||||
.concat([modifierTypes.MAP().withIdFromFunc(modifierTypes.MAP).newModifier()])
|
.concat([modifierTypes.MAP().withIdFromFunc(modifierTypes.MAP).newModifier()])
|
||||||
.concat(getDailyRunStarterModifiers(party))
|
|
||||||
.filter(m => m !== null);
|
.filter(m => m !== null);
|
||||||
|
|
||||||
|
assignDailyRunStarterHeldItems(party);
|
||||||
|
|
||||||
for (const m of modifiers) {
|
for (const m of modifiers) {
|
||||||
globalScene.addModifier(m, true, false, false, true);
|
globalScene.addModifier(m, true, false, false, true);
|
||||||
}
|
}
|
||||||
globalScene.updateModifiers(true, true);
|
globalScene.updateModifiers(true);
|
||||||
|
|
||||||
Promise.all(loadPokemonAssets).then(() => {
|
Promise.all(loadPokemonAssets).then(() => {
|
||||||
globalScene.time.delayedCall(500, () => globalScene.playBgm());
|
globalScene.time.delayedCall(500, () => globalScene.playBgm());
|
||||||
|
@ -5,16 +5,12 @@ import { WeatherType } from "#app/enums/weather-type";
|
|||||||
import { TurnEndEvent } from "#app/events/battle-scene";
|
import { TurnEndEvent } from "#app/events/battle-scene";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import {
|
import { EnemyTurnHealModifier, EnemyStatusEffectHealChanceModifier } from "#app/modifier/modifier";
|
||||||
TurnHealModifier,
|
|
||||||
EnemyTurnHealModifier,
|
|
||||||
EnemyStatusEffectHealChanceModifier,
|
|
||||||
TurnStatusEffectModifier,
|
|
||||||
TurnHeldItemTransferModifier,
|
|
||||||
} from "#app/modifier/modifier";
|
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { FieldPhase } from "./field-phase";
|
import { FieldPhase } from "./field-phase";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { applyHeldItems } from "#app/items/all-held-items";
|
||||||
|
import { ITEM_EFFECT } from "#app/items/held-item";
|
||||||
|
|
||||||
export class TurnEndPhase extends FieldPhase {
|
export class TurnEndPhase extends FieldPhase {
|
||||||
public readonly phaseName = "TurnEndPhase";
|
public readonly phaseName = "TurnEndPhase";
|
||||||
@ -30,7 +26,7 @@ export class TurnEndPhase extends FieldPhase {
|
|||||||
if (!pokemon.switchOutStatus) {
|
if (!pokemon.switchOutStatus) {
|
||||||
pokemon.lapseTags(BattlerTagLapseType.TURN_END);
|
pokemon.lapseTags(BattlerTagLapseType.TURN_END);
|
||||||
|
|
||||||
globalScene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon);
|
applyHeldItems(ITEM_EFFECT.TURN_END_HEAL, { pokemon: 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(
|
||||||
@ -52,8 +48,9 @@ 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);
|
|
||||||
|
applyHeldItems(ITEM_EFFECT.TURN_END_ITEM_STEAL, { pokemon: pokemon });
|
||||||
|
|
||||||
pokemon.tempSummonData.turnCount++;
|
pokemon.tempSummonData.turnCount++;
|
||||||
pokemon.tempSummonData.waveTurnCount++;
|
pokemon.tempSummonData.waveTurnCount++;
|
||||||
|
@ -4,7 +4,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/data/moves/pokemon-move";
|
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
||||||
import { BypassSpeedChanceModifier } from "#app/modifier/modifier";
|
|
||||||
import { Command } from "#enums/command";
|
import { Command } from "#enums/command";
|
||||||
import { randSeedShuffle, BooleanHolder } from "#app/utils/common";
|
import { randSeedShuffle, BooleanHolder } from "#app/utils/common";
|
||||||
import { FieldPhase } from "./field-phase";
|
import { FieldPhase } from "./field-phase";
|
||||||
@ -12,6 +11,8 @@ import { BattlerIndex } from "#enums/battler-index";
|
|||||||
import { TrickRoomTag } from "#app/data/arena-tag";
|
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 { 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";
|
||||||
@ -69,7 +70,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;
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import type { Modifier } from "typescript";
|
import type { Modifier } from "typescript";
|
||||||
import { TurnHeldItemTransferModifier } from "../modifier/modifier";
|
|
||||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { NumberHolder } from "#app/utils/common";
|
import { NumberHolder } from "#app/utils/common";
|
||||||
@ -16,6 +15,8 @@ import type { ConditionFn } from "#app/@types/common";
|
|||||||
import { Stat, getShortenedStatKey } from "#app/enums/stat";
|
import { Stat, getShortenedStatKey } from "#app/enums/stat";
|
||||||
import { Challenges } from "#app/enums/challenges";
|
import { Challenges } from "#app/enums/challenges";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
|
||||||
export enum AchvTier {
|
export enum AchvTier {
|
||||||
COMMON,
|
COMMON,
|
||||||
@ -189,6 +190,19 @@ export class ModifierAchv extends Achv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class HeldItemAchv extends Achv {
|
||||||
|
constructor(
|
||||||
|
localizationKey: string,
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
|
iconImage: string,
|
||||||
|
score: number,
|
||||||
|
pokemonFunc: (pokemon: Pokemon) => boolean,
|
||||||
|
) {
|
||||||
|
super(localizationKey, name, description, iconImage, score, (args: any[]) => pokemonFunc(args[0] as Pokemon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class ChallengeAchv extends Achv {
|
export class ChallengeAchv extends Achv {
|
||||||
constructor(
|
constructor(
|
||||||
localizationKey: string,
|
localizationKey: string,
|
||||||
@ -490,13 +504,13 @@ export const achvs = {
|
|||||||
25,
|
25,
|
||||||
).setSecret(true),
|
).setSecret(true),
|
||||||
SPLICE: new Achv("SPLICE", "", "SPLICE.description", "dna_splicers", 10),
|
SPLICE: new Achv("SPLICE", "", "SPLICE.description", "dna_splicers", 10),
|
||||||
MINI_BLACK_HOLE: new ModifierAchv(
|
MINI_BLACK_HOLE: new HeldItemAchv(
|
||||||
"MINI_BLACK_HOLE",
|
"MINI_BLACK_HOLE",
|
||||||
"",
|
"",
|
||||||
"MINI_BLACK_HOLE.description",
|
"MINI_BLACK_HOLE.description",
|
||||||
"mini_black_hole",
|
"mini_black_hole",
|
||||||
25,
|
25,
|
||||||
modifier => modifier instanceof TurnHeldItemTransferModifier,
|
pokemon => pokemon.heldItemManager.hasItem(HeldItemId.MINI_BLACK_HOLE),
|
||||||
).setSecret(),
|
).setSecret(),
|
||||||
CATCH_MYTHICAL: new Achv("CATCH_MYTHICAL", "", "CATCH_MYTHICAL.description", "strange_ball", 50).setSecret(),
|
CATCH_MYTHICAL: new Achv("CATCH_MYTHICAL", "", "CATCH_MYTHICAL.description", "strange_ball", 50).setSecret(),
|
||||||
CATCH_SUB_LEGENDARY: new Achv("CATCH_SUB_LEGENDARY", "", "CATCH_SUB_LEGENDARY.description", "rb", 75).setSecret(),
|
CATCH_SUB_LEGENDARY: new Achv("CATCH_SUB_LEGENDARY", "", "CATCH_SUB_LEGENDARY.description", "rb", 75).setSecret(),
|
||||||
|
@ -177,8 +177,8 @@ export default class BattleFlyout extends Phaser.GameObjects.Container {
|
|||||||
const berryUsedEvent = event as BerryUsedEvent;
|
const berryUsedEvent = event as BerryUsedEvent;
|
||||||
if (
|
if (
|
||||||
!berryUsedEvent ||
|
!berryUsedEvent ||
|
||||||
berryUsedEvent.berryModifier.pokemonId !== this.pokemon?.id ||
|
berryUsedEvent.pokemon.id !== this.pokemon?.id ||
|
||||||
berryUsedEvent.berryModifier.berryType !== BerryType.LEPPA
|
berryUsedEvent.berryType !== BerryType.LEPPA
|
||||||
) {
|
) {
|
||||||
// We only care about Leppa berries
|
// We only care about Leppa berries
|
||||||
return;
|
return;
|
||||||
|
@ -5,7 +5,7 @@ import { getPokeballAtlasKey } from "#app/data/pokeball";
|
|||||||
import { addTextObject, getTextStyleOptions, getModifierTierTextTint, getTextColor, TextStyle } from "./text";
|
import { addTextObject, getTextStyleOptions, getModifierTierTextTint, getTextColor, TextStyle } from "./text";
|
||||||
import AwaitableUiHandler from "./awaitable-ui-handler";
|
import AwaitableUiHandler from "./awaitable-ui-handler";
|
||||||
import { UiMode } from "#enums/ui-mode";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import { LockModifierTiersModifier, PokemonHeldItemModifier, HealShopCostModifier } from "../modifier/modifier";
|
import { LockModifierTiersModifier, HealShopCostModifier } from "../modifier/modifier";
|
||||||
import { handleTutorial, Tutorial } from "../tutorial";
|
import { handleTutorial, Tutorial } from "../tutorial";
|
||||||
import { Button } from "#enums/buttons";
|
import { Button } from "#enums/buttons";
|
||||||
import MoveInfoOverlay from "./move-info-overlay";
|
import MoveInfoOverlay from "./move-info-overlay";
|
||||||
@ -183,7 +183,10 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
|
|||||||
this.player = args[0];
|
this.player = args[0];
|
||||||
|
|
||||||
const partyHasHeldItem =
|
const partyHasHeldItem =
|
||||||
this.player && !!globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.isTransferable).length;
|
globalScene
|
||||||
|
.getPlayerParty()
|
||||||
|
.map(p => p.heldItemManager.getTransferableHeldItems().length)
|
||||||
|
.reduce((tot, i) => tot + i, 0) > 0;
|
||||||
const canLockRarities = !!globalScene.findModifier(m => m instanceof LockModifierTiersModifier);
|
const canLockRarities = !!globalScene.findModifier(m => m instanceof LockModifierTiersModifier);
|
||||||
|
|
||||||
this.transferButtonContainer.setVisible(false);
|
this.transferButtonContainer.setVisible(false);
|
||||||
@ -258,10 +261,13 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
|
|||||||
this.shopOptionsRows[row].push(option);
|
this.shopOptionsRows[row].push(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxUpgradeCount = typeOptions.map(to => to.upgradeCount).reduce((max, current) => Math.max(current, max), 0);
|
//TODO: temporary stopgap so the game does not crash, will have to fix this later
|
||||||
|
// console.log(typeOptions.map(to => to.upgradeCount))
|
||||||
|
// const maxUpgradeCount = typeOptions.map(to => to.upgradeCount).reduce((max, current) => Math.max(current, max), 0);
|
||||||
|
const maxUpgradeCount = 0;
|
||||||
|
|
||||||
/* Force updateModifiers without pokemonSpecificModifiers */
|
/* Force updateModifiers without pokemon held items */
|
||||||
globalScene.getModifierBar().updateModifiers(globalScene.modifiers, true);
|
globalScene.updateModifiers(true, false);
|
||||||
|
|
||||||
/* Multiplies the appearance duration by the speed parameter so that it is always constant, and avoids "flashbangs" at game speed x5 */
|
/* Multiplies the appearance duration by the speed parameter so that it is always constant, and avoids "flashbangs" at game speed x5 */
|
||||||
globalScene.showShopOverlay(750 * globalScene.gameSpeed);
|
globalScene.showShopOverlay(750 * globalScene.gameSpeed);
|
||||||
@ -676,7 +682,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
|
|||||||
globalScene.hideLuckText(250);
|
globalScene.hideLuckText(250);
|
||||||
|
|
||||||
/* Normally already called just after the shop, but not sure if it happens in 100% of cases */
|
/* Normally already called just after the shop, but not sure if it happens in 100% of cases */
|
||||||
globalScene.getModifierBar().updateModifiers(globalScene.modifiers);
|
globalScene.updateModifiers(true);
|
||||||
|
|
||||||
const options = this.options.concat(this.shopOptionsRows.flat());
|
const options = this.options.concat(this.shopOptionsRows.flat());
|
||||||
this.options.splice(0, this.options.length);
|
this.options.splice(0, this.options.length);
|
||||||
@ -763,7 +769,7 @@ class ModifierOption extends Phaser.GameObjects.Container {
|
|||||||
this.add(this.itemContainer);
|
this.add(this.itemContainer);
|
||||||
|
|
||||||
const getItem = () => {
|
const getItem = () => {
|
||||||
const item = globalScene.add.sprite(0, 0, "items", this.modifierTypeOption.type?.iconImage);
|
const item = globalScene.add.sprite(0, 0, "items", this.modifierTypeOption.type?.getIcon());
|
||||||
return item;
|
return item;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import { Command } from "#enums/command";
|
|||||||
import MessageUiHandler from "#app/ui/message-ui-handler";
|
import MessageUiHandler from "#app/ui/message-ui-handler";
|
||||||
import { UiMode } from "#enums/ui-mode";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import { BooleanHolder, toReadableString, randInt, getLocalizedSpriteKey } from "#app/utils/common";
|
import { BooleanHolder, toReadableString, randInt, getLocalizedSpriteKey } from "#app/utils/common";
|
||||||
import type { PokemonFormChangeItemModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { allMoves } from "#app/data/data-lists";
|
import { allMoves } from "#app/data/data-lists";
|
||||||
import { Gender, getGenderColor, getGenderSymbol } from "#app/data/gender";
|
import { Gender, getGenderColor, getGenderSymbol } from "#app/data/gender";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
@ -28,6 +27,9 @@ import { SpeciesId } from "#enums/species-id";
|
|||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import type { CommandPhase } from "#app/phases/command-phase";
|
import type { CommandPhase } from "#app/phases/command-phase";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { HeldItemId } from "#enums/held-item-id";
|
||||||
|
import { formChangeItemName } from "#app/data/pokemon-forms";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
const defaultMessage = i18next.t("partyUiHandler:choosePokemon");
|
const defaultMessage = i18next.t("partyUiHandler:choosePokemon");
|
||||||
|
|
||||||
@ -138,10 +140,7 @@ export type PartyModifierTransferSelectCallback = (
|
|||||||
) => void;
|
) => void;
|
||||||
export type PartyModifierSpliceSelectCallback = (fromCursor: number, toCursor?: number) => void;
|
export type PartyModifierSpliceSelectCallback = (fromCursor: number, toCursor?: number) => void;
|
||||||
export type PokemonSelectFilter = (pokemon: PlayerPokemon) => string | null;
|
export type PokemonSelectFilter = (pokemon: PlayerPokemon) => string | null;
|
||||||
export type PokemonModifierTransferSelectFilter = (
|
export type PokemonModifierTransferSelectFilter = (pokemon: PlayerPokemon, item: HeldItemId) => string | null;
|
||||||
pokemon: PlayerPokemon,
|
|
||||||
modifier: PokemonHeldItemModifier,
|
|
||||||
) => string | null;
|
|
||||||
export type PokemonMoveSelectFilter = (pokemonMove: PokemonMove) => string | null;
|
export type PokemonMoveSelectFilter = (pokemonMove: PokemonMove) => string | null;
|
||||||
|
|
||||||
export default class PartyUiHandler extends MessageUiHandler {
|
export default class PartyUiHandler extends MessageUiHandler {
|
||||||
@ -220,11 +219,8 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
private static FilterAllMoves = (_pokemonMove: PokemonMove) => null;
|
private static FilterAllMoves = (_pokemonMove: PokemonMove) => null;
|
||||||
|
|
||||||
public static FilterItemMaxStacks = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => {
|
public static FilterItemMaxStacks = (pokemon: PlayerPokemon, item: HeldItemId) => {
|
||||||
const matchingModifier = globalScene.findModifier(
|
if (pokemon.heldItemManager.isMaxStack(item)) {
|
||||||
m => m.is("PokemonHeldItemModifier") && m.pokemonId === pokemon.id && m.matchType(modifier),
|
|
||||||
) as PokemonHeldItemModifier;
|
|
||||||
if (matchingModifier && matchingModifier.stackCount === matchingModifier.getMaxStackCount()) {
|
|
||||||
return i18next.t("partyUiHandler:tooManyItems", { pokemonName: getPokemonNameWithAffix(pokemon, false) });
|
return i18next.t("partyUiHandler:tooManyItems", { pokemonName: getPokemonNameWithAffix(pokemon, false) });
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -503,8 +499,10 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
if (this.transferCursor !== this.cursor) {
|
if (this.transferCursor !== this.cursor) {
|
||||||
if (this.transferAll) {
|
if (this.transferAll) {
|
||||||
this.getTransferrableItemsFromPokemon(globalScene.getPlayerParty()[this.transferCursor]).forEach(
|
globalScene
|
||||||
(_, i, array) => {
|
.getPlayerParty()
|
||||||
|
[this.transferCursor].heldItemManager.getTransferableHeldItems()
|
||||||
|
.forEach((_, i, array) => {
|
||||||
const invertedIndex = array.length - 1 - i;
|
const invertedIndex = array.length - 1 - i;
|
||||||
(this.selectCallback as PartyModifierTransferSelectCallback)(
|
(this.selectCallback as PartyModifierTransferSelectCallback)(
|
||||||
this.transferCursor,
|
this.transferCursor,
|
||||||
@ -512,8 +510,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
this.transferQuantitiesMax[invertedIndex],
|
this.transferQuantitiesMax[invertedIndex],
|
||||||
this.cursor,
|
this.cursor,
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
(this.selectCallback as PartyModifierTransferSelectCallback)(
|
(this.selectCallback as PartyModifierTransferSelectCallback)(
|
||||||
this.transferCursor,
|
this.transferCursor,
|
||||||
@ -548,18 +545,15 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
const newPokemon = globalScene.getPlayerParty()[p];
|
const newPokemon = globalScene.getPlayerParty()[p];
|
||||||
// this next bit checks to see if the the selected item from the original transfer pokemon exists on the new pokemon `p`
|
// this next bit checks to see if the the selected item from the original transfer pokemon exists on the new pokemon `p`
|
||||||
// this returns `undefined` if the new pokemon doesn't have the item at all, otherwise it returns the `pokemonHeldItemModifier` for that item
|
// this returns `undefined` if the new pokemon doesn't have the item at all, otherwise it returns the `pokemonHeldItemModifier` for that item
|
||||||
const matchingModifier = globalScene.findModifier(
|
const transferItem = pokemon.heldItemManager.getTransferableHeldItems()[this.transferOptionCursor];
|
||||||
m =>
|
const matchingItem = newPokemon.heldItemManager.hasItem(transferItem);
|
||||||
m.is("PokemonHeldItemModifier") &&
|
|
||||||
m.pokemonId === newPokemon.id &&
|
|
||||||
m.matchType(this.getTransferrableItemsFromPokemon(pokemon)[this.transferOptionCursor]),
|
|
||||||
) as PokemonHeldItemModifier;
|
|
||||||
const partySlot = this.partySlots.filter(m => m.getPokemon() === newPokemon)[0]; // this gets pokemon [p] for us
|
const partySlot = this.partySlots.filter(m => m.getPokemon() === newPokemon)[0]; // this gets pokemon [p] for us
|
||||||
if (p !== this.transferCursor) {
|
if (p !== this.transferCursor) {
|
||||||
// this skips adding the able/not able labels on the pokemon doing the transfer
|
// this skips adding the able/not able labels on the pokemon doing the transfer
|
||||||
if (matchingModifier) {
|
if (matchingItem) {
|
||||||
// if matchingModifier exists then the item exists on the new pokemon
|
// if matchingModifier exists then the item exists on the new pokemon
|
||||||
if (matchingModifier.getMaxStackCount() === matchingModifier.stackCount) {
|
if (newPokemon.heldItemManager.isMaxStack(transferItem)) {
|
||||||
// checks to see if the stack of items is at max stack; if so, set the description label to "Not able"
|
// checks to see if the stack of items is at max stack; if so, set the description label to "Not able"
|
||||||
ableToTransferText = i18next.t("partyUiHandler:notAble");
|
ableToTransferText = i18next.t("partyUiHandler:notAble");
|
||||||
} else {
|
} else {
|
||||||
@ -681,12 +675,6 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTransferrableItemsFromPokemon(pokemon: PlayerPokemon) {
|
|
||||||
return globalScene.findModifiers(
|
|
||||||
m => m.is("PokemonHeldItemModifier") && m.isTransferable && m.pokemonId === pokemon.id,
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
}
|
|
||||||
|
|
||||||
private getFilterResult(option: number, pokemon: PlayerPokemon): string | null {
|
private getFilterResult(option: number, pokemon: PlayerPokemon): string | null {
|
||||||
let filterResult: string | null;
|
let filterResult: string | null;
|
||||||
if (option !== PartyOption.TRANSFER && option !== PartyOption.SPLICE) {
|
if (option !== PartyOption.TRANSFER && option !== PartyOption.SPLICE) {
|
||||||
@ -700,7 +688,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
} else {
|
} else {
|
||||||
filterResult = (this.selectFilter as PokemonModifierTransferSelectFilter)(
|
filterResult = (this.selectFilter as PokemonModifierTransferSelectFilter)(
|
||||||
pokemon,
|
pokemon,
|
||||||
this.getTransferrableItemsFromPokemon(globalScene.getPlayerParty()[this.transferCursor])[
|
globalScene.getPlayerParty()[this.transferCursor].heldItemManager.getTransferableHeldItems()[
|
||||||
this.transferOptionCursor
|
this.transferOptionCursor
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -751,9 +739,9 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase") &&
|
globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase") &&
|
||||||
this.partyUiMode === PartyUiMode.CHECK
|
this.partyUiMode === PartyUiMode.CHECK
|
||||||
) {
|
) {
|
||||||
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
|
const formChangeItems = this.getFormChangeItems(pokemon);
|
||||||
const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM];
|
const item = formChangeItems[option - PartyOption.FORM_CHANGE_ITEM];
|
||||||
modifier.active = !modifier.active;
|
pokemon.heldItemManager.toggleActive(item);
|
||||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeItemTrigger, false, true);
|
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeItemTrigger, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -922,14 +910,10 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
if (this.cursor < 6) {
|
if (this.cursor < 6) {
|
||||||
if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && !this.transferMode) {
|
if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && !this.transferMode) {
|
||||||
/** Initialize item quantities for the selected Pokemon */
|
/** Initialize item quantities for the selected Pokemon */
|
||||||
const itemModifiers = globalScene.findModifiers(
|
const pokemon = globalScene.getPlayerParty()[this.cursor];
|
||||||
m =>
|
const items = pokemon.heldItemManager.getTransferableHeldItems();
|
||||||
m.is("PokemonHeldItemModifier") &&
|
this.transferQuantities = items.map(item => pokemon.heldItemManager.getStack(item));
|
||||||
m.isTransferable &&
|
this.transferQuantitiesMax = items.map(item => pokemon.heldItemManager.getStack(item));
|
||||||
m.pokemonId === globalScene.getPlayerParty()[this.cursor].id,
|
|
||||||
) as PokemonHeldItemModifier[];
|
|
||||||
this.transferQuantities = itemModifiers.map(item => item.getStackCount());
|
|
||||||
this.transferQuantitiesMax = itemModifiers.map(item => item.getStackCount());
|
|
||||||
}
|
}
|
||||||
this.showOptions();
|
this.showOptions();
|
||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
@ -1160,9 +1144,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
private allowBatonModifierSwitch(): boolean {
|
private allowBatonModifierSwitch(): boolean {
|
||||||
return !!(
|
return !!(
|
||||||
this.partyUiMode !== PartyUiMode.FAINT_SWITCH &&
|
this.partyUiMode !== PartyUiMode.FAINT_SWITCH &&
|
||||||
globalScene.findModifier(
|
globalScene.getPlayerField()[this.fieldIndex].heldItemManager.hasItem(HeldItemId.BATON)
|
||||||
m => m.is("SwitchEffectTransferModifier") && m.pokemonId === globalScene.getPlayerField()[this.fieldIndex].id,
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,14 +1159,6 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getItemModifiers(pokemon: Pokemon): PokemonHeldItemModifier[] {
|
|
||||||
return (
|
|
||||||
(globalScene.findModifiers(
|
|
||||||
m => m.is("PokemonHeldItemModifier") && m.isTransferable && m.pokemonId === pokemon.id,
|
|
||||||
) as PokemonHeldItemModifier[]) ?? []
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateOptionsWithRememberMoveModifierMode(pokemon): void {
|
private updateOptionsWithRememberMoveModifierMode(pokemon): void {
|
||||||
const learnableMoves = pokemon.getLearnableLevelMoves();
|
const learnableMoves = pokemon.getLearnableLevelMoves();
|
||||||
for (let m = 0; m < learnableMoves.length; m++) {
|
for (let m = 0; m < learnableMoves.length; m++) {
|
||||||
@ -1204,11 +1178,11 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateOptionsWithModifierTransferMode(pokemon): void {
|
private updateOptionsWithModifierTransferMode(pokemon): void {
|
||||||
const itemModifiers = this.getItemModifiers(pokemon);
|
const items = pokemon.getHeldItems();
|
||||||
for (let im = 0; im < itemModifiers.length; im++) {
|
for (let im = 0; im < items.length; im++) {
|
||||||
this.options.push(im);
|
this.options.push(im);
|
||||||
}
|
}
|
||||||
if (itemModifiers.length > 1) {
|
if (items.length > 1) {
|
||||||
this.options.push(PartyOption.ALL);
|
this.options.push(PartyOption.ALL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1335,8 +1309,8 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
break;
|
break;
|
||||||
case PartyUiMode.CHECK:
|
case PartyUiMode.CHECK:
|
||||||
if (globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase")) {
|
if (globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase")) {
|
||||||
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
|
const formChangeItems = this.getFormChangeItems(pokemon);
|
||||||
for (let i = 0; i < formChangeItemModifiers.length; i++) {
|
for (let i = 0; i < formChangeItems.length; i++) {
|
||||||
this.options.push(PartyOption.FORM_CHANGE_ITEM + i);
|
this.options.push(PartyOption.FORM_CHANGE_ITEM + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1397,10 +1371,10 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
|
const formChangeItems = this.getFormChangeItems(pokemon);
|
||||||
if (formChangeItemModifiers && option >= PartyOption.FORM_CHANGE_ITEM) {
|
if (formChangeItems && option >= PartyOption.FORM_CHANGE_ITEM) {
|
||||||
const modifier = formChangeItemModifiers[option - PartyOption.FORM_CHANGE_ITEM];
|
const item = formChangeItems[option - PartyOption.FORM_CHANGE_ITEM];
|
||||||
optionName = `${modifier.active ? i18next.t("partyUiHandler:DEACTIVATE") : i18next.t("partyUiHandler:ACTIVATE")} ${modifier.type.name}`;
|
optionName = `${pokemon.heldItemManager.hasActiveFormChangeItem(item) ? i18next.t("partyUiHandler:DEACTIVATE") : i18next.t("partyUiHandler:ACTIVATE")} ${formChangeItemName(item)}`;
|
||||||
} else if (option === PartyOption.UNPAUSE_EVOLUTION) {
|
} else if (option === PartyOption.UNPAUSE_EVOLUTION) {
|
||||||
optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:UNPAUSE_EVOLUTION") : i18next.t("partyUiHandler:PAUSE_EVOLUTION")}`;
|
optionName = `${pokemon.pauseEvolutions ? i18next.t("partyUiHandler:UNPAUSE_EVOLUTION") : i18next.t("partyUiHandler:PAUSE_EVOLUTION")}`;
|
||||||
} else {
|
} else {
|
||||||
@ -1424,9 +1398,9 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
} else if (option === PartyOption.ALL) {
|
} else if (option === PartyOption.ALL) {
|
||||||
optionName = i18next.t("partyUiHandler:ALL");
|
optionName = i18next.t("partyUiHandler:ALL");
|
||||||
} else {
|
} else {
|
||||||
const itemModifiers = this.getItemModifiers(pokemon);
|
const items = pokemon.getHeldItems();
|
||||||
const itemModifier = itemModifiers[option];
|
const item = items[option];
|
||||||
optionName = itemModifier.type.name;
|
optionName = allHeldItems[item].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const yCoord = -6 - 16 * o;
|
const yCoord = -6 - 16 * o;
|
||||||
@ -1438,19 +1412,19 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
optionText.setOrigin(0, 0);
|
optionText.setOrigin(0, 0);
|
||||||
|
|
||||||
/** For every item that has stack bigger than 1, display the current quantity selection */
|
/** For every item that has stack bigger than 1, display the current quantity selection */
|
||||||
const itemModifiers = this.getItemModifiers(pokemon);
|
const items = pokemon.getHeldItems();
|
||||||
const itemModifier = itemModifiers[option];
|
const item = items[option];
|
||||||
if (
|
if (
|
||||||
this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER &&
|
this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER &&
|
||||||
this.transferQuantitiesMax[option] > 1 &&
|
this.transferQuantitiesMax[option] > 1 &&
|
||||||
!this.transferMode &&
|
!this.transferMode &&
|
||||||
itemModifier !== undefined &&
|
item !== undefined &&
|
||||||
itemModifier.type.name === optionName
|
allHeldItems[item].name === optionName
|
||||||
) {
|
) {
|
||||||
let amountText = ` (${this.transferQuantities[option]})`;
|
let amountText = ` (${this.transferQuantities[option]})`;
|
||||||
|
|
||||||
/** If the amount held is the maximum, display the count in red */
|
/** If the amount held is the maximum, display the count in red */
|
||||||
if (this.transferQuantitiesMax[option] === itemModifier.getMaxHeldItemCount(undefined)) {
|
if (this.transferQuantitiesMax[option] === allHeldItems[item].maxStackCount) {
|
||||||
amountText = `[color=${getTextColor(TextStyle.SUMMARY_RED)}]${amountText}[/color]`;
|
amountText = `[color=${getTextColor(TextStyle.SUMMARY_RED)}]${amountText}[/color]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1499,7 +1473,6 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
null,
|
null,
|
||||||
() => {
|
() => {
|
||||||
this.clearPartySlots();
|
this.clearPartySlots();
|
||||||
globalScene.removePartyMemberModifiers(slotIndex);
|
|
||||||
const releasedPokemon = globalScene.getPlayerParty().splice(slotIndex, 1)[0];
|
const releasedPokemon = globalScene.getPlayerParty().splice(slotIndex, 1)[0];
|
||||||
releasedPokemon.destroy();
|
releasedPokemon.destroy();
|
||||||
this.populatePartySlots();
|
this.populatePartySlots();
|
||||||
@ -1560,29 +1533,24 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormChangeItemsModifiers(pokemon: Pokemon) {
|
getFormChangeItems(pokemon: Pokemon) {
|
||||||
let formChangeItemModifiers = globalScene.findModifiers(
|
let formChangeItems = pokemon.heldItemManager.getFormChangeItems();
|
||||||
m => m.is("PokemonFormChangeItemModifier") && m.pokemonId === pokemon.id,
|
const hasActiveFormChangeItems = pokemon.heldItemManager.getFormChangeItems().length;
|
||||||
) as PokemonFormChangeItemModifier[];
|
const ultraNecrozmaActive = pokemon.heldItemManager.hasActiveFormChangeItem(FormChangeItem.ULTRANECROZIUM_Z);
|
||||||
const ultraNecrozmaModifiers = formChangeItemModifiers.filter(
|
if (ultraNecrozmaActive) {
|
||||||
m => m.active && m.formChangeItem === FormChangeItem.ULTRANECROZIUM_Z,
|
|
||||||
);
|
|
||||||
if (ultraNecrozmaModifiers.length > 0) {
|
|
||||||
// ULTRANECROZIUM_Z is active and deactivating it should be the only option
|
// ULTRANECROZIUM_Z is active and deactivating it should be the only option
|
||||||
return ultraNecrozmaModifiers;
|
return [FormChangeItem.ULTRANECROZIUM_Z];
|
||||||
}
|
}
|
||||||
if (formChangeItemModifiers.find(m => m.active)) {
|
if (hasActiveFormChangeItems) {
|
||||||
// a form is currently active. the user has to disable the form or activate ULTRANECROZIUM_Z
|
// a form is currently active. the user has to disable the form or activate ULTRANECROZIUM_Z
|
||||||
formChangeItemModifiers = formChangeItemModifiers.filter(
|
formChangeItems = formChangeItems.filter(
|
||||||
m => m.active || m.formChangeItem === FormChangeItem.ULTRANECROZIUM_Z,
|
m => pokemon.heldItemManager.hasActiveFormChangeItem(m) || m === FormChangeItem.ULTRANECROZIUM_Z,
|
||||||
);
|
);
|
||||||
} else if (pokemon.species.speciesId === SpeciesId.NECROZMA) {
|
} else if (pokemon.species.speciesId === SpeciesId.NECROZMA) {
|
||||||
// no form is currently active. the user has to activate some form, except ULTRANECROZIUM_Z
|
// no form is currently active. the user has to activate some form, except ULTRANECROZIUM_Z
|
||||||
formChangeItemModifiers = formChangeItemModifiers.filter(
|
formChangeItems = formChangeItems.filter(m => m !== FormChangeItem.ULTRANECROZIUM_Z);
|
||||||
m => m.formChangeItem !== FormChangeItem.ULTRANECROZIUM_Z,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return formChangeItemModifiers;
|
return formChangeItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
getOptionsCursorWithScroll(): number {
|
getOptionsCursorWithScroll(): number {
|
||||||
|
@ -27,6 +27,7 @@ import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
|
|||||||
import { getBiomeName } from "#app/data/balance/biomes";
|
import { getBiomeName } from "#app/data/balance/biomes";
|
||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { modifierSortFunc } from "#app/modifier/modifier-bar";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RunInfoUiMode indicates possible overlays of RunInfoUiHandler.
|
* RunInfoUiMode indicates possible overlays of RunInfoUiHandler.
|
||||||
@ -894,7 +895,7 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (heldItemsList.length > 0) {
|
if (heldItemsList.length > 0) {
|
||||||
(heldItemsList as Modifier.PokemonHeldItemModifier[]).sort(Modifier.modifierSortFunc);
|
(heldItemsList as Modifier.PokemonHeldItemModifier[]).sort(modifierSortFunc);
|
||||||
let row = 0;
|
let row = 0;
|
||||||
for (const [index, item] of heldItemsList.entries()) {
|
for (const [index, item] of heldItemsList.entries()) {
|
||||||
if (index > 36) {
|
if (index > 36) {
|
||||||
|
@ -25,7 +25,6 @@ import { MoveCategory } from "#enums/MoveCategory";
|
|||||||
import { getPokeballAtlasKey } from "#app/data/pokeball";
|
import { getPokeballAtlasKey } from "#app/data/pokeball";
|
||||||
import { getGenderColor, getGenderSymbol } from "#app/data/gender";
|
import { getGenderColor, getGenderSymbol } from "#app/data/gender";
|
||||||
import { getLevelRelExp, getLevelTotalExp } from "#app/data/exp";
|
import { getLevelRelExp, getLevelTotalExp } from "#app/data/exp";
|
||||||
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import { getBiomeName } from "#app/data/balance/biomes";
|
import { getBiomeName } from "#app/data/balance/biomes";
|
||||||
import { getNatureName, getNatureStatMultiplier } from "#app/data/nature";
|
import { getNatureName, getNatureStatMultiplier } from "#app/data/nature";
|
||||||
@ -35,11 +34,12 @@ import { getVariantTint } from "#app/sprites/variant";
|
|||||||
import { Button } from "#enums/buttons";
|
import { Button } from "#enums/buttons";
|
||||||
import type { Ability } from "#app/data/abilities/ability";
|
import type { Ability } from "#app/data/abilities/ability";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { modifierSortFunc } from "#app/modifier/modifier";
|
import { heldItemSortFunc } from "#app/modifier/modifier-bar";
|
||||||
import { PlayerGender } from "#enums/player-gender";
|
import { PlayerGender } from "#enums/player-gender";
|
||||||
import { Stat, PERMANENT_STATS, getStatKey } from "#enums/stat";
|
import { Stat, PERMANENT_STATS, getStatKey } from "#enums/stat";
|
||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import { achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv";
|
||||||
|
import { allHeldItems } from "#app/items/all-held-items";
|
||||||
|
|
||||||
enum Page {
|
enum Page {
|
||||||
PROFILE,
|
PROFILE,
|
||||||
@ -1032,24 +1032,36 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
});
|
});
|
||||||
this.ivContainer.setVisible(false);
|
this.ivContainer.setVisible(false);
|
||||||
|
|
||||||
const itemModifiers = (
|
const heldItems = this.pokemon?.getHeldItems().sort(heldItemSortFunc);
|
||||||
globalScene.findModifiers(
|
|
||||||
m => m instanceof PokemonHeldItemModifier && m.pokemonId === this.pokemon?.id,
|
|
||||||
this.playerParty,
|
|
||||||
) as PokemonHeldItemModifier[]
|
|
||||||
).sort(modifierSortFunc);
|
|
||||||
|
|
||||||
itemModifiers.forEach((item, i) => {
|
heldItems?.forEach((itemKey, i) => {
|
||||||
const icon = item.getIcon(true);
|
const heldItem = allHeldItems[itemKey];
|
||||||
|
const icon = heldItem.createSummaryIcon(this.pokemon);
|
||||||
|
|
||||||
|
console.log(icon);
|
||||||
icon.setPosition((i % 17) * 12 + 3, 14 * Math.floor(i / 17) + 15);
|
icon.setPosition((i % 17) * 12 + 3, 14 * Math.floor(i / 17) + 15);
|
||||||
this.statsContainer.add(icon);
|
this.statsContainer.add(icon);
|
||||||
|
|
||||||
icon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 32, 32), Phaser.Geom.Rectangle.Contains);
|
icon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 32, 32), Phaser.Geom.Rectangle.Contains);
|
||||||
icon.on("pointerover", () => globalScene.ui.showTooltip(item.type.name, item.type.getDescription(), true));
|
icon.on("pointerover", () => globalScene.ui.showTooltip(heldItem.getName(), heldItem.getDescription(), true));
|
||||||
icon.on("pointerout", () => globalScene.ui.hideTooltip());
|
icon.on("pointerout", () => globalScene.ui.hideTooltip());
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
|
const formChangeItems = this.pokemon?.heldItemManager.getFormChangeItems().sort(formChangeItemSortFunc);
|
||||||
|
|
||||||
|
//TODO: Make an equivalent function for form change items
|
||||||
|
formChangeItems?.forEach((itemKey, i) => {
|
||||||
|
const icon = heldItem.createSummaryIcon(stack);
|
||||||
|
|
||||||
|
console.log(icon);
|
||||||
|
icon.setPosition((i % 17) * 12 + 3, 14 * Math.floor(i / 17) + 15);
|
||||||
|
this.statsContainer.add(icon);
|
||||||
|
|
||||||
|
icon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 32, 32), Phaser.Geom.Rectangle.Contains);
|
||||||
|
icon.on("pointerover", () => globalScene.ui.showTooltip(heldItem.getName(), heldItem.getDescription(), true));
|
||||||
|
icon.on("pointerout", () => globalScene.ui.hideTooltip());
|
||||||
|
});
|
||||||
|
*/
|
||||||
const pkmLvl = this.pokemon?.level!; // TODO: is this bang correct?
|
const pkmLvl = this.pokemon?.level!; // TODO: is this bang correct?
|
||||||
const pkmLvlExp = this.pokemon?.levelExp!; // TODO: is this bang correct?
|
const pkmLvlExp = this.pokemon?.levelExp!; // TODO: is this bang correct?
|
||||||
const pkmExp = this.pokemon?.exp!; // TODO: is this bang correct?
|
const pkmExp = this.pokemon?.exp!; // TODO: is this bang correct?
|
||||||
|
@ -6,9 +6,9 @@ import { getMoveTargets } from "#app/data/moves/move-utils";
|
|||||||
import { Button } from "#enums/buttons";
|
import { Button } from "#enums/buttons";
|
||||||
import type { MoveId } from "#enums/move-id";
|
import type { MoveId } from "#enums/move-id";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { ModifierBar } from "#app/modifier/modifier";
|
|
||||||
import { SubstituteTag } from "#app/data/battler-tags";
|
import { SubstituteTag } from "#app/data/battler-tags";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import type { ModifierBar } from "#app/modifier/modifier-bar";
|
||||||
|
|
||||||
export type TargetSelectCallback = (targets: BattlerIndex[]) => void;
|
export type TargetSelectCallback = (targets: BattlerIndex[]) => void;
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user