Skip to content

Commit

Permalink
Fix multihit interactions with tera stellar and tera shell
Browse files Browse the repository at this point in the history
  • Loading branch information
ShivaD173 committed Dec 31, 2023
1 parent 50ca0f6 commit 05df464
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 49 deletions.
14 changes: 2 additions & 12 deletions calc/src/mechanics/gen56.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
getFinalDamage,
getModifiedStat,
getMoveEffectiveness,
getStabMod,
getWeightFactor,
handleFixedDamageMoves,
isGrounded,
Expand Down Expand Up @@ -754,18 +755,7 @@ export function calculateBWXY(

// the random factor is applied between the crit mod and the stab mod, so don't apply anything
// below this until we're inside the loop
let stabMod = 4096;
if (attacker.hasType(move.type)) {
if (attacker.hasAbility('Adaptability')) {
stabMod = 8192;
desc.attackerAbility = attacker.ability;
} else {
stabMod = 6144;
}
} else if (attacker.hasAbility('Protean')) {
stabMod = 6144;
desc.attackerAbility = attacker.ability;
}
const stabMod = getStabMod(attacker, move, desc);

const applyBurn =
attacker.hasStatus('brn') &&
Expand Down
57 changes: 23 additions & 34 deletions calc/src/mechanics/gen789.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import {
OF16, OF32,
pokeRound,
isQPActive,
getStabMod,
getStellarStabMod,
} from './util';

export function calculateSMSSSV(
Expand Down Expand Up @@ -345,6 +347,8 @@ export function calculateSMSSSV(
typeEffectiveness = !defender.teraType ? 1 : 2;
}

const turn2typeEffectiveness = typeEffectiveness;

// Tera Shell works only at full HP, but for all hits of multi-hit moves
if (defender.hasAbility('Tera Shell') &&
defender.curHP() === defender.maxHP() &&
Expand Down Expand Up @@ -511,34 +515,8 @@ export function calculateSMSSSV(

// the random factor is applied between the crit mod and the stab mod, so don't apply anything
// below this until we're inside the loop
let stabMod = 4096;
if (attacker.hasOriginalType(move.type)) {
stabMod += 2048;
} else if (attacker.hasAbility('Protean', 'Libero') && !attacker.teraType) {
stabMod += 2048;
desc.attackerAbility = attacker.ability;
}
const teraType = attacker.teraType;
if (teraType === move.type && teraType !== 'Stellar') {
stabMod += 2048;
desc.attackerTera = teraType;
}
if (attacker.hasAbility('Adaptability') && attacker.hasType(move.type)) {
stabMod += teraType && attacker.hasOriginalType(teraType) ? 1024 : 2048;
desc.attackerAbility = attacker.ability;
}

// TODO: For now all moves are always boosted
const isStellarBoosted =
attacker.teraType === 'Stellar' &&
(move.isStellarFirstUse || attacker.named('Terapagos-Stellar'));
if (isStellarBoosted) {
if (attacker.hasOriginalType(move.type)) {
stabMod += 2048;
} else {
stabMod = 4915;
}
}
let preStellarStabMod = getStabMod(attacker, move, desc);
let stabMod = getStellarStabMod(attacker, move, preStellarStabMod);

const applyBurn =
attacker.hasStatus('brn') &&
Expand Down Expand Up @@ -613,6 +591,15 @@ export function calculateSMSSSV(
hasAteAbilityTypeChange = hasAteAbilityTypeChange &&
attacker.hasAbility('Aerilate', 'Galvanize', 'Pixilate', 'Refrigerate', 'Normalize');

if ((move.dropsStats && 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
typeEffectiveness = turn2typeEffectiveness;
}
// Stellar damage boost drops off after first hit, even on multihit moves
stabMod = getStellarStabMod(attacker, move, preStellarStabMod, times);

const newFinalMods = calculateFinalModsSMSSSV(
gen,
attacker,
Expand All @@ -632,7 +619,8 @@ export function calculateSMSSSV(
move,
field,
hasAteAbilityTypeChange,
desc
desc,
times + 1
);
const newBaseDamage = calculateBaseDamageSMSSSV(
gen,
Expand Down Expand Up @@ -681,7 +669,8 @@ export function calculateBasePowerSMSSSV(
move: Move,
field: Field,
hasAteAbilityTypeChange: boolean,
desc: RawDesc
desc: RawDesc,
hit = 1,
) {
const turnOrder = attacker.stats.spe > defender.stats.spe ? 'first' : 'last';

Expand Down Expand Up @@ -844,13 +833,13 @@ export function calculateBasePowerSMSSSV(
break;
// Triple Axel's damage doubles after each consecutive hit (20, 40, 60), this is a hack
case 'Triple Axel':
basePower = move.hits === 2 ? 30 : move.hits === 3 ? 40 : 20;
desc.moveBP = basePower;
basePower = hit * 20;
desc.moveBP = move.hits === 2 ? 60 : move.hits === 3 ? 120 : 20;
break;
// Triple Kick's damage doubles after each consecutive hit (10, 20, 30), this is a hack
case 'Triple Kick':
basePower = move.hits === 2 ? 15 : move.hits === 3 ? 30 : 10;
desc.moveBP = basePower;
basePower = hit * 10;
desc.moveBP = move.hits === 2 ? 30 : move.hits === 3 ? 60 : 20;
break;
case 'Crush Grip':
case 'Wring Out':
Expand Down
38 changes: 36 additions & 2 deletions calc/src/mechanics/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,15 @@ export function checkMultihitBoost(
field.weather = 'Sand';
}

if (defender.hasAbility('Stamina')) {
if (defender.hasAbility('Stamina') && !move.isCrit) {
if (attacker.hasAbility('Unaware')) {
desc.attackerAbility = attacker.ability;
} else {
defender.boosts.def = Math.min(defender.boosts.def + 1, 6);
defender.stats.def = getModifiedStat(defender.rawStats.def, defender.boosts.def, gen);
desc.defenderAbility = defender.ability;
}
} else if (defender.hasAbility('Water Compaction') && move.hasType('Water')) {
} else if (defender.hasAbility('Water Compaction') && move.hasType('Water') && !move.isCrit) {
if (attacker.hasAbility('Unaware')) {
desc.attackerAbility = attacker.ability;
} else {
Expand Down Expand Up @@ -556,6 +556,40 @@ export function getWeightFactor(pokemon: Pokemon) {
: (pokemon.hasAbility('Light Metal') || pokemon.hasItem('Float Stone')) ? 0.5 : 1;
}

export function getStabMod(pokemon: Pokemon, move: Move, desc: RawDesc) {
let stabMod = 4096;
if (pokemon.hasOriginalType(move.type)) {
stabMod += 2048;
} else if (pokemon.hasAbility('Protean', 'Libero') && !pokemon.teraType) {
stabMod += 2048;
desc.attackerAbility = pokemon.ability;
}
const teraType = pokemon.teraType;
if (teraType === move.type && teraType !== 'Stellar') {
stabMod += 2048;
desc.attackerTera = teraType;
}
if (pokemon.hasAbility('Adaptability') && pokemon.hasType(move.type)) {
stabMod += teraType && pokemon.hasOriginalType(teraType) ? 1024 : 2048;
desc.attackerAbility = pokemon.ability;
}
return stabMod;
}

export function getStellarStabMod(pokemon: Pokemon, move: Move, stabMod = 1, turns = 0) {
const isStellarBoosted =
pokemon.teraType === 'Stellar' &&
((move.isStellarFirstUse && turns === 0) || pokemon.named('Terapagos-Stellar'));
if (isStellarBoosted) {
if (pokemon.hasOriginalType(move.type)) {
stabMod += 2048;
} else {
stabMod = 4915;
}
}
return stabMod;
}

export function countBoosts(gen: Generation, boosts: StatsTable) {
let sum = 0;

Expand Down
1 change: 0 additions & 1 deletion src/js/shared_controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,6 @@ function showFormes(formeObj, pokemonName, pokemon, baseFormeName) {
function stellarButtonsVisibility(pokeObj, vis) {
var fullSetName = pokeObj.find("input.set-selector").val();
var pokemonName = fullSetName.substring(0, fullSetName.indexOf(" ("));
console.log(pokemonName);
var moveObjs = [
pokeObj.find(".move1"),
pokeObj.find(".move2"),
Expand Down

0 comments on commit 05df464

Please sign in to comment.