mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-13 11:52:18 +02:00
Compare commits
16 Commits
751a3d1e49
...
4277439a2d
Author | SHA1 | Date | |
---|---|---|---|
|
4277439a2d | ||
|
5f7c593365 | ||
|
1e283afc84 | ||
|
32fadf8cb6 | ||
|
840ac9f53f | ||
|
623c05a3df | ||
|
564add66d2 | ||
|
dc828c6801 | ||
|
5e7a9b0872 | ||
|
416d666b30 | ||
|
815b37d23c | ||
|
c8b77cffc1 | ||
|
919760e2e1 | ||
|
410b33a44f | ||
|
3985c63dad | ||
|
74bf42b4b7 |
1
.github/workflows/deploy.yml
vendored
1
.github/workflows/deploy.yml
vendored
@ -6,6 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.repository == 'pagefaultgames/pokerogue'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
25
src/battle-scene-events.ts
Normal file
25
src/battle-scene-events.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import Move from "./data/move";
|
||||
|
||||
export enum BattleSceneEventType {
|
||||
MOVE_USED = "onMoveUsed"
|
||||
}
|
||||
|
||||
/**
|
||||
* Container class for `onMoveUsed` events
|
||||
* @extends Event
|
||||
*/
|
||||
export class MoveUsedEvent extends Event {
|
||||
/** The ID of the {@linkcode Pokemon} that used the {@linkcode Move} */
|
||||
public userId: number;
|
||||
/** The {@linkcode Move} used */
|
||||
public move: Move;
|
||||
/** The amount of PP used on the {@linkcode Move} this turn */
|
||||
public ppUsed: number;
|
||||
constructor(userId: number, move: Move, ppUsed: number) {
|
||||
super(BattleSceneEventType.MOVE_USED);
|
||||
|
||||
this.userId = userId;
|
||||
this.move = move;
|
||||
this.ppUsed = ppUsed;
|
||||
}
|
||||
}
|
@ -151,7 +151,8 @@ export default class BattleScene extends SceneBase {
|
||||
public money: integer;
|
||||
public pokemonInfoContainer: PokemonInfoContainer;
|
||||
private party: PlayerPokemon[];
|
||||
private waveCountText: Phaser.GameObjects.Text;
|
||||
/** Combined Biome and Wave count text */
|
||||
private biomeWaveText: Phaser.GameObjects.Text;
|
||||
private moneyText: Phaser.GameObjects.Text;
|
||||
private scoreText: Phaser.GameObjects.Text;
|
||||
private luckLabelText: Phaser.GameObjects.Text;
|
||||
@ -184,6 +185,14 @@ export default class BattleScene extends SceneBase {
|
||||
public rngSeedOverride: string = "";
|
||||
public rngOffset: integer = 0;
|
||||
|
||||
/**
|
||||
* Allows subscribers to listen for events
|
||||
*
|
||||
* Current Events:
|
||||
* - {@linkcode BattleSceneEventType.MOVE_USED} {@linkcode MoveUsedEvent}
|
||||
*/
|
||||
public readonly eventTarget: EventTarget = new EventTarget();
|
||||
|
||||
constructor() {
|
||||
super("battle");
|
||||
this.phaseQueue = [];
|
||||
@ -342,9 +351,9 @@ export default class BattleScene extends SceneBase {
|
||||
this.candyBar.setup();
|
||||
this.fieldUI.add(this.candyBar);
|
||||
|
||||
this.waveCountText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, startingWave.toString(), TextStyle.BATTLE_INFO);
|
||||
this.waveCountText.setOrigin(1, 0);
|
||||
this.fieldUI.add(this.waveCountText);
|
||||
this.biomeWaveText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, startingWave.toString(), TextStyle.BATTLE_INFO);
|
||||
this.biomeWaveText.setOrigin(1, 0);
|
||||
this.fieldUI.add(this.biomeWaveText);
|
||||
|
||||
this.moneyText = addTextObject(this, (this.game.canvas.width / 6) - 2, 0, "", TextStyle.MONEY);
|
||||
this.moneyText.setOrigin(1, 0);
|
||||
@ -472,7 +481,7 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
});
|
||||
|
||||
this.updateWaveCountText();
|
||||
this.updateBiomeWaveText();
|
||||
this.updateMoneyText();
|
||||
this.updateScoreText();
|
||||
}
|
||||
@ -786,8 +795,8 @@ export default class BattleScene extends SceneBase {
|
||||
|
||||
this.currentBattle = null;
|
||||
|
||||
this.waveCountText.setText(startingWave.toString());
|
||||
this.waveCountText.setVisible(false);
|
||||
this.biomeWaveText.setText(startingWave.toString());
|
||||
this.biomeWaveText.setVisible(false);
|
||||
|
||||
this.updateMoneyText();
|
||||
this.moneyText.setVisible(false);
|
||||
@ -1236,12 +1245,13 @@ export default class BattleScene extends SceneBase {
|
||||
});
|
||||
}
|
||||
|
||||
updateWaveCountText(): void {
|
||||
updateBiomeWaveText(): void {
|
||||
const isBoss = !(this.currentBattle.waveIndex % 10);
|
||||
this.waveCountText.setText(this.currentBattle.waveIndex.toString());
|
||||
this.waveCountText.setColor(!isBoss ? "#404040" : "#f89890");
|
||||
this.waveCountText.setShadowColor(!isBoss ? "#ded6b5" : "#984038");
|
||||
this.waveCountText.setVisible(true);
|
||||
const biomeString: string = getBiomeName(this.arena.biomeType);
|
||||
this.biomeWaveText.setText( biomeString + " - " + this.currentBattle.waveIndex.toString());
|
||||
this.biomeWaveText.setColor(!isBoss ? "#ffffff" : "#f89890");
|
||||
this.biomeWaveText.setShadowColor(!isBoss ? "#636363" : "#984038");
|
||||
this.biomeWaveText.setVisible(true);
|
||||
}
|
||||
|
||||
updateMoneyText(): void {
|
||||
@ -1289,8 +1299,8 @@ export default class BattleScene extends SceneBase {
|
||||
|
||||
updateUIPositions(): void {
|
||||
const enemyModifierCount = this.enemyModifiers.filter(m => m.isIconVisible(this)).length;
|
||||
this.waveCountText.setY(-(this.game.canvas.height / 6) + (enemyModifierCount ? enemyModifierCount <= 12 ? 15 : 24 : 0));
|
||||
this.moneyText.setY(this.waveCountText.y + 10);
|
||||
this.biomeWaveText.setY(-(this.game.canvas.height / 6) + (enemyModifierCount ? enemyModifierCount <= 12 ? 15 : 24 : 0));
|
||||
this.moneyText.setY(this.biomeWaveText.y + 10);
|
||||
this.scoreText.setY(this.moneyText.y + 10);
|
||||
[ this.luckLabelText, this.luckText ].map(l => l.setY((this.scoreText.visible ? this.scoreText : this.moneyText).y + 10));
|
||||
const offsetY = (this.scoreText.visible ? this.scoreText : this.moneyText).y + 15;
|
||||
|
@ -2,14 +2,14 @@ import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
||||
import { Type } from "./type";
|
||||
import * as Utils from "../utils";
|
||||
import { BattleStat, getBattleStatName } from "./battle-stat";
|
||||
import { PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
||||
import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
||||
import { getPokemonMessage, getPokemonPrefix } from "../messages";
|
||||
import { Weather, WeatherType } from "./weather";
|
||||
import { BattlerTag } from "./battler-tags";
|
||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||
import { Gender } from "./gender";
|
||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
|
||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
|
||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { Stat } from "./pokemon-stat";
|
||||
@ -22,6 +22,7 @@ import i18next, { Localizable } from "#app/plugins/i18n.js";
|
||||
import { Command } from "../ui/command-ui-handler";
|
||||
import { getPokeballName } from "./pokeball";
|
||||
import { BerryModifierType } from "#app/modifier/modifier-type";
|
||||
import {BattlerIndex} from "#app/battle";
|
||||
|
||||
export class Ability implements Localizable {
|
||||
public id: Abilities;
|
||||
@ -2484,6 +2485,62 @@ export class PostBiomeChangeTerrainChangeAbAttr extends PostBiomeChangeAbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers just after a move is used either by the opponent or the player
|
||||
* @extends AbAttr
|
||||
*/
|
||||
export class PostMoveUsedAbAttr extends AbAttr {
|
||||
applyPostMoveUsed(pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], args: any[]): boolean | Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers after a dance move is used either by the opponent or the player
|
||||
* @extends PostMoveUsedAbAttr
|
||||
*/
|
||||
export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
|
||||
/**
|
||||
* Resolves the Dancer ability by replicating the move used by the source of the dance
|
||||
* either on the source itself or on the target of the dance
|
||||
* @param dancer {@linkcode Pokemon} with Dancer ability
|
||||
* @param move {@linkcode PokemonMove} Dancing move used by the source
|
||||
* @param source {@linkcode Pokemon} that used the dancing move
|
||||
* @param targets {@linkcode BattlerIndex}Targets of the dancing move
|
||||
* @param args N/A
|
||||
*
|
||||
* @return true if the Dancer ability was resolved
|
||||
*/
|
||||
applyPostMoveUsed(dancer: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], args: any[]): boolean | Promise<boolean> {
|
||||
// The move to replicate cannot come from the Dancer
|
||||
if (source.getBattlerIndex() !== dancer.getBattlerIndex()) {
|
||||
// If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance
|
||||
if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) {
|
||||
const target = this.getTarget(dancer, source, targets);
|
||||
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true));
|
||||
} else if (move.getMove() instanceof SelfStatusMove) {
|
||||
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself
|
||||
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the correct targets of Dancer ability
|
||||
*
|
||||
* @param dancer {@linkcode Pokemon} Pokemon with Dancer ability
|
||||
* @param source {@linkcode Pokemon} Source of the dancing move
|
||||
* @param targets {@linkcode BattlerIndex} Targets of the dancing move
|
||||
*/
|
||||
getTarget(dancer: Pokemon, source: Pokemon, targets: BattlerIndex[]) : BattlerIndex[] {
|
||||
if (dancer.isPlayer()) {
|
||||
return source.isPlayer() ? targets : [source.getBattlerIndex()];
|
||||
}
|
||||
return source.isPlayer() ? [source.getBattlerIndex()] : targets;
|
||||
}
|
||||
}
|
||||
|
||||
export class StatChangeMultiplierAbAttr extends AbAttr {
|
||||
private multiplier: integer;
|
||||
|
||||
@ -3013,6 +3070,11 @@ export function applyPostDefendAbAttrs(attrType: { new(...args: any[]): PostDefe
|
||||
return applyAbAttrsInternal<PostDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args);
|
||||
}
|
||||
|
||||
export function applyPostMoveUsedAbAttrs(attrType: { new(...args: any[]): PostMoveUsedAbAttr },
|
||||
pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], ...args: any[]): Promise<void> {
|
||||
return applyAbAttrsInternal<PostMoveUsedAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostMoveUsed(pokemon, move, source, targets, args), args);
|
||||
}
|
||||
|
||||
export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]): BattleStatMultiplierAbAttr },
|
||||
pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, ...args: any[]): Promise<void> {
|
||||
return applyAbAttrsInternal<BattleStatMultiplierAbAttr>(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args);
|
||||
@ -3770,7 +3832,7 @@ export function initAbilities() {
|
||||
.attr(PostFaintHPDamageAbAttr)
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.DANCER, 7)
|
||||
.unimplemented(),
|
||||
.attr(PostDancingMoveAbAttr),
|
||||
new Ability(Abilities.BATTERY, 7)
|
||||
.unimplemented(),
|
||||
new Ability(Abilities.FLUFFY, 7)
|
||||
|
@ -18,10 +18,8 @@ export function getBiomeName(biome: Biome | -1) {
|
||||
return "Ancient Ruins";
|
||||
case Biome.ABYSS:
|
||||
return "The Abyss";
|
||||
case Biome.SPACE:
|
||||
return "Stratosphere";
|
||||
case Biome.END:
|
||||
return "Final Destination";
|
||||
return "???";
|
||||
default:
|
||||
return Utils.toReadableString(Biome[biome]);
|
||||
}
|
||||
|
@ -630,13 +630,15 @@ export class TrainerConfig {
|
||||
? scene.anims.generateFrameNames(partnerTrainerKey, {zeroPad: 4,suffix: ".png",start: 1,end: 128})
|
||||
: null;
|
||||
console.warn = originalWarn;
|
||||
if (!(scene.anims.exists(trainerKey))) {
|
||||
scene.anims.create({
|
||||
key: trainerKey,
|
||||
frames: frameNames,
|
||||
frameRate: 24,
|
||||
repeat: -1
|
||||
});
|
||||
if (isDouble) {
|
||||
}
|
||||
if (isDouble && !(scene.anims.exists(partnerTrainerKey))) {
|
||||
scene.anims.create({
|
||||
key: partnerTrainerKey,
|
||||
frames: partnerFrameNames,
|
||||
|
@ -24,12 +24,14 @@ export function addPokeballOpenParticles(scene: BattleScene, x: number, y: numbe
|
||||
|
||||
function doDefaultPbOpenParticles(scene: BattleScene, x: number, y: number, radius: number) {
|
||||
const pbOpenParticlesFrameNames = scene.anims.generateFrameNames("pb_particles", { start: 0, end: 3, suffix: ".png" });
|
||||
if (!(scene.anims.exists("pb_open_particle"))) {
|
||||
scene.anims.create({
|
||||
key: "pb_open_particle",
|
||||
frames: pbOpenParticlesFrameNames,
|
||||
frameRate: 16,
|
||||
repeat: -1
|
||||
});
|
||||
}
|
||||
|
||||
const addParticle = (index: integer) => {
|
||||
const particle = scene.add.sprite(x, y, "pb_open_particle");
|
||||
|
@ -726,12 +726,14 @@ export class ArenaBase extends Phaser.GameObjects.Container {
|
||||
|
||||
if (this.base.texture.frameTotal > 1) {
|
||||
const baseFrameNames = this.scene.anims.generateFrameNames(baseKey, { zeroPad: 4, suffix: ".png", start: 1, end: this.base.texture.frameTotal - 1 });
|
||||
if (!(this.scene.anims.exists(baseKey))) {
|
||||
this.scene.anims.create({
|
||||
key: baseKey,
|
||||
frames: baseFrameNames,
|
||||
frameRate: 12,
|
||||
repeat: -1
|
||||
});
|
||||
}
|
||||
this.base.play(baseKey);
|
||||
} else {
|
||||
this.base.stop();
|
||||
@ -751,12 +753,14 @@ export class ArenaBase extends Phaser.GameObjects.Container {
|
||||
|
||||
if (hasProps && prop.texture.frameTotal > 1) {
|
||||
const propFrameNames = this.scene.anims.generateFrameNames(propKey, { zeroPad: 4, suffix: ".png", start: 1, end: prop.texture.frameTotal - 1 });
|
||||
if (!(this.scene.anims.exists(propKey))) {
|
||||
this.scene.anims.create({
|
||||
key: propKey,
|
||||
frames: propFrameNames,
|
||||
frameRate: 12,
|
||||
repeat: -1
|
||||
});
|
||||
}
|
||||
prop.play(propKey);
|
||||
} else {
|
||||
prop.stop();
|
||||
|
@ -322,6 +322,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
console.warn = () => {};
|
||||
const battleFrameNames = this.scene.anims.generateFrameNames(this.getBattleSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 400 });
|
||||
console.warn = originalWarn;
|
||||
if (!(this.scene.anims.exists(this.getBattleSpriteKey()))) {
|
||||
this.scene.anims.create({
|
||||
key: this.getBattleSpriteKey(),
|
||||
frames: battleFrameNames,
|
||||
@ -329,6 +330,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
repeat: -1
|
||||
});
|
||||
}
|
||||
}
|
||||
this.playAnim();
|
||||
const updateFusionPaletteAndResolve = () => {
|
||||
this.updateFusionPalette();
|
||||
@ -524,6 +526,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
shinySparkle.setVisible(false);
|
||||
shinySparkle.setOrigin(0.5, 1);
|
||||
const frameNames = this.scene.anims.generateFrameNames(key, { suffix: ".png", end: 34 });
|
||||
if (!(this.scene.anims.exists(`sparkle${keySuffix}`))) {
|
||||
this.scene.anims.create({
|
||||
key: `sparkle${keySuffix}`,
|
||||
frames: frameNames,
|
||||
@ -531,6 +534,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
showOnStart: true,
|
||||
hideOnComplete: true,
|
||||
});
|
||||
}
|
||||
this.add(shinySparkle);
|
||||
|
||||
this.shinySparkle = shinySparkle;
|
||||
|
@ -29,7 +29,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"confirmPassword": "Confirm Password",
|
||||
"registrationAgeWarning": "By registering, you confirm you are of 13 years of age or older.",
|
||||
"backToLogin": "Back to Login",
|
||||
"failedToLoadSaveData": "Failed to load save data. Please reload the page.\nIf this continues, please contact the administrator.",
|
||||
"failedToLoadSaveData": "Failed to load save data. Please reload the page.\nIf this persists, please check #announcements in Discord.",
|
||||
"sessionSuccess": "Session loaded successfully.",
|
||||
"failedToLoadSession": "Your session data could not be loaded.\nIt may be corrupted.",
|
||||
"boyOrGirl": "Are you a boy or a girl?",
|
||||
|
@ -475,7 +475,7 @@ export const ability: AbilityTranslationEntries = {
|
||||
},
|
||||
frisk: {
|
||||
name: "察觉",
|
||||
description: "进入战斗时,神奇宝贝可以检查对方神奇宝贝的能力。",
|
||||
description: "出场时,可以察觉对手的特性。",
|
||||
},
|
||||
reckless: {
|
||||
name: "舍身",
|
||||
@ -1063,7 +1063,7 @@ export const ability: AbilityTranslationEntries = {
|
||||
},
|
||||
asOneGlastrier: {
|
||||
name: "人马一体",
|
||||
description: "兼备蕾冠王的紧张感和灵幽\n马的漆黑嘶鸣这两种特性。",
|
||||
description: "兼备蕾冠王的紧张感和雪暴\n马的苍白嘶鸣这两种特性。",
|
||||
},
|
||||
asOneSpectrier: {
|
||||
name: "人马一体",
|
||||
@ -1211,11 +1211,11 @@ export const ability: AbilityTranslationEntries = {
|
||||
},
|
||||
embodyAspectTeal: {
|
||||
name: "面影辉映",
|
||||
description: "将回忆映于心中,让水井面\n具发出光辉,提高自己的特\n防。",
|
||||
description: "将回忆映于心中,让碧草面\n具发出光辉,提高自己的速\n度。",
|
||||
},
|
||||
embodyAspectWellspring: {
|
||||
name: "面影辉映",
|
||||
description: "将回忆映于心中,让碧草面\n具发出光辉,提高自己的速\n度。",
|
||||
description: "将回忆映于心中,让水井面\n具发出光辉,提高自己的特\n防。",
|
||||
},
|
||||
embodyAspectHearthflame: {
|
||||
name: "面影辉映",
|
||||
|
@ -2915,7 +2915,7 @@ export const move: MoveTranslationEntries = {
|
||||
},
|
||||
"zippyZap": {
|
||||
name: "电电加速",
|
||||
effect: "The user attacks the target with bursts of electricity at high speed. This move always goes first and raises the user's evasiveness.",
|
||||
effect: "迅猛无比的电击。必定能够\n先制攻击,并且提高自己的\n闪避率。",
|
||||
},
|
||||
"splishySplash": {
|
||||
name: "滔滔冲浪",
|
||||
|
@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
|
||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
||||
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr } from "./data/ability";
|
||||
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr } from "./data/ability";
|
||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||
import { getBiomeKey } from "./field/arena";
|
||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||
@ -61,6 +61,7 @@ import { Abilities } from "./data/enums/abilities";
|
||||
import * as Overrides from "./overrides";
|
||||
import { TextStyle, addTextObject } from "./ui/text";
|
||||
import { Type } from "./data/type";
|
||||
import { MoveUsedEvent } from "./battle-scene-events";
|
||||
|
||||
|
||||
export class LoginPhase extends Phase {
|
||||
@ -2155,13 +2156,28 @@ export class TurnStartPhase extends FieldPhase {
|
||||
this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets[0] % 2, turnCommand.cursor));
|
||||
break;
|
||||
case Command.POKEMON:
|
||||
case Command.RUN:
|
||||
const isSwitch = turnCommand.command === Command.POKEMON;
|
||||
if (isSwitch) {
|
||||
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor, true, turnCommand.args[0] as boolean, pokemon.isPlayer()));
|
||||
break;
|
||||
case Command.RUN:
|
||||
let runningPokemon = pokemon;
|
||||
if (this.scene.currentBattle.double) {
|
||||
const playerActivePokemon = field.filter(pokemon => {
|
||||
if (!!pokemon) {
|
||||
return pokemon.isPlayer() && pokemon.isActive();
|
||||
} else {
|
||||
this.scene.unshiftPhase(new AttemptRunPhase(this.scene, pokemon.getFieldIndex()));
|
||||
return;
|
||||
}
|
||||
});
|
||||
// if only one pokemon is alive, use that one
|
||||
if (playerActivePokemon.length > 1) {
|
||||
// find which active pokemon has faster speed
|
||||
const fasterPokemon = playerActivePokemon[0].getStat(Stat.SPD) > playerActivePokemon[1].getStat(Stat.SPD) ? playerActivePokemon[0] : playerActivePokemon[1];
|
||||
// check if either active pokemon has the ability "Run Away"
|
||||
const hasRunAway = playerActivePokemon.find(p => p.hasAbility(Abilities.RUN_AWAY));
|
||||
runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon;
|
||||
}
|
||||
}
|
||||
this.scene.unshiftPhase(new AttemptRunPhase(this.scene, runningPokemon.getFieldIndex()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2388,7 +2404,7 @@ export class MovePhase extends BattlePhase {
|
||||
console.log(Moves[this.move.moveId]);
|
||||
|
||||
if (!this.canMove()) {
|
||||
if (this.move.moveId && this.pokemon.summonData.disabledMove === this.move.moveId) {
|
||||
if (this.move.moveId && this.pokemon.summonData?.disabledMove === this.move.moveId) {
|
||||
this.scene.queueMessage(`${this.move.getName()} is disabled!`);
|
||||
}
|
||||
return this.end();
|
||||
@ -2466,8 +2482,9 @@ export class MovePhase extends BattlePhase {
|
||||
const moveQueue = this.pokemon.getMoveQueue();
|
||||
if (this.cancelled || this.failed) {
|
||||
if (this.failed) {
|
||||
this.move.usePp(ppUsed);
|
||||
} // Only use PP if the move failed
|
||||
this.move.usePp(ppUsed); // Only use PP if the move failed
|
||||
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed));
|
||||
}
|
||||
|
||||
// Record a failed move so Abilities like Truant don't trigger next turn and soft-lock
|
||||
this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL });
|
||||
@ -2499,6 +2516,7 @@ export class MovePhase extends BattlePhase {
|
||||
|
||||
if (!moveQueue.length || !moveQueue.shift().ignorePP) { // using .shift here clears out two turn moves once they've been used
|
||||
this.move.usePp(ppUsed);
|
||||
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed));
|
||||
}
|
||||
|
||||
if (!allMoves[this.move.moveId].getAttrs(CopyMoveAttr).length) {
|
||||
@ -2525,7 +2543,16 @@ export class MovePhase extends BattlePhase {
|
||||
this.showFailedText(failedText);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if Dancer ability is triggered
|
||||
if (this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && !this.followUp) {
|
||||
// Pokemon with Dancer can be on either side of the battle so we check in both cases
|
||||
this.scene.getPlayerField().forEach(pokemon => {
|
||||
applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets);
|
||||
});
|
||||
this.scene.getEnemyParty().forEach(pokemon => {
|
||||
applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets);
|
||||
});
|
||||
}
|
||||
this.end();
|
||||
};
|
||||
|
||||
@ -4393,7 +4420,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
||||
}
|
||||
const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value));
|
||||
if (healAmount.value < 0) {
|
||||
pokemon.damageAndUpdate(healAmount.value * -1, HitResult.HEAL);
|
||||
pokemon.damageAndUpdate(healAmount.value * -1, HitResult.HEAL as DamageResult);
|
||||
healAmount.value = 0;
|
||||
}
|
||||
// Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock)
|
||||
|
@ -61,16 +61,20 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
||||
this.eggGachaContainer.add(bg);
|
||||
|
||||
const hatchFrameNames = this.scene.anims.generateFrameNames("gacha_hatch", { suffix: ".png", start: 1, end: 4 });
|
||||
if (!(this.scene.anims.exists("open"))) {
|
||||
this.scene.anims.create({
|
||||
key: "open",
|
||||
frames: hatchFrameNames,
|
||||
frameRate: 12
|
||||
});
|
||||
}
|
||||
if (!(this.scene.anims.exists("close"))) {
|
||||
this.scene.anims.create({
|
||||
key: "close",
|
||||
frames: hatchFrameNames.reverse(),
|
||||
frameRate: 12
|
||||
});
|
||||
}
|
||||
|
||||
Utils.getEnumValues(GachaType).forEach((gachaType, g) => {
|
||||
const gachaTypeKey = GachaType[gachaType].toString().toLowerCase();
|
||||
|
@ -16,12 +16,14 @@ export default class EggHatchSceneHandler extends UiHandler {
|
||||
this.scene.fieldUI.add(this.eggHatchContainer);
|
||||
|
||||
const eggLightraysAnimFrames = this.scene.anims.generateFrameNames("egg_lightrays", { start: 0, end: 3 });
|
||||
if (!(this.scene.anims.exists("egg_lightrays"))) {
|
||||
this.scene.anims.create({
|
||||
key: "egg_lightrays",
|
||||
frames: eggLightraysAnimFrames,
|
||||
frameRate: 32
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
show(_args: any[]): boolean {
|
||||
super.show(_args);
|
||||
|
@ -6,7 +6,7 @@ import { updateUserInfo } from "#app/account";
|
||||
|
||||
export default class UnavailableModalUiHandler extends ModalUiHandler {
|
||||
private reconnectTimer: number;
|
||||
private reconnectInterval: number;
|
||||
private reconnectDuration: number;
|
||||
private reconnectCallback: () => void;
|
||||
|
||||
private readonly minTime = 1000 * 5;
|
||||
@ -16,7 +16,7 @@ export default class UnavailableModalUiHandler extends ModalUiHandler {
|
||||
|
||||
constructor(scene: BattleScene, mode?: Mode) {
|
||||
super(scene, mode);
|
||||
this.reconnectInterval = this.minTime;
|
||||
this.reconnectDuration = this.minTime;
|
||||
}
|
||||
|
||||
getModalTitle(): string {
|
||||
@ -51,19 +51,17 @@ export default class UnavailableModalUiHandler extends ModalUiHandler {
|
||||
tryReconnect(): void {
|
||||
updateUserInfo().then(response => {
|
||||
if (response[0] || [200, 400].includes(response[1])) {
|
||||
clearInterval(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
this.reconnectInterval = this.minTime;
|
||||
this.reconnectDuration = this.minTime;
|
||||
this.scene.playSound("pb_bounce_1");
|
||||
this.reconnectCallback();
|
||||
} else {
|
||||
clearInterval(this.reconnectTimer);
|
||||
this.reconnectInterval = Math.min(this.reconnectInterval * 2, this.maxTime); // Set a max delay so it isn't infinite
|
||||
this.reconnectDuration = Math.min(this.reconnectDuration * 2, this.maxTime); // Set a max delay so it isn't infinite
|
||||
this.reconnectTimer =
|
||||
setTimeout(
|
||||
() => this.tryReconnect(),
|
||||
// Adds a random factor to avoid pendulum effect during long total breakdown
|
||||
this.reconnectInterval + (Math.random() * this.randVarianceTime));
|
||||
this.reconnectDuration + (Math.random() * this.randVarianceTime));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -75,8 +73,8 @@ export default class UnavailableModalUiHandler extends ModalUiHandler {
|
||||
};
|
||||
|
||||
this.reconnectCallback = args[0];
|
||||
|
||||
this.reconnectTimer = setInterval(() => this.tryReconnect(), this.reconnectInterval);
|
||||
this.reconnectDuration = this.minTime;
|
||||
this.reconnectTimer = setTimeout(() => this.tryReconnect(), this.reconnectDuration);
|
||||
|
||||
return super.show([ config ]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user