diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 271cde1aaa9..80eb6ec9729 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -27,13 +27,7 @@ import { UiInputs } from "#app/ui-inputs"; import { biomeDepths, getBiomeName } from "#balance/biomes"; import { pokemonPrevolutions } from "#balance/pokemon-evolutions"; import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#balance/starters"; -import { - initCommonAnims, - initMoveAnim, - loadCommonAnimAssets, - loadMoveAnimAssets, - populateAnims, -} from "#data/battle-anims"; +import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets } from "#data/battle-anims"; import { allAbilities, allMoves, allSpecies, modifierTypes } from "#data/data-lists"; import { battleSpecDialogue } from "#data/dialogue"; import type { SpeciesFormChangeTrigger } from "#data/form-change-triggers"; @@ -387,7 +381,6 @@ export class BattleScene extends SceneBase { const defaultMoves = [MoveId.TACKLE, MoveId.TAIL_WHIP, MoveId.FOCUS_ENERGY, MoveId.STRUGGLE]; await Promise.all([ - populateAnims(), this.initVariantData(), initCommonAnims().then(() => loadCommonAnimAssets(true)), Promise.all(defaultMoves.map(m => initMoveAnim(m))).then(() => loadMoveAnimAssets(defaultMoves, true)), diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index 55a3cc4e916..aa4951f3263 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -404,22 +404,18 @@ export const chargeAnims = new Map(); export const encounterAnims = new Map(); -export function initCommonAnims(): Promise { - return new Promise(resolve => { - const commonAnimNames = getEnumKeys(CommonAnim); - const commonAnimIds = getEnumValues(CommonAnim); - const commonAnimFetches: Promise>[] = []; - for (let ca = 0; ca < commonAnimIds.length; ca++) { - const commonAnimId = commonAnimIds[ca]; - commonAnimFetches.push( - globalScene - .cachedFetch(`./battle-anims/common-${toKebabCase(commonAnimNames[ca])}.json`) - .then(response => response.json()) - .then(cas => commonAnims.set(commonAnimId, new AnimConfig(cas))), - ); - } - Promise.allSettled(commonAnimFetches).then(() => resolve()); - }); +export async function initCommonAnims(): Promise { + const commonAnimFetches: Promise>[] = []; + for (const commonAnimName of getEnumKeys(CommonAnim)) { + const commonAnimId = CommonAnim[commonAnimName]; + commonAnimFetches.push( + globalScene + .cachedFetch(`./battle-anims/common-${toKebabCase(commonAnimName)}.json`) + .then(response => response.json()) + .then(cas => commonAnims.set(commonAnimId, new AnimConfig(cas))), + ); + } + await Promise.allSettled(commonAnimFetches); } export function initMoveAnim(move: MoveId): Promise { @@ -1396,279 +1392,3 @@ export class EncounterBattleAnim extends BattleAnim { return this.oppAnim; } } - -export async function populateAnims() { - const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase()); - const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/_/g, "")); - const commonAnimIds = getEnumValues(CommonAnim); - const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase()); - const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/_/g, " ")); - const chargeAnimIds = getEnumValues(ChargeAnim); - const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/; - const moveNameToId = {}; - // Exclude MoveId.NONE; - for (const move of getEnumValues(MoveId).slice(1)) { - // KARATE_CHOP => KARATECHOP - const moveName = MoveId[move].toUpperCase().replace(/_/g, ""); - moveNameToId[moveName] = move; - } - - const seNames: string[] = []; //(await fs.readdir('./public/audio/se/battle_anims/')).map(se => se.toString()); - - const animsData: any[] = []; //battleAnimRawData.split('!ruby/array:PBAnimation').slice(1); // TODO: add a proper type - for (let a = 0; a < animsData.length; a++) { - const fields = animsData[a].split("@").slice(1); - - const nameField = fields.find(f => f.startsWith("name: ")); - - let isOppMove: boolean | undefined; - let commonAnimId: CommonAnim | undefined; - let chargeAnimId: ChargeAnim | undefined; - if (!nameField.startsWith("name: Move:") && !(isOppMove = nameField.startsWith("name: OppMove:"))) { - const nameMatch = commonNamePattern.exec(nameField)!; // TODO: is this bang correct? - const name = nameMatch[2].toLowerCase(); - if (commonAnimMatchNames.indexOf(name) > -1) { - commonAnimId = commonAnimIds[commonAnimMatchNames.indexOf(name)]; - } else if (chargeAnimMatchNames.indexOf(name) > -1) { - isOppMove = nameField.startsWith("name: Opp "); - chargeAnimId = chargeAnimIds[chargeAnimMatchNames.indexOf(name)]; - } - } - const nameIndex = nameField.indexOf(":", 5) + 1; - const animName = nameField.slice(nameIndex, nameField.indexOf("\n", nameIndex)); - if (!moveNameToId.hasOwnProperty(animName) && !commonAnimId && !chargeAnimId) { - continue; - } - const anim = commonAnimId || chargeAnimId ? new AnimConfig() : new AnimConfig(); - if (anim instanceof AnimConfig) { - (anim as AnimConfig).id = moveNameToId[animName]; - } - if (commonAnimId) { - commonAnims.set(commonAnimId, anim); - } else if (chargeAnimId) { - chargeAnims.set(chargeAnimId, !isOppMove ? anim : [chargeAnims.get(chargeAnimId) as AnimConfig, anim]); - } else { - moveAnims.set( - moveNameToId[animName], - !isOppMove ? (anim as AnimConfig) : [moveAnims.get(moveNameToId[animName]) as AnimConfig, anim as AnimConfig], - ); - } - for (let f = 0; f < fields.length; f++) { - const field = fields[f]; - const fieldName = field.slice(0, field.indexOf(":")); - const fieldData = field.slice(fieldName.length + 1, field.lastIndexOf("\n")).trim(); - switch (fieldName) { - case "array": { - const framesData = fieldData.split(" - - - ").slice(1); - for (let fd = 0; fd < framesData.length; fd++) { - anim.frames.push([]); - const frameData = framesData[fd]; - const focusFramesData = frameData.split(" - - "); - for (let tf = 0; tf < focusFramesData.length; tf++) { - const values = focusFramesData[tf].replace(/ {6}- /g, "").split("\n"); - const targetFrame = new AnimFrame( - Number.parseFloat(values[0]), - Number.parseFloat(values[1]), - Number.parseFloat(values[2]), - Number.parseFloat(values[11]), - Number.parseFloat(values[3]), - Number.parseInt(values[4]) === 1, - Number.parseInt(values[6]) === 1, - Number.parseInt(values[5]), - Number.parseInt(values[7]), - Number.parseInt(values[8]), - Number.parseInt(values[12]), - Number.parseInt(values[13]), - Number.parseInt(values[14]), - Number.parseInt(values[15]), - Number.parseInt(values[16]), - Number.parseInt(values[17]), - Number.parseInt(values[18]), - Number.parseInt(values[19]), - Number.parseInt(values[21]), - Number.parseInt(values[22]), - Number.parseInt(values[23]), - Number.parseInt(values[24]), - Number.parseInt(values[20]) === 1, - Number.parseInt(values[25]), - Number.parseInt(values[26]) as AnimFocus, - ); - anim.frames[fd].push(targetFrame); - } - } - break; - } - case "graphic": { - const graphic = fieldData !== "''" ? fieldData : ""; - anim.graphic = graphic.indexOf(".") > -1 ? graphic.slice(0, fieldData.indexOf(".")) : graphic; - break; - } - case "timing": { - const timingEntries = fieldData.split("- !ruby/object:PBAnimTiming ").slice(1); - for (let t = 0; t < timingEntries.length; t++) { - const timingData = timingEntries[t] - .replace(/\n/g, " ") - .replace(/[ ]{2,}/g, " ") - .replace(/[a-z]+: ! '', /gi, "") - .replace(/name: (.*?),/, 'name: "$1",') - .replace( - /flashColor: !ruby\/object:Color { alpha: ([\d.]+), blue: ([\d.]+), green: ([\d.]+), red: ([\d.]+)}/, - "flashRed: $4, flashGreen: $3, flashBlue: $2, flashAlpha: $1", - ); - const frameIndex = Number.parseInt(/frame: (\d+)/.exec(timingData)![1]); // TODO: is the bang correct? - let resourceName = /name: "(.*?)"/.exec(timingData)![1].replace("''", ""); // TODO: is the bang correct? - const timingType = Number.parseInt(/timingType: (\d)/.exec(timingData)![1]); // TODO: is the bang correct? - let timedEvent: AnimTimedEvent | undefined; - switch (timingType) { - case 0: - if (resourceName && resourceName.indexOf(".") === -1) { - let ext: string | undefined; - ["wav", "mp3", "m4a"].every(e => { - if (seNames.indexOf(`${resourceName}.${e}`) > -1) { - ext = e; - return false; - } - return true; - }); - if (!ext) { - ext = ".wav"; - } - resourceName += `.${ext}`; - } - timedEvent = new AnimTimedSoundEvent(frameIndex, resourceName); - break; - case 1: - timedEvent = new AnimTimedAddBgEvent(frameIndex, resourceName.slice(0, resourceName.indexOf("."))); - break; - case 2: - timedEvent = new AnimTimedUpdateBgEvent(frameIndex, resourceName.slice(0, resourceName.indexOf("."))); - break; - } - if (!timedEvent) { - continue; - } - const propPattern = /([a-z]+): (.*?)(?:,|\})/gi; - let propMatch: RegExpExecArray; - while ((propMatch = propPattern.exec(timingData)!)) { - // TODO: is this bang correct? - const prop = propMatch[1]; - let value: any = propMatch[2]; - switch (prop) { - case "bgX": - case "bgY": - value = Number.parseFloat(value); - break; - case "volume": - case "pitch": - case "opacity": - case "colorRed": - case "colorGreen": - case "colorBlue": - case "colorAlpha": - case "duration": - case "flashScope": - case "flashRed": - case "flashGreen": - case "flashBlue": - case "flashAlpha": - case "flashDuration": - value = Number.parseInt(value); - break; - } - if (timedEvent.hasOwnProperty(prop)) { - timedEvent[prop] = value; - } - } - if (!anim.frameTimedEvents.has(frameIndex)) { - anim.frameTimedEvents.set(frameIndex, []); - } - anim.frameTimedEvents.get(frameIndex)!.push(timedEvent); // TODO: is this bang correct? - } - break; - } - case "position": - anim.position = Number.parseInt(fieldData); - break; - case "hue": - anim.hue = Number.parseInt(fieldData); - break; - } - } - } - - // biome-ignore lint/correctness/noUnusedVariables: used in commented code - const animReplacer = (k, v) => { - if (k === "id" && !v) { - return undefined; - } - if (v instanceof Map) { - return Object.fromEntries(v); - } - if (v instanceof AnimTimedEvent) { - v["eventType"] = v.getEventType(); - } - return v; - }; - - const animConfigProps = ["id", "graphic", "frames", "frameTimedEvents", "position", "hue"]; - const animFrameProps = [ - "x", - "y", - "zoomX", - "zoomY", - "angle", - "mirror", - "visible", - "blendType", - "target", - "graphicFrame", - "opacity", - "color", - "tone", - "flash", - "locked", - "priority", - "focus", - ]; - const propSets = [animConfigProps, animFrameProps]; - - // biome-ignore lint/correctness/noUnusedVariables: used in commented code - const animComparator = (a: Element, b: Element) => { - let props: string[]; - for (let p = 0; p < propSets.length; p++) { - props = propSets[p]; - // @ts-expect-error TODO - const ai = props.indexOf(a.key); - if (ai === -1) { - continue; - } - // @ts-expect-error TODO - const bi = props.indexOf(b.key); - - return ai < bi ? -1 : ai > bi ? 1 : 0; - } - - return 0; - }; - - /*for (let ma of moveAnims.keys()) { - const data = moveAnims.get(ma); - (async () => { - await fs.writeFile(`../public/battle-anims/${Moves[ma].toLowerCase().replace(/\_/g, '-')}.json`, stringify(data, { replacer: animReplacer, cmp: animComparator, space: ' ' })); - })(); - } - - for (let ca of chargeAnims.keys()) { - const data = chargeAnims.get(ca); - (async () => { - await fs.writeFile(`../public/battle-anims/${chargeAnimNames[chargeAnimIds.indexOf(ca)].replace(/\_/g, '-')}.json`, stringify(data, { replacer: animReplacer, cmp: animComparator, space: ' ' })); - })(); - } - - for (let cma of commonAnims.keys()) { - const data = commonAnims.get(cma); - (async () => { - await fs.writeFile(`../public/battle-anims/common-${commonAnimNames[commonAnimIds.indexOf(cma)].replace(/\_/g, '-')}.json`, stringify(data, { replacer: animReplacer, cmp: animComparator, space: ' ' })); - })(); - }*/ -}