mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-21 14:59:26 +02:00
unburden implemented
This commit is contained in:
parent
c9664b66d3
commit
0d894e9009
@ -1692,6 +1692,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
|||||||
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)];
|
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)];
|
||||||
pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => {
|
pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => {
|
||||||
if (success) {
|
if (success) {
|
||||||
|
defender.turnData.itemsLost += 1;
|
||||||
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postAttackStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), defenderName: defender.name, stolenItemType: stolenItem.type.name }));
|
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postAttackStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), defenderName: defender.name, stolenItemType: stolenItem.type.name }));
|
||||||
}
|
}
|
||||||
resolve(success);
|
resolve(success);
|
||||||
@ -1785,6 +1786,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
|||||||
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)];
|
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)];
|
||||||
pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => {
|
pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => {
|
||||||
if (success) {
|
if (success) {
|
||||||
|
attacker.turnData.itemsLost += 1;
|
||||||
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postDefendStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), attackerName: attacker.name, stolenItemType: stolenItem.type.name }));
|
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postDefendStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), attackerName: attacker.name, stolenItemType: stolenItem.type.name }));
|
||||||
}
|
}
|
||||||
resolve(success);
|
resolve(success);
|
||||||
@ -3835,6 +3837,92 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class UnburdenBerryAbAttr extends PostTurnAbAttr {
|
||||||
|
private stats: BattleStat[];
|
||||||
|
private stages: number;
|
||||||
|
|
||||||
|
constructor(stats: BattleStat[], stages: number) {
|
||||||
|
super(true);
|
||||||
|
|
||||||
|
this.stats = Array.isArray(stats)
|
||||||
|
? stats
|
||||||
|
: [ stats ];
|
||||||
|
this.stages = stages;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||||
|
const multipleItems = pokemon.battleData.berriesEaten.length * this.stages;
|
||||||
|
if (multipleItems > 6) {
|
||||||
|
this.stages = 6;
|
||||||
|
} else {
|
||||||
|
this.stages = multipleItems;
|
||||||
|
}
|
||||||
|
if (!simulated) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.stages));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): AbAttrCondition {
|
||||||
|
return (pokemon: Pokemon) => pokemon.battleData.berriesEaten.length !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UnburdenDefStolenAbAttr extends PostDefendAbAttr {
|
||||||
|
private stats: BattleStat[];
|
||||||
|
private stages: number;
|
||||||
|
|
||||||
|
constructor(stats: BattleStat[], stages: number) {
|
||||||
|
super(true);
|
||||||
|
|
||||||
|
this.stats = Array.isArray(stats)
|
||||||
|
? stats
|
||||||
|
: [ stats ];
|
||||||
|
this.stages = stages;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
|
if (!simulated) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.stages));
|
||||||
|
pokemon.turnData.itemsLost -= 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): AbAttrCondition {
|
||||||
|
return (pokemon: Pokemon) => pokemon.turnData.itemsLost > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UnburdenAtkStolenAbAttr extends PostAttackAbAttr {
|
||||||
|
private stats: BattleStat[];
|
||||||
|
private stages: number;
|
||||||
|
|
||||||
|
constructor(stats: BattleStat[], stages: number) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.stats = Array.isArray(stats)
|
||||||
|
? stats
|
||||||
|
: [ stats ];
|
||||||
|
this.stages = stages;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
|
if (!simulated) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.stages));
|
||||||
|
pokemon.turnData.itemsLost -= 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): AbAttrCondition {
|
||||||
|
return (pokemon: Pokemon) => pokemon.turnData.itemsLost > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class StatStageChangeMultiplierAbAttr extends AbAttr {
|
export class StatStageChangeMultiplierAbAttr extends AbAttr {
|
||||||
private multiplier: integer;
|
private multiplier: integer;
|
||||||
|
|
||||||
@ -5146,7 +5234,9 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.ANGER_POINT, 4)
|
new Ability(Abilities.ANGER_POINT, 4)
|
||||||
.attr(PostDefendCritStatStageChangeAbAttr, Stat.ATK, 6),
|
.attr(PostDefendCritStatStageChangeAbAttr, Stat.ATK, 6),
|
||||||
new Ability(Abilities.UNBURDEN, 4)
|
new Ability(Abilities.UNBURDEN, 4)
|
||||||
.unimplemented(),
|
.attr(UnburdenBerryAbAttr, [ Stat.SPD ], 2)
|
||||||
|
.attr(UnburdenAtkStolenAbAttr, [ Stat.SPD ], 2)
|
||||||
|
.attr(UnburdenDefStolenAbAttr, [ Stat.SPD ], 2),
|
||||||
new Ability(Abilities.HEATPROOF, 4)
|
new Ability(Abilities.HEATPROOF, 4)
|
||||||
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
|
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
|
||||||
.attr(ReduceBurnDamageAbAttr, 0.5)
|
.attr(ReduceBurnDamageAbAttr, 0.5)
|
||||||
|
@ -2146,6 +2146,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
|||||||
const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)];
|
const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)];
|
||||||
user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => {
|
user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => {
|
||||||
if (success) {
|
if (success) {
|
||||||
|
target.turnData.itemsLost += 1;
|
||||||
user.scene.queueMessage(i18next.t("moveTriggers:stoleItem", {pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name}));
|
user.scene.queueMessage(i18next.t("moveTriggers:stoleItem", {pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name}));
|
||||||
}
|
}
|
||||||
resolve(success);
|
resolve(success);
|
||||||
@ -2227,6 +2228,7 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
|||||||
// Decrease item amount and update icon
|
// Decrease item amount and update icon
|
||||||
!--removedItem.stackCount;
|
!--removedItem.stackCount;
|
||||||
target.scene.updateModifiers(target.isPlayer());
|
target.scene.updateModifiers(target.isPlayer());
|
||||||
|
target.turnData.itemsLost+=1;
|
||||||
|
|
||||||
if (this.berriesOnly) {
|
if (this.berriesOnly) {
|
||||||
user.scene.queueMessage(i18next.t("moveTriggers:incineratedItem", {pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name}));
|
user.scene.queueMessage(i18next.t("moveTriggers:incineratedItem", {pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name}));
|
||||||
@ -2341,6 +2343,7 @@ export class StealEatBerryAttr extends EatBerryAttr {
|
|||||||
}
|
}
|
||||||
// if the target has berries, pick a random berry and steal it
|
// if the target has berries, pick a random berry and steal it
|
||||||
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
|
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
|
||||||
|
target.turnData.itemsLost+=1;
|
||||||
const message = i18next.t("battle:stealEatBerry", {pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name});
|
const message = i18next.t("battle:stealEatBerry", {pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name});
|
||||||
user.scene.queueMessage(message);
|
user.scene.queueMessage(message);
|
||||||
this.reduceBerryModifier(target);
|
this.reduceBerryModifier(target);
|
||||||
|
@ -5011,6 +5011,7 @@ export class PokemonTurnData {
|
|||||||
public order: number;
|
public order: number;
|
||||||
public statStagesIncreased: boolean = false;
|
public statStagesIncreased: boolean = false;
|
||||||
public statStagesDecreased: boolean = false;
|
public statStagesDecreased: boolean = false;
|
||||||
|
public itemsLost: number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AiType {
|
export enum AiType {
|
||||||
|
@ -2719,6 +2719,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
|
|||||||
const randItem = itemModifiers[randItemIndex];
|
const randItem = itemModifiers[randItemIndex];
|
||||||
heldItemTransferPromises.push(pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false).then(success => {
|
heldItemTransferPromises.push(pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false).then(success => {
|
||||||
if (success) {
|
if (success) {
|
||||||
|
targetPokemon.turnData.itemsLost += 1;
|
||||||
transferredModifierTypes.push(randItem.type);
|
transferredModifierTypes.push(randItem.type);
|
||||||
itemModifiers.splice(randItemIndex, 1);
|
itemModifiers.splice(randItemIndex, 1);
|
||||||
}
|
}
|
||||||
|
136
src/test/abilities/unburden.test.ts
Normal file
136
src/test/abilities/unburden.test.ts
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
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, vi } from "vitest";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import { BerryType } from "#app/enums/berry-type";
|
||||||
|
import { allMoves, StealHeldItemChanceAttr } from "#app/data/move";
|
||||||
|
|
||||||
|
|
||||||
|
describe("Abilities - Unburden", () => {
|
||||||
|
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
|
||||||
|
.battleType("single")
|
||||||
|
.starterSpecies(Species.TREECKO)
|
||||||
|
.startingLevel(1)
|
||||||
|
.moveset([Moves.POPULATION_BOMB, Moves.KNOCK_OFF, Moves.PLUCK, Moves.THIEF])
|
||||||
|
.ability(Abilities.UNBURDEN)
|
||||||
|
.startingHeldItems([
|
||||||
|
{ name: "BERRY", count: 1, type: BerryType.SITRUS },
|
||||||
|
{ name: "BERRY", count: 2, type: BerryType.APICOT },
|
||||||
|
{ name: "BERRY", count: 2, type: BerryType.LUM },
|
||||||
|
])
|
||||||
|
.enemySpecies(Species.NINJASK)
|
||||||
|
.enemyLevel(100)
|
||||||
|
.enemyMoveset([Moves.FALSE_SWIPE])
|
||||||
|
.enemyAbility(Abilities.UNBURDEN)
|
||||||
|
.enemyHeldItems([
|
||||||
|
{ name: "BERRY", type: BerryType.SITRUS, count: 1 },
|
||||||
|
{ name: "BERRY", type: BerryType.LUM, count: 1 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate when a berry is eaten", async () => {
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const playerHeldItems = playerPokemon.getHeldItems().length;
|
||||||
|
game.move.select(Moves.FALSE_SWIPE);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon.getHeldItems().length).toBeLessThan(playerHeldItems);
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(4);
|
||||||
|
|
||||||
|
});
|
||||||
|
it("should activate when a berry is stolen", async () => {
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
const enemyHeldItemCt = enemyPokemon.getHeldItems().length;
|
||||||
|
game.move.select(Moves.PLUCK);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt);
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.SPD)).toBe(2);
|
||||||
|
});
|
||||||
|
it("should activate when an item is knocked off", async () => {
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
const enemyHeldItemCt = enemyPokemon.getHeldItems().length;
|
||||||
|
game.move.select(Moves.KNOCK_OFF);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt);
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.SPD)).toBe(2);
|
||||||
|
});
|
||||||
|
it("should activate when an item is stolen via attacking ability", async () => {
|
||||||
|
game.override
|
||||||
|
.ability(Abilities.MAGICIAN)
|
||||||
|
.startingHeldItems([
|
||||||
|
{ name: "MULTI_LENS", count: 3 },
|
||||||
|
]);
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
vi.spyOn(allMoves[Moves.POPULATION_BOMB], "accuracy", "get").mockReturnValue(100);
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
const enemyHeldItemCt = enemyPokemon.getHeldItems().length;
|
||||||
|
game.move.select(Moves.POPULATION_BOMB);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt);
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.SPD)).toBe(4);
|
||||||
|
});
|
||||||
|
it("should activate when an item is stolen via defending ability", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyAbility(Abilities.PICKPOCKET)
|
||||||
|
.startingHeldItems([
|
||||||
|
{ name: "MULTI_LENS", count: 3 },
|
||||||
|
{ name: "SOUL_DEW", count: 1},
|
||||||
|
{ name: "LUCKY_EGG", count: 1 },
|
||||||
|
]);
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
vi.spyOn(allMoves[Moves.POPULATION_BOMB], "accuracy", "get").mockReturnValue(100);
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const playerHeldItems = playerPokemon.getHeldItems().length;
|
||||||
|
game.move.select(Moves.POPULATION_BOMB);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon.getHeldItems().length).toBeLessThan(playerHeldItems);
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(6);
|
||||||
|
});
|
||||||
|
it("should activate when an item is stolen via move", async () => {
|
||||||
|
vi.spyOn(allMoves[Moves.THIEF], "attrs", "get").mockReturnValue([new StealHeldItemChanceAttr(1.0)]); // give Thief 100% steal rate
|
||||||
|
game.override.startingHeldItems([
|
||||||
|
{ name: "MULTI_LENS", count: 3 },
|
||||||
|
]);
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
const enemyHeldItemCt = enemyPokemon.getHeldItems().length;
|
||||||
|
game.move.select(Moves.THIEF);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt);
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.SPD)).toBe(4);
|
||||||
|
});
|
||||||
|
it("should activate when an item is stolen via grip claw", async () => {
|
||||||
|
game.override.startingHeldItems([
|
||||||
|
{ name: "GRIP_CLAW", count: 5 },
|
||||||
|
{ name: "MULTI_LENS", count: 3 },
|
||||||
|
]);
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
vi.spyOn(allMoves[Moves.POPULATION_BOMB], "accuracy", "get").mockReturnValue(100);
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
const enemyHeldItemCt = enemyPokemon.getHeldItems().length;
|
||||||
|
game.move.select(Moves.POPULATION_BOMB);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(enemyPokemon.getHeldItems().length).toBeLessThan(enemyHeldItemCt);
|
||||||
|
expect(enemyPokemon.getStatStage(Stat.SPD)).toBe(4);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user