Introduced getSpeciesData function

This commit is contained in:
Wlowscha 2025-08-16 19:14:40 +02:00
parent 46c78a0540
commit 1ddcca7da5
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
5 changed files with 117 additions and 17 deletions

View File

@ -3,9 +3,11 @@ import { getRandomTrainerFunc } from "#app/battle";
import { defaultStarterSpecies } from "#app/constants";
import { speciesStarterCosts } from "#balance/starters";
import type { PokemonSpecies } from "#data/pokemon-species";
import { AbilityAttr } from "#enums/ability-attr";
import { BattleType } from "#enums/battle-type";
import { Challenges } from "#enums/challenges";
import { TypeColor, TypeShadow } from "#enums/color";
import { DexAttr } from "#enums/dex-attr";
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
import { ModifierTier } from "#enums/modifier-tier";
import { MoveId } from "#enums/move-id";
@ -19,8 +21,9 @@ import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
import { Trainer } from "#field/trainer";
import type { ModifierTypeOption } from "#modifiers/modifier-type";
import { PokemonMove } from "#moves/pokemon-move";
import type { DexAttrProps, GameData } from "#system/game-data";
import type { DexAttrProps, GameData, StarterDataEntry } from "#system/game-data";
import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data";
import type { DexEntry } from "#types/dex-data";
import { type BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common";
import { deepCopy } from "#utils/data";
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
@ -237,6 +240,15 @@ export abstract class Challenge {
return false;
}
/**
* An apply function for STARTER_SELECT_MODIFY challenges. Derived classes should alter this.
* @param _pokemon {@link Pokemon} The starter pokemon to modify.
* @returns {@link boolean} Whether this function did anything.
*/
applyStarterSelectModify(_dexEntry: DexEntry, _starterDataEntry: StarterDataEntry): boolean {
return false;
}
/**
* An apply function for STARTER_MODIFY challenges. Derived classes should alter this.
* @param _pokemon {@link Pokemon} The starter pokemon to modify.
@ -797,6 +809,53 @@ export class FreshStartChallenge extends Challenge {
return true;
}
applyStarterSelectModify(dexEntry: DexEntry, starterDataEntry: StarterDataEntry): boolean {
// Remove all egg moves
starterDataEntry.eggMoves = 0;
console.log("I AM APPLYING, ", starterDataEntry.eggMoves);
// Remove hidden and passive ability
const defaultAbilities = AbilityAttr.ABILITY_1 | AbilityAttr.ABILITY_2;
starterDataEntry.abilityAttr &= defaultAbilities;
starterDataEntry.passiveAttr = 0;
// Remove cost reduction
starterDataEntry.valueReduction = 0;
// Remove natures except for the default ones
const neutralNaturesAttr =
(1 << (Nature.HARDY + 1)) |
(1 << (Nature.DOCILE + 1)) |
(1 << (Nature.SERIOUS + 1)) |
(1 << (Nature.BASHFUL + 1)) |
(1 << (Nature.QUIRKY + 1));
dexEntry.natureAttr &= neutralNaturesAttr;
// Set all ivs to 15
dexEntry.ivs = [15, 15, 15, 15, 15, 15];
// Removes shiny, variants, and any unlocked forms
const defaultDexEntry = DexAttr.NON_SHINY | DexAttr.MALE | DexAttr.FEMALE | DexAttr.DEFAULT_FORM;
dexEntry.caughtAttr &= defaultDexEntry;
/**
let validMoves = pokemon.species
.getLevelMoves()
.filter(m => isBetween(m[0], 1, 5))
.map(lm => lm[1]);
// Filter egg moves out of the moveset
pokemon.moveset = pokemon.moveset.filter(pm => validMoves.includes(pm.moveId));
if (pokemon.moveset.length < 4) {
// If there's empty slots fill with remaining valid moves
const existingMoveIds = pokemon.moveset.map(pm => pm.moveId);
validMoves = validMoves.filter(m => !existingMoveIds.includes(m));
pokemon.moveset = pokemon.moveset.concat(validMoves.map(m => new PokemonMove(m))).slice(0, 4);
}
pokemon.teraType = pokemon.species.type1; // Always primary tera type
*/
return true;
}
applyStarterModify(pokemon: Pokemon): boolean {
pokemon.abilityIndex = pokemon.abilityIndex % 2; // Always base ability, if you set it to hidden it wraps to first ability
pokemon.passive = false; // Passive isn't unlocked

View File

@ -18,6 +18,11 @@ export enum ChallengeType {
* @see {@link Challenge.applyStarterPointCost}
*/
STARTER_COST,
/**
* Challenges which modify the starter data in starter select
* @see {@link Challenge.applyStarterSelectModify}
*/
STARTER_SELECT_MODIFY,
/**
* Challenges which modify your starters in some way
* @see {@link Challenge.applyStarterModify}

View File

@ -64,7 +64,7 @@ import { trainerConfigs } from "#trainers/trainer-config";
import type { DexData, DexEntry } from "#types/dex-data";
import { RUN_HISTORY_LIMIT } from "#ui/run-history-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { executeIf, fixedInt, isLocal, NumberHolder, randInt, randSeedItem } from "#utils/common";
import { executeIf, fixedInt, isLocal, isNullOrUndefined, NumberHolder, randInt, randSeedItem } from "#utils/common";
import { decrypt, encrypt } from "#utils/data";
import { getEnumKeys } from "#utils/enums";
import { getPokemonSpecies } from "#utils/pokemon-utils";
@ -2103,8 +2103,10 @@ export class GameData {
};
}
getStarterSpeciesDefaultAbilityIndex(species: PokemonSpecies): number {
const abilityAttr = this.starterData[species.speciesId].abilityAttr;
getStarterSpeciesDefaultAbilityIndex(species: PokemonSpecies, abilityAttr?: number): number {
if (isNullOrUndefined(abilityAttr)) {
abilityAttr = this.starterData[species.speciesId].abilityAttr;
}
return abilityAttr & AbilityAttr.ABILITY_1 ? 0 : !species.ability2 || abilityAttr & AbilityAttr.ABILITY_2 ? 1 : 2;
}

View File

@ -44,7 +44,7 @@ import { BattleSceneEventType } from "#events/battle-scene";
import type { Variant } from "#sprites/variant";
import { getVariantIcon, getVariantTint } from "#sprites/variant";
import { achvs } from "#system/achv";
import type { DexAttrProps, StarterAttributes, StarterMoveset } from "#system/game-data";
import type { DexAttrProps, StarterAttributes, StarterDataEntry, StarterMoveset } from "#system/game-data";
import { RibbonData } from "#system/ribbons/ribbon-data";
import { SettingKeyboard } from "#system/settings-keyboard";
import type { DexEntry } from "#types/dex-data";
@ -1141,7 +1141,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.allSpecies.forEach((species, s) => {
const icon = this.starterContainers[s].icon;
const dexEntry = globalScene.gameData.dexData[species.speciesId];
const { dexEntry } = this.getSpeciesData(species.speciesId);
// Initialize the StarterAttributes for this species
this.starterPreferences[species.speciesId] = this.initStarterPrefs(species);
@ -1714,7 +1714,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
this.isPartyValid(),
);
const isCaught = globalScene.gameData.dexData[species.speciesId].caughtAttr;
const { dexEntry } = this.getSpeciesData(species.speciesId);
const isCaught = dexEntry.caughtAttr;
return (
!isDupe && isValidForChallenge && currentPartyValue + starterCost <= this.getValueLimit() && isCaught
);
@ -2994,8 +2995,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
container.cost = globalScene.gameData.getSpeciesStarterValue(container.species.speciesId);
// First, ensure you have the caught attributes for the species else default to bigint 0
const caughtAttr = globalScene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0);
const starterData = globalScene.gameData.starterData[container.species.speciesId];
const { dexEntry, starterDataEntry } = this.getSpeciesData(container.species.speciesId);
const caughtAttr = dexEntry?.caughtAttr || BigInt(0);
const starterData = starterDataEntry;
const isStarterProgressable = speciesEggMoves.hasOwnProperty(container.species.speciesId);
// Gen filter
@ -3393,7 +3395,11 @@ export class StarterSelectUiHandler extends MessageUiHandler {
}
setSpecies(species: PokemonSpecies | null) {
this.speciesStarterDexEntry = species ? globalScene.gameData.dexData[species.speciesId] : null;
this.speciesStarterDexEntry = null;
if (species) {
const { dexEntry } = this.getSpeciesData(species.speciesId);
this.speciesStarterDexEntry = dexEntry;
}
this.dexAttrCursor = species ? this.getCurrentDexProps(species.speciesId) : 0n;
this.abilityCursor = species ? globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species) : 0;
this.natureCursor = species ? globalScene.gameData.getSpeciesDefaultNature(species) : 0;
@ -3663,6 +3669,17 @@ export class StarterSelectUiHandler extends MessageUiHandler {
}
}
getSpeciesData(speciesId: SpeciesId): { dexEntry: DexEntry; starterDataEntry: StarterDataEntry } {
const dexEntry = globalScene.gameData.dexData[speciesId];
const starterDataEntry = globalScene.gameData.starterData[speciesId];
const copiedDexEntry = { ...dexEntry };
const copiedStarterDataEntry = { ...starterDataEntry };
applyChallenges(ChallengeType.STARTER_SELECT_MODIFY, copiedDexEntry, copiedStarterDataEntry);
return { dexEntry: { ...copiedDexEntry }, starterDataEntry: { ...copiedStarterDataEntry } };
}
setSpeciesDetails(species: PokemonSpecies, options: SpeciesDetails = {}): void {
let { shiny, formIndex, female, variant, abilityIndex, natureIndex, teraType } = options;
const forSeen: boolean = options.forSeen ?? false;
@ -3740,12 +3757,12 @@ export class StarterSelectUiHandler extends MessageUiHandler {
this.speciesStarterMoves = [];
if (species) {
const dexEntry = globalScene.gameData.dexData[species.speciesId];
const abilityAttr = globalScene.gameData.starterData[species.speciesId].abilityAttr;
const { dexEntry, starterDataEntry } = this.getSpeciesData(species.speciesId);
const caughtAttr = dexEntry.caughtAttr || BigInt(0);
const abilityAttr = starterDataEntry.abilityAttr;
console.log("I HAVE APPLIED, ", starterDataEntry.eggMoves);
const caughtAttr = globalScene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0);
if (!dexEntry.caughtAttr) {
if (!caughtAttr) {
const props = globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId));
const defaultAbilityIndex = globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
const defaultNature = globalScene.gameData.getSpeciesDefaultNature(species);
@ -4382,7 +4399,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
*/
getCurrentDexProps(speciesId: number): bigint {
let props = 0n;
const caughtAttr = globalScene.gameData.dexData[speciesId].caughtAttr;
const { dexEntry } = this.getSpeciesData(speciesId);
const caughtAttr = dexEntry.caughtAttr;
/* this checks the gender of the pokemon; this works by checking a) that the starter preferences for the species exist, and if so, is it female. If so, it'll add DexAttr.FEMALE to our temp props
* It then checks b) if the caughtAttr for the pokemon is female and NOT male - this means that the ONLY gender we've gotten is female, and we need to add DexAttr.FEMALE to our temp props

View File

@ -10,7 +10,8 @@ import type { MoveSourceType } from "#enums/move-source-type";
import type { SpeciesId } from "#enums/species-id";
import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
import type { ModifierTypeOption } from "#modifiers/modifier-type";
import type { DexAttrProps } from "#system/game-data";
import type { DexAttrProps, StarterDataEntry } from "#system/game-data";
import type { DexEntry } from "#types/dex-data";
import { BooleanHolder, type NumberHolder } from "./common";
import { getPokemonSpecies } from "./pokemon-utils";
@ -47,6 +48,18 @@ export function applyChallenges(
species: SpeciesId,
cost: NumberHolder,
): boolean;
/**
* Apply all challenges that modify selectable starter data.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_SELECT_MODIFY
* @param dexEntry {@link DexEntry} The pokedex data associated to the pokemon.
* @param starterDataEntry {@link StarterDataEntry} The starter data associated to the pokemon.
* @returns True if any challenge was successfully applied.
*/
export function applyChallenges(
challengeType: ChallengeType.STARTER_SELECT_MODIFY,
dexEntry: DexEntry,
starterDataEntry: StarterDataEntry,
): boolean;
/**
* Apply all challenges that modify a starter after selection.
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_MODIFY
@ -269,6 +282,9 @@ export function applyChallenges(challengeType: ChallengeType, ...args: any[]): b
case ChallengeType.STARTER_COST:
ret ||= c.applyStarterCost(args[0], args[1]);
break;
case ChallengeType.STARTER_SELECT_MODIFY:
ret ||= c.applyStarterSelectModify(args[0], args[1]);
break;
case ChallengeType.STARTER_MODIFY:
ret ||= c.applyStarterModify(args[0]);
break;