Add Pokemon Reborn move animations
This commit is contained in:
1 parent
5f845839af
commit
1cf81869d0
2497 files changed
+3777463
-114
No files matched your search
@@ -1,9 +0,0 @@
|
||||
import BattleScene from "./battle-scene";
|
||||
|
||||
export class BattleAnimHandler {
|
||||
private scene: BattleScene;
|
||||
|
||||
constructor(scene: BattleScene) {
|
||||
this.scene = scene;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
//import { battleAnimRawData } from "./battle-anim-raw-data";
|
||||
import BattleScene from "./battle-scene";
|
||||
import { Moves } from "./move";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "./pokemon";
|
||||
import * as Utils from "./utils";
|
||||
import fs from 'vite-plugin-fs/browser';
|
||||
|
||||
export enum AnimFrameTarget {
|
||||
USER,
|
||||
TARGET,
|
||||
GRAPHIC
|
||||
}
|
||||
|
||||
enum AnimFocus {
|
||||
USER = 1,
|
||||
TARGET,
|
||||
USER_TARGET,
|
||||
SCREEN
|
||||
}
|
||||
|
||||
export class Anim {
|
||||
public id: integer;
|
||||
public graphic: string;
|
||||
public frames: AnimFrame[][];
|
||||
public frameTimedEvents: Map<integer, AnimTimedEvent[]>;
|
||||
public position: integer;
|
||||
public hue: integer;
|
||||
|
||||
constructor(source?: any) {
|
||||
this.frameTimedEvents = new Map<integer, AnimTimedEvent[]>;
|
||||
|
||||
if (source) {
|
||||
this.id = source.id;
|
||||
this.graphic = source.graphic;
|
||||
this.frames = source.frames;
|
||||
|
||||
const frameTimedEvents = source.frameTimedEvents;
|
||||
for (let fte of Object.keys(frameTimedEvents)) {
|
||||
const timedEvents: AnimTimedEvent[] = [];
|
||||
for (let te of frameTimedEvents[fte]) {
|
||||
let timedEvent: AnimTimedEvent;
|
||||
switch (te.eventType) {
|
||||
case 'AnimTimedSoundEvent':
|
||||
timedEvent = new AnimTimedSoundEvent(te.frameIndex, te.resourceName, te);
|
||||
break;
|
||||
case 'AnimTimedAddBgEvent':
|
||||
timedEvent = new AnimTimedAddBgEvent(te.frameIndex, te.resourceName, te);
|
||||
break;
|
||||
case 'AnimTimedUpdateBgEvent':
|
||||
timedEvent = new AnimTimedUpdateBgEvent(te.frameIndex, te.resourceName, te);
|
||||
break;
|
||||
}
|
||||
timedEvents.push(timedEvent);
|
||||
}
|
||||
this.frameTimedEvents.set(parseInt(fte), timedEvents);
|
||||
}
|
||||
|
||||
this.position = source.position;
|
||||
this.hue = source.hue;
|
||||
} else
|
||||
this.frames = [];
|
||||
}
|
||||
|
||||
getSoundResourceNames(): string[] {
|
||||
const sounds = new Set<string>();
|
||||
|
||||
for (let ftes of this.frameTimedEvents.values()) {
|
||||
for (let fte of ftes) {
|
||||
if (fte instanceof AnimTimedSoundEvent && fte.resourceName)
|
||||
sounds.add(fte.resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(sounds.values());
|
||||
}
|
||||
|
||||
getBackgroundResourceNames(): string[] {
|
||||
const backgrounds = new Set<string>();
|
||||
|
||||
for (let ftes of this.frameTimedEvents.values()) {
|
||||
for (let fte of ftes) {
|
||||
if (fte instanceof AnimTimedAddBgEvent && fte.resourceName)
|
||||
backgrounds.add(fte.resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(backgrounds.values());
|
||||
}
|
||||
}
|
||||
|
||||
class AnimFrame {
|
||||
public x: number;
|
||||
public y: number;
|
||||
public zoomX: number;
|
||||
public zoomY: number;
|
||||
public angle: number;
|
||||
public mirror: boolean;
|
||||
public visible: boolean;
|
||||
public blendType: integer;
|
||||
public target: AnimFrameTarget;
|
||||
public graphicFrame: integer;
|
||||
public opacity: integer;
|
||||
public color: integer[];
|
||||
public tone: integer[];
|
||||
public flash: integer[];
|
||||
public locked: boolean;
|
||||
public priority: integer;
|
||||
public focus: AnimFocus;
|
||||
|
||||
constructor(x: number, y: number, zoomX: number, zoomY: number, angle: number, mirror: boolean, visible: boolean, blendType: integer, pattern: integer,
|
||||
opacity: integer, colorR: integer, colorG: integer, colorB: integer, colorA: integer, toneR: integer, toneG: integer, toneB: integer, toneA: integer,
|
||||
flashR: integer, flashG: integer, flashB: integer, flashA: integer, locked: boolean, priority: integer, focus: AnimFocus) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.zoomX = zoomX;
|
||||
this.zoomY = zoomY;
|
||||
this.angle = angle;
|
||||
this.mirror = mirror;
|
||||
this.visible = visible;
|
||||
this.blendType = blendType;
|
||||
let target = AnimFrameTarget.GRAPHIC;
|
||||
switch (pattern) {
|
||||
case -2:
|
||||
target = AnimFrameTarget.TARGET;
|
||||
this.x -= 384;
|
||||
this.y -= 96;
|
||||
break;
|
||||
case -1:
|
||||
target = AnimFrameTarget.USER;
|
||||
this.x -= 128;
|
||||
this.y -= 224;
|
||||
break;
|
||||
default:
|
||||
this.x = (this.x - 128) * 0.5;
|
||||
this.y = (this.y - 224) * 0.5;
|
||||
}
|
||||
this.target = target;
|
||||
this.graphicFrame = pattern >= 0 ? pattern : 0;
|
||||
this.opacity = opacity;
|
||||
this.color = [ colorR, colorG, colorB, colorA ];
|
||||
this.tone = [ toneR, toneG, toneB, toneA ];
|
||||
this.flash = [ flashR, flashG, flashB, flashA ];
|
||||
this.locked = locked;
|
||||
this.priority = priority;
|
||||
this.focus = focus;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AnimTimedEvent {
|
||||
public frameIndex: integer;
|
||||
public resourceName: string;
|
||||
|
||||
constructor(frameIndex: integer, resourceName: string) {
|
||||
this.frameIndex = frameIndex;
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
abstract execute(scene: BattleScene, moveAnim: MoveAnim): void;
|
||||
|
||||
abstract getEventType(): string;
|
||||
}
|
||||
|
||||
class AnimTimedSoundEvent extends AnimTimedEvent {
|
||||
public volume: number;
|
||||
public pitch: number;
|
||||
|
||||
constructor(frameIndex: integer, resourceName: string, source?: any) {
|
||||
super(frameIndex, resourceName);
|
||||
|
||||
if (source) {
|
||||
this.volume = source.volume;
|
||||
this.pitch = source.pitch;
|
||||
} else
|
||||
this.pitch = 100;
|
||||
}
|
||||
|
||||
execute(scene: BattleScene, moveAnim: MoveAnim): void {
|
||||
const soundConfig = { rate: (this.pitch * 0.01), volume: (this.volume * 0.01) };
|
||||
if (this.resourceName)
|
||||
scene.sound.play(this.resourceName, soundConfig);
|
||||
else
|
||||
moveAnim.user.cry(soundConfig);
|
||||
}
|
||||
|
||||
getEventType(): string {
|
||||
return 'AnimTimedSoundEvent';
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AnimTimedBgEvent extends AnimTimedEvent {
|
||||
public bgX: number;
|
||||
public bgY: number;
|
||||
public opacity: integer;
|
||||
public colorRed: integer;
|
||||
public colorGreen: integer;
|
||||
public colorBlue: integer;
|
||||
public colorAlpha: integer;
|
||||
public duration: integer;
|
||||
public flashScope: integer;
|
||||
public flashRed: integer;
|
||||
public flashGreen: integer;
|
||||
public flashBlue: integer;
|
||||
public flashAlpha: integer;
|
||||
public flashDuration: integer;
|
||||
|
||||
constructor(frameIndex: integer, resourceName: string, source: any) {
|
||||
super(frameIndex, resourceName);
|
||||
|
||||
if (source) {
|
||||
this.bgX = source.bgX;
|
||||
this.bgY = source.bgY;
|
||||
this.opacity = source.opacity;
|
||||
this.colorRed = source.colorRed;
|
||||
this.colorGreen = source.colorGreen;
|
||||
this.colorBlue = source.colorBlue;
|
||||
this.colorAlpha = source.colorAlpha;
|
||||
this.duration = source.duration;
|
||||
this.flashScope = source.flashScope;
|
||||
this.flashRed = source.flashRed;
|
||||
this.flashGreen = source.flashGreen;
|
||||
this.flashBlue = source.flashBlue;
|
||||
this.flashAlpha = source.flashAlpha;
|
||||
this.flashDuration = source.flashDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
|
||||
constructor(frameIndex: integer, resourceName: string, source?: any) {
|
||||
super(frameIndex, resourceName, source);
|
||||
}
|
||||
|
||||
execute(scene: BattleScene, moveAnim: MoveAnim): void {
|
||||
const tweenProps = {};
|
||||
if (this.bgX !== undefined)
|
||||
tweenProps['x'] = (this.bgX * 0.5) - 256;
|
||||
if (this.bgY !== undefined)
|
||||
tweenProps['y'] = (this.bgY * 0.5) - 284;
|
||||
if (this.opacity !== undefined)
|
||||
tweenProps['alpha'] = this.opacity / 255;
|
||||
if (Object.keys(tweenProps).length) {
|
||||
scene.tweens.add(Object.assign({
|
||||
targets: moveAnim.bgSprite,
|
||||
duration: this.duration * 2,
|
||||
useFrames: true
|
||||
}, tweenProps))
|
||||
}
|
||||
}
|
||||
|
||||
getEventType(): string {
|
||||
return 'AnimTimedUpdateBgEvent';
|
||||
}
|
||||
}
|
||||
|
||||
class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
||||
constructor(frameIndex: integer, resourceName: string, source?: any) {
|
||||
super(frameIndex, resourceName, source);
|
||||
}
|
||||
|
||||
execute(scene: BattleScene, moveAnim: MoveAnim): void {
|
||||
moveAnim.bgSprite = scene.add.tileSprite(this.bgX - 256, this.bgY - 284, 768, 576, this.resourceName);
|
||||
moveAnim.bgSprite.setOrigin(0, 0);
|
||||
moveAnim.bgSprite.setScale(1.25);
|
||||
moveAnim.bgSprite.setAlpha(0);
|
||||
scene.field.add(moveAnim.bgSprite);
|
||||
scene.field.moveBelow(moveAnim.bgSprite, scene.getEnemyPokemon());
|
||||
|
||||
scene.tweens.add({
|
||||
targets: moveAnim.bgSprite,
|
||||
alpha: 1,
|
||||
duration: this.duration * 2,
|
||||
useFrames: true
|
||||
});
|
||||
}
|
||||
|
||||
getEventType(): string {
|
||||
return 'AnimTimedAddBgEvent';
|
||||
}
|
||||
}
|
||||
|
||||
export const moveAnims = new Map<Moves, Anim | [Anim, Anim]>();
|
||||
|
||||
export function initAnim(move: Moves): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (moveAnims.has(move)) {
|
||||
if (moveAnims.get(move) !== null)
|
||||
resolve();
|
||||
else {
|
||||
let loadedCheckTimer = setInterval(() => {
|
||||
if (moveAnims.get(move) !== null) {
|
||||
clearInterval(loadedCheckTimer);
|
||||
resolve();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
} else {
|
||||
moveAnims.set(move, null);
|
||||
fetch(`./battle-anims/${Moves[move].toLowerCase().replace(/\_/g, '-')}.json`)
|
||||
.then(response => response.json())
|
||||
.then(ba => {
|
||||
if (Array.isArray(ba)) {
|
||||
populateMoveAnim(move, ba[0]);
|
||||
populateMoveAnim(move, ba[1]);
|
||||
} else
|
||||
populateMoveAnim(move, ba);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function populateMoveAnim(move: Moves, animSource: any) {
|
||||
const moveAnim = new Anim(animSource);
|
||||
if (moveAnims.get(move) === null) {
|
||||
moveAnims.set(move, moveAnim);
|
||||
return;
|
||||
}
|
||||
moveAnims.set(move, [ moveAnims.get(move) as Anim, moveAnim ]);
|
||||
}
|
||||
|
||||
export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLoad?: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const moveAnimations = moveIds.map(m => {
|
||||
const anims = moveAnims.get(m);
|
||||
if (anims instanceof Anim)
|
||||
return anims as Anim;
|
||||
return anims[0] as Anim;
|
||||
});
|
||||
const backgrounds = new Set<string>();
|
||||
const sounds = new Set<string>();
|
||||
for (let ma of moveAnimations) {
|
||||
const moveSounds = ma.getSoundResourceNames();
|
||||
for (let ms of moveSounds)
|
||||
sounds.add(ms);
|
||||
const moveBackgrounds = ma.getBackgroundResourceNames();
|
||||
for (let mbg of moveBackgrounds)
|
||||
backgrounds.add(mbg);
|
||||
if (ma.graphic)
|
||||
scene.loadSpritesheet(ma.graphic, 'battle_anims', 96);
|
||||
}
|
||||
for (let bg of backgrounds)
|
||||
scene.loadImage(bg, 'battle_anims');
|
||||
for (let s of sounds)
|
||||
scene.loadSe(s, 'battle_anims', s);
|
||||
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => resolve());
|
||||
if (startLoad && !scene.load.isLoading())
|
||||
scene.load.start();
|
||||
});
|
||||
}
|
||||
|
||||
export class MoveAnim {
|
||||
public move: Moves;
|
||||
public user: Pokemon;
|
||||
public target: Pokemon;
|
||||
public moveSprites: Phaser.GameObjects.Sprite[];
|
||||
public bgSprite: Phaser.GameObjects.TileSprite;
|
||||
|
||||
constructor(move: Moves, user: Pokemon, target: Pokemon) {
|
||||
this.move = move;
|
||||
this.user = user;
|
||||
this.target = target;
|
||||
this.moveSprites = [];
|
||||
}
|
||||
|
||||
play(scene: BattleScene, callback?: Function) {
|
||||
const anim = moveAnims.get(this.move) instanceof Anim
|
||||
? moveAnims.get(this.move) as Anim
|
||||
: moveAnims.get(this.move)[this.user instanceof PlayerPokemon ? 0 : 1] as Anim;
|
||||
const isOppMove = Array.isArray(moveAnims.get(this.move)) && this.user instanceof EnemyPokemon;
|
||||
|
||||
const userInitialX = this.user.x;
|
||||
const userInitialY = this.user.y;
|
||||
const userHalfHeight = this.user.getSprite().displayHeight / 2;
|
||||
const targetInitialX = this.target.x;
|
||||
const targetInitialY = this.target.y;
|
||||
const targetHalfHeight = this.target.getSprite().displayHeight / 2;
|
||||
|
||||
const coordMultiplayer = this.user instanceof PlayerPokemon || isOppMove ? 1 : -1;
|
||||
|
||||
let f = 0;
|
||||
|
||||
const moveSprites: Phaser.GameObjects.Sprite[] = [];
|
||||
|
||||
scene.tweens.addCounter({
|
||||
useFrames: true,
|
||||
duration: 2,
|
||||
repeat: anim.frames.length,
|
||||
onRepeat: () => {
|
||||
const spriteFrames = anim.frames[f];
|
||||
let g = 0;
|
||||
for (let frame of spriteFrames) {
|
||||
switch (frame.target) {
|
||||
case AnimFrameTarget.USER:
|
||||
this.user.setPosition(userInitialX + frame.x * coordMultiplayer, userInitialY + frame.y * coordMultiplayer);
|
||||
break;
|
||||
case AnimFrameTarget.TARGET:
|
||||
this.target.setPosition(targetInitialX + frame.x * coordMultiplayer, targetInitialY + frame.y * coordMultiplayer);
|
||||
break;
|
||||
case AnimFrameTarget.GRAPHIC:
|
||||
if (g === moveSprites.length) {
|
||||
const newSprite = scene.add.sprite(0, 0, anim.graphic, 1);
|
||||
scene.field.add(newSprite);
|
||||
moveSprites.push(newSprite);
|
||||
}
|
||||
const moveSprite = moveSprites[g++];
|
||||
moveSprite.setFrame(frame.graphicFrame);
|
||||
const xProgress = Math.min(Math.max(frame.x, 0) / 128, 1);
|
||||
const yOffset = ((userHalfHeight * (1 - xProgress)) + (targetHalfHeight * xProgress)) * -1;
|
||||
moveSprite.setPosition((!isOppMove ? userInitialX : targetInitialX) + frame.x * coordMultiplayer, (!isOppMove ? userInitialY : targetInitialY) + yOffset + frame.y * coordMultiplayer);
|
||||
moveSprite.setAlpha(frame.opacity);
|
||||
moveSprite.setAngle(-frame.angle * coordMultiplayer);
|
||||
break;
|
||||
}
|
||||
if (frame.target !== AnimFrameTarget.GRAPHIC) {
|
||||
const pokemon = frame.target === AnimFrameTarget.USER
|
||||
? this.user
|
||||
: this.target;
|
||||
pokemon.setAlpha(frame.opacity);
|
||||
pokemon.setAngle(-frame.angle * coordMultiplayer);
|
||||
const zoomScaleX = frame.zoomX / 100;
|
||||
const zoomScaleY = frame.zoomY / 100;
|
||||
const zoomSprite = pokemon.getZoomSprite();
|
||||
zoomSprite.setY(zoomSprite.displayHeight * (zoomScaleY - 1) * 0.5);
|
||||
zoomSprite.setScale(zoomScaleX, zoomScaleY);
|
||||
}
|
||||
}
|
||||
if (anim.frameTimedEvents.has(f)) {
|
||||
for (let event of anim.frameTimedEvents.get(f))
|
||||
event.execute(scene, this);
|
||||
}
|
||||
if (g < moveSprites.length) {
|
||||
const removedSprites = moveSprites.splice(g, moveSprites.length - g);
|
||||
for (let rs of removedSprites)
|
||||
rs.destroy();
|
||||
}
|
||||
f++;
|
||||
},
|
||||
onComplete: () => {
|
||||
this.user.setPosition(userInitialX, userInitialY);
|
||||
this.user.setAlpha(1);
|
||||
this.user.setAngle(0);
|
||||
this.target.setPosition(targetInitialX, targetInitialY);
|
||||
this.target.setAlpha(1);
|
||||
this.target.setAngle(0);
|
||||
for (let ms of moveSprites)
|
||||
ms.destroy();
|
||||
if (callback)
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function populateAnims() {
|
||||
return;
|
||||
const moveNameToId = {};
|
||||
for (let move of Utils.getEnumValues(Moves)) {
|
||||
const moveName = Moves[move].toUpperCase().replace(/\_/g, '');
|
||||
moveNameToId[moveName] = move;
|
||||
}
|
||||
const animsData = [];//battleAnimRawData.split('!ruby/array:PBAnimation').slice(1);
|
||||
for (let a = 0; a < animsData.length; a++) {
|
||||
const fields = animsData[a].split('@').slice(1);
|
||||
|
||||
let isOppMove: boolean;
|
||||
if (!fields[1].startsWith('name: Move:') && !(isOppMove = fields[1].startsWith('name: OppMove:')))
|
||||
continue;
|
||||
const nameIndex = fields[1].indexOf(':', 5) + 1;
|
||||
const moveName = fields[1].slice(nameIndex, fields[1].indexOf('\n', nameIndex));
|
||||
if (!moveNameToId.hasOwnProperty(moveName))
|
||||
continue;
|
||||
let anim = new Anim();
|
||||
anim.id = moveNameToId[moveName];
|
||||
moveAnims.set(moveNameToId[moveName], !isOppMove ? anim : [ moveAnims.get(moveNameToId[moveName]) as Anim, anim ]);
|
||||
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(/ \- /g, '').split('\n');
|
||||
const targetFrame = new AnimFrame(parseFloat(values[0]), parseFloat(values[1]), parseFloat(values[2]), parseFloat(values[11]), parseFloat(values[3]),
|
||||
values[4] === '1', values[6] === '1', parseInt(values[5]), parseInt(values[7]), parseInt(values[8]), parseInt(values[12]), parseInt(values[13]),
|
||||
parseInt(values[14]), parseInt(values[15]), parseInt(values[16]), parseInt(values[17]), parseInt(values[18]), parseInt(values[19]),
|
||||
parseInt(values[21]), parseInt(values[22]), parseInt(values[23]), parseInt(values[24]), values[20] === '1', parseInt(values[25]), parseInt(values[26]) as AnimFocus);
|
||||
anim.frames[fd].push(targetFrame);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'graphic':
|
||||
anim.graphic = fieldData !== "''" ? fieldData.slice(0, fieldData.indexOf('.')) : '';
|
||||
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]+: ! '', /ig, '').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 = parseInt(/frame: (\d+)/.exec(timingData)[1]);
|
||||
const resourceName = /name: "(.*?)"/.exec(timingData)[1].replace("''", '');
|
||||
const timingType = parseInt(/timingType: (\d)/.exec(timingData)[1]);
|
||||
let timedEvent: AnimTimedEvent;
|
||||
switch (timingType) {
|
||||
case 0:
|
||||
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]+): (.*?)(?:,|\})/ig;
|
||||
let propMatch: RegExpExecArray;
|
||||
while ((propMatch = propPattern.exec(timingData))) {
|
||||
const prop = propMatch[1];
|
||||
let value: any = propMatch[2];
|
||||
switch (prop) {
|
||||
case 'bgX':
|
||||
case 'bgY':
|
||||
value = 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 = 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);
|
||||
}
|
||||
break;
|
||||
case 'position':
|
||||
anim.position = parseInt(fieldData);
|
||||
break;
|
||||
case 'hue':
|
||||
anim.hue = parseInt(fieldData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let ma of moveAnims.keys()) {
|
||||
const data = moveAnims.get(ma);
|
||||
(async () => {
|
||||
await fs.writeFile(`./public/battle-anims/${Moves[ma].toLowerCase().replace(/\_/g, '-')}.json`, JSON.stringify(data, (k, v) => {
|
||||
if (v instanceof Map)
|
||||
return Object.fromEntries(v);
|
||||
if (v instanceof AnimTimedEvent)
|
||||
v['eventType'] = v.getEventType();
|
||||
return v;
|
||||
}, ' '));
|
||||
})();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
|
||||
private lastExp: integer;
|
||||
private lastLevelExp: integer;
|
||||
private lastLevel: integer;
|
||||
private lastName: string;
|
||||
|
||||
private nameText: Phaser.GameObjects.Text;
|
||||
private genderText: Phaser.GameObjects.Text;
|
||||
@@ -31,7 +30,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
|
||||
this.lastExp = -1;
|
||||
this.lastLevelExp = -1;
|
||||
this.lastLevel = -1;
|
||||
this.lastName = null;
|
||||
|
||||
// Initially invisible and shown via Pokemon.showInfo
|
||||
this.setVisible(false);
|
||||
|
||||
+48
-43
@@ -1,15 +1,15 @@
|
||||
import BattleScene from "./battle-scene";
|
||||
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove } from "./pokemon";
|
||||
import * as Utils from './utils';
|
||||
import { allMoves, Moves as Move, MoveCategory } from "./move";
|
||||
import { allMoves, Moves as Move, MoveCategory, Moves } from "./move";
|
||||
import { Mode } from './ui/ui';
|
||||
import { Command } from "./ui/command-ui-handler";
|
||||
import { interp } from "./temp_interpreter";
|
||||
import { Stat } from "./pokemon-stat";
|
||||
import { ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, getModifierTypesForWave, ModifierType, PokemonModifierType, regenerateModifierPoolThresholds } from "./modifier";
|
||||
import PartyUiHandler from "./ui/party-ui-handler";
|
||||
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor as getPokeballTintColor, PokeballType } from "./pokeball";
|
||||
import { pokemonLevelMoves } from "./pokemon-level-moves";
|
||||
import { MoveAnim, loadMoveAnimAssets } from "./battle-anims";
|
||||
|
||||
export class BattlePhase {
|
||||
protected scene: BattleScene;
|
||||
@@ -49,7 +49,6 @@ export class EncounterPhase extends BattlePhase {
|
||||
enemyPokemon.tint(0, 0.5);
|
||||
this.doEncounter();
|
||||
});
|
||||
this.scene.load.start();
|
||||
}
|
||||
|
||||
doEncounter() {
|
||||
@@ -257,7 +256,7 @@ export class SummonPhase extends BattlePhase {
|
||||
}
|
||||
|
||||
end() {
|
||||
if (this.scene.getEnemyPokemon().shiny)
|
||||
if (this.scene.getPlayerPokemon().shiny)
|
||||
this.scene.unshiftPhase(new ShinySparklePhase(this.scene, true));
|
||||
|
||||
super.end();
|
||||
@@ -336,10 +335,7 @@ export class CommandPhase extends BattlePhase {
|
||||
start() {
|
||||
super.start();
|
||||
|
||||
//interp(this.scene);
|
||||
|
||||
this.scene.ui.setMode(Mode.COMMAND);
|
||||
console.log('add participant', this.scene.getPlayerPokemon().name)
|
||||
this.scene.currentBattle.addParticipant(this.scene.getPlayerPokemon());
|
||||
}
|
||||
|
||||
@@ -443,11 +439,35 @@ abstract class MovePhase extends BattlePhase {
|
||||
}
|
||||
if (!this.move)
|
||||
console.log(this.pokemon.moveset);
|
||||
this.scene.ui.showText(`${this.pokemon.name} used\n${this.move.getName()}!`, null, () => this.end(), 500);
|
||||
this.move.ppUsed++;
|
||||
if (this.move.getMove().category !== MoveCategory.STATUS)
|
||||
this.scene.unshiftPhase(this.getEffectPhase());
|
||||
this.scene.ui.showText(`${this.pokemon.name} used\n${this.move.getName()}!`, null, () => {
|
||||
this.move.ppUsed++;
|
||||
if (this.move.getMove().category !== MoveCategory.STATUS) {
|
||||
if (this.hitCheck())
|
||||
this.scene.unshiftPhase(this.getEffectPhase());
|
||||
else
|
||||
this.scene.unshiftPhase(new MessagePhase(this.scene, `${this.pokemon instanceof EnemyPokemon ? 'Foe ' : ''}${this.pokemon.name}'s\nattack missed!`));
|
||||
} else
|
||||
this.scene.unshiftPhase(this.getEffectPhase());
|
||||
this.end();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
hitCheck(): boolean {
|
||||
if (this.move.getMove().category !== MoveCategory.STATUS) {
|
||||
const userAccuracyLevel = 0;
|
||||
const targetEvasionLevel = 0;
|
||||
const rand = Utils.randInt(100, 1);
|
||||
let accuracyMultiplier = 1;
|
||||
if (userAccuracyLevel !== targetEvasionLevel) {
|
||||
accuracyMultiplier = userAccuracyLevel > targetEvasionLevel
|
||||
? (3 + Math.min(userAccuracyLevel - targetEvasionLevel, 6)) / 3
|
||||
: 3 / (3 + Math.min(targetEvasionLevel - userAccuracyLevel, 6));
|
||||
}
|
||||
return rand <= this.move.getMove().accuracy * accuracyMultiplier;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class PlayerMovePhase extends MovePhase {
|
||||
@@ -482,31 +502,14 @@ abstract class MoveEffectPhase extends PokemonPhase {
|
||||
start() {
|
||||
super.start();
|
||||
|
||||
if (this.hitCheck()) {
|
||||
this.getTargetPokemon().apply(this.getUserPokemon(), this.move, () => this.end());
|
||||
if (this.getTargetPokemon().hp <= 0) {
|
||||
this.scene.pushPhase(new FaintPhase(this.scene, !this.player));
|
||||
}
|
||||
} else {
|
||||
this.scene.unshiftPhase(new MessagePhase(this.scene, `${!this.player ? 'Foe ' : ''}${this.getPokemon().name}'s\nattack missed!`));
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
const user = this.getUserPokemon();
|
||||
const target = this.getTargetPokemon();
|
||||
|
||||
hitCheck(): boolean {
|
||||
if (this.move.getMove().category !== MoveCategory.STATUS) {
|
||||
const userAccuracyLevel = 0;
|
||||
const targetEvasionLevel = 0;
|
||||
const rand = Utils.randInt(100, 1);
|
||||
let accuracyMultiplier = 1;
|
||||
if (userAccuracyLevel !== targetEvasionLevel) {
|
||||
accuracyMultiplier = userAccuracyLevel > targetEvasionLevel
|
||||
? (3 + Math.min(userAccuracyLevel - targetEvasionLevel, 6)) / 3
|
||||
: 3 / (3 + Math.min(targetEvasionLevel - userAccuracyLevel, 6));
|
||||
}
|
||||
return rand <= this.move.getMove().accuracy * accuracyMultiplier;
|
||||
}
|
||||
return true;
|
||||
new MoveAnim(this.move.getMove().id as Moves, user, target).play(this.scene, () =>{
|
||||
this.getTargetPokemon().apply(this.getUserPokemon(), this.move, () => this.end());
|
||||
if (this.getTargetPokemon().hp <= 0)
|
||||
this.scene.pushPhase(new FaintPhase(this.scene, !this.player));
|
||||
});
|
||||
}
|
||||
|
||||
abstract getUserPokemon(): Pokemon;
|
||||
@@ -524,8 +527,8 @@ export class PlayerMoveEffectPhase extends MoveEffectPhase {
|
||||
}
|
||||
|
||||
getTargetPokemon(): Pokemon {
|
||||
if (this.move.getMove().category === MoveCategory.STATUS)
|
||||
return this.getUserPokemon();
|
||||
/*if (this.move.getMove().category === MoveCategory.STATUS)
|
||||
return this.getUserPokemon();*/
|
||||
return this.scene.getEnemyPokemon();
|
||||
}
|
||||
}
|
||||
@@ -540,8 +543,8 @@ export class EnemyMoveEffectPhase extends MoveEffectPhase {
|
||||
}
|
||||
|
||||
getTargetPokemon(): Pokemon {
|
||||
if (this.move.getMove().category === MoveCategory.STATUS)
|
||||
return this.getUserPokemon();
|
||||
/*if (this.move.getMove().category === MoveCategory.STATUS)
|
||||
return this.getUserPokemon();*/
|
||||
return this.scene.getPlayerPokemon();
|
||||
}
|
||||
}
|
||||
@@ -743,8 +746,11 @@ export class LearnMovePhase extends PartyMemberPokemonPhase {
|
||||
|
||||
if (pokemon.moveset.length < 4) {
|
||||
pokemon.moveset.push(new PokemonMove(this.moveId, 0, 0));
|
||||
this.scene.sound.play('level_up_fanfare');
|
||||
this.scene.ui.showText(`${pokemon.name} learned\n${Utils.toPokemonUpperCase(move.name)}!`, null, () => this.end(), null, true);
|
||||
loadMoveAnimAssets(this.scene, [ this.moveId ])
|
||||
.then(() => {
|
||||
this.scene.sound.play('level_up_fanfare');
|
||||
this.scene.ui.showText(`${pokemon.name} learned\n${Utils.toPokemonUpperCase(move.name)}!`, null, () => this.end(), null, true);
|
||||
});
|
||||
} else
|
||||
this.end();
|
||||
}
|
||||
@@ -827,7 +833,7 @@ export class AttemptCapturePhase extends BattlePhase {
|
||||
this.pokeball.setAngle(value * 27.5 * directionMultiplier);
|
||||
}
|
||||
},
|
||||
onRepeat: t => {
|
||||
onRepeat: () => {
|
||||
if (shakeCount++ < 3) {
|
||||
if (Utils.randInt(65536) < y)
|
||||
this.scene.sound.play('pb_move');
|
||||
@@ -888,7 +894,6 @@ export class AttemptCapturePhase extends BattlePhase {
|
||||
this.removePb();
|
||||
this.end();
|
||||
});
|
||||
this.scene.load.start();
|
||||
}, 0, true);
|
||||
}
|
||||
|
||||
|
||||
+15
-6
@@ -10,6 +10,7 @@ import { PokeballType } from './pokeball';
|
||||
import { Species } from './species';
|
||||
import { initAutoPlay } from './auto-play';
|
||||
import { Battle } from './battle';
|
||||
import { populateAnims } from './battle-anims';
|
||||
|
||||
export default class BattleScene extends Phaser.Scene {
|
||||
private auto: boolean;
|
||||
@@ -37,6 +38,8 @@ export default class BattleScene extends Phaser.Scene {
|
||||
public uiContainer: Phaser.GameObjects.Container;
|
||||
public ui: UI;
|
||||
|
||||
//public spritePipeline: SpritePipeline;
|
||||
|
||||
private bgm: Phaser.Sound.BaseSound;
|
||||
|
||||
private upKey: Phaser.Input.Keyboard.Key;
|
||||
@@ -72,6 +75,12 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.load.atlas(key, `images/${folder}${filenameRoot}.png`, `images/${folder}/${filenameRoot}.json`)
|
||||
}
|
||||
|
||||
loadSpritesheet(key: string, folder: string, size: integer, filename?: string) {
|
||||
if (!filename)
|
||||
filename = `${key}.png`;
|
||||
this.load.spritesheet(key, `images/${folder}/${filename}`, { frameWidth: size, frameHeight: size });
|
||||
}
|
||||
|
||||
loadSe(key: string, folder?: string, filenames?: string | string[]) {
|
||||
if (!filenames)
|
||||
filenames = `${key}.wav`;
|
||||
@@ -103,7 +112,6 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.loadImage('pbinfo_enemy', 'ui');
|
||||
this.loadImage('overlay_lv', 'ui');
|
||||
this.loadAtlas('numbers', 'ui');
|
||||
this.loadAtlas('gender', 'ui');
|
||||
this.loadAtlas('overlay_hp', 'ui');
|
||||
this.loadImage('overlay_exp', 'ui');
|
||||
this.loadImage('level_up_stats', 'ui');
|
||||
@@ -168,16 +176,18 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.loadSe('pb_catch');
|
||||
this.loadSe('pb_lock');
|
||||
|
||||
this.loadSe('m_bubble');
|
||||
this.loadSe('m_bubble3');
|
||||
this.loadSe('m_crabhammer');
|
||||
|
||||
this.loadBgm('level_up_fanfare');
|
||||
|
||||
this.load.glsl('sprite', 'shaders/sprite.frag');
|
||||
|
||||
populateAnims();
|
||||
}
|
||||
|
||||
create() {
|
||||
this.load.setBaseURL();
|
||||
|
||||
//this.spritePipeline = (this.renderer as Phaser.Renderer.WebGL.WebGLRenderer).pipelines.get('Sprite') as SpritePipeline;
|
||||
|
||||
const field = this.add.container(0, 0);
|
||||
field.setScale(6);
|
||||
|
||||
@@ -279,7 +289,6 @@ export default class BattleScene extends Phaser.Scene {
|
||||
|
||||
this.shiftPhase();
|
||||
});
|
||||
this.load.start();
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
+3
-1
@@ -1,8 +1,9 @@
|
||||
import Phaser from 'phaser';
|
||||
import BattleScene from './battle-scene';
|
||||
//import SpritePipeline from './pipelines/sprite';
|
||||
|
||||
const config: Phaser.Types.Core.GameConfig = {
|
||||
type: Phaser.AUTO,
|
||||
type: Phaser.WEBGL,
|
||||
parent: 'app',
|
||||
scale: {
|
||||
width: 1920,
|
||||
@@ -10,6 +11,7 @@ const config: Phaser.Types.Core.GameConfig = {
|
||||
mode: Phaser.Scale.FIT
|
||||
},
|
||||
pixelArt: true,
|
||||
//pipeline: { 'Sprite': SpritePipeline },
|
||||
scene: [ BattleScene ]
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -7,9 +7,9 @@ export enum MoveCategory {
|
||||
};
|
||||
|
||||
export default class Move {
|
||||
public id: integer;
|
||||
public id: Moves;
|
||||
public name: string;
|
||||
public type: integer;
|
||||
public type: Type;
|
||||
public category: integer;
|
||||
public power: integer;
|
||||
public accuracy: integer;
|
||||
|
||||
+46
-21
@@ -12,6 +12,7 @@ import { Stat } from './pokemon-stat';
|
||||
import { PokemonBaseStatModifier as PokemonBaseStatBoosterModifier, ShinyRateBoosterModifier } from './modifier';
|
||||
import { PokeballType } from './pokeball';
|
||||
import { Gender } from './gender';
|
||||
import { Anim, initAnim, loadMoveAnimAssets, moveAnims } from './battle-anims';
|
||||
|
||||
export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
public id: integer;
|
||||
@@ -98,6 +99,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.winCount = 0;
|
||||
}
|
||||
|
||||
//this.setPipeline((this.scene as BattleScene).spritePipeline);
|
||||
|
||||
this.calculateStats();
|
||||
|
||||
(scene as BattleScene).fieldUI.add(this.battleInfo);
|
||||
@@ -112,11 +115,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
const sprite = getSprite();
|
||||
const tintSprite = getSprite();
|
||||
const zoomSprite = getSprite();
|
||||
|
||||
tintSprite.setVisible(false);
|
||||
zoomSprite.setAlpha(0.5);
|
||||
|
||||
this.add(sprite);
|
||||
this.add(tintSprite);
|
||||
this.add(zoomSprite);
|
||||
|
||||
if (this.shiny) {
|
||||
const shinySparkle = this.scene.add.sprite(0, 0, 'shiny');
|
||||
@@ -140,24 +146,32 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
loadAssets(): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
(this.scene as BattleScene).loadAtlas(this.getSpriteKey(), 'pokemon', this.getAtlasPath());
|
||||
this.scene.load.audio(this.species.speciesId.toString(), `audio/cry/${this.species.speciesId}.mp3`);
|
||||
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
|
||||
const originalWarn = console.warn;
|
||||
// Ignore warnings for missing frames, because there will be a lot
|
||||
console.warn = () => {};
|
||||
const frameNames = this.scene.anims.generateFrameNames(this.getSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
|
||||
console.warn = originalWarn;
|
||||
this.scene.anims.create({
|
||||
key: this.getSpriteKey(),
|
||||
frames: frameNames,
|
||||
frameRate: 12,
|
||||
repeat: -1
|
||||
const moveIds = this.moveset.map(m => m.getMove().id);
|
||||
Promise.allSettled(moveIds.map(m => initAnim(m)))
|
||||
.then(() => {
|
||||
loadMoveAnimAssets(this.scene as BattleScene, moveIds);
|
||||
(this.scene as BattleScene).loadAtlas(this.getSpriteKey(), 'pokemon', this.getAtlasPath());
|
||||
this.scene.load.audio(this.species.speciesId.toString(), `audio/cry/${this.species.speciesId}.mp3`);
|
||||
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
|
||||
const originalWarn = console.warn;
|
||||
// Ignore warnings for missing frames, because there will be a lot
|
||||
console.warn = () => {};
|
||||
const frameNames = this.scene.anims.generateFrameNames(this.getSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
|
||||
console.warn = originalWarn;
|
||||
this.scene.anims.create({
|
||||
key: this.getSpriteKey(),
|
||||
frames: frameNames,
|
||||
frameRate: 12,
|
||||
repeat: -1
|
||||
});
|
||||
this.getSprite().play(this.getSpriteKey());
|
||||
this.getTintSprite().play(this.getSpriteKey());
|
||||
this.getZoomSprite().play(this.getSpriteKey());
|
||||
resolve();
|
||||
});
|
||||
if (!this.scene.load.isLoading())
|
||||
this.scene.load.start();
|
||||
});
|
||||
this.getSprite().play(this.getSpriteKey());
|
||||
this.getTintSprite().play(this.getSpriteKey());
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -193,6 +207,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
return this.getAt(1) as Phaser.GameObjects.Sprite;
|
||||
}
|
||||
|
||||
getZoomSprite(): Phaser.GameObjects.Sprite {
|
||||
return this.getAt(2) as Phaser.GameObjects.Sprite;
|
||||
}
|
||||
|
||||
calculateStats() {
|
||||
if (!this.stats)
|
||||
this.stats = [ 0, 0, 0, 0, 0, 0 ];
|
||||
@@ -394,8 +412,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
callback();
|
||||
}
|
||||
|
||||
cry() {
|
||||
this.scene.sound.play(this.species.speciesId.toString());
|
||||
cry(soundConfig?: Phaser.Types.Sound.SoundConfig) {
|
||||
this.scene.sound.play(this.species.speciesId.toString(), soundConfig);
|
||||
}
|
||||
|
||||
faintCry(callback: Function) {
|
||||
@@ -406,10 +424,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
rate: rate
|
||||
});
|
||||
const sprite = this.getSprite();
|
||||
const tintSprite = this.getTintSprite();
|
||||
const zoomSprite = this.getZoomSprite();
|
||||
const delay = Math.max(this.scene.sound.get(key).totalDuration * 50, 25);
|
||||
let frameProgress = 0;
|
||||
let frameThreshold: number;
|
||||
sprite.anims.pause();
|
||||
tintSprite.anims.pause();
|
||||
zoomSprite.anims.pause();
|
||||
let faintCryTimer = this.scene.time.addEvent({
|
||||
delay: delay,
|
||||
repeat: -1,
|
||||
@@ -418,8 +440,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
frameThreshold = sprite.anims.msPerFrame / rate;
|
||||
frameProgress += delay;
|
||||
while (frameProgress > frameThreshold) {
|
||||
if (sprite.anims.duration)
|
||||
if (sprite.anims.duration) {
|
||||
sprite.anims.nextFrame();
|
||||
tintSprite.anims.nextFrame();
|
||||
zoomSprite.anims.nextFrame();
|
||||
}
|
||||
frameProgress -= frameThreshold;
|
||||
}
|
||||
const crySound = this.scene.sound.get(key);
|
||||
@@ -522,7 +547,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
public aiType: AiType;
|
||||
|
||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer) {
|
||||
super(scene, -63, 86, species, level);
|
||||
super(scene, -66, 84, species, level);
|
||||
|
||||
this.aiType = AiType.SMART_RANDOM;
|
||||
}
|
||||
|
||||
+150
-19
@@ -4,6 +4,7 @@ import Pokemon, { PlayerPokemon } from "./pokemon";
|
||||
|
||||
var moveAnimsContent;
|
||||
let funcNames = [];
|
||||
let templateNames = [];
|
||||
let animFuncsContents = '';
|
||||
let animTemplateContents = '';
|
||||
|
||||
@@ -14,6 +15,7 @@ var gBattleAnimArgs = [ 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var gSprites: Sprite[] = [];
|
||||
var gTasks: Function[] = [];
|
||||
var gAnimVisualTaskCount: integer = 0;
|
||||
var onAnimsComplete: Function;
|
||||
|
||||
const MAX_BATTLERS_COUNT = 4;
|
||||
const ANIM_PLAYER_LEFT = 4;
|
||||
@@ -40,6 +42,8 @@ class SpriteTemplate {
|
||||
}
|
||||
|
||||
class Sprite {
|
||||
public spriteObj: Phaser.GameObjects.Sprite;
|
||||
|
||||
public template: SpriteTemplate;
|
||||
public callback: Function;
|
||||
|
||||
@@ -61,7 +65,9 @@ class Sprite {
|
||||
|
||||
public subpriority: integer;
|
||||
|
||||
constructor() {
|
||||
constructor(scene: BattleScene, x: integer, y: integer, image: string) {
|
||||
this.spriteObj = scene.add.sprite(x, y, image, 0);
|
||||
scene.field.add(this.spriteObj);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,8 +77,7 @@ class Sprite {
|
||||
callback(sprite);
|
||||
}*/
|
||||
|
||||
function CreateSprite(template: SpriteTemplate, target: AnimTarget, subpriorityOffset: integer, args: any[])
|
||||
{
|
||||
function CreateSprite(template: SpriteTemplate, target: AnimTarget, subpriorityOffset: integer, args: any[]) {
|
||||
/*s32 i;
|
||||
const struct SpriteTemplate *template;
|
||||
u8 argVar;
|
||||
@@ -134,15 +139,16 @@ function CreateSprite(template: SpriteTemplate, target: AnimTarget, subpriorityO
|
||||
gAnimVisualTaskCount++;
|
||||
}
|
||||
|
||||
function CreateNewSprite(index: integer, template: SpriteTemplate, x: integer, y: integer, subpriority: integer): integer {
|
||||
const sprite = new Sprite();
|
||||
function CreateNewSprite(index: integer, template: SpriteTemplate, x: integer, y: integer, subpriority: integer): Sprite {
|
||||
const sprite = new Sprite(scene, x, y, template.imageName.toLowerCase());
|
||||
|
||||
sprite.subpriority = subpriority;
|
||||
sprite.template = template;
|
||||
sprite.callback = template.callback;
|
||||
sprite.x = x;
|
||||
sprite.y = y;
|
||||
sprite.callback();
|
||||
|
||||
gSprites[index] = sprite;
|
||||
|
||||
return sprite;
|
||||
/*
|
||||
struct Sprite *sprite = &gSprites[index];
|
||||
|
||||
@@ -194,6 +200,33 @@ function CreateNewSprite(index: integer, template: SpriteTemplate, x: integer, y
|
||||
}
|
||||
|
||||
function CreateSpriteAndAnimate(template: SpriteTemplate, x: integer, y: integer, subpriority: integer) {
|
||||
const sprite = CreateNewSprite(gSprites.length, template, x, y, subpriority);
|
||||
|
||||
console.log(template.imageName.toLowerCase());
|
||||
|
||||
const animateSpriteFrame = (sprite: Sprite) => {
|
||||
scene.time.delayedCall(16, () => {
|
||||
sprite.callback(sprite);
|
||||
if (!sprite.data[0]) {
|
||||
const originalOnAnimsComplete = onAnimsComplete;
|
||||
if (originalOnAnimsComplete) {
|
||||
onAnimsComplete = null;
|
||||
originalOnAnimsComplete();
|
||||
}
|
||||
return;
|
||||
}
|
||||
console.log(sprite.data)
|
||||
sprite.spriteObj.setPosition(sprite.x, sprite.y);
|
||||
animateSpriteFrame(sprite);
|
||||
});
|
||||
};
|
||||
|
||||
sprite.callback(sprite);
|
||||
animateSpriteFrame(sprite);
|
||||
|
||||
return gSprites.length - 1;
|
||||
|
||||
//gSprites.push(gSprites.length);
|
||||
/*u8 i;
|
||||
|
||||
for (i = 0; i < MAX_SPRITES; i++)
|
||||
@@ -248,12 +281,33 @@ function CreateVisualTask(taskFunc: Function, taskPriority: integer, args: any[]
|
||||
gAnimVisualTaskCount++;
|
||||
}
|
||||
|
||||
function DestroyAnimSprite(sprite: Sprite) {
|
||||
|
||||
//FreeSpriteOamMatrix(sprite);
|
||||
DestroySprite(sprite);
|
||||
gAnimVisualTaskCount--;
|
||||
}
|
||||
|
||||
function DestroyAnimVisualTask(taskId: integer)
|
||||
{
|
||||
DestroyTask(taskId);
|
||||
gAnimVisualTaskCount--;
|
||||
}
|
||||
|
||||
function DestroySprite(sprite:Sprite) {
|
||||
/*if (sprite->inUse)
|
||||
{
|
||||
if (!sprite->usingSheet)
|
||||
{
|
||||
u16 i;
|
||||
u16 tileEnd = (sprite->images->size / TILE_SIZE_4BPP) + sprite->oam.tileNum;
|
||||
for (i = sprite->oam.tileNum; i < tileEnd; i++)
|
||||
FREE_SPRITE_TILE(i);
|
||||
}
|
||||
ResetSprite(sprite);
|
||||
}*/
|
||||
}
|
||||
|
||||
function CreateTask(func: Function, priority: integer): integer
|
||||
{
|
||||
const taskId = gTasks.length;
|
||||
@@ -273,7 +327,7 @@ function DestroyTask(taskId: integer) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gTasks[taskId].next == TAIL_SENTINEL)
|
||||
if (gdTasks[taskId].next == TAIL_SENTINEL)
|
||||
{
|
||||
gTasks[gTasks[taskId].prev].next = TAIL_SENTINEL;
|
||||
}
|
||||
@@ -372,18 +426,32 @@ enum BattleSide {
|
||||
ENEMY
|
||||
}
|
||||
|
||||
/*function AnimateSprite(sprite: Sprite) {
|
||||
sAnimFuncs[sprite.animBeginning](sprite);
|
||||
|
||||
if (!gAffineAnimsDisabled)
|
||||
sAffineAnimFuncs[sprite->affineAnimBeginning](sprite);
|
||||
}*/
|
||||
|
||||
function StartSpriteAffineAnim(sprite: Sprite, animNum: integer) {
|
||||
/*u8 matrixNum = GetSpriteMatrixNum(sprite);
|
||||
AffineAnimStateStartAnim(matrixNum, animNum);
|
||||
sprite->affineAnimBeginning = TRUE;
|
||||
sprite->affineAnimEnded = FALSE;*/
|
||||
}
|
||||
|
||||
function GetBattlerSpriteCoord(target: Pokemon, coordType: BattlerCoord): integer {
|
||||
console.log('TEST1');
|
||||
console.log('TEST1', target.y, target.getSprite().height);
|
||||
|
||||
switch (coordType) {
|
||||
case BattlerCoord.X:
|
||||
case BattlerCoord.X_2:
|
||||
return target.x;
|
||||
case BattlerCoord.Y:
|
||||
return target.y;
|
||||
return target.y - target.getSprite().height / 2;
|
||||
case BattlerCoord.Y_PIC_OFFSET:
|
||||
case BattlerCoord.Y_PIC_OFFSET_DEFAULT:
|
||||
return target.y;
|
||||
return target.y - target.getSprite().height / 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,9 +480,9 @@ function GetBattlerSpriteCoord2(target: Pokemon, coordType: BattlerCoord): integ
|
||||
case BattlerCoord.X:
|
||||
return target.x;
|
||||
case BattlerCoord.Y:
|
||||
return target.y;
|
||||
return target.y - target.getSprite().height / 2;
|
||||
case BattlerCoord.Y_PIC_OFFSET:
|
||||
return target.y;
|
||||
return target.y - target.getSprite().height / 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,6 +514,51 @@ function SetCallbackToStoredInData6(sprite: Sprite)
|
||||
//sprite->callback = (void (*)(struct Sprite *))callback;
|
||||
}
|
||||
|
||||
function AnimTranslateLinear(sprite: Sprite): boolean
|
||||
{
|
||||
let v1: integer;
|
||||
let v2: integer;
|
||||
let x: integer
|
||||
let y: integer;
|
||||
|
||||
if (!sprite.data[0])
|
||||
return true;
|
||||
|
||||
v1 = sprite.data[1];
|
||||
v2 = sprite.data[2];
|
||||
x = sprite.data[3];
|
||||
y = sprite.data[4];
|
||||
x += v1;
|
||||
y += v2;
|
||||
|
||||
console.log('XY', x, y)
|
||||
|
||||
if (v1 & 1)
|
||||
sprite.x2 = -(x >> 8);
|
||||
else
|
||||
sprite.x2 = x >> 8;
|
||||
|
||||
if (v2 & 1)
|
||||
sprite.y2 = -(y >> 8);
|
||||
else
|
||||
sprite.y2 = y >> 8;
|
||||
|
||||
sprite.data[3] = x;
|
||||
sprite.data[4] = y;
|
||||
sprite.data[0]--;
|
||||
return false;
|
||||
}
|
||||
|
||||
function Sin(index: integer, amplitude: integer): integer
|
||||
{
|
||||
return (amplitude * Math.sin(index * (Math.PI / 128))) >> 8;
|
||||
}
|
||||
|
||||
function Cos(index: integer, amplitude: integer): integer
|
||||
{
|
||||
return (amplitude * Math.cos(index * (Math.PI / 128))) >> 8;
|
||||
}
|
||||
|
||||
function GetBattlerSide(pokemon: Pokemon): BattleSide
|
||||
{
|
||||
return pokemon instanceof PlayerPokemon ? BattleSide.PLAYER : BattleSide.ENEMY;
|
||||
@@ -463,7 +576,6 @@ const linePatterns = [
|
||||
} ],
|
||||
[ /([\t ]+)createsprite (.*?), (.*?), (.*?)(?:, (.*?))?$/, res => {
|
||||
let ret = res[0];
|
||||
const args = res[5].split(', ');
|
||||
|
||||
let search = `const struct SpriteTemplate ${res[2]}`;
|
||||
let i = animTemplates.indexOf(search);
|
||||
@@ -478,10 +590,14 @@ const linePatterns = [
|
||||
search = '.callback = ';
|
||||
i = template.indexOf(search);
|
||||
const animFuncName = template.slice(i + search.length, template.indexOf(',', i));
|
||||
console.log(imageName, animFuncName)
|
||||
console.log(imageName, animFuncName);
|
||||
|
||||
if (templateNames.indexOf(res[2]) === -1) {
|
||||
animTemplateContents += `const ${res[2]} = new SpriteTemplate('${imageName}', ${affineAnimName !== 'gDummySpriteAffineAnimTable' && false ? affineAnimName : 'null'}, ${animFuncName});\n`;
|
||||
templateNames.push(res[2]);
|
||||
}
|
||||
|
||||
if (funcNames.indexOf(animFuncName) === -1) {
|
||||
animTemplateContents += `const ${res[2]} = new SpriteTemplate('${imageName}', ${affineAnimName !== 'gDummySpriteAffineAnimTable' && false ? affineAnimName : 'null'}, ${animFuncName});\n`
|
||||
|
||||
search = `void ${animFuncName}(struct Sprite *sprite`;
|
||||
i = animTemplates.indexOf(search);
|
||||
@@ -517,6 +633,7 @@ const linePatterns = [
|
||||
[ /([\t ]+)delay (\d+)/, res => {
|
||||
return `${res[1]}delay ${Math.round(16.6666666667 * parseInt(res[2]))}`;
|
||||
} ],
|
||||
[ /([\t ]+waitforvisualfinish)/, '$1' ],
|
||||
[ /splitbgprio.*?$/, '' ],
|
||||
[ /ANIM\_TARGET/g, 'AnimTarget.TARGET' ],
|
||||
[ /ANIM\_ATTACKER/g, 'AnimTarget.ATTACKER' ]
|
||||
@@ -550,16 +667,19 @@ const funcLinePatterns = [
|
||||
[ /struct Sprite \*sprite/, 'sprite: Sprite' ],
|
||||
[ /&sprite/g, 'sprite' ],
|
||||
[ /^u8 ([A-Z][A-Za-z\_0-9]+)\((.*?)\)/, 'function $1($2): integer' ],
|
||||
[ /^bool8 ([A-Z][A-Za-z\_0-9]+)\((.*?)\)/, 'function $1($2): boolean' ],
|
||||
[ /^(?:static )?void /, 'function ' ],
|
||||
[ /TRUE/g, 'true' ],
|
||||
[ /FALSE/g, 'false' ],
|
||||
[ /ANIM_(ATTACKER|TARGET)/g, 'AnimTarget.$1' ],
|
||||
[ /BATTLER\_COORD\_/g, 'BattlerCoord.' ],
|
||||
[ /B\_SIDE\_PLAYER/g, 'BattleSide.PLAYER' ],
|
||||
[ /B\_SIDE\_OPPONENT/g, 'BattleSide.ENEMY' ],
|
||||
[ /abs\(/g, 'Math.abs(' ],
|
||||
[ /\(integer\)/g, '' ],
|
||||
[ /^([\t ]+)\*([a-zA-Z\_]+) =/, '$1$2 =' ],
|
||||
[ /([\t ]+)([a-zA-Z\_]+) = (.*?);/, '$1$2 = $3;' ],
|
||||
[ /^[\t ]+([^ ]+ =|return|if \() ([A-Z][a-zA-Z0-9\_]+)(?:\((.*?)\))?(\))?;$/, res => {
|
||||
[ /^[\t ]+([^ ]+ =|return|if \() ?([A-Z][a-zA-Z0-9\_]+)(?:\((.*?)\))?(\))?;?$/, res => {
|
||||
const funcName = res[2];
|
||||
if (funcNames.indexOf(funcName) === -1) {
|
||||
const searchRes = new RegExp(`\n\n(?:static )?([^ ]+) ${funcName}\\((.*?)\\)\n\{`).exec(animTemplates);
|
||||
@@ -656,10 +776,21 @@ export function interp(sceneIn) {
|
||||
console.log(contIndex)
|
||||
if (!contMatch)
|
||||
console.log(output.slice(delayMatch.index))
|
||||
console.log(delayMatch)
|
||||
output = output.slice(0, delayMatch.index) + delayMatch[1] + `scene.time.delayedCall(${delayMatch[2]}, () => {` + output.slice(contIndex, contMatch.index + contIndex).replace(/\n/g, '\n\t') + '\n' + delayMatch[1] + '});' + output.slice(contMatch.index + contIndex);
|
||||
}
|
||||
|
||||
const visualWaitPattern = /([\t ]+)waitforvisualfinish/;
|
||||
let visualWaitMatch;
|
||||
while ((visualWaitMatch = visualWaitPattern.exec(output))) {
|
||||
const contIndex = visualWaitMatch.index + visualWaitMatch[1].length + 19;
|
||||
const contMatch = /\n\}/.exec(output.slice(contIndex));
|
||||
console.log(contIndex)
|
||||
if (!contMatch)
|
||||
console.log(output.slice(visualWaitMatch.index))
|
||||
console.log(visualWaitMatch)
|
||||
output = output.slice(0, visualWaitMatch.index) + visualWaitMatch[1] + `onAnimsComplete = () => {` + output.slice(contIndex, contMatch.index + contIndex).replace(/\n/g, '\n\t') + '\n' + visualWaitMatch[1] + '};' + output.slice(contMatch.index + contIndex);
|
||||
}
|
||||
|
||||
output += '\ndoMoveAnim_WATER_GUN();\n\n';
|
||||
|
||||
console.log(output, animTemplateContents, animFuncsContents)
|
||||
|
||||
Reference in new issue
Block a user