Merge branch 'beta' into pokemon-info-box-formName-enhancement
This commit is contained in:
commit
5f562ba4b9
|
@ -55,7 +55,7 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to
|
||||||
- Pokémon Sword/Shield
|
- Pokémon Sword/Shield
|
||||||
- Pokémon Legends: Arceus
|
- Pokémon Legends: Arceus
|
||||||
- Pokémon Scarlet/Violet
|
- Pokémon Scarlet/Violet
|
||||||
- Firel (Custom Laboratory, Metropolis, Seabed, and Space biome music)
|
- Firel (Custom Ice Cave, Laboratory, Metropolis, Plains, Power Plant, Seabed, Space, and Volcano biome music)
|
||||||
- Lmz (Custom Jungle biome music)
|
- Lmz (Custom Jungle biome music)
|
||||||
- Andr06 (Custom Slum and Sea biome music)
|
- Andr06 (Custom Slum and Sea biome music)
|
||||||
|
|
||||||
|
|
28
index.css
28
index.css
|
@ -26,10 +26,36 @@ body {
|
||||||
#app {
|
#app {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app > div:first-child {
|
#app > div:first-child {
|
||||||
transform-origin: top !important;
|
transform-origin: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Supports automatic vertical centering as suggested in PR#1114, but only via CSS
|
||||||
|
|
||||||
|
Condition factorized to deduce CSS rules:
|
||||||
|
true if (isLandscape && !isMobile() && !hasTouchscreen() || (hasTouchscreen() && !isTouchControlsEnabled))
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* isLandscape && !isMobile() && !hasTouchscreen() */
|
||||||
|
@media (orientation: landscape) and (pointer: fine) {
|
||||||
|
#app {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (pointer: coarse) {
|
||||||
|
/* hasTouchscreen() && !isTouchControlsEnabled */
|
||||||
|
body:has(> #touchControls[class=visible]) #app {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
body:has(> #touchControls[class=visible]) #app > div:first-child {
|
||||||
|
transform-origin: top !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#layout:fullscreen #dpad, #layout:fullscreen {
|
#layout:fullscreen #dpad, #layout:fullscreen {
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2625,7 +2625,11 @@ export class PreStatStageChangeAbAttr extends AbAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protect one or all {@linkcode BattleStat} from reductions caused by other Pokémon's moves and Abilities
|
||||||
|
*/
|
||||||
export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
|
export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
|
||||||
|
/** {@linkcode BattleStat} to protect or `undefined` if **all** {@linkcode BattleStat} are protected */
|
||||||
private protectedStat?: BattleStat;
|
private protectedStat?: BattleStat;
|
||||||
|
|
||||||
constructor(protectedStat?: BattleStat) {
|
constructor(protectedStat?: BattleStat) {
|
||||||
|
@ -2634,7 +2638,17 @@ export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
|
||||||
this.protectedStat = protectedStat;
|
this.protectedStat = protectedStat;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, _args: any[]): boolean {
|
/**
|
||||||
|
* Apply the {@linkcode ProtectedStatAbAttr} to an interaction
|
||||||
|
* @param _pokemon
|
||||||
|
* @param _passive
|
||||||
|
* @param simulated
|
||||||
|
* @param stat the {@linkcode BattleStat} being affected
|
||||||
|
* @param cancelled The {@linkcode Utils.BooleanHolder} that will be set to true if the stat is protected
|
||||||
|
* @param _args
|
||||||
|
* @returns true if the stat is protected, false otherwise
|
||||||
|
*/
|
||||||
|
applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, _args: any[]): boolean {
|
||||||
if (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) {
|
if (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) {
|
||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -3757,7 +3771,7 @@ export class StatStageChangeMultiplierAbAttr extends AbAttr {
|
||||||
this.multiplier = multiplier;
|
this.multiplier = multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
(args[0] as Utils.IntegerHolder).value *= this.multiplier;
|
(args[0] as Utils.IntegerHolder).value *= this.multiplier;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -488,14 +488,14 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
||||||
} else {
|
} else {
|
||||||
moveAnims.set(move, null);
|
moveAnims.set(move, null);
|
||||||
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP;
|
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP;
|
||||||
const moveName = Moves[move].toLowerCase().replace(/\_/g, "-");
|
|
||||||
const fetchAnimAndResolve = (move: Moves) => {
|
const fetchAnimAndResolve = (move: Moves) => {
|
||||||
scene.cachedFetch(`./battle-anims/${moveName}.json`)
|
scene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const contentType = response.headers.get("content-type");
|
const contentType = response.headers.get("content-type");
|
||||||
if (!response.ok || contentType?.indexOf("application/json") === -1) {
|
if (!response.ok || contentType?.indexOf("application/json") === -1) {
|
||||||
console.error(`Could not load animation file for move '${moveName}'`, response.status, response.statusText);
|
useDefaultAnim(move, defaultMoveAnim);
|
||||||
populateMoveAnim(move, moveAnims.get(defaultMoveAnim));
|
logMissingMoveAnim(move, response.status, response.statusText);
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
|
@ -515,6 +515,11 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
useDefaultAnim(move, defaultMoveAnim);
|
||||||
|
logMissingMoveAnim(move, error);
|
||||||
|
return resolve();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
fetchAnimAndResolve(move);
|
fetchAnimAndResolve(move);
|
||||||
|
@ -522,6 +527,29 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the default animation for the given move.
|
||||||
|
*
|
||||||
|
* @param move the move to populate an animation for
|
||||||
|
* @param defaultMoveAnim the move to use as the default animation
|
||||||
|
*/
|
||||||
|
function useDefaultAnim(move: Moves, defaultMoveAnim: Moves) {
|
||||||
|
populateMoveAnim(move, moveAnims.get(defaultMoveAnim));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for printing a warning to the console when a move animation is missing.
|
||||||
|
*
|
||||||
|
* @param move the move to populate an animation for
|
||||||
|
* @param optionalParams parameters to add to the error logging
|
||||||
|
*
|
||||||
|
* @remarks use {@linkcode useDefaultAnim} to use a default animation
|
||||||
|
*/
|
||||||
|
function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
|
||||||
|
const moveName = Utils.animationFileName(move);
|
||||||
|
console.warn(`Could not load animation file for move '${moveName}'`, ...optionalParams);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches animation configs to be used in a Mystery Encounter
|
* Fetches animation configs to be used in a Mystery Encounter
|
||||||
* @param scene
|
* @param scene
|
||||||
|
|
|
@ -746,7 +746,7 @@ export class Arena {
|
||||||
case Biome.TOWN:
|
case Biome.TOWN:
|
||||||
return 7.288;
|
return 7.288;
|
||||||
case Biome.PLAINS:
|
case Biome.PLAINS:
|
||||||
return 7.693;
|
return 17.485;
|
||||||
case Biome.GRASS:
|
case Biome.GRASS:
|
||||||
return 1.995;
|
return 1.995;
|
||||||
case Biome.TALL_GRASS:
|
case Biome.TALL_GRASS:
|
||||||
|
@ -774,13 +774,13 @@ export class Arena {
|
||||||
case Biome.DESERT:
|
case Biome.DESERT:
|
||||||
return 1.143;
|
return 1.143;
|
||||||
case Biome.ICE_CAVE:
|
case Biome.ICE_CAVE:
|
||||||
return 15.010;
|
return 0.000;
|
||||||
case Biome.MEADOW:
|
case Biome.MEADOW:
|
||||||
return 3.891;
|
return 3.891;
|
||||||
case Biome.POWER_PLANT:
|
case Biome.POWER_PLANT:
|
||||||
return 2.810;
|
return 9.447;
|
||||||
case Biome.VOLCANO:
|
case Biome.VOLCANO:
|
||||||
return 5.116;
|
return 17.637;
|
||||||
case Biome.GRAVEYARD:
|
case Biome.GRAVEYARD:
|
||||||
return 3.232;
|
return 3.232;
|
||||||
case Biome.DOJO:
|
case Biome.DOJO:
|
||||||
|
|
|
@ -1273,13 +1273,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
* @param attrType {@linkcode AbAttr} The ability attribute to check for.
|
* @param attrType {@linkcode AbAttr} The ability attribute to check for.
|
||||||
* @param canApply {@linkcode Boolean} If false, it doesn't check whether the ability is currently active
|
* @param canApply {@linkcode Boolean} If false, it doesn't check whether the ability is currently active
|
||||||
* @param ignoreOverride {@linkcode Boolean} If true, it ignores ability changing effects
|
* @param ignoreOverride {@linkcode Boolean} If true, it ignores ability changing effects
|
||||||
* @returns {AbAttr[]} A list of all the ability attributes on this ability.
|
* @returns A list of all the ability attributes on this ability.
|
||||||
*/
|
*/
|
||||||
getAbilityAttrs(attrType: { new(...args: any[]): AbAttr }, canApply: boolean = true, ignoreOverride?: boolean): AbAttr[] {
|
getAbilityAttrs<T extends AbAttr = AbAttr>(attrType: { new(...args: any[]): T }, canApply: boolean = true, ignoreOverride?: boolean): T[] {
|
||||||
const abilityAttrs: AbAttr[] = [];
|
const abilityAttrs: T[] = [];
|
||||||
|
|
||||||
if (!canApply || this.canApplyAbility()) {
|
if (!canApply || this.canApplyAbility()) {
|
||||||
abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs(attrType));
|
abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs<T>(attrType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canApply || this.canApplyAbility(true)) {
|
if (!canApply || this.canApplyAbility(true)) {
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
"forest": "PMD EoS Dusk Forest",
|
"forest": "PMD EoS Dusk Forest",
|
||||||
"grass": "PMD EoS Apple Woods",
|
"grass": "PMD EoS Apple Woods",
|
||||||
"graveyard": "PMD EoS Mystifying Forest",
|
"graveyard": "PMD EoS Mystifying Forest",
|
||||||
"ice_cave": "PMD EoS Vast Ice Mountain",
|
"ice_cave": "Firel - -60F",
|
||||||
"island": "PMD EoS Craggy Coast",
|
"island": "PMD EoS Craggy Coast",
|
||||||
"jungle": "Lmz - Jungle",
|
"jungle": "Lmz - Jungle",
|
||||||
"laboratory": "Firel - Laboratory",
|
"laboratory": "Firel - Laboratory",
|
||||||
|
@ -116,8 +116,8 @@
|
||||||
"meadow": "PMD EoS Sky Peak Forest",
|
"meadow": "PMD EoS Sky Peak Forest",
|
||||||
"metropolis": "Firel - Metropolis",
|
"metropolis": "Firel - Metropolis",
|
||||||
"mountain": "PMD EoS Mt. Horn",
|
"mountain": "PMD EoS Mt. Horn",
|
||||||
"plains": "PMD EoS Sky Peak Prairie",
|
"plains": "Firel - Route 888",
|
||||||
"power_plant": "PMD EoS Far Amp Plains",
|
"power_plant": "Firel - The Klink",
|
||||||
"ruins": "PMD EoS Deep Sealed Ruin",
|
"ruins": "PMD EoS Deep Sealed Ruin",
|
||||||
"sea": "Andr06 - Marine Mystique",
|
"sea": "Andr06 - Marine Mystique",
|
||||||
"seabed": "Firel - Seabed",
|
"seabed": "Firel - Seabed",
|
||||||
|
@ -128,7 +128,7 @@
|
||||||
"tall_grass": "PMD EoS Foggy Forest",
|
"tall_grass": "PMD EoS Foggy Forest",
|
||||||
"temple": "PMD EoS Aegis Cave",
|
"temple": "PMD EoS Aegis Cave",
|
||||||
"town": "PMD EoS Random Dungeon Theme 3",
|
"town": "PMD EoS Random Dungeon Theme 3",
|
||||||
"volcano": "PMD EoS Steam Cave",
|
"volcano": "Firel - Twisturn Volcano",
|
||||||
"wasteland": "PMD EoS Hidden Highland",
|
"wasteland": "PMD EoS Hidden Highland",
|
||||||
"encounter_ace_trainer": "BW Trainers' Eyes Meet (Ace Trainer)",
|
"encounter_ace_trainer": "BW Trainers' Eyes Meet (Ace Trainer)",
|
||||||
"encounter_backpacker": "BW Trainers' Eyes Meet (Backpacker)",
|
"encounter_backpacker": "BW Trainers' Eyes Meet (Backpacker)",
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
"ALL": "전부",
|
"ALL": "전부",
|
||||||
"PASS_BATON": "배턴터치한다",
|
"PASS_BATON": "배턴터치한다",
|
||||||
"UNPAUSE_EVOLUTION": "진화 재개",
|
"UNPAUSE_EVOLUTION": "진화 재개",
|
||||||
|
"PAUSE_EVOLUTION": "진화 중지",
|
||||||
"REVIVE": "되살린다",
|
"REVIVE": "되살린다",
|
||||||
"RENAME": "닉네임 바꾸기",
|
"RENAME": "닉네임 바꾸기",
|
||||||
|
"SELECT": "선택한다",
|
||||||
"choosePokemon": "포켓몬을 선택하세요.",
|
"choosePokemon": "포켓몬을 선택하세요.",
|
||||||
"doWhatWithThisPokemon": "포켓몬을 어떻게 하겠습니까?",
|
"doWhatWithThisPokemon": "포켓몬을 어떻게 하겠습니까?",
|
||||||
"noEnergy": "{{pokemonName}}[[는]] 싸울 수 있는\n기력이 남아 있지 않습니다!",
|
"noEnergy": "{{pokemonName}}[[는]] 싸울 수 있는\n기력이 남아 있지 않습니다!",
|
||||||
|
@ -23,6 +25,7 @@
|
||||||
"tooManyItems": "{{pokemonName}}[[는]] 지닌 도구의 수가\n너무 많습니다",
|
"tooManyItems": "{{pokemonName}}[[는]] 지닌 도구의 수가\n너무 많습니다",
|
||||||
"anyEffect": "써도 효과가 없다.",
|
"anyEffect": "써도 효과가 없다.",
|
||||||
"unpausedEvolutions": "{{pokemonName}}의 진화가 재개되었다.",
|
"unpausedEvolutions": "{{pokemonName}}의 진화가 재개되었다.",
|
||||||
|
"pausedEvolutions": "{{pokemonName}}[[가]] 진화하지 않도록 했다.",
|
||||||
"unspliceConfirmation": "{{pokemonName}}로부터 {{fusionName}}의 융합을 해제하시겠습니까?\n{{fusionName}}는 사라지게 됩니다.",
|
"unspliceConfirmation": "{{pokemonName}}로부터 {{fusionName}}의 융합을 해제하시겠습니까?\n{{fusionName}}는 사라지게 됩니다.",
|
||||||
"wasReverted": "{{fusionName}}은 {{pokemonName}}의 모습으로 돌아갔습니다!",
|
"wasReverted": "{{fusionName}}은 {{pokemonName}}의 모습으로 돌아갔습니다!",
|
||||||
"releaseConfirmation": "{{pokemonName}}[[를]]\n정말 놓아주겠습니까?",
|
"releaseConfirmation": "{{pokemonName}}[[를]]\n정말 놓아주겠습니까?",
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
"expGainsSpeed": "경험치 획득 속도",
|
"expGainsSpeed": "경험치 획득 속도",
|
||||||
"expPartyDisplay": "파티 경험치 표시",
|
"expPartyDisplay": "파티 경험치 표시",
|
||||||
"skipSeenDialogues": "본 대화 생략",
|
"skipSeenDialogues": "본 대화 생략",
|
||||||
|
"eggSkip": "알 스킵",
|
||||||
|
"never": "안 함",
|
||||||
|
"always": "항상",
|
||||||
|
"ask": "확인하기",
|
||||||
"battleStyle": "시합 룰",
|
"battleStyle": "시합 룰",
|
||||||
"enableRetries": "재도전 허용",
|
"enableRetries": "재도전 허용",
|
||||||
"hideIvs": "개체값탐지기 효과 끄기",
|
"hideIvs": "개체값탐지기 효과 끄기",
|
||||||
|
|
|
@ -6,7 +6,7 @@ import Pokemon from "#app/field/pokemon";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { ResetNegativeStatStageModifier } from "#app/modifier/modifier";
|
import { ResetNegativeStatStageModifier } from "#app/modifier/modifier";
|
||||||
import { handleTutorial, Tutorial } from "#app/tutorial";
|
import { handleTutorial, Tutorial } from "#app/tutorial";
|
||||||
import * as Utils from "#app/utils";
|
import { NumberHolder, BooleanHolder } from "#app/utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { PokemonPhase } from "./pokemon-phase";
|
import { PokemonPhase } from "./pokemon-phase";
|
||||||
import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat";
|
import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat";
|
||||||
|
@ -42,17 +42,23 @@ export class StatStageChangePhase extends PokemonPhase {
|
||||||
return this.end();
|
return this.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stages = new NumberHolder(this.stages);
|
||||||
|
|
||||||
|
if (!this.ignoreAbilities) {
|
||||||
|
applyAbAttrs(StatStageChangeMultiplierAbAttr, pokemon, null, false, stages);
|
||||||
|
}
|
||||||
|
|
||||||
let simulate = false;
|
let simulate = false;
|
||||||
|
|
||||||
const filteredStats = this.stats.filter(stat => {
|
const filteredStats = this.stats.filter(stat => {
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
|
|
||||||
if (!this.selfTarget && this.stages < 0) {
|
if (!this.selfTarget && stages.value < 0) {
|
||||||
// TODO: Include simulate boolean when tag applications can be simulated
|
// TODO: Include simulate boolean when tag applications can be simulated
|
||||||
this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, cancelled);
|
this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cancelled.value && !this.selfTarget && this.stages < 0) {
|
if (!cancelled.value && !this.selfTarget && stages.value < 0) {
|
||||||
applyPreStatStageChangeAbAttrs(ProtectStatAbAttr, pokemon, stat, cancelled, simulate);
|
applyPreStatStageChangeAbAttrs(ProtectStatAbAttr, pokemon, stat, cancelled, simulate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,12 +70,6 @@ export class StatStageChangePhase extends PokemonPhase {
|
||||||
return !cancelled.value;
|
return !cancelled.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const stages = new Utils.IntegerHolder(this.stages);
|
|
||||||
|
|
||||||
if (!this.ignoreAbilities) {
|
|
||||||
applyAbAttrs(StatStageChangeMultiplierAbAttr, pokemon, null, false, stages);
|
|
||||||
}
|
|
||||||
|
|
||||||
const relLevels = filteredStats.map(s => (stages.value >= 1 ? Math.min(pokemon.getStatStage(s) + stages.value, 6) : Math.max(pokemon.getStatStage(s) + stages.value, -6)) - pokemon.getStatStage(s));
|
const relLevels = filteredStats.map(s => (stages.value >= 1 ? Math.min(pokemon.getStatStage(s) + stages.value, 6) : Math.max(pokemon.getStatStage(s) + stages.value, -6)) - pokemon.getStatStage(s));
|
||||||
|
|
||||||
this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels);
|
this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels);
|
||||||
|
|
|
@ -31,7 +31,7 @@ describe("Abilities - Contrary", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should invert stat changes when applied", async() => {
|
it("should invert stat changes when applied", async() => {
|
||||||
await game.startBattle([
|
await game.classicMode.startBattle([
|
||||||
Species.SLOWBRO
|
Species.SLOWBRO
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -39,4 +39,39 @@ describe("Abilities - Contrary", () => {
|
||||||
|
|
||||||
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
|
describe("With Clear Body", () => {
|
||||||
|
it("should apply positive effects", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyPassiveAbility(Abilities.CLEAR_BODY)
|
||||||
|
.moveset([Moves.TAIL_WHIP]);
|
||||||
|
await game.classicMode.startBattle([Species.SLOWBRO]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
||||||
|
|
||||||
|
game.move.select(Moves.TAIL_WHIP);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should block negative effects", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyPassiveAbility(Abilities.CLEAR_BODY)
|
||||||
|
.enemyMoveset([Moves.HOWL, Moves.HOWL, Moves.HOWL, Moves.HOWL])
|
||||||
|
.moveset([Moves.SPLASH]);
|
||||||
|
await game.classicMode.startBattle([Species.SLOWBRO]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -162,7 +162,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
|
||||||
this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains);
|
this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains);
|
||||||
this.add(this.splicedIcon);
|
this.add(this.splicedIcon);
|
||||||
|
|
||||||
this.statusIndicator = this.scene.add.sprite(0, 0, `statuses_${i18next.resolvedLanguage}`);
|
this.statusIndicator = this.scene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses"));
|
||||||
this.statusIndicator.setName("icon_status");
|
this.statusIndicator.setName("icon_status");
|
||||||
this.statusIndicator.setVisible(false);
|
this.statusIndicator.setVisible(false);
|
||||||
this.statusIndicator.setOrigin(0, 0);
|
this.statusIndicator.setOrigin(0, 0);
|
||||||
|
|
|
@ -91,7 +91,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
|
||||||
valuesBg.setOrigin(0, 0);
|
valuesBg.setOrigin(0, 0);
|
||||||
this.val.add(valuesBg);
|
this.val.add(valuesBg);
|
||||||
|
|
||||||
this.typ = this.scene.add.sprite(25, EFF_HEIGHT - 35, `types${Utils.verifyLang(i18next.language) ? `_${i18next.language}` : ""}`, "unknown");
|
this.typ = this.scene.add.sprite(25, EFF_HEIGHT - 35, Utils.getLocalizedSpriteKey("types"), "unknown");
|
||||||
this.typ.setScale(0.8);
|
this.typ.setScale(0.8);
|
||||||
this.val.add(this.typ);
|
this.val.add(this.typ);
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
|
||||||
this.pow.setText(move.power >= 0 ? move.power.toString() : "---");
|
this.pow.setText(move.power >= 0 ? move.power.toString() : "---");
|
||||||
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
|
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
|
||||||
this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---");
|
this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---");
|
||||||
this.typ.setTexture(`types${Utils.verifyLang(i18next.language) ? `_${i18next.language}` : ""}`, Type[move.type].toLowerCase());
|
this.typ.setTexture(Utils.getLocalizedSpriteKey("types"), Type[move.type].toLowerCase());
|
||||||
this.cat.setFrame(MoveCategory[move.category].toLowerCase());
|
this.cat.setFrame(MoveCategory[move.category].toLowerCase());
|
||||||
|
|
||||||
this.desc.setText(move?.effect || "");
|
this.desc.setText(move?.effect || "");
|
||||||
|
|
|
@ -1272,7 +1272,7 @@ class PartySlot extends Phaser.GameObjects.Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.pokemon.status) {
|
if (this.pokemon.status) {
|
||||||
const statusIndicator = this.scene.add.sprite(0, 0, `statuses_${i18next.resolvedLanguage}`);
|
const statusIndicator = this.scene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses"));
|
||||||
statusIndicator.setFrame(StatusEffect[this.pokemon.status?.effect].toLowerCase());
|
statusIndicator.setFrame(StatusEffect[this.pokemon.status?.effect].toLowerCase());
|
||||||
statusIndicator.setOrigin(0, 0);
|
statusIndicator.setOrigin(0, 0);
|
||||||
statusIndicator.setPositionRelative(slotLevelLabel, this.slotIndex >= battlerCount ? 43 : 55, 0);
|
statusIndicator.setPositionRelative(slotLevelLabel, this.slotIndex >= battlerCount ? 43 : 55, 0);
|
||||||
|
|
|
@ -214,7 +214,7 @@ export default class SummaryUiHandler extends UiHandler {
|
||||||
|
|
||||||
this.statusContainer.add(statusLabel);
|
this.statusContainer.add(statusLabel);
|
||||||
|
|
||||||
this.status = this.scene.add.sprite(91, 4, `statuses_${i18next.resolvedLanguage}`);
|
this.status = this.scene.add.sprite(91, 4, Utils.getLocalizedSpriteKey("statuses"));
|
||||||
this.status.setOrigin(0.5, 0);
|
this.status.setOrigin(0.5, 0);
|
||||||
|
|
||||||
this.statusContainer.add(this.status);
|
this.statusContainer.add(this.status);
|
||||||
|
|
10
src/utils.ts
10
src/utils.ts
|
@ -1,4 +1,5 @@
|
||||||
import { MoneyFormat } from "#enums/money-format";
|
import { MoneyFormat } from "#enums/money-format";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export const MissingTextureKey = "__MISSING";
|
export const MissingTextureKey = "__MISSING";
|
||||||
|
@ -628,3 +629,12 @@ export function getLocalizedSpriteKey(baseKey: string) {
|
||||||
export function isBetween(num: number, min: number, max: number): boolean {
|
export function isBetween(num: number, min: number, max: number): boolean {
|
||||||
return num >= min && num <= max;
|
return num >= min && num <= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to return the animation filename for a given move
|
||||||
|
*
|
||||||
|
* @param move the move for which the animation filename is needed
|
||||||
|
*/
|
||||||
|
export function animationFileName(move: Moves): string {
|
||||||
|
return Moves[move].toLowerCase().replace(/\_/g, "-");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue