Compare commits

..

10 Commits

Author SHA1 Message Date
Terrorforge
6917db7429
[Balance] give Goomy Regenerator (#2248) 2024-06-15 12:23:32 -04:00
Tempoanon
fdf139d529
[Bug] Add rest of trailblaze Pokemon (#2239) 2024-06-15 12:18:52 -04:00
chaosgrimmon
4e8a2e87d2
[Sprite] Replace Togedemaru Animation Datafiles (#2255)
* [Sprite] Replace Exp front Togedemaru .json

animation stretched 11% upon artist request: https://discord.com/channels/1125469663833370665/1229465263532019712/1251422382745325609

* [Sprite] Replace exp back Togedemaru .json

taken from exp/back/shiny/777.json

* [Sprite] Extend exp front shiny Togedemaru .json

animation stretched 11% upon artist request: https://discord.com/channels/1125469663833370665/1229465263532019712/1251422382745325609
2024-06-15 12:14:59 -04:00
Adrian T
dbecb72890
[Bug] add ability revelead for trace, refactor (#2258) 2024-06-15 12:13:59 -04:00
Adrian T
0b019d9823
[Ability] Implement Wonder Skin (#2231)
* implement wonder skin

* add unit tests

* fixes

* move applyPreDefendAbAttrs
2024-06-15 17:06:32 +01:00
Adam Clemons
422a561dfe
[Feature] Add Missing Champion Dialogue (#2120)
* Add Alder dialogue

* Add Kieran dialogue

* Add line breaks

* typo fix

* Add placeholder dialogue
2024-06-15 16:47:44 +01:00
Lugiad
523f818e12
[Localization] Many corrections of recent French translations (#2257)
* Update ability-trigger.ts

* Update achv.ts

* Update battle.ts

* Update challenges.ts

* Update battle.ts

* Update party-ui-handler.ts

* Update pokemon-info-container.ts

* Update trainers.ts

* Update achv.ts

* Update achv.ts

* Update achv.ts

* Update splash-messages.ts

* Update achv.ts

* Update achv.ts

* Update trainers.ts

* Update src/locales/fr/achv.ts

Co-authored-by: Dakurei <maxime.palanchini@gmail.com>

* Update challenges.ts

* Update src/locales/fr/battle.ts

Co-authored-by: Dakurei <maxime.palanchini@gmail.com>

* Update battle.ts

* Update battle.ts

---------

Co-authored-by: Dakurei <maxime.palanchini@gmail.com>
2024-06-15 16:28:33 +01:00
Alexis Faizeau
8e5b454c87
[Localization] Fix french translations (#2253)
* Translate missing fr keys for acheviements

* Translate missing fr keys for ability triggers

* Translate missing fr keys for battle

* Translate missing fr keys for fight ui handler

* Translate missing fr keys for challenge

* Translate missing fr keys for party ui handler

* Translate missing fr keys for pokémon infos container

* Translate missing fr keys for trainers
2024-06-15 13:06:57 +02:00
Franck TROUILLEZ
a4b07158f9
[QoL] Add ALL option when transferring items to Pokemons (#1694)
* Add ALL option to transfer menu

It adds a new attribute to the PartyUiHandler to track whether the transfer is meant for all items of only for a particular one

It also introduces translations for PartyUiHandler, even though only the 'ALL' option can be translated for now.

* Use updated translation key for i18n for partyUiHandler:ALL

* Fix duplicated import

* Use optionCursor instead of optionCursorWithScroll to check if we need to transfer ALL
2024-06-15 12:32:15 +02:00
EmberCM
16084878c3
Remove random trailing commas (#2245) 2024-06-15 12:13:54 +02:00
31 changed files with 3708 additions and 5291 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@
"scale": 1,
"frames": [
{
"filename": "0034.png",
"filename": "0039.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -31,7 +31,7 @@
}
},
{
"filename": "0042.png",
"filename": "0047.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -52,7 +52,28 @@
}
},
{
"filename": "0035.png",
"filename": "0040.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 44
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 37,
"h": 44
},
"frame": {
"x": 0,
"y": 44,
"w": 37,
"h": 44
}
},
{
"filename": "0046.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -88,13 +109,13 @@
},
"frame": {
"x": 0,
"y": 44,
"y": 88,
"w": 37,
"h": 44
}
},
{
"filename": "0036.png",
"filename": "0043.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -115,7 +136,7 @@
}
},
{
"filename": "0038.png",
"filename": "0045.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -136,28 +157,7 @@
}
},
{
"filename": "0040.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 44
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 37,
"h": 44
},
"frame": {
"x": 0,
"y": 88,
"w": 37,
"h": 44
}
},
{
"filename": "0006.png",
"filename": "0007.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -178,7 +178,7 @@
}
},
{
"filename": "0012.png",
"filename": "0014.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -199,7 +199,7 @@
}
},
{
"filename": "0018.png",
"filename": "0021.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -220,7 +220,7 @@
}
},
{
"filename": "0024.png",
"filename": "0028.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -241,7 +241,7 @@
}
},
{
"filename": "0030.png",
"filename": "0035.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -283,7 +283,7 @@
}
},
{
"filename": "0007.png",
"filename": "0008.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -304,7 +304,7 @@
}
},
{
"filename": "0013.png",
"filename": "0015.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -325,7 +325,7 @@
}
},
{
"filename": "0019.png",
"filename": "0022.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -346,7 +346,7 @@
}
},
{
"filename": "0025.png",
"filename": "0029.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -367,7 +367,7 @@
}
},
{
"filename": "0031.png",
"filename": "0036.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -388,7 +388,7 @@
}
},
{
"filename": "0045.png",
"filename": "0050.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -430,7 +430,7 @@
}
},
{
"filename": "0011.png",
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -451,7 +451,7 @@
}
},
{
"filename": "0017.png",
"filename": "00012.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -472,7 +472,7 @@
}
},
{
"filename": "0023.png",
"filename": "0013.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -493,7 +493,7 @@
}
},
{
"filename": "0029.png",
"filename": "0019.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -514,7 +514,113 @@
}
},
{
"filename": "0032.png",
"filename": "0020.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 44
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 40,
"h": 41
},
"frame": {
"x": 117,
"y": 0,
"w": 40,
"h": 41
}
},
{
"filename": "0026.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 44
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 40,
"h": 41
},
"frame": {
"x": 117,
"y": 0,
"w": 40,
"h": 41
}
},
{
"filename": "0027.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 44
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 40,
"h": 41
},
"frame": {
"x": 117,
"y": 0,
"w": 40,
"h": 41
}
},
{
"filename": "0033.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 44
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 40,
"h": 41
},
"frame": {
"x": 117,
"y": 0,
"w": 40,
"h": 41
}
},
{
"filename": "0034.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 40,
"h": 44
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 40,
"h": 41
},
"frame": {
"x": 117,
"y": 0,
"w": 40,
"h": 41
}
},
{
"filename": "0037.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -535,7 +641,7 @@
}
},
{
"filename": "0044.png",
"filename": "0049.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -577,7 +683,7 @@
}
},
{
"filename": "0008.png",
"filename": "0009.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -598,7 +704,7 @@
}
},
{
"filename": "0014.png",
"filename": "0016.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -619,7 +725,7 @@
}
},
{
"filename": "0020.png",
"filename": "0023.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -640,7 +746,7 @@
}
},
{
"filename": "0026.png",
"filename": "0030.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -682,7 +788,7 @@
}
},
{
"filename": "0010.png",
"filename": "0011.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -703,7 +809,7 @@
}
},
{
"filename": "0016.png",
"filename": "0018.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -724,7 +830,7 @@
}
},
{
"filename": "0022.png",
"filename": "0025.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -745,7 +851,7 @@
}
},
{
"filename": "0028.png",
"filename": "0032.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -787,7 +893,7 @@
}
},
{
"filename": "0009.png",
"filename": "0010.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -808,7 +914,7 @@
}
},
{
"filename": "0015.png",
"filename": "0017.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -829,7 +935,7 @@
}
},
{
"filename": "0021.png",
"filename": "0024.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -850,7 +956,7 @@
}
},
{
"filename": "0027.png",
"filename": "0031.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -871,7 +977,7 @@
}
},
{
"filename": "0037.png",
"filename": "0042.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -892,7 +998,7 @@
}
},
{
"filename": "0039.png",
"filename": "0044.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -913,7 +1019,7 @@
}
},
{
"filename": "0033.png",
"filename": "0038.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
@ -934,7 +1040,7 @@
}
},
{
"filename": "0043.png",
"filename": "0048.png",
"rotated": false,
"trimmed": true,
"sourceSize": {

View File

@ -574,6 +574,24 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr {
}
}
/**
* Reduces the accuracy of status moves used against the Pokémon with this ability to 50%.
* Used by Wonder Skin.
*
* @extends PreDefendAbAttr
*/
export class WonderSkinAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const moveAccuracy = args[0] as Utils.NumberHolder;
if (move.category === MoveCategory.STATUS && moveAccuracy.value >= 50) {
moveAccuracy.value = 50;
return true;
}
return false;
}
}
export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr {
private stat: BattleStat;
private levels: integer;
@ -1881,6 +1899,7 @@ export class TraceAbAttr extends PostSummonAbAttr {
pokemon.summonData.ability = target.getAbility().id;
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` traced ${target.name}'s\n${allAbilities[target.getAbility().id].name}!`));
setAbilityRevealed(target);
return true;
}
@ -2439,9 +2458,7 @@ export class FriskAbAttr extends PostSummonAbAttr {
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
for (const opponent of pokemon.getOpponents()) {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " frisked " + opponent.name + "'s " + opponent.getAbility().name + "!"));
if (opponent.battleData) {
opponent.battleData.abilityRevealed = true;
}
setAbilityRevealed(opponent);
}
return true;
}
@ -3802,6 +3819,17 @@ function queueShowAbility(pokemon: Pokemon, passive: boolean): void {
pokemon.scene.clearPhaseQueueSplice();
}
/**
* Sets the ability of a Pokémon as revealed.
*
* @param pokemon - The Pokémon whose ability is being revealed.
*/
function setAbilityRevealed(pokemon: Pokemon): void {
if (pokemon.battleData) {
pokemon.battleData.abilityRevealed = true;
}
}
export const allAbilities = [ new Ability(Abilities.NONE, 3) ];
export function initAbilities() {
@ -4250,8 +4278,8 @@ export function initAbilities() {
.attr(BlockWeatherDamageAttr, WeatherType.SANDSTORM)
.condition(getWeatherCondition(WeatherType.SANDSTORM)),
new Ability(Abilities.WONDER_SKIN, 5)
.ignorable()
.unimplemented(),
.attr(WonderSkinAbAttr)
.ignorable(),
new Ability(Abilities.ANALYTIC, 5)
.attr(MovePowerBoostAbAttr, (user, target, move) => !!target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command !== Command.FIGHT, 1.3),
new Ability(Abilities.ILLUSION, 5)

View File

@ -2934,7 +2934,7 @@ export function initBiomes() {
[ Species.AZUMARILL, Type.WATER, Type.FAIRY, [
[ Biome.LAKE, BiomePoolTier.COMMON, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ],
[ Biome.LAKE, BiomePoolTier.BOSS, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ],
[ Biome.FAIRY_CAVE, BiomePoolTier.COMMON ],
[ Biome.FAIRY_CAVE, BiomePoolTier.COMMON ]
]
],
[ Species.SUDOWOODO, Type.ROCK, -1, [
@ -3630,7 +3630,7 @@ export function initBiomes() {
[ Species.FLYGON, Type.GROUND, Type.DRAGON, [
[ Biome.DESERT, BiomePoolTier.RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ],
[ Biome.WASTELAND, BiomePoolTier.COMMON ],
[ Biome.WASTELAND, BiomePoolTier.BOSS ],
[ Biome.WASTELAND, BiomePoolTier.BOSS ]
]
],
[ Species.CACNEA, Type.GRASS, -1, [
@ -3694,14 +3694,14 @@ export function initBiomes() {
[ Species.BALTOY, Type.GROUND, Type.PSYCHIC, [
[ Biome.RUINS, BiomePoolTier.COMMON ],
[ Biome.SPACE, BiomePoolTier.UNCOMMON ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ]
]
],
[ Species.CLAYDOL, Type.GROUND, Type.PSYCHIC, [
[ Biome.RUINS, BiomePoolTier.COMMON ],
[ Biome.RUINS, BiomePoolTier.BOSS ],
[ Biome.SPACE, BiomePoolTier.UNCOMMON ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ]
]
],
[ Species.LILEEP, Type.ROCK, Type.GRASS, [
@ -4199,14 +4199,14 @@ export function initBiomes() {
[ Species.SKORUPI, Type.POISON, Type.BUG, [
[ Biome.SWAMP, BiomePoolTier.UNCOMMON ],
[ Biome.DESERT, BiomePoolTier.COMMON ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ]
]
],
[ Species.DRAPION, Type.POISON, Type.DARK, [
[ Biome.SWAMP, BiomePoolTier.UNCOMMON ],
[ Biome.DESERT, BiomePoolTier.COMMON ],
[ Biome.DESERT, BiomePoolTier.BOSS ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ],
[ Biome.TEMPLE, BiomePoolTier.UNCOMMON ]
]
],
[ Species.CROAGUNK, Type.POISON, Type.FIGHTING, [
@ -4793,7 +4793,7 @@ export function initBiomes() {
]
],
[ Species.CINCCINO, Type.NORMAL, -1, [
[ Biome.MEADOW, BiomePoolTier.BOSS, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ],
[ Biome.MEADOW, BiomePoolTier.BOSS, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ]
]
],
[ Species.GOTHITA, Type.PSYCHIC, -1, [
@ -4898,7 +4898,7 @@ export function initBiomes() {
]
],
[ Species.JOLTIK, Type.BUG, Type.ELECTRIC, [
[ Biome.JUNGLE, BiomePoolTier.UNCOMMON ],
[ Biome.JUNGLE, BiomePoolTier.UNCOMMON ]
]
],
[ Species.GALVANTULA, Type.BUG, Type.ELECTRIC, [

View File

@ -2290,6 +2290,28 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
"dialogue:raihan_elite.defeat.2"
]
},
[TrainerType.ALDER]: {
encounter: [
"dialogue:alder.encounter.1"
],
victory: [
"dialogue:alder.victory.1"
],
defeat: [
"dialogue:alder.defeat.1"
]
},
[TrainerType.KIERAN]: {
encounter: [
"dialogue:kieran.encounter.1"
],
victory: [
"dialogue:kieran.victory.1"
],
defeat: [
"dialogue:kieran.defeat.1"
]
},
[TrainerType.RIVAL]: [
{
encounter: [

View File

@ -3634,7 +3634,7 @@ export const starterPassiveAbilities = {
[Species.HAWLUCHA]: Abilities.MOXIE,
[Species.DEDENNE]: Abilities.PIXILATE,
[Species.CARBINK]: Abilities.SOLID_ROCK,
[Species.GOOMY]: Abilities.DRIZZLE,
[Species.GOOMY]: Abilities.REGENERATOR,
[Species.KLEFKI]: Abilities.LEVITATE,
[Species.PHANTUMP]: Abilities.RIPEN,
[Species.PUMPKABOO]: Abilities.WELL_BAKED_BODY,

View File

@ -63324,12 +63324,18 @@ export const tmSpecies: TmSpecies = {
Species.HYDRAPPLE,
],
[Moves.TRAILBLAZE]: [
Species.BULBASAUR,
Species.IVYSAUR,
Species.VENUSAUR,
Species.EKANS,
Species.ARBOK,
Species.PIKACHU,
Species.RAICHU,
Species.JIGGLYPUFF,
Species.WIGGLYTUFF,
Species.ODDISH,
Species.GLOOM,
Species.VILEPLUME,
Species.MEOWTH,
Species.PERSIAN,
Species.PSYDUCK,
@ -63337,8 +63343,10 @@ export const tmSpecies: TmSpecies = {
Species.BELLSPROUT,
Species.WEEPINBELL,
Species.VICTREEBEL,
Species.DODRIO,
Species.DROWZEE,
Species.HYPNO,
Species.HITMONCHAN,
Species.CHANSEY,
Species.SCYTHER,
Species.TAUROS,
@ -63349,6 +63357,12 @@ export const tmSpecies: TmSpecies = {
Species.SNORLAX,
Species.MEWTWO,
Species.MEW,
Species.CHIKORITA,
Species.BAYLEEF,
Species.MEGANIUM,
Species.TOTODILE,
Species.CROCONAW,
Species.FERALIGATR,
Species.SENTRET,
Species.FURRET,
Species.SPINARAK,
@ -63358,6 +63372,7 @@ export const tmSpecies: TmSpecies = {
Species.MAREEP,
Species.FLAAFFY,
Species.AMPHAROS,
Species.BELLOSSOM,
Species.MARILL,
Species.AZUMARILL,
Species.SUDOWOODO,
@ -63372,6 +63387,8 @@ export const tmSpecies: TmSpecies = {
Species.ESPEON,
Species.UMBREON,
Species.GIRAFARIG,
Species.SNUBBULL,
Species.GRANBULL,
Species.SCIZOR,
Species.HERACROSS,
Species.SNEASEL,
@ -63385,7 +63402,14 @@ export const tmSpecies: TmSpecies = {
Species.PHANPY,
Species.DONPHAN,
Species.STANTLER,
Species.ELEKID,
Species.BLISSEY,
Species.RAIKOU,
Species.ENTEI,
Species.SUICUNE,
Species.TREECKO,
Species.GROVYLE,
Species.SCEPTILE,
Species.POOCHYENA,
Species.MIGHTYENA,
Species.LOTAD,
@ -63398,6 +63422,8 @@ export const tmSpecies: TmSpecies = {
Species.SLAKING,
Species.MEDITITE,
Species.MEDICHAM,
Species.PLUSLE,
Species.MINUN,
Species.VOLBEAT,
Species.ILLUMISE,
Species.NUMEL,
@ -63422,6 +63448,10 @@ export const tmSpecies: TmSpecies = {
Species.SHINX,
Species.LUXIO,
Species.LUXRAY,
Species.CRANIDOS,
Species.RAMPARDOS,
Species.SHIELDON,
Species.BASTIODON,
Species.PACHIRISU,
Species.AMBIPOM,
Species.STUNKY,
@ -63433,9 +63463,21 @@ export const tmSpecies: TmSpecies = {
Species.SNOVER,
Species.ABOMASNOW,
Species.WEAVILE,
Species.ELECTIVIRE,
Species.LEAFEON,
Species.GLACEON,
Species.MAMOSWINE,
Species.FROSLASS,
Species.SHAYMIN,
Species.ARCEUS,
Species.SNIVY,
Species.SERVINE,
Species.SERPERIOR,
Species.TEPIG,
Species.PIGNITE,
Species.EMBOAR,
Species.BLITZLE,
Species.ZEBSTRIKA,
Species.SEWADDLE,
Species.SWADLOON,
Species.LEAVANNY,
@ -63444,6 +63486,8 @@ export const tmSpecies: TmSpecies = {
Species.SCRAGGY,
Species.SCRAFTY,
Species.DUCKLETT,
Species.MINCCINO,
Species.CINCCINO,
Species.SWANNA,
Species.DEERLING,
Species.SAWSBUCK,
@ -63475,6 +63519,8 @@ export const tmSpecies: TmSpecies = {
Species.FLORGES,
Species.SKIDDO,
Species.GOGOAT,
Species.MEOWSTIC,
Species.MALAMAR,
Species.SYLVEON,
Species.HAWLUCHA,
Species.DEDENNE,
@ -63490,6 +63536,8 @@ export const tmSpecies: TmSpecies = {
Species.RIBOMBEE,
Species.ROCKRUFF,
Species.LYCANROC,
Species.DEWPIDER,
Species.ARAQUANID,
Species.FOMANTIS,
Species.LURANTIS,
Species.SALANDIT,
@ -63497,6 +63545,7 @@ export const tmSpecies: TmSpecies = {
Species.BOUNSWEET,
Species.STEENEE,
Species.TSAREENA,
Species.COMFEY,
Species.ORANGURU,
Species.PASSIMIAN,
Species.KOMALA,
@ -63508,6 +63557,7 @@ export const tmSpecies: TmSpecies = {
Species.RABOOT,
Species.CINDERACE,
Species.SKWOVET,
Species.GREEDENT,
Species.FLAPPLE,
Species.APPLETUN,
Species.TOXTRICITY,

View File

@ -2349,6 +2349,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "Du bist in meinen Sturm geraten! Viel Glück beim nächsten Mal!"
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {

View File

@ -27,6 +27,7 @@ import { menuUiHandler } from "./menu-ui-handler";
import { modifierType } from "./modifier-type";
import { move } from "./move";
import { nature } from "./nature";
import { partyUiHandler } from "./party-ui-handler";
import { pokeball } from "./pokeball";
import { pokemon } from "./pokemon";
import { pokemonInfo } from "./pokemon-info";
@ -38,7 +39,6 @@ import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
export const enConfig = {
ability: ability,
@ -69,6 +69,7 @@ export const enConfig = {
modifierType: modifierType,
move: move,
nature: nature,
partyUiHandler: partyUiHandler,
pokeball: pokeball,
pokemon: pokemon,
pokemonInfo: pokemonInfo,
@ -82,5 +83,4 @@ export const enConfig = {
tutorial: tutorial,
voucher: voucher,
weather: weather,
partyUiHandler: partyUiHandler
};

View File

@ -2287,6 +2287,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "You got caught in my storm! Better luck next time!"
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: `@c{smile}Hey, I was looking for you! I knew you were eager to get going but I expected at least a goodbye…

View File

@ -1,6 +1,7 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const partyUiHandler: SimpleTranslationEntries = {
"ALL": "All",
"SEND_OUT": "Send Out",
"SUMMARY": "Summary",
"CANCEL": "Cancel",

View File

@ -2107,6 +2107,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "You got caught in my storm! Better luck next time!"
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: `@c{smile}Hey, I was looking for you! I knew you were eager to get going but I expected at least a goodbye…

View File

@ -4,5 +4,7 @@ export const abilityTriggers: SimpleTranslationEntries = {
"blockRecoilDamage" : "{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !",
"badDreams": "{{pokemonName}} a le sommeil agité !",
"windPowerCharged": "{{pokemonName}} a été touché par la capacité {{moveName}} et se charge en électricité !",
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!"
"perishBody": "{{abilityName}} de {{pokemonName}}\nmettra les deux Pokémon K.O. dans trois tours !",
"poisonHeal": "{{abilityName}} de {{pokemonName}}\nrestaure un peu ses PV !",
"iceFaceAvoidedDamage": "{{pokemonName}} évite les dégâts\navec {{abilityName}} !"
} as const;

View File

@ -162,7 +162,7 @@ export const PGMachv: AchievementTranslationEntries = {
description: "Capturer un Pokémon possédant un talent caché",
},
"PERFECT_IVS": {
name: "Certificat dAuthenticité",
name: "Certificat dauthenticité",
description: "Avoir des IV parfaits sur un Pokémon",
},
"CLASSIC_VICTORY": {
@ -171,98 +171,98 @@ export const PGMachv: AchievementTranslationEntries = {
},
"MONO_GEN_ONE": {
name: "The Original Rival",
description: "Complete the generation one only challenge.",
name: "Le rival originel",
description: "Terminer un challenge avec uniquement des Pokémon de 1re génération.",
},
"MONO_GEN_TWO": {
name: "Generation 1.5",
description: "Complete the generation two only challenge.",
name: "Entre tradition et modernité",
description: "Terminer un challenge avec uniquement des Pokémon de 2e génération.",
},
"MONO_GEN_THREE": {
name: "Too much water?",
description: "Complete the generation three only challenge.",
name: "Too much water ?",
description: "Terminer un challenge avec uniquement des Pokémon de 3e génération.",
},
"MONO_GEN_FOUR": {
name: "Is she really the hardest?",
description: "Complete the generation four only challenge.",
name: "Réellement la plus difficile ?",
description: "Terminer un challenge avec uniquement des Pokémon de 4e génération.",
},
"MONO_GEN_FIVE": {
name: "All Original",
description: "Complete the generation five only challenge.",
name: "Recast complet",
description: "Terminer un challenge avec uniquement des Pokémon de 5e génération.",
},
"MONO_GEN_SIX": {
name: "Almost Royalty",
description: "Complete the generation six only challenge.",
name: "Aristocrate",
description: "Terminer un challenge avec uniquement des Pokémon de 6e génération.",
},
"MONO_GEN_SEVEN": {
name: "Only Technically",
description: "Complete the generation seven only challenge.",
name: "Seulement techniquement",
description: "Terminer un challenge avec uniquement des Pokémon de 7e génération.",
},
"MONO_GEN_EIGHT": {
name: "A Champion Time!",
description: "Complete the generation eight only challenge.",
name: "Lheure de gloire",
description: "Terminer un challenge avec uniquement des Pokémon de 8e génération.",
},
"MONO_GEN_NINE": {
name: "She was going easy on you",
description: "Complete the generation nine only challenge.",
name: "Ça va, cétait EZ",
description: "Terminer un challenge avec uniquement des Pokémon de 9e génération.",
},
"MonoType": {
description: "Complete the {{type}} monotype challenge.",
description: "Terminer un challenge en monotype {{type}}.",
},
"MONO_NORMAL": {
name: "Mono NORMAL",
name: "Extraordinairement banal",
},
"MONO_FIGHTING": {
name: "I Know Kung Fu",
name: "Je connais le kung-fu",
},
"MONO_FLYING": {
name: "Mono FLYING",
name: "Angry Birds",
},
"MONO_POISON": {
name: "Kanto's Favourite",
name: "Touche moi je tempoisonne !",
},
"MONO_GROUND": {
name: "Mono GROUND",
name: "Prévisions : Séisme",
},
"MONO_ROCK": {
name: "Brock Hard",
name: "Comme un roc",
},
"MONO_BUG": {
name: "Sting Like A Beedrill",
name: "Une chenille !",
},
"MONO_GHOST": {
name: "Who you gonna call?",
name: "SOS Fantômes",
},
"MONO_STEEL": {
name: "Mono STEEL",
name: "De type Acier !",
},
"MONO_FIRE": {
name: "Mono FIRE",
name: "Allumer le feu",
},
"MONO_WATER": {
name: "When It Rains, It Pours",
name: "Vacances en Bretagne",
},
"MONO_GRASS": {
name: "Mono GRASS",
name: "Ne pas toucher !",
},
"MONO_ELECTRIC": {
name: "Mono ELECTRIC",
name: "À la masse",
},
"MONO_PSYCHIC": {
name: "Mono PSYCHIC",
name: "Grocervo",
},
"MONO_ICE": {
name: "Mono ICE",
name: "Froid comme la glace",
},
"MONO_DRAGON": {
name: "Mono DRAGON",
name: "Légendes du club, ou presque",
},
"MONO_DARK": {
name: "It's just a phase",
name: "Ça va lui passer",
},
"MONO_FAIRY": {
name: "Mono FAIRY",
name: "Hey ! Listen !",
},
} as const;

View File

@ -54,12 +54,12 @@ export const battle: SimpleTranslationEntries = {
"escapeVerbFlee": "la fuite",
"notDisabled": "La capacité {{moveName}}\nde {{pokemonName}} nest plus sous entrave !",
"skipItemQuestion": "Êtes-vous sûr·e de ne pas vouloir prendre dobjet ?",
"eggHatching": "Oh ?",
"eggHatching": "Hein ?",
"ivScannerUseQuestion": "Utiliser le Scanner dIV sur {{pokemonName}} ?",
"wildPokemonWithAffix": "{{pokemonName}} sauvage",
"foePokemonWithAffix": "{{pokemonName}} ennemi",
"useMove": "{{pokemonNameWithAffix}} utilise\n{{moveName}} !",
"drainMessage": "{{pokemonName}} had its\nenergy drained!",
"regainHealth": "{{pokemonName}} a récupéré\ndes PV!",
"fainted": "{{pokemonNameWithAffix}} est tombé KO!"
"drainMessage": "Lénergie de {{pokemonName}}\nest drainée !",
"regainHealth": "{{pokemonName}} récupère\ndes PV !",
"fainted": "{{pokemonNameWithAffix}}\nest K.O. !"
} as const;

View File

@ -2,8 +2,8 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const challenges: SimpleTranslationEntries = {
"title": "Paramètres du Challenge",
"points": "Bad Ideas",
"confirm_start": "Continuer avec ces paramètres ?",
"start": "Démarrer",
"illegalEvolution": "{{pokemon}} sest transformé en Pokémon\ninéligible pour ce challenge !",
"singleGeneration.name": "Mono-génération",
"singleGeneration.value.0": "Désactivé",
"singleGeneration.desc.0": "Vous ne pouvez choisir que des Pokémon de la génération sélectionnée.",

View File

@ -2107,6 +2107,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "You got caught in my storm! Better luck next time!"
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: `@c{smile}Ah, je te cherchais ! Je savais que tétais pressée de partir, mais je mattendais quand même à un au revoir…

View File

@ -4,6 +4,6 @@ export const fightUiHandler: SimpleTranslationEntries = {
"pp": "PP",
"power": "Puissance",
"accuracy": "Précision",
"abilityFlyInText": " {{pokemonName}}'s {{passive}}{{abilityName}}",
"passive": "Passive ", // The space at the end is important
"abilityFlyInText": " {{passive}}{{abilityName}} de {{pokemonName}}",
"passive": "Passif ", // The space at the end is important
} as const;

View File

@ -1,10 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const partyUiHandler: SimpleTranslationEntries = {
"SEND_OUT": "Send Out",
"SUMMARY": "Summary",
"CANCEL": "Cancel",
"RELEASE": "Release",
"APPLY": "Apply",
"TEACH": "Teach"
"ALL": "Tout",
"SEND_OUT": "Envoyer",
"SUMMARY": "Résumé",
"CANCEL": "Annuler",
"RELEASE": "Relâcher",
"APPLY": "Appliquer",
"TEACH": "Apprendre"
} as const;

View File

@ -7,5 +7,6 @@ export const pokemonInfoContainer: SimpleTranslationEntries = {
"nature": "Nature :",
"epic": "Épique",
"rare": "Rare",
"common": "Commun"
"common": "Commun",
"form": "Forme :"
} as const;

View File

@ -28,7 +28,7 @@ export const splashMessages: SimpleTranslationEntries = {
"mostlyConsistentSeeds": "Des seeds à peu près stables !",
"achievementPointsDontDoAnything": "Les Points de Succès servent à rien !",
"youDoNotStartAtLevel": "Ne commence pas au Niveau 2000 !",
"dontTalkAboutTheManaphyEggIncident": "Ne parle pas de l'incident de lŒuf de Manaphy !",
"dontTalkAboutTheManaphyEggIncident": "Ne parle pas de lincident de lŒuf de Manaphy !",
"alsoTryPokengine": "Essaye aussi Pokéngine !",
"alsoTryEmeraldRogue": "Essaye aussi Emerald Rogue!",
"alsoTryRadicalRed": "Essaye aussi Radical Red !",

View File

@ -13,6 +13,12 @@ export const titles: SimpleTranslationEntries = {
"rival": "Rival·e", //Written in gender-inclusive language in wait of a potential split of the entry
"professor": "Professeur·e", //Written in gender-inclusive language in wait of a potential split of the entry
"frontier_brain": "Meneur·euse de Zone", //Written in gender-inclusive language in wait of a potential split of the entry
"rocket_boss": "Leader de la Team Rocket",
"magma_boss": "Leader de la Team Magma",
"aqua_boss": "Leader de la Team Aqua",
"galactic_boss": "Leader de la Team Galaxie",
"plasma_boss": "Leader de la Team Plasma",
"flare_boss": "Leader de la Team Flare",
// 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;
@ -118,7 +124,19 @@ export const trainerClasses: SimpleTranslationEntries = {
"worker": "Ouvrier",
"worker_female": "Ouvrière",
"workers": "Ouvriers",
"youngster": "Gamin"
"youngster": "Gamin",
"rocket_grunt": "Sbire de la Team Rocket",
"rocket_grunt_female": "Sbire de la Team Rocket",
"magma_grunt": "Sbire de la Team Magma",
"magma_grunt_female": "Sbire de la Team Magma",
"aqua_grunt": "Sbire de la Team Aqua",
"aqua_grunt_female": "Sbire de la Team Aqua",
"galactic_grunt": "Sbire de la Team Galaxie",
"galactic_grunt_female": "Sbire Team Galaxie",
"plasma_grunt": "Sbire de la Team Plasma",
"plasma_grunt_female": "Sbire de la Team Plasma",
"flare_grunt": "Sbire de la Team Flare",
"flare_grunt_female": "Sbire de la Team Flare",
} as const;
// Names of special trainers like gym leaders, elite four, and the champion

View File

@ -2107,6 +2107,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "You got caught in my storm! Better luck next time!"
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: `@c{smile}Hey, I was looking for you! I knew you were eager to get going but I expected at least a goodbye…

View File

@ -2287,6 +2287,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "넌 내 폭풍을 잡아냈잖아! 다음엔 더 잘해봐!"
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: `@c{smile}오, 찾았다! 떠나려는 건 알고 있었지만\n인사정도는 해줄 줄 알았는데…

View File

@ -2096,6 +2096,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "Você foi pego na minha tempestade! Melhor sorte na próxima vez!"
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: `@c{smile}Eai, estava procurando você! Sabia que você estava ansioso para começar, mas esperava pelo menos um tchau…

View File

@ -2007,6 +2007,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "你被我的风暴卷入了!祝你下次好运!",
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: "@c{smile}嘿,我在找你呢!我知道你急着上路,\n但至少说个再见吧…$@c{smile_eclosed}所以你终于要开始追逐梦想了?\n我几乎不敢相信。$@c{serious_smile_fists}来都来了,来一场对战怎么样?\n毕竟我想看看你是不是准备周全了。$@c{serious_mopen_fists}不要手下留情,我想让你全力以赴!",

View File

@ -2007,6 +2007,32 @@ export const PGMdialogue: DialogueTranslationEntries = {
2: "你被我的風暴捲入了!祝你下次好運!",
}
},
"alder": {
"encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!"
},
"victory": {
1: "Well done! You certainly are an unmatched talent."
},
"defeat": {
1: `A fresh wind blows through my heart...
$What an extraordinary effort!`
}
},
"kieran": {
"encounter": {
1: `Through hard work, I become stronger and stronger!
$I don't lose.`
},
"victory": {
1: `I don't believe it...
$What a fun and heart-pounding battle!`
},
"defeat": {
1: `Wowzers, what a battle!
$Time for you to train even harder.`
}
},
"rival": {
"encounter": {
1: "@c{smile}嘿,我在找你呢!我知道你急著上路,\n但至少說個再見吧…$@c{smile_eclosed}所以你終於要開始追逐夢想了?\n我幾乎不敢相信。$@c{serious_smile_fists}來都來了,來一場對戰怎麼樣?\n畢竟我想看看你是不是準備周全了。$@c{serious_mopen_fists}不要手下留情,我想讓你全力以赴!",

View File

@ -26,7 +26,7 @@ import { Gender } from "./data/gender";
import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather";
import { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, PokemonTypeChangeAbAttr, applyPreAttackAbAttrs, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr } from "./data/ability";
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, PokemonTypeChangeAbAttr, applyPreAttackAbAttrs, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr, WonderSkinAbAttr, applyPreDefendAbAttrs } from "./data/ability";
import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
@ -3012,6 +3012,7 @@ export class MoveEffectPhase extends PokemonPhase {
const moveAccuracy = new Utils.NumberHolder(this.move.getMove().accuracy);
applyMoveAttrs(VariableAccuracyAttr, user, target, this.move.getMove(), moveAccuracy);
applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this.move.getMove(), { value: false }, moveAccuracy);
if (moveAccuracy.value === -1) {
return true;

View File

@ -0,0 +1,138 @@
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 { TurnEndPhase, } from "#app/phases";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import Move, { allMoves } from "#app/data/move.js";
import { MoveAbilityBypassAbAttr, WonderSkinAbAttr } from "#app/data/ability.js";
import { NumberHolder } from "#app/utils.js";
import Pokemon from "#app/field/pokemon.js";
describe("Abilities - Wonder Skin", () => {
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_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.WONDER_SKIN);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.CHARM]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
});
it("lowers accuracy of status moves to 50%", async () => {
await game.startBattle([Species.MAGIKARP]);
game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM));
const appliedAccuracy = getAppliedMoveAccuracy(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[Moves.CHARM]);
await game.phaseInterceptor.to(TurnEndPhase);
expect(appliedAccuracy).not.toBe(undefined);
expect(appliedAccuracy).not.toBe(100);
expect(appliedAccuracy).toBe(50);
});
it("does not lower accuracy of non-status moves", async () => {
await game.startBattle([Species.MAGIKARP]);
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
const appliedAccuracy = getAppliedMoveAccuracy(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[Moves.TACKLE]);
await game.phaseInterceptor.to(TurnEndPhase);
expect(appliedAccuracy).not.toBe(undefined);
expect(appliedAccuracy).toBe(100);
expect(appliedAccuracy).not.toBe(50);
});
it("does not affect pokemon with Mold Breaker", async () => {
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.MOLD_BREAKER);
await game.startBattle([Species.MAGIKARP]);
game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM));
const appliedAccuracy = getAppliedMoveAccuracy(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[Moves.CHARM]);
await game.phaseInterceptor.to(TurnEndPhase);
expect(appliedAccuracy).not.toBe(undefined);
expect(appliedAccuracy).toBe(100);
expect(appliedAccuracy).not.toBe(50);
});
it("does not affect pokemon with Teravolt", async () => {
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.TERAVOLT);
await game.startBattle([Species.MAGIKARP]);
game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM));
const appliedAccuracy = getAppliedMoveAccuracy(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[Moves.CHARM]);
await game.phaseInterceptor.to(TurnEndPhase);
expect(appliedAccuracy).not.toBe(undefined);
expect(appliedAccuracy).toBe(100);
expect(appliedAccuracy).not.toBe(50);
});
it("does not affect pokemon with Turboblaze", async () => {
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.TURBOBLAZE);
await game.startBattle([Species.MAGIKARP]);
game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM));
const appliedAccuracy = getAppliedMoveAccuracy(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[Moves.CHARM]);
await game.phaseInterceptor.to(TurnEndPhase);
expect(appliedAccuracy).not.toBe(undefined);
expect(appliedAccuracy).toBe(100);
expect(appliedAccuracy).not.toBe(50);
});
});
/**
* Calculates the adjusted applied accuracy of a move.
*
* @param defender - The defending Pokémon.
* @param attacker - The attacking Pokémon.
* @param move - The move being used by the attacker.
* @returns The adjusted accuracy of the move.
*/
const getAppliedMoveAccuracy = (defender: Pokemon, attacker: Pokemon, move: Move) => {
const accuracyHolder = new NumberHolder(move.accuracy);
/**
* Simulate ignoring ability
* @see MoveAbilityBypassAbAttr
*/
if (attacker.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
return accuracyHolder.value;
}
const wonderSkinInstance = new WonderSkinAbAttr();
wonderSkinInstance.applyPreDefend(defender, false, attacker, move, { value: false }, [ accuracyHolder ]);
return accuracyHolder.value;
};

View File

@ -57,7 +57,8 @@ export enum PartyOption {
MOVE_1 = 3000,
MOVE_2,
MOVE_3,
MOVE_4
MOVE_4,
ALL = 4000
}
export type PartySelectCallback = (cursor: integer, option: PartyOption) => void;
@ -96,6 +97,8 @@ export default class PartyUiHandler extends MessageUiHandler {
private transferQuantities: integer[];
/** Stack size of every item that the selected pokemon is holding */
private transferQuantitiesMax: integer[];
/** Whether to transfer all items */
private transferAll: boolean;
private lastCursor: integer = 0;
private selectCallback: PartySelectCallback | PartyModifierTransferSelectCallback;
@ -294,6 +297,8 @@ export default class PartyUiHandler extends MessageUiHandler {
} else if ((option !== PartyOption.SUMMARY && option !== PartyOption.UNPAUSE_EVOLUTION && option !== PartyOption.UNSPLICE && option !== PartyOption.RELEASE && option !== PartyOption.CANCEL)
|| (option === PartyOption.RELEASE && this.partyUiMode === PartyUiMode.RELEASE)) {
let filterResult: string;
const getTransferrableItemsFromPokemon = (pokemon: PlayerPokemon) =>
this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === pokemon.id) as PokemonHeldItemModifier[];
if (option !== PartyOption.TRANSFER && option !== PartyOption.SPLICE) {
filterResult = (this.selectFilter as PokemonSelectFilter)(pokemon);
if (filterResult === null && (option === PartyOption.SEND_OUT || option === PartyOption.PASS_BATON)) {
@ -303,10 +308,7 @@ export default class PartyUiHandler extends MessageUiHandler {
filterResult = this.moveSelectFilter(pokemon.moveset[this.optionsCursor]);
}
} else {
const transferPokemon = this.scene.getParty()[this.transferCursor];
const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === transferPokemon.id) as PokemonHeldItemModifier[];
filterResult = (this.selectFilter as PokemonModifierTransferSelectFilter)(pokemon, itemModifiers[this.transferOptionCursor]);
filterResult = (this.selectFilter as PokemonModifierTransferSelectFilter)(pokemon, getTransferrableItemsFromPokemon(this.scene.getParty()[this.transferCursor])[this.transferOptionCursor]);
}
if (filterResult === null) {
if (this.partyUiMode !== PartyUiMode.SPLICE) {
@ -315,8 +317,12 @@ export default class PartyUiHandler extends MessageUiHandler {
if (this.selectCallback && this.partyUiMode !== PartyUiMode.CHECK) {
if (option === PartyOption.TRANSFER) {
if (this.transferCursor !== this.cursor) {
if (this.transferAll) {
getTransferrableItemsFromPokemon(this.scene.getParty()[this.transferCursor]).forEach((_, i) => (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, i, this.transferQuantitiesMax[i], this.cursor));
} else {
(this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, this.transferOptionCursor, this.transferQuantities[this.transferOptionCursor], this.cursor);
}
}
this.clearTransfer();
} else if (this.partyUiMode === PartyUiMode.SPLICE) {
if (option === PartyOption.SPLICE) {
@ -430,7 +436,9 @@ export default class PartyUiHandler extends MessageUiHandler {
case Button.UP:
/** If currently selecting items to transfer, reset quantity selection */
if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER) {
if (option !== PartyOption.ALL) {
this.transferQuantities[option] = this.transferQuantitiesMax[option];
}
this.updateOptions();
}
success = this.setCursor(this.optionsCursor ? this.optionsCursor - 1 : this.options.length - 1); /** Move cursor */
@ -438,7 +446,9 @@ export default class PartyUiHandler extends MessageUiHandler {
case Button.DOWN:
/** If currently selecting items to transfer, reset quantity selection */
if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER) {
if (option !== PartyOption.ALL) {
this.transferQuantities[option] = this.transferQuantitiesMax[option];
}
this.updateOptions();
}
success = this.setCursor(this.optionsCursor < this.options.length - 1 ? this.optionsCursor + 1 : 0); /** Move cursor */
@ -770,6 +780,9 @@ export default class PartyUiHandler extends MessageUiHandler {
for (let im = 0; im < itemModifiers.length; im++) {
this.options.push(im);
}
if (itemModifiers.length > 1) {
this.options.push(PartyOption.ALL);
}
}
this.optionsScrollTotal = this.options.length;
@ -842,6 +855,9 @@ 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) {
optionName = i18next.t("partyUiHandler:ALL");
} else {
const itemModifier = itemModifiers[option];
optionName = itemModifier.type.name;
@ -850,6 +866,7 @@ export default class PartyUiHandler extends MessageUiHandler {
optionName += ` (${this.transferQuantities[option]})`;
}
}
}
const yCoord = -6 - 16 * o;
const optionText = addTextObject(this.scene, 0, yCoord - 16, optionName, TextStyle.WINDOW);
@ -876,12 +893,14 @@ export default class PartyUiHandler extends MessageUiHandler {
this.transferMode = true;
this.transferCursor = this.cursor;
this.transferOptionCursor = this.getOptionsCursorWithScroll();
this.transferAll = this.options[this.optionsCursor] === PartyOption.ALL;
this.partySlots[this.transferCursor].setTransfer(true);
}
clearTransfer(): void {
this.transferMode = false;
this.transferAll = false;
this.partySlots[this.transferCursor].setTransfer(false);
}