mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-18 22:32:32 +02:00
Merge branch 'beta' into pr-illusion
This commit is contained in:
commit
86114a9ce0
@ -1,7 +1,20 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move";
|
import {
|
||||||
|
AttackMove,
|
||||||
|
BeakBlastHeaderAttr,
|
||||||
|
DelayedAttackAttr,
|
||||||
|
MoveFlags,
|
||||||
|
SelfStatusMove,
|
||||||
|
allMoves,
|
||||||
|
} from "./move";
|
||||||
import type Pokemon from "../field/pokemon";
|
import type Pokemon from "../field/pokemon";
|
||||||
import * as Utils from "../utils";
|
import {
|
||||||
|
type nil,
|
||||||
|
getFrameMs,
|
||||||
|
getEnumKeys,
|
||||||
|
getEnumValues,
|
||||||
|
animationFileName,
|
||||||
|
} from "../utils";
|
||||||
import type { BattlerIndex } from "../battle";
|
import type { BattlerIndex } from "../battle";
|
||||||
import type { Element } from "json-stable-stringify";
|
import type { Element } from "json-stable-stringify";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
@ -401,7 +414,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
|
|||||||
if (Object.keys(tweenProps).length) {
|
if (Object.keys(tweenProps).length) {
|
||||||
globalScene.tweens.add(Object.assign({
|
globalScene.tweens.add(Object.assign({
|
||||||
targets: moveAnim.bgSprite,
|
targets: moveAnim.bgSprite,
|
||||||
duration: Utils.getFrameMs(this.duration * 3)
|
duration: getFrameMs(this.duration * 3)
|
||||||
}, tweenProps));
|
}, tweenProps));
|
||||||
}
|
}
|
||||||
return this.duration * 2;
|
return this.duration * 2;
|
||||||
@ -437,7 +450,7 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
|||||||
|
|
||||||
globalScene.tweens.add({
|
globalScene.tweens.add({
|
||||||
targets: moveAnim.bgSprite,
|
targets: moveAnim.bgSprite,
|
||||||
duration: Utils.getFrameMs(this.duration * 3)
|
duration: getFrameMs(this.duration * 3)
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.duration * 2;
|
return this.duration * 2;
|
||||||
@ -455,8 +468,8 @@ export const encounterAnims = new Map<EncounterAnim, AnimConfig>();
|
|||||||
|
|
||||||
export function initCommonAnims(): Promise<void> {
|
export function initCommonAnims(): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const commonAnimNames = Utils.getEnumKeys(CommonAnim);
|
const commonAnimNames = getEnumKeys(CommonAnim);
|
||||||
const commonAnimIds = Utils.getEnumValues(CommonAnim);
|
const commonAnimIds = getEnumValues(CommonAnim);
|
||||||
const commonAnimFetches: Promise<Map<CommonAnim, AnimConfig>>[] = [];
|
const commonAnimFetches: Promise<Map<CommonAnim, AnimConfig>>[] = [];
|
||||||
for (let ca = 0; ca < commonAnimIds.length; ca++) {
|
for (let ca = 0; ca < commonAnimIds.length; ca++) {
|
||||||
const commonAnimId = commonAnimIds[ca];
|
const commonAnimId = commonAnimIds[ca];
|
||||||
@ -493,7 +506,7 @@ export function initMoveAnim(move: Moves): Promise<void> {
|
|||||||
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP;
|
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP;
|
||||||
|
|
||||||
const fetchAnimAndResolve = (move: Moves) => {
|
const fetchAnimAndResolve = (move: Moves) => {
|
||||||
globalScene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`)
|
globalScene.cachedFetch(`./battle-anims/${animationFileName(move)}.json`)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const contentType = response.headers.get("content-type");
|
const contentType = response.headers.get("content-type");
|
||||||
if (!response.ok || contentType?.indexOf("application/json") === -1) {
|
if (!response.ok || contentType?.indexOf("application/json") === -1) {
|
||||||
@ -550,7 +563,7 @@ function useDefaultAnim(move: Moves, defaultMoveAnim: Moves) {
|
|||||||
* @remarks use {@linkcode useDefaultAnim} to use a default animation
|
* @remarks use {@linkcode useDefaultAnim} to use a default animation
|
||||||
*/
|
*/
|
||||||
function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
|
function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
|
||||||
const moveName = Utils.animationFileName(move);
|
const moveName = animationFileName(move);
|
||||||
console.warn(`Could not load animation file for move '${moveName}'`, ...optionalParams);
|
console.warn(`Could not load animation file for move '${moveName}'`, ...optionalParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,7 +573,7 @@ function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
|
|||||||
*/
|
*/
|
||||||
export async function initEncounterAnims(encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
|
export async function initEncounterAnims(encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
|
||||||
const anims = Array.isArray(encounterAnim) ? encounterAnim : [ encounterAnim ];
|
const anims = Array.isArray(encounterAnim) ? encounterAnim : [ encounterAnim ];
|
||||||
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
|
const encounterAnimNames = getEnumKeys(EncounterAnim);
|
||||||
const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = [];
|
const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = [];
|
||||||
for (const anim of anims) {
|
for (const anim of anims) {
|
||||||
if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) {
|
if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) {
|
||||||
@ -922,7 +935,7 @@ export abstract class BattleAnim {
|
|||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
globalScene.tweens.addCounter({
|
globalScene.tweens.addCounter({
|
||||||
duration: Utils.getFrameMs(3),
|
duration: getFrameMs(3),
|
||||||
repeat: anim?.frames.length ?? 0,
|
repeat: anim?.frames.length ?? 0,
|
||||||
onRepeat: () => {
|
onRepeat: () => {
|
||||||
if (!f) {
|
if (!f) {
|
||||||
@ -994,47 +1007,39 @@ export abstract class BattleAnim {
|
|||||||
const moveSprite = sprites[graphicIndex];
|
const moveSprite = sprites[graphicIndex];
|
||||||
if (spritePriorities[graphicIndex] !== frame.priority) {
|
if (spritePriorities[graphicIndex] !== frame.priority) {
|
||||||
spritePriorities[graphicIndex] = frame.priority;
|
spritePriorities[graphicIndex] = frame.priority;
|
||||||
|
/** Move the position that the moveSprite is rendered in based on the priority.
|
||||||
|
* @param priority The priority level to draw the sprite.
|
||||||
|
* - 0: Draw the sprite in front of the pokemon on the field.
|
||||||
|
* - 1: Draw the sprite in front of the user pokemon.
|
||||||
|
* - 2: Draw the sprite in front of its `bgSprite` (if it has one), or its
|
||||||
|
* `AnimFocus` (if that is user/target), otherwise behind everything.
|
||||||
|
* - 3: Draw the sprite behind its `AnimFocus` (if that is user/target), otherwise in front of everything.
|
||||||
|
*/
|
||||||
const setSpritePriority = (priority: number) => {
|
const setSpritePriority = (priority: number) => {
|
||||||
switch (priority) {
|
/** The sprite we are moving the moveSprite in relation to */
|
||||||
case 0:
|
let targetSprite: Phaser.GameObjects.GameObject | nil;
|
||||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, globalScene.getEnemyPokemon(false) ?? globalScene.getPlayerPokemon(false)!); // TODO: is this bang correct?
|
/** The method that is being used to move the sprite.*/
|
||||||
break;
|
let moveFunc: ((sprite: Phaser.GameObjects.GameObject, target: Phaser.GameObjects.GameObject) => void) |
|
||||||
case 1:
|
((sprite: Phaser.GameObjects.GameObject) => void) = globalScene.field.bringToTop;
|
||||||
globalScene.field.moveTo(moveSprite, globalScene.field.getAll().length - 1);
|
|
||||||
break;
|
if (priority === 0) { // Place the sprite in front of the pokemon on the field.
|
||||||
case 2:
|
targetSprite = globalScene.getEnemyField().find(p => p) ?? globalScene.getPlayerField().find(p => p);
|
||||||
switch (frame.focus) {
|
console.log(typeof targetSprite);
|
||||||
case AnimFocus.USER:
|
moveFunc = globalScene.field.moveBelow;
|
||||||
if (this.bgSprite) {
|
} else if (priority === 2 && this.bgSprite) {
|
||||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite);
|
moveFunc = globalScene.field.moveAbove;
|
||||||
} else {
|
targetSprite = this.bgSprite;
|
||||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
} else if (priority === 2 || priority === 3) {
|
||||||
}
|
moveFunc = priority === 2 ? globalScene.field.moveBelow : globalScene.field.moveAbove;
|
||||||
break;
|
if (frame.focus === AnimFocus.USER) {
|
||||||
case AnimFocus.TARGET:
|
targetSprite = this.user;
|
||||||
globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
} else if (frame.focus === AnimFocus.TARGET) {
|
||||||
break;
|
targetSprite = this.target;
|
||||||
default:
|
}
|
||||||
setSpritePriority(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
switch (frame.focus) {
|
|
||||||
case AnimFocus.USER:
|
|
||||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
|
||||||
break;
|
|
||||||
case AnimFocus.TARGET:
|
|
||||||
globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setSpritePriority(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setSpritePriority(1);
|
|
||||||
}
|
}
|
||||||
|
// If target sprite is not undefined and exists in the field container, then move the sprite using the moveFunc.
|
||||||
|
// Otherwise, default to just bringing it to the top.
|
||||||
|
targetSprite && globalScene.field.exists(targetSprite) ? moveFunc.bind(globalScene.field)(moveSprite as Phaser.GameObjects.GameObject, targetSprite) : globalScene.field.bringToTop(moveSprite as Phaser.GameObjects.GameObject);
|
||||||
};
|
};
|
||||||
setSpritePriority(frame.priority);
|
setSpritePriority(frame.priority);
|
||||||
}
|
}
|
||||||
@ -1052,11 +1057,13 @@ export abstract class BattleAnim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anim?.frameTimedEvents.has(f)) {
|
if (anim?.frameTimedEvents.has(f)) {
|
||||||
for (const event of anim.frameTimedEvents.get(f)!) { // TODO: is this bang correct?
|
const base = anim.frames.length - f;
|
||||||
r = Math.max((anim.frames.length - f) + event.execute(this), r);
|
// Bang is correct due to `has` check above, which cannot return true for an undefined / null `f`
|
||||||
|
for (const event of anim.frameTimedEvents.get(f)!) {
|
||||||
|
r = Math.max(base + event.execute(this), r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const targets = Utils.getEnumValues(AnimFrameTarget);
|
const targets = getEnumValues(AnimFrameTarget);
|
||||||
for (const i of targets) {
|
for (const i of targets) {
|
||||||
const count = i === AnimFrameTarget.GRAPHIC ? g : i === AnimFrameTarget.USER ? u : t;
|
const count = i === AnimFrameTarget.GRAPHIC ? g : i === AnimFrameTarget.USER ? u : t;
|
||||||
if (count < spriteCache[i].length) {
|
if (count < spriteCache[i].length) {
|
||||||
@ -1084,7 +1091,7 @@ export abstract class BattleAnim {
|
|||||||
}
|
}
|
||||||
if (r) {
|
if (r) {
|
||||||
globalScene.tweens.addCounter({
|
globalScene.tweens.addCounter({
|
||||||
duration: Utils.getFrameMs(r),
|
duration: getFrameMs(r),
|
||||||
onComplete: () => cleanUpAndComplete()
|
onComplete: () => cleanUpAndComplete()
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -1166,7 +1173,7 @@ export abstract class BattleAnim {
|
|||||||
let existingFieldSprites = globalScene.field.getAll().slice(0);
|
let existingFieldSprites = globalScene.field.getAll().slice(0);
|
||||||
|
|
||||||
globalScene.tweens.addCounter({
|
globalScene.tweens.addCounter({
|
||||||
duration: Utils.getFrameMs(3) * frameTimeMult,
|
duration: getFrameMs(3) * frameTimeMult,
|
||||||
repeat: anim!.frames.length,
|
repeat: anim!.frames.length,
|
||||||
onRepeat: () => {
|
onRepeat: () => {
|
||||||
existingFieldSprites = globalScene.field.getAll().slice(0);
|
existingFieldSprites = globalScene.field.getAll().slice(0);
|
||||||
@ -1215,11 +1222,12 @@ export abstract class BattleAnim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anim?.frameTimedEvents.get(frameCount)) {
|
if (anim?.frameTimedEvents.get(frameCount)) {
|
||||||
|
const base = anim.frames.length - frameCount;
|
||||||
for (const event of anim.frameTimedEvents.get(frameCount)!) {
|
for (const event of anim.frameTimedEvents.get(frameCount)!) {
|
||||||
totalFrames = Math.max((anim.frames.length - frameCount) + event.execute(this, frameTimedEventPriority), totalFrames);
|
totalFrames = Math.max(base + event.execute(this, frameTimedEventPriority), totalFrames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const targets = Utils.getEnumValues(AnimFrameTarget);
|
const targets = getEnumValues(AnimFrameTarget);
|
||||||
for (const i of targets) {
|
for (const i of targets) {
|
||||||
const count = graphicFrameCount;
|
const count = graphicFrameCount;
|
||||||
if (count < spriteCache[i].length) {
|
if (count < spriteCache[i].length) {
|
||||||
@ -1244,7 +1252,7 @@ export abstract class BattleAnim {
|
|||||||
}
|
}
|
||||||
if (totalFrames) {
|
if (totalFrames) {
|
||||||
globalScene.tweens.addCounter({
|
globalScene.tweens.addCounter({
|
||||||
duration: Utils.getFrameMs(totalFrames),
|
duration: getFrameMs(totalFrames),
|
||||||
onComplete: () => cleanUpAndComplete()
|
onComplete: () => cleanUpAndComplete()
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -1342,15 +1350,15 @@ export class EncounterBattleAnim extends BattleAnim {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function populateAnims() {
|
export async function populateAnims() {
|
||||||
const commonAnimNames = Utils.getEnumKeys(CommonAnim).map(k => k.toLowerCase());
|
const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase());
|
||||||
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/\_/g, ""));
|
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/\_/g, ""));
|
||||||
const commonAnimIds = Utils.getEnumValues(CommonAnim) as CommonAnim[];
|
const commonAnimIds = getEnumValues(CommonAnim) as CommonAnim[];
|
||||||
const chargeAnimNames = Utils.getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
|
const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
|
||||||
const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/\_/g, " "));
|
const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/\_/g, " "));
|
||||||
const chargeAnimIds = Utils.getEnumValues(ChargeAnim) as ChargeAnim[];
|
const chargeAnimIds = getEnumValues(ChargeAnim) as ChargeAnim[];
|
||||||
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
|
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
|
||||||
const moveNameToId = {};
|
const moveNameToId = {};
|
||||||
for (const move of Utils.getEnumValues(Moves).slice(1)) {
|
for (const move of getEnumValues(Moves).slice(1)) {
|
||||||
const moveName = Moves[move].toUpperCase().replace(/\_/g, "");
|
const moveName = Moves[move].toUpperCase().replace(/\_/g, "");
|
||||||
moveNameToId[moveName] = move;
|
moveNameToId[moveName] = move;
|
||||||
}
|
}
|
||||||
|
@ -1407,10 +1407,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Checks if the {@linkcode Pokemon} has is the specified {@linkcode Species} or is fused with it.
|
* Checks if the {@linkcode Pokemon} has is the specified {@linkcode Species} or is fused with it.
|
||||||
* @param species the pokemon {@linkcode Species} to check
|
* @param species the pokemon {@linkcode Species} to check
|
||||||
|
* @param formKey If provided, requires the species to be in that form
|
||||||
* @returns `true` if the pokemon is the species or is fused with it, `false` otherwise
|
* @returns `true` if the pokemon is the species or is fused with it, `false` otherwise
|
||||||
*/
|
*/
|
||||||
hasSpecies(species: Species): boolean {
|
hasSpecies(species: Species, formKey?: string): boolean {
|
||||||
return this.species.speciesId === species || this.fusionSpecies?.speciesId === species;
|
if (Utils.isNullOrUndefined(formKey)) {
|
||||||
|
return this.species.speciesId === species || this.fusionSpecies?.speciesId === species;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.species.speciesId === species && this.getFormKey() === formKey) || (this.fusionSpecies?.speciesId === species && this.getFusionFormKey() === formKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract isBoss(): boolean;
|
abstract isBoss(): boolean;
|
||||||
@ -3390,6 +3395,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!));
|
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isMega(): boolean {
|
||||||
|
const megaForms = [ SpeciesFormKey.MEGA, SpeciesFormKey.MEGA_X, SpeciesFormKey.MEGA_Y, SpeciesFormKey.PRIMAL ] as string[];
|
||||||
|
return megaForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && megaForms.includes(this.getFusionFormKey()!));
|
||||||
|
}
|
||||||
|
|
||||||
canAddTag(tagType: BattlerTagType): boolean {
|
canAddTag(tagType: BattlerTagType): boolean {
|
||||||
if (this.getTag(tagType)) {
|
if (this.getTag(tagType)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -10,6 +10,7 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import { TerastallizeAccessModifier } from "#app/modifier/modifier";
|
import { TerastallizeAccessModifier } from "#app/modifier/modifier";
|
||||||
import { Type } from "#app/enums/type";
|
import { Type } from "#app/enums/type";
|
||||||
import { getTypeRgb } from "#app/data/type";
|
import { getTypeRgb } from "#app/data/type";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
|
||||||
export enum Command {
|
export enum Command {
|
||||||
FIGHT = 0,
|
FIGHT = 0,
|
||||||
@ -180,9 +181,11 @@ export default class CommandUiHandler extends UiHandler {
|
|||||||
|
|
||||||
canTera(): boolean {
|
canTera(): boolean {
|
||||||
const hasTeraMod = !!globalScene.getModifiers(TerastallizeAccessModifier).length;
|
const hasTeraMod = !!globalScene.getModifiers(TerastallizeAccessModifier).length;
|
||||||
|
const activePokemon = globalScene.getField()[this.fieldIndex];
|
||||||
|
const isBlockedForm = activePokemon.isMega() || activePokemon.isMax() || activePokemon.hasSpecies(Species.NECROZMA, "ultra");
|
||||||
const currentTeras = globalScene.arena.playerTerasUsed;
|
const currentTeras = globalScene.arena.playerTerasUsed;
|
||||||
const plannedTera = globalScene.currentBattle.preTurnCommands[0]?.command === Command.TERA && this.fieldIndex > 0 ? 1 : 0;
|
const plannedTera = globalScene.currentBattle.preTurnCommands[0]?.command === Command.TERA && this.fieldIndex > 0 ? 1 : 0;
|
||||||
return hasTeraMod && (currentTeras + plannedTera) < 1;
|
return hasTeraMod && !isBlockedForm && (currentTeras + plannedTera) < 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleTeraButton() {
|
toggleTeraButton() {
|
||||||
|
Loading…
Reference in New Issue
Block a user