Compare commits

..

No commits in common. "9eb57c0c661cde84064ae5a5319bd27e6d01be5f" and "17517d467b3af44f8c93e8371022a2dd5e69b971" have entirely different histories.

50 changed files with 322 additions and 508 deletions

View File

@ -176,27 +176,6 @@
"w": 12,
"h": 6
}
},
{
"filename": "HP",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 9,
"h": 8
},
"spriteSourceSize": {
"x": 1,
"y": 2,
"w": 8,
"h": 6
},
"frame": {
"x": 112,
"y": 0,
"w": 8,
"h": 6
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

After

Width:  |  Height:  |  Size: 263 B

View File

@ -281,27 +281,6 @@
"w": 9,
"h": 8
}
},
{
"filename": "empty",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 1,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 1,
"h": 8
},
"frame": {
"x": 117,
"y": 0,
"w": 1,
"h": 8
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 B

After

Width:  |  Height:  |  Size: 392 B

View File

@ -176,27 +176,6 @@
"w": 13,
"h": 7
}
},
{
"filename": "HP",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 9,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 9,
"h": 7
},
"frame": {
"x": 120,
"y": 0,
"w": 9,
"h": 7
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 B

After

Width:  |  Height:  |  Size: 278 B

View File

@ -281,27 +281,6 @@
"w": 9,
"h": 8
}
},
{
"filename": "empty",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 1,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 1,
"h": 8
},
"frame": {
"x": 117,
"y": 0,
"w": 1,
"h": 8
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 430 B

View File

@ -122,7 +122,6 @@ export default class BattleScene extends SceneBase {
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
public enableMoveInfo: boolean = true;
public enableRetries: boolean = false;
public hideIvs: boolean = false;
/**
* Determines the condition for a notification should be shown for Candy Upgrades
* - 0 = 'Off'

View File

@ -8,8 +8,7 @@ export enum BattleStat {
SPD,
ACC,
EVA,
RAND,
HP
RAND
}
export function getBattleStatName(stat: BattleStat) {
@ -28,8 +27,6 @@ export function getBattleStatName(stat: BattleStat) {
return i18next.t("pokemonInfo:Stat.ACC");
case BattleStat.EVA:
return i18next.t("pokemonInfo:Stat.EVA");
case BattleStat.HP:
return i18next.t("pokemonInfo:Stat.HPStat");
default:
return "???";
}

View File

@ -64,21 +64,21 @@ export class SpeciesFormEvolution {
public level: integer;
public item: EvolutionItem | null;
public condition: SpeciesEvolutionCondition | null;
public wildDelay: SpeciesWildEvolutionDelay;
public wildDelay: SpeciesWildEvolutionDelay | null;
constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) {
constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay | null) {
this.speciesId = speciesId;
this.preFormKey = preFormKey;
this.evoFormKey = evoFormKey;
this.level = level;
this.item = item || EvolutionItem.NONE;
this.condition = condition;
this.wildDelay = wildDelay ?? SpeciesWildEvolutionDelay.NONE;
this.wildDelay = wildDelay!; // TODO: is this bang correct?
}
}
export class SpeciesEvolution extends SpeciesFormEvolution {
constructor(speciesId: Species, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) {
constructor(speciesId: Species, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay | null) {
super(speciesId, null, null, level, item, condition, wildDelay);
}
}
@ -400,8 +400,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.LINOONE, 20, null, null)
],
[Species.WURMPLE]: [
new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)),
new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null),
new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null)
],
[Species.SILCOON]: [
new SpeciesEvolution(Species.BEAUTIFLY, 10, null, null)
@ -945,7 +945,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.SHIINOTIC, 24, null, null)
],
[Species.SALANDIT]: [
new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), null)
],
[Species.STUFFUL]: [
new SpeciesEvolution(Species.BEWEAR, 27, null, null)
@ -969,8 +969,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.COSMOEM, 43, null, null)
],
[Species.COSMOEM]: [
new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)),
new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null),
new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null)
],
[Species.MELTAN]: [
new SpeciesEvolution(Species.MELMETAL, 48, null, null)
@ -1406,9 +1406,9 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.CRABOMINABLE, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
],
[Species.ROCKRUFF]: [
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0))),
new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)),
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)))
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0)), null),
new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1), null),
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)), null)
],
[Species.STEENEE]: [
new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG)

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Gesehenen Dialog überspringen",
"battleStyle": "Kampfstil",
"enableRetries": "Erneut versuchen aktivieren",
"hideIvs": "IS-Scanner verstecken",
"tutorials": "Tutorials",
"touchControls": "Touch Steuerung",
"vibrations": "Vibration",

View File

@ -15,8 +15,7 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPD": "Speed",
"SPDshortened": "Spd",
"ACC": "Accuracy",
"EVA": "Evasiveness",
"HPStat": "HP"
"EVA": "Evasiveness"
},
Type: {

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Skip Seen Dialogues",
"battleStyle": "Battle Style",
"enableRetries": "Enable Retries",
"hideIvs": "Hide IV scanner",
"tutorials": "Tutorials",
"touchControls": "Touch Controls",
"vibrations": "Vibrations",

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Skip Seen Dialogues",
"battleStyle": "Battle Style",
"enableRetries": "Enable Retries",
"hideIvs": "Hide IV scanner",
"tutorials": "Tutorials",
"touchControls": "Touch Controls",
"vibrations": "Vibrations",

View File

@ -24,7 +24,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
}
},
"PokemonReviveModifierType": {
description: "Ranime un Pokémon et restaure {{restorePercent}}% de ses PV.",
description: "Réanime un Pokémon et restaure {{restorePercent}}% de ses PV.",
},
"PokemonStatusHealModifierType": {
description: "Soigne tous les problèmes de statut dun Pokémon.",
@ -64,13 +64,13 @@ export const modifierType: ModifierTypeTranslationEntries = {
description: "Fait monter toute léquipe de {{levels}} niveau·x.",
},
"PokemonBaseStatBoosterModifierType": {
description: "Augmente de 10% {{statName}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.",
description: "Augmente de 10% {{statName}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.",
},
"AllPokemonFullHpRestoreModifierType": {
description: "Restaure tous les PV de toute léquipe.",
description: "Restaure tous les PV de toute l'équipe.",
},
"AllPokemonFullReviveModifierType": {
description: "Ranime et restaure tous les PV de tous les Pokémon K.O. .",
description: "Réanime et restaure tous les PV de tous les Pokémon K.O.",
},
"MoneyRewardModifierType": {
description: "Octroie une {{moneyMultiplier}} somme dargent.\n({{moneyAmount}} ₽)",
@ -151,9 +151,9 @@ export const modifierType: ModifierTypeTranslationEntries = {
"SACRED_ASH": { name: "Cendre Sacrée" },
"REVIVER_SEED": { name: "Résugraine", description: "Ranime et restaure la moitié des PV de son porteur sil est mis K.O. par une capacité directe." },
"REVIVER_SEED": { name: "Résugraine", description: "Réanime et restaure la moitié des PV de son porteur sil est mis K.O. par une capacité directe." },
"WHITE_HERB": { name: "Herbe Blanche", description: "Restaure toute stat ayant subi une baisse en combat." },
"WHITE_HERB": { name: "White Herb", description: "An item to be held by a Pokémon. It will restore any lowered stat in battle." },
"ETHER": { name: "Huile" },
"MAX_ETHER": { name: "Huile Max" },
@ -184,12 +184,12 @@ export const modifierType: ModifierTypeTranslationEntries = {
"SOOTHE_BELL": { name: "Grelot Zen" },
"SCOPE_LENS": { name: "Lentilscope", description: "Une lentille qui augmente dun cran le taux de critiques du porteur." },
"LEEK": { name: "Poireau", description: "À faire tenir à Canarticho ou Palarticho. Un poireau très long et solide qui augmente de 2 crans le taux de critiques." },
"SCOPE_LENS": { name: "Lentilscope", description: "Une lentille qui augmente le taux de critiques du porteur." },
"LEEK": { name: "Poireau", description: "Objet à faire tenir à Canarticho. Un poireau très long et solide qui augmente son taux de critiques." },
"EVIOLITE": { name: "Évoluroc", description: "Augmente de 50% la Défense et Déf. Spé. si le porteur peut évoluer, 25% aux fusions dont une moitié le peut encore." },
"EVIOLITE": { name: "Évoluroc", description: "Un étrange concentré dévolution qui augmente la Défense et la Défense Spéciale dun Pokémon pouvant évoluer." },
"SOUL_DEW": { name: "Rosée Âme", description: "Augmente de 10% linfluence de la nature dun Pokémon sur ses statistiques. Effet cumulatif." },
"SOUL_DEW": { name: "Rosée Âme", description: "Augmente de 10% linfluence de la nature dun Pokémon sur ses statistiques (cumulatif)." },
"NUGGET": { name: "Pépite" },
"BIG_NUGGET": { name: "Maxi Pépite" },
@ -199,7 +199,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
"GOLDEN_PUNCH": { name: "Poing Doré", description: "50% des dégâts infligés sont convertis en argent." },
"COIN_CASE": { name: "Boite Jetons", description: "Tous les 10 combats, recevez 10% de votre argent en intérêts." },
"LOCK_CAPSULE": { name: "Poké Écrin", description: "Permet de conserver la rareté des objets si vous relancez les objets proposés." },
"LOCK_CAPSULE": { name: "Poké Écrin", description: "Permet de verrouiller des objets rares si vous relancez les objets proposés." },
"GRIP_CLAW": { name: "Accro Griffe" },
"WIDE_LENS": { name: "Loupe" },
@ -220,8 +220,8 @@ export const modifierType: ModifierTypeTranslationEntries = {
"LEFTOVERS": { name: "Restes", description: "Soigne à chaque tour 1/16 des PV max dun Pokémon." },
"SHELL_BELL": { name: "Grelot Coque", description: "Soigne son porteur avec 1/8 des dégâts quil inflige à un Pokémon." },
"TOXIC_ORB": { name: "Orbe Toxique", description: "Empoisonne gravement son porteur à la fin du tour sil na pas déjà de problème de statut." },
"FLAME_ORB": { name: "Orbe Flamme", description: "Brule son porteur à la fin du tour sil na pas déjà de problème de statut." },
"TOXIC_ORB": { name: "Orbe Toxique", description: "Un orbe bizarre qui empoisonne gravement son porteur durant le combat." },
"FLAME_ORB": { name: "Orbe Flamme", description: "Un orbe bizarre qui brule son porteur durant le combat." },
"BATON": { name: "Bâton", description: "Permet de transmettre les effets en cas de changement de Pokémon. Ignore les pièges." },
@ -242,21 +242,21 @@ export const modifierType: ModifierTypeTranslationEntries = {
"ENEMY_ATTACK_POISON_CHANCE": { name: "Jeton Poison" },
"ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Jeton Paralysie" },
"ENEMY_ATTACK_BURN_CHANCE": { name: "Jeton Brulure" },
"ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Jeton Total Soin", description: "Ajoute 2,5% de chances à chaque tour de se soigner dun problème de statut." },
"ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Jeton Total Soin", description: "Ajoute 2.5% de chances à chaque tour de se soigner dun problème de statut." },
"ENEMY_ENDURE_CHANCE": { name: "Jeton Ténacité" },
"ENEMY_FUSED_CHANCE": { name: "Jeton Fusion", description: "Ajoute 1% de chances quun Pokémon sauvage soit une fusion." },
},
SpeciesBoosterItem: {
"LIGHT_BALL": { name: "Balle Lumière", description: "À faire tenir à Pikachu. Un orbe énigmatique qui double son Attaque et son Atq. Spé. ." },
"THICK_CLUB": { name: "Masse Os", description: "À faire tenir à Osselait ou Ossatueur. Un os dur qui double leur Attaque." },
"METAL_POWDER": { name: "Poudre Métal", description: "À faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, double sa Défense." },
"QUICK_POWDER": { name: "Poudre Vite", description: "À faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, double sa Vitesse." }
"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 +",
"x_sp_atk": "Atq. Spé. +",
"x_sp_def": "Déf. Spé. +",
"x_sp_atk": "Atq. Spé. +",
"x_sp_def": "Déf. Spé. +",
"x_speed": "Vitesse +",
"x_accuracy": "Précision +",
"dire_hit": "Muscle +",
@ -265,8 +265,8 @@ export const modifierType: ModifierTypeTranslationEntries = {
TempBattleStatBoosterStatName: {
"ATK": "Attaque",
"DEF": "Défense",
"SPATK": "Atq. Spé.",
"SPDEF": "Déf. Spé.",
"SPATK": "Atq. Spé.",
"SPDEF": "Déf. Spé.",
"SPD": "Vitesse",
"ACC": "Précision",
"CRIT": "Taux de critique",

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Passer dialogues connus",
"battleStyle": "Style de combat",
"enableRetries": "Activer les réessais",
"hideIvs": "Masquer Scanner dIV",
"tutorials": "Tutoriels",
"touchControls": "Contrôles tactiles",
"vibrations": "Vibrations",

View File

@ -34,9 +34,9 @@ export const tutorial: SimpleTranslationEntries = {
"selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre quun.
$Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents.
$La plupart des effets des objets non-consommables se cumuleront de diverses manières.
$Certains objets apparaitront sils peuvent être utilisés, comme les objets dévolution.
$Certains objets apparaîtront sils peuvent être utilisés, comme les objets dévolution.
$Vous pouvez aussi transférer des objets tenus entre Pokémon en utilisant loption de transfert.
$Loption de transfert apparait en bas à droite dès que vous avez obtenu un objet à faire tenir.
$Loption de transfert apparaît en bas à droite dès que vous avez obtenu un objet à faire tenir.
$Vous pouvez acheter des consommables avec de largent.\nPlus vous progressez, plus le choix sera varié.
$Choisir un des objets gratuits déclenchera le prochain combat, donc faites bien tous vos achats avant.`,

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Skip Seen Dialogues",
"battleStyle": "Battle Style",
"enableRetries": "Enable Retries",
"hideIvs": "Hide IV scanner",
"tutorials": "Tutorials",
"touchControls": "Touch Controls",
"vibrations": "Vibrations",

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Skip Seen Dialogues",
"battleStyle": "試合のルール",
"enableRetries": "リトライを有効にする",
"hideIvs": "Hide IV scanner",
"tutorials": "チュートリアル",
"touchControls": "タッチ操作",
"vibrations": "振動",

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "본 대화 생략",
"battleStyle": "시합 룰",
"enableRetries": "재도전 허용",
"hideIvs": "개체값탐지기 효과 끄기",
"tutorials": "튜토리얼",
"touchControls": "터치 컨트롤",
"vibrations": "진동",

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Pular Diálogos Vistos",
"battleStyle": "Estilo de Batalha",
"enableRetries": "Habilitar Novas Tentativas",
"hideIvs": "Esconder scanner de IV",
"tutorials": "Tutorial",
"touchControls": "Controles de Toque",
"vibrations": "Vibração",

View File

@ -170,8 +170,8 @@ export const PGMachv: AchievementTranslationEntries = {
description: "在经典模式中通关游戏",
},
"UNEVOLVED_CLASSIC_VICTORY": {
name: "带孩子来上班",
description: "通关经典模式时队伍中至少有一名未进化的宝可梦"
name: "Bring Your Child To Work Day",
description: "Beat the game in Classic Mode with at least one unevolved party member."
},
"MONO_GEN_ONE": {

View File

@ -384,199 +384,199 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"archer": {
"encounter": {
1: "在你继续前进之前,\n让我看看你要如何和对付火箭队。",
2: "我收到报告说你的实力与众不同,\n就让我来看看这是否属实吧。",
3: "我是阿波罗,火箭对的干部。\n我不会对组织的敌人手软。"
1: "Before you go any further, let's see how you far against us, Team Rocket!",
2: "I have received reports that your skills are not insignificant. Let's see if they are true.",
3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization."
},
"victory": {
1: "大失误……",
2: "以我现在的实力,无法胜任我的任务……",
3: "原……谅我,坂木。\n我竟被一名训练师打败了。."
1: "What a blunder!",
2: "With my current skills, I was not up to the task after all.",
3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..."
},
},
"ariana": {
"encounter": {
1: `站住!我们可不能放过你!"
$这会损伤火箭对的名誉`,
2: `我不知道也不想知道我的所作所为正确与否…
$我只要遵从坂木老大的指令就可以了`,
3: "你的旅途到此为止了,我会把你狠狠扳倒!"
1: `Hold it right there! We can't someone on the loose."
$It's harmful to Team Rocket's pride, you see.`,
2: `I don't know or care if what I'm doing is right or wrong...
$I just put my faith in Giovanni and do as I am told`,
3: "Your trip ends here. I'm going to take you down!"
},
"victory": {
1: `切,你好强,可恶。
$如果你加入火箭队`,
2: "好……好崩溃……",
3: "嗯啊啊!这不可能!我使出全力还是输了!"
1: `Tch, you really are strong. It's too bad.
$If you were to join Team Rocket, you could become an Executive.`,
2: "I... I'm shattered...",
3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…"
},
},
"proton": {
"encounter": {
1: "你想干什么?如果你要妨碍我们的事业,我可不会手下留情。",
2: `你在这干什么?别人总说我是火箭队里最残忍和恐怖的人
$我强烈推荐你别来碍我们的事`,
3: "我是兰斯,火箭队的干部。就让来扫除你对我们的阻挠。"
1: "What do you want? If you interrupt our work, don't expect any mercy!",
2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket
$I strongly urge you not to interfere with our business!`,
3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!"
},
"victory": {
1: "我的防线崩溃了……",
2: "你虽然这次赢了,但是这只是让火箭队的怒火继续燃烧!",
3: "我输了…但是我不会忘记的。"
1: "The fortress came down!",
2: "You may have won this time… But all you did was make Team Rocket's wrath grow…",
3: "I am defeated… But I will not forget this!"
},
},
"petrel": {
"encounter": {
1: `哇哈哈哈,我们一直在等你。我?你不知道我是谁?是我,坂木啊。
$伟大的坂木大人本人
$我连看起来都不像`,
2: "我是拉姆达,火箭队的干部。我不会允许你干涉我们的计划!",
3: "火箭队干部拉姆达来会会这个入侵者!"
1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni.
$The majestic Giovanni himself! Wahahaha! Huh? I don't sound anything like Giovanni?
$I don't even look like Giovanni? How come? I've worked so hard to mimic him!`,
2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!",
3: "Rocket Executive Petrel will deal with this intruder!"
},
"victory": {
1: "好好好,我会说他在哪的",
2: "我……我什么也做不了……坂木,请原谅我……",
3: "不,我不能慌了神,必须通知其他人…"
1: "OK, OK. I'll tell you where he is.",
2: "I… I couldn't do a thing… Giovanni, please forgive me…",
3: "No, I can't let this affect me. I have to inform the others…"
},
},
"tabitha": {
"encounter": {
1: "呵呵呵!原来你都一路来到这里了!但你来晚了!",
2: `呵呵呵……你终于来了?我们小瞧你了,没不过事!
$我比你见过的所有队员都要厉害
$我会把你碾碎`,
3: "我要让你尝尝痛苦的滋味!认命吧!"
1: "Hehehe! So you've come all the way here! But you're too late!",
2: `Hehehe... Got here already, did you? We underestimated you! But this is it!
$I'm a cut above the Grunts you've seen so far. I'm not stalling for time.
$I'm going to pulverize you!`,
3: "I'm going to give you a little taste of pain! Resign yourself to it!"
},
"victory": {
1: `呵呵呵!虽然你打败了我,但你根本没机会打败老大!
$如果你现在输了`,
2: "呵呵呵……所以,我也输了……",
3: "啊哈!怎么会这样?像我这样的干部\n竟然输给了一个随处可见的训练师……"
1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss!
$If you get lost now, you won't have to face a sound whipping!`,
2: "Hehehe... So, I lost, too...",
3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..."
},
},
"courtney": {
"encounter": {
1: "那个东西……你所拥有的那个东西……\n那就是……那就是我们熔岩队所寻找的东西……",
2: "……那么……删除记忆……",
3: "……哈……分析中……啊哈♪"
1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...",
2: "... Well then...Deleting...",
3: "...Ha. ...Analyzing... ...Hah♪"
},
"victory": {
1: "……改变……世界。",
2: `如预期。出乎意料。目标锁定…锁定你……完成。
$开始`,
3: "……又来了?出乎意料……我就知道。你……很有趣!……啊哈哈!♪"
1: "... ...Change...the world.",
2: `As anticipated. Unanticipated. You. Target lock...completed.
$Commencing...experiment. You. Forever. Aha... `,
3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪"
},
},
"shelly": {
"encounter": {
1: `啊哈哈哈哈!你要插手海洋队的事?
$你要么是绝对无畏
$你太可爱了`,
2: "怎么回事?这个小鬼头是谁?",
3: "冷静点,耐心点。我很快就会把你击溃。"
1: `Ahahahaha! You're going to meddle in Team Aqua's affairs?
$You're either absolutely fearless, simply ignorant, or both!
$You're so cute, you're disgusting! I'll put you down`,
2: "What's this? Who's this spoiled brat?",
3: "Cool your jets. Be patient. I'll crush you shortly."
},
"victory": {
1: `啊哈哈哈哈!我们意外地被人干扰了!我们别无选择。
$不得不撤退了
$我们还有其他计划`,
2: "啊?!我是不是对你太温柔了?!",
3: `呃…难道在对战中你也一刻不停地在变强吗?
$你真是个前途光明的小鬼\n我和我的宝可梦已经没有任何力量去战斗了
$继续吧`
1: `Ahahahaha! We got meddled with unexpectedly! We're out of options.
$We'll have to pull out. But this isn't the last you'll see of Team Aqua!
$We have other plans! Don't you forget it!`,
2: "Ahhh?! Did I go too easy on you?!",
3: `Uh. Are you telling me you've upped your game even more during the fight?
$You're a brat with a bright future… My Pokémon and I don't have any strength left to fight
$Go on Go and be destroyed by Archie.`
},
},
"matt": {
"encounter": {
1: "嚯!哈哈哈!怎么,你是不是脑子不正常了?\n看看你像个幕下力士",
2: "“哦吼!你!你真是个有趣的孩子!",
3: "你在这里干什么?你跟踪我们了吗?"
1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!",
2: "Oho! You! You're that funny kid!",
3: "What are you doing here? Did you follow us?"
},
"victory": {
1: "好吧,在老大有时间对付你之前,我来成为你的对手!",
2: `我能感觉到!我感觉到了,没错!你身上散发出的力量!
$更多`,
3: "真有趣!我就知道你会让我尽兴的!\n我期待有一天再次面对你"
1: "All right then, until the Boss has time for you, I'll be your opponent!",
2: `I can feel it! I can feel it, all right! The strength coming offa you!
$More! I still want more! But looks like we're outta time...`,
3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!"
},
},
"mars": {
"encounter": {
1: "我是伙星,银河队的顶级干部之一。",
2: "银河队对未来的愿景坚定不移。\n反对者将被无情地粉碎",
3: "“紧张吗?你是该感到紧张了!"
1: "I'm Mars, one of Team Galactic's top Commanders.",
2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!",
3: "Feeling nervous? You should be!"
},
"victory": {
1: "这不可能!我怎么会输?!",
2: "你很有本事,我承认。",
3: "输了……犯了一个代价高昂的大错。"
1: "This can't be happening! How did I lose?!",
2: "You have some skill, I'll give you that.",
3: "Defeated... This was a costly mistake."
}
},
"jupiter": {
"encounter": {
1: "岁星,银河队干部,为您效劳。",
2: "抵抗是徒劳的。银河队必将获胜!",
3: "你在发抖啊……已经害怕了吗?"
1: "Jupiter, Commander of Team Galactic, at your service.",
2: "Resistance is futile. Team Galactic will prevail!",
3: "You're trembling... scared already?"
},
"victory": {
1: "不会吧……我输了?!",
2: "厉害,你胆子真大!",
3: "输成这样……真丢人。"
1: "No way... I lost?!",
2: "Impressive, you've got guts!",
3: "Losing like this... How embarrassing."
}
},
"saturn": {
"encounter": {
1: "我是镇星,银河队的干部。",
2: "我们的使命是绝对的,任何阻碍都将被消灭!",
3: "我从你的眼中看到的是恐惧吗?"
1: "I am Saturn, Commander of Team Galactic.",
2: "Our mission is absolute. Any hindrance will be obliterated!",
3: "Is that fear I see in your eyes?"
},
"victory": {
1: "不可能……被你打败了?!",
2: "你证明了自己是一个值得尊敬的对手。",
3: "失败的苦涩……难以接受……。"
1: "Impossible... Defeated by you?!",
2: "You have proven yourself a worthy adversary.",
3: "Bestowed in defeat... This is unacceptable."
}},
"zinzolin": {
"encounter": {
1: "你可能会对等离子队构成威胁,所以我们现在就消灭你!",
2: "哦,天哪……我没想到要在这么冷的天气里战斗!",
3: "能走到今天这一步,你真是个了不起的训练师。\n但一切到此结束。"
1: "You could become a threat to Team Plasma, so we will eliminate you here and now!",
2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!",
3: "You're an impressive Trainer to have made it this far. But it ends here."
},
"victory": {
1: "魁奇思大人……我让你失望了……",
2: "好冷,我不仅发抖,还要遭罪。",
3: "哼。你比我想象的要聪明,但还不够。"
1: "Ghetsis... I have failed you...",
2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.",
3: "Hmph. You're a smarter Trainer than I expected, but not smart enough."
}
},
"rood": {
"encounter": {
1: "你对等离子队是个威胁。我们现在不能让你离开这里!",
2: "哦,这寒风……我从没想过我必须在这里战斗!",
3: "能走到今天这一步,你是一位了不起的训练师,但这就是你的结局了。"
1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!",
2: "Oh, this icy wind... I never thought I'd have to fight here!",
3: "You are a remarkable Trainer to have made it this far. But this is where it ends."
},
"victory": {
1: "魁奇思大人……我的任务失败了",
2: "寒风刺骨。我瑟瑟发抖。我痛苦不堪。",
3: "嗯,你是很有才。但是要打败等离子队还不够……!"
1: "Ghetsis... I have failed my mission...",
2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.",
3: "Hm. You are a talented Trainer, but unfortunately not talented enough."
}
},
"xerosic": {
"encounter": {
1: "啊哈哈!我很乐意。\n来吧小训练师让我们看看你有什么本事",
2: "嗯……你比看上去更强大。\n我想知道你体内有多少能量。",
3: "我一直在等你!我需要对你做一点研究!\n来吧我们开始吧"
1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!",
2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.",
3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!"
},
"victory": {
1: "啊,你好强大啊……嗯……确实非常强大。",
2: "叮叮叮!你成功了!\n战利品归胜利者",
3: "太棒了!太神奇了!\n你的技巧和勇气都无与伦比"
1: "Ah, you're quite strong. Oh yes—very strong, indeed.",
2: "Ding-ding-ding! You did it! To the victor go the spoils!",
3: "Wonderful! Amazing! You have tremendous skill and bravery!"
}
},
"bryony": {
"encounter": {
1: "我是芭菈,能与你一战是我的荣幸。\n让我看看你的实力。",
2: "令人印象深刻……你比你看上去的还要强大。\n让我们看看你真正的实力。",
3: "我预料到了你的到来。\n是时候进行一个小实验了我们开始吧"
1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.",
2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.",
3: "I've anticipated your arrival. It's time for a little test. Shall we begin?"
},
"victory": {
1: "你很强大。哦,嗯嗯!确实非常强大",
2: "叮叮叮!你做得很好。胜利属于你。",
3: "太棒了!了不起!你的技巧和勇气值得称赞。"
1: "You're quite strong. Oh yes—very strong, indeed.",
2: "Ding-ding-ding! You've done well. Victory is yours.",
3: "Wonderful! Remarkable! Your skill and bravery are commendable."
}
},
"rocket_grunt": {

View File

@ -13,18 +13,18 @@ export const filterBar: SimpleTranslationEntries = {
"passive": "被动",
"passiveUnlocked": "被动解锁",
"passiveLocked": "被动未解锁",
"costReduction": "费用降低",
"costReductionUnlocked": "已降费",
"costReductionLocked": "未降费",
"costReduction": "Cost Reduction",
"costReductionUnlocked": "Cost Reduction Unlocked",
"costReductionLocked": "Cost Reduction Locked",
"ribbon": "缎带",
"hasWon": "有缎带",
"hasNotWon": "无缎带",
"hiddenAbility": "梦特",
"hasHiddenAbility": "有梦特",
"noHiddenAbility": "无梦特",
"pokerus": "病毒",
"hasPokerus": "有病毒",
"noPokerus": "无病毒",
"hiddenAbility": "Hidden Ability",
"hasHiddenAbility": "Hidden Ability - Yes",
"noHiddenAbility": "Hidden Ability - No",
"pokerus": "Pokerus",
"hasPokerus": "Pokerus - Yes",
"noPokerus": "Pokerus - No",
"sortByNumber": "编号",
"sortByCost": "费用",
"sortByCandies": "糖果",

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "跳过已读对话",
"battleStyle": "对战模式",
"enableRetries": "允许重试",
"hideIvs": "禁用个体值探测器信息",
"tutorials": "教程",
"touchControls": "触摸操作",
"vibrations": "手柄震动",

View File

@ -7,7 +7,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales";
*/
export const starterSelectUiHandler: SimpleTranslationEntries = {
"confirmStartTeam": "使用这些宝可梦开始游戏吗?",
"confirmExit": "确定要退出吗?",
"confirmExit": "Do you want to exit?",
"invalidParty": "初始队伍不可用!",
"gen1": "I",
"gen2": "II",

View File

@ -20,18 +20,18 @@ export const titles: SimpleTranslationEntries = {
"plasma_boss": "等离子队老大",
"flare_boss": "闪焰队老大",
"rocket_admin": "火箭队干部",
"rocket_admin_female": "火箭队干部",
"magma_admin": "熔岩队干部",
"magma_admin_female": "熔岩队干部",
"aqua_admin": "海洋队干部",
"aqua_admin_female": "海洋队干部",
"galactic_commander": "银河队干部",
"galactic_commander_female": "银河队干部",
"plasma_sage": "等离子队贤人",
"plasma_admin": "等离子队干部",
"flare_admin": "闪焰队干部",
"flare_admin_female": "闪焰队干部",
"rocket_admin": "Team Rocket Admin",
"rocket_admin_female": "Team Rocket Admin",
"magma_admin": "Team Magma Admin",
"magma_admin_female": "Team Magma Admin",
"aqua_admin": "Team Aqua Admin",
"aqua_admin_female": "Team Aqua Admin",
"galactic_commander": "Team Galactic Commander",
"galactic_commander_female": "Team Galactic Commander",
"plasma_sage": "Team Plasma Sage",
"plasma_admin": "Team Plasma Admin",
"flare_admin": "Team Flare Admin",
"flare_admin_female": "Team Flare Admin",
// Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc.
} as const;
@ -342,21 +342,21 @@ export const trainerNames: SimpleTranslationEntries = {
"rival_female": "艾薇",
// Evil Team Admins
"archer": "阿波罗",
"ariana": "雅典娜",
"proton": "兰斯",
"petrel": "拉姆达",
"tabitha": "火村",
"courtney": "火雁",
"shelly": "阿泉",
"matt": "阿潮",
"mars": "伙星",
"jupiter": "碎星",
"saturn": "镇星",
"zinzolin": "维奥",
"rood": "罗德",
"xerosic": "库瑟洛斯奇",
"bryony": "芭菈",
"archer": "Archer",
"ariana": "Ariana",
"proton": "Proton",
"petrel": "Petrel",
"tabitha": "Tabitha",
"courtney": "Courtney",
"shelly": "Shelly",
"matt": "Matt",
"mars": "Mars",
"jupiter": "Jupiter",
"saturn": "Saturn",
"zinzolin": "Zinzolin",
"rood": "Rood",
"xerosic": "Xerosic",
"bryony": "Bryony",
// ---- 组织老大 Bosses ----
"maxie": "赤焰松",

View File

@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "跳過已讀對話",
"battleStyle": "對戰模式",
"enableRetries": "允許重試",
"hideIvs": "禁用個體值探測器信息",
"tutorials": "教程",
"touchControls": "觸摸操作",
"vibrations": "手柄震動",

View File

@ -50,7 +50,7 @@ import { GameMode, GameModes, getGameMode } from "./game-mode";
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
import i18next from "./plugins/i18n";
import Overrides from "#app/overrides";
import { TextStyle, addTextObject, getTextColor } from "./ui/text";
import { TextStyle, addTextObject } from "./ui/text";
import { Type } from "./data/type";
import { BerryUsedEvent, EncounterPhaseEvent, MoveUsedEvent, TurnEndEvent, TurnInitEvent } from "./events/battle-scene";
import { Abilities } from "#enums/abilities";
@ -5599,45 +5599,19 @@ export class ScanIvsPhase extends PokemonPhase {
const pokemon = this.getPokemon();
let enemyIvs: number[] = [];
let statsContainer: Phaser.GameObjects.Sprite[] = [];
let statsContainerLabels: Phaser.GameObjects.Sprite[] = [];
const enemyField = this.scene.getEnemyField();
const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible
for (let e = 0; e < enemyField.length; e++) {
enemyIvs = enemyField[e].ivs;
const currentIvs = this.scene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs; // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists
const ivsToShow = this.scene.ui.getMessageHandler().getTopIvs(enemyIvs, this.shownIvs);
statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[];
statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0);
for (let s = 0; s < statsContainerLabels.length; s++) {
const ivStat = Stat[statsContainerLabels[s].frame.name];
if (enemyIvs[ivStat] > currentIvs[ivStat] && ivsToShow.indexOf(Number(ivStat)) >= 0) {
const hexColour = enemyIvs[ivStat] === 31 ? getTextColor(TextStyle.PERFECT_IV, false, uiTheme) : getTextColor(TextStyle.SUMMARY_GREEN, false, uiTheme);
const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color;
statsContainerLabels[s].setTint(hexTextColour);
}
statsContainerLabels[s].setVisible(true);
}
}
if (!this.scene.hideIvs) {
this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => {
this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.clearText();
new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => {
this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end());
});
}, () => {
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.clearText();
this.end();
this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => {
this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.clearText();
new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => {
this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end());
});
}, () => {
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.clearText();
this.end();
});
} else {
this.end();
}
});
}
}

View File

@ -79,7 +79,6 @@ export const SettingKeys = {
Skip_Seen_Dialogues: "SKIP_SEEN_DIALOGUES",
Battle_Style: "BATTLE_STYLE",
Enable_Retries: "ENABLE_RETRIES",
Hide_IVs: "HIDE_IVS",
Tutorials: "TUTORIALS",
Touch_Controls: "TOUCH_CONTROLS",
Vibration: "VIBRATION",
@ -251,13 +250,6 @@ export const Setting: Array<Setting> = [
default: 0,
type: SettingType.GENERAL
},
{
key: SettingKeys.Hide_IVs,
label: i18next.t("settings:hideIvs"),
options: OFF_ON,
default: 0,
type: SettingType.GENERAL
},
{
key: SettingKeys.Tutorials,
label: i18next.t("settings:tutorials"),
@ -626,9 +618,6 @@ export function setSetting(scene: BattleScene, setting: string, value: integer):
case SettingKeys.Enable_Retries:
scene.enableRetries = Setting[index].options[value].value === "On";
break;
case SettingKeys.Hide_IVs:
scene.hideIvs = Setting[index].options[value].value === "On";
break;
case SettingKeys.Skip_Seen_Dialogues:
scene.skipSeenDialogues = Setting[index].options[value].value === "On";
break;

View File

@ -8,7 +8,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
describe("Abilities - Hustle", () => {
let phaserGame: Phaser.Game;
@ -44,7 +44,8 @@ describe("Abilities - Hustle", () => {
vi.spyOn(pikachu, "getBattleStat");
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase);
expect(pikachu.getBattleStat).toHaveReturnedWith(atk * 1.5);

View File

@ -2,7 +2,7 @@ import { allMoves } from "#app/data/move.js";
import { Type } from "#app/data/type.js";
import { Weather, WeatherType } from "#app/data/weather.js";
import { PlayerPokemon } from "#app/field/pokemon.js";
import { TurnEndPhase } from "#app/phases.js";
import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js";
import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Biome } from "#enums/biome";
@ -12,7 +12,7 @@ import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -192,7 +192,8 @@ describe("Abilities - Protean", () => {
expect(leadPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await mockHitCheck(game, false);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false);
await game.phaseInterceptor.to(TurnEndPhase);
const enemyPokemon = game.scene.getEnemyPokemon()!;

View File

@ -1,8 +1,8 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import Phaser from "phaser";
import GameManager from "#test/utils/gameManager";
import { Species } from "#enums/species";
import { TurnEndPhase } from "#app/phases";
import { TurnEndPhase, MoveEffectPhase } from "#app/phases";
import { Moves } from "#enums/moves";
import { ArenaTagType } from "#enums/arena-tag-type";
import { ArenaTagSide, getArenaTag } from "#app/data/arena-tag";
@ -11,7 +11,7 @@ import { Abilities } from "#enums/abilities";
import { WeatherType } from "#app/data/weather.js";
import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
import { BattlerTagType } from "#enums/battler-tag-type";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000; // 20 sec timeout
@ -258,7 +258,8 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!;
game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK));
await mockHitCheck(game, false);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false);
await game.phaseInterceptor.to(TurnEndPhase);

View File

@ -7,10 +7,10 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -129,7 +129,10 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(BerryPhase, false);
@ -172,7 +175,9 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase, false);
@ -368,7 +373,9 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.hp;
game.doAttack(getMovePosition(game.scene, 0, Moves.SUPER_FANG));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase);
@ -397,7 +404,9 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.hp;
game.doAttack(getMovePosition(game.scene, 0, Moves.SEISMIC_TOSS));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase);
@ -423,7 +432,9 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase);
@ -451,7 +462,9 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase);
@ -481,7 +494,9 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase);
@ -508,7 +523,9 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(MoveEffectPhase);
expect(leadPokemon.turnData.hitCount).toBe(2);
@ -532,7 +549,9 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP));
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
await game.phaseInterceptor.to(DamagePhase);

View File

@ -2,7 +2,7 @@ import { allMoves } from "#app/data/move.js";
import { Type } from "#app/data/type.js";
import { Weather, WeatherType } from "#app/data/weather.js";
import { PlayerPokemon } from "#app/field/pokemon.js";
import { TurnEndPhase } from "#app/phases.js";
import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js";
import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Biome } from "#enums/biome";
@ -12,7 +12,7 @@ import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -192,7 +192,8 @@ describe("Abilities - Protean", () => {
expect(leadPokemon).not.toBe(undefined);
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await mockHitCheck(game, false);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false);
await game.phaseInterceptor.to(TurnEndPhase);
const enemyPokemon = game.scene.getEnemyPokemon()!;

View File

@ -11,7 +11,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { mockTurnOrder } from "../utils/testUtils";
import { changeTurnOrder } from "../utils/testUtils";
import { BattlerIndex } from "#app/battle.js";
@ -57,7 +57,7 @@ describe("Abilities - Serene Grace", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Check chance of Air Slash without Serene Grace
@ -90,7 +90,7 @@ describe("Abilities - Serene Grace", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Check chance of Air Slash with Serene Grace

View File

@ -11,7 +11,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { mockTurnOrder } from "../utils/testUtils";
import { changeTurnOrder } from "../utils/testUtils";
import { BattlerIndex } from "#app/battle.js";
@ -58,7 +58,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
@ -97,7 +97,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
@ -136,7 +136,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
@ -177,7 +177,7 @@ describe("Abilities - Sheer Force", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;

View File

@ -12,7 +12,7 @@ import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { BattlerIndex } from "#app/battle.js";
import { mockTurnOrder } from "../utils/testUtils";
import { changeTurnOrder } from "../utils/testUtils";
describe("Abilities - Shield Dust", () => {
@ -58,7 +58,7 @@ describe("Abilities - Shield Dust", () => {
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Shield Dust negates secondary effect

View File

@ -1,14 +1,14 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import Phaser from "phaser";
import GameManager from "#test/utils/gameManager";
import { Species } from "#enums/species";
import { CommandPhase, MovePhase, TurnEndPhase } from "#app/phases";
import { CommandPhase, MoveEffectPhase, MovePhase, TurnEndPhase } from "#app/phases";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { BattlerTagType } from "#app/enums/battler-tag-type.js";
import { Abilities } from "#app/enums/abilities.js";
import { BattlerIndex } from "#app/battle.js";
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
describe("Abilities - Sweet Veil", () => {
let phaserGame: Phaser.Game;
@ -80,11 +80,13 @@ describe("Abilities - Sweet Veil", () => {
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
// First pokemon move
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(true);
// Second pokemon move
await game.phaseInterceptor.to(MovePhase, false);
await mockHitCheck(game, true);
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(true);
expect(game.scene.getPlayerField().some(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(true);

View File

@ -12,7 +12,7 @@ import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
import { BattlerIndex } from "#app/battle.js";
import { mockTurnOrder } from "../utils/testUtils";
import { changeTurnOrder } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -58,7 +58,7 @@ describe("Abilities - ZEN MODE", () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(DamagePhase, false);
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
@ -86,7 +86,7 @@ describe("Abilities - ZEN MODE", () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(QuietFormChangePhase);
await game.phaseInterceptor.to(TurnInitPhase, false);
expect(game.scene.getParty()[0].hp).not.toBe(100);
@ -111,7 +111,7 @@ describe("Abilities - ZEN MODE", () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(DamagePhase, false);
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;

View File

@ -1,4 +1,4 @@
import { pokemonEvolutions, SpeciesFormEvolution, SpeciesWildEvolutionDelay } from "#app/data/pokemon-evolutions.js";
import { pokemonEvolutions } from "#app/data/pokemon-evolutions.js";
import { Abilities } from "#app/enums/abilities.js";
import { Species } from "#app/enums/species.js";
import GameManager from "#test/utils/gameManager";
@ -83,10 +83,4 @@ describe("Evolution", () => {
expect(ninjask.abilityIndex).toBe(2);
expect(shedinja.abilityIndex).toBe(1);
}, TIMEOUT);
it("should set wild delay to NONE by default", () => {
const speciesFormEvo = new SpeciesFormEvolution(Species.ABRA, null, null, 1000, null, null);
expect(speciesFormEvo.wildDelay).toBe(SpeciesWildEvolutionDelay.NONE);
});
});

View File

@ -8,7 +8,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { mockTurnOrder } from "#test/utils/testUtils";
import { changeTurnOrder } from "#test/utils/testUtils";
describe("Items - Leek", () => {
let phaserGame: Phaser.Game;
@ -44,7 +44,7 @@ describe("Items - Leek", () => {
game.doAttack(0);
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase);

View File

@ -8,7 +8,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { mockTurnOrder } from "#test/utils/testUtils";
import { changeTurnOrder } from "#test/utils/testUtils";
describe("Items - Scope Lens", () => {
let phaserGame: Phaser.Game;
@ -43,7 +43,7 @@ describe("Items - Scope Lens", () => {
]);
game.doAttack(0);
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase);

View File

@ -8,7 +8,7 @@ import { allMoves } from "#app/data/move";
import { BattlerIndex } from "#app/battle";
import { Species } from "#enums/species";
import { Moves } from "#enums/moves";
import { mockTurnOrder } from "#test/utils/testUtils";
import { changeTurnOrder } from "#test/utils/testUtils";
describe("Moves - Fusion Flare and Fusion Bolt", () => {
let phaserGame: Phaser.Game;
@ -56,7 +56,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force user party to act before enemy party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
@ -82,7 +82,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force user party to act before enemy party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
@ -108,7 +108,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(0);
// Force first enemy to act (and fail) in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
@ -140,7 +140,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force first enemy to act in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
@ -170,7 +170,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.PLAYER);
// Force user party to act before enemy party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
@ -222,7 +222,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.ENEMY);
// Force first enemy to act in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
@ -284,7 +284,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
game.doSelectTarget(BattlerIndex.PLAYER);
// Force first enemy to act in between party
await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
await game.phaseInterceptor.to(MoveEffectPhase, false);
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);

View File

@ -6,7 +6,7 @@ import { MoveResult } from "#app/field/pokemon.js";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { mockTurnOrder, SPLASH_ONLY } from "#test/utils/testUtils";
import { changeTurnOrder, SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -75,7 +75,7 @@ describe("Moves - Gastro Acid", () => {
game.doAttack(getMovePosition(game.scene, 0, Moves.CORE_ENFORCER));
// Force player to be slower to enable Core Enforcer to proc its suppression effect
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to("TurnInitPhase");

View File

@ -3,7 +3,7 @@ import i18next, { type ParseKeys } from "i18next";
import { vi } from "vitest";
import GameManager from "./gameManager";
import { BattlerIndex } from "#app/battle.js";
import { MoveEffectPhase, TurnStartPhase } from "#app/phases.js";
import { TurnStartPhase } from "#app/phases.js";
/** Ready to use array of Moves.SPLASH x4 */
export const SPLASH_ONLY = [Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH];
@ -40,33 +40,16 @@ export function removeEnemyHeldItems(game: GameManager): void {
}
/**
* Intercepts `TurnStartPhase` and mocks the getOrder's return value {@linkcode TurnStartPhase.getOrder}
* Used to modify the turn order.
* @param {GameManager} game The GameManager instance
* @param {BattlerIndex[]} order The turn order to set
* Used to modify the turn order. Will advance the turn to {@link TurnStartPhase}
* @param game The {@link GameManager} instance
* @param order The turn order to set
* @example
* ```ts
* await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]);
* await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]);
* ```
*/
export async function mockTurnOrder(game: GameManager, order: BattlerIndex[]): Promise<void> {
export async function changeTurnOrder(game: GameManager, order: BattlerIndex[]): Promise<void> {
await game.phaseInterceptor.to(TurnStartPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order);
}
/**
* Intercepts `MoveEffectPhase` and mocks the hitCheck's return value {@linkcode MoveEffectPhase.hitCheck}.
* Used to force a move to either hit or miss.
* Note that this uses `mockReturnValue()`, meaning it will also apply to a
* succeeding `MoveEffectPhase` immediately following the first one
* (in the case of a multi-target move)
*
* @param {GameManager} game The GameManager instance
* @param shouldHit Whether the move should hit
*/
export async function mockHitCheck(game: GameManager, shouldHit: boolean): Promise<void> {
await game.phaseInterceptor.to(MoveEffectPhase, false);
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(shouldHit);
}

View File

@ -12,6 +12,8 @@ import BattleFlyout from "./battle-flyout";
import { WindowVariant, addWindow } from "./ui-theme";
import i18next from "i18next";
const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ];
export default class BattleInfo extends Phaser.GameObjects.Container {
private baseY: number;
@ -68,10 +70,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
public flyoutMenu?: BattleFlyout;
private battleStatOrder: BattleStat[];
private battleStatOrderPlayer = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD];
private battleStatOrderEnemy = [BattleStat.HP, BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD];
constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) {
super(scene, x, y);
this.baseY = y;
@ -224,44 +222,20 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.statValuesContainer = this.scene.add.container(0, 0);
this.statsContainer.add(this.statValuesContainer);
// this gives us a different starting location from the left of the label and padding between stats for a player vs enemy
// since the player won't have HP to show, it doesn't need to change from the current version
const startingX = this.player ? -this.statsBox.width + 8 : -this.statsBox.width + 5;
const paddingX = this.player ? 4 : 2;
const statOverflow = this.player ? 1 : 0;
this.battleStatOrder = this.player ? this.battleStatOrderPlayer : this.battleStatOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order
this.battleStatOrder.map((s, i) => {
// we do a check for i > statOverflow to see when the stat labels go onto the next column
// For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0
// For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1
const statX = i > statOverflow ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0
const baseY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis
let statY: number; // this will be the y-axis placement for the labels
if (this.battleStatOrder[i] === BattleStat.SPD || this.battleStatOrder[i] === BattleStat.HP) {
statY = baseY + 5;
} else {
statY = baseY + (!!(i % 2) === this.player ? 10 : 0); // we compare i % 2 against this.player to tell us where to place the label; because this.battleStatOrder for enemies has HP, this.battleStatOrder[1]=ATK, but for players this.battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us
}
battleStatOrder.map((s, i) => {
const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8;
const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5);
const statLabel = this.scene.add.sprite(statX, statY, "pbinfo_stat", BattleStat[s]);
statLabel.setName("icon_stat_label_" + i.toString());
statLabel.setOrigin(0, 0);
statLabels.push(statLabel);
this.statValuesContainer.add(statLabel);
const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", this.battleStatOrder[i] !== BattleStat.HP ? "3" : "empty");
const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", "3");
statNumber.setName("icon_stat_number_" + i.toString());
statNumber.setOrigin(0, 0);
this.statNumbers.push(statNumber);
this.statValuesContainer.add(statNumber);
if (this.battleStatOrder[i] === BattleStat.HP) {
statLabel.setVisible(false);
statNumber.setVisible(false);
}
});
if (!this.player) {
@ -300,10 +274,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
}
}
getStatsValueContainer(): Phaser.GameObjects.Container {
return this.statValuesContainer;
}
initInfo(pokemon: Pokemon) {
this.updateNameText(pokemon);
const nameTextWidth = this.nameText.displayWidth;
@ -433,7 +403,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.statValuesContainer.setPosition(8, 7);
}
const battleStats = this.battleStatOrder.map(() => 0);
const battleStats = battleStatOrder.map(() => 0);
this.lastBattleStats = battleStats.join("");
this.updateBattleStats(battleStats);
@ -652,7 +622,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
const battleStats = pokemon.summonData
? pokemon.summonData.battleStats
: this.battleStatOrder.map(() => 0);
: battleStatOrder.map(() => 0);
const battleStatsStr = battleStats.join("");
if (this.lastBattleStats !== battleStatsStr) {
@ -770,10 +740,8 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
}
updateBattleStats(battleStats: integer[]): void {
this.battleStatOrder.map((s, i) => {
if (s !== BattleStat.HP) {
this.statNumbers[i].setFrame(battleStats[s].toString());
}
battleStatOrder.map((s, i) => {
this.statNumbers[i].setFrame(battleStats[s].toString());
});
}

View File

@ -196,7 +196,24 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
this.scene.executeWithSeedOffset(() => {
let levelUpStatsValuesText = "";
const stats = Utils.getEnumValues(Stat);
const shownStats = this.getTopIvs(ivs, shownIvsCount);
let shownStats: Stat[] = [];
if (shownIvsCount < 6) {
const statsPool = stats.slice(0);
for (let i = 0; i < shownIvsCount; i++) {
let shownStat: Stat;
let highestIv = -1;
statsPool.map(s => {
if (ivs[s] > highestIv) {
shownStat = s as Stat;
highestIv = ivs[s];
}
});
shownStats.push(shownStat!); // TODO: is the bang correct?
statsPool.splice(statsPool.indexOf(shownStat!), 1); // TODO: is the bang correct?
}
} else {
shownStats = stats;
}
for (const s of stats) {
levelUpStatsValuesText += `${shownStats.indexOf(s) > -1 ? this.getIvDescriptor(ivs[s], s, pokemonId) : "???"}\n`;
}
@ -212,70 +229,35 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
});
}
getTopIvs(ivs: integer[], shownIvsCount: integer): Stat[] {
const stats = Utils.getEnumValues(Stat);
let shownStats: Stat[] = [];
if (shownIvsCount < 6) {
const statsPool = stats.slice(0);
for (let i = 0; i < shownIvsCount; i++) {
let shownStat: Stat | null = null;
let highestIv = -1;
statsPool.map(s => {
if (ivs[s] > highestIv) {
shownStat = s as Stat;
highestIv = ivs[s];
}
});
if (shownStat) {
shownStats.push(shownStat);
statsPool.splice(statsPool.indexOf(shownStat), 1);
}
}
} else {
shownStats = stats;
}
return shownStats;
}
getIvDescriptor(value: integer, typeIv: integer, pokemonId: integer): string {
const starterSpecies = this.scene.getPokemonById(pokemonId)!.species.getRootSpeciesId(); // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists
const starterSpecies = this.scene.getPokemonById(pokemonId)!.species.getRootSpeciesId(true); // TODO: is this bang correct?
const starterIvs: number[] = this.scene.gameData.dexData[starterSpecies].ivs;
const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible
// Function to wrap text in color based on comparison
const coloredText = (text: string, isBetter: boolean, ivValue) => {
let textStyle: TextStyle;
if (isBetter) {
if (ivValue === 31) {
textStyle = TextStyle.PERFECT_IV;
} else {
textStyle = TextStyle.SUMMARY_GREEN;
}
} else {
textStyle = TextStyle.SUMMARY;
}
//const textStyle: TextStyle = isBetter ? TextStyle.SUMMARY_GREEN : TextStyle.SUMMARY;
const coloredText = (text: string, isBetter: boolean) => {
const textStyle: TextStyle = isBetter ? TextStyle.SUMMARY_GREEN : TextStyle.SUMMARY;
const color = getTextColor(textStyle, false, uiTheme);
return `[color=${color}][shadow=${getTextColor(textStyle, true, uiTheme)}]${text}[/shadow][/color]`;
};
if (value > 30) {
return coloredText(i18next.t("battleMessageUiHandler:ivBest"), value > starterIvs[typeIv], value);
return coloredText(i18next.t("battleMessageUiHandler:ivBest"), value > starterIvs[typeIv]);
}
if (value === 30) {
return coloredText(i18next.t("battleMessageUiHandler:ivFantastic"), value > starterIvs[typeIv], value);
return coloredText(i18next.t("battleMessageUiHandler:ivFantastic"), value > starterIvs[typeIv]);
}
if (value > 20) {
return coloredText(i18next.t("battleMessageUiHandler:ivVeryGood"), value > starterIvs[typeIv], value);
return coloredText(i18next.t("battleMessageUiHandler:ivVeryGood"), value > starterIvs[typeIv]);
}
if (value > 10) {
return coloredText(i18next.t("battleMessageUiHandler:ivPrettyGood"), value > starterIvs[typeIv], value);
return coloredText(i18next.t("battleMessageUiHandler:ivPrettyGood"), value > starterIvs[typeIv]);
}
if (value > 0) {
return coloredText(i18next.t("battleMessageUiHandler:ivDecent"), value > starterIvs[typeIv], value);
return coloredText(i18next.t("battleMessageUiHandler:ivDecent"), value > starterIvs[typeIv]);
}
return coloredText(i18next.t("battleMessageUiHandler:ivNoGood"), value > starterIvs[typeIv], value);
return coloredText(i18next.t("battleMessageUiHandler:ivNoGood"), value > starterIvs[typeIv]);
}
showNameText(name: string): void {

View File

@ -37,8 +37,7 @@ export enum TextStyle {
MOVE_PP_NEAR_EMPTY,
MOVE_PP_EMPTY,
SMALLER_WINDOW_ALT,
BGM_BAR,
PERFECT_IV
BGM_BAR
}
export interface TextStyleOptions {
@ -292,7 +291,6 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
case TextStyle.SUMMARY_GREEN:
return !shadow ? "#78c850" : "#306850";
case TextStyle.SETTINGS_LABEL:
case TextStyle.PERFECT_IV:
return !shadow ? "#f8b050" : "#c07800";
case TextStyle.SETTINGS_SELECTED:
return !shadow ? "#f88880" : "#f83018";