Merge branch 'pagefaultgames:main' into main

This commit is contained in:
3ae3ae 2024-07-07 13:49:03 +09:00 committed by GitHub
commit b434b959c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
74 changed files with 809 additions and 296 deletions

View File

@ -15,19 +15,19 @@
"trimmed": false,
"sourceSize": {
"w": 37,
"h": 35
"h": 37
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 37,
"h": 35
"h": 37
},
"frame": {
"x": 0,
"y": 0,
"w": 37,
"h": 35
"h": 37
}
}
]
@ -36,6 +36,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:fa61a53a0684a1d00e0ed5d6737743af:3e6463caf33bbb58cfba4bd9c20890aa:37281ac0aa1e619ef385b889b64064b7$"
"smartupdate": "$TexturePacker:SmartUpdate:241dff4083e172e8503b54a7f0210f8d:982b194223ffeef2ba672b3c5979a426:37281ac0aa1e619ef385b889b64064b7$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -15,19 +15,19 @@
"trimmed": false,
"sourceSize": {
"w": 37,
"h": 35
"h": 37
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 37,
"h": 35
"h": 37
},
"frame": {
"x": 0,
"y": 0,
"w": 37,
"h": 35
"h": 37
}
}
]
@ -36,6 +36,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:29265d2eed2689ecb95874383b7e7da7:1339971def468ab6d7c93a72472c7b3d:37281ac0aa1e619ef385b889b64064b7$"
"smartupdate": "$TexturePacker:SmartUpdate:566b51540ed595250ead15a4733d98d6:172aa05dcc207383119cd2f2f7977e0e:37281ac0aa1e619ef385b889b64064b7$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 B

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1227,6 +1227,7 @@ export default class BattleScene extends SceneBase {
case Species.ZARUDE:
case Species.SQUAWKABILLY:
case Species.TATSUGIRI:
case Species.GIMMIGHOUL:
case Species.PALDEA_TAUROS:
return Utils.randSeedInt(species.forms.length);
case Species.PIKACHU:

View File

@ -1296,6 +1296,7 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr {
const multiplier = args[2] as Utils.NumberHolder;
if (this.canApplyPreAttack(move, numTargets)) {
this.showAbility = !!hitCount?.value;
if (!!hitCount?.value) {
hitCount.value *= 2;
}

View File

@ -935,9 +935,11 @@ export class ContactDamageProtectedTag extends ProtectedTag {
const effectPhase = pokemon.scene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon();
if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);
}
}
}
return ret;
}

View File

@ -2961,9 +2961,29 @@ export class HpPowerAttr extends VariablePowerAttr {
}
}
/**
* Attribute used for moves whose base power scales with the opponent's HP
* Used for Crush Grip, Wring Out, and Hard Press
* maxBasePower 100 for Hard Press, 120 for others
*/
export class OpponentHighHpPowerAttr extends VariablePowerAttr {
maxBasePower: number;
constructor(maxBasePower: number) {
super();
this.maxBasePower = maxBasePower;
}
/**
* Changes the base power of the move to be the target's HP ratio times the maxBasePower with a min value of 1
* @param user n/a
* @param target the Pokemon being attacked
* @param move n/a
* @param args holds the base power of the move at args[0]
* @returns true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value = Math.max(Math.floor(120 * target.getHpRatio()), 1);
(args[0] as Utils.NumberHolder).value = Math.max(Math.floor(this.maxBasePower * target.getHpRatio()), 1);
return true;
}
@ -6705,7 +6725,7 @@ export function initMoves() {
.target(MoveTarget.ALL_NEAR_ENEMIES)
.unimplemented(),
new AttackMove(Moves.WRING_OUT, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 5, -1, 0, 4)
.attr(OpponentHighHpPowerAttr)
.attr(OpponentHighHpPowerAttr, 120)
.makesContact(),
new SelfStatusMove(Moves.POWER_TRICK, Type.PSYCHIC, -1, 10, -1, 0, 4)
.unimplemented(),
@ -6929,7 +6949,7 @@ export function initMoves() {
.triageMove()
.unimplemented(),
new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
.attr(OpponentHighHpPowerAttr),
.attr(OpponentHighHpPowerAttr, 120),
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4)
.attr(TrapAttr, BattlerTagType.MAGMA_STORM),
new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4)
@ -8399,8 +8419,8 @@ export function initMoves() {
new AttackMove(Moves.TACHYON_CUTTER, Type.STEEL, MoveCategory.SPECIAL, 50, -1, 10, -1, 0, 9)
.attr(MultiHitAttr, MultiHitType._2)
.slicingMove(),
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.attr(OpponentHighHpPowerAttr),
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 9)
.attr(OpponentHighHpPowerAttr, 100),
new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, -1, 0, 9)
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true)
.target(MoveTarget.NEAR_ALLY)

View File

@ -1618,7 +1618,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.FROSMOTH, 1, null, new SpeciesFriendshipEvolutionCondition(90, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.MEDIUM)
],
[Species.GIMMIGHOUL]: [
new SpeciesEvolution(Species.GHOLDENGO, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesFormEvolution(Species.GHOLDENGO, "chest", "", 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.VERY_LONG),
new SpeciesFormEvolution(Species.GHOLDENGO, "roaming", "", 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.VERY_LONG)
]
};

View File

@ -38685,6 +38685,8 @@ export const tmSpecies: TmSpecies = {
Species.GOLDEEN,
Species.SEAKING,
Species.SCYTHER,
Species.ELECTABUZZ,
Species.MAGMAR,
Species.PINSIR,
Species.OMANYTE,
Species.OMASTAR,
@ -38692,6 +38694,8 @@ export const tmSpecies: TmSpecies = {
Species.KABUTOPS,
Species.MEWTWO,
Species.MEW,
Species.BAYLEEF,
Species.MEGANIUM,
Species.SENTRET,
Species.FURRET,
Species.LEDYBA,
@ -38708,8 +38712,10 @@ export const tmSpecies: TmSpecies = {
Species.SNEASEL,
Species.PHANPY,
Species.DONPHAN,
Species.ELEKID,
Species.TYRANITAR,
Species.BLAZIKEN,
Species.SWAMPERT,
Species.LOMBRE,
Species.LUDICOLO,
Species.NUZLEAF,
@ -38740,12 +38746,7 @@ export const tmSpecies: TmSpecies = {
Species.CHIMECHO,
Species.ABSOL,
Species.METAGROSS,
[
Species.DEOXYS,
"",
"defense",
"speed",
],
Species.CHIMCHAR,
Species.MONFERNO,
Species.INFERNAPE,
@ -38767,6 +38768,8 @@ export const tmSpecies: TmSpecies = {
Species.WEAVILE,
Species.LICKILICKY,
Species.TANGROWTH,
Species.ELECTIVIRE,
Species.MAGMORTAR,
Species.LEAFEON,
Species.GLISCOR,
Species.MAMOSWINE,
@ -38781,6 +38784,8 @@ export const tmSpecies: TmSpecies = {
Species.SNIVY,
Species.SERVINE,
Species.SERPERIOR,
Species.PIGNITE,
Species.EMBOAR,
Species.OSHAWOTT,
Species.DEWOTT,
Species.SAMUROTT,
@ -38837,6 +38842,8 @@ export const tmSpecies: TmSpecies = {
Species.ACCELGOR,
Species.MIENFOO,
Species.MIENSHAO,
Species.GOLETT,
Species.GOLURK,
Species.PAWNIARD,
Species.BISHARP,
Species.VULLABY,
@ -38873,6 +38880,7 @@ export const tmSpecies: TmSpecies = {
Species.SALAZZLE,
Species.STEENEE,
Species.TSAREENA,
Species.COMFEY,
Species.ORANGURU,
Species.PASSIMIAN,
Species.GOLISOPOD,
@ -38945,6 +38953,7 @@ export const tmSpecies: TmSpecies = {
Species.GALAR_FARFETCHD,
Species.GALAR_ZAPDOS,
Species.GALAR_ZIGZAGOON,
Species.GALAR_LINOONE,
Species.HISUI_SAMUROTT,
Species.HISUI_ZORUA,
Species.HISUI_ZOROARK,
@ -61853,6 +61862,7 @@ export const tmSpecies: TmSpecies = {
Species.METANG,
Species.METAGROSS,
Species.JIRACHI,
Species.DEOXYS,
Species.BRONZOR,
Species.BRONZONG,
Species.GALLADE,

View File

@ -1162,7 +1162,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return (!cancelled.value ? Number(typeMultiplier.value) : 0) as TypeDamageMultiplier;
}
getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false): TypeDamageMultiplier {
/**
* Calculates the type effectiveness multiplier for an attack type
* @param moveType Type of the move
* @param source the Pokemon using the move
* @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks)
* @param simulated tag to only apply the strong winds effect message when the move is used
* @returns a multiplier for the type effectiveness
*/
getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false, simulated: boolean = true): TypeDamageMultiplier {
if (moveType === Type.STELLAR) {
return this.isTerastallized() ? 2 : 1;
}
@ -1183,8 +1191,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
// Handle strong winds lowering effectiveness of types super effective against pure flying
if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && multiplier >= 2 && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
multiplier /= 2;
if (!simulated) {
this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
}
}
if (!!this.summonData?.tags.find((tag) => tag instanceof TypeImmuneTag && tag.immuneType === moveType)) {
@ -1739,7 +1750,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const cancelled = new Utils.BooleanHolder(false);
const typeless = move.hasAttr(TypelessAttr);
const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes(attr.immuneType)))
? this.getAttackTypeEffectiveness(move.type, source)
? this.getAttackTypeEffectiveness(move.type, source, false, false)
: 1);
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
if (typeless) {

View File

@ -78,6 +78,7 @@ export class LoadingScene extends SceneBase {
this.loadImage("overlay_exp", "ui");
this.loadImage("icon_owned", "ui");
this.loadImage("ability_bar_left", "ui");
this.loadImage("bgm_bar", "ui");
this.loadImage("party_exp_bar", "ui");
this.loadImage("achv_bar", "ui");
this.loadImage("achv_bar_2", "ui");

View File

@ -25,6 +25,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "Es hat keine Wirkung auf {{pokemonName}}…",
"hitResultOneHitKO": "Ein K.O.-Treffer!",
"attackFailed": "Es ist fehlgeschlagen!",
"attackMissed": "Die Attacke hat {{pokemonNameWithAffix}} verfehlt!",
"attackHitsCount": "{{count}}-mal getroffen!",
"rewardGain": "Du erhältst\n{{modifierName}}!",
"expGain": "{{pokemonName}} erhält\n{{exp}} Erfahrungspunkte!",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Musik",
"music": "Musik: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "S2W2 Vs. Kanto Champion",
"battle_johto_champion": "S2W2 Vs. Johto Champion",

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "Alle Flug-Pokémon werden von rätselhaften Luftströmungen geschützt!",
"strongWindsLapseMessage": "Die rätselhafte Luftströmung hält an.",
"strongWindsEffectMessage": "Rätselhafte Luftströmungen haben den Angriff abgeschwächt!",
"strongWindsClearMessage": "Die rätselhafte Luftströmung hat sich wieder geleget.",
};

View File

@ -25,6 +25,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "It doesn't affect {{pokemonName}}!",
"hitResultOneHitKO": "It's a one-hit KO!",
"attackFailed": "But it failed!",
"attackMissed": "{{pokemonNameWithAffix}} avoided the attack!",
"attackHitsCount": "Hit {{count}} time(s)!",
"rewardGain": "You received\n{{modifierName}}!",
"expGain": "{{pokemonName}} gained\n{{exp}} EXP. Points!",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Music",
"music": "Music: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 Kanto Champion Battle",
"battle_johto_champion": "B2W2 Johto Champion Battle",

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "A heavy wind began!",
"strongWindsLapseMessage": "The wind blows intensely.",
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "The heavy wind stopped."
};

View File

@ -25,6 +25,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "No afecta a {{pokemonName}}!",
"hitResultOneHitKO": "¡KO en 1 golpe!",
"attackFailed": "¡Pero ha fallado!",
"attackMissed": "¡{{pokemonNameWithAffix}}\nha evitado el ataque!",
"attackHitsCount": "N.º de golpes: {{count}}.",
"rewardGain": "¡Has obtenido\n{{modifierName}}!",
"expGain": "{{pokemonName}} ha ganado\n{{exp}} puntos de experiencia.",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Música",
"music": "Música: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 - ¡Vs Campeón de Kanto!",
"battle_johto_champion": "B2W2 - ¡Vs Campeón de Johto!",

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "¡Comenzó un fuerte viento!",
"strongWindsLapseMessage": "El viento sopla intensamente.",
"strongWindsEffectMessage": "¡Las misteriosas turbulencias atenúan el ataque!",
"strongWindsClearMessage": "El fuerte viento cesó."
};

View File

@ -25,6 +25,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "Ça naffecte pas {{pokemonName}}…",
"hitResultOneHitKO": "K.O. en un coup !",
"attackFailed": "Mais cela échoue !",
"attackMissed": "{{pokemonNameWithAffix}}\névite lattaque!",
"attackHitsCount": "Touché {{count}} fois !",
"rewardGain": "Vous recevez\n{{modifierName}} !",
"expGain": "{{pokemonName}} gagne\n{{exp}} Points dExp !",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Musique ",
"music": "Musique : ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "N2B2 - Vs. Maitre de Kanto",
"battle_johto_champion": "N2B2 - Vs. Maitre de Johto",

View File

@ -28,7 +28,7 @@ export const partyUiHandler: SimpleTranslationEntries = {
"unspliceConfirmation": "Voulez-vous vraiment séparer {{fusionName}}\nde {{pokemonName}} ? {{fusionName}} sera perdu.",
"wasReverted": "{{fusionName}} est redevenu {{pokemonName}}.",
"releaseConfirmation": "Voulez-vous relâcher {{pokemonName}} ?",
"releaseInBattle": "Vous ne pouvez pas relâcher Pokémon en combat !",
"releaseInBattle": "Vous ne pouvez pas relâcher un Pokémon en combat !",
"selectAMove": "Sélectionnez une capacité.",
"changeQuantity": "Sélect. un objet à transférer.\nChangez la quantité avec < et >.",
"selectAnotherPokemonToSplice": "Sélectionnez un autre Pokémon à séparer.",
@ -44,7 +44,7 @@ export const partyUiHandler: SimpleTranslationEntries = {
"byebye": "Bye-bye, {{pokemonName}} !",
"farewell": "Adieu, {{pokemonName}} !",
"soLong": "Salut, {{pokemonName}} !",
"thisIsWhereWePart": "Cest là quon se sépare, {{pokemonName}}!",
"thisIsWhereWePart": "Cest là quon se sépare, {{pokemonName}} !",
"illMissYou": "Tu vas me manquer, {{pokemonName}} !",
"illNeverForgetYou": "Je ne toublierai pas, {{pokemonName}} !",
"untilWeMeetAgain": "À la prochaine, {{pokemonName}} !",

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "Un vent mystérieux se lève !",
"strongWindsLapseMessage": "Le vent mystérieux souffle violemment !",
"strongWindsEffectMessage": "Le courant aérien mystérieux affaiblit lattaque!",
"strongWindsClearMessage": "Le vent mystérieux sest dissipé…"
};

View File

@ -5,8 +5,8 @@ export const battle: SimpleTranslationEntries = {
"trainerAppeared": "{{trainerName}}\nvuole combattere!",
"trainerAppearedDouble": "{{trainerName}}\nvogliono combattere!",
"trainerSendOut": "{{trainerName}} manda in campo\n{{pokemonName}}!",
"singleWildAppeared": "Appare {{pokemonName}} selvatico!",
"multiWildAppeared": "Appaiono {{pokemonName1}}\ne {{pokemonName2}} salvatici!",
"singleWildAppeared": "È apparso {{pokemonName}} selvatico!",
"multiWildAppeared": "Sono apparsi {{pokemonName1}}\ne {{pokemonName2}} salvatici!",
"playerComeBack": "Rientra, {{pokemonName}}!",
"trainerComeBack": "{{trainerName}} ha ritirato {{pokemonName}}!",
"playerGo": "Vai! {{pokemonName}}!",
@ -25,6 +25,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "Non ha effetto su {{pokemonName}}!",
"hitResultOneHitKO": "KO con un colpo!",
"attackFailed": "Ma ha fallito!",
"attackMissed": "{{pokemonNameWithAffix}}\nevita lattacco!",
"attackHitsCount": "Colpito {{count}} volta/e!",
"rewardGain": "You received\n{{modifierName}}!",
"expGain": "{{pokemonName}} ha guadagnato\n{{exp}} Punti Esperienza!",
@ -43,10 +44,10 @@ export const battle: SimpleTranslationEntries = {
"moveNotImplemented": "{{moveName}} non è ancora implementata e non può essere selezionata.",
"moveNoPP": "Non ci sono PP rimanenti\nper questa mossa!",
"moveDisabled": "{{moveName}} è disabilitata!",
"noPokeballForce": "Una forza misteriosa\nimpedisce l'uso dell Poké Ball.",
"noPokeballForce": "Una forza misteriosa\nimpedisce l'uso delle Poké Ball.",
"noPokeballTrainer": "Non puoi catturare\nPokémon di altri allenatori!",
"noPokeballMulti": "Puoi lanciare una Poké Ball\nquando rimane un solo Pokémon!",
"noPokeballStrong": "Il Pokémon avversario è troppo forte per essere catturato!\nDevi prima indebolirlo!",
"noPokeballMulti": "Puoi lanciare una Poké Ball\nsolo quando rimane un singolo Pokémon!",
"noPokeballStrong": "Il Pokémon avversario è troppo forte per essere catturato!\nDevi prima indebolirlo.",
"noEscapeForce": "Una forza misteriosa\nimpedisce la fuga.",
"noEscapeTrainer": "Non puoi sottrarti\nalla lotta con un'allenatore!",
"noEscapePokemon": "{{moveName}} di {{pokemonName}}\npreviene la {{escapeVerb}}!",
@ -54,11 +55,11 @@ export const battle: SimpleTranslationEntries = {
"runAwayCannotEscape": "Non puoi fuggire!",
"escapeVerbSwitch": "cambiando",
"escapeVerbFlee": "fuggendo",
"notDisabled": "{{pokemonName}}'s {{moveName}} non è più\ndisabilitata!",
"notDisabled": "{{moveName}} di {{pokemonName}} non è più\ndisabilitata!",
"turnEndHpRestore": "{{pokemonName}}'s HP was restored.",
"hpIsFull": "{{pokemonName}}'s\nHP is full!",
"skipItemQuestion": "Sei sicuro di non voler prendere nessun oggetto?",
"eggHatching": "Oh!",
"eggHatching": "Oh?",
"ivScannerUseQuestion": "Vuoi usare lo scanner di IV su {{pokemonName}}?",
"stealEatBerry": "{{pokemonName}} stole and ate\n{{targetName}}'s {{berryName}}!",
"wildPokemonWithAffix": "{{pokemonName}} selvatico",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Music",
"music": "Music: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 Kanto Champion Battle",
"battle_johto_champion": "B2W2 Johto Champion Battle",

View File

@ -6,18 +6,18 @@ export const egg: SimpleTranslationEntries = {
"greatTier": "Raro",
"ultraTier": "Epico",
"masterTier": "Leggendario",
"hatchWavesMessageSoon": "Si sentono dei suoni provenienti dall'interno! Si schiuderà presto!",
"hatchWavesMessageSoon": "Si sentono dei rumori provenienti dall'interno. Si schiuderà presto!",
"hatchWavesMessageClose": "Sembra muoversi di tanto in tanto. Potrebbe essere prossimo alla schiusa.",
"hatchWavesMessageNotClose": "Cosa uscirà da qui? Non sembra si schiuderà presto.",
"hatchWavesMessageLongTime": "Sembra che questo uovo impiegherà molto tempo per schiudersi.",
"gachaTypeLegendary": "Tasso dei Leggendari Aumentato",
"gachaTypeMove": "Tasso delle Mosse Rare delle Uova Aumentato",
"gachaTypeShiny": "Tasso degli Shiny Aumentato",
"selectMachine": "Seleziona un distributore.",
"notEnoughVouchers": "Non hai abbastanza Biglietti!",
"tooManyEggs": "Hai troppe Uova!",
"pull": "Tiro",
"pulls": "Tiri",
"hatchWavesMessageNotClose": "Cosa uscirà da qui? Pare che non si schiuderà presto.",
"hatchWavesMessageLongTime": "Sembra che questo uovo impiegherà ancora molto tempo per schiudersi.",
"gachaTypeLegendary": "Tasso dei leggendari aumentato",
"gachaTypeMove": "Tasso delle mosse rare da uova aumentato",
"gachaTypeShiny": "Tasso degli shiny aumentato",
"selectMachine": "Seleziona un macchinario.",
"notEnoughVouchers": "Non hai abbastanza biglietti!",
"tooManyEggs": "Hai troppe uova!",
"pull": "Estrazione",
"pulls": "Estrazioni",
"sameSpeciesEgg": "{{species}} will hatch from this egg!",
"hatchFromTheEgg": "DallUovo è nato {{pokemonName}}!",
"eggMoveUnlock": "Egg Move unlocked: {{moveName}}",

View File

@ -2,23 +2,23 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const menuUiHandler: SimpleTranslationEntries = {
"GAME_SETTINGS": "Impostazioni",
"ACHIEVEMENTS": "Trofei",
"ACHIEVEMENTS": "Obiettivi",
"STATS": "Statistiche",
"VOUCHERS": "Biglietti",
"EGG_LIST": "Lista Uova",
"EGG_GACHA": "Gacha Uova",
"MANAGE_DATA": "Gestisci Dati",
"EGG_LIST": "Lista uova",
"EGG_GACHA": "Macchine uova",
"MANAGE_DATA": "Gestisci dati",
"COMMUNITY": "Community",
"SAVE_AND_QUIT": "Salva ed Esci",
"SAVE_AND_QUIT": "Salva ed esci",
"LOG_OUT": "Disconnettiti",
"slot": "Slot {{slotNumber}}",
"importSession": "Importa Sessione",
"importSession": "Importa sessione",
"importSlotSelect": "Seleziona uno slot in cui importare.",
"exportSession": "Esporta Sessione",
"exportSession": "Esporta sessione",
"exportSlotSelect": "Seleziona uno slot da cui esportare.",
"importData": "Importa Dati",
"exportData": "Esporta Dati",
"importData": "Importa dati",
"exportData": "Esporta dati",
"cancel": "Annulla",
"losingProgressionWarning": "Perderai tutti i progressi dall'inizio della battaglia. Procedere?",
"losingProgressionWarning": "Perderai tutti i progressi dall'inizio della battaglia. Confermi?",
"noEggs": "You are not hatching\nany eggs at the moment!"
} as const;

View File

@ -13,18 +13,18 @@ export const modifierType: ModifierTypeTranslationEntries = {
"PokemonHeldItemModifierType": {
extra: {
"inoperable": "{{pokemonName}} non può prendere\nquesto oggetto!",
"tooMany": "{{pokemonName}} ne ha troppi\ndi questo oggetto!",
"tooMany": "{{pokemonName}} possiede già\nquesto oggetto in abbondanza.",
}
},
"PokemonHpRestoreModifierType": {
description: "Restituisce {{restorePoints}} PS o {{restorePercent}}% PS ad un Pokémon, a seconda del valore più alto.",
extra: {
"fully": "Restituisce tutti i PS ad un Pokémon.",
"fullyWithStatus": "Restituisce tutti i PS ad un Pokémon e lo cura da ogni stato.",
"fullyWithStatus": "Restituisce tutti i PS ad un Pokémon e lo cura da ogni problema di stato.",
}
},
"PokemonReviveModifierType": {
description: "Rianima un Pokémon esausto e gli restituisce il {{restorePercent}}% PS.",
description: "Rianima un Pokémon esausto e gli restituisce il {{restorePercent}}% dei PS totali.",
},
"PokemonStatusHealModifierType": {
description: "Cura tutti i problemi di stato di un Pokémon.",
@ -46,7 +46,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
},
"PokemonNatureChangeModifierType": {
name: "Menta {{natureName}}.",
description: "Cambia la natura del Pokémon in {{natureName}} e sblocca la natura per il Pokémon iniziale.",
description: "Cambia la natura del Pokémon in {{natureName}} e sblocca la natura nel menu degli starter.",
},
"DoubleBattleChanceBoosterModifierType": {
description: "Raddoppia la possibilità di imbattersi in doppie battaglie per {{battleCount}} battaglie.",
@ -67,7 +67,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
description: "Aumenta {{statName}} di base del possessore del 10%.",
},
"AllPokemonFullHpRestoreModifierType": {
description: "Recupera il 100% dei PS per tutti i Pokémon.",
description: "Restituisce il 100% dei PS a tutti i Pokémon.",
},
"AllPokemonFullReviveModifierType": {
description: "Rianima tutti i Pokémon esausti restituendogli tutti i PS.",
@ -75,7 +75,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
"MoneyRewardModifierType": {
description: "Garantisce una {{moneyMultiplier}} quantità di soldi (₽{{moneyAmount}}).",
extra: {
"small": "poca",
"small": "contenuta",
"moderate": "moderata",
"large": "grande",
},
@ -90,7 +90,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
description: "Aumenta del 50% il guadagno di amicizia per vittoria.",
},
"PokemonMoveAccuracyBoosterModifierType": {
description: "Aumenta l'accuratezza delle mosse di {{accuracyAmount}} (massimo 100).",
description: "Aumenta la precisione delle mosse di {{accuracyAmount}} (massimo 100).",
},
"PokemonMultiHitModifierType": {
description: "Gli attacchi colpiscono una volta in più al costo di una riduzione di potenza del 60/75/82,5% per mossa.",
@ -117,7 +117,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
description: "Teracristallizza in {{teraType}} il possessore per massimo 10 battaglie.",
},
"ContactHeldItemTransferChanceModifierType": {
description: "Quando si attacca, c'è una probabilità del {{chancePercent}}% che l'oggetto in possesso del nemico venga rubato.",
description: "Quando il possessore attacca, c'è una probabilità del {{chancePercent}}% che l'oggetto in possesso del nemico gli venga rubato.",
},
"TurnHeldItemTransferModifierType": {
description: "Ogni turno, il possessore acquisisce un oggetto posseduto dal nemico.",
@ -129,72 +129,71 @@ export const modifierType: ModifierTypeTranslationEntries = {
description: "Aggiunge una probabilità del {{probabilitàPercent}}% di resistere ad un colpo.",
},
"RARE_CANDY": { name: "Caramella Rara" },
"RARER_CANDY": { name: "Caramella Molto Rara" },
"RARE_CANDY": { name: "Caramella rara" },
"RARER_CANDY": { name: "Caramella molto rara" },
"MEGA_BRACELET": { name: "Megapolsiera", description: "Le Megapietre sono disponibili." },
"DYNAMAX_BAND": { name: "Polsino Dynamax", description: "I Fungomax sono disponibili." },
"TERA_ORB": { name: "Terasfera", description: "I Teraliti sono disponibili." },
"MEGA_BRACELET": { name: "Megapolsiera", description: "Le megapietre diventano disponibili." },
"DYNAMAX_BAND": { name: "Polsino Dynamax", description: "I fungomax diventano disponibili." },
"TERA_ORB": { name: "Terasfera", description: "I teraliti diventano disponibili." },
"MAP": { name: "Mappa", description: "Permette di scegliere la propria strada a un bivio." },
"POTION": { name: "Pozione" },
"SUPER_POTION": { name: "Superpozione" },
"HYPER_POTION": { name: "Iperpozione" },
"MAX_POTION": { name: "Pozione Max" },
"FULL_RESTORE": { name: "Ricarica Totale" },
"MAX_POTION": { name: "Pozione max" },
"FULL_RESTORE": { name: "Ricarica totale" },
"REVIVE": { name: "Revitalizzante" },
"MAX_REVIVE": { name: "Revitalizzante Max" },
"MAX_REVIVE": { name: "Revitalizzante max" },
"FULL_HEAL": { name: "Cura Totale" },
"FULL_HEAL": { name: "Cura totale" },
"SACRED_ASH": { name: "Cenere Magica" },
"SACRED_ASH": { name: "Cenere magica" },
"REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di svenimento." },
"REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di KO." },
"ETHER": { name: "Etere" },
"MAX_ETHER": { name: "Etere Max" },
"MAX_ETHER": { name: "Etere max" },
"ELIXIR": { name: "Elisir" },
"MAX_ELIXIR": { name: "Elisir Max" },
"MAX_ELIXIR": { name: "Elisir max" },
"PP_UP": { name: "PP-su" },
"PP_MAX": { name: "PP-max" },
"LURE": { name: "Profumo Invito" },
"SUPER_LURE": { name: "Profumo Invito Super" },
"MAX_LURE": { name: "Profumo Invito Max" },
"LURE": { name: "Esca" },
"SUPER_LURE": { name: "Super esca" },
"MAX_LURE": { name: "Esca max" },
"MEMORY_MUSHROOM": { name: "Fungo della Memoria", description: "Ricorda la mossa dimenticata di un Pokémon." },
"MEMORY_MUSHROOM": { name: "Fungo della memoria", description: "Permette di insegnare nuovamente una mossa dimenticata ad un Pokémon." },
"EXP_SHARE": { name: "Condividi Esperienza", description: "Tutti i Pokémon della squadra ricevono il 20% dei Punti Esperienza dalla lotta anche se non vi hanno partecipato." },
"EXP_BALANCE": { name: "Bilancia Esperienza", description: "Bilancia i Punti Esperienza ricevuti verso i Pokémon del gruppo di livello inferiore." },
"EXP_SHARE": { name: "Condividi esperienza", description: "Tutti i Pokémon della squadra ricevono il 20% dei Punti Esperienza dalla lotta, anche se non vi hanno partecipato." },
"EXP_BALANCE": { name: "Bilancia esperienza", description: "Bilancia i Punti Esperienza ricevuti verso i Pokémon della squadra di livello inferiore." },
"OVAL_CHARM": { name: "Ovamuleto", description: "Quando più Pokémon partecipano a una battaglia, ognuno di essi riceve il 10% in più dell'esperienza totale." },
"EXP_CHARM": { name: "Esperienzamuleto" },
"SUPER_EXP_CHARM": { name: "Esperienzamuleto Super" },
"GOLDEN_EXP_CHARM": { name: "Esperienzamuleto Oro" },
"SUPER_EXP_CHARM": { name: "Esperienzamuleto super" },
"GOLDEN_EXP_CHARM": { name: "Esperienzamuleto dorato" },
"LUCKY_EGG": { name: "Uovo Fortunato" },
"GOLDEN_EGG": { name: "Uovo d'Oro" },
"LUCKY_EGG": { name: "Fortunuovo" },
"GOLDEN_EGG": { name: "Uovo dorato" },
"SOOTHE_BELL": { name: "Calmanella" },
"EVIOLITE": { name: "Evolcondensa", description: "Misteriosa materia evolutiva. Aumenta la Difesa e la Difesa Speciale di un Pokémon che può ancora evolversi." },
"SOUL_DEW": { name: "Cuorugiada", description: "Aumenta del 10% l'influenza della natura di un Pokémon sulle sue statistiche (Aggiuntivo)." },
"SOUL_DEW": { name: "Cuorugiada", description: "Aumenta del 10% l'influenza della natura di un Pokémon sulle sue statistiche (cumulativo)." },
"NUGGET": { name: "Pepita" },
"BIG_NUGGET": { name: "Granpepita" },
"RELIC_GOLD": { name: "Dobloantico" },
"AMULET_COIN": { name: "Monetamuleto", description: "Aumenta le ricompense in denaro del 20%." },
"GOLDEN_PUNCH": { name: "Pugno Dorato", description: "Garantisce il 50% dei danni inflitti come denaro." },
"COIN_CASE": { name: " Salvadanaio", description: "Dopo ogni 10° battaglia, riceverete il 10% del vostro denaro in interessi." },
"GOLDEN_PUNCH": { name: "Pugno dorato", description: "Fornisce il 50% dei danni inflitti sottoforma di denaro." },
"COIN_CASE": { name: "Salvadanaio", description: "Dopo ogni 10° battaglia, fornisce il 10% del proprio denaro in interessi." },
"LOCK_CAPSULE": { name: "Capsula Scrigno", description: "Permette di bloccare le rarità degli oggetti quando si fa un reroll degli oggetti." },
"LOCK_CAPSULE": { name: "Capsula scrigno", description: "Permette di bloccare le rarità degli oggetti quando si fa un reroll (i costi variano in base alle rarità)." },
"GRIP_CLAW": { name: "Presartigli" },
"WIDE_LENS": { name: "Grandelente" },
@ -202,18 +201,18 @@ export const modifierType: ModifierTypeTranslationEntries = {
"MULTI_LENS": { name: "Multilente" },
"HEALING_CHARM": { name: "Curamuleto", description: "Aumenta del 10% l'efficacia delle mosse e degli oggetti che ripristinano i PS (escluse le rianimazioni)." },
"CANDY_JAR": { name: "Barattolo di caramelle", description: "Aumenta di 1 il numero di livelli aggiunti dalle Caramelle Rare." },
"CANDY_JAR": { name: "Barattolo di caramelle", description: "Aumenta di 1 il numero di livelli aggiunti dalle caramelle rare." },
"BERRY_POUCH": { name: "Porta Bacche", description: "Aggiunge il 30% di possibilità che una bacca usata non venga consumata." },
"BERRY_POUCH": { name: "Porta bacche", description: "Aggiunge il 30% di possibilità che una bacca usata non venga consumata." },
"FOCUS_BAND": { name: "Bandana", description: "Chi ce l'ha ottiene il 10% di possibilità aggiuntivo di evitare un potenziale KO e rimanere con un solo PS." },
"FOCUS_BAND": { name: "Bandana", description: "Il possessore ottiene il 10% di possibilità aggiuntivo di evitare un potenziale KO e rimanere con un solo PS." },
"QUICK_CLAW": { name: "Rapidartigli", description: "Aggiunge una probabilità del 10% di muoversi per primi, indipendentemente dalla velocità (dopo la priorità)." },
"QUICK_CLAW": { name: "Rapidartigli", description: "Aggiunge una probabilità del 10% di muoversi per primi, indipendentemente dalla velocità (priorità escluse)." },
"KINGS_ROCK": { name: "Roccia di re", description: "Aggiunge il 10% di possibilità che una mossa d'attacco faccia tentennare l'avversario." },
"LEFTOVERS": { name: "Avanzi", description: "Ripristina 1/16 dei PS massimi di un Pokémon ogni turno." },
"SHELL_BELL": { name: "Conchinella", description: "Guarisce 1/8 del danno inflitto a un Pokémon." },
"SHELL_BELL": { name: "Conchinella", description: "Cura il possessore di 1/8 del danno inflitto ad un Pokémon." },
"TOXIC_ORB": { name: "Tossicsfera", description: "Sfera bizzarra che iperavvelena chi lha con sé in una lotta." },
"FLAME_ORB": { name: "Fiammosfera", description: "Sfera bizzarra che procura una scottatura a chi lha con sé in una lotta." },
@ -223,22 +222,22 @@ export const modifierType: ModifierTypeTranslationEntries = {
"SHINY_CHARM": { name: "Cromamuleto", description: "Misterioso amuleto luminoso che aumenta la probabilità di incontrare Pokémon cromatici." },
"ABILITY_CHARM": { name: "Abilitamuleto", description: "Aumenta drasticamente la possibilità che un Pokémon selvatico abbia un'abilità nascosta." },
"IV_SCANNER": { name: "Scanner IV", description: "Permette di scansionare gli IV dei Pokémon selvatici. Vengono rivelati 2 IV per pila. I migliori IV vengono mostrati per primi." },
"IV_SCANNER": { name: "Scanner IV", description: "Permette di scansionare gli IV dei Pokémon selvatici. Vengono rivelati 2 IV per ogni scanner. I migliori IV vengono mostrati per primi." },
"DNA_SPLICERS": { name: "Cuneo DNA" },
"MINI_BLACK_HOLE": { name: "Piccolo Buco Nero" },
"MINI_BLACK_HOLE": { name: "Piccolo buco nero" },
"GOLDEN_POKEBALL": { name: "Poké Ball Oro", description: "Aggiunge 1 opzione di oggetto extra alla fine di ogni battaglia." },
"GOLDEN_POKEBALL": { name: "Poké Ball dorata", description: "Aggiunge 1 opzione di oggetto extra alla fine di ogni battaglia." },
"ENEMY_DAMAGE_BOOSTER": { name: "Gettone del Danno", description: "Aumenta il danno del 5%." },
"ENEMY_DAMAGE_REDUCTION": { name: "Gettone della Protezione", description: "Riduce i danni ricevuti del 2.5%." },
"ENEMY_HEAL": { name: "Gettone del Recupero", description: "Cura il 2% dei PS massimi ogni turno." },
"ENEMY_ATTACK_POISON_CHANCE": { name: "Gettone del Veleno" },
"ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Gettone della Paralisi" },
"ENEMY_ATTACK_BURN_CHANCE": { name: "Gettone della Bruciatura" },
"ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Gettone Guarigione Completa", description: "Aggiunge una probabilità del 2.5% a ogni turno di curare una condizione di stato." },
"ENEMY_ENDURE_CHANCE": { name: "Gettone di Resistenza" },
"ENEMY_DAMAGE_BOOSTER": { name: "Gettone del danno", description: "Aumenta i danni inflitti del 5%." },
"ENEMY_DAMAGE_REDUCTION": { name: "Gettone della protezione", description: "Riduce i danni ricevuti del 2.5%." },
"ENEMY_HEAL": { name: "Gettone del recupero", description: "Cura il 2% dei PS massimi ogni turno." },
"ENEMY_ATTACK_POISON_CHANCE": { name: "Gettone del veleno" },
"ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Gettone della paralisi" },
"ENEMY_ATTACK_BURN_CHANCE": { name: "Gettone della bruciatura" },
"ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Gettone guarigione completa", description: "Aggiunge una probabilità del 2.5% a ogni turno di guarire da un problema di stato." },
"ENEMY_ENDURE_CHANCE": { name: "Gettone di resistenza" },
"ENEMY_FUSED_CHANCE": { name: "Gettone della fusione", description: "Aggiunge l'1% di possibilità che un Pokémon selvatico sia una fusione." },
},
SpeciesBoosterItem: {
@ -258,14 +257,14 @@ export const modifierType: ModifierTypeTranslationEntries = {
},
TempBattleStatBoosterStatName: {
"ATK": "Attack",
"DEF": "Defense",
"SPATK": "Sp. Atk",
"SPDEF": "Sp. Def",
"SPD": "Speed",
"ACC": "Accuracy",
"CRIT": "Critical Hit Ratio",
"EVA": "Evasiveness",
"ATK": "Attacco",
"DEF": "Difesa",
"SPATK": "Att. Speciale",
"SPDEF": "Dif. Speciale",
"SPD": "Velocità",
"ACC": "Precisione",
"CRIT": "Tasso di brutti colpi",
"EVA": "Elusione",
"DEFAULT": "???",
},

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "È apparsa una corrente d'aria misteriosa!",
"strongWindsLapseMessage": "La corrente d'aria soffia intensamente.",
"strongWindsEffectMessage": "La corrente misteriosa indebolisce lattacco!",
"strongWindsClearMessage": "La corrente d'aria è cessata."
};

View File

@ -24,7 +24,8 @@ export const battle: SimpleTranslationEntries = {
"hitResultNotVeryEffective": "효과가 별로인 듯하다…",
"hitResultNoEffect": "{{pokemonName}}에게는\n효과가 없는 것 같다…",
"hitResultOneHitKO": "일격필살!",
"attackFailed": "하지만 실패했다!",
"attackFailed": "그러나 실패하고 말았다!!",
"attackMissed": "{{pokemonNameWithAffix}}에게는\n맞지 않았다!",
"attackHitsCount": "{{count}}번 맞았다!",
"rewardGain": "{{modifierName}}[[를]] 받았다!",
"expGain": "{{pokemonName}}[[는]]\n{{exp}} 경험치를 얻었다!",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Music",
"music": "Music: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "BW2 관동 챔피언 배틀",
"battle_johto_champion": "BW2 성도 챔피언 배틀",
@ -62,7 +62,7 @@ export const bgmName: SimpleTranslationEntries = {
"battle_legendary_calyrex": "SWSH 버드렉스 배틀",
"battle_legendary_birds_galar": "SWSH 가라르 전설의 새 배틀",
"battle_legendary_ruinous": "SV 재앙의 보물 배틀",
"battle_legendary_kor_mir": "SV Depths of Area Zero Battle",
"battle_legendary_kor_mir": "SV 에리어 제로 배틀",
"battle_legendary_loyal_three": "SV 세벗들 배틀",
"battle_legendary_ogerpon": "SV 오거폰 배틀",
"battle_legendary_terapagos": "SV 테라파고스 배틀",
@ -74,16 +74,16 @@ export const bgmName: SimpleTranslationEntries = {
"battle_wild": "BW 야생 포켓몬 배틀",
"battle_wild_strong": "BW 강한 야생 포켓몬 조우 배틀",
"end_summit": "불가사의 던전 구조대 DX 천공의 탑 꼭대기",
"battle_rocket_grunt": "HGSS Team Rocket Battle",
"battle_aqua_magma_grunt": "ORAS Team Aqua & Magma Battle",
"battle_galactic_grunt": "BDSP Team Galactic Battle",
"battle_rocket_grunt": "HGSS 로켓단 배틀",
"battle_aqua_magma_grunt": "ORAS 아쿠아단 & 마그마단 배틀",
"battle_galactic_grunt": "BDSP 갤럭시단 배틀",
"battle_plasma_grunt": "BW 플라스마단 배틀",
"battle_flare_grunt": "XY Team Flare Battle",
"battle_rocket_boss": "USUM Giovanni Battle",
"battle_aqua_magma_boss": "ORAS Archie & Maxie Battle",
"battle_galactic_boss": "BDSP Cyrus Battle",
"battle_plasma_boss": "B2W2 Ghetsis Battle",
"battle_flare_boss": "XY Lysandre Battle",
"battle_flare_grunt": "XY 플레어단 배틀",
"battle_rocket_boss": "USUM 비주기 배틀",
"battle_aqua_magma_boss": "ORAS 아강 & 마적 배틀",
"battle_galactic_boss": "BDSP 태홍 배틀",
"battle_plasma_boss": "B2W2 게치스 배틀",
"battle_flare_boss": "XY 플라드리 배틀",
// Biome Music
"abyss": "불가사의 던전 하늘의 탐험대 어둠의 화구",

View File

@ -2,7 +2,7 @@ import { TranslationEntries } from "#app/interfaces/locales";
export const challenges: TranslationEntries = {
"title": "챌린지 조건 설정",
"illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
"illegalEvolution": "{{pokemon}}[[는]] 현재의 챌린지에\n부적합한 포켓몬이 되었습니다!",
"singleGeneration": {
"name": "단일 세대",
"desc": "{{gen}}의 포켓몬만 사용할 수 있습니다.",

View File

@ -20,5 +20,5 @@ export const menuUiHandler: SimpleTranslationEntries = {
"exportData": "데이터 내보내기",
"cancel": "취소",
"losingProgressionWarning": "전투 시작으로부터의 진행 상황을 잃게 됩니다. 계속하시겠습니까?",
"noEggs": "You are not hatching\nany eggs at the moment!"
"noEggs": "부화중인 알이 없습니다!"
} as const;

View File

@ -35,8 +35,8 @@ export const partyUiHandler: SimpleTranslationEntries = {
"cancel": "그만둔다",
// Slot TM text
"able": "배울 수 있다",
"notAble": "배울 수 없다",
"able": "배운다!",
"notAble": "배우지 못함",
"learned": "알고 있다",
// Releasing messages

View File

@ -41,5 +41,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "수수께끼의 난기류가\n비행포켓몬을 지킨다!",
"strongWindsLapseMessage": "수수께끼의 난기류가 강렬하게 불고 있다",
"strongWindsEffectMessage": "수수께끼의 난기류가 공격을 약하게 만들었다!",
"strongWindsClearMessage": "수수께끼의 난기류가 멈췄다!" // 임의번역
};

View File

@ -25,6 +25,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "Isso não afeta {{pokemonName}}!",
"hitResultOneHitKO": "Foi um nocaute de um golpe!",
"attackFailed": "Mas falhou!",
"attackMissed": "{{pokemonNameWithAffix}} desviou do ataque!",
"attackHitsCount": "Acertou {{count}} vezes.",
"rewardGain": "Você recebeu\n{{modifierName}}!",
"expGain": "{{pokemonName}} ganhou\n{{exp}} pontos de experiência.",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Music",
"music": "Music: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 Kanto Champion Battle",
"battle_johto_champion": "B2W2 Johto Champion Battle",

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "Ventos fortes apareceram!",
"strongWindsLapseMessage": "Os ventos fortes continuam.",
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "Os ventos fortes diminuíram.",
};

View File

@ -25,6 +25,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "对{{pokemonName}}没有效果!!",
"hitResultOneHitKO": "一击必杀!",
"attackFailed": "但是失败了!",
"attackMissed": "没有命中{{pokemonNameWithAffix}}",
"attackHitsCount": "击中{{count}}次!",
"rewardGain": "你获得了\n{{modifierName}}",
"expGain": "{{pokemonName}}获得了 {{exp}} 点经验值!",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "BGM",
"music": "BGM: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "黑2白2「决战关都冠军」",
"battle_johto_champion": "黑2白2「决战城都冠军」",

View File

@ -14,7 +14,7 @@ export const partyUiHandler: SimpleTranslationEntries = {
"TRANSFER": "交换",
"ALL": "全部道具",
"PASS_BATON": "接棒",
"UNPAUSE_EVOLUTION": "接触进化暂停",
"UNPAUSE_EVOLUTION": "解除进化暂停",
"REVIVE": "复活",
"choosePokemon": "选择一只宝可梦。",

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "吹起了神秘的乱流!",
"strongWindsLapseMessage": "神秘的乱流势头不减。",
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "神秘的乱流停止了。"
};

View File

@ -22,6 +22,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultNoEffect": "對 {{pokemonName}} 沒有效果!",
"hitResultOneHitKO": "一擊切殺!",
"attackFailed": "但是失敗了!",
"attackMissed": "沒有命中{{pokemonNameWithAffix}}",
"attackHitsCount": "擊中 {{count}} 次!",
"rewardGain": "You received\n{{modifierName}}!",
"expGain": "{{pokemonName}} 獲得了 {{exp}} 經驗值!",

View File

@ -1,7 +1,7 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const bgmName: SimpleTranslationEntries = {
"music": "Music",
"music": "Music: ",
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 Kanto Champion Battle",
"battle_johto_champion": "B2W2 Johto Champion Battle",

View File

@ -40,5 +40,6 @@ export const weather: SimpleTranslationEntries = {
"strongWindsStartMessage": "吹起了神秘的亂流!",
"strongWindsLapseMessage": "神秘的亂流勢頭不減。",
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "神秘的亂流停止了。"
};

View File

@ -2894,7 +2894,7 @@ export class MoveEffectPhase extends PokemonPhase {
if (!activeTargets.length || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]])) {
this.stopMultiHit();
if (activeTargets.length) {
this.scene.queueMessage(getPokemonMessage(user, "'s\nattack missed!"));
this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(this.getTarget()) }));
moveHistoryEntry.result = MoveResult.MISS;
applyMoveAttrs(MissEffectAttr, user, null, move);
} else {
@ -2912,7 +2912,7 @@ export class MoveEffectPhase extends PokemonPhase {
for (const target of targets) {
if (!targetHitChecks[target.getBattlerIndex()]) {
this.stopMultiHit(target);
this.scene.queueMessage(getPokemonMessage(user, "'s\nattack missed!"));
this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) }));
if (moveHistoryEntry.result === MoveResult.PENDING) {
moveHistoryEntry.result = MoveResult.MISS;
}
@ -3616,7 +3616,9 @@ export class DamagePhase extends PokemonPhase {
super.start();
if (this.damageResult === HitResult.ONE_HIT_KO) {
if (this.scene.moveAnimations) {
this.scene.toggleInvert(true);
}
this.scene.time.delayedCall(Utils.fixedInt(1000), () => {
this.scene.toggleInvert(false);
this.applyDamage();

View File

@ -316,10 +316,10 @@ export const achvs = {
CATCH_LEGENDARY: new Achv("CATCH_LEGENDARY", "", "CATCH_LEGENDARY.description","mb", 100).setSecret(),
SEE_SHINY: new Achv("SEE_SHINY", "", "SEE_SHINY.description","pb_gold", 75),
SHINY_PARTY: new Achv("SHINY_PARTY", "", "SHINY_PARTY.description","shiny_charm", 100).setSecret(true),
HATCH_MYTHICAL: new Achv("HATCH_MYTHICAL", "", "HATCH_MYTHICAL.description","pair_of_tickets", 75).setSecret(),
HATCH_SUB_LEGENDARY: new Achv("HATCH_SUB_LEGENDARY","", "HATCH_SUB_LEGENDARY.description","mystic_ticket", 100).setSecret(),
HATCH_LEGENDARY: new Achv("HATCH_LEGENDARY","", "HATCH_LEGENDARY.description","mystic_ticket", 125).setSecret(),
HATCH_SHINY: new Achv("HATCH_SHINY","", "HATCH_SHINY.description","golden_mystic_ticket", 100).setSecret(),
HATCH_MYTHICAL: new Achv("HATCH_MYTHICAL", "", "HATCH_MYTHICAL.description","mystery_egg", 75).setSecret(),
HATCH_SUB_LEGENDARY: new Achv("HATCH_SUB_LEGENDARY","", "HATCH_SUB_LEGENDARY.description","oval_stone", 100).setSecret(),
HATCH_LEGENDARY: new Achv("HATCH_LEGENDARY","", "HATCH_LEGENDARY.description","lucky_egg", 125).setSecret(),
HATCH_SHINY: new Achv("HATCH_SHINY","", "HATCH_SHINY.description","golden_egg", 100).setSecret(),
HIDDEN_ABILITY: new Achv("HIDDEN_ABILITY","", "HIDDEN_ABILITY.description","ability_charm", 75),
PERFECT_IVS: new Achv("PERFECT_IVS","", "PERFECT_IVS.description","blunder_policy", 100),
CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY","", "CLASSIC_VICTORY.description","relic_crown", 150),

View File

@ -0,0 +1,82 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import Phaser from "phaser";
import GameManager from "#app/test/utils/gameManager";
import * as overrides from "#app/overrides";
import { Species } from "#enums/species";
import {
TurnStartPhase,
} from "#app/phases";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { allMoves } from "#app/data/move.js";
describe("Weather - Strong Winds", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(10);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.TAILLOW);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.DELTA_STREAM);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.THUNDERBOLT, Moves.ICE_BEAM, Moves.ROCK_SLIDE]);
});
it("electric type move is not very effective on Rayquaza", async () => {
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RAYQUAZA);
await game.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon();
game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT));
await game.phaseInterceptor.to(TurnStartPhase);
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.THUNDERBOLT].type, pikachu)).toBe(0.5);
});
it("electric type move is neutral for flying type pokemon", async () => {
await game.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon();
game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT));
await game.phaseInterceptor.to(TurnStartPhase);
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.THUNDERBOLT].type, pikachu)).toBe(1);
});
it("ice type move is neutral for flying type pokemon", async () => {
await game.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon();
game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM));
await game.phaseInterceptor.to(TurnStartPhase);
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ICE_BEAM].type, pikachu)).toBe(1);
});
it("rock type move is neutral for flying type pokemon", async () => {
await game.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon();
game.doAttack(getMovePosition(game.scene, 0, Moves.ROCK_SLIDE));
await game.phaseInterceptor.to(TurnStartPhase);
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1);
});
});

View File

@ -0,0 +1,149 @@
import {
BattleStat,
getBattleStatLevelChangeDescription,
getBattleStatName,
} from "#app/data/battle-stat.js";
import { describe, expect, it } from "vitest";
import { arrayOfRange, mockI18next } from "./utils/testUtils";
const TEST_BATTLE_STAT = -99 as unknown as BattleStat;
const TEST_POKEMON = "Testmon";
const TEST_STAT = "Teststat";
describe("battle-stat", () => {
describe("getBattleStatName", () => {
it("should return the correct name for each BattleStat", () => {
mockI18next();
expect(getBattleStatName(BattleStat.ATK)).toBe("pokemonInfo:Stat.ATK");
expect(getBattleStatName(BattleStat.DEF)).toBe("pokemonInfo:Stat.DEF");
expect(getBattleStatName(BattleStat.SPATK)).toBe(
"pokemonInfo:Stat.SPATK"
);
expect(getBattleStatName(BattleStat.SPDEF)).toBe(
"pokemonInfo:Stat.SPDEF"
);
expect(getBattleStatName(BattleStat.SPD)).toBe("pokemonInfo:Stat.SPD");
expect(getBattleStatName(BattleStat.ACC)).toBe("pokemonInfo:Stat.ACC");
expect(getBattleStatName(BattleStat.EVA)).toBe("pokemonInfo:Stat.EVA");
});
it("should fall back to ??? for an unknown BattleStat", () => {
expect(getBattleStatName(TEST_BATTLE_STAT)).toBe("???");
});
});
describe("getBattleStatLevelChangeDescription", () => {
it("should return battle:statRose for +1", () => {
mockI18next();
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
1,
true
);
expect(message).toBe("battle:statRose");
});
it("should return battle:statSharplyRose for +2", () => {
mockI18next();
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
2,
true
);
expect(message).toBe("battle:statSharplyRose");
});
it("should return battle:statRoseDrastically for +3 to +6", () => {
mockI18next();
arrayOfRange(3, 6).forEach((n) => {
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
n,
true
);
expect(message).toBe("battle:statRoseDrastically");
});
});
it("should return battle:statWontGoAnyHigher for 7 or higher", () => {
mockI18next();
arrayOfRange(7, 10).forEach((n) => {
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
n,
true
);
expect(message).toBe("battle:statWontGoAnyHigher");
});
});
it("should return battle:statFell for -1", () => {
mockI18next();
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
1,
false
);
expect(message).toBe("battle:statFell");
});
it("should return battle:statHarshlyFell for -2", () => {
mockI18next();
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
2,
false
);
expect(message).toBe("battle:statHarshlyFell");
});
it("should return battle:statSeverelyFell for -3 to -6", () => {
mockI18next();
arrayOfRange(3, 6).forEach((n) => {
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
n,
false
);
expect(message).toBe("battle:statSeverelyFell");
});
});
it("should return battle:statWontGoAnyLower for -7 or lower", () => {
mockI18next();
arrayOfRange(7, 10).forEach((n) => {
const message = getBattleStatLevelChangeDescription(
TEST_POKEMON,
TEST_STAT,
n,
false
);
expect(message).toBe("battle:statWontGoAnyLower");
});
});
});
});

View File

@ -7,9 +7,9 @@ import {
getStatusEffectObtainText,
getStatusEffectOverlapText,
} from "#app/data/status-effect";
import i18next, { ParseKeys } from "i18next";
import i18next from "i18next";
import { mockI18next } from "../utils/testUtils";
const tMock = (key: ParseKeys) => key;
const pokemonName = "PKM";
const sourceText = "SOURCE";
@ -22,7 +22,7 @@ describe("status-effect", () => {
const statusEffect = StatusEffect.NONE;
it("should return the obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:none.obtain");
@ -32,7 +32,7 @@ describe("status-effect", () => {
});
it("should return the source-obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName, sourceText);
expect(text).toBe("statusEffect:none.obtainSource");
@ -42,25 +42,25 @@ describe("status-effect", () => {
});
it("should return the activation text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectActivationText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:none.activation");
});
it("should return the overlap text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:none.overlap");
});
it("should return the heal text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectHealText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:none.heal");
});
it("should return the descriptor", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectDescriptor(statusEffect);
expect(text).toBe("statusEffect:none.description");
});
@ -70,7 +70,7 @@ describe("status-effect", () => {
const statusEffect = StatusEffect.POISON;
it("should return the obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:poison.obtain");
@ -80,25 +80,25 @@ describe("status-effect", () => {
});
it("should return the activation text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectActivationText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:poison.activation");
});
it("should return the descriptor", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectDescriptor(statusEffect);
expect(text).toBe("statusEffect:poison.description");
});
it("should return the heal text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectHealText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:poison.heal");
});
it("should return the overlap text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:poison.overlap");
});
@ -108,7 +108,7 @@ describe("status-effect", () => {
const statusEffect = StatusEffect.TOXIC;
it("should return the obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:toxic.obtain");
@ -118,25 +118,25 @@ describe("status-effect", () => {
});
it("should return the activation text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectActivationText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:toxic.activation");
});
it("should return the descriptor", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectDescriptor(statusEffect);
expect(text).toBe("statusEffect:toxic.description");
});
it("should return the heal text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectHealText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:toxic.heal");
});
it("should return the overlap text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:toxic.overlap");
});
@ -146,7 +146,7 @@ describe("status-effect", () => {
const statusEffect = StatusEffect.PARALYSIS;
it("should return the obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:paralysis.obtain");
@ -156,25 +156,25 @@ describe("status-effect", () => {
});
it("should return the activation text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectActivationText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:paralysis.activation");
});
it("should return the descriptor", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectDescriptor(statusEffect);
expect(text).toBe("statusEffect:paralysis.description");
});
it("should return the heal text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectHealText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:paralysis.heal");
});
it("should return the overlap text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:paralysis.overlap");
});
@ -184,7 +184,7 @@ describe("status-effect", () => {
const statusEffect = StatusEffect.SLEEP;
it("should return the obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:sleep.obtain");
@ -194,25 +194,25 @@ describe("status-effect", () => {
});
it("should return the activation text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectActivationText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:sleep.activation");
});
it("should return the descriptor", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectDescriptor(statusEffect);
expect(text).toBe("statusEffect:sleep.description");
});
it("should return the heal text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectHealText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:sleep.heal");
});
it("should return the overlap text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:sleep.overlap");
});
@ -222,7 +222,7 @@ describe("status-effect", () => {
const statusEffect = StatusEffect.FREEZE;
it("should return the obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:freeze.obtain");
@ -232,25 +232,25 @@ describe("status-effect", () => {
});
it("should return the activation text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectActivationText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:freeze.activation");
});
it("should return the descriptor", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectDescriptor(statusEffect);
expect(text).toBe("statusEffect:freeze.description");
});
it("should return the heal text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectHealText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:freeze.heal");
});
it("should return the overlap text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:freeze.overlap");
});
@ -260,7 +260,7 @@ describe("status-effect", () => {
const statusEffect = StatusEffect.BURN;
it("should return the obtain text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectObtainText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:burn.obtain");
@ -270,25 +270,25 @@ describe("status-effect", () => {
});
it("should return the activation text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectActivationText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:burn.activation");
});
it("should return the descriptor", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectDescriptor(statusEffect);
expect(text).toBe("statusEffect:burn.description");
});
it("should return the heal text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectHealText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:burn.heal");
});
it("should return the overlap text", () => {
vi.spyOn(i18next, "t").mockImplementation(tMock);
mockI18next();
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
expect(text).toBe("statusEffect:burn.overlap");
});

View File

@ -0,0 +1,83 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import Phaser from "phaser";
import GameManager from "#app/test/utils/gameManager";
import * as overrides from "#app/overrides";
import { Species } from "#enums/species";
import {
MoveEffectPhase,
} from "#app/phases";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { NumberHolder } from "#app/utils.js";
import Move from "#app/data/move.js";
import Pokemon from "#app/field/pokemon.js";
import { allMoves, OpponentHighHpPowerAttr } from "#app/data/move.js";
describe("Moves - Hard Press", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.NONE);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.HARD_PRESS]);
});
it("power varies between 1 and 100, and is greater the more HP the target has", async () => {
await game.startBattle([Species.GRAVELER]);
const moveToBeUsed = allMoves[Moves.HARD_PRESS];
game.doAttack(getMovePosition(game.scene, 0, moveToBeUsed));
await game.phaseInterceptor.to(MoveEffectPhase);
const enemy = game.scene.getEnemyPokemon();
const movePower = getMockedMovePower(enemy, game.scene.getPlayerPokemon(), moveToBeUsed);
const moveMaxBasePower = getMoveMaxBasePower(moveToBeUsed);
expect(movePower).toBe(moveMaxBasePower * enemy.getHpRatio());
});
});
/**
* Calculates the mocked move power based on the attributes of the move and the opponent's high HP.
*
* @param defender - The defending Pokémon.
* @param attacker - The attacking Pokémon.
* @param move - The move being used.
* @returns The calculated move power.
*/
const getMockedMovePower = (defender: Pokemon, attacker: Pokemon, move: Move) => {
const powerHolder = new NumberHolder(move.power);
if (move.hasAttr(OpponentHighHpPowerAttr)) {
const attr = move.getAttrs(OpponentHighHpPowerAttr);
attr[0].apply(attacker, defender, move, [ powerHolder ]);
}
return powerHolder.value;
};
/**
* Retrieves the maximum base power of a move based on its attributes.
*
* @param move - The move which maximum base power is being retrieved.
* @returns The maximum base power of the move.
*/
const getMoveMaxBasePower = (move: Move) => {
const attr = move.getAttrs(OpponentHighHpPowerAttr);
return (attr[0] as OpponentHighHpPowerAttr)["maxBasePower"];
};

View File

@ -0,0 +1,100 @@
import { BerryType } from "#app/enums/berry-type";
import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import { Button } from "#app/enums/buttons";
import * as overrides from "#app/overrides";
import {
BattleEndPhase,
SelectModifierPhase
} from "#app/phases";
import GameManager from "#app/test/utils/gameManager";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui";
import Phaser from "phaser";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { getMovePosition } from "../utils/gameManagerUtils";
describe("UI - Transfer Items", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(async () => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(1);
vi.spyOn(overrides, "STARTING_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([
{ name: "BERRY", count: 1, type: BerryType.SITRUS },
{ name: "BERRY", count: 2, type: BerryType.APICOT },
{ name: "BERRY", count: 2, type: BerryType.LUM },
]);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.DRAGON_CLAW]);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
await game.startBattle([Species.RAYQUAZA, Species.RAYQUAZA, Species.RAYQUAZA]);
game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_CLAW));
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler);
const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler;
handler.setCursor(1);
handler.processInput(Button.ACTION);
game.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER);
});
await game.phaseInterceptor.to(BattleEndPhase);
});
it("check red tint for held item limit in transfer menu", async () => {
game.onNextPrompt("SelectModifierPhase", Mode.PARTY, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler);
const handler = game.scene.ui.getHandler() as PartyUiHandler;
handler.processInput(Button.ACTION);
expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Sitrus Berry"))).toBe(true);
expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Apicot Berry (2)"))).toBe(true);
expect(handler.optionsContainer.list.some((option) => RegExp(/Lum Berry\[color.*(2)/).exec((option as BBCodeText).text))).toBe(true);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.to(SelectModifierPhase);
}, 20000);
it("check transfer option for pokemon to transfer to", async () => {
game.onNextPrompt("SelectModifierPhase", Mode.PARTY, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler);
const handler = game.scene.ui.getHandler() as PartyUiHandler;
handler.processInput(Button.ACTION); // select Pokemon
handler.processInput(Button.ACTION); // select held item (Sitrus Berry)
handler.setCursor(1); // move to other Pokemon
handler.processInput(Button.ACTION); // select Pokemon
expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Transfer"))).toBe(true);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.to(SelectModifierPhase);
}, 20000);
});

View File

@ -0,0 +1,23 @@
import i18next, { type ParseKeys } from "i18next";
import { vi } from "vitest";
/**
* Sets up the i18next mock.
* Includes a i18next.t mocked implementation only returning the raw key (`(key) => key`)
*
* @returns A spy/mock of i18next
*/
export function mockI18next() {
return vi.spyOn(i18next, "t").mockImplementation((key: ParseKeys) => key);
}
/**
* Creates an array of range `start - end`
*
* @param start start number e.g. 1
* @param end end number e.g. 10
* @returns an array of numbers
*/
export function arrayOfRange(start: integer, end: integer) {
return Array.from({ length: end - start }, (_v, k) => k + start);
}

View File

@ -3,24 +3,16 @@ import {addTextObject, TextStyle} from "./text";
import i18next from "i18next";
import * as Utils from "#app/utils";
const hiddenX = -150;
const shownX = 0;
const baseY = 0;
export default class BgmBar extends Phaser.GameObjects.Container {
private defaultWidth: number;
private defaultHeight: number;
private bg: Phaser.GameObjects.NineSlice;
private musicText: Phaser.GameObjects.Text;
private noteText: Phaser.GameObjects.Text;
private tween: Phaser.Tweens.Tween;
private autoHideTimer: NodeJS.Timeout;
private queue: (string)[] = [];
public shown: boolean;
@ -29,19 +21,15 @@ export default class BgmBar extends Phaser.GameObjects.Container {
}
setup(): void {
this.defaultWidth = 200;
this.defaultWidth = 230;
this.defaultHeight = 100;
this.bg = this.scene.add.nineslice(-5, -5, "ability_bar_left", null, this.defaultWidth, this.defaultHeight, 0, 0, 10, 10);
this.bg = this.scene.add.nineslice(-5, -5, "bgm_bar", null, this.defaultWidth, this.defaultHeight, 0, 0, 10, 10);
this.bg.setOrigin(0, 0);
this.add(this.bg);
this.noteText = addTextObject(this.scene, 5, 5, "", TextStyle.MESSAGE, {fontSize: "72px"});
this.noteText.setOrigin(0, 0);
this.add(this.noteText);
this.musicText = addTextObject(this.scene, 30, 5, "", TextStyle.MESSAGE, {fontSize: "72px"});
this.musicText = addTextObject(this.scene, 5, 5, "", TextStyle.BGM_BAR);
this.musicText.setOrigin(0, 0);
this.musicText.setWordWrapWidth(650, true);
@ -56,16 +44,15 @@ export default class BgmBar extends Phaser.GameObjects.Container {
* @param {string} bgmName The name of the BGM to set.
*/
setBgmToBgmBar(bgmName: string): void {
this.noteText.setText(`${i18next.t("bgmName:music")}:`);
this.musicText.setText(`${this.getRealBgmName(bgmName)}`);
this.musicText.setText(`${i18next.t("bgmName:music")}${this.getRealBgmName(bgmName)}`);
if (!(this.scene as BattleScene).showBgmBar) {
return;
}
this.musicText.width = this.bg.width - 20;
this.musicText.setWordWrapWidth(this.defaultWidth * 4);
this.bg.width = Math.min(this.defaultWidth, this.noteText.displayWidth + this.musicText.displayWidth + 30);
this.bg.width = Math.min(this.defaultWidth, this.musicText.displayWidth + 23);
this.bg.height = Math.min(this.defaultHeight, this.musicText.displayHeight + 20);
(this.scene as BattleScene).fieldUI.bringToTop(this);
@ -97,5 +84,3 @@ export default class BgmBar extends Phaser.GameObjects.Container {
return i18next.t([`bgmName:${bgmName}`, "bgmName:missing_entries"], {name: Utils.formatText(bgmName)});
}
}

View File

@ -1,12 +1,12 @@
import { CommandPhase, SelectModifierPhase } from "../phases";
import BattleScene from "../battle-scene";
import { PlayerPokemon, PokemonMove } from "../field/pokemon";
import { addTextObject, TextStyle } from "./text";
import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text";
import { Command } from "./command-ui-handler";
import MessageUiHandler from "./message-ui-handler";
import { Mode } from "./ui";
import * as Utils from "../utils";
import { PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier";
import { PokemonBaseStatModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier";
import { allMoves } from "../data/move";
import { getGenderColor, getGenderSymbol } from "../data/gender";
import { StatusEffect } from "../data/status-effect";
@ -19,6 +19,7 @@ import {Button} from "#enums/buttons";
import { applyChallenges, ChallengeType } from "#app/data/challenge.js";
import MoveInfoOverlay from "./move-info-overlay";
import i18next from "i18next";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { Moves } from "#enums/moves";
const defaultMessage = i18next.t("partyUiHandler:choosePokemon");
@ -85,7 +86,8 @@ export default class PartyUiHandler extends MessageUiHandler {
private optionsCursor: integer = 0;
private optionsScrollCursor: integer = 0;
private optionsScrollTotal: integer = 0;
private optionsContainer: Phaser.GameObjects.Container;
/** This is only public for test/ui/transfer-item.test.ts */
public optionsContainer: Phaser.GameObjects.Container;
private optionsBg: Phaser.GameObjects.NineSlice;
private optionsCursorObj: Phaser.GameObjects.Image;
private options: integer[];
@ -819,7 +821,7 @@ export default class PartyUiHandler extends MessageUiHandler {
optionEndIndex = this.options.length;
let widestOptionWidth = 0;
const optionTexts: Phaser.GameObjects.Text[] = [];
const optionTexts: BBCodeText[] = [];
for (let o = optionStartIndex; o < optionEndIndex; o++) {
const option = this.options[this.options.length - (o + 1)];
@ -861,27 +863,42 @@ export default class PartyUiHandler extends MessageUiHandler {
const move = learnableLevelMoves[option];
optionName = allMoves[move].name;
altText = !pokemon.getSpeciesForm().getLevelMoves().find(plm => plm[1] === move);
} else {
if (option === PartyOption.ALL) {
} else if (option === PartyOption.ALL) {
optionName = i18next.t("partyUiHandler:ALL");
} else {
const itemModifier = itemModifiers[option];
optionName = itemModifier.type.name;
/** For every item that has stack bigger than 1, display the current quantity selection */
if (this.transferQuantitiesMax[option] > 1) {
optionName += ` (${this.transferQuantities[option]})`;
}
}
}
const yCoord = -6 - 16 * o;
const optionText = addTextObject(this.scene, 0, yCoord - 16, optionName, TextStyle.WINDOW);
const optionText = addBBCodeTextObject(this.scene, 0, yCoord - 16, optionName, TextStyle.WINDOW, { maxLines: 1 });
if (altText) {
optionText.setColor("#40c8f8");
optionText.setShadowColor("#006090");
}
optionText.setOrigin(0, 0);
/** For every item that has stack bigger than 1, display the current quantity selection */
if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && this.transferQuantitiesMax[option] > 1) {
const itemModifier = itemModifiers[option];
/** Not sure why getMaxHeldItemCount had an error, but it only checks the Pokemon parameter if the modifier is PokemonBaseStatModifier */
if (itemModifier === undefined || itemModifier instanceof PokemonBaseStatModifier) {
continue;
}
let amountText = ` (${this.transferQuantities[option]})`;
/** If the amount held is the maximum, display the count in red */
if (this.transferQuantitiesMax[option] === itemModifier.getMaxHeldItemCount(undefined)) {
amountText = `[color=${getTextColor(TextStyle.SUMMARY_RED)}]${amountText}[/color]`;
}
optionText.setText(optionName + amountText);
}
optionText.setText(`[shadow]${optionText.text}[/shadow]`);
optionTexts.push(optionText);
widestOptionWidth = Math.max(optionText.displayWidth, widestOptionWidth);

View File

@ -34,7 +34,8 @@ export enum TextStyle {
MOVE_PP_HALF_FULL,
MOVE_PP_NEAR_EMPTY,
MOVE_PP_EMPTY,
SMALLER_WINDOW_ALT
SMALLER_WINDOW_ALT,
BGM_BAR
}
export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): Phaser.GameObjects.Text {
@ -146,6 +147,11 @@ export function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraSty
shadowXpos = 3;
shadowYpos = 3;
break;
case TextStyle.BGM_BAR:
styleOptions.fontSize = defaultFontSize - 24;
shadowXpos = 3;
shadowYpos = 3;
break;
}
const shadowColor = getTextColor(style, true, uiTheme);
@ -235,6 +241,8 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
return !shadow ? "#f88880" : "#f83018";
case TextStyle.SMALLER_WINDOW_ALT:
return !shadow ? "#484848" : "#d0d0c8";
case TextStyle.BGM_BAR:
return !shadow ? "#f8f8f8" : "#6b5a73";
}
}