Merge branch 'beta' into pr-illusion
This commit is contained in:
commit
a89591a42e
|
@ -38,7 +38,7 @@ import PokemonData from "#app/system/pokemon-data";
|
|||
import { Nature } from "#app/data/nature";
|
||||
import { FormChangeItem, pokemonFormChanges, SpeciesFormChange, SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger } from "#app/data/pokemon-forms";
|
||||
import { FormChangePhase } from "#app/phases/form-change-phase";
|
||||
import { getTypeRgb } from "#app/data/type";
|
||||
import { getTypeRgb, Type } from "#app/data/type";
|
||||
import PokemonSpriteSparkleHandler from "#app/field/pokemon-sprite-sparkle-handler";
|
||||
import CharSprite from "#app/ui/char-sprite";
|
||||
import DamageNumberHandler from "#app/field/damage-number-handler";
|
||||
|
@ -98,6 +98,7 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
|||
import { ExpGainsSpeed } from "#enums/exp-gains-speed";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
|
||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||
|
||||
|
@ -2982,12 +2983,21 @@ export default class BattleScene extends SceneBase {
|
|||
|
||||
updateGameInfo(): void {
|
||||
const gameInfo = {
|
||||
playTime: this.sessionPlayTime ? this.sessionPlayTime : 0,
|
||||
playTime: this.sessionPlayTime ?? 0,
|
||||
gameMode: this.currentBattle ? this.gameMode.getName() : "Title",
|
||||
biome: this.currentBattle ? getBiomeName(this.arena.biomeType) : "",
|
||||
wave: this.currentBattle?.waveIndex || 0,
|
||||
party: this.party ? this.party.map(p => {
|
||||
return { name: p.name, level: p.level };
|
||||
wave: this.currentBattle?.waveIndex ?? 0,
|
||||
party: this.party ? this.party.map((p) => {
|
||||
return {
|
||||
name: p.name,
|
||||
form: p.getFormKey(),
|
||||
types: p.getTypes().map((type) => Type[type]),
|
||||
teraType: p.getTeraType() !== Type.UNKNOWN ? Type[p.getTeraType()] : "",
|
||||
level: p.level,
|
||||
currentHP: p.hp,
|
||||
maxHP: p.getMaxHp(),
|
||||
status: p.status?.effect ? StatusEffect[p.status.effect] : ""
|
||||
};
|
||||
}) : [],
|
||||
modeChain: this.ui?.getModeChain() ?? [],
|
||||
};
|
||||
|
|
|
@ -5544,8 +5544,7 @@ export function initAbilities() {
|
|||
.attr(EffectSporeAbAttr),
|
||||
new Ability(Abilities.SYNCHRONIZE, 3)
|
||||
.attr(SyncEncounterNatureAbAttr)
|
||||
.attr(SynchronizeStatusAbAttr)
|
||||
.partial(), // interaction with psycho shift needs work, keeping to old Gen interaction for now
|
||||
.attr(SynchronizeStatusAbAttr),
|
||||
new Ability(Abilities.CLEAR_BODY, 3)
|
||||
.attr(ProtectStatAbAttr)
|
||||
.ignorable(),
|
||||
|
@ -6155,7 +6154,7 @@ export function initAbilities() {
|
|||
.bypassFaint(),
|
||||
new Ability(Abilities.CORROSION, 7)
|
||||
.attr(IgnoreTypeStatusEffectImmunityAbAttr, [ StatusEffect.POISON, StatusEffect.TOXIC ], [ Type.STEEL, Type.POISON ])
|
||||
.edgeCase(), // Should interact correctly with magic coat/bounce (not yet implemented), fling with toxic orb (not implemented yet), and synchronize (not fully implemented yet)
|
||||
.edgeCase(), // Should interact correctly with magic coat/bounce (not yet implemented) + fling with toxic orb (not implemented yet)
|
||||
new Ability(Abilities.COMATOSE, 7)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
|
|
|
@ -18,7 +18,7 @@ import Move, {
|
|||
StatusCategoryOnAllyAttr
|
||||
} from "#app/data/move";
|
||||
import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms";
|
||||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import { getStatusEffectHealText, StatusEffect } from "#app/data/status-effect";
|
||||
import { TerrainType } from "#app/data/terrain";
|
||||
import { Type } from "#app/data/type";
|
||||
import { WeatherType } from "#app/data/weather";
|
||||
|
@ -2866,6 +2866,28 @@ export class GrudgeTag extends BattlerTag {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag used to heal the user of Psycho Shift of its status effect if Psycho Shift succeeds in transferring its status effect to the target Pokemon
|
||||
*/
|
||||
export class PsychoShiftTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.PSYCHO_SHIFT, BattlerTagLapseType.AFTER_MOVE, 1, Moves.PSYCHO_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Heals Psycho Shift's user of its status effect after it uses a move
|
||||
* @returns `false` to expire the tag immediately
|
||||
*/
|
||||
override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
|
||||
if (pokemon.status && pokemon.isActive(true)) {
|
||||
pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
|
||||
pokemon.resetStatus();
|
||||
pokemon.updateInfo();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
|
||||
* @param sourceId - The ID of the pokemon adding the tag
|
||||
|
@ -3049,6 +3071,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||
return new PowerTrickTag(sourceMove, sourceId);
|
||||
case BattlerTagType.GRUDGE:
|
||||
return new GrudgeTag();
|
||||
case BattlerTagType.PSYCHO_SHIFT:
|
||||
return new PsychoShiftTag();
|
||||
case BattlerTagType.NONE:
|
||||
default:
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||
|
|
|
@ -2270,24 +2270,26 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
|||
super(false, { trigger: MoveEffectTrigger.HIT });
|
||||
}
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
/**
|
||||
* Applies the effect of Psycho Shift to its target
|
||||
* Psycho Shift takes the user's status effect and passes it onto the target. The user is then healed after the move has been successfully executed.
|
||||
* @returns `true` if Psycho Shift's effect is able to be applied to the target
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
||||
const statusToApply: StatusEffect | undefined = user.status?.effect ?? (user.hasAbility(Abilities.COMATOSE) ? StatusEffect.SLEEP : undefined);
|
||||
|
||||
if (target.status) {
|
||||
return false;
|
||||
} else {
|
||||
const canSetStatus = target.canSetStatus(statusToApply, true, false, user);
|
||||
const trySetStatus = canSetStatus ? target.trySetStatus(statusToApply, true, user) : false;
|
||||
|
||||
if (canSetStatus) {
|
||||
if (user.status) {
|
||||
user.scene.queueMessage(getStatusEffectHealText(user.status.effect, getPokemonNameWithAffix(user)));
|
||||
}
|
||||
user.resetStatus();
|
||||
user.updateInfo();
|
||||
target.trySetStatus(statusToApply, true, user);
|
||||
if (trySetStatus && user.status) {
|
||||
// PsychoShiftTag is added to the user if move succeeds so that the user is healed of its status effect after its move
|
||||
user.addTag(BattlerTagType.PSYCHO_SHIFT);
|
||||
}
|
||||
|
||||
return canSetStatus;
|
||||
return trySetStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,5 +90,6 @@ export enum BattlerTagType {
|
|||
ELECTRIFIED = "ELECTRIFIED",
|
||||
TELEKINESIS = "TELEKINESIS",
|
||||
COMMANDED = "COMMANDED",
|
||||
GRUDGE = "GRUDGE"
|
||||
GRUDGE = "GRUDGE",
|
||||
PSYCHO_SHIFT = "PSYCHO_SHIFT",
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ export class CommandPhase extends FieldPhase {
|
|||
start() {
|
||||
super.start();
|
||||
|
||||
this.scene.updateGameInfo();
|
||||
|
||||
const commandUiHandler = this.scene.ui.handlers[Mode.COMMAND];
|
||||
if (commandUiHandler) {
|
||||
if (this.scene.currentBattle.turn === 1 || commandUiHandler.getCursor() === Command.POKEMON) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Corrosion", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([ Moves.SPLASH ])
|
||||
.battleType("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.GRIMER)
|
||||
.enemyAbility(Abilities.CORROSION)
|
||||
.enemyMoveset(Moves.TOXIC);
|
||||
});
|
||||
|
||||
it("If a Poison- or Steel-type Pokémon with this Ability poisons a target with Synchronize, Synchronize does not gain the ability to poison Poison- or Steel-type Pokémon.", async () => {
|
||||
game.override.ability(Abilities.SYNCHRONIZE);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(playerPokemon!.status).toBeUndefined();
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(playerPokemon!.status).toBeDefined();
|
||||
expect(enemyPokemon!.status).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -94,16 +94,4 @@ describe("Abilities - Synchronize", () => {
|
|||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
|
||||
});
|
||||
|
||||
it("should activate with Psycho Shift after the move clears the status", async () => {
|
||||
game.override.statusEffect(StatusEffect.PARALYSIS);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
game.move.select(Moves.PSYCHO_SHIFT);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); // keeping old gen < V impl for now since it's buggy otherwise
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { StatusEffect } from "#app/enums/status-effect";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Moves - Psycho Shift", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([ Moves.PSYCHO_SHIFT ])
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.statusEffect(StatusEffect.POISON)
|
||||
.battleType("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyLevel(20)
|
||||
.enemyAbility(Abilities.SYNCHRONIZE)
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("If Psycho Shift is used on a Pokémon with Synchronize, the user of Psycho Shift will already be afflicted with a status condition when Synchronize activates", async () => {
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon?.status).toBeUndefined();
|
||||
|
||||
game.move.select(Moves.PSYCHO_SHIFT);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
expect(playerPokemon?.status).toBeNull();
|
||||
expect(enemyPokemon?.status).toBeDefined();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue