Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Knock off Damage during Klutz/Magic Room #651

Merged
merged 4 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions calc/src/mechanics/gen56.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,18 +600,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 @@ -1003,30 +1003,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
Loading