Fix issues with Sticky Hold ability

pull/14/head
Flashfyre 2023-12-22 23:57:05 -05:00
parent 2bb1676d82
commit 40a4d4cf13
4 changed files with 70 additions and 59 deletions

View File

@ -1209,7 +1209,7 @@ export default class BattleScene extends Phaser.Scene {
this.phaseQueue.push(new TurnInitPhase(this)); this.phaseQueue.push(new TurnInitPhase(this));
} }
addModifier(modifier: Modifier, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean): Promise<void> { addModifier(modifier: Modifier, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
const soundName = modifier.type.soundName; const soundName = modifier.type.soundName;
this.validateAchvs(ModifierAchv, modifier); this.validateAchvs(ModifierAchv, modifier);
@ -1220,11 +1220,11 @@ export default class BattleScene extends Phaser.Scene {
} else if (!virtual) { } else if (!virtual) {
const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier); const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier);
this.queueMessage(`The stack for this item is full.\n You will receive ${defaultModifierType.name} instead.`, null, true); this.queueMessage(`The stack for this item is full.\n You will receive ${defaultModifierType.name} instead.`, null, true);
return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound).then(() => resolve()); return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant).then(() => resolve());
} }
if (!ignoreUpdate && !virtual) if (!ignoreUpdate && !virtual)
return this.updateModifiers().then(() => resolve()); return this.updateModifiers(true, instant).then(() => resolve());
} else if (modifier instanceof ConsumableModifier) { } else if (modifier instanceof ConsumableModifier) {
if (playSound && !this.sound.get(soundName)) if (playSound && !this.sound.get(soundName))
this.playSound(soundName); this.playSound(soundName);
@ -1248,7 +1248,7 @@ export default class BattleScene extends Phaser.Scene {
modifier.apply(args); modifier.apply(args);
} }
return Promise.allSettled(this.party.map(p => p.updateInfo())).then(() => resolve()); return Promise.allSettled(this.party.map(p => p.updateInfo(instant))).then(() => resolve());
} else { } else {
const args = [ this ]; const args = [ this ];
if (modifier.shouldApply(args)) if (modifier.shouldApply(args))
@ -1260,61 +1260,58 @@ export default class BattleScene extends Phaser.Scene {
}); });
} }
addEnemyModifier(itemModifier: PersistentModifier, ignoreUpdate?: boolean): Promise<void> { addEnemyModifier(itemModifier: PersistentModifier, ignoreUpdate?: boolean, instant?: boolean): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
itemModifier.add(this.enemyModifiers, false, this); itemModifier.add(this.enemyModifiers, false, this);
if (!ignoreUpdate) if (!ignoreUpdate)
this.updateModifiers(false).then(() => resolve()); this.updateModifiers(false, instant).then(() => resolve());
else else
resolve(); resolve();
}); });
} }
tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferStack: boolean, playSound: boolean): Promise<boolean> { tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferStack: boolean, playSound: boolean, instant?: boolean): Promise<boolean> {
return new Promise(resolve => { return new Promise(resolve => {
const source = itemModifier.getPokemon(target.scene); const source = itemModifier.getPokemon(target.scene);
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); applyAbAttrs(BlockItemTheftAbAttr, source, cancelled).then(() => {
if (cancelled.value) { if (cancelled.value)
resolve(false); return resolve(false);
return; const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier;
} newItemModifier.pokemonId = target.id;
const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier; const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier
newItemModifier.pokemonId = target.id; && (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier;
const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier let removeOld = true;
&& (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier; if (matchingModifier) {
let removeOld = true; const maxStackCount = matchingModifier.getMaxStackCount(source.scene);
if (matchingModifier) { if (matchingModifier.stackCount >= maxStackCount)
const maxStackCount = matchingModifier.getMaxStackCount(source.scene); return resolve(false);
if (matchingModifier.stackCount >= maxStackCount) { const countTaken = transferStack ? Math.min(itemModifier.stackCount, maxStackCount - matchingModifier.stackCount) : 1;
resolve(false); itemModifier.stackCount -= countTaken;
newItemModifier.stackCount = matchingModifier.stackCount + countTaken;
removeOld = !itemModifier.stackCount;
} else if (!transferStack) {
newItemModifier.stackCount = 1;
removeOld = !(--itemModifier.stackCount);
}
if (!removeOld || this.removeModifier(itemModifier, !source.isPlayer())) {
const addModifier = () => {
if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) {
if (target.isPlayer())
this.addModifier(newItemModifier, false, playSound, false, instant).then(() => resolve(true));
else
this.addEnemyModifier(newItemModifier, false, instant).then(() => resolve(true));
} else
resolve(false);
};
if (source.isPlayer() !== target.isPlayer())
this.updateModifiers(source.isPlayer(), instant).then(() => addModifier());
else
addModifier();
return; return;
} }
const countTaken = transferStack ? Math.min(itemModifier.stackCount, maxStackCount - matchingModifier.stackCount) : 1; resolve(false);
itemModifier.stackCount -= countTaken; });
newItemModifier.stackCount = matchingModifier.stackCount + countTaken;
removeOld = !itemModifier.stackCount;
} else if (!transferStack) {
newItemModifier.stackCount = 1;
removeOld = !(--itemModifier.stackCount);
}
if (!removeOld || this.removeModifier(itemModifier, !source.isPlayer())) {
const addModifier = () => {
if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) {
if (target.isPlayer())
this.addModifier(newItemModifier, false, playSound).then(() => resolve(true));
else
this.addEnemyModifier(newItemModifier).then(() => resolve(true));
} else
resolve(false);
};
if (source.isPlayer() !== target.isPlayer())
this.updateModifiers(source.isPlayer()).then(() => addModifier());
else
addModifier();
return;
}
resolve(false);
}); });
} }
@ -1366,7 +1363,7 @@ export default class BattleScene extends Phaser.Scene {
this.updateModifiers(false).then(() => this.updateUIPositions()); this.updateModifiers(false).then(() => this.updateUIPositions());
} }
updateModifiers(player?: boolean): Promise<void> { updateModifiers(player?: boolean, instant?: boolean): Promise<void> {
if (player === undefined) if (player === undefined)
player = true; player = true;
return new Promise(resolve => { return new Promise(resolve => {
@ -1387,7 +1384,7 @@ export default class BattleScene extends Phaser.Scene {
modifiers.splice(modifiers.indexOf(modifier), 1); modifiers.splice(modifiers.indexOf(modifier), 1);
} }
this.updatePartyForModifiers(player ? this.getParty() : this.getEnemyParty()).then(() => { this.updatePartyForModifiers(player ? this.getParty() : this.getEnemyParty(), instant).then(() => {
(player ? this.modifierBar : this.enemyModifierBar).updateModifiers(modifiers); (player ? this.modifierBar : this.enemyModifierBar).updateModifiers(modifiers);
if (!player) if (!player)
this.updateUIPositions(); this.updateUIPositions();
@ -1396,11 +1393,11 @@ export default class BattleScene extends Phaser.Scene {
}); });
} }
updatePartyForModifiers(party: Pokemon[]): Promise<void> { updatePartyForModifiers(party: Pokemon[], instant?: boolean): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
Promise.allSettled(party.map(p => { Promise.allSettled(party.map(p => {
p.calculateStats(); p.calculateStats();
return p.updateInfo(); return p.updateInfo(instant);
})).then(() => resolve()); })).then(() => resolve());
}); });
} }

View File

@ -17,6 +17,7 @@ export class Ability {
public name: string; public name: string;
public description: string; public description: string;
public generation: integer; public generation: integer;
public isPassive: boolean;
public attrs: AbAttr[]; public attrs: AbAttr[];
public conditions: AbAttrCondition[]; public conditions: AbAttrCondition[];
@ -44,6 +45,11 @@ export class Ability {
return !!this.getAttrs(attrType).length; return !!this.getAttrs(attrType).length;
} }
passive(): Ability {
this.isPassive = true;
return this;
}
condition(condition: AbAttrCondition): Ability { condition(condition: AbAttrCondition): Ability {
this.conditions.push(condition); this.conditions.push(condition);
@ -1508,7 +1514,8 @@ export function initAbilities() {
new Ability(Abilities.MINUS, "Minus (N)", "Boosts the Sp. Atk stat of the Pokémon if an ally with the Plus or Minus Ability is also in battle.", 3), new Ability(Abilities.MINUS, "Minus (N)", "Boosts the Sp. Atk stat of the Pokémon if an ally with the Plus or Minus Ability is also in battle.", 3),
new Ability(Abilities.FORECAST, "Forecast (N)", "The Pokémon transforms with the weather to change its type to Water, Fire, or Ice.", 3), new Ability(Abilities.FORECAST, "Forecast (N)", "The Pokémon transforms with the weather to change its type to Water, Fire, or Ice.", 3),
new Ability(Abilities.STICKY_HOLD, "Sticky Hold", "Items held by the Pokémon are stuck fast and cannot be removed by other Pokémon.", 3) new Ability(Abilities.STICKY_HOLD, "Sticky Hold", "Items held by the Pokémon are stuck fast and cannot be removed by other Pokémon.", 3)
.attr(BlockItemTheftAbAttr), .attr(BlockItemTheftAbAttr)
.passive(),
new Ability(Abilities.SHED_SKIN, "Shed Skin (N)", "The Pokémon may heal its own status conditions by shedding its skin.", 3), new Ability(Abilities.SHED_SKIN, "Shed Skin (N)", "The Pokémon may heal its own status conditions by shedding its skin.", 3),
new Ability(Abilities.GUTS, "Guts (N)", "It's so gutsy that having a status condition boosts the Pokémon's Attack stat.", 3), new Ability(Abilities.GUTS, "Guts (N)", "It's so gutsy that having a status condition boosts the Pokémon's Attack stat.", 3),
new Ability(Abilities.MARVEL_SCALE, "Marvel Scale (N)", "The Pokémon's marvelous scales boost the Defense stat if it has a status condition.", 3), new Ability(Abilities.MARVEL_SCALE, "Marvel Scale (N)", "The Pokémon's marvelous scales boost the Defense stat if it has a status condition.", 3),

View File

@ -1398,20 +1398,26 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
const transferredModifierTypes: ModifierTypes.ModifierType[] = []; const transferredModifierTypes: ModifierTypes.ModifierType[] = [];
const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id && m.getTransferrable(withinParty), targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; && (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id && m.getTransferrable(withinParty), targetPokemon.isPlayer()) as PokemonHeldItemModifier[];
let heldItemTransferPromises: Promise<void>[] = [];
for (let i = 0; i < transferredItemCount; i++) { for (let i = 0; i < transferredItemCount; i++) {
if (!itemModifiers.length) if (!itemModifiers.length)
break; break;
const randItemIndex = Utils.randInt(itemModifiers.length); const randItemIndex = Utils.randInt(itemModifiers.length);
const randItem = itemModifiers[randItemIndex]; const randItem = itemModifiers[randItemIndex];
if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false, false)) { heldItemTransferPromises.push(pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false, false, true).then(success => {
transferredModifierTypes.push(randItem.type); if (success) {
itemModifiers.splice(randItemIndex, 1); transferredModifierTypes.push(randItem.type);
} itemModifiers.splice(randItemIndex, 1);
}
}));
} }
for (let mt of transferredModifierTypes) Promise.all(heldItemTransferPromises).then(() => {
pokemon.scene.queueMessage(this.getTransferMessage(pokemon, targetPokemon, mt)); for (let mt of transferredModifierTypes)
pokemon.scene.queueMessage(this.getTransferMessage(pokemon, targetPokemon, mt));
});
return !!transferredModifierTypes.length; return !!transferredModifierTypes.length;
} }
@ -1447,7 +1453,7 @@ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier {
} }
getMaxHeldItemCount(pokemon: Pokemon): integer { getMaxHeldItemCount(pokemon: Pokemon): integer {
return 3; return 1;
} }
} }

View File

@ -608,7 +608,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
canApplyAbility(): boolean { canApplyAbility(): boolean {
return this.hp && !this.getAbility().conditions.find(condition => !condition(this)); const ability = this.getAbility();
return (this.hp || ability.isPassive) && !this.getAbility().conditions.find(condition => !condition(this));
} }
getWeight(): number { getWeight(): number {