Implement Pickup ability

This commit is contained in:
Flashfyre 2024-03-06 21:05:23 -05:00
parent bc236cd048
commit 113ac10c1b
4 changed files with 58 additions and 9 deletions

View File

@ -1604,9 +1604,9 @@ export default class BattleScene extends Phaser.Scene {
tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferStack: boolean, playSound: boolean, instant?: boolean, ignoreUpdate?: boolean): Promise<boolean> { tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferStack: boolean, playSound: boolean, instant?: boolean, ignoreUpdate?: boolean): Promise<boolean> {
return new Promise(resolve => { return new Promise(resolve => {
const source = itemModifier.getPokemon(target.scene); const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null;
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled).then(() => { Utils.executeIf(!!source, () => applyAbAttrs(BlockItemTheftAbAttr, source, cancelled)).then(() => {
if (cancelled.value) if (cancelled.value)
return resolve(false); return resolve(false);
const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier; const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier;
@ -1615,7 +1615,7 @@ export default class BattleScene extends Phaser.Scene {
&& (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier; && (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier;
let removeOld = true; let removeOld = true;
if (matchingModifier) { if (matchingModifier) {
const maxStackCount = matchingModifier.getMaxStackCount(source.scene); const maxStackCount = matchingModifier.getMaxStackCount(target.scene);
if (matchingModifier.stackCount >= maxStackCount) if (matchingModifier.stackCount >= maxStackCount)
return resolve(false); return resolve(false);
const countTaken = transferStack ? Math.min(itemModifier.stackCount, maxStackCount - matchingModifier.stackCount) : 1; const countTaken = transferStack ? Math.min(itemModifier.stackCount, maxStackCount - matchingModifier.stackCount) : 1;
@ -1626,7 +1626,7 @@ export default class BattleScene extends Phaser.Scene {
newItemModifier.stackCount = 1; newItemModifier.stackCount = 1;
removeOld = !(--itemModifier.stackCount); removeOld = !(--itemModifier.stackCount);
} }
if (!removeOld || this.removeModifier(itemModifier, !source.isPlayer())) { if (!removeOld || !source || this.removeModifier(itemModifier, !source.isPlayer())) {
const addModifier = () => { const addModifier = () => {
if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) {
if (target.isPlayer()) if (target.isPlayer())
@ -1636,7 +1636,7 @@ export default class BattleScene extends Phaser.Scene {
} else } else
resolve(false); resolve(false);
}; };
if (source.isPlayer() !== target.isPlayer() && !ignoreUpdate) if (source && source.isPlayer() !== target.isPlayer() && !ignoreUpdate)
this.updateModifiers(source.isPlayer(), instant).then(() => addModifier()); this.updateModifiers(source.isPlayer(), instant).then(() => addModifier());
else else
addModifier(); addModifier();

View File

@ -9,6 +9,7 @@ import { TrainerType } from "./data/enums/trainer-type";
import { GameMode } from "./game-mode"; import { GameMode } from "./game-mode";
import { BattleSpec } from "./enums/battle-spec"; import { BattleSpec } from "./enums/battle-spec";
import { PlayerGender } from "./system/game-data"; import { PlayerGender } from "./system/game-data";
import { PersistentModifier, PokemonHeldItemModifier } from "./modifier/modifier";
export enum BattleType { export enum BattleType {
WILD, WILD,
@ -49,8 +50,9 @@ export default class Battle {
public started: boolean; public started: boolean;
public turn: integer; public turn: integer;
public turnCommands: TurnCommands; public turnCommands: TurnCommands;
public playerParticipantIds: Set<integer> = new Set<integer>(); public playerParticipantIds: Set<integer>;
public escapeAttempts: integer = 0; public postBattleLoot: PokemonHeldItemModifier[];
public escapeAttempts: integer;
public lastMove: Moves; public lastMove: Moves;
public battleSeed: string; public battleSeed: string;
private battleSeedState: string; private battleSeedState: string;
@ -68,6 +70,9 @@ export default class Battle {
this.seenEnemyPartyMemberIds = new Set<integer>(); this.seenEnemyPartyMemberIds = new Set<integer>();
this.double = double; this.double = double;
this.turn = 0; this.turn = 0;
this.playerParticipantIds = new Set<integer>();
this.postBattleLoot = [];
this.escapeAttempts = 0;
this.started = false; this.started = false;
this.battleSeed = Utils.randomString(16, true); this.battleSeed = Utils.randomString(16, true);
this.battleSeedState = null; this.battleSeedState = null;
@ -123,6 +128,14 @@ export default class Battle {
this.playerParticipantIds.delete(playerPokemon.id); this.playerParticipantIds.delete(playerPokemon.id);
} }
addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id, false).map(i => {
const ret = i as PokemonHeldItemModifier;
ret.pokemonId = null;
return ret;
}));
}
getBgmOverride(scene: BattleScene): string { getBgmOverride(scene: BattleScene): string {
const battlers = this.enemyParty.slice(0, this.getBattlerCount()); const battlers = this.enemyParty.slice(0, this.getBattlerCount());
if (this.battleType === BattleType.TRAINER) { if (this.battleType === BattleType.TRAINER) {

View File

@ -1020,6 +1020,31 @@ export class MaxMultiHitAbAttr extends AbAttr {
} }
} }
export class PostBattleAbAttr extends AbAttr {
constructor() {
super(true);
}
applyPostBattle(pokemon: Pokemon, args: any[]): boolean {
return false;
}
}
export class PostBattleLootAbAttr extends PostBattleAbAttr {
applyPostBattle(pokemon: Pokemon, args: any[]): boolean {
const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot;
if (postBattleLoot.length) {
const randItem = Utils.randSeedItem(postBattleLoot);
if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false, true, true)) {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` picked up\n${randItem.type.name}!`));
return true;
}
}
return false;
}
}
export class ReduceStatusEffectDurationAbAttr extends AbAttr { export class ReduceStatusEffectDurationAbAttr extends AbAttr {
private statusEffect: StatusEffect; private statusEffect: StatusEffect;
@ -1247,6 +1272,11 @@ export function applyCheckTrappedAbAttrs(attrType: { new(...args: any[]): CheckT
return applyAbAttrsInternal<CheckTrappedAbAttr>(attrType, pokemon, attr => attr.applyCheckTrapped(pokemon, trapped, args), true); return applyAbAttrsInternal<CheckTrappedAbAttr>(attrType, pokemon, attr => attr.applyCheckTrapped(pokemon, trapped, args), true);
} }
export function applyPostBattleAbAttrs(attrType: { new(...args: any[]): PostBattleAbAttr },
pokemon: Pokemon, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<PostBattleAbAttr>(attrType, pokemon, attr => attr.applyPostBattle(pokemon, args));
}
function canApplyAttr(pokemon: Pokemon, attr: AbAttr): boolean { function canApplyAttr(pokemon: Pokemon, attr: AbAttr): boolean {
const condition = attr.getCondition(); const condition = attr.getCondition();
return !condition || condition(pokemon); return !condition || condition(pokemon);
@ -1676,7 +1706,8 @@ export function initAbilities() {
.attr(ProtectStatAbAttr, BattleStat.ACC), .attr(ProtectStatAbAttr, BattleStat.ACC),
new Ability(Abilities.HYPER_CUTTER, "Hyper Cutter", "The Pokémon's proud of its powerful pincers. They prevent other Pokémon from lowering its Attack stat.", 3) new Ability(Abilities.HYPER_CUTTER, "Hyper Cutter", "The Pokémon's proud of its powerful pincers. They prevent other Pokémon from lowering its Attack stat.", 3)
.attr(ProtectStatAbAttr, BattleStat.ATK), .attr(ProtectStatAbAttr, BattleStat.ATK),
new Ability(Abilities.PICKUP, "Pickup (N)", "The Pokémon may pick up the item an opposing Pokémon used during a battle. It may pick up items outside of battle, too.", 3), new Ability(Abilities.PICKUP, "Pickup", "The Pokémon may pick up the item an opposing Pokémon held during a battle.", 3)
.attr(PostBattleLootAbAttr),
new Ability(Abilities.TRUANT, "Truant", "The Pokémon can't use a move if it had used a move on the previous turn.", 3) new Ability(Abilities.TRUANT, "Truant", "The Pokémon can't use a move if it had used a move on the previous turn.", 3)
.attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.TRUANT, 1, false), .attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.TRUANT, 1, false),
new Ability(Abilities.HUSTLE, "Hustle", "Boosts the Attack stat, but lowers accuracy.", 3) new Ability(Abilities.HUSTLE, "Hustle", "Boosts the Attack stat, but lowers accuracy.", 3)

View File

@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, ge
import { TempBattleStat } from "./data/temp-battle-stat"; import { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag"; import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
import { ArenaTagType } from "./data/enums/arena-tag-type"; import { ArenaTagType } from "./data/enums/arena-tag-type";
import { Abilities, CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability"; import { Abilities, CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability";
import { Unlockables, getUnlockableName } from "./system/unlockables"; import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena"; import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle"; import { BattleType, BattlerIndex, TurnCommand } from "./battle";
@ -1772,6 +1772,9 @@ export class BattleEndPhase extends BattlePhase {
pokemon.resetBattleSummonData(); pokemon.resetBattleSummonData();
} }
for (let pokemon of this.scene.getParty())
applyPostBattleAbAttrs(PostBattleAbAttr, pokemon);
this.scene.clearEnemyHeldItemModifiers(); this.scene.clearEnemyHeldItemModifiers();
const lapsingModifiers = this.scene.findModifiers(m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[]; const lapsingModifiers = this.scene.findModifiers(m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[];
@ -2688,6 +2691,8 @@ export class FaintPhase extends PokemonPhase {
pokemon.trySetStatus(StatusEffect.FAINT); pokemon.trySetStatus(StatusEffect.FAINT);
if (pokemon.isPlayer()) if (pokemon.isPlayer())
this.scene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon); this.scene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon);
else
this.scene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon);
this.scene.field.remove(pokemon); this.scene.field.remove(pokemon);
this.end(); this.end();
} }