From b1c2f5b1574681e93c130de149efb6379a2bbb4f Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sat, 27 Mar 2021 12:20:56 -0400 Subject: [PATCH 01/10] Added Power Spot --- calc/src/desc.ts | 4 ++++ calc/src/field.ts | 2 ++ calc/src/mechanics/gen56.ts | 5 +++++ calc/src/mechanics/gen78.ts | 5 +++++ calc/src/state.ts | 1 + src/honkalculate.template.html | 10 ++++++++++ src/index.template.html | 11 +++++++++++ src/js/shared_controls.js | 3 ++- src/randoms.template.html | 11 +++++++++++ 9 files changed, 51 insertions(+), 1 deletion(-) diff --git a/calc/src/desc.ts b/calc/src/desc.ts index 2381b905f..27cac459c 100644 --- a/calc/src/desc.ts +++ b/calc/src/desc.ts @@ -29,6 +29,7 @@ export interface RawDesc { isProtected?: boolean; isReflect?: boolean; isBattery?: boolean; + isPowerSpot?: boolean; isSwitching?: 'out' | 'in'; moveBP?: number; moveName: string; @@ -825,6 +826,9 @@ function buildDescription(description: RawDesc, attacker: Pokemon, defender: Pok if (description.isBattery) { output += ' Battery boosted '; } + if (description.isPowerSpot) { + output += ' Power Spot boosted '; + } if (description.isSwitching) { output += ' switching boosted '; } diff --git a/calc/src/field.ts b/calc/src/field.ts index 19474d110..ec8f58632 100644 --- a/calc/src/field.ts +++ b/calc/src/field.ts @@ -71,6 +71,7 @@ export class Side implements State.Side { isFriendGuard: boolean; isAuroraVeil: boolean; isBattery: boolean; + isPowerSpot: boolean; isSwitching?: 'out' | 'in'; constructor(side: State.Side = {}) { @@ -91,6 +92,7 @@ export class Side implements State.Side { this.isFriendGuard = !!side.isFriendGuard; this.isAuroraVeil = !!side.isAuroraVeil; this.isBattery = !!side.isBattery; + this.isPowerSpot = !!side.isPowerSpot; this.isSwitching = side.isSwitching; } diff --git a/calc/src/mechanics/gen56.ts b/calc/src/mechanics/gen56.ts index 2073d9897..addf1094c 100644 --- a/calc/src/mechanics/gen56.ts +++ b/calc/src/mechanics/gen56.ts @@ -456,6 +456,11 @@ export function calculateBWXY( desc.isBattery = true; } + if (field.attackerSide.isPowerSpot) { + bpMods.push(0x14cc); + desc.isPowerSpot = true; + } + if (isAerilate || isPixilate || isRefrigerate || isNormalize) { bpMods.push(0x14cd); desc.attackerAbility = attacker.ability; diff --git a/calc/src/mechanics/gen78.ts b/calc/src/mechanics/gen78.ts index c78275e00..c5dd7d8c8 100644 --- a/calc/src/mechanics/gen78.ts +++ b/calc/src/mechanics/gen78.ts @@ -812,6 +812,11 @@ export function calculateBPModsSMSS( desc.isBattery = true; } + if (field.attackerSide.isPowerSpot) { + bpMods.push(0x14CD); + desc.isPowerSpot = true; + } + // Sheer Force does not power up max moves or remove the effects (SadisticMystic) const analyticBoost = attacker.hasAbility('Analytic') && (turnOrder !== 'first' || field.defenderSide.isSwitching === 'out'); diff --git a/calc/src/state.ts b/calc/src/state.ts index e1a99c4a3..bc39b9c75 100644 --- a/calc/src/state.ts +++ b/calc/src/state.ts @@ -61,6 +61,7 @@ export namespace State { isFriendGuard?: boolean; isAuroraVeil?: boolean; isBattery?: boolean; + isPowerSpot?: boolean; isSwitching?: 'out' | 'in'; } } diff --git a/src/honkalculate.template.html b/src/honkalculate.template.html index 0a7909ccd..4a82e5ee1 100644 --- a/src/honkalculate.template.html +++ b/src/honkalculate.template.html @@ -774,6 +774,16 @@ +
+
+ + +
+
+ + +
+
diff --git a/src/index.template.html b/src/index.template.html index bda007133..853012ea9 100644 --- a/src/index.template.html +++ b/src/index.template.html @@ -893,6 +893,17 @@
+ +
+ + + +
+
+ + +
+
diff --git a/src/js/shared_controls.js b/src/js/shared_controls.js index 67c5f8dbd..77bb77767 100644 --- a/src/js/shared_controls.js +++ b/src/js/shared_controls.js @@ -846,6 +846,7 @@ function createField() { var isFriendGuard = [$("#friendGuardL").prop("checked"), $("#friendGuardR").prop("checked")]; var isAuroraVeil = [$("#auroraVeilL").prop("checked"), $("#auroraVeilR").prop("checked")]; var isBattery = [$("#batteryL").prop("checked"), $("#batteryR").prop("checked")]; + var isPowerSpot = [$("#powerSpotL").prop("checked"), $("#powerSpotR").prop("checked")]; // TODO: support switching in as well! var isSwitchingOut = [$("#switchingL").prop("checked"), $("#switchingR").prop("checked")]; @@ -856,7 +857,7 @@ function createField() { isReflect: isReflect[i], isLightScreen: isLightScreen[i], isProtected: isProtected[i], isSeeded: isSeeded[i], isForesight: isForesight[i], isTailwind: isTailwind[i], isHelpingHand: isHelpingHand[i], isFriendGuard: isFriendGuard[i], - isAuroraVeil: isAuroraVeil[i], isBattery: isBattery[i], isSwitching: isSwitchingOut[i] ? 'out' : undefined + isAuroraVeil: isAuroraVeil[i], isBattery: isBattery[i], isPowerSpot: isPowerSpot[i], isSwitching: isSwitchingOut[i] ? 'out' : undefined }); }; return new calc.Field({ diff --git a/src/randoms.template.html b/src/randoms.template.html index 035f8c30e..215f393c5 100644 --- a/src/randoms.template.html +++ b/src/randoms.template.html @@ -877,6 +877,17 @@
+ +
+ + + +
+
+ + +
+
From d5d63a3b52bad7533833d106bc7110b4fa22c8dc Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sat, 27 Mar 2021 12:35:59 -0400 Subject: [PATCH 02/10] Fixed a minor typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 770abb844..a27fccd52 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ $ cd calc && npm install ``` Next, run `node build` from the root directory of your clone of this repository. This should -run `npm run compile` in the `calc/` subdirectory to compile the `@smoogon/calc` package from +run `npm run compile` in the `calc/` subdirectory to compile the `@smogon/calc` package from TypeScript to JavaScript that can be run in the browser, and then compile the 'templated' HTML and copy everything into the top-level `dist/` folder. To then view the UI, open `dist/index.html` - simply double-clicking on the file from your operating system's file manager UI should open it in From 95992d882d6d4feb3470f04104515a9a92917811 Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sat, 27 Mar 2021 22:30:02 -0400 Subject: [PATCH 03/10] fixed Dauntless Shield Bug (#436) --- calc/src/mechanics/gen78.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calc/src/mechanics/gen78.ts b/calc/src/mechanics/gen78.ts index c5dd7d8c8..b952fe9c9 100644 --- a/calc/src/mechanics/gen78.ts +++ b/calc/src/mechanics/gen78.ts @@ -58,6 +58,8 @@ export function calculateSMSS( checkKlutz(defender); checkSeedBoost(attacker, field); checkSeedBoost(defender, field); + checkDauntlessShield(attacker); + checkDauntlessShield(defender); computeFinalStats(gen, attacker, defender, field, 'def', 'spd', 'spe'); @@ -67,8 +69,6 @@ export function calculateSMSS( checkDownload(defender, attacker); checkIntrepidSword(attacker); checkIntrepidSword(defender); - checkDauntlessShield(attacker); - checkDauntlessShield(defender); computeFinalStats(gen, attacker, defender, field, 'atk', 'spa'); From faed3236d0ec019ae55c57940ffe649b0864d57f Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sat, 27 Mar 2021 22:31:19 -0400 Subject: [PATCH 04/10] added a trigger for Competitive when opposing Pokemon has Intimidate --- calc/src/mechanics/util.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/calc/src/mechanics/util.ts b/calc/src/mechanics/util.ts index c81d6cc5e..23d3e00fd 100644 --- a/calc/src/mechanics/util.ts +++ b/calc/src/mechanics/util.ts @@ -181,6 +181,9 @@ export function checkIntimidate(gen: Generation, source: Pokemon, target: Pokemo } else { target.boosts.atk = Math.max(-6, target.boosts.atk - 1); } + if(target.hasAbility('Competitive')) { + target.boosts.spa = Math.min(6, target.boosts.spa + 2); + } } } From 02e79d3066fbf46d27ea28499a5214b947379232 Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sun, 28 Mar 2021 14:47:27 -0400 Subject: [PATCH 05/10] cleaned up IV and EV exporting --- src/js/moveset_import.js | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/js/moveset_import.js b/src/js/moveset_import.js index 895bd2410..263180c7f 100644 --- a/src/js/moveset_import.js +++ b/src/js/moveset_import.js @@ -17,27 +17,35 @@ function ExportPokemon(pokeInfo) { finalText += "Level: " + pokemon.level + "\n"; finalText += pokemon.nature && gen > 2 ? pokemon.nature + " Nature" + "\n" : ""; finalText += pokemon.ability ? "Ability: " + pokemon.ability + "\n" : ""; - if (gen > 2) { - finalText += "EVs: "; + if (gen > 2) { var EVs_Array = []; for (var stat in pokemon.evs) { var ev = pokemon.evs[stat] ? pokemon.evs[stat] : 0; - EVs_Array.push(ev + " " + calc.Stats.displayStat(stat)); + if(ev > 0) { + EVs_Array.push(ev + " " + calc.Stats.displayStat(stat)); + } EV_counter += ev; if (EV_counter > 510) break; } - finalText += serialize(EVs_Array, " / "); - finalText += "\n"; + if(EVs_Array.length > 0){ + finalText += "EVs: "; + finalText += serialize(EVs_Array, " / "); + finalText += "\n"; + } } - - finalText += "IVs: "; + var IVs_Array = []; for (var stat in pokemon.ivs) { var iv = pokemon.ivs[stat] ? pokemon.ivs[stat] : 0; - IVs_Array.push(iv + " " + calc.Stats.displayStat(stat)); + if(iv < 31) { + IVs_Array.push(iv + " " + calc.Stats.displayStat(stat)); + } + } + if(IVs_Array.length > 0) { + finalText += "IVs: "; + finalText += serialize(IVs_Array, " / "); + finalText += "\n"; } - finalText += serialize(IVs_Array, " / "); - finalText += "\n"; for (var i = 0; i < 4; i++) { var moveName = pokemon.moves[i].name; From 086326fbb4479ebd565a86fd9dc52e970420e8a4 Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sun, 28 Mar 2021 19:50:27 -0400 Subject: [PATCH 06/10] added iron ball check to immunity checks --- calc/src/mechanics/gen56.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/calc/src/mechanics/gen56.ts b/calc/src/mechanics/gen56.ts index addf1094c..0fcfd84f2 100644 --- a/calc/src/mechanics/gen56.ts +++ b/calc/src/mechanics/gen56.ts @@ -180,6 +180,8 @@ export function calculateBWXY( } else if (defender.types[1] && effectiveness[defender.types[1]]! === 0) { typeEffectiveness = type1Effectiveness; } + } else if (typeEffectiveness === 0 && move.hasType('Ground') && defender.hasItem('Iron Ball')) { + typeEffectiveness = 1; } if (typeEffectiveness === 0) { @@ -202,7 +204,8 @@ export function calculateBWXY( (move.hasType('Electric') && defender.hasAbility('Lightning Rod', 'Motor Drive', 'Volt Absorb')) || (move.hasType('Ground') && - !field.isGravity && !move.named('Thousand Arrows') && defender.hasAbility('Levitate')) || + !field.isGravity && !defender.hasItem('Iron Ball') && + !move.named('Thousand Arrows') && defender.hasAbility('Levitate')) || (move.flags.bullet && defender.hasAbility('Bulletproof')) || (move.flags.sound && defender.hasAbility('Soundproof')) ) { From 913c489bb917443d4700bf2beadbd661ae0634d6 Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sun, 28 Mar 2021 19:51:24 -0400 Subject: [PATCH 07/10] added iron ball check to immunity checks, made terrain pulse only take terrain type for grounded pokemon --- calc/src/mechanics/gen78.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/calc/src/mechanics/gen78.ts b/calc/src/mechanics/gen78.ts index b952fe9c9..85452ddae 100644 --- a/calc/src/mechanics/gen78.ts +++ b/calc/src/mechanics/gen78.ts @@ -154,7 +154,7 @@ export function calculateSMSS( desc.attackerItem = attacker.item; desc.moveBP = move.bp; desc.moveType = move.type; - } else if (move.named('Nature Power', 'Terrain Pulse')) { + } else if (move.named('Nature Power') || (move.named('Terrain Pulse') && isGrounded(attacker, field))) { move.type = field.hasTerrain('Electric') ? 'Electric' : field.hasTerrain('Grassy') ? 'Grass' @@ -234,6 +234,8 @@ export function calculateSMSS( } else if (defender.types[1] && effectiveness[defender.types[1]]! === 0) { typeEffectiveness = type1Effectiveness; } + } else if (typeEffectiveness === 0 && move.hasType('Ground') && defender.hasItem('Iron Ball')) { + typeEffectiveness = 1; } if (typeEffectiveness === 0) { @@ -256,7 +258,8 @@ export function calculateSMSS( (move.hasType('Electric') && defender.hasAbility('Lightning Rod', 'Motor Drive', 'Volt Absorb')) || (move.hasType('Ground') && - !field.isGravity && !move.named('Thousand Arrows') && defender.hasAbility('Levitate')) || + !field.isGravity && !defender.hasItem('Iron Ball') && + !move.named('Thousand Arrows') && defender.hasAbility('Levitate')) || (move.flags.bullet && defender.hasAbility('Bulletproof')) || (move.flags.sound && !move.named('Clangorous Soul') && defender.hasAbility('Soundproof')) || (move.priority > 0 && defender.hasAbility('Queenly Majesty', 'Dazzling')) @@ -648,7 +651,7 @@ export function calculateBasePowerSMSS( desc.moveBP = basePower; break; case 'Terrain Pulse': - basePower = move.bp * (field.terrain ? 2 : 1); + basePower = move.bp * (field.terrain && isGrounded(attacker, field) ? 2 : 1); desc.moveBP = basePower; break; case 'Fling': From c47a3ab90ffd3ee8781809104613674c038b0e25 Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sun, 28 Mar 2021 19:52:25 -0400 Subject: [PATCH 08/10] made max move names change based on ability --- calc/src/move.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/calc/src/move.ts b/calc/src/move.ts index 4e9ec64a4..1384b7ee1 100644 --- a/calc/src/move.ts +++ b/calc/src/move.ts @@ -58,7 +58,8 @@ export class Move implements State.Move { const maxMoveName: string = getMaxMoveName( data.type, options.species, - !!(data.category === 'Status') + !!(data.category === 'Status'), + options.ability ); const maxMove = gen.moves.get(toID(maxMoveName)); const maxPower = () => { @@ -232,8 +233,9 @@ const ZMOVES_TYPING: { Water: 'Hydro Vortex', }; -export function getMaxMoveName(moveType: I.TypeName, pokemonSpecies?: string, isStatus?: boolean) { +export function getMaxMoveName(moveType: I.TypeName, pokemonSpecies?: string, isStatus?: boolean, pokemonAbility?: string) { if (isStatus) return 'Max Guard'; + if (pokemonAbility === 'Normalize') return 'Max Strike'; if (moveType === 'Fire') { if (pokemonSpecies === 'Charizard-Gmax') return 'G-Max Wildfire'; if (pokemonSpecies === 'Centiskorch-Gmax') return 'G-Max Centiferno'; @@ -243,6 +245,10 @@ export function getMaxMoveName(moveType: I.TypeName, pokemonSpecies?: string, is if (pokemonSpecies === 'Eevee-Gmax') return 'G-Max Cuddle'; if (pokemonSpecies === 'Meowth-Gmax') return 'G-Max Gold Rush'; if (pokemonSpecies === 'Snorlax-Gmax') return 'G-Max Replenish'; + if (pokemonAbility === 'Pixilate') return 'Max Starfall'; + if (pokemonAbility === 'Aerilate') return 'Max Airstream'; + if (pokemonAbility === 'Refrigerate') return 'Max Hailstorm'; + if (pokemonAbility === 'Galvanize') return 'Max Lightning'; } if (moveType === 'Fairy') { if (pokemonSpecies === 'Alcremie-Gmax') return 'G-Max Finale'; From e593be205304662bb75621c38f9cdde882cb0a3d Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sun, 28 Mar 2021 19:52:48 -0400 Subject: [PATCH 09/10] added Iron Ball to isGrounded check --- calc/src/mechanics/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calc/src/mechanics/util.ts b/calc/src/mechanics/util.ts index 23d3e00fd..4a873868c 100644 --- a/calc/src/mechanics/util.ts +++ b/calc/src/mechanics/util.ts @@ -28,7 +28,7 @@ const EV_ITEMS = [ ]; export function isGrounded(pokemon: Pokemon, field: Field) { - return (field.isGravity || + return (field.isGravity || pokemon.hasItem('Iron Ball') || (!pokemon.hasType('Flying') && !pokemon.hasAbility('Levitate') && !pokemon.hasItem('Air Balloon'))); From 01d96563da01239bfaadff05f463af489f97ef8a Mon Sep 17 00:00:00 2001 From: Jake Magier Date: Sun, 28 Mar 2021 22:57:11 -0400 Subject: [PATCH 10/10] Dynamic Max Moves get the right type, name and desc still wrong (#437) --- calc/src/mechanics/gen78.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/calc/src/mechanics/gen78.ts b/calc/src/mechanics/gen78.ts index 85452ddae..0f76d631e 100644 --- a/calc/src/mechanics/gen78.ts +++ b/calc/src/mechanics/gen78.ts @@ -130,8 +130,7 @@ export function calculateSMSS( const isCritical = !defender.hasAbility('Battle Armor', 'Shell Armor') && (move.isCrit || (attacker.hasAbility('Merciless') && defender.hasStatus('psn', 'tox'))) && move.timesUsed === 1; - - if (move.named('Weather Ball')) { + if (move.named('Weather Ball') || move.originalName === 'Weather Ball') { const holdingUmbrella = attacker.hasItem('Utility Umbrella'); move.type = field.hasWeather('Sun', 'Harsh Sunshine') && !holdingUmbrella ? 'Fire' @@ -154,7 +153,8 @@ export function calculateSMSS( desc.attackerItem = attacker.item; desc.moveBP = move.bp; desc.moveType = move.type; - } else if (move.named('Nature Power') || (move.named('Terrain Pulse') && isGrounded(attacker, field))) { + } else if (move.named('Nature Power') || move.originalName === 'Nature Power' || + ((move.named('Terrain Pulse') || move.originalName === 'Terrain Pulse') && isGrounded(attacker, field))) { move.type = field.hasTerrain('Electric') ? 'Electric' : field.hasTerrain('Grassy') ? 'Grass'