From 7fea8603f3f34ad639debfda6a45191af42d33bf Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:41:22 -0500 Subject: [PATCH 1/2] [Refactor] Add support for showing separate species form names (#5294) * Support for localization of regional form names * Show names of regional and other forms where appropriate * Add form name to evolution screen * Remove formKey parameter * Update docstrings * More SpeciesFormKey Co-authored-by: Wlowscha <54003515+Wlowscha@users.noreply.github.com> * Clean up * Fix inconsistent key name --------- Co-authored-by: Wlowscha <54003515+Wlowscha@users.noreply.github.com> --- src/data/pokemon-species.ts | 50 +++++++++++++++++++++++++ src/phases/egg-hatch-phase.ts | 3 +- src/phases/evolution-phase.ts | 2 +- src/ui/pokedex-page-ui-handler.ts | 57 +++++------------------------ src/ui/pokemon-info-container.ts | 19 +--------- src/ui/starter-select-ui-handler.ts | 13 ++----- 6 files changed, 66 insertions(+), 78 deletions(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 55da6a7e76c..041632b183d 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -690,6 +690,56 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali return this.name; } + /** + * Find the name of species with proper attachments for regionals and separate starter forms (Floette, Ursaluna) + * @returns a string with the region name or other form name attached + */ + getExpandedSpeciesName(): string { + if (this.speciesId < 2000) { + return this.name; // Other special cases could be put here too + } else { // Everything beyond this point essentially follows the pattern of FORMNAME_SPECIES + return i18next.t(`pokemonForm:appendForm.${Species[this.speciesId].split("_")[0]}`, { pokemonName: this.name }); + } + } + + /** + * Find the form name for species with just one form (regional variants, Floette, Ursaluna) + * @param formIndex The form index to check (defaults to 0) + * @param append Whether to append the species name to the end (defaults to false) + * @returns the pokemon-form locale key for the single form name ("Alolan Form", "Eternal Flower" etc) + */ + getFormNameToDisplay(formIndex: number = 0, append: boolean = false): string { + const formKey = this.forms?.[formIndex!]?.formKey; + const formText = Utils.capitalizeString(formKey, "-", false, false) || ""; + const speciesName = Utils.capitalizeString(Species[this.speciesId], "_", true, false); + let ret: string = ""; + + const region = this.getRegion(); + if (this.speciesId === Species.ARCEUS) { + ret = i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`); + } else if ([ SpeciesFormKey.MEGA, SpeciesFormKey.MEGA_X, SpeciesFormKey.MEGA_Y, SpeciesFormKey.PRIMAL, SpeciesFormKey.GIGANTAMAX, SpeciesFormKey.GIGANTAMAX_RAPID, SpeciesFormKey.GIGANTAMAX_SINGLE, SpeciesFormKey.ETERNAMAX ].includes(formKey as SpeciesFormKey)) { + return i18next.t(`battlePokemonForm:${formKey}`, { pokemonName: (append ? this.name : "") }); + } else if (region === Region.NORMAL || (this.speciesId === Species.GALAR_DARMANITAN && formIndex > 0) || this.speciesId === Species.PALDEA_TAUROS) { // More special cases can be added here + const i18key = `pokemonForm:${speciesName}${formText}`; + if (i18next.exists(i18key)) { + ret = i18next.t(i18key); + } else { + const rootSpeciesName = Utils.capitalizeString(Species[this.getRootSpeciesId()], "_", true, false); + const i18RootKey = `pokemonForm:${rootSpeciesName}${formText}`; + ret = i18next.exists(i18RootKey) ? i18next.t(i18RootKey) : formText; + } + } else if (append) { // Everything beyond this has an expanded name + return this.getExpandedSpeciesName(); + } else if (this.speciesId === Species.ETERNAL_FLOETTE) { // Not a real form, so the key is made up + return i18next.t("pokemonForm:floetteEternalFlower"); + } else if (this.speciesId === Species.BLOODMOON_URSALUNA) { // Not a real form, so the key is made up + return i18next.t("pokemonForm:ursalunaBloodmoon"); + } else { // Only regional forms should be left at this point + return i18next.t(`pokemonForm:regionalForm.${Region[region]}`); + } + return append ? i18next.t("pokemonForm:appendForm.GENERIC", { pokemonName: this.name, formName: ret }) : ret; + } + localize(): void { this.name = i18next.t(`pokemon:${Species[this.speciesId].toLowerCase()}`); } diff --git a/src/phases/egg-hatch-phase.ts b/src/phases/egg-hatch-phase.ts index 2d0aa24dd1f..b2844591e33 100644 --- a/src/phases/egg-hatch-phase.ts +++ b/src/phases/egg-hatch-phase.ts @@ -3,7 +3,6 @@ import { globalScene } from "#app/global-scene"; import type { Egg } from "#app/data/egg"; import { EggCountChangedEvent } from "#app/events/egg"; import type { PlayerPokemon } from "#app/field/pokemon"; -import { getPokemonNameWithAffix } from "#app/messages"; import { Phase } from "#app/phase"; import { achvs } from "#app/system/achv"; import EggCounterContainer from "#app/ui/egg-counter-container"; @@ -356,7 +355,7 @@ export class EggHatchPhase extends Phase { globalScene.playSoundWithoutBgm("evolution_fanfare"); - globalScene.ui.showText(i18next.t("egg:hatchFromTheEgg", { pokemonName: getPokemonNameWithAffix(this.pokemon) }), null, () => { + globalScene.ui.showText(i18next.t("egg:hatchFromTheEgg", { pokemonName: this.pokemon.species.getExpandedSpeciesName() }), null, () => { globalScene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs); globalScene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => { globalScene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then((value) => { diff --git a/src/phases/evolution-phase.ts b/src/phases/evolution-phase.ts index 533edd320e3..12d2923ec36 100644 --- a/src/phases/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -270,7 +270,7 @@ export class EvolutionPhase extends Phase { globalScene.playSoundWithoutBgm("evolution_fanfare"); evolvedPokemon.destroy(); - globalScene.ui.showText(i18next.t("menu:evolutionDone", { pokemonName: this.preEvolvedPokemonName, evolvedPokemonName: this.pokemon.name }), null, () => this.end(), null, true, Utils.fixedInt(4000)); + globalScene.ui.showText(i18next.t("menu:evolutionDone", { pokemonName: this.preEvolvedPokemonName, evolvedPokemonName: this.pokemon.species.getExpandedSpeciesName() }), null, () => this.end(), null, true, Utils.fixedInt(4000)); globalScene.time.delayedCall(Utils.fixedInt(4250), () => globalScene.playBgm()); }); }); diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index 2047095d067..683045d7814 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -15,7 +15,6 @@ import type { SpeciesFormChange } from "#app/data/pokemon-forms"; import { pokemonFormChanges } from "#app/data/pokemon-forms"; import type { LevelMoves } from "#app/data/balance/pokemon-level-moves"; import { pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves"; -import type { PokemonForm } from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; @@ -44,7 +43,7 @@ import { Species } from "#enums/species"; import { Button } from "#enums/buttons"; import { EggSourceType } from "#enums/egg-source-types"; import { getPassiveCandyCount, getValueReductionCandyCounts, getSameSpeciesEggCandyCounts } from "#app/data/balance/starters"; -import { BooleanHolder, capitalizeString, getLocalizedSpriteKey, isNullOrUndefined, NumberHolder, padInt, rgbHexToRgba, toReadableString } from "#app/utils"; +import { BooleanHolder, getLocalizedSpriteKey, isNullOrUndefined, NumberHolder, padInt, rgbHexToRgba, toReadableString } from "#app/utils"; import type { Nature } from "#enums/nature"; import BgmBar from "./bgm-bar"; import * as Utils from "../utils"; @@ -899,43 +898,6 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } } - /** - * Assign a form string to a given species and form - * @param formKey the form to format - * @param species the species to format - * @param speciesId whether the name of the species should be shown at the end - * @returns the formatted string - */ - getFormString(formKey: string, species: PokemonSpecies, append: boolean = false): string { - let label: string; - const formText = capitalizeString(formKey, "-", false, false) ?? ""; - const speciesName = capitalizeString(this.getStarterSpecies(species).name, "_", true, false) ?? ""; - if (species.speciesId === Species.ARCEUS) { - label = i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`); - return label; - } - label = formText ? i18next.t(`pokemonForm:${speciesName}${formText}`) : ""; - if (label === `${speciesName}${formText}`) { - label = i18next.t(`battlePokemonForm:${formKey}`, { pokemonName:species.name }); - } else { - // If the label is only the form, we can append the name of the pokemon - label += append ? ` ${species.name}` : ""; - } - return label; - } - - /** - * Find the name of the region for regional species - * @param species the species to check - * @returns a string with the region name - */ - getRegionName(species: PokemonSpecies): string { - const name = species.name; - const label = Species[species.speciesId]; - const suffix = label.includes("_") ? " (" + label.split("_")[0].toLowerCase() + ")" : ""; - return name + suffix; - } - processInput(button: Button): boolean { if (this.blockInput) { return false; @@ -1375,13 +1337,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler { }); this.prevolutions.map(pre => { const preSpecies = allSpecies.find(species => species.speciesId === pokemonPrevolutions[this.species.speciesId]); + const preFormIndex: number = preSpecies?.forms.find(f => f.formKey === pre.preFormKey)?.formIndex ?? 0; const conditionText: string = pre.description; options.push({ label: pre.preFormKey ? - this.getFormString(pre.preFormKey, preSpecies ?? this.species, true) : - this.getRegionName(preSpecies ?? this.species), + (preSpecies ?? this.species).getFormNameToDisplay(preFormIndex, true) : + (preSpecies ?? this.species).getExpandedSpeciesName(), handler: () => { const newSpecies = allSpecies.find(species => species.speciesId === pokemonPrevolutions[pre.speciesId]); // Attempts to find the formIndex of the prevolved species @@ -1421,8 +1384,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler { options.push({ label: evo.evoFormKey ? - this.getFormString(evo.evoFormKey, evoSpecies ?? this.species, true) : - this.getRegionName(evoSpecies ?? this.species), + (evoSpecies ?? this.species).getFormNameToDisplay(newFormIndex, true) : + (evoSpecies ?? this.species).getExpandedSpeciesName(), style: isCaughtEvo && isFormCaughtEvo ? TextStyle.WINDOW : TextStyle.SHADOW_TEXT, handler: () => { this.starterAttributes.form = newFormIndex; @@ -1445,6 +1408,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler { handler: () => false }); this.battleForms.map(bf => { + const matchingForm = this.species?.forms.find(form => form.formKey === bf.formKey); + const newFormIndex = matchingForm ? matchingForm.formIndex : 0; let conditionText:string = ""; if (bf.trigger) { @@ -1452,12 +1417,10 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { conditionText = ""; } - let label: string = this.getFormString(bf.formKey, this.species); + let label: string = this.species.getFormNameToDisplay(newFormIndex); if (label === "") { label = this.species.name; } - const matchingForm = this.species?.forms.find(form => form.formKey === bf.formKey); - const newFormIndex = matchingForm ? matchingForm.formIndex : 0; const isFormCaught = this.isFormCaught(this.species, newFormIndex); if (conditionText) { @@ -2313,7 +2276,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { if (isFormCaught || isFormSeen) { const speciesForm = getPokemonSpeciesForm(species.speciesId, formIndex!); // TODO: is the bang correct? this.setTypeIcons(speciesForm.type1, speciesForm.type2); - this.pokemonFormText.setText(this.getFormString((speciesForm as PokemonForm).formKey, species)); + this.pokemonFormText.setText(species.getFormNameToDisplay(formIndex)); this.pokemonFormText.setVisible(true); if (!isFormCaught) { this.pokemonFormText.setY(18); diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 554cea39731..eda5ac3f580 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -13,7 +13,6 @@ import ConfirmUiHandler from "./confirm-ui-handler"; import { StatsContainer } from "./stats-container"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; import { addWindow } from "./ui-theme"; -import { Species } from "#enums/species"; interface LanguageSetting { infoContainerTextSize: string; @@ -218,23 +217,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.pokemonGenderText.setVisible(false); } - const formKey = (pokemon.species?.forms?.[pokemon.formIndex!]?.formKey); - const formText = Utils.capitalizeString(formKey, "-", false, false) || ""; - const speciesName = Utils.capitalizeString(Species[pokemon.species.speciesId], "_", true, false); - - let formName = ""; - if (pokemon.species.speciesId === Species.ARCEUS) { - formName = i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`); - } else { - const i18key = `pokemonForm:${speciesName}${formText}`; - if (i18next.exists(i18key)) { - formName = i18next.t(i18key); - } else { - const rootSpeciesName = Utils.capitalizeString(Species[pokemon.species.getRootSpeciesId()], "_", true, false); - const i18RootKey = `pokemonForm:${rootSpeciesName}${formText}`; - formName = i18next.exists(i18RootKey) ? i18next.t(i18RootKey) : formText; - } - } + const formName = pokemon.species.getFormNameToDisplay(pokemon.formIndex); if (formName) { this.pokemonFormLabelText.setVisible(true); diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 5476f38cc6a..65c159c62a8 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -53,7 +53,7 @@ import { EncounterPhase } from "#app/phases/encounter-phase"; import { TitlePhase } from "#app/phases/title-phase"; import { Abilities } from "#enums/abilities"; import { getPassiveCandyCount, getValueReductionCandyCounts, getSameSpeciesEggCandyCounts } from "#app/data/balance/starters"; -import { BooleanHolder, capitalizeString, fixedInt, getLocalizedSpriteKey, isNullOrUndefined, NumberHolder, padInt, randIntRange, rgbHexToRgba, toReadableString } from "#app/utils"; +import { BooleanHolder, fixedInt, getLocalizedSpriteKey, isNullOrUndefined, NumberHolder, padInt, randIntRange, rgbHexToRgba, toReadableString } from "#app/utils"; import type { Nature } from "#enums/nature"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; @@ -3408,15 +3408,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { }) as StarterMoveset; const speciesForm = getPokemonSpeciesForm(species.speciesId, formIndex!); // TODO: is the bang correct? - const formText = capitalizeString(species?.forms[formIndex!]?.formKey, "-", false, false); // TODO: is the bang correct? - - const speciesName = capitalizeString(Species[species.speciesId], "_", true, false); - - if (species.speciesId === Species.ARCEUS) { - this.pokemonFormText.setText(i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`)); - } else { - this.pokemonFormText.setText(formText ? i18next.t(`pokemonForm:${speciesName}${formText}`) : ""); - } + const formText = species.getFormNameToDisplay(formIndex); + this.pokemonFormText.setText(formText); this.setTypeIcons(speciesForm.type1, speciesForm.type2); } else { From 5045b637ff14a3c0d6fe97db7c80faca1ed5dfa1 Mon Sep 17 00:00:00 2001 From: damocleas Date: Tue, 11 Feb 2025 17:10:25 -0500 Subject: [PATCH 2/2] [Balance] Item Table Removals and increased Wide Lens Frequency (#5296) * Update modifier-type.ts * Up weight of event DNA Splicers * fix attempt 1 * Removed 100 pokemon minimum requirement for Catching Charm commit fontbane suggestion Co-authored-by: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> * Removed unused items from item table * removed selfStatLowerMoves --------- Co-authored-by: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> --- src/modifier/modifier-type.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index b1e8b69df36..da2ab49e9fc 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { tmPoolTiers, tmSpecies } from "#app/data/balance/tms"; import { getBerryEffectDescription, getBerryName } from "#app/data/berry"; -import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move"; +import { allMoves, AttackMove } from "#app/data/move"; import { getNatureName, getNatureStatMultiplier } from "#app/data/nature"; import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; @@ -1725,7 +1725,7 @@ const modifierPool: ModifierPool = { if (globalScene.gameMode.isSplicedOnly) { return 4; } else if (globalScene.gameMode.isClassic && globalScene.eventManager.areFusionsBoosted()) { - return 1; + return 2; } } return 0; @@ -1833,14 +1833,6 @@ const modifierPool: ModifierPool = { return false; }) ? 10 : 0; }, 10), - new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => { - const checkedAbilities = [ Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT ]; - const weightMultiplier = party.filter( - p => !p.getHeldItems().some(i => i instanceof ResetNegativeStatStageModifier && i.stackCount >= i.getMaxHeldItemCount(p)) && - (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && selfStatLowerMoves.includes(m.moveId)))).length; - // If a party member has one of the above moves or abilities and doesn't have max herbs, the herb will appear more frequently - return 0 * (weightMultiplier ? 2 : 1) + (weightMultiplier ? weightMultiplier * 0 : 0); - }, 10), new WeightedModifierType(modifierTypes.REVIVER_SEED, 4), new WeightedModifierType(modifierTypes.CANDY_JAR, skipInLastClassicWaveOrDefault(5)), new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 9), @@ -1850,10 +1842,9 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.IV_SCANNER, skipInLastClassicWaveOrDefault(4)), new WeightedModifierType(modifierTypes.EXP_CHARM, skipInLastClassicWaveOrDefault(8)), new WeightedModifierType(modifierTypes.EXP_SHARE, skipInLastClassicWaveOrDefault(10)), - new WeightedModifierType(modifierTypes.EXP_BALANCE, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.TERA_ORB, () => Math.min(Math.max(Math.floor(globalScene.currentBattle.waveIndex / 50) * 2, 1), 4), 4), new WeightedModifierType(modifierTypes.QUICK_CLAW, 3), - new WeightedModifierType(modifierTypes.WIDE_LENS, 4), + new WeightedModifierType(modifierTypes.WIDE_LENS, 7), ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }), @@ -1867,8 +1858,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.SCOPE_LENS, 4), new WeightedModifierType(modifierTypes.BATON, 2), new WeightedModifierType(modifierTypes.SOUL_DEW, 7), - //new WeightedModifierType(modifierTypes.OVAL_CHARM, 6), - new WeightedModifierType(modifierTypes.CATCHING_CHARM, () => globalScene.gameMode.isDaily || (!globalScene.gameMode.isFreshStartChallenge() && globalScene.gameData.getSpeciesCount(d => !!d.caughtAttr) > 100) ? 4 : 0, 4), + new WeightedModifierType(modifierTypes.CATCHING_CHARM, () => !globalScene.gameMode.isClassic ? 4 : 0, 4), new WeightedModifierType(modifierTypes.ABILITY_CHARM, skipInClassicAfterWave(189, 6)), new WeightedModifierType(modifierTypes.FOCUS_BAND, 5), new WeightedModifierType(modifierTypes.KINGS_ROCK, 3),