clean up battle animation logic
This commit is contained in:
parent
09a3167bac
commit
06684e06a2
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@ import {Constructor, isNullOrUndefined} from "#app/utils";
|
||||||
import * as Utils from "./utils";
|
import * as Utils from "./utils";
|
||||||
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
|
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
|
||||||
import { PokeballType } from "./data/pokeball";
|
import { PokeballType } from "./data/pokeball";
|
||||||
import { initCommonAnims, initEncounterAnims, initMoveAnim, loadCommonAnimAssets, loadEncounterAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims";
|
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims";
|
||||||
import { Phase } from "./phase";
|
import { Phase } from "./phase";
|
||||||
import { initGameSpeed } from "./system/game-speed";
|
import { initGameSpeed } from "./system/game-speed";
|
||||||
import { Arena, ArenaBase } from "./field/arena";
|
import { Arena, ArenaBase } from "./field/arena";
|
||||||
|
@ -555,7 +555,6 @@ export default class BattleScene extends SceneBase {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
Promise.all(loadPokemonAssets),
|
Promise.all(loadPokemonAssets),
|
||||||
initCommonAnims(this).then(() => loadCommonAnimAssets(this, true)),
|
initCommonAnims(this).then(() => loadCommonAnimAssets(this, true)),
|
||||||
initEncounterAnims(this).then(() => loadEncounterAnimAssets(this, true)),
|
|
||||||
Promise.all([ Moves.TACKLE, Moves.TAIL_WHIP, Moves.FOCUS_ENERGY, Moves.STRUGGLE ].map(m => initMoveAnim(this, m))).then(() => loadMoveAnimAssets(this, defaultMoves, true)),
|
Promise.all([ Moves.TACKLE, Moves.TAIL_WHIP, Moves.FOCUS_ENERGY, Moves.STRUGGLE ].map(m => initMoveAnim(this, m))).then(() => loadMoveAnimAssets(this, defaultMoves, true)),
|
||||||
this.initStarterColors()
|
this.initStarterColors()
|
||||||
]).then(() => {
|
]).then(() => {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import * as Utils from "../utils";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { Element } from "json-stable-stringify";
|
import { Element } from "json-stable-stringify";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
|
import { isNullOrUndefined } from "../utils";
|
||||||
//import fs from 'vite-plugin-fs/browser';
|
//import fs from 'vite-plugin-fs/browser';
|
||||||
|
|
||||||
export enum AnimFrameTarget {
|
export enum AnimFrameTarget {
|
||||||
|
@ -307,7 +308,7 @@ abstract class AnimTimedEvent {
|
||||||
this.resourceName = resourceName;
|
this.resourceName = resourceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract execute(scene: BattleScene, battleAnim: BattleAnim): integer;
|
abstract execute(scene: BattleScene, battleAnim: BattleAnim, priority?: number): integer;
|
||||||
|
|
||||||
abstract getEventType(): string;
|
abstract getEventType(): string;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +326,7 @@ class AnimTimedSoundEvent extends AnimTimedEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(scene: BattleScene, battleAnim: BattleAnim): integer {
|
execute(scene: BattleScene, battleAnim: BattleAnim, priority?: number): integer {
|
||||||
const soundConfig = { rate: (this.pitch * 0.01), volume: (this.volume * 0.01) };
|
const soundConfig = { rate: (this.pitch * 0.01), volume: (this.volume * 0.01) };
|
||||||
if (this.resourceName) {
|
if (this.resourceName) {
|
||||||
try {
|
try {
|
||||||
|
@ -387,7 +388,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
|
||||||
super(frameIndex, resourceName, source);
|
super(frameIndex, resourceName, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(scene: BattleScene, moveAnim: MoveAnim): integer {
|
execute(scene: BattleScene, moveAnim: MoveAnim, priority?: number): integer {
|
||||||
const tweenProps = {};
|
const tweenProps = {};
|
||||||
if (this.bgX !== undefined) {
|
if (this.bgX !== undefined) {
|
||||||
tweenProps["x"] = (this.bgX * 0.5) - 320;
|
tweenProps["x"] = (this.bgX * 0.5) - 320;
|
||||||
|
@ -417,7 +418,7 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
||||||
super(frameIndex, resourceName, source);
|
super(frameIndex, resourceName, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(scene: BattleScene, moveAnim: MoveAnim): integer {
|
execute(scene: BattleScene, moveAnim: MoveAnim, priority?: number): integer {
|
||||||
if (moveAnim.bgSprite) {
|
if (moveAnim.bgSprite) {
|
||||||
moveAnim.bgSprite.destroy();
|
moveAnim.bgSprite.destroy();
|
||||||
}
|
}
|
||||||
|
@ -429,7 +430,9 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
||||||
moveAnim.bgSprite.setAlpha(this.opacity / 255);
|
moveAnim.bgSprite.setAlpha(this.opacity / 255);
|
||||||
scene.field.add(moveAnim.bgSprite);
|
scene.field.add(moveAnim.bgSprite);
|
||||||
const fieldPokemon = scene.getEnemyPokemon() || scene.getPlayerPokemon();
|
const fieldPokemon = scene.getEnemyPokemon() || scene.getPlayerPokemon();
|
||||||
if (fieldPokemon?.isOnField()) {
|
if (!isNullOrUndefined(priority)) {
|
||||||
|
scene.field.moveTo(moveAnim.bgSprite as Phaser.GameObjects.GameObject, priority);
|
||||||
|
} else if (fieldPokemon?.isOnField()) {
|
||||||
scene.field.moveBelow(moveAnim.bgSprite as Phaser.GameObjects.GameObject, fieldPokemon);
|
scene.field.moveBelow(moveAnim.bgSprite as Phaser.GameObjects.GameObject, fieldPokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,14 +520,18 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initEncounterAnims(scene: BattleScene): Promise<void> {
|
export function initEncounterAnims(scene: BattleScene, anims: EncounterAnim | EncounterAnim[]): Promise<void> {
|
||||||
|
anims = anims instanceof Array ? anims : [anims];
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
|
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
|
||||||
const encounterAnimIds = Utils.getEnumValues(EncounterAnim);
|
const encounterAnimIds = Utils.getEnumValues(EncounterAnim);
|
||||||
const encounterAnimFetches = [];
|
const encounterAnimFetches = [];
|
||||||
for (let ea = 0; ea < encounterAnimIds.length; ea++) {
|
for (const anim of anims) {
|
||||||
const encounterAnimId = encounterAnimIds[ea];
|
if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) {
|
||||||
encounterAnimFetches.push(scene.cachedFetch(`./battle-anims/encounter-${encounterAnimNames[ea].toLowerCase().replace(/\_/g, "-")}.json`)
|
continue;
|
||||||
|
}
|
||||||
|
const encounterAnimId = encounterAnimIds[anim];
|
||||||
|
encounterAnimFetches.push(scene.cachedFetch(`./battle-anims/encounter-${encounterAnimNames[anim].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(cas => encounterAnims.set(encounterAnimId, new AnimConfig(cas))));
|
.then(cas => encounterAnims.set(encounterAnimId, new AnimConfig(cas))));
|
||||||
}
|
}
|
||||||
|
@ -1005,18 +1012,13 @@ export abstract class BattleAnim {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getGraphicFrameDataWithoutTarget(scene: BattleScene, frames: AnimFrame[], targetInitialX: number, targetInitialY: number): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
|
private getGraphicFrameDataWithoutTarget(frames: AnimFrame[], targetInitialX: number, targetInitialY: number): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
|
||||||
const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([
|
const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([
|
||||||
[AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ],
|
[AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ],
|
||||||
[AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ],
|
[AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ],
|
||||||
[AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ]
|
[AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const userInitialX = 0;
|
|
||||||
const userInitialY = 0;
|
|
||||||
const userHalfHeight = 30;
|
|
||||||
const targetHalfHeight = 30;
|
|
||||||
|
|
||||||
let g = 0;
|
let g = 0;
|
||||||
let u = 0;
|
let u = 0;
|
||||||
let t = 0;
|
let t = 0;
|
||||||
|
@ -1024,27 +1026,10 @@ export abstract class BattleAnim {
|
||||||
for (const frame of frames) {
|
for (const frame of frames) {
|
||||||
let x = frame.x;
|
let x = frame.x;
|
||||||
let y = frame.y;
|
let y = frame.y;
|
||||||
let scaleX = (frame.zoomX / 100) * (!frame.mirror ? 1 : -1);
|
const scaleX = (frame.zoomX / 100) * (!frame.mirror ? 1 : -1);
|
||||||
const scaleY = (frame.zoomY / 100);
|
const scaleY = (frame.zoomY / 100);
|
||||||
switch (frame.focus) {
|
x += targetInitialX;
|
||||||
case AnimFocus.TARGET:
|
y += targetInitialY;
|
||||||
x += targetInitialX - targetFocusX;
|
|
||||||
y += (targetInitialY - targetHalfHeight) - targetFocusY;
|
|
||||||
break;
|
|
||||||
case AnimFocus.USER:
|
|
||||||
x += userInitialX - userFocusX;
|
|
||||||
y += (userInitialY - userHalfHeight) - userFocusY;
|
|
||||||
break;
|
|
||||||
case AnimFocus.USER_TARGET:
|
|
||||||
const point = transformPoint(this.srcLine[0], this.srcLine[1], this.srcLine[2], this.srcLine[3],
|
|
||||||
this.dstLine[0], this.dstLine[1] - userHalfHeight, this.dstLine[2], this.dstLine[3] - targetHalfHeight, x, y);
|
|
||||||
x = point[0];
|
|
||||||
y = point[1];
|
|
||||||
if (frame.target === AnimFrameTarget.GRAPHIC && isReversed(this.srcLine[0], this.srcLine[2], this.dstLine[0], this.dstLine[2])) {
|
|
||||||
scaleX = scaleX * -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const angle = -frame.angle;
|
const angle = -frame.angle;
|
||||||
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
|
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
|
||||||
ret.get(frame.target).set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle });
|
ret.get(frame.target).set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle });
|
||||||
|
@ -1053,7 +1038,20 @@ export abstract class BattleAnim {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
playWithoutTargets(scene: BattleScene, targetInitialX: number, targetInitialY: number, frameTimeMult: number, callback?: Function) {
|
/**
|
||||||
|
*
|
||||||
|
* @param scene
|
||||||
|
* @param targetInitialX
|
||||||
|
* @param targetInitialY
|
||||||
|
* @param frameTimeMult
|
||||||
|
* @param frameTimedEventPriority
|
||||||
|
* - 0 is behind all other sprites (except BG)
|
||||||
|
* - 1 on top of player field
|
||||||
|
* - 3 is on top of both fields
|
||||||
|
* - 5 is on top of player sprite
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
playWithoutTargets(scene: BattleScene, targetInitialX: number, targetInitialY: number, frameTimeMult: number, frameTimedEventPriority?: 0 | 1 | 3 | 5, callback?: Function) {
|
||||||
const spriteCache: SpriteCache = {
|
const spriteCache: SpriteCache = {
|
||||||
[AnimFrameTarget.GRAPHIC]: [],
|
[AnimFrameTarget.GRAPHIC]: [],
|
||||||
[AnimFrameTarget.USER]: [],
|
[AnimFrameTarget.USER]: [],
|
||||||
|
@ -1087,12 +1085,17 @@ export abstract class BattleAnim {
|
||||||
let r = anim.frames.length;
|
let r = anim.frames.length;
|
||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
|
const fieldSprites = scene.field.getAll();
|
||||||
|
const playerFieldSprite = fieldSprites[1];
|
||||||
|
const enemyFieldSprite = fieldSprites[3];
|
||||||
|
const trainerSprite = fieldSprites[5];
|
||||||
|
|
||||||
scene.tweens.addCounter({
|
scene.tweens.addCounter({
|
||||||
duration: Utils.getFrameMs(3) * frameTimeMult,
|
duration: Utils.getFrameMs(3) * frameTimeMult,
|
||||||
repeat: anim.frames.length,
|
repeat: anim.frames.length,
|
||||||
onRepeat: () => {
|
onRepeat: () => {
|
||||||
const spriteFrames = anim.frames[f];
|
const spriteFrames = anim.frames[f];
|
||||||
const frameData = this.getGraphicFrameDataWithoutTarget(scene, anim.frames[f], targetInitialX, targetInitialY);
|
const frameData = this.getGraphicFrameDataWithoutTarget(anim.frames[f], targetInitialX, targetInitialY);
|
||||||
const u = 0;
|
const u = 0;
|
||||||
const t = 0;
|
const t = 0;
|
||||||
let g = 0;
|
let g = 0;
|
||||||
|
@ -1118,11 +1121,27 @@ export abstract class BattleAnim {
|
||||||
if (priority < 0) {
|
if (priority < 0) {
|
||||||
// Move to top of scene
|
// Move to top of scene
|
||||||
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
||||||
} else if (priority < scene.field.getAll().length) {
|
} else if (priority === 1) {
|
||||||
// Indexes of field:
|
// Move above player field
|
||||||
// 0 is scene background
|
if (playerFieldSprite) {
|
||||||
// 1 is enemy field
|
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, playerFieldSprite);
|
||||||
scene.field.moveTo(moveSprite, priority);
|
} else {
|
||||||
|
setSpritePriority(-1);
|
||||||
|
}
|
||||||
|
} else if (priority === 3) {
|
||||||
|
// Move above player enemy field
|
||||||
|
if (enemyFieldSprite) {
|
||||||
|
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, enemyFieldSprite);
|
||||||
|
} else {
|
||||||
|
setSpritePriority(-1);
|
||||||
|
}
|
||||||
|
} else if (priority === 5) {
|
||||||
|
// Move above player trainer sprite
|
||||||
|
if (trainerSprite) {
|
||||||
|
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, trainerSprite);
|
||||||
|
} else {
|
||||||
|
setSpritePriority(-1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setSpritePriority(-1);
|
setSpritePriority(-1);
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1162,7 @@ export abstract class BattleAnim {
|
||||||
}
|
}
|
||||||
if (anim.frameTimedEvents.has(f)) {
|
if (anim.frameTimedEvents.has(f)) {
|
||||||
for (const event of anim.frameTimedEvents.get(f)) {
|
for (const event of anim.frameTimedEvents.get(f)) {
|
||||||
r = Math.max((anim.frames.length - f) + event.execute(scene, this), r);
|
r = Math.max((anim.frames.length - f) + event.execute(scene, this, frameTimedEventPriority), r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const targets = Utils.getEnumValues(AnimFrameTarget);
|
const targets = Utils.getEnumValues(AnimFrameTarget);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, initCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { modifierTypes, } from "#app/modifier/modifier-type";
|
import { modifierTypes, } from "#app/modifier/modifier-type";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import BattleScene from "../../../battle-scene";
|
import BattleScene from "../../../battle-scene";
|
||||||
|
@ -12,7 +12,7 @@ import { Type } from "#app/data/type";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { EncounterAnim, EncounterBattleAnim, initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
|
import { EncounterAnim, EncounterBattleAnim } from "#app/data/battle-anims";
|
||||||
import { WeatherType } from "#app/data/weather";
|
import { WeatherType } from "#app/data/weather";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils";
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ export const FieryFalloutEncounter: IMysteryEncounter =
|
||||||
.withSceneWaveRangeRequirement(40, 180) // waves 10 to 180
|
.withSceneWaveRangeRequirement(40, 180) // waves 10 to 180
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
.withIntroSpriteConfigs([]) // Set in onInit()
|
.withIntroSpriteConfigs([]) // Set in onInit()
|
||||||
|
.withAnimations(EncounterAnim.MAGMA_BG, EncounterAnim.MAGMA_SPOUT)
|
||||||
.withIntroDialogue([
|
.withIntroDialogue([
|
||||||
{
|
{
|
||||||
text: `${namespace}_intro_message`,
|
text: `${namespace}_intro_message`,
|
||||||
|
@ -60,21 +61,20 @@ export const FieryFalloutEncounter: IMysteryEncounter =
|
||||||
scene.arena.trySetWeather(WeatherType.SUNNY, true);
|
scene.arena.trySetWeather(WeatherType.SUNNY, true);
|
||||||
|
|
||||||
// Load animations/sfx for Volcarona moves
|
// Load animations/sfx for Volcarona moves
|
||||||
Promise.all([initMoveAnim(scene, Moves.QUIVER_DANCE), initMoveAnim(scene, Moves.FIRE_SPIN)])
|
initCustomMovesForEncounter(scene, [Moves.FIRE_SPIN, Moves.QUIVER_DANCE]);
|
||||||
.then(() => loadMoveAnimAssets(scene, [Moves.QUIVER_DANCE, Moves.FIRE_SPIN]));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.withOnVisualsStart((scene: BattleScene) => {
|
.withOnVisualsStart((scene: BattleScene) => {
|
||||||
// Play animations
|
// Play animations
|
||||||
const background = new EncounterBattleAnim(EncounterAnim.MAGMA_BG, scene.getPlayerPokemon(), scene.getPlayerPokemon());
|
const background = new EncounterBattleAnim(EncounterAnim.MAGMA_BG, scene.getPlayerPokemon(), scene.getPlayerPokemon());
|
||||||
background.playWithoutTargets(scene, 200, 70, 2);
|
background.playWithoutTargets(scene, 200, 70, 2, 3);
|
||||||
const animation = new EncounterBattleAnim(EncounterAnim.MAGMA_SPOUT, scene.getPlayerPokemon(), scene.getPlayerPokemon());
|
const animation = new EncounterBattleAnim(EncounterAnim.MAGMA_SPOUT, scene.getPlayerPokemon(), scene.getPlayerPokemon());
|
||||||
animation.playWithoutTargets(scene, 200, 70, 2);
|
animation.playWithoutTargets(scene, 100, 100, 2);
|
||||||
const increment = 600;
|
const increment = 600;
|
||||||
for (let i = 3; i < 6; i++) {
|
for (let i = 3; i < 6; i++) {
|
||||||
scene.time.delayedCall((increment) * (i - 2), () => {
|
scene.time.delayedCall((increment) * (i - 2), () => {
|
||||||
animation.playWithoutTargets(scene, 100 + randSeedInt(12) * 20, 110 - randSeedInt(10) * 15, 2);
|
animation.playWithoutTargets(scene, randSeedInt(12) * 15, 150 - randSeedInt(10) * 15, 2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
WaveRangeRequirement
|
WaveRangeRequirement
|
||||||
} from "./mystery-encounter-requirements";
|
} from "./mystery-encounter-requirements";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { EncounterAnim } from "#app/data/battle-anims";
|
||||||
|
|
||||||
export enum MysteryEncounterVariant {
|
export enum MysteryEncounterVariant {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
|
@ -57,6 +58,7 @@ export default interface IMysteryEncounter {
|
||||||
* Optional params
|
* Optional params
|
||||||
*/
|
*/
|
||||||
encounterTier?: MysteryEncounterTier;
|
encounterTier?: MysteryEncounterTier;
|
||||||
|
encounterAnimations?: EncounterAnim[];
|
||||||
hideBattleIntroMessage?: boolean;
|
hideBattleIntroMessage?: boolean;
|
||||||
hideIntroVisuals?: boolean;
|
hideIntroVisuals?: boolean;
|
||||||
catchAllowed?: boolean;
|
catchAllowed?: boolean;
|
||||||
|
@ -193,13 +195,6 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
||||||
const secReqs = this.meetsSecondaryRequirementAndSecondaryPokemonSelected(scene); // secondary is checked first to handle cases of primary overlapping with secondary
|
const secReqs = this.meetsSecondaryRequirementAndSecondaryPokemonSelected(scene); // secondary is checked first to handle cases of primary overlapping with secondary
|
||||||
const priReqs = this.meetsPrimaryRequirementAndPrimaryPokemonSelected(scene);
|
const priReqs = this.meetsPrimaryRequirementAndPrimaryPokemonSelected(scene);
|
||||||
|
|
||||||
// console.log("-------" + MysteryEncounterType[this.encounterType] + " Encounter Check -------");
|
|
||||||
// console.log(this);
|
|
||||||
// console.log( "sceneCheck: " + sceneReq);
|
|
||||||
// console.log( "primaryCheck: " + priReqs);
|
|
||||||
// console.log( "secondaryCheck: " + secReqs);
|
|
||||||
// console.log(MysteryEncounterTier[this.encounterTier]);
|
|
||||||
|
|
||||||
return sceneReq && secReqs && priReqs;
|
return sceneReq && secReqs && priReqs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +372,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||||
|
|
||||||
dialogue?: MysteryEncounterDialogue;
|
dialogue?: MysteryEncounterDialogue;
|
||||||
encounterTier?: MysteryEncounterTier;
|
encounterTier?: MysteryEncounterTier;
|
||||||
|
encounterAnimations?: EncounterAnim[];
|
||||||
requirements?: EncounterSceneRequirement[] = [];
|
requirements?: EncounterSceneRequirement[] = [];
|
||||||
primaryPokemonRequirements?: EncounterPokemonRequirement[] = [];
|
primaryPokemonRequirements?: EncounterPokemonRequirement[] = [];
|
||||||
secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
|
secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
|
||||||
|
@ -471,6 +467,16 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||||
return Object.assign(this, { encounterTier: encounterTier });
|
return Object.assign(this, { encounterTier: encounterTier });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines any EncounterAnim animations that are intended to be used during the encounter
|
||||||
|
* @param encounterAnimations
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
withAnimations(...encounterAnimations: EncounterAnim[]): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> {
|
||||||
|
encounterAnimations = encounterAnimations instanceof Array ? encounterAnimations : [encounterAnimations];
|
||||||
|
return Object.assign(this, { encounterAnimations: encounterAnimations });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the maximum number of times that an encounter can spawn in a given Classic run
|
* Sets the maximum number of times that an encounter can spawn in a given Classic run
|
||||||
* @param maxAllowedEncounters
|
* @param maxAllowedEncounters
|
||||||
|
|
|
@ -26,6 +26,8 @@ import * as Overrides from "#app/overrides";
|
||||||
import MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
|
import MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { Gender } from "#app/data/gender";
|
import { Gender } from "#app/data/gender";
|
||||||
|
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
|
||||||
export class EnemyPokemonConfig {
|
export class EnemyPokemonConfig {
|
||||||
species: PokemonSpecies;
|
species: PokemonSpecies;
|
||||||
|
@ -230,6 +232,20 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load special move animations/sfx for hard-coded encounter-specific moves that a pokemon uses at the start of an encounter
|
||||||
|
* See: [startOfBattleEffects](IMysteryEncounter.startOfBattleEffects) for more details
|
||||||
|
*
|
||||||
|
* This promise does not need to be awaited on if called in an encounter onInit (will just load lazily)
|
||||||
|
* @param scene
|
||||||
|
* @param moves
|
||||||
|
*/
|
||||||
|
export function initCustomMovesForEncounter(scene: BattleScene, moves: Moves | Moves[]) {
|
||||||
|
moves = moves instanceof Array ? moves : [moves];
|
||||||
|
return Promise.all(moves.map(move => initMoveAnim(scene, move)))
|
||||||
|
.then(() => loadMoveAnimAssets(scene, moves));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will update player money, and animate change (sound optional)
|
* Will update player money, and animate change (sound optional)
|
||||||
* @param scene - Battle Scene
|
* @param scene - Battle Scene
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Stat } from "./data/pokemon-stat";
|
||||||
import { BerryModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, IvScannerModifier, LapsingPersistentModifier, LapsingPokemonHeldItemModifier, MapModifier, Modifier, MoneyInterestModifier, MoneyMultiplierModifier, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier } from "./modifier/modifier";
|
import { BerryModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, IvScannerModifier, LapsingPersistentModifier, LapsingPokemonHeldItemModifier, MapModifier, Modifier, MoneyInterestModifier, MoneyMultiplierModifier, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier } from "./modifier/modifier";
|
||||||
import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler";
|
import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler";
|
||||||
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball";
|
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball";
|
||||||
import { CommonAnim, CommonBattleAnim, initMoveAnim, loadMoveAnimAssets, MoveAnim } from "./data/battle-anims";
|
import { CommonAnim, CommonBattleAnim, initEncounterAnims, initMoveAnim, loadEncounterAnimAssets, loadMoveAnimAssets, MoveAnim } from "./data/battle-anims";
|
||||||
import { getStatusEffectActivationText, getStatusEffectCatchRateMultiplier, getStatusEffectHealText, getStatusEffectObtainText, getStatusEffectOverlapText, StatusEffect } from "./data/status-effect";
|
import { getStatusEffectActivationText, getStatusEffectCatchRateMultiplier, getStatusEffectHealText, getStatusEffectObtainText, getStatusEffectOverlapText, StatusEffect } from "./data/status-effect";
|
||||||
import { SummaryUiMode } from "./ui/summary-ui-handler";
|
import { SummaryUiMode } from "./ui/summary-ui-handler";
|
||||||
import EvolutionSceneHandler from "./ui/evolution-scene-handler";
|
import EvolutionSceneHandler from "./ui/evolution-scene-handler";
|
||||||
|
@ -832,6 +832,11 @@ export class EncounterPhase extends BattlePhase {
|
||||||
mysteryEncounter.populateDialogueTokensFromRequirements(this.scene);
|
mysteryEncounter.populateDialogueTokensFromRequirements(this.scene);
|
||||||
}, this.scene.currentBattle.waveIndex);
|
}, this.scene.currentBattle.waveIndex);
|
||||||
|
|
||||||
|
// Add any special encounter animations to load
|
||||||
|
if (mysteryEncounter.encounterAnimations && mysteryEncounter.encounterAnimations.length > 0) {
|
||||||
|
loadEnemyAssets.push(initEncounterAnims(this.scene, mysteryEncounter.encounterAnimations).then(() => loadEncounterAnimAssets(this.scene, true)));
|
||||||
|
}
|
||||||
|
|
||||||
// Add intro visuals for mystery encounter
|
// Add intro visuals for mystery encounter
|
||||||
mysteryEncounter.initIntroVisuals(this.scene);
|
mysteryEncounter.initIntroVisuals(this.scene);
|
||||||
this.scene.field.add(mysteryEncounter.introVisuals);
|
this.scene.field.add(mysteryEncounter.introVisuals);
|
||||||
|
|
|
@ -89,8 +89,8 @@ describe("Mystery Encounter Phases", () => {
|
||||||
expect(dialogueSpy).toHaveBeenCalledTimes(1);
|
expect(dialogueSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(messageSpy).toHaveBeenCalledTimes(2);
|
expect(messageSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(dialogueSpy).toHaveBeenCalledWith("What's this?", "???", null, expect.any(Function));
|
expect(dialogueSpy).toHaveBeenCalledWith("What's this?", "???", null, expect.any(Function));
|
||||||
expect(messageSpy).toHaveBeenCalledWith("Mysterious challengers have appeared!", null, expect.any(Function), 750, true);
|
expect(messageSpy).toHaveBeenCalledWith("Mysterious challengers have appeared!", null, expect.any(Function), 300, true);
|
||||||
expect(messageSpy).toHaveBeenCalledWith("The trainer steps forward...", null, expect.any(Function), 750, true);
|
expect(messageSpy).toHaveBeenCalledWith("The trainer steps forward...", null, expect.any(Function), 300, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue