This commit is contained in:
AJ Fontaine 2025-02-25 09:11:05 -05:00
commit a683aa5bc9
7 changed files with 135 additions and 28 deletions

View File

@ -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)

View File

@ -2848,7 +2848,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
stabMultiplier.value += 0.5;
}
if (source.isTerastallized && source.teraType === Type.STELLAR && (!source.stellarTypesBoosted.includes(moveType) || source.hasSpecies(Species.TERAPAGOS))) {
if (source.isTerastallized && source.getTeraType() === Type.STELLAR && (!source.stellarTypesBoosted.includes(moveType) || source.hasSpecies(Species.TERAPAGOS))) {
if (matchesSourceType) {
stabMultiplier.value += 0.5;
} else {
@ -4632,8 +4632,9 @@ export class PlayerPokemon extends Pokemon {
newPokemon.fusionVariant = this.fusionVariant;
newPokemon.fusionGender = this.fusionGender;
newPokemon.fusionLuck = this.fusionLuck;
newPokemon.fusionTeraType = this.teraType;
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;
}

View File

@ -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();

View File

@ -20,9 +20,7 @@ export class TeraPhase extends BattlePhase {
start() {
super.start();
console.log(this.pokemon.name, "terastallized to", Type[this.pokemon.teraType].toString());
globalScene.queueMessage(i18next.t("battle:pokemonTerastallized", { pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), type: i18next.t(`pokemonInfo:Type.${Type[this.pokemon.teraType]}`) }));
globalScene.queueMessage(i18next.t("battle:pokemonTerastallized", { pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), type: i18next.t(`pokemonInfo:Type.${Type[this.pokemon.getTeraType()]}`) }));
new CommonBattleAnim(CommonAnim.TERASTALLIZE, this.pokemon).play(false, () => {
this.end();
});
@ -41,7 +39,7 @@ export class TeraPhase extends BattlePhase {
if (this.pokemon.isPlayer()) {
globalScene.validateAchv(achvs.TERASTALLIZE);
if (this.pokemon.teraType === Type.STELLAR) {
if (this.pokemon.getTeraType() === Type.STELLAR) {
globalScene.validateAchv(achvs.STELLAR_TERASTALLIZE);
}
}

View File

@ -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

View File

@ -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,8 @@ 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;
private unlockedVariants: boolean[];
@ -560,6 +562,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();
}
@ -631,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];
@ -1447,7 +1452,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)
@ -1591,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;
@ -1600,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;
@ -1752,31 +1773,45 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
case Button.LEFT:
this.blockInput = true;
ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => {
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;
const newSpecies = allSpecies[newIndex];
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(() => {
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;
const newSpecies = allSpecies[newIndex];
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;
}
@ -2260,7 +2295,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)) {

View File

@ -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) {
@ -1207,7 +1208,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
shiny: false,
female: props.female,
variant: 0,
formIndex: 0,
formIndex: props.formIndex,
};
return sanitizedProps;
}
@ -1534,8 +1535,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;
@ -1551,6 +1552,8 @@ export default class PokedexUiHandler extends MessageUiHandler {
return 0;
});
this.filteredIndices = this.filteredPokemonContainers.map(c => c.species.speciesId);
this.updateScroll();
};
@ -1906,7 +1909,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) {