[Move] Implemented Incinerate and Knock Off (#1671)
* Implemented Incinerate and Knock Off * Ran linter * Removed unnecessary code
This commit is contained in:
parent
9b8f6f312b
commit
2d254bab96
101
src/data/move.ts
101
src/data/move.ts
|
@ -1739,7 +1739,11 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
||||||
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(user.status?.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0;
|
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(user.status?.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* The following needs to be implemented for Thief
|
||||||
|
* "If the user faints due to the target's Ability (Rough Skin or Iron Barbs) or held Rocky Helmet, it cannot remove the target's held item."
|
||||||
|
* "If Knock Off causes a Pokémon with the Sticky Hold Ability to faint, it can now remove that Pokémon's held item."
|
||||||
|
*/
|
||||||
export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
||||||
private chance: number;
|
private chance: number;
|
||||||
|
|
||||||
|
@ -1789,37 +1793,65 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a random held item (or berry) from target.
|
||||||
|
* Used for Incinerate and Knock Off.
|
||||||
|
* Not Implemented Cases: (Same applies for Thief)
|
||||||
|
* "If the user faints due to the target's Ability (Rough Skin or Iron Barbs) or held Rocky Helmet, it cannot remove the target's held item."
|
||||||
|
* "If Knock Off causes a Pokémon with the Sticky Hold Ability to faint, it can now remove that Pokémon's held item."
|
||||||
|
*/
|
||||||
export class RemoveHeldItemAttr extends MoveEffectAttr {
|
export class RemoveHeldItemAttr extends MoveEffectAttr {
|
||||||
private chance: number;
|
|
||||||
|
|
||||||
constructor(chance: number) {
|
/** Optional restriction for item pool to berries only i.e. Differentiating Incinerate and Knock Off */
|
||||||
|
private berriesOnly: boolean;
|
||||||
|
|
||||||
|
constructor(berriesOnly: boolean) {
|
||||||
super(false, MoveEffectTrigger.HIT);
|
super(false, MoveEffectTrigger.HIT);
|
||||||
this.chance = chance;
|
this.berriesOnly = berriesOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
|
/**
|
||||||
return new Promise<boolean>(resolve => {
|
*
|
||||||
const rand = Phaser.Math.RND.realInRange(0, 1);
|
* @param user {@linkcode Pokemon} that used the move
|
||||||
if (rand >= this.chance) {
|
* @param target Target {@linkcode Pokemon} that the moves applies to
|
||||||
return resolve(false);
|
* @param move {@linkcode Move} that is used
|
||||||
}
|
* @param args N/A
|
||||||
const heldItems = this.getTargetHeldItems(target).filter(i => i.getTransferrable(false));
|
* @returns {boolean} True if an item was removed
|
||||||
if (heldItems.length) {
|
*/
|
||||||
const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD;
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier, highestTier), 0);
|
|
||||||
const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier);
|
|
||||||
const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)];
|
|
||||||
user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => {
|
|
||||||
if (success) {
|
|
||||||
user.scene.queueMessage(getPokemonMessage(user, ` knocked off\n${target.name}'s ${stolenItem.type.name}!`));
|
|
||||||
}
|
|
||||||
resolve(success);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(false);
|
if (!this.berriesOnly && target.isPlayer()) { // "Wild Pokemon cannot knock off Player Pokemon's held items" (See Bulbapedia)
|
||||||
});
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // Check for abilities that block item theft
|
||||||
|
|
||||||
|
if (cancelled.value === true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Considers entire transferrable item pool by default (Knock Off). Otherwise berries only if specified (Incinerate).
|
||||||
|
let heldItems = this.getTargetHeldItems(target).filter(i => i.getTransferrable(false));
|
||||||
|
if (this.berriesOnly) {
|
||||||
|
heldItems = heldItems.filter(m => m instanceof BerryModifier && m.pokemonId === target.id, target.isPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heldItems.length) {
|
||||||
|
const removedItem = heldItems[user.randSeedInt(heldItems.length)];
|
||||||
|
|
||||||
|
// Decrease item amount and update icon
|
||||||
|
!--removedItem.stackCount;
|
||||||
|
target.scene.updateModifiers(target.isPlayer());
|
||||||
|
|
||||||
|
if (this.berriesOnly) {
|
||||||
|
user.scene.queueMessage(getPokemonMessage(user, ` incinerated\n${target.name}'s ${removedItem.type.name}!`));
|
||||||
|
} else {
|
||||||
|
user.scene.queueMessage(getPokemonMessage(user, ` knocked off\n${target.name}'s ${removedItem.type.name}!`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
|
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
|
||||||
|
@ -3093,17 +3125,6 @@ export class PresentPowerAttr extends VariablePowerAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KnockOffPowerAttr extends VariablePowerAttr {
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
|
||||||
if (target.getHeldItems().length > 0) {
|
|
||||||
(args[0] as Utils.NumberHolder).value *= 1.5;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WaterShurikenPowerAttr extends VariablePowerAttr {
|
export class WaterShurikenPowerAttr extends VariablePowerAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (user.species.speciesId === Species.GRENINJA && user.hasAbility(Abilities.BATTLE_BOND) && user.formIndex === 2) {
|
if (user.species.speciesId === Species.GRENINJA && user.hasAbility(Abilities.BATTLE_BOND) && user.formIndex === 2) {
|
||||||
|
@ -6261,8 +6282,8 @@ export function initMoves() {
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true)
|
.attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true)
|
||||||
.condition((user, target, move) => !target.status),
|
.condition((user, target, move) => !target.status),
|
||||||
new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3)
|
new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3)
|
||||||
.attr(KnockOffPowerAttr)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getHeldItems().filter(i => i.getTransferrable(false)).length > 0 ? 1.5 : 1)
|
||||||
.partial(),
|
.attr(RemoveHeldItemAttr, false),
|
||||||
new AttackMove(Moves.ENDEAVOR, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 3)
|
new AttackMove(Moves.ENDEAVOR, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 3)
|
||||||
.attr(MatchHpAttr)
|
.attr(MatchHpAttr)
|
||||||
.condition(failOnBossCondition),
|
.condition(failOnBossCondition),
|
||||||
|
@ -6891,7 +6912,7 @@ export function initMoves() {
|
||||||
.attr(ForceSwitchOutAttr),
|
.attr(ForceSwitchOutAttr),
|
||||||
new AttackMove(Moves.INCINERATE, Type.FIRE, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5)
|
new AttackMove(Moves.INCINERATE, Type.FIRE, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||||
.partial(),
|
.attr(RemoveHeldItemAttr, true),
|
||||||
new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5)
|
new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5)
|
new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5)
|
||||||
|
|
Loading…
Reference in New Issue