Skip to content

Commit 8d527cb

Browse files
authored
Added Power Spot, Fixed Dauntless Shield, Made Competitive activate from Intimidate, Cleaned up EV and IV exporting (#435)
* Added Power Spot * Fixed a minor typo * fixed Dauntless Shield Bug (#436) * added a trigger for Competitive when opposing Pokemon has Intimidate * cleaned up IV and EV exporting * added iron ball check to immunity checks * added iron ball check to immunity checks, made terrain pulse only take terrain type for grounded pokemon * made max move names change based on ability * added Iron Ball to isGrounded check * Dynamic Max Moves get the right type, name and desc still wrong (#437)
1 parent 0cc3c16 commit 8d527cb

File tree

13 files changed

+96
-23
lines changed

13 files changed

+96
-23
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ $ cd calc && npm install
135135
```
136136

137137
Next, run `node build` from the root directory of your clone of this repository. This should
138-
run `npm run compile` in the `calc/` subdirectory to compile the `@smoogon/calc` package from
138+
run `npm run compile` in the `calc/` subdirectory to compile the `@smogon/calc` package from
139139
TypeScript to JavaScript that can be run in the browser, and then compile the 'templated' HTML
140140
and copy everything into the top-level `dist/` folder. To then view the UI, open `dist/index.html` -
141141
simply double-clicking on the file from your operating system's file manager UI should open it in

calc/src/desc.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface RawDesc {
2929
isProtected?: boolean;
3030
isReflect?: boolean;
3131
isBattery?: boolean;
32+
isPowerSpot?: boolean;
3233
isSwitching?: 'out' | 'in';
3334
moveBP?: number;
3435
moveName: string;
@@ -825,6 +826,9 @@ function buildDescription(description: RawDesc, attacker: Pokemon, defender: Pok
825826
if (description.isBattery) {
826827
output += ' Battery boosted ';
827828
}
829+
if (description.isPowerSpot) {
830+
output += ' Power Spot boosted ';
831+
}
828832
if (description.isSwitching) {
829833
output += ' switching boosted ';
830834
}

calc/src/field.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class Side implements State.Side {
7171
isFriendGuard: boolean;
7272
isAuroraVeil: boolean;
7373
isBattery: boolean;
74+
isPowerSpot: boolean;
7475
isSwitching?: 'out' | 'in';
7576

7677
constructor(side: State.Side = {}) {
@@ -91,6 +92,7 @@ export class Side implements State.Side {
9192
this.isFriendGuard = !!side.isFriendGuard;
9293
this.isAuroraVeil = !!side.isAuroraVeil;
9394
this.isBattery = !!side.isBattery;
95+
this.isPowerSpot = !!side.isPowerSpot;
9496
this.isSwitching = side.isSwitching;
9597
}
9698

calc/src/mechanics/gen56.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ export function calculateBWXY(
180180
} else if (defender.types[1] && effectiveness[defender.types[1]]! === 0) {
181181
typeEffectiveness = type1Effectiveness;
182182
}
183+
} else if (typeEffectiveness === 0 && move.hasType('Ground') && defender.hasItem('Iron Ball')) {
184+
typeEffectiveness = 1;
183185
}
184186

185187
if (typeEffectiveness === 0) {
@@ -202,7 +204,8 @@ export function calculateBWXY(
202204
(move.hasType('Electric') &&
203205
defender.hasAbility('Lightning Rod', 'Motor Drive', 'Volt Absorb')) ||
204206
(move.hasType('Ground') &&
205-
!field.isGravity && !move.named('Thousand Arrows') && defender.hasAbility('Levitate')) ||
207+
!field.isGravity && !defender.hasItem('Iron Ball') &&
208+
!move.named('Thousand Arrows') && defender.hasAbility('Levitate')) ||
206209
(move.flags.bullet && defender.hasAbility('Bulletproof')) ||
207210
(move.flags.sound && defender.hasAbility('Soundproof'))
208211
) {
@@ -456,6 +459,11 @@ export function calculateBWXY(
456459
desc.isBattery = true;
457460
}
458461

462+
if (field.attackerSide.isPowerSpot) {
463+
bpMods.push(0x14cc);
464+
desc.isPowerSpot = true;
465+
}
466+
459467
if (isAerilate || isPixilate || isRefrigerate || isNormalize) {
460468
bpMods.push(0x14cd);
461469
desc.attackerAbility = attacker.ability;

calc/src/mechanics/gen78.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export function calculateSMSS(
5858
checkKlutz(defender);
5959
checkSeedBoost(attacker, field);
6060
checkSeedBoost(defender, field);
61+
checkDauntlessShield(attacker);
62+
checkDauntlessShield(defender);
6163

6264
computeFinalStats(gen, attacker, defender, field, 'def', 'spd', 'spe');
6365

@@ -67,8 +69,6 @@ export function calculateSMSS(
6769
checkDownload(defender, attacker);
6870
checkIntrepidSword(attacker);
6971
checkIntrepidSword(defender);
70-
checkDauntlessShield(attacker);
71-
checkDauntlessShield(defender);
7272

7373
computeFinalStats(gen, attacker, defender, field, 'atk', 'spa');
7474

@@ -130,8 +130,7 @@ export function calculateSMSS(
130130
const isCritical = !defender.hasAbility('Battle Armor', 'Shell Armor') &&
131131
(move.isCrit || (attacker.hasAbility('Merciless') && defender.hasStatus('psn', 'tox'))) &&
132132
move.timesUsed === 1;
133-
134-
if (move.named('Weather Ball')) {
133+
if (move.named('Weather Ball') || move.originalName === 'Weather Ball') {
135134
const holdingUmbrella = attacker.hasItem('Utility Umbrella');
136135
move.type =
137136
field.hasWeather('Sun', 'Harsh Sunshine') && !holdingUmbrella ? 'Fire'
@@ -154,7 +153,8 @@ export function calculateSMSS(
154153
desc.attackerItem = attacker.item;
155154
desc.moveBP = move.bp;
156155
desc.moveType = move.type;
157-
} else if (move.named('Nature Power', 'Terrain Pulse')) {
156+
} else if (move.named('Nature Power') || move.originalName === 'Nature Power' ||
157+
((move.named('Terrain Pulse') || move.originalName === 'Terrain Pulse') && isGrounded(attacker, field))) {
158158
move.type =
159159
field.hasTerrain('Electric') ? 'Electric'
160160
: field.hasTerrain('Grassy') ? 'Grass'
@@ -234,6 +234,8 @@ export function calculateSMSS(
234234
} else if (defender.types[1] && effectiveness[defender.types[1]]! === 0) {
235235
typeEffectiveness = type1Effectiveness;
236236
}
237+
} else if (typeEffectiveness === 0 && move.hasType('Ground') && defender.hasItem('Iron Ball')) {
238+
typeEffectiveness = 1;
237239
}
238240

239241
if (typeEffectiveness === 0) {
@@ -256,7 +258,8 @@ export function calculateSMSS(
256258
(move.hasType('Electric') &&
257259
defender.hasAbility('Lightning Rod', 'Motor Drive', 'Volt Absorb')) ||
258260
(move.hasType('Ground') &&
259-
!field.isGravity && !move.named('Thousand Arrows') && defender.hasAbility('Levitate')) ||
261+
!field.isGravity && !defender.hasItem('Iron Ball') &&
262+
!move.named('Thousand Arrows') && defender.hasAbility('Levitate')) ||
260263
(move.flags.bullet && defender.hasAbility('Bulletproof')) ||
261264
(move.flags.sound && !move.named('Clangorous Soul') && defender.hasAbility('Soundproof')) ||
262265
(move.priority > 0 && defender.hasAbility('Queenly Majesty', 'Dazzling'))
@@ -648,7 +651,7 @@ export function calculateBasePowerSMSS(
648651
desc.moveBP = basePower;
649652
break;
650653
case 'Terrain Pulse':
651-
basePower = move.bp * (field.terrain ? 2 : 1);
654+
basePower = move.bp * (field.terrain && isGrounded(attacker, field) ? 2 : 1);
652655
desc.moveBP = basePower;
653656
break;
654657
case 'Fling':
@@ -812,6 +815,11 @@ export function calculateBPModsSMSS(
812815
desc.isBattery = true;
813816
}
814817

818+
if (field.attackerSide.isPowerSpot) {
819+
bpMods.push(0x14CD);
820+
desc.isPowerSpot = true;
821+
}
822+
815823
// Sheer Force does not power up max moves or remove the effects (SadisticMystic)
816824
const analyticBoost = attacker.hasAbility('Analytic') &&
817825
(turnOrder !== 'first' || field.defenderSide.isSwitching === 'out');

calc/src/mechanics/util.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const EV_ITEMS = [
2828
];
2929

3030
export function isGrounded(pokemon: Pokemon, field: Field) {
31-
return (field.isGravity ||
31+
return (field.isGravity || pokemon.hasItem('Iron Ball') ||
3232
(!pokemon.hasType('Flying') &&
3333
!pokemon.hasAbility('Levitate') &&
3434
!pokemon.hasItem('Air Balloon')));
@@ -181,6 +181,9 @@ export function checkIntimidate(gen: Generation, source: Pokemon, target: Pokemo
181181
} else {
182182
target.boosts.atk = Math.max(-6, target.boosts.atk - 1);
183183
}
184+
if(target.hasAbility('Competitive')) {
185+
target.boosts.spa = Math.min(6, target.boosts.spa + 2);
186+
}
184187
}
185188
}
186189

calc/src/move.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export class Move implements State.Move {
5858
const maxMoveName: string = getMaxMoveName(
5959
data.type,
6060
options.species,
61-
!!(data.category === 'Status')
61+
!!(data.category === 'Status'),
62+
options.ability
6263
);
6364
const maxMove = gen.moves.get(toID(maxMoveName));
6465
const maxPower = () => {
@@ -232,8 +233,9 @@ const ZMOVES_TYPING: {
232233
Water: 'Hydro Vortex',
233234
};
234235

235-
export function getMaxMoveName(moveType: I.TypeName, pokemonSpecies?: string, isStatus?: boolean) {
236+
export function getMaxMoveName(moveType: I.TypeName, pokemonSpecies?: string, isStatus?: boolean, pokemonAbility?: string) {
236237
if (isStatus) return 'Max Guard';
238+
if (pokemonAbility === 'Normalize') return 'Max Strike';
237239
if (moveType === 'Fire') {
238240
if (pokemonSpecies === 'Charizard-Gmax') return 'G-Max Wildfire';
239241
if (pokemonSpecies === 'Centiskorch-Gmax') return 'G-Max Centiferno';
@@ -243,6 +245,10 @@ export function getMaxMoveName(moveType: I.TypeName, pokemonSpecies?: string, is
243245
if (pokemonSpecies === 'Eevee-Gmax') return 'G-Max Cuddle';
244246
if (pokemonSpecies === 'Meowth-Gmax') return 'G-Max Gold Rush';
245247
if (pokemonSpecies === 'Snorlax-Gmax') return 'G-Max Replenish';
248+
if (pokemonAbility === 'Pixilate') return 'Max Starfall';
249+
if (pokemonAbility === 'Aerilate') return 'Max Airstream';
250+
if (pokemonAbility === 'Refrigerate') return 'Max Hailstorm';
251+
if (pokemonAbility === 'Galvanize') return 'Max Lightning';
246252
}
247253
if (moveType === 'Fairy') {
248254
if (pokemonSpecies === 'Alcremie-Gmax') return 'G-Max Finale';

calc/src/state.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export namespace State {
6161
isFriendGuard?: boolean;
6262
isAuroraVeil?: boolean;
6363
isBattery?: boolean;
64+
isPowerSpot?: boolean;
6465
isSwitching?: 'out' | 'in';
6566
}
6667
}

src/honkalculate.template.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,16 @@
774774
<input class="visually-hidden" type="checkbox" id="batteryR" />
775775
<label class="btn btn-xxwide" for="batteryR">Battery</label>
776776
</div>
777+
<div class="btn-group gen-specific g8">
778+
<div class="left" title="Has this Pok&eacute;mon's power been boosted by an ally's Power Spot ability?">
779+
<input class="visually-hidden" type="checkbox" id="powerSpotL" />
780+
<label class="btn btn-xxwide" for="powerSpotL">Power Spot</label>
781+
</div>
782+
<div class="right" title="Has this Pok&eacute;mon's power been boosted by an ally's Power Spot ability?">
783+
<input class="visually-hidden" type="checkbox" id="powerSpotR" />
784+
<label class="btn btn-xxwide" for="powerSpotR">Power Spot</label>
785+
</div>
786+
</div>
777787
<div class="btn-group gen-specific g2 g3 g4 g5 g6 g7 g8">
778788
<div class="left" title="Is the defending Pok&eacute;mon switching out?">
779789
<input class="visually-hidden" type="checkbox" id="switchingL" />

src/index.template.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,17 @@
893893
<label class="btn btn-xxwide" for="batteryR">Battery</label>
894894
</div></td>
895895
</tr>
896+
<tr class="gen-specific g8">
897+
<td><div class="left" title="Is the Pok&eacute;mon boosted by an ally's Power Spot ability?">
898+
<div hidden id="selectPowerSpotInstruction">Is the Pok&eacute;mon boosted by an ally's Power Spot ability?</div>
899+
<input aria-describedby="selectPowerSpotInstruction" class="visually-hidden calc-trigger" type="checkbox" id="powerSpotL" />
900+
<label class="btn btn-xxwide" for="powerSpotL">Power Spot</label>
901+
</div></td>
902+
<td><div class="right" title="Is the Pok&eacute;mon boosted by an ally's Power Spot ability?">
903+
<input aria-describedby="selectPowerSpotInstruction" class="visually-hidden calc-trigger" type="checkbox" id="powerSpotR" />
904+
<label class="btn btn-xxwide" for="powerSpotR">Power Spot</label>
905+
</div></td>
906+
</tr>
896907
<tr class="gen-specific g2 g3 g4 g5 g6 g7 g8">
897908
<td><div class="left" title="Is the defending Pok&eacute;mon switching out?">
898909
<div hidden id="selectSwitchingInstruction">Is the defending Pok&eacute;mon switching out?</div>

0 commit comments

Comments
 (0)