Untangle circular deps from game data

This commit is contained in:
Sirz Benjie 2025-06-08 17:14:42 -05:00
parent c8e8b8b492
commit db5ce39a5c
No known key found for this signature in database
GPG Key ID: 4A524B4D196C759E
19 changed files with 140 additions and 114 deletions

View File

@ -1,3 +1,5 @@
import { SpeciesId } from "#enums/species-id";
/** The maximum size of the player's party */
export const PLAYER_PARTY_MAX_SIZE: number = 6;
@ -17,3 +19,38 @@ export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180
/** The raw percentage power boost for type boost items*/
export const TYPE_BOOST_ITEM_BOOST_PERCENT = 20;
/**
* The default species that a new player can choose from
*/
export const defaultStarterSpecies: SpeciesId[] = [
SpeciesId.BULBASAUR,
SpeciesId.CHARMANDER,
SpeciesId.SQUIRTLE,
SpeciesId.CHIKORITA,
SpeciesId.CYNDAQUIL,
SpeciesId.TOTODILE,
SpeciesId.TREECKO,
SpeciesId.TORCHIC,
SpeciesId.MUDKIP,
SpeciesId.TURTWIG,
SpeciesId.CHIMCHAR,
SpeciesId.PIPLUP,
SpeciesId.SNIVY,
SpeciesId.TEPIG,
SpeciesId.OSHAWOTT,
SpeciesId.CHESPIN,
SpeciesId.FENNEKIN,
SpeciesId.FROAKIE,
SpeciesId.ROWLET,
SpeciesId.LITTEN,
SpeciesId.POPPLIO,
SpeciesId.GROOKEY,
SpeciesId.SCORBUNNY,
SpeciesId.SOBBLE,
SpeciesId.SPRIGATITO,
SpeciesId.FUECOCO,
SpeciesId.QUAXLY,
];
export const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary

View File

@ -2,7 +2,7 @@ import { BooleanHolder, type NumberHolder, randSeedItem } from "#app/utils/commo
import { deepCopy } from "#app/utils/data";
import i18next from "i18next";
import type { DexAttrProps, GameData } from "#app/system/game-data";
import { defaultStarterSpecies } from "#app/system/game-data";
import { defaultStarterSpecies } from "#app/constants";
import type PokemonSpecies from "#app/data/pokemon-species";
import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters";

View File

@ -12,7 +12,7 @@ import { speciesStarterCosts } from "#app/data/balance/starters";
import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon";
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { AbilityAttr } from "#app/system/game-data";
import { AbilityAttr } from "#enums/ability-attr";
import PokemonData from "#app/system/pokemon-data";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { isNullOrUndefined, randSeedShuffle } from "#app/utils/common";

View File

@ -7,7 +7,8 @@ import i18next from "i18next";
import type { AnySound } from "#app/battle-scene";
import { globalScene } from "#app/global-scene";
import type { GameMode } from "#app/game-mode";
import { DexAttr, type StarterMoveset } from "#app/system/game-data";
import type { StarterMoveset } from "#app/system/game-data";
import { DexAttr } from "#enums/dex-attr";
import {
isNullOrUndefined,
capitalizeString,

11
src/enums/ability-attr.ts Normal file
View File

@ -0,0 +1,11 @@
/**
* Not to be confused with an Ability Attribute.
* This is an object literal storing the slot that an ability can occupy.
*/
export const AbilityAttr = Object.freeze({
ABILITY_1: 1,
ABILITY_2: 2,
ABILITY_HIDDEN: 4,
});
export type AbilityAttr = typeof AbilityAttr[keyof typeof AbilityAttr];

11
src/enums/dex-attr.ts Normal file
View File

@ -0,0 +1,11 @@
export const DexAttr = Object.freeze({
NON_SHINY: 1n,
SHINY: 2n,
MALE: 4n,
FEMALE: 8n,
DEFAULT_VARIANT: 16n,
VARIANT_2: 32n,
VARIANT_3: 64n,
DEFAULT_FORM: 128n,
});
export type DexAttr = typeof DexAttr[keyof typeof DexAttr];

View File

@ -177,7 +177,7 @@ import type { LevelMoves } from "#app/data/balance/pokemon-level-moves";
import { EVOLVE_MOVE, RELEARN_MOVE } from "#app/data/balance/pokemon-level-moves";
import { achvs } from "#app/system/achv";
import type { StarterDataEntry, StarterMoveset } from "#app/system/game-data";
import { DexAttr } from "#app/system/game-data";
import { DexAttr } from "#enums/dex-attr";
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
import { getNatureStatMultiplier } from "#app/data/nature";
import type { SpeciesFormChange } from "#app/data/pokemon-forms";

View File

@ -64,40 +64,12 @@ import { ArenaTrapTag } from "#app/data/arena-tag";
import { pokemonFormChanges } from "#app/data/pokemon-forms";
import type { PokemonType } from "#enums/pokemon-type";
import type { DexData, DexEntry } from "../@types/dex-data";
import { DexAttr } from "#enums/dex-attr";
import { AbilityAttr } from "#enums/ability-attr";
import { defaultStarterSpecies, saveKey } from "#app/constants";
import { encrypt, decrypt } from "#app/utils/data";
export const defaultStarterSpecies: SpeciesId[] = [
SpeciesId.BULBASAUR,
SpeciesId.CHARMANDER,
SpeciesId.SQUIRTLE,
SpeciesId.CHIKORITA,
SpeciesId.CYNDAQUIL,
SpeciesId.TOTODILE,
SpeciesId.TREECKO,
SpeciesId.TORCHIC,
SpeciesId.MUDKIP,
SpeciesId.TURTWIG,
SpeciesId.CHIMCHAR,
SpeciesId.PIPLUP,
SpeciesId.SNIVY,
SpeciesId.TEPIG,
SpeciesId.OSHAWOTT,
SpeciesId.CHESPIN,
SpeciesId.FENNEKIN,
SpeciesId.FROAKIE,
SpeciesId.ROWLET,
SpeciesId.LITTEN,
SpeciesId.POPPLIO,
SpeciesId.GROOKEY,
SpeciesId.SCORBUNNY,
SpeciesId.SOBBLE,
SpeciesId.SPRIGATITO,
SpeciesId.FUECOCO,
SpeciesId.QUAXLY,
];
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
export function getDataTypeKey(dataType: GameDataType, slotId = 0): string {
function getDataTypeKey(dataType: GameDataType, slotId = 0): string {
switch (dataType) {
case GameDataType.SYSTEM:
return "data";
@ -119,20 +91,6 @@ export function getDataTypeKey(dataType: GameDataType, slotId = 0): string {
}
}
export function encrypt(data: string, bypassLogin: boolean): string {
return (bypassLogin
? (data: string) => btoa(encodeURIComponent(data))
: (data: string) => AES.encrypt(data, saveKey))(data) as unknown as string; // TODO: is this correct?
}
export function decrypt(data: string, bypassLogin: boolean): string {
return (
bypassLogin
? (data: string) => decodeURIComponent(atob(data))
: (data: string) => AES.decrypt(data, saveKey).toString(enc.Utf8)
)(data);
}
// TODO: Move all these exported interfaces to @types
export interface SystemSaveData {
trainerId: number;
@ -216,10 +174,6 @@ export interface StarterAttributes {
tera?: PokemonType;
}
export interface StarterPreferences {
[key: number]: StarterAttributes;
}
export interface DexAttrProps {
shiny: boolean;
female: boolean;
@ -236,53 +190,6 @@ export interface RunEntry {
isFavorite: boolean;
}
export const DexAttr = {
NON_SHINY: 1n,
SHINY: 2n,
MALE: 4n,
FEMALE: 8n,
DEFAULT_VARIANT: 16n,
VARIANT_2: 32n,
VARIANT_3: 64n,
DEFAULT_FORM: 128n,
};
export const AbilityAttr = {
ABILITY_1: 1,
ABILITY_2: 2,
ABILITY_HIDDEN: 4,
};
// the latest data saved/loaded for the Starter Preferences. Required to reduce read/writes. Initialize as "{}", since this is the default value and no data needs to be stored if present.
// if they ever add private static variables, move this into StarterPrefs
const StarterPrefers_DEFAULT: string = "{}";
let StarterPrefers_private_latest: string = StarterPrefers_DEFAULT;
// called on starter selection show once
export function loadStarterPreferences(): StarterPreferences {
return JSON.parse(
(StarterPrefers_private_latest =
localStorage.getItem(`starterPrefs_${loggedInUser?.username}`) || StarterPrefers_DEFAULT),
);
}
// called on starter selection clear, always
export function saveStarterPreferences(prefs: StarterPreferences): void {
const pStr: string = JSON.stringify(prefs);
if (pStr !== StarterPrefers_private_latest) {
// something changed, store the update
localStorage.setItem(`starterPrefs_${loggedInUser?.username}`, pStr);
// update the latest prefs
StarterPrefers_private_latest = pStr;
}
}
// This is its own class as StarterPreferences...
// - don't need to be loaded on startup
// - isn't stored with other data
// - don't require to be encrypted
// - shouldn't require calls outside of the starter selection
export class StarterPrefs {}
export interface StarterDataEntry {
moveset: StarterMoveset | StarterFormMoveData | null;
eggMoves: number;

View File

@ -1,6 +1,8 @@
import { SettingKeys } from "#app/system/settings/settings";
import type { SystemSaveData, SessionSaveData } from "#app/system/game-data";
import { AbilityAttr, defaultStarterSpecies, DexAttr } from "#app/system/game-data";
import { defaultStarterSpecies } from "#app/constants";
import { AbilityAttr } from "#enums/ability-attr";
import { DexAttr } from "#enums/dex-attr";
import { allSpecies } from "#app/data/pokemon-species";
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { isNullOrUndefined } from "#app/utils/common";

View File

@ -2,7 +2,8 @@ import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator";
import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator";
import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { globalScene } from "#app/global-scene";
import { DexAttr, type SessionSaveData, type SystemSaveData } from "#app/system/game-data";
import type { SessionSaveData, SystemSaveData } from "#app/system/game-data";
import { DexAttr } from "#enums/dex-attr";
import { isNullOrUndefined } from "#app/utils/common";
/**

View File

@ -1,6 +1,7 @@
import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator";
import { getPokemonSpecies } from "#app/data/pokemon-species";
import { DexAttr, type SystemSaveData } from "#app/system/game-data";
import type { SystemSaveData } from "#app/system/game-data";
import { DexAttr } from "#enums/dex-attr";
import { SpeciesId } from "#enums/species-id";
/**

View File

@ -5,7 +5,7 @@ import UiHandler from "#app/ui/ui-handler";
import { addWindow } from "#app/ui/ui-theme";
import { getPlayTimeString, formatFancyLargeNumber, toReadableString } from "#app/utils/common";
import type { GameData } from "#app/system/game-data";
import { DexAttr } from "#app/system/game-data";
import { DexAttr } from "#enums/dex-attr";
import { speciesStarterCosts } from "#app/data/balance/starters";
import { Button } from "#enums/buttons";
import i18next from "i18next";

View File

@ -1,7 +1,7 @@
import type { EggHatchData } from "#app/data/egg-hatch-data";
import { Gender } from "#app/data/gender";
import { getVariantTint } from "#app/sprites/variant";
import { DexAttr } from "#app/system/game-data";
import { DexAttr } from "#enums/dex-attr";
import { globalScene } from "#app/global-scene";
import type PokemonSpecies from "#app/data/pokemon-species";
import type PokemonIconAnimHandler from "./pokemon-icon-anim-handler";

View File

@ -22,7 +22,8 @@ import { starterPassiveAbilities } from "#app/data/balance/passives";
import { PokemonType } from "#enums/pokemon-type";
import type { StarterAttributes } from "#app/system/game-data";
import type { DexEntry } from "#app/@types/dex-data";
import { AbilityAttr, DexAttr } from "#app/system/game-data";
import { AbilityAttr } from "#enums/ability-attr";
import { DexAttr } from "#enums/dex-attr";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import MessageUiHandler from "#app/ui/message-ui-handler";
import { StatsContainer } from "#app/ui/stats-container";

View File

@ -11,9 +11,12 @@ import { allSpecies, getPokemonSpeciesForm, getPokerusStarters, normalForm } fro
import { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
import { catchableSpecies } from "#app/data/balance/biomes";
import { PokemonType } from "#enums/pokemon-type";
import type { DexAttrProps, StarterAttributes, StarterPreferences } from "#app/system/game-data";
import type { DexAttrProps, StarterAttributes } from "#app/system/game-data";
import type { StarterPreferences } from "#app/utils/data";
import type { DexEntry } from "#app/@types/dex-data";
import { AbilityAttr, DexAttr, loadStarterPreferences } from "#app/system/game-data";
import { loadStarterPreferences } from "#app/utils/data";
import { AbilityAttr } from "#enums/ability-attr";
import { DexAttr } from "#enums/dex-attr";
import MessageUiHandler from "#app/ui/message-ui-handler";
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler";
import { TextStyle, addTextObject } from "#app/ui/text";

View File

@ -8,7 +8,7 @@ import type Pokemon from "../field/pokemon";
import i18next from "i18next";
import type { StarterDataEntry } from "../system/game-data";
import type { DexEntry } from "#app/@types/dex-data";
import { DexAttr } from "../system/game-data";
import { DexAttr } from "#enums/dex-attr";
import { fixedInt, getShinyDescriptor } from "#app/utils/common";
import ConfirmUiHandler from "./confirm-ui-handler";
import { StatsContainer } from "./stats-container";

View File

@ -23,9 +23,12 @@ import { allSpecies, getPokemonSpeciesForm, getPokerusStarters } from "#app/data
import { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
import { PokemonType } from "#enums/pokemon-type";
import { GameModes } from "#enums/game-modes";
import type { DexAttrProps, StarterMoveset, StarterAttributes, StarterPreferences } from "#app/system/game-data";
import type { DexAttrProps, StarterMoveset, StarterAttributes } from "#app/system/game-data";
import type { StarterPreferences } from "#app/utils/data";
import type { DexEntry } from "#app/@types/dex-data";
import { AbilityAttr, DexAttr, loadStarterPreferences, saveStarterPreferences } from "#app/system/game-data";
import { loadStarterPreferences, saveStarterPreferences } from "#app/utils/data";
import { AbilityAttr } from "#enums/ability-attr";
import { DexAttr } from "#enums/dex-attr";
import { Tutorial, handleTutorial } from "#app/tutorial";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import MessageUiHandler from "#app/ui/message-ui-handler";

View File

@ -1,3 +1,8 @@
import { loggedInUser } from "#app/account";
import type { StarterAttributes } from "#app/system/game-data";
import { AES, enc } from "crypto-js";
import { saveKey } from "#app/constants";
/**
* Perform a deep copy of an object.
* @param values - The object to be deep copied.
@ -38,3 +43,45 @@ export function deepMergeSpriteData(dest: object, source: object) {
}
}
}
export function encrypt(data: string, bypassLogin: boolean): string {
return (bypassLogin
? (data: string) => btoa(encodeURIComponent(data))
: (data: string) => AES.encrypt(data, saveKey))(data) as unknown as string; // TODO: is this correct?
}
export function decrypt(data: string, bypassLogin: boolean): string {
return (
bypassLogin
? (data: string) => decodeURIComponent(atob(data))
: (data: string) => AES.decrypt(data, saveKey).toString(enc.Utf8)
)(data);
}
// the latest data saved/loaded for the Starter Preferences. Required to reduce read/writes. Initialize as "{}", since this is the default value and no data needs to be stored if present.
// if they ever add private static variables, move this into StarterPrefs
const StarterPrefers_DEFAULT: string = "{}";
let StarterPrefers_private_latest: string = StarterPrefers_DEFAULT;
export interface StarterPreferences {
[key: number]: StarterAttributes;
}
// called on starter selection show once
export function loadStarterPreferences(): StarterPreferences {
return JSON.parse(
(StarterPrefers_private_latest =
localStorage.getItem(`starterPrefs_${loggedInUser?.username}`) || StarterPrefers_DEFAULT),
);
}
// called on starter selection clear, always
export function saveStarterPreferences(prefs: StarterPreferences): void {
const pStr: string = JSON.stringify(prefs);
if (pStr !== StarterPrefers_private_latest) {
// something changed, store the update
localStorage.setItem(`starterPrefs_${loggedInUser?.username}`, pStr);
// update the latest prefs
StarterPrefers_private_latest = pStr;
}
}

View File

@ -1,7 +1,8 @@
import type { ArenaTrapTag } from "#app/data/arena-tag";
import { ArenaTagSide } from "#enums/arena-tag-side";
import type { SessionSaveData } from "#app/system/game-data";
import { decrypt, encrypt, GameData } from "#app/system/game-data";
import { GameData } from "#app/system/game-data";
import { decrypt, encrypt } from "#app/utils/data";
import { AbilityId } from "#enums/ability-id";
import { ArenaTagType } from "#enums/arena-tag-type";
import { MoveId } from "#enums/move-id";