Merge branch 'pagefaultgames:main' into Flyout-Add

This commit is contained in:
Benjamin Odom 2024-05-21 06:23:06 -05:00 committed by GitHub
commit 7fba9ebf46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 383 additions and 75 deletions

View File

@ -74,7 +74,7 @@ Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to s
### 🎨 Trainer Portraits ### 🎨 Trainer Portraits
- pkmn_realidea (Paid Commissions) - pkmn_realidea (Paid Commissions)
### 🎨 Pokemon Sprites ### 🎨 Pokemon Sprites and Animation
- GAMEFREAK (Pokémon Black/White 2) - GAMEFREAK (Pokémon Black/White 2)
- Smogon Sprite Project (Various Artists) - Smogon Sprite Project (Various Artists)
- Skyflyer - Skyflyer
@ -100,6 +100,7 @@ Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to s
- bizcoeindoloro - bizcoeindoloro
- mangalos810 - mangalos810
- Involuntary-Twitch - Involuntary-Twitch
- selstar
### 🎨 Move Animations ### 🎨 Move Animations
- Pokémon Reborn - Pokémon Reborn

View File

@ -2282,6 +2282,34 @@ export class PostTurnFormChangeAbAttr extends PostTurnAbAttr {
} }
} }
/**
* Attribute used for abilities (Bad Dreams) that damages the opponents for being asleep
*/
export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
/**
* Deals damage to all sleeping opponents equal to 1/8 of their max hp (min 1)
* @param {Pokemon} pokemon Pokemon that has this ability
* @param {boolean} passive N/A
* @param {any[]} args N/A
* @returns {boolean} true if any opponents are sleeping
*/
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
let hadEffect: boolean = false;
for(let opp of pokemon.getOpponents()) {
if(opp.status !== undefined && opp.status.effect === StatusEffect.SLEEP) {
opp.damageAndUpdate(Math.floor(Math.max(1, opp.getMaxHp() / 8)), HitResult.OTHER);
pokemon.scene.queueMessage(i18next.t('abilityTriggers:badDreams', {pokemonName: `${getPokemonPrefix(opp)}${opp.name}`}));
hadEffect = true;
}
}
return hadEffect;
}
}
/** /**
* Grabs the last failed Pokeball used * Grabs the last failed Pokeball used
* @extends PostTurnAbAttr * @extends PostTurnAbAttr
@ -3327,7 +3355,7 @@ export function initAbilities() {
.ignorable() .ignorable()
.partial(), .partial(),
new Ability(Abilities.BAD_DREAMS, 4) new Ability(Abilities.BAD_DREAMS, 4)
.unimplemented(), .attr(PostTurnHurtIfSleepingAbAttr),
new Ability(Abilities.PICKPOCKET, 5) new Ability(Abilities.PICKPOCKET, 5)
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)), .attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)),
new Ability(Abilities.SHEER_FORCE, 5) new Ability(Abilities.SHEER_FORCE, 5)

View File

@ -1608,8 +1608,7 @@ 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) 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]: [ [Species.GIMMIGHOUL]: [
new SpeciesEvolution(Species.GHOLDENGO, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.VERY_LONG) new SpeciesEvolution(Species.GHOLDENGO, 1, null, new SpeciesFriendshipEvolutionCondition(70), SpeciesWildEvolutionDelay.VERY_LONG) ]
]
}; };
interface PokemonPrevolutions { interface PokemonPrevolutions {

View File

@ -2634,7 +2634,7 @@ export const speciesStarters = {
[Species.MOLTRES]: 6, [Species.MOLTRES]: 6,
[Species.DRATINI]: 4, [Species.DRATINI]: 4,
[Species.MEWTWO]: 8, [Species.MEWTWO]: 8,
[Species.MEW]: 7, [Species.MEW]: 6,
[Species.CHIKORITA]: 3, [Species.CHIKORITA]: 3,
[Species.CYNDAQUIL]: 3, [Species.CYNDAQUIL]: 3,
@ -2693,7 +2693,7 @@ export const speciesStarters = {
[Species.LARVITAR]: 4, [Species.LARVITAR]: 4,
[Species.LUGIA]: 8, [Species.LUGIA]: 8,
[Species.HO_OH]: 8, [Species.HO_OH]: 8,
[Species.CELEBI]: 7, [Species.CELEBI]: 6,
[Species.TREECKO]: 3, [Species.TREECKO]: 3,
[Species.TORCHIC]: 3, [Species.TORCHIC]: 3,
@ -2765,9 +2765,9 @@ export const speciesStarters = {
[Species.REGISTEEL]: 6, [Species.REGISTEEL]: 6,
[Species.LATIAS]: 7, [Species.LATIAS]: 7,
[Species.LATIOS]: 7, [Species.LATIOS]: 7,
[Species.KYOGRE]: 8, [Species.KYOGRE]: 9,
[Species.GROUDON]: 8, [Species.GROUDON]: 9,
[Species.RAYQUAZA]: 8, [Species.RAYQUAZA]: 9,
[Species.JIRACHI]: 7, [Species.JIRACHI]: 7,
[Species.DEOXYS]: 7, [Species.DEOXYS]: 7,
@ -2809,19 +2809,19 @@ export const speciesStarters = {
[Species.MANTYKE]: 3, [Species.MANTYKE]: 3,
[Species.SNOVER]: 3, [Species.SNOVER]: 3,
[Species.ROTOM]: 5, [Species.ROTOM]: 5,
[Species.UXIE]: 7, [Species.UXIE]: 6,
[Species.MESPRIT]: 7, [Species.MESPRIT]: 6,
[Species.AZELF]: 7, [Species.AZELF]: 6,
[Species.DIALGA]: 8, [Species.DIALGA]: 8,
[Species.PALKIA]: 8, [Species.PALKIA]: 8,
[Species.HEATRAN]: 7, [Species.HEATRAN]: 6,
[Species.REGIGIGAS]: 8, [Species.REGIGIGAS]: 7,
[Species.GIRATINA]: 8, [Species.GIRATINA]: 8,
[Species.CRESSELIA]: 7, [Species.CRESSELIA]: 6,
[Species.PHIONE]: 5, [Species.PHIONE]: 4,
[Species.MANAPHY]: 7, [Species.MANAPHY]: 7,
[Species.DARKRAI]: 7, [Species.DARKRAI]: 6,
[Species.SHAYMIN]: 7, [Species.SHAYMIN]: 6,
[Species.ARCEUS]: 9, [Species.ARCEUS]: 9,
[Species.VICTINI]: 7, [Species.VICTINI]: 7,
@ -2903,9 +2903,9 @@ export const speciesStarters = {
[Species.ZEKROM]: 8, [Species.ZEKROM]: 8,
[Species.LANDORUS]: 7, [Species.LANDORUS]: 7,
[Species.KYUREM]: 8, [Species.KYUREM]: 8,
[Species.KELDEO]: 7, [Species.KELDEO]: 6,
[Species.MELOETTA]: 7, [Species.MELOETTA]: 6,
[Species.GENESECT]: 7, [Species.GENESECT]: 6,
[Species.CHESPIN]: 3, [Species.CHESPIN]: 3,
[Species.FENNEKIN]: 3, [Species.FENNEKIN]: 3,
@ -2943,7 +2943,7 @@ export const speciesStarters = {
[Species.ZYGARDE]: 8, [Species.ZYGARDE]: 8,
[Species.DIANCIE]: 7, [Species.DIANCIE]: 7,
[Species.HOOPA]: 7, [Species.HOOPA]: 7,
[Species.VOLCANION]: 7, [Species.VOLCANION]: 6,
[Species.ETERNAL_FLOETTE]: 5, [Species.ETERNAL_FLOETTE]: 5,
[Species.ROWLET]: 3, [Species.ROWLET]: 3,
@ -2971,7 +2971,7 @@ export const speciesStarters = {
[Species.WIMPOD]: 3, [Species.WIMPOD]: 3,
[Species.SANDYGAST]: 3, [Species.SANDYGAST]: 3,
[Species.PYUKUMUKU]: 3, [Species.PYUKUMUKU]: 3,
[Species.TYPE_NULL]: 6, [Species.TYPE_NULL]: 5,
[Species.MINIOR]: 5, [Species.MINIOR]: 5,
[Species.KOMALA]: 5, [Species.KOMALA]: 5,
[Species.TURTONATOR]: 5, [Species.TURTONATOR]: 5,
@ -2985,21 +2985,21 @@ export const speciesStarters = {
[Species.TAPU_LELE]: 6, [Species.TAPU_LELE]: 6,
[Species.TAPU_BULU]: 6, [Species.TAPU_BULU]: 6,
[Species.TAPU_FINI]: 6, [Species.TAPU_FINI]: 6,
[Species.COSMOG]: 7, [Species.COSMOG]: 6,
[Species.NIHILEGO]: 7, [Species.NIHILEGO]: 6,
[Species.BUZZWOLE]: 7, [Species.BUZZWOLE]: 6,
[Species.PHEROMOSA]: 7, [Species.PHEROMOSA]: 7,
[Species.XURKITREE]: 7, [Species.XURKITREE]: 6,
[Species.CELESTEELA]: 7, [Species.CELESTEELA]: 6,
[Species.KARTANA]: 7, [Species.KARTANA]: 7,
[Species.GUZZLORD]: 7, [Species.GUZZLORD]: 6,
[Species.NECROZMA]: 8, [Species.NECROZMA]: 8,
[Species.MAGEARNA]: 7, [Species.MAGEARNA]: 7,
[Species.MARSHADOW]: 7, [Species.MARSHADOW]: 7,
[Species.POIPOLE]: 7, [Species.POIPOLE]: 7,
[Species.STAKATAKA]: 7, [Species.STAKATAKA]: 6,
[Species.BLACEPHALON]: 7, [Species.BLACEPHALON]: 7,
[Species.ZERAORA]: 7, [Species.ZERAORA]: 6,
[Species.MELTAN]: 6, [Species.MELTAN]: 6,
[Species.ALOLA_RATTATA]: 2, [Species.ALOLA_RATTATA]: 2,
[Species.ALOLA_SANDSHREW]: 4, [Species.ALOLA_SANDSHREW]: 4,
@ -3046,14 +3046,14 @@ export const speciesStarters = {
[Species.ARCTOVISH]: 5, [Species.ARCTOVISH]: 5,
[Species.DURALUDON]: 5, [Species.DURALUDON]: 5,
[Species.DREEPY]: 4, [Species.DREEPY]: 4,
[Species.ZACIAN]: 8, [Species.ZACIAN]: 9,
[Species.ZAMAZENTA]: 8, [Species.ZAMAZENTA]: 8,
[Species.ETERNATUS]: 10, [Species.ETERNATUS]: 10,
[Species.KUBFU]: 7, [Species.KUBFU]: 6,
[Species.ZARUDE]: 7, [Species.ZARUDE]: 6,
[Species.REGIELEKI]: 6, [Species.REGIELEKI]: 6,
[Species.REGIDRAGO]: 6, [Species.REGIDRAGO]: 6,
[Species.GLASTRIER]: 7, [Species.GLASTRIER]: 6,
[Species.SPECTRIER]: 7, [Species.SPECTRIER]: 7,
[Species.CALYREX]: 8, [Species.CALYREX]: 8,
[Species.GALAR_MEOWTH]: 4, [Species.GALAR_MEOWTH]: 4,
@ -3127,27 +3127,27 @@ export const speciesStarters = {
[Species.IRON_THORNS]: 6, [Species.IRON_THORNS]: 6,
[Species.FRIGIBAX]: 4, [Species.FRIGIBAX]: 4,
[Species.GIMMIGHOUL]: 5, [Species.GIMMIGHOUL]: 5,
[Species.WO_CHIEN]: 7, [Species.WO_CHIEN]: 6,
[Species.CHIEN_PAO]: 7, [Species.CHIEN_PAO]: 7,
[Species.TING_LU]: 7, [Species.TING_LU]: 6,
[Species.CHI_YU]: 7, [Species.CHI_YU]: 7,
[Species.ROARING_MOON]: 6, [Species.ROARING_MOON]: 6,
[Species.IRON_VALIANT]: 6, [Species.IRON_VALIANT]: 6,
[Species.KORAIDON]: 8, [Species.KORAIDON]: 9,
[Species.MIRAIDON]: 8, [Species.MIRAIDON]: 9,
[Species.WALKING_WAKE]: 7, [Species.WALKING_WAKE]: 6,
[Species.IRON_LEAVES]: 7, [Species.IRON_LEAVES]: 6,
[Species.POLTCHAGEIST]: 4, [Species.POLTCHAGEIST]: 4,
[Species.OKIDOGI]: 7, [Species.OKIDOGI]: 6,
[Species.MUNKIDORI]: 7, [Species.MUNKIDORI]: 6,
[Species.FEZANDIPITI]: 7, [Species.FEZANDIPITI]: 6,
[Species.OGERPON]: 8, [Species.OGERPON]: 7,
[Species.GOUGING_FIRE]: 7, [Species.GOUGING_FIRE]: 7,
[Species.RAGING_BOLT]: 7, [Species.RAGING_BOLT]: 6,
[Species.IRON_BOULDER]: 7, [Species.IRON_BOULDER]: 7,
[Species.IRON_CROWN]: 7, [Species.IRON_CROWN]: 6,
[Species.TERAPAGOS]: 8, [Species.TERAPAGOS]: 8,
[Species.PECHARUNT]: 7, [Species.PECHARUNT]: 6,
[Species.PALDEA_TAUROS]: 5, [Species.PALDEA_TAUROS]: 5,
[Species.PALDEA_WOOPER]: 3, [Species.PALDEA_WOOPER]: 3,
[Species.BLOODMOON_URSALUNA]: 7, [Species.BLOODMOON_URSALUNA]: 7,

View File

@ -60026,10 +60026,14 @@ export const tmSpecies: TmSpecies = {
Species.ARCANINE, Species.ARCANINE,
Species.AERODACTYL, Species.AERODACTYL,
Species.MEW, Species.MEW,
Species.CROCONAW,
Species.FERALIGATR,
Species.ESPEON, Species.ESPEON,
Species.GIRAFARIG, Species.GIRAFARIG,
Species.GLIGAR, Species.GLIGAR,
Species.STEELIX, Species.STEELIX,
Species.SNUBBULL,
Species.GRANBULL,
Species.HOUNDOUR, Species.HOUNDOUR,
Species.HOUNDOOM, Species.HOUNDOOM,
Species.POOCHYENA, Species.POOCHYENA,

View File

@ -4,7 +4,7 @@ import { Variant, VariantSet, variantColorCache } from '#app/data/variant';
import { variantData } from '#app/data/variant'; import { variantData } from '#app/data/variant';
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info'; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info';
import { Moves } from "../data/enums/moves"; import { Moves } from "../data/enums/moves";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr } from "../data/move"; import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit } from "../data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species'; import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species';
import * as Utils from '../utils'; import * as Utils from '../utils';
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type'; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type';
@ -336,7 +336,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
console.error(`Could not load ${res.url}!`); console.error(`Could not load ${res.url}!`);
return; return;
} }
res.json() return res.json()
}).then(c => { }).then(c => {
variantColorCache[key] = c; variantColorCache[key] = c;
resolve(); resolve();
@ -1127,7 +1127,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let shinyThreshold = new Utils.IntegerHolder(32); let shinyThreshold = new Utils.IntegerHolder(32);
if (thresholdOverride === undefined) { if (thresholdOverride === undefined) {
if (!this.hasTrainer()) { if (!this.hasTrainer()) {
if (new Date() < new Date('2024-05-21')) if (new Date() < new Date(2024, 4, 21, 20))
shinyThreshold.value *= 3; shinyThreshold.value *= 3;
this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
} }
@ -1282,11 +1282,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.isBoss()) // Bosses never get self ko moves if (this.isBoss()) // Bosses never get self ko moves
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(SacrificialAttr).length); movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(SacrificialAttr).length);
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(SacrificialAttrOnHit).length);
if (this.hasTrainer()) { if (this.hasTrainer()) {
// Trainers never get OHKO moves // Trainers never get OHKO moves
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(OneHitKOAttr).length); movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(OneHitKOAttr).length);
// Half the weight of self KO moves // Half the weight of self KO moves
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(SacrificialAttr).length ? 0.5 : 1)]); movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(SacrificialAttr).length ? 0.5 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(SacrificialAttrOnHit).length ? 0.5 : 1)]);
// Trainers get a weight bump to stat buffing moves // Trainers get a weight bump to stat buffing moves
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatChangeAttr).some(a => (a as StatChangeAttr).levels > 1 && (a as StatChangeAttr).selfTarget) ? 1.25 : 1)]); movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatChangeAttr).some(a => (a as StatChangeAttr).levels > 1 && (a as StatChangeAttr).selfTarget) ? 1.25 : 1)]);
// Trainers get a weight decrease to multiturn moves // Trainers get a weight decrease to multiturn moves

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!`, 'blockRecoilDamage' : `{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!`,
'badDreams': `{{pokemonName}} wird gequält!`,
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`,
'badDreams': `{{pokemonName}} is tormented!`,
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`,
'badDreams': `{{pokemonName}} Está atormentado!`
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !`, 'blockRecoilDamage' : `{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !`,
'badDreams': `{{pokemonName}} est tourmenté!`
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!`, 'blockRecoilDamage' : `{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!`,
'badDreams': `{{pokemonName}} è tormentato!`,
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力`, 'blockRecoilDamage' : `{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力`,
'badDreams': `{{pokemonName}} 被折磨着!`
} as const; } as const;

View File

@ -1423,7 +1423,7 @@ export class ExpBalanceModifier extends PersistentModifier {
} }
getMaxStackCount(scene: BattleScene): integer { getMaxStackCount(scene: BattleScene): integer {
return 5; return 4;
} }
} }

View File

@ -366,12 +366,16 @@ export class TitlePhase extends Phase {
this.scene.pushPhase(new SummonPhase(this.scene, 0, true, true)); this.scene.pushPhase(new SummonPhase(this.scene, 0, true, true));
if (this.scene.currentBattle.double && availablePartyMembers > 1) if (this.scene.currentBattle.double && availablePartyMembers > 1)
this.scene.pushPhase(new SummonPhase(this.scene, 1, true, true)); this.scene.pushPhase(new SummonPhase(this.scene, 1, true, true));
if (this.scene.currentBattle.waveIndex > 1 && this.scene.currentBattle.battleType !== BattleType.TRAINER) {
if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) {
const minPartySize = this.scene.currentBattle.double ? 2 : 1;
if (availablePartyMembers > minPartySize) {
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double));
if (this.scene.currentBattle.double && availablePartyMembers > 1) if (this.scene.currentBattle.double)
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double));
} }
} }
}
for (let achv of Object.keys(this.scene.gameData.achvUnlocks)) { for (let achv of Object.keys(this.scene.gameData.achvUnlocks)) {
if (vouchers.hasOwnProperty(achv)) if (vouchers.hasOwnProperty(achv))
@ -955,12 +959,15 @@ export class EncounterPhase extends BattlePhase {
this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, false)); this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, false));
} }
if (this.scene.currentBattle.waveIndex > startingWave && this.scene.currentBattle.battleType !== BattleType.TRAINER) { if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) {
const minPartySize = this.scene.currentBattle.double ? 2 : 1;
if (availablePartyMembers.length > minPartySize) {
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double));
if (this.scene.currentBattle.double && availablePartyMembers.length > 1) if (this.scene.currentBattle.double)
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double));
} }
} }
}
handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end()); handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end());
} }
@ -4416,6 +4423,7 @@ export class AttemptCapturePhase extends PokemonPhase {
if (this.scene.getParty().length === 6) { if (this.scene.getParty().length === 6) {
const promptRelease = () => { const promptRelease = () => {
this.scene.ui.showText(`Your party is full.\nRelease a Pokémon to make room for ${pokemon.name}?`, null, () => { this.scene.ui.showText(`Your party is full.\nRelease a Pokémon to make room for ${pokemon.name}?`, null, () => {
this.scene.pokemonInfoContainer.makeRoomForConfirmUi();
this.scene.ui.setMode(Mode.CONFIRM, () => { this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: integer, _option: PartyOption) => { this.scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: integer, _option: PartyOption) => {
this.scene.ui.setMode(Mode.MESSAGE).then(() => { this.scene.ui.setMode(Mode.MESSAGE).then(() => {

View File

@ -93,8 +93,9 @@ export function initI18n(): void {
i18next.use(LanguageDetector).init({ i18next.use(LanguageDetector).init({
lng: lang, lng: lang,
nonExplicitSupportedLngs: true,
fallbackLng: 'en', fallbackLng: 'en',
supportedLngs: ['en', 'es', 'fr', 'it', 'de', 'zh_CN','pt_BR'], supportedLngs: ['en', 'es', 'fr', 'it', 'de', 'zh','pt'],
debug: true, debug: true,
interpolation: { interpolation: {
escapeValue: false, escapeValue: false,

View File

@ -867,8 +867,11 @@ export class GameData {
const ret: PersistentModifierData[] = []; const ret: PersistentModifierData[] = [];
if (v === null) if (v === null)
v = []; v = [];
for (let md of v) for (let md of v) {
if(md?.className === 'ExpBalanceModifier') // Temporarily limit EXP Balance until it gets reworked
md.stackCount = Math.min(md.stackCount, 4);
ret.push(new PersistentModifierData(md, player)); ret.push(new PersistentModifierData(md, player));
}
return ret; return ret;
} }

View File

@ -0,0 +1,225 @@
import {beforeAll, describe, expect, it} from "vitest";
import _masterlist from '../../public/images/pokemon/variant/_masterlist.json';
import fs from 'fs';
import path from 'path';
import {getAppRootDir} from "#app/test/testUtils";
const deepCopy = (data) => {
return JSON.parse(JSON.stringify(data));
}
describe("check if every variant's sprite are correctly set", () => {
let masterlist;
let expVariant;
let femaleVariant;
let backVariant;
let rootDir;
beforeAll(() => {
rootDir = `${getAppRootDir()}${path.sep}public${path.sep}images${path.sep}pokemon${path.sep}variant${path.sep}`
masterlist = deepCopy(_masterlist);
expVariant = masterlist.exp;
femaleVariant = masterlist.female;
backVariant = masterlist.back;
delete masterlist.exp
delete masterlist.female
delete masterlist.back
});
it('data should not be undefined', () => {
expect(masterlist).not.toBeUndefined();
expect(expVariant).not.toBeUndefined();
expect(femaleVariant).not.toBeUndefined();
expect(backVariant).not.toBeUndefined();
});
function getMissingMasterlist(mlist, dirpath, excludes = []) {
const errors = [];
const trimmedDirpath = `variant${path.sep}${dirpath.split(rootDir)[1]}`;
if (fs.existsSync(dirpath)) {
const files = fs.readdirSync(dirpath);
for (const filename of files) {
const filePath = `${dirpath}${filename}`
const trimmedFilePath = `${trimmedDirpath}${filename}`
const ext = filename.split('.')[1];
const name = filename.split('.')[0];
if (excludes.includes(name)) continue;
if (name.includes('_')) {
const id = name.split('_')[0];
const variant = name.split('_')[1];
if (ext !== 'json') {
if (mlist.hasOwnProperty(id)) {
const urlJsonFile = `${dirpath}${id}.json`;
const trimmedUrlJsonFilepath = `${trimmedDirpath}${id}.json`;
const jsonFileExists = fs.existsSync(urlJsonFile);
if (mlist[id].includes(1)) {
const msg = `[${name}] MISSING JSON ${trimmedUrlJsonFilepath}`;
if (!jsonFileExists && !errors.includes(msg)) errors.push(msg);
}
}
if (!mlist.hasOwnProperty(id)) errors.push(`[${id}] missing key ${id} in masterlist for ${trimmedFilePath}`);
else if (mlist[id][parseInt(variant, 10) - 1] !== 2) {
const urlJsonFile = `${dirpath}${name}.json`;
const trimmedUrlJsonFilepath = `${trimmedDirpath}${name}.json`;
const jsonFileExists = fs.existsSync(urlJsonFile);
if (mlist[id].includes(1)) {
const msg = `[${id}] MISSING JSON ${trimmedUrlJsonFilepath}`;
if (!jsonFileExists && !errors.includes(msg)) errors.push(msg);
}
errors.push(`[${id}] [${mlist[id]}] - the value should be 2 for the index ${parseInt(variant, 10) - 1} - ${trimmedFilePath}`);
}
}
} else if (!mlist.hasOwnProperty(name)) errors.push(`named - missing key ${name} in masterlist for ${trimmedFilePath}`);else {
const raw = fs.readFileSync(filePath, {encoding: 'utf8', flag: 'r'});
const data = JSON.parse(raw);
for (const key of Object.keys(data)) {
if (mlist[name][key] !== 1) errors.push(`[${name}] [${mlist[name]}] - the value should be 1 for the index ${key} - ${trimmedFilePath}`);
}
}
}
}
return errors;
}
function getMissingFiles(keys, dirPath) {
const errors = [];
for (const key of Object.keys(keys)) {
const row = keys[key];
for (const [index, elm] of row.entries()) {
let url;
if (elm === 0) continue
else if (elm === 1) {
url = `${key}.json`
let filePath = `${dirPath}${url}`;
const raw = fs.readFileSync(filePath, {encoding: 'utf8', flag: 'r'});
const data = JSON.parse(raw);
if (!data.hasOwnProperty(index)) {
errors.push(`index: ${index} - ${filePath}`);
}
} else if (elm === 2) {
url = `${key}_${parseInt(index, 10) + 1}.png`;
let filePath = `${dirPath}${url}`;
if (!fs.existsSync(filePath)) {
errors.push(filePath)
}
url = `${key}_${parseInt(index, 10) + 1}.json`;
filePath = `${dirPath}${url}`;
if (!fs.existsSync(filePath)) {
errors.push(filePath)
}
}
}
}
return errors;
}
// chech presence of every files listed in masterlist
it('check root variant files', () => {
const dirPath = rootDir;
const errors = getMissingFiles(masterlist, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check female variant files', () => {
const dirPath = `${rootDir}female${path.sep}`;
const errors = getMissingFiles(femaleVariant, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check back female variant files', () => {
const dirPath = `${rootDir}back${path.sep}female${path.sep}`;
const errors = getMissingFiles(backVariant.female, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check back male back variant files', () => {
const dirPath = `${rootDir}back${path.sep}`;
let backMaleVariant = deepCopy(backVariant);
delete backMaleVariant.female;
const errors = getMissingFiles(backMaleVariant, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check exp back variant files', () => {
const dirPath = `${rootDir}exp${path.sep}back${path.sep}`;
const errors = getMissingFiles(expVariant.back, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check exp female variant files', () => {
const dirPath = `${rootDir}exp${path.sep}female${path.sep}`;
const errors = getMissingFiles(expVariant.female, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check exp male variant files', () => {
const dirPath = `${rootDir}exp${path.sep}`;
let expMaleVariant = deepCopy(expVariant);
delete expMaleVariant.female;
delete expMaleVariant.back;
const errors = getMissingFiles(expMaleVariant, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
// check over every file if it's correctly set in the masterlist
it('look over every file in variant female and check if present in masterlist', () => {
const dirPath = `${rootDir}female${path.sep}`;
const errors = getMissingMasterlist(femaleVariant, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant back female and check if present in masterlist', () => {
const dirPath = `${rootDir}back${path.sep}female${path.sep}`;
const errors = getMissingMasterlist(backVariant.female, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant back male and check if present in masterlist', () => {
const dirPath = `${rootDir}back${path.sep}`;
let backMaleVariant = deepCopy(backVariant);
const errors = getMissingMasterlist(backMaleVariant, dirPath, ['female']);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant exp back and check if present in masterlist', () => {
const dirPath = `${rootDir}exp${path.sep}back${path.sep}`;
const errors = getMissingMasterlist(expVariant.back, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant exp female and check if present in masterlist', () => {
const dirPath = `${rootDir}exp${path.sep}female${path.sep}`;
const errors = getMissingMasterlist(expVariant.female, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant exp male and check if present in masterlist', () => {
const dirPath = `${rootDir}exp${path.sep}`;
const errors = getMissingMasterlist(expVariant, dirPath, ['back', 'female']);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant root and check if present in masterlist', () => {
const dirPath = `${rootDir}`;
const errors = getMissingMasterlist(masterlist, dirPath, ['back', 'female', 'exp', 'icons']);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
});

10
src/test/testUtils.ts Normal file
View File

@ -0,0 +1,10 @@
const fs = require('fs')
const path = require('path')
export function getAppRootDir () {
let currentDir = __dirname
while(!fs.existsSync(path.join(currentDir, 'package.json'))) {
currentDir = path.join(currentDir, '..')
}
return currentDir
}

View File

@ -5,6 +5,9 @@ import i18next from "i18next";
import {Button} from "../enums/buttons"; import {Button} from "../enums/buttons";
export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler { export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
public static readonly windowWidth: integer = 48;
private switchCheck: boolean; private switchCheck: boolean;
private switchCheckCursor: integer; private switchCheckCursor: integer;
@ -13,7 +16,7 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
} }
getWindowWidth(): integer { getWindowWidth(): integer {
return 48; return ConfirmUiHandler.windowWidth;
} }
show(args: any[]): boolean { show(args: any[]): boolean {

View File

@ -9,8 +9,11 @@ import { getNatureName } from "../data/nature";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { Type } from "../data/type"; import { Type } from "../data/type";
import { getVariantTint } from "#app/data/variant"; import { getVariantTint } from "#app/data/variant";
import ConfirmUiHandler from "./confirm-ui-handler";
export default class PokemonInfoContainer extends Phaser.GameObjects.Container { export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
private readonly infoWindowWidth = 104;
private pokemonGenderLabelText: Phaser.GameObjects.Text; private pokemonGenderLabelText: Phaser.GameObjects.Text;
private pokemonGenderText: Phaser.GameObjects.Text; private pokemonGenderText: Phaser.GameObjects.Text;
private pokemonAbilityLabelText: Phaser.GameObjects.Text; private pokemonAbilityLabelText: Phaser.GameObjects.Text;
@ -37,7 +40,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
} }
setup(): void { setup(): void {
const infoBg = addWindow(this.scene, 0, 0, 104, 132); const infoBg = addWindow(this.scene, 0, 0, this.infoWindowWidth, 132);
infoBg.setOrigin(0.5, 0.5); infoBg.setOrigin(0.5, 0.5);
this.pokemonMovesContainer = this.scene.add.container(6, 14); this.pokemonMovesContainer = this.scene.add.container(6, 14);
@ -172,7 +175,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
targets: this, targets: this,
duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)),
ease: 'Cubic.easeInOut', ease: 'Cubic.easeInOut',
x: this.initialX - 104, x: this.initialX - this.infoWindowWidth,
onComplete: () => { onComplete: () => {
resolve(); resolve();
} }
@ -201,6 +204,20 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
}); });
} }
makeRoomForConfirmUi(speedMultiplier: number = 1): Promise<void> {
return new Promise<void>(resolve => {
this.scene.tweens.add({
targets: this,
duration: Utils.fixedInt(Math.floor(150 / speedMultiplier)),
ease: 'Cubic.easeInOut',
x: this.initialX - this.infoWindowWidth - ConfirmUiHandler.windowWidth,
onComplete: () => {
resolve();
}
});
});
}
hide(speedMultiplier: number = 1): Promise<void> { hide(speedMultiplier: number = 1): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
if (!this.shown) if (!this.shown)

View File

@ -70,12 +70,12 @@ const languageSettings: { [key: string]: LanguageSetting } = {
starterInfoTextSize: '54px', starterInfoTextSize: '54px',
instructionTextSize: '42px', instructionTextSize: '42px',
}, },
"zh_CN":{ "zh":{
starterInfoTextSize: '40px', starterInfoTextSize: '40px',
instructionTextSize: '42px', instructionTextSize: '42px',
starterInfoYOffset: 2 starterInfoYOffset: 2
}, },
"pt_BR":{ "pt":{
starterInfoTextSize: '47px', starterInfoTextSize: '47px',
instructionTextSize: '38px', instructionTextSize: '38px',
starterInfoXPos: 32, starterInfoXPos: 32,
@ -85,11 +85,11 @@ const languageSettings: { [key: string]: LanguageSetting } = {
const starterCandyCosts: { passive: integer, costReduction: [integer, integer] }[] = [ const starterCandyCosts: { passive: integer, costReduction: [integer, integer] }[] = [
{ passive: 50, costReduction: [30, 75] }, // 1 { passive: 50, costReduction: [30, 75] }, // 1
{ passive: 45, costReduction: [25, 60] }, // 2 { passive: 45, costReduction: [25, 60] }, // 2
{ passive: 30, costReduction: [20, 50] }, // 3 { passive: 40, costReduction: [20, 50] }, // 3
{ passive: 25, costReduction: [15, 40] }, // 4 { passive: 30, costReduction: [15, 40] }, // 4
{ passive: 20, costReduction: [12, 35] }, // 5 { passive: 25, costReduction: [12, 35] }, // 5
{ passive: 15, costReduction: [10, 30] }, // 6 { passive: 20, costReduction: [10, 30] }, // 6
{ passive: 10, costReduction: [8, 20] }, // 7 { passive: 15, costReduction: [8, 20] }, // 7
{ passive: 10, costReduction: [5, 15] }, // 8 { passive: 10, costReduction: [5, 15] }, // 8
{ passive: 10, costReduction: [3, 10] }, // 9 { passive: 10, costReduction: [3, 10] }, // 9
{ passive: 10, costReduction: [3, 10] }, // 10 { passive: 10, costReduction: [3, 10] }, // 10
@ -217,7 +217,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
setup() { setup() {
const ui = this.getUi(); const ui = this.getUi();
const currentLanguage = i18next.language; const currentLanguage = i18next.language;
const textSettings = languageSettings[currentLanguage]; const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage.includes(lang));
const textSettings = languageSettings[langSettingKey];
this.starterSelectContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); this.starterSelectContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
this.starterSelectContainer.setVisible(false); this.starterSelectContainer.setVisible(false);
@ -280,7 +281,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
let starterInfoYOffset = textSettings?.starterInfoYOffset || 0; let starterInfoYOffset = textSettings?.starterInfoYOffset || 0;
// The font size should be set per language // The font size should be set per language
let starterInfoTextSize = textSettings.starterInfoTextSize; let starterInfoTextSize = textSettings?.starterInfoTextSize || 56;
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127 + starterInfoYOffset, i18next.t("starterSelectUiHandler:ability"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize }); this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127 + starterInfoYOffset, i18next.t("starterSelectUiHandler:ability"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityLabelText.setOrigin(0, 0); this.pokemonAbilityLabelText.setOrigin(0, 0);