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

Knock off multihit #672

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
17 changes: 12 additions & 5 deletions calc/src/mechanics/gen56.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,12 +371,12 @@ export function calculateBWXY(
desc.attackBoost =
move.named('Foul Play') ? defender.boosts[attackStat] : attacker.boosts[attackStat];

if ((move.dropsStats && move.timesUsed! > 1) || move.hits > 1) {
if (move.timesUsed! > 1 || move.hits > 1) {
ShivaD173 marked this conversation as resolved.
Show resolved Hide resolved
// store boosts so intermediate boosts don't show.
const origDefBoost = desc.defenseBoost;
const origAtkBoost = desc.attackBoost;
let numAttacks = 1;
if (move.dropsStats && move.timesUsed! > 1) {
if (move.timesUsed! > 1) {
desc.moveTurns = `over ${move.timesUsed} turns`;
numAttacks = move.timesUsed!;
} else {
Expand All @@ -393,7 +393,7 @@ export function calculateBWXY(
hasAteAbilityTypeChange = hasAteAbilityTypeChange &&
attacker.hasAbility('Aerilate', 'Galvanize', 'Pixilate', 'Refrigerate');

if ((move.dropsStats && move.timesUsed! > 1)) {
if (move.timesUsed! > 1) {
// Adaptability does not change between hits of a multihit, only between turns
stabMod = getStabMod(attacker, move, desc);
}
Expand Down Expand Up @@ -600,7 +600,8 @@ export function calculateBasePowerBWXY(
desc,
basePower,
hasAteAbilityTypeChange,
turnOrder
turnOrder,
hit
);

basePower = OF16(Math.max(1, pokeRound((basePower * chainMods(bpMods, 41, 2097152)) / 4096)));
Expand All @@ -616,7 +617,8 @@ export function calculateBPModsBWXY(
desc: RawDesc,
basePower: number,
hasAteAbilityTypeChange: boolean,
turnOrder: string
turnOrder: string,
hit: number
) {
const bpMods = [];

Expand All @@ -637,6 +639,11 @@ export function calculateBPModsBWXY(
resistedKnockOffDamage = !!(item.megaEvolves && defender.name.includes(item.megaEvolves));
}

// Resist knock off damage if your item was already knocked off
if (!resistedKnockOffDamage && hit > 1 && !defender.hasAbility('Sticky Hold')) {
resistedKnockOffDamage = true;
}


// Use BasePower after moves with custom BP to determine if Technician should boost
if ((attacker.hasAbility('Technician') && basePower <= 60) ||
Expand Down
17 changes: 12 additions & 5 deletions calc/src/mechanics/gen789.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,13 +676,13 @@ export function calculateSMSSSV(
desc.attackBoost =
move.named('Foul Play') ? defender.boosts[attackStat] : attacker.boosts[attackStat];

if ((move.dropsStats && move.timesUsed! > 1) || move.hits > 1) {
if (move.timesUsed! > 1 || move.hits > 1) {
// store boosts so intermediate boosts don't show.
const origDefBoost = desc.defenseBoost;
const origAtkBoost = desc.attackBoost;

let numAttacks = 1;
if (move.dropsStats && move.timesUsed! > 1) {
if (move.timesUsed! > 1) {
desc.moveTurns = `over ${move.timesUsed} turns`;
numAttacks = move.timesUsed!;
} else {
Expand All @@ -701,7 +701,7 @@ export function calculateSMSSSV(
hasAteAbilityTypeChange = hasAteAbilityTypeChange &&
attacker.hasAbility('Aerilate', 'Galvanize', 'Pixilate', 'Refrigerate', 'Normalize');

if ((move.dropsStats && move.timesUsed! > 1)) {
if (move.timesUsed! > 1) {
// Adaptability does not change between hits of a multihit, only between turns
preStellarStabMod = getStabMod(attacker, move, desc);
// Hack to make Tera Shell with multihit moves, but not over multiple turns
Expand Down Expand Up @@ -1004,7 +1004,8 @@ export function calculateBasePowerSMSSSV(
desc,
basePower,
hasAteAbilityTypeChange,
turnOrder
turnOrder,
hit
);
basePower = OF16(Math.max(1, pokeRound((basePower * chainMods(bpMods, 41, 2097152)) / 4096)));
if (
Expand All @@ -1028,7 +1029,8 @@ export function calculateBPModsSMSSSV(
desc: RawDesc,
basePower: number,
hasAteAbilityTypeChange: boolean,
turnOrder: string
turnOrder: string,
hit: number
) {
const bpMods = [];

Expand Down Expand Up @@ -1061,6 +1063,11 @@ export function calculateBPModsSMSSSV(
resistedKnockOffDamage = !!item.megaEvolves && defender.name.includes(item.megaEvolves);
}

// Resist knock off damage if your item was already knocked off
if (!resistedKnockOffDamage && hit > 1 && !defender.hasAbility('Sticky Hold')) {
resistedKnockOffDamage = true;
}

if ((move.named('Facade') && attacker.hasStatus('brn', 'par', 'psn', 'tox')) ||
(move.named('Brine') && defender.curHP() <= defender.maxHP() / 2) ||
(move.named('Venoshock') && defender.hasStatus('psn', 'tox')) ||
Expand Down
2 changes: 1 addition & 1 deletion calc/src/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class Move implements State.Move {
if (data.self?.boosts && data.self.boosts[stat] && data.self.boosts[stat]! < 0) {
this.dropsStats = Math.abs(data.self.boosts[stat]!);
}
this.timesUsed = (this.dropsStats && options.timesUsed) || 1;
this.timesUsed = options.timesUsed || 1;
this.secondaries = data.secondaries;
// For the purposes of the damage formula only 'allAdjacent' and 'allAdjacentFoes' matter, so we
// simply default to 'any' for the others even though they may not actually be 'any'-target
Expand Down
7 changes: 1 addition & 6 deletions src/js/shared_controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,8 +521,6 @@ $(".move-selector").change(function () {
moveGroupObj.children(".move-crit").prop("checked", move.willCrit === true);

var stat = move.category === 'Special' ? 'spa' : 'atk';
var dropsStats =
move.self && move.self.boosts && move.self.boosts[stat] && move.self.boosts[stat] < 0;
if (Array.isArray(move.multihit) || (!isNaN(move.multihit) && move.multiaccuracy)) {
moveGroupObj.children(".stat-drops").hide();
moveGroupObj.children(".move-hits").empty();
Expand All @@ -548,12 +546,9 @@ $(".move-selector").change(function () {
}

moveGroupObj.children(".move-hits").val(moveHits);
} else if (dropsStats) {
moveGroupObj.children(".move-hits").hide();
moveGroupObj.children(".stat-drops").show();
} else {
moveGroupObj.children(".move-hits").hide();
moveGroupObj.children(".stat-drops").hide();
moveGroupObj.children(".stat-drops").show();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This being in the else block means it won't be shown for multihit moves (is it intentional because of accuracy issues?).

It can be smarter by only showing on moves that do damage, also the class should be renamed because .stat-drops is inaccurate with this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed. This was intentionally not done with multihits because i didn't want to make it too cluttered. This means that there is still at max 1 box active at a time. It is also quite dubious with accuracy, and I can't see where multiple hits and multiple times is useful other than maybe skill link and similar due to the inherent randomness of it.

}
moveGroupObj.children(".move-z").prop("checked", false);
});
Expand Down
Loading