From cc7e1af82760712fee4444967101abb7df4238fc Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Tue, 25 Feb 2025 05:43:34 +0100 Subject: [PATCH 1/6] [BUG] Base forms are now counted as caught when catching a battle form (#5385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Base forms are counted as caught when catching a battle form * Ensuring that correct form shows up in Pokédex Index --- src/system/game-data.ts | 21 ++++++++++++++++++++- src/ui/pokedex-ui-handler.ts | 4 ++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 6b25013795f..57e25325ba4 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -55,6 +55,7 @@ import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-e import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { ArenaTrapTag } from "#app/data/arena-tag"; +import { pokemonFormChanges } from "#app/data/pokemon-forms"; import type { Type } from "#enums/type"; export const defaultStarterSpecies: Species[] = [ @@ -1629,11 +1630,29 @@ export class GameData { const caughtAttr = dexEntry.caughtAttr; const formIndex = pokemon.formIndex; const dexAttr = pokemon.getDexAttr(); - pokemon.formIndex = formIndex; // Mark as caught dexEntry.caughtAttr |= dexAttr; + // If the caught form is a battleform, we want to also mark the base form as caught. + // This snippet assumes that the base form has formIndex equal to 0, which should be + // always true except for the case of Urshifu. + const formKey = pokemon.getFormKey(); + if (formIndex > 0) { + if (pokemon.species.speciesId === Species.URSHIFU) { + if (formIndex === 2) { + dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(0); + } else if (formIndex === 3) { + dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(1); + } + } + const allFormChanges = pokemonFormChanges.hasOwnProperty(species.speciesId) ? pokemonFormChanges[species.speciesId] : []; + const toCurrentFormChanges = allFormChanges.filter(f => (f.formKey === formKey)); + if (toCurrentFormChanges.length > 0) { + dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(0); + } + } + // Unlock ability if (speciesStarterCosts.hasOwnProperty(species.speciesId)) { this.starterData[species.speciesId].abilityAttr |= pokemon.abilityIndex !== 1 || pokemon.species.ability2 diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index 1ba1b846224..6b8fdc41539 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -1207,7 +1207,7 @@ export default class PokedexUiHandler extends MessageUiHandler { shiny: false, female: props.female, variant: 0, - formIndex: 0, + formIndex: props.formIndex, }; return sanitizedProps; } @@ -1906,7 +1906,7 @@ export default class PokedexUiHandler extends MessageUiHandler { const dexEntry = globalScene.gameData.dexData[species.speciesId]; const caughtAttr = dexEntry.caughtAttr & globalScene.gameData.dexData[this.getStarterSpeciesId(species.speciesId)].caughtAttr & species.getFullUnlocksData(); - if (!caughtAttr) { + if (caughtAttr) { const props = this.getSanitizedProps(globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId))); if (shiny === undefined) { From 6857cd459cb2f5457cecadd35bfcef85f49741ae Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Tue, 25 Feb 2025 05:43:53 +0100 Subject: [PATCH 2/6] =?UTF-8?q?[UI/UX]=20Pok=C3=A9dex=20-=20Fix=20candy=20?= =?UTF-8?q?filter=20(#5377)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Hardcoding Pikachu to show 0 candies * Looking at starterId to determine order in sort by candy --- src/ui/pokedex-page-ui-handler.ts | 2 +- src/ui/pokedex-ui-handler.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index a086762bb57..ad05b265a50 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -2260,7 +2260,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.pokemonCaughtHatchedContainer.setY(25); this.pokemonCandyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0]))); this.pokemonCandyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1]))); - this.pokemonCandyCountText.setText(`x${globalScene.gameData.starterData[this.starterId].candyCount}`); + this.pokemonCandyCountText.setText(`x${species.speciesId === Species.PIKACHU ? 0 : globalScene.gameData.starterData[this.starterId].candyCount}`); this.pokemonCandyContainer.setVisible(true); if (pokemonPrevolutions.hasOwnProperty(species.speciesId)) { diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index 6b8fdc41539..ed0c3e7ee33 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -1534,8 +1534,8 @@ export default class PokedexUiHandler extends MessageUiHandler { case SortCriteria.COST: return (a.cost - b.cost) * -sort.dir; case SortCriteria.CANDY: - const candyCountA = globalScene.gameData.starterData[a.species.speciesId].candyCount; - const candyCountB = globalScene.gameData.starterData[b.species.speciesId].candyCount; + const candyCountA = globalScene.gameData.starterData[this.getStarterSpeciesId(a.species.speciesId)].candyCount; + const candyCountB = globalScene.gameData.starterData[this.getStarterSpeciesId(b.species.speciesId)].candyCount; return (candyCountA - candyCountB) * -sort.dir; case SortCriteria.IV: const avgIVsA = globalScene.gameData.dexData[a.species.speciesId].ivs.reduce((a, b) => a + b, 0) / globalScene.gameData.dexData[a.species.speciesId].ivs.length; From 4128d09a1d908634c2130b3c719200031c589e32 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Tue, 25 Feb 2025 05:44:13 +0100 Subject: [PATCH 3/6] [UI/UX] Pokedex - Page turning takes filters into account (#5372) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introducing list of indices of filtered mons to be passed to the Pokédex Page for scrolling * Update pokedex-page-ui-handler.ts --- src/ui/pokedex-page-ui-handler.ts | 36 ++++++++++++++++++++++--------- src/ui/pokedex-ui-handler.ts | 7 ++++-- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index ad05b265a50..ef7ee57cc17 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -16,7 +16,7 @@ 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 PokemonSpecies from "#app/data/pokemon-species"; -import { allSpecies, getPokemonSpeciesForm, normalForm } from "#app/data/pokemon-species"; +import { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, normalForm } from "#app/data/pokemon-species"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; import { starterPassiveAbilities } from "#app/data/balance/passives"; import { Type } from "#enums/type"; @@ -244,6 +244,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { private menuOptions: MenuOptions[]; protected scale: number = 0.1666666667; private menuDescriptions: string[]; + private filteredIndices: Species[] | null = null; private availableVariants: number; private unlockedVariants: boolean[]; @@ -560,6 +561,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.species = args[0]; this.formIndex = args[1] ?? 0; this.savedStarterAttributes = args[2] ?? { shiny:false, female:true, variant:0, form:0 }; + this.filteredIndices = args[3] ?? null; this.starterSetup(); } @@ -1447,7 +1449,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.savedStarterAttributes.form = newFormIndex; this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, newSpecies, newFormIndex, this.savedStarterAttributes); + ui.setMode(Mode.POKEDEX_PAGE, newSpecies, newFormIndex, this.savedStarterAttributes, this.filteredIndices); return true; }, onHover: () => this.showText(conditionText) @@ -1752,31 +1754,45 @@ export default class PokedexPageUiHandler extends MessageUiHandler { case Button.LEFT: this.blockInput = true; ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => { - const index = allSpecies.findIndex(species => species.speciesId === this.species.speciesId); - const newIndex = index <= 0 ? allSpecies.length - 1 : index - 1; - const newSpecies = allSpecies[newIndex]; + let newSpecies: PokemonSpecies; + if (this.filteredIndices) { + const index = this.filteredIndices.findIndex(id => id === this.species.speciesId); + const newIndex = index <= 0 ? this.filteredIndices.length - 1 : index - 1; + newSpecies = getPokemonSpecies(this.filteredIndices[newIndex]); + } else { + const index = allSpecies.findIndex(species => species.speciesId === this.species.speciesId); + const newIndex = index <= 0 ? allSpecies.length - 1 : index - 1; + newSpecies = allSpecies[newIndex]; + } const matchingForm = newSpecies?.forms.find(form => form.formKey === this.species?.forms[this.formIndex]?.formKey); const newFormIndex = matchingForm ? matchingForm.formIndex : 0; this.starterAttributes.form = newFormIndex; this.savedStarterAttributes.form = newFormIndex; this.moveInfoOverlay.clear(); this.clearText(); - ui.setModeForceTransition(Mode.POKEDEX_PAGE, newSpecies, newFormIndex, this.savedStarterAttributes); + ui.setModeForceTransition(Mode.POKEDEX_PAGE, newSpecies, newFormIndex, this.savedStarterAttributes, this.filteredIndices); }); this.blockInput = false; break; case Button.RIGHT: ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => { - const index = allSpecies.findIndex(species => species.speciesId === this.species.speciesId); - const newIndex = index >= allSpecies.length - 1 ? 0 : index + 1; - const newSpecies = allSpecies[newIndex]; + let newSpecies: PokemonSpecies; + if (this.filteredIndices) { + const index = this.filteredIndices.findIndex(id => id === this.species.speciesId); + const newIndex = index >= this.filteredIndices.length - 1 ? 0 : index + 1; + newSpecies = getPokemonSpecies(this.filteredIndices[newIndex]); + } else { + const index = allSpecies.findIndex(species => species.speciesId === this.species.speciesId); + const newIndex = index >= allSpecies.length - 1 ? 0 : index + 1; + newSpecies = allSpecies[newIndex]; + } const matchingForm = newSpecies?.forms.find(form => form.formKey === this.species?.forms[this.formIndex]?.formKey); const newFormIndex = matchingForm ? matchingForm.formIndex : 0; this.starterAttributes.form = newFormIndex; this.savedStarterAttributes.form = newFormIndex; this.moveInfoOverlay.clear(); this.clearText(); - ui.setModeForceTransition(Mode.POKEDEX_PAGE, newSpecies, newFormIndex, this.savedStarterAttributes); + ui.setModeForceTransition(Mode.POKEDEX_PAGE, newSpecies, newFormIndex, this.savedStarterAttributes, this.filteredIndices); }); break; } diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index ed0c3e7ee33..82208a5899d 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -215,6 +215,7 @@ export default class PokedexUiHandler extends MessageUiHandler { private showFormTrayIconElement: Phaser.GameObjects.Sprite; private showFormTrayLabel: Phaser.GameObjects.Text; private canShowFormTray: boolean; + private filteredIndices: Species[]; constructor() { super(Mode.POKEDEX); @@ -1037,7 +1038,7 @@ export default class PokedexUiHandler extends MessageUiHandler { } else if (this.showingTray) { if (button === Button.ACTION) { const formIndex = this.trayForms[this.trayCursor].formIndex; - ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, formIndex, { form: formIndex }); + ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, formIndex, { form: formIndex }, this.filteredIndices); success = true; } else { const numberOfForms = this.trayContainers.length; @@ -1084,7 +1085,7 @@ export default class PokedexUiHandler extends MessageUiHandler { } } else { if (button === Button.ACTION) { - ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, 0); + ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, 0, null, this.filteredIndices); success = true; } else { switch (button) { @@ -1551,6 +1552,8 @@ export default class PokedexUiHandler extends MessageUiHandler { return 0; }); + this.filteredIndices = this.filteredPokemonContainers.map(c => c.species.speciesId); + this.updateScroll(); }; From b95bedce7afeb10b4d7d9fbbab31b921571bcdbb Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Tue, 25 Feb 2025 05:45:45 +0100 Subject: [PATCH 4/6] [UI/UX] Pokedex - Ensure gender forms loop correctly with either button (#5387) --- src/ui/pokedex-page-ui-handler.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index ef7ee57cc17..99b25c3c383 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -244,6 +244,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { private menuOptions: MenuOptions[]; protected scale: number = 0.1666666667; private menuDescriptions: string[]; + private isFormGender: boolean; private filteredIndices: Species[] | null = null; private availableVariants: number; @@ -633,6 +634,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.tmMoves = speciesTmMoves[species.speciesId]?.filter(m => Array.isArray(m) ? (m[0] === formKey ? true : false ) : true) .map(m => Array.isArray(m) ? m[1] : m).sort((a, b) => allMoves[a].name > allMoves[b].name ? 1 : -1) ?? []; + this.isFormGender = formKey === "male" || formKey === "female"; + const passiveId = starterPassiveAbilities.hasOwnProperty(species.speciesId) ? species.speciesId : starterPassiveAbilities.hasOwnProperty(this.starterId) ? this.starterId : pokemonPrevolutions[this.starterId]; const passives = starterPassiveAbilities[passiveId]; @@ -1593,8 +1596,15 @@ export default class PokedexPageUiHandler extends MessageUiHandler { starterAttributes.form = newFormIndex; // store the selected form this.savedStarterAttributes.form = starterAttributes.form; this.formIndex = newFormIndex; + // Some forms are tied to the gender and should change accordingly + let newFemale = props.female; + if (this.isFormGender) { + newFemale = !props.female; + } + starterAttributes.female = newFemale; + this.savedStarterAttributes.female = starterAttributes.female; this.starterSetup(); - this.setSpeciesDetails(this.species, { formIndex: newFormIndex }); + this.setSpeciesDetails(this.species, { formIndex: newFormIndex, female: newFemale }); success = this.setCursor(this.cursor); } break; @@ -1602,7 +1612,16 @@ export default class PokedexPageUiHandler extends MessageUiHandler { if (this.canCycleGender) { starterAttributes.female = !props.female; this.savedStarterAttributes.female = starterAttributes.female; - this.setSpeciesDetails(this.species, { female: !props.female }); + let newFormIndex = this.formIndex; + // Some forms are tied to the gender and should change accordingly + if (this.isFormGender) { + newFormIndex = this.formIndex === 0 ? 1 : 0; + } + starterAttributes.form = newFormIndex; // store the selected form + this.savedStarterAttributes.form = starterAttributes.form; + this.formIndex = newFormIndex; + this.starterSetup(); + this.setSpeciesDetails(this.species, { female: !props.female, formIndex: newFormIndex }); success = true; } break; From d14f71d27a6da203fd30843bfb1e42c95be6a15e Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Tue, 25 Feb 2025 00:15:15 -0500 Subject: [PATCH 5/6] [Bug] Maintain Gimmighoul evo counter when fusing (#5411) --- src/field/pokemon.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 61815ec649c..4e3e53f994f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -4634,6 +4634,7 @@ export class PlayerPokemon extends Pokemon { newPokemon.fusionLuck = this.fusionLuck; newPokemon.fusionTeraType = this.fusionTeraType; newPokemon.usedTMs = this.usedTMs; + newPokemon.evoCounter = this.evoCounter; globalScene.getPlayerParty().push(newPokemon); newPokemon.evolve((!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution)), evoSpecies); @@ -4702,6 +4703,7 @@ export class PlayerPokemon extends Pokemon { this.fusionGender = pokemon.gender; this.fusionLuck = pokemon.luck; this.fusionCustomPokemonData = pokemon.customPokemonData; + this.evoCounter = Math.max(pokemon.evoCounter, this.evoCounter); if (pokemon.pauseEvolutions || this.pauseEvolutions) { this.pauseEvolutions = true; } From 88a5c9d41651dcb2efc3e83ca64240144a36347c Mon Sep 17 00:00:00 2001 From: Madmadness65 <59298170+Madmadness65@users.noreply.github.com> Date: Tue, 25 Feb 2025 01:46:07 -0600 Subject: [PATCH 6/6] [Ability] Implement Teraform Zero ability (#5359) * Partially implement Teraform Zero ability The functionality of the ability is all there, it just isn't limited to one use per Terastallization yet. * Add the once per battle condition This removes the partial from the ability. * Make attribute names more generic --------- Co-authored-by: damocleas --- src/data/ability.ts | 50 ++++++++++++++++++++++++++- src/phases/quiet-form-change-phase.ts | 4 ++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 131b7d0ff7a..8de0c68a8e7 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -266,6 +266,52 @@ export class PostTeraFormChangeStatChangeAbAttr extends AbAttr { } } +/** + * Clears a specified weather whenever this attribute is called. + */ +export class ClearWeatherAbAttr extends AbAttr { + private weather: WeatherType[]; + + /** + * @param weather {@linkcode WeatherType[]} - the weather to be removed + */ + constructor(weather: WeatherType[]) { + super(true); + + this.weather = weather; + } + + apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + if (!simulated) { + globalScene.arena.trySetWeather(WeatherType.NONE, true); + } + return true; + } +} + +/** + * Clears a specified terrain whenever this attribute is called. + */ +export class ClearTerrainAbAttr extends AbAttr { + private terrain: TerrainType[]; + + /** + * @param terrain {@linkcode TerrainType[]} - the terrain to be removed + */ + constructor(terrain: TerrainType[]) { + super(true); + + this.terrain = terrain; + } + + apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + if (!simulated) { + globalScene.arena.trySetTerrain(TerrainType.NONE, true, true); + } + return true; + } +} + type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: Move) => boolean; export class PreDefendAbAttr extends AbAttr { @@ -6993,9 +7039,11 @@ export function initAbilities() { .attr(UnswappableAbilityAbAttr) .ignorable(), new Ability(Abilities.TERAFORM_ZERO, 9) + .attr(ClearWeatherAbAttr, [ WeatherType.SUNNY, WeatherType.RAIN, WeatherType.SANDSTORM, WeatherType.HAIL, WeatherType.SNOW, WeatherType.FOG, WeatherType.HEAVY_RAIN, WeatherType.HARSH_SUN, WeatherType.STRONG_WINDS ]) + .attr(ClearTerrainAbAttr, [ TerrainType.MISTY, TerrainType.ELECTRIC, TerrainType.GRASSY, TerrainType.PSYCHIC ]) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .unimplemented(), + .condition(getOncePerBattleCondition(Abilities.TERAFORM_ZERO)), new Ability(Abilities.POISON_PUPPETEER, 9) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) diff --git a/src/phases/quiet-form-change-phase.ts b/src/phases/quiet-form-change-phase.ts index 6cd1129d318..81a39f53a76 100644 --- a/src/phases/quiet-form-change-phase.ts +++ b/src/phases/quiet-form-change-phase.ts @@ -11,7 +11,7 @@ import { getPokemonNameWithAffix } from "#app/messages"; import { BattlePhase } from "./battle-phase"; import { MovePhase } from "./move-phase"; import { PokemonHealPhase } from "./pokemon-heal-phase"; -import { applyAbAttrs, PostTeraFormChangeStatChangeAbAttr } from "#app/data/ability"; +import { applyAbAttrs, ClearTerrainAbAttr, ClearWeatherAbAttr, PostTeraFormChangeStatChangeAbAttr } from "#app/data/ability"; export class QuietFormChangePhase extends BattlePhase { protected pokemon: Pokemon; @@ -148,6 +148,8 @@ export class QuietFormChangePhase extends BattlePhase { } if (this.formChange.trigger instanceof SpeciesFormChangeTeraTrigger) { applyAbAttrs(PostTeraFormChangeStatChangeAbAttr, this.pokemon, null); + applyAbAttrs(ClearWeatherAbAttr, this.pokemon, null); + applyAbAttrs(ClearTerrainAbAttr, this.pokemon, null); } super.end();