Skip to content

Commit

Permalink
Fix Knock Off damage in Klutz/Magic Room (#651)
Browse files Browse the repository at this point in the history
A `Pokemon#disabledItem` field is used to check Knock Off damage
during Klutz/Magic Room.
  • Loading branch information
ShivaD173 authored Nov 1, 2024
1 parent cdb0195 commit effac17
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 27 deletions.
18 changes: 10 additions & 8 deletions calc/src/mechanics/gen56.ts
Original file line number Diff line number Diff line change
Expand Up @@ -620,18 +620,20 @@ export function calculateBPModsBWXY(
) {
const bpMods = [];

const defenderItem = (defender.item && defender.item !== '')
? defender.item : defender.disabledItem;
let resistedKnockOffDamage =
!defender.item ||
(defender.named('Giratina-Origin') && defender.hasItem('Griseous Orb')) ||
(defender.name.includes('Arceus') && defender.item.includes('Plate')) ||
(defender.name.includes('Genesect') && defender.item.includes('Drive')) ||
(defender.named('Groudon', 'Groudon-Primal') && defender.hasItem('Red Orb')) ||
(defender.named('Kyogre', 'Kyogre-Primal') && defender.hasItem('Blue Orb'));
!defenderItem ||
(defender.named('Giratina-Origin') && defenderItem === 'Griseous Orb') ||
(defender.name.includes('Arceus') && defenderItem.includes('Plate')) ||
(defender.name.includes('Genesect') && defenderItem.includes('Drive')) ||
(defender.named('Groudon', 'Groudon-Primal') && defenderItem === 'Red Orb') ||
(defender.named('Kyogre', 'Kyogre-Primal') && defenderItem === 'Blue Orb');

// The last case only applies when the Pokemon is holding the Mega Stone that matches its species
// (or when it's already a Mega-Evolution)
if (!resistedKnockOffDamage && defender.item) {
const item = gen.items.get(toID(defender.item))!;
if (!resistedKnockOffDamage && defenderItem) {
const item = gen.items.get(toID(defenderItem))!;
resistedKnockOffDamage = !!(item.megaEvolves && defender.name.includes(item.megaEvolves));
}

Expand Down
39 changes: 20 additions & 19 deletions calc/src/mechanics/gen789.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1028,30 +1028,31 @@ export function calculateBPModsSMSSSV(
const bpMods = [];

// Move effects

const defenderItem = (defender.item && defender.item !== '')
? defender.item : defender.disabledItem;
let resistedKnockOffDamage =
(!defender.item || isQPActive(defender, field)) ||
(defender.named('Dialga-Origin') && defender.hasItem('Adamant Crystal')) ||
(defender.named('Palkia-Origin') && defender.hasItem('Lustrous Globe')) ||
(!defenderItem || isQPActive(defender, field)) ||
(defender.named('Dialga-Origin') && defenderItem === 'Adamant Crystal') ||
(defender.named('Palkia-Origin') && defenderItem === 'Lustrous Globe') ||
// Griseous Core for gen 9, Griseous Orb otherwise
(defender.name.includes('Giratina-Origin') && defender.item.includes('Griseous')) ||
(defender.name.includes('Arceus') && defender.item.includes('Plate')) ||
(defender.name.includes('Genesect') && defender.item.includes('Drive')) ||
(defender.named('Groudon', 'Groudon-Primal') && defender.hasItem('Red Orb')) ||
(defender.named('Kyogre', 'Kyogre-Primal') && defender.hasItem('Blue Orb')) ||
(defender.name.includes('Silvally') && defender.item.includes('Memory')) ||
defender.item.includes(' Z') ||
(defender.named('Zacian') && defender.hasItem('Rusted Sword')) ||
(defender.named('Zamazenta') && defender.hasItem('Rusted Shield')) ||
(defender.name.includes('Ogerpon-Cornerstone') && defender.hasItem('Cornerstone Mask')) ||
(defender.name.includes('Ogerpon-Hearthflame') && defender.hasItem('Hearthflame Mask')) ||
(defender.name.includes('Ogerpon-Wellspring') && defender.hasItem('Wellspring Mask')) ||
(defender.named('Venomicon-Epilogue') && defender.hasItem('Vile Vial'));
(defender.name.includes('Giratina-Origin') && defenderItem.includes('Griseous')) ||
(defender.name.includes('Arceus') && defenderItem.includes('Plate')) ||
(defender.name.includes('Genesect') && defenderItem.includes('Drive')) ||
(defender.named('Groudon', 'Groudon-Primal') && defenderItem === 'Red Orb') ||
(defender.named('Kyogre', 'Kyogre-Primal') && defenderItem === 'Blue Orb') ||
(defender.name.includes('Silvally') && defenderItem.includes('Memory')) ||
defenderItem.includes(' Z') ||
(defender.named('Zacian') && defenderItem === 'Rusted Sword') ||
(defender.named('Zamazenta') && defenderItem === 'Rusted Shield') ||
(defender.name.includes('Ogerpon-Cornerstone') && defenderItem === 'Cornerstone Mask') ||
(defender.name.includes('Ogerpon-Hearthflame') && defenderItem === 'Hearthflame Mask') ||
(defender.name.includes('Ogerpon-Wellspring') && defenderItem === 'Wellspring Mask') ||
(defender.named('Venomicon-Epilogue') && defenderItem === 'Vile Vial');

// The last case only applies when the Pokemon has the Mega Stone that matches its species
// (or when it's already a Mega-Evolution)
if (!resistedKnockOffDamage && defender.item) {
const item = gen.items.get(toID(defender.item))!;
if (!resistedKnockOffDamage && defenderItem) {
const item = gen.items.get(toID(defenderItem))!;
resistedKnockOffDamage = !!item.megaEvolves && defender.name.includes(item.megaEvolves);
}

Expand Down
1 change: 1 addition & 0 deletions calc/src/mechanics/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export function checkItem(pokemon: Pokemon, magicRoomActive?: boolean) {
pokemon.hasAbility('Klutz') && !EV_ITEMS.includes(pokemon.item!) ||
magicRoomActive
) {
pokemon.disabledItem = pokemon.item;
pokemon.item = '' as ItemName;
}
}
Expand Down
1 change: 1 addition & 0 deletions calc/src/pokemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class Pokemon implements State.Pokemon {
alliesFainted?: number;
boostedStat?: I.StatIDExceptHP | 'auto';
item?: I.ItemName;
disabledItem?: I.ItemName;
teraType?: I.TypeName;

nature: I.NatureName;
Expand Down
17 changes: 17 additions & 0 deletions calc/src/test/calc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,23 @@ describe('calc', () => {
});
});

inGens(6, 9, ({gen, calculate, Pokemon, Move}) => {
test('Knock Off vs. Klutz', () => {
const weavile = Pokemon('Weavile');
const audino = Pokemon('Audino', {ability: 'Klutz', item: 'Leftovers'});
const audinoMega = Pokemon('Audino', {ability: 'Klutz', item: 'Audinite'});
const knockoff = Move('Knock Off');
const result = calculate(weavile, audino, knockoff);
expect(result.desc()).toBe(
'0 Atk Weavile Knock Off (97.5 BP) vs. 0 HP / 0 Def Audino: 139-165 (40 - 47.5%) -- guaranteed 3HKO'
);
const result2 = calculate(weavile, audinoMega, knockoff);
expect(result2.desc()).toBe(
'0 Atk Weavile Knock Off vs. 0 HP / 0 Def Audino: 93-111 (26.8 - 31.9%) -- guaranteed 4HKO'
);
});
});

inGens(5, 9, ({gen, calculate, Pokemon, Move}) => {
test(`Multi-hit interaction with Multiscale (gen ${gen})`, () => {
const result = calculate(
Expand Down

0 comments on commit effac17

Please sign in to comment.