[Item] Add Light Ball, Thick Club, Metal Powder, and Quick Powder (#1899)
* Add Light Ball, Thick Club, and Metal/Quick Powder * Fix Typo, Account for Fusions * Fix Errors with Fusions * Group Items into Generator * Refactor Generator and Type, Fix Localization (en) * Adjust Generator, Add Override Type * Fix Enum Import * Localize for de, es, fr, it, ko, zh_CN, zh_TW * Add Unit Tests * Add Type * Fix Items Atlas * Change Cubone Passive Ability, Adjust Weight
This commit is contained in:
parent
74a7b1bb79
commit
f7f8988cdb
13336
public/images/items.json
13336
public/images/items.json
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 132 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
|
@ -3327,7 +3327,7 @@ export const starterPassiveAbilities = {
|
|||
[Species.KRABBY]: Abilities.UNBURDEN,
|
||||
[Species.VOLTORB]: Abilities.ELECTRIC_SURGE,
|
||||
[Species.EXEGGCUTE]: Abilities.RIPEN,
|
||||
[Species.CUBONE]: Abilities.HUGE_POWER,
|
||||
[Species.CUBONE]: Abilities.PARENTAL_BOND,
|
||||
[Species.LICKITUNG]: Abilities.THICK_FAT,
|
||||
[Species.KOFFING]: Abilities.PARENTAL_BOND,
|
||||
[Species.RHYHORN]: Abilities.FILTER,
|
||||
|
|
|
@ -10,7 +10,7 @@ import * as Utils from "../utils";
|
|||
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type";
|
||||
import { getLevelTotalExp } from "../data/exp";
|
||||
import { Stat } from "../data/pokemon-stat";
|
||||
import { AttackTypeBoosterModifier, DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonMultiHitModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, EvolutionStatBoosterModifier, TerastallizeModifier } from "../modifier/modifier";
|
||||
import { AttackTypeBoosterModifier, DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonMultiHitModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, StatBoosterModifier, TerastallizeModifier } from "../modifier/modifier";
|
||||
import { PokeballType } from "../data/pokeball";
|
||||
import { Gender } from "../data/gender";
|
||||
import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims";
|
||||
|
@ -657,7 +657,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), battleStat as integer as TempBattleStat, statLevel);
|
||||
}
|
||||
const statValue = new Utils.NumberHolder(this.getStat(stat));
|
||||
this.scene.applyModifiers(EvolutionStatBoosterModifier, this.isPlayer(), this, stat, statValue);
|
||||
this.scene.applyModifiers(StatBoosterModifier, this.isPlayer(), this, stat, statValue);
|
||||
|
||||
const fieldApplied = new Utils.BooleanHolder(false);
|
||||
for (const pokemon of this.scene.getField(true)) {
|
||||
|
|
|
@ -35,6 +35,7 @@ export interface ModifierTypeTranslationEntry {
|
|||
|
||||
export interface ModifierTypeTranslationEntries {
|
||||
ModifierType: { [key: string]: ModifierTypeTranslationEntry },
|
||||
SpeciesBoosterItem: { [key: string]: ModifierTypeTranslationEntry },
|
||||
AttackTypeBoosterItem: SimpleTranslationEntries,
|
||||
TempBattleStatBoosterItem: SimpleTranslationEntries,
|
||||
TempBattleStatBoosterStatName: SimpleTranslationEntries,
|
||||
|
|
|
@ -242,6 +242,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_FUSED_CHANCE": { "name": "Fusionsmarke", "description": "Fügt eine 1%ige Chance hinzu, dass ein wildes Pokémon eine Fusion ist." },
|
||||
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "Kugelblitz", description: "Ein Item, das von Pikachu getragen werden kann. Es erhöht den Angriff und den Spezial-Angriff." },
|
||||
"THICK_CLUB": { name: "Kampfknochen", description: "Ein Item, das von Tragosso oder Knogga getragen werden kann. Dieser harte Knochen erhöht den Angriff." },
|
||||
"METAL_POWDER": { name: "Metallstaub", description: "Ein Item, das von Ditto getragen werden kann. Fein und doch hart, erhöht dieses sonderbare Pulver die Verteidigung." },
|
||||
"QUICK_POWDER": { name: "Flottstaub", description: "Ein Item, das Ditto zum Tragen gegeben werden kann. Fein und doch hart, erhöht dieses sonderbare Pulver die Initiative." }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "X-Angriff",
|
||||
"x_defense": "X-Verteidigung",
|
||||
|
|
|
@ -241,6 +241,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_ENDURE_CHANCE": { name: "Endure Token" },
|
||||
"ENEMY_FUSED_CHANCE": { name: "Fusion Token", description: "Adds a 1% chance that a wild Pokémon will be a fusion." },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "Light Ball", description: "It's a mysterious orb that boosts Pikachu's Attack and Sp. Atk stats." },
|
||||
"THICK_CLUB": { name: "Thick Club", description: "This hard bone of unknown origin boosts Cubone or Marowak's Attack stat." },
|
||||
"METAL_POWDER": { name: "Metal Powder", description: "Extremely fine yet hard, this odd powder boosts Ditto's Defense stat." },
|
||||
"QUICK_POWDER": { name: "Quick Powder", description: "Extremely fine yet hard, this odd powder boosts Ditto's Speed stat." }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "X Attack",
|
||||
"x_defense": "X Defense",
|
||||
|
|
|
@ -241,6 +241,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_ENDURE_CHANCE": { name: "Ficha Aguante" },
|
||||
"ENEMY_FUSED_CHANCE": { name: "Ficha Fusión", description: "Agrega un 1% de probabilidad de que un Pokémon salvaje sea una fusión." },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "Bola Luminosa", description: "Asombrosa esfera que aumenta el Ataque y el Ataque Especial. Debe llevarla Pikachu." },
|
||||
"THICK_CLUB": { name: "Hueso Grueso", description: "Extraño tipo de hueso que potencia los ataques físicos. Debe llevarlo Cubone o Marowak." },
|
||||
"METAL_POWDER": { name: "Polvo Metálico", description: "Polvo muy fino, pero a la vez poderoso, que aumenta la Defensa. Debe llevarlo Ditto." },
|
||||
"QUICK_POWDER": { name: "Polvo Veloz", description: "Polvo muy fino, pero a la vez poderoso, que aumenta la Velocidad. Debe llevarlo Ditto." }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "Ataque X",
|
||||
"x_defense": "Defensa X",
|
||||
|
|
|
@ -241,6 +241,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_ENDURE_CHANCE": { name: "Jeton Ténacité" },
|
||||
"ENEMY_FUSED_CHANCE": { name: "Jeton Fusion", description: "Ajoute 1% de chances qu’un Pokémon sauvage soit une fusion." },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "Balle Lumière", description: "Objet à faire tenir à Pikachu. Un orbe énigmatique qui augmente son Attaque et son Attaque Spéciale." },
|
||||
"THICK_CLUB": { name: "Masse Os", description: "Objet à faire tenir à Osselait ou Ossatueur. Un os dur qui augmente leur Attaque." },
|
||||
"METAL_POWDER": { name: "Poudre Métal", description: "Objet à faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, augmente sa Défense." },
|
||||
"QUICK_POWDER": { name: "Poudre Vite", description: "Objet à faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, augmente sa Vitesse." }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "Attaque +",
|
||||
"x_defense": "Défense +",
|
||||
|
|
|
@ -241,6 +241,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_ENDURE_CHANCE": { name: "Gettone di Resistenza" },
|
||||
"ENEMY_FUSED_CHANCE": { name: "Gettone della fusione", description: "Aggiunge l'1% di possibilità che un Pokémon selvatico sia una fusione." },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "Elettropalla", description: "Strumento da dare a Pikachu. Sfera insolita che aumenta l’Attacco e l’Attacco Speciale." },
|
||||
"THICK_CLUB": { name: "Osso spesso", description: "Strumento da dare a Cubone o Marowak. Osso duro che aumenta l’Attacco." },
|
||||
"METAL_POWDER": { name: "Metalpolvere", description: "Strumento da dare a Ditto. Strana polvere finissima e al tempo stesso dura che migliora la Difesa." },
|
||||
"QUICK_POWDER": { name: "Velopolvere", description: "Strumento da dare a Ditto. Questa strana polvere, fine e al contempo dura, aumenta la Velocità." }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "Attacco X",
|
||||
"x_defense": "Difesa X",
|
||||
|
|
|
@ -241,6 +241,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_ENDURE_CHANCE": { name: "버티기 토큰" },
|
||||
"ENEMY_FUSED_CHANCE": { name: "합체 토큰", description: "야생 포켓몬이 합체되어 등장할 확률이 1% 추가된다." },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "전기구슬", description: "피카츄에게 지니게 하면 공격과 특수공격이 올라가는 이상한 구슬." },
|
||||
"THICK_CLUB": { name: "굵은뼈", description: "무언가의 단단한 뼈. 탕구리 혹은 텅구리에게 지니게 하면 공격이 올라간다." },
|
||||
"METAL_POWDER": { name: "금속파우더", description: "메타몽에게 지니게 하면 방어가 올라가는 이상한 가루. 매우 잘고 단단하다." },
|
||||
"QUICK_POWDER": { name: "스피드파우더", description: "메타몽에게 지니게 하면 스피드가 올라가는 이상한 가루. 매우 잘고 단단하다." }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "플러스파워",
|
||||
"x_defense": "디펜드업",
|
||||
|
|
|
@ -241,6 +241,8 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_ENDURE_CHANCE": { name: "Token de Persistência" },
|
||||
"ENEMY_FUSED_CHANCE": { name: "Token de Fusão", description: "Adiciona uma chance de 1% de que um Pokémon selvagem seja uma fusão." },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "Ataque X",
|
||||
"x_defense": "Defesa X",
|
||||
|
|
|
@ -241,6 +241,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
"ENEMY_ENDURE_CHANCE": { name: "忍受硬币" },
|
||||
"ENEMY_FUSED_CHANCE": { name: "融合硬币", description: "增加1%野生融合宝可梦出现概率。" },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "电气球", description: "让皮卡丘携带后,攻击和特攻就会 提高的神奇之球。" },
|
||||
"THICK_CLUB": { name: "粗骨头", description: "某种坚硬的骨头。让卡拉卡拉或嘎啦嘎啦携带后,攻击就会提高。" },
|
||||
"METAL_POWDER": { name: "金属粉", description: "让百变怪携带后,防御就会提高的神奇粉末。非常细腻坚硬。" },
|
||||
"QUICK_POWDER": { name: "速度粉", description: "让百变怪携带后,速度就会提高的神奇粉末。非常细腻坚硬。" }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
"x_attack": "力量强化",
|
||||
"x_defense": "防御强化",
|
||||
|
|
|
@ -301,6 +301,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
|||
description: "增加1%野生融合寶可夢出現概率。",
|
||||
},
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
"LIGHT_BALL": { name: "電氣球", description: "讓皮卡丘攜帶後,攻擊和特攻就會 提高的神奇之球。" },
|
||||
"THICK_CLUB": { name: "粗骨頭", description: "某種堅硬的骨頭。讓卡拉卡拉或嘎啦嘎啦攜帶後,攻擊就會提高。" },
|
||||
"METAL_POWDER": { name: "金屬粉", description: "讓百變怪攜帶後,防禦就會提高的神奇粉末。非常細緻堅硬。" },
|
||||
"QUICK_POWDER": { name: "速度粉", description: "讓百變怪攜帶後,速度就會提高的神奇粉末。非常細緻堅硬。" }
|
||||
},
|
||||
TempBattleStatBoosterItem: {
|
||||
x_attack: "力量強化",
|
||||
x_defense: "防禦強化",
|
||||
|
|
|
@ -26,6 +26,7 @@ import { Abilities } from "#enums/abilities";
|
|||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
|
||||
const outputModifierData = false;
|
||||
const useMaxWeightForOutput = false;
|
||||
|
@ -539,6 +540,28 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i
|
|||
}
|
||||
}
|
||||
|
||||
export type SpeciesStatBoosterItem = keyof typeof SpeciesStatBoosterModifierTypeGenerator.items;
|
||||
|
||||
/**
|
||||
* Modifier type for {@linkcode Modifiers.SpeciesStatBoosterModifier}
|
||||
* @extends PokemonHeldItemModifierType
|
||||
* @implements GeneratedPersistentModifierType
|
||||
*/
|
||||
export class SpeciesStatBoosterModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
||||
private key: SpeciesStatBoosterItem;
|
||||
|
||||
constructor(key: SpeciesStatBoosterItem) {
|
||||
const item = SpeciesStatBoosterModifierTypeGenerator.items[key];
|
||||
super(`modifierType:SpeciesBoosterItem.${key}`, key.toLowerCase(), (type, args) => new Modifiers.SpeciesStatBoosterModifier(type, (args[0] as Pokemon).id, item.stats, item.multiplier, item.species));
|
||||
|
||||
this.id = this.key = key;
|
||||
}
|
||||
|
||||
getPregenArgs(): any[] {
|
||||
return [ this.key ];
|
||||
}
|
||||
}
|
||||
|
||||
export class PokemonLevelIncrementModifierType extends PokemonModifierType {
|
||||
constructor(localeKey: string, iconImage: string) {
|
||||
super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonLevelIncrementModifier(this, (args[0] as PlayerPokemon).id), (_pokemon: PlayerPokemon) => null);
|
||||
|
@ -870,6 +893,81 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifier type generator for {@linkcode SpeciesStatBoosterModifierType}, which
|
||||
* encapsulates the logic for weighting the most useful held item from
|
||||
* the current list of {@linkcode items}.
|
||||
* @extends ModifierTypeGenerator
|
||||
*/
|
||||
class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
/** Object comprised of the currently available species-based stat boosting held items */
|
||||
public static items = {
|
||||
LIGHT_BALL: { stats: [Stat.ATK, Stat.SPATK], multiplier: 2, species: [Species.PIKACHU] },
|
||||
THICK_CLUB: { stats: [Stat.ATK], multiplier: 2, species: [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK] },
|
||||
METAL_POWDER: { stats: [Stat.DEF], multiplier: 2, species: [Species.DITTO] },
|
||||
QUICK_POWDER: { stats: [Stat.SPD], multiplier: 2, species: [Species.DITTO] },
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super((party: Pokemon[], pregenArgs?: any[]) => {
|
||||
if (pregenArgs) {
|
||||
return new SpeciesStatBoosterModifierType(pregenArgs[0] as SpeciesStatBoosterItem);
|
||||
}
|
||||
|
||||
const values = Object.values(SpeciesStatBoosterModifierTypeGenerator.items);
|
||||
const keys = Object.keys(SpeciesStatBoosterModifierTypeGenerator.items);
|
||||
const weights = keys.map(() => 0);
|
||||
|
||||
for (const p of party) {
|
||||
const speciesId = p.getSpeciesForm(true).speciesId;
|
||||
const fusionSpeciesId = p.isFusion() ? p.getFusionSpeciesForm(true).speciesId : null;
|
||||
const hasFling = p.getMoveset(true).some(m => m.moveId === Moves.FLING);
|
||||
|
||||
for (const i in values) {
|
||||
const checkedSpecies = values[i].species;
|
||||
const checkedStats = values[i].stats;
|
||||
|
||||
// If party member already has the item being weighted currently, skip to the next item
|
||||
const hasItem = p.getHeldItems().some(m => m instanceof Modifiers.SpeciesStatBoosterModifier
|
||||
&& (m as Modifiers.SpeciesStatBoosterModifier).contains(checkedSpecies[0], checkedStats[0]));
|
||||
|
||||
if (!hasItem) {
|
||||
if (checkedSpecies.includes(speciesId) || (!!fusionSpeciesId && checkedSpecies.includes(fusionSpeciesId))) {
|
||||
// Add weight if party member has a matching species or, if applicable, a matching fusion species
|
||||
weights[i]++;
|
||||
} else if (checkedSpecies.includes(Species.PIKACHU) && hasFling) {
|
||||
// Add weight to Light Ball if party member has Fling
|
||||
weights[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let totalWeight = 0;
|
||||
for (const weight of weights) {
|
||||
totalWeight += weight;
|
||||
}
|
||||
|
||||
if (totalWeight !== 0) {
|
||||
const randInt = Utils.randSeedInt(totalWeight, 1);
|
||||
let weight = 0;
|
||||
|
||||
for (const i in weights) {
|
||||
if (weights[i] !== 0) {
|
||||
const curWeight = weight + weights[i];
|
||||
if (randInt <= weight + weights[i]) {
|
||||
return new SpeciesStatBoosterModifierType(keys[i] as SpeciesStatBoosterItem);
|
||||
}
|
||||
weight = curWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TmModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
constructor(tier: ModifierTier) {
|
||||
super((party: Pokemon[]) => {
|
||||
|
@ -1110,6 +1208,8 @@ export const modifierTypes = {
|
|||
SUPER_LURE: () => new DoubleBattleChanceBoosterModifierType("modifierType:ModifierType.SUPER_LURE", "super_lure", 10),
|
||||
MAX_LURE: () => new DoubleBattleChanceBoosterModifierType("modifierType:ModifierType.MAX_LURE", "max_lure", 25),
|
||||
|
||||
SPECIES_STAT_BOOSTER: () => new SpeciesStatBoosterModifierTypeGenerator(),
|
||||
|
||||
TEMP_STAT_BOOSTER: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
|
||||
if (pregenArgs) {
|
||||
return new TempBattleStatBoosterModifierType(pregenArgs[0] as TempBattleStat);
|
||||
|
@ -1369,6 +1469,7 @@ const modifierPool: ModifierPool = {
|
|||
new WeightedModifierType(modifierTypes.RARE_EVOLUTION_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * 4, 32), 32),
|
||||
new WeightedModifierType(modifierTypes.AMULET_COIN, 3),
|
||||
//new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))) && !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier)) ? 10 : 0),
|
||||
new WeightedModifierType(modifierTypes.SPECIES_STAT_BOOSTER, 12),
|
||||
new WeightedModifierType(modifierTypes.TOXIC_ORB, (party: Pokemon[]) => {
|
||||
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD];
|
||||
const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT];
|
||||
|
|
|
@ -23,6 +23,7 @@ import { Nature } from "#app/data/nature";
|
|||
import * as Overrides from "../overrides";
|
||||
import { ModifierType, modifierTypes } from "./modifier-type";
|
||||
import { Command } from "#app/ui/command-ui-handler.js";
|
||||
import { Species } from "#enums/species";
|
||||
|
||||
import { allMoves } from "#app/data/move.js";
|
||||
import { Abilities } from "#app/enums/abilities.js";
|
||||
|
@ -707,16 +708,16 @@ export class PokemonBaseStatModifier extends PokemonHeldItemModifier {
|
|||
}
|
||||
|
||||
/**
|
||||
* Modifier used for held items, specifically Eviolite, that apply
|
||||
* {@linkcode Stat} boost(s) using a multiplier if the holder can evolve.
|
||||
* Modifier used for held items that apply {@linkcode Stat} boost(s)
|
||||
* using a multiplier.
|
||||
* @extends PokemonHeldItemModifier
|
||||
* @see {@linkcode apply}
|
||||
*/
|
||||
export class EvolutionStatBoosterModifier extends PokemonHeldItemModifier {
|
||||
export class StatBoosterModifier extends PokemonHeldItemModifier {
|
||||
/** The stats that the held item boosts */
|
||||
private stats: Stat[];
|
||||
protected stats: Stat[];
|
||||
/** The multiplier used to increase the relevant stat(s) */
|
||||
private multiplier: number;
|
||||
protected multiplier: number;
|
||||
|
||||
constructor(type: ModifierType, pokemonId: integer, stats: Stat[], multiplier: number, stackCount?: integer) {
|
||||
super(type, pokemonId, stackCount);
|
||||
|
@ -726,7 +727,7 @@ export class EvolutionStatBoosterModifier extends PokemonHeldItemModifier {
|
|||
}
|
||||
|
||||
clone() {
|
||||
return new EvolutionStatBoosterModifier(this.type, this.pokemonId, this.stats, this.multiplier, this.stackCount);
|
||||
return new StatBoosterModifier(this.type, this.pokemonId, this.stats, this.multiplier, this.stackCount);
|
||||
}
|
||||
|
||||
getArgs(): any[] {
|
||||
|
@ -734,7 +735,14 @@ export class EvolutionStatBoosterModifier extends PokemonHeldItemModifier {
|
|||
}
|
||||
|
||||
matchType(modifier: Modifier): boolean {
|
||||
return modifier instanceof EvolutionStatBoosterModifier;
|
||||
if (modifier instanceof StatBoosterModifier) {
|
||||
const modifierInstance = modifier as StatBoosterModifier;
|
||||
if ((modifierInstance.multiplier === this.multiplier) && (modifierInstance.stats.length === this.stats.length)) {
|
||||
return modifierInstance.stats.every((e, i) => e === this.stats[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -748,6 +756,42 @@ export class EvolutionStatBoosterModifier extends PokemonHeldItemModifier {
|
|||
return this.stats.includes(args[1] as Stat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Boosts the incoming stat by a {@linkcode multiplier} if the stat is listed
|
||||
* in {@linkcode stats}.
|
||||
* @param args [0] {@linkcode Pokemon} N/A
|
||||
* [1] {@linkcode Stat} N/A
|
||||
* [2] {@linkcode Utils.NumberHolder} that holds the resulting value of the stat
|
||||
* @returns true if the stat boost applies successfully, false otherwise
|
||||
* @see shouldApply
|
||||
*/
|
||||
apply(args: any[]): boolean {
|
||||
const statValue = args[2] as Utils.NumberHolder;
|
||||
|
||||
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 EvolutionStatBoosterModifier extends StatBoosterModifier {
|
||||
clone() {
|
||||
return super.clone() as EvolutionStatBoosterModifier;
|
||||
}
|
||||
|
||||
matchType(modifier: Modifier): boolean {
|
||||
return modifier instanceof EvolutionStatBoosterModifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boosts the incoming stat value by a {@linkcode multiplier} if the holder
|
||||
* can evolve. Note that, if the holder is a fusion, they will receive
|
||||
|
@ -771,15 +815,69 @@ export class EvolutionStatBoosterModifier extends PokemonHeldItemModifier {
|
|||
return true;
|
||||
} else if (isUnevolved) {
|
||||
// Full boost applied if holder is unfused and unevolved or, if fused, both parts of fusion are unevolved
|
||||
statValue.value *= this.multiplier;
|
||||
return true;
|
||||
return super.apply(args);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifier used for held items that apply {@linkcode Stat} boost(s) using a
|
||||
* multiplier if the holder is of a specific {@linkcode Species}.
|
||||
* @extends StatBoosterModifier
|
||||
* @see {@linkcode apply}
|
||||
*/
|
||||
export class SpeciesStatBoosterModifier extends StatBoosterModifier {
|
||||
/** The species that the held item's stat boost(s) apply to */
|
||||
private species: Species[];
|
||||
|
||||
constructor(type: ModifierType, pokemonId: integer, stats: Stat[], multiplier: number, species: Species[], stackCount?: integer) {
|
||||
super(type, pokemonId, stats, multiplier, stackCount);
|
||||
|
||||
this.species = species;
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new SpeciesStatBoosterModifier(this.type, this.pokemonId, this.stats, this.multiplier, this.species, this.stackCount);
|
||||
}
|
||||
|
||||
getArgs(): any[] {
|
||||
return [ ...super.getArgs(), this.species ];
|
||||
}
|
||||
|
||||
matchType(modifier: Modifier): boolean {
|
||||
if (modifier instanceof SpeciesStatBoosterModifier) {
|
||||
const modifierInstance = modifier as SpeciesStatBoosterModifier;
|
||||
if (modifierInstance.species.length === this.species.length) {
|
||||
return super.matchType(modifier) && modifierInstance.species.every((e, i) => e === this.species[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getMaxHeldItemCount(_pokemon: Pokemon): integer {
|
||||
return 1;
|
||||
/**
|
||||
* Checks if the incoming stat is listed in {@linkcode stats} and if the holder's {@linkcode Species}
|
||||
* (or its fused species) is listed in {@linkcode species}.
|
||||
* @param args [0] {@linkcode Pokemon} that holds the held item
|
||||
* [1] {@linkcode Stat} being checked at the time
|
||||
* [2] {@linkcode Utils.NumberHolder} N/A
|
||||
* @returns true if the stat could be boosted, false otherwise
|
||||
*/
|
||||
shouldApply(args: any[]): boolean {
|
||||
const holder = args[0] as Pokemon;
|
||||
return super.shouldApply(args) && (this.species.includes(holder.getSpeciesForm(true).speciesId) || (holder.isFusion() && this.species.includes(holder.getFusionSpeciesForm(true).speciesId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if either parameter is included in the corresponding lists
|
||||
* @param speciesId {@linkcode Species} 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: Species, stat: Stat): boolean {
|
||||
return this.species.includes(speciesId) && this.stats.includes(stat);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { PokeballCounts } from "./battle-scene";
|
|||
import { PokeballType } from "./data/pokeball";
|
||||
import { Gender } from "./data/gender";
|
||||
import { StatusEffect } from "./data/status-effect";
|
||||
import { modifierTypes } from "./modifier/modifier-type";
|
||||
import { SpeciesStatBoosterItem, modifierTypes } from "./modifier/modifier-type";
|
||||
import { VariantTier } from "./enums/variant-tiers";
|
||||
import { EggTier } from "#enums/egg-type";
|
||||
import { allSpecies } from "./data/pokemon-species"; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
|
@ -125,11 +125,12 @@ export const EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0;
|
|||
* - Nature is for MINT
|
||||
* - Type is for TERA_SHARD or ATTACK_TYPE_BOOSTER (type boosting items i.e Silk Scarf)
|
||||
* - BerryType is for BERRY
|
||||
* - SpeciesStatBoosterItem is for SPECIES_STAT_BOOSTER
|
||||
*/
|
||||
interface ModifierOverride {
|
||||
name: keyof typeof modifierTypes & string,
|
||||
count?: integer
|
||||
type?: TempBattleStat|Stat|Nature|Type|BerryType
|
||||
type?: TempBattleStat|Stat|Nature|Type|BerryType|SpeciesStatBoosterItem
|
||||
}
|
||||
export const STARTING_MODIFIER_OVERRIDE: Array<ModifierOverride> = [];
|
||||
export const OPP_MODIFIER_OVERRIDE: Array<ModifierOverride> = [];
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import Phase from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#app/data/pokemon-stat";
|
||||
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import * as Utils from "#app/utils";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
|
||||
describe("Items - Light Ball", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phase.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("LIGHT_BALL activates in battle correctly", async() => {
|
||||
vi.spyOn(overrides, "STARTING_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([{ name: "SPECIES_STAT_BOOSTER", type: "LIGHT_BALL" }]);
|
||||
const consoleSpy = vi.spyOn(console, "log");
|
||||
await game.startBattle([
|
||||
Species.PIKACHU
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
// Checking consoe log to make sure Light Ball is applied when getBattleStat (with the appropriate stat) is called
|
||||
partyMember.getBattleStat(Stat.DEF);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.LIGHT_BALL.name"), "");
|
||||
|
||||
// Printing dummy console messages along the way so subsequent checks don't pass because of the first
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPDEF);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.LIGHT_BALL.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.ATK);
|
||||
expect(consoleSpy).toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.LIGHT_BALL.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPATK);
|
||||
expect(consoleSpy).toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.LIGHT_BALL.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPD);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.LIGHT_BALL.name"), "");
|
||||
});
|
||||
|
||||
it("LIGHT_BALL held by PIKACHU", async() => {
|
||||
await game.startBattle([
|
||||
Species.PIKACHU
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
const spAtkStat = partyMember.getStat(Stat.SPATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
|
||||
const spAtkValue = new Utils.NumberHolder(spAtkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("LIGHT_BALL held by fused PIKACHU (base)", async() => {
|
||||
await game.startBattle([
|
||||
Species.PIKACHU,
|
||||
Species.MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
const spAtkStat = partyMember.getStat(Stat.SPATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
|
||||
const spAtkValue = new Utils.NumberHolder(spAtkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("LIGHT_BALL held by fused PIKACHU (part)", async() => {
|
||||
await game.startBattle([
|
||||
Species.MAROWAK,
|
||||
Species.PIKACHU
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
const spAtkStat = partyMember.getStat(Stat.SPATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
|
||||
const spAtkValue = new Utils.NumberHolder(spAtkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("LIGHT_BALL not held by PIKACHU", async() => {
|
||||
await game.startBattle([
|
||||
Species.MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
const spAtkStat = partyMember.getStat(Stat.SPATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue);
|
||||
const spAtkValue = new Utils.NumberHolder(spAtkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
expect(spAtkValue.value / spAtkStat).toBe(1);
|
||||
}, 20000);
|
||||
});
|
|
@ -0,0 +1,176 @@
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import Phase from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#app/data/pokemon-stat";
|
||||
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import * as Utils from "#app/utils";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
|
||||
describe("Items - Metal Powder", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phase.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("METAL_POWDER activates in battle correctly", async() => {
|
||||
vi.spyOn(overrides, "STARTING_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([{ name: "SPECIES_STAT_BOOSTER", type: "METAL_POWDER" }]);
|
||||
const consoleSpy = vi.spyOn(console, "log");
|
||||
await game.startBattle([
|
||||
Species.DITTO
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
// Checking consoe log to make sure Metal Powder is applied when getBattleStat (with the appropriate stat) is called
|
||||
partyMember.getBattleStat(Stat.DEF);
|
||||
expect(consoleSpy).toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.METAL_POWDER.name"), "");
|
||||
|
||||
// Printing dummy console messages along the way so subsequent checks don't pass because of the first
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPDEF);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.METAL_POWDER.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.ATK);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.METAL_POWDER.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPATK);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.METAL_POWDER.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPD);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.METAL_POWDER.name"), "");
|
||||
});
|
||||
|
||||
it("METAL_POWDER held by DITTO", async() => {
|
||||
await game.startBattle([
|
||||
Species.DITTO
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const defStat = partyMember.getStat(Stat.DEF);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const defValue = new Utils.NumberHolder(defStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("METAL_POWDER held by fused DITTO (base)", async() => {
|
||||
await game.startBattle([
|
||||
Species.DITTO,
|
||||
Species.MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const defStat = partyMember.getStat(Stat.DEF);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const defValue = new Utils.NumberHolder(defStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("METAL_POWDER held by fused DITTO (part)", async() => {
|
||||
await game.startBattle([
|
||||
Species.MAROWAK,
|
||||
Species.DITTO
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const defStat = partyMember.getStat(Stat.DEF);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const defValue = new Utils.NumberHolder(defStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("METAL_POWDER not held by DITTO", async() => {
|
||||
await game.startBattle([
|
||||
Species.MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const defStat = partyMember.getStat(Stat.DEF);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const defValue = new Utils.NumberHolder(defStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue);
|
||||
|
||||
expect(defValue.value / defStat).toBe(1);
|
||||
}, 20000);
|
||||
});
|
|
@ -0,0 +1,176 @@
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import Phase from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#app/data/pokemon-stat";
|
||||
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import * as Utils from "#app/utils";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
|
||||
describe("Items - Quick Powder", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phase.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("QUICK_POWDER activates in battle correctly", async() => {
|
||||
vi.spyOn(overrides, "STARTING_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([{ name: "SPECIES_STAT_BOOSTER", type: "QUICK_POWDER" }]);
|
||||
const consoleSpy = vi.spyOn(console, "log");
|
||||
await game.startBattle([
|
||||
Species.DITTO
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
// Checking consoe log to make sure Quick Powder is applied when getBattleStat (with the appropriate stat) is called
|
||||
partyMember.getBattleStat(Stat.DEF);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.QUICK_POWDER.name"), "");
|
||||
|
||||
// Printing dummy console messages along the way so subsequent checks don't pass because of the first
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPDEF);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.QUICK_POWDER.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.ATK);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.QUICK_POWDER.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPATK);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.QUICK_POWDER.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPD);
|
||||
expect(consoleSpy).toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.QUICK_POWDER.name"), "");
|
||||
});
|
||||
|
||||
it("QUICK_POWDER held by DITTO", async() => {
|
||||
await game.startBattle([
|
||||
Species.DITTO
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const spdStat = partyMember.getStat(Stat.SPD);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const spdValue = new Utils.NumberHolder(spdStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("QUICK_POWDER held by fused DITTO (base)", async() => {
|
||||
await game.startBattle([
|
||||
Species.DITTO,
|
||||
Species.MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const spdStat = partyMember.getStat(Stat.SPD);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const spdValue = new Utils.NumberHolder(spdStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("QUICK_POWDER held by fused DITTO (part)", async() => {
|
||||
await game.startBattle([
|
||||
Species.MAROWAK,
|
||||
Species.DITTO
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const spdStat = partyMember.getStat(Stat.SPD);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const spdValue = new Utils.NumberHolder(spdStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("QUICK_POWDER not held by DITTO", async() => {
|
||||
await game.startBattle([
|
||||
Species.MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const spdStat = partyMember.getStat(Stat.SPD);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const spdValue = new Utils.NumberHolder(spdStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue);
|
||||
|
||||
expect(spdValue.value / spdStat).toBe(1);
|
||||
}, 20000);
|
||||
});
|
|
@ -0,0 +1,228 @@
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import Phase from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#app/data/pokemon-stat";
|
||||
import { SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import * as Utils from "#app/utils";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
|
||||
describe("Items - Thick Club", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phase.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("THICK_CLUB activates in battle correctly", async() => {
|
||||
vi.spyOn(overrides, "STARTING_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([{ name: "SPECIES_STAT_BOOSTER", type: "THICK_CLUB" }]);
|
||||
const consoleSpy = vi.spyOn(console, "log");
|
||||
await game.startBattle([
|
||||
Species.CUBONE
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
// Checking consoe log to make sure Thick Club is applied when getBattleStat (with the appropriate stat) is called
|
||||
partyMember.getBattleStat(Stat.DEF);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.THICK_CLUB.name"), "");
|
||||
|
||||
// Printing dummy console messages along the way so subsequent checks don't pass because of the first
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPDEF);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.THICK_CLUB.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.ATK);
|
||||
expect(consoleSpy).toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.THICK_CLUB.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPATK);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.THICK_CLUB.name"), "");
|
||||
|
||||
console.log("");
|
||||
|
||||
partyMember.getBattleStat(Stat.SPD);
|
||||
expect(consoleSpy).not.toHaveBeenLastCalledWith("Applied", i18next.t("modifierType:SpeciesBoosterItem.THICK_CLUB.name"), "");
|
||||
});
|
||||
|
||||
it("THICK_CLUB held by CUBONE", async() => {
|
||||
await game.startBattle([
|
||||
Species.CUBONE
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("THICK_CLUB held by MAROWAK", async() => {
|
||||
await game.startBattle([
|
||||
Species.MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("THICK_CLUB held by ALOLA_MAROWAK", async() => {
|
||||
await game.startBattle([
|
||||
Species.ALOLA_MAROWAK
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("THICK_CLUB held by fused CUBONE line (base)", async() => {
|
||||
// Randomly choose from the Cubone line
|
||||
const species = [ Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK ];
|
||||
const randSpecies = Utils.randInt(species.length);
|
||||
|
||||
await game.startBattle([
|
||||
species[randSpecies],
|
||||
Species.PIKACHU
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("THICK_CLUB held by fused CUBONE line (part)", async() => {
|
||||
// Randomly choose from the Cubone line
|
||||
const species = [ Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK ];
|
||||
const randSpecies = Utils.randInt(species.length);
|
||||
|
||||
await game.startBattle([
|
||||
Species.PIKACHU,
|
||||
species[randSpecies]
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
const ally = game.scene.getParty()[1];
|
||||
|
||||
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||
partyMember.fusionSpecies = ally.species;
|
||||
partyMember.fusionFormIndex = ally.formIndex;
|
||||
partyMember.fusionAbilityIndex = ally.abilityIndex;
|
||||
partyMember.fusionShiny = ally.shiny;
|
||||
partyMember.fusionVariant = ally.variant;
|
||||
partyMember.fusionGender = ally.gender;
|
||||
partyMember.fusionLuck = ally.luck;
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("THICK_CLUB not held by CUBONE", async() => {
|
||||
await game.startBattle([
|
||||
Species.PIKACHU
|
||||
]);
|
||||
|
||||
const partyMember = game.scene.getParty()[0];
|
||||
|
||||
const atkStat = partyMember.getStat(Stat.ATK);
|
||||
|
||||
// Making sure modifier is not applied without holding item
|
||||
const atkValue = new Utils.NumberHolder(atkStat);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
|
||||
// Giving Eviolite to party member and testing if it applies
|
||||
partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true);
|
||||
partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue);
|
||||
|
||||
expect(atkValue.value / atkStat).toBe(1);
|
||||
}, 20000);
|
||||
});
|
Loading…
Reference in New Issue