mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-06-02 22:08:36 -05:00
Implement Mega Sol and Spicy Spray in the base mod (#12017)
Some checks failed
Node.js CI / build (18.x) (push) Has been cancelled
Some checks failed
Node.js CI / build (18.x) (push) Has been cancelled
* Implement Mega Sol and Spicy Spray in the base mod * Remove empty line * Refactor check in Growth * Fix
This commit is contained in:
parent
537ee47903
commit
e1290bb1fc
|
|
@ -2683,7 +2683,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
|
|||
|
|
@ -2512,11 +2512,11 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
megasol: {
|
||||
isNonstandard: "Future",
|
||||
onWeatherModifyDamagePriority: 1,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (this.field.weather !== 'sunnyday') {
|
||||
(this.dex.conditions.getByID('sunnyday' as ID) as any).onWeatherModifyDamage
|
||||
.call(this, damage, attacker, defender, move);
|
||||
}
|
||||
(this.dex.conditions.getByID('sunnyday' as ID) as any).onWeatherModifyDamage
|
||||
.call(this, damage, attacker, defender, move);
|
||||
return damage; // fast exit from event
|
||||
},
|
||||
flags: {},
|
||||
name: "Mega Sol",
|
||||
|
|
@ -4421,7 +4421,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
spicyspray: {
|
||||
isNonstandard: "Future",
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
source.trySetStatus('brn', target);
|
||||
if (!source.trySetStatus('brn', target) && !source.status && source.hasType('Fire')) {
|
||||
this.add('-immune', source);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Spicy Spray",
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
// So we give it increased priority.
|
||||
onModifySpDPriority: 10,
|
||||
onModifySpD(spd, pokemon) {
|
||||
if (pokemon.hasType('Rock') && this.field.isWeather('sandstorm')) {
|
||||
if (pokemon.hasType('Rock') && pokemon.effectiveWeather() === 'sandstorm') {
|
||||
return this.modify(spd, 1.5);
|
||||
}
|
||||
},
|
||||
|
|
@ -705,7 +705,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
},
|
||||
onModifyDefPriority: 10,
|
||||
onModifyDef(def, pokemon) {
|
||||
if (pokemon.hasType('Ice') && this.field.isWeather('snowscape')) {
|
||||
if (pokemon.hasType('Ice') && pokemon.effectiveWeather() === 'snowscape') {
|
||||
return this.modify(def, 1.5);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
|
|||
|
|
@ -77,12 +77,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
spicyspray: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
// this is only in the mod folder because it is weird like Dire Claw
|
||||
if (!source.trySetStatus('brn', target) && !source.status && source.hasType('Fire')) {
|
||||
this.add('-immune', source);
|
||||
}
|
||||
},
|
||||
},
|
||||
unseenfist: {
|
||||
onModifyMove: undefined, // no inherit
|
||||
|
|
|
|||
|
|
@ -54,90 +54,4 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
return false;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* If Utility Umbrella continues to work as in previous gens and Mega Sol continues to bypass defensive
|
||||
* weather boosts, the best implementation is:
|
||||
* - run WeatherModifyDamage with `fastExit`
|
||||
* - give WeatherModifyDamagePriority to Mega Sol
|
||||
* - delete the weather conditions below
|
||||
*/
|
||||
raindance: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'raindance') return;
|
||||
if (move.type === 'Water') {
|
||||
this.debug('rain water boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('rain fire suppress');
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
primordialsea: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'primordialsea') return;
|
||||
if (move.type === 'Water') {
|
||||
this.debug('Rain water boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
sunnyday: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'sunnyday') return;
|
||||
if (move.id === 'hydrosteam') {
|
||||
this.debug('Sunny Day Hydro Steam boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('Sunny Day fire boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
if (move.type === 'Water') {
|
||||
this.debug('Sunny Day water suppress');
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
desolateland: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'desolateland') return;
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('Desolate Land fire boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
sandstorm: {
|
||||
inherit: true,
|
||||
onModifySpD(spd, target, source) {
|
||||
if (target.hasType('Rock') && source.effectiveWeather() === 'sandstorm') {
|
||||
return this.modify(spd, 1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
snowscape: {
|
||||
inherit: true,
|
||||
onModifyDef(def, target, source) {
|
||||
if (target.hasType('Ice') && source.effectiveWeather() === 'snowscape') {
|
||||
return this.modify(def, 1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
// TODO: check Mega Sol's interaction with Deltastream
|
||||
// deltastream: {
|
||||
// inherit: true,
|
||||
// onEffectiveness(typeMod, target, type, move) {
|
||||
// if (move && move.effectType === 'Move' && move.category !== 'Status' && type === 'Flying' && typeMod > 0) {
|
||||
// this.add('-fieldactivate', 'Delta Stream');
|
||||
// return 0;
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -116,16 +116,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
ceaselessedge: {
|
||||
inherit: true,
|
||||
onAfterHit(target, source, move) {
|
||||
if (!move.hasSheerForce && source.hp) {
|
||||
for (const side of source.side.foeSidesWithConditions()) {
|
||||
side.addSideCondition('spikes');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
celebrate: {
|
||||
inherit: true,
|
||||
isNonstandard: "Past",
|
||||
|
|
@ -470,14 +460,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
growth: {
|
||||
inherit: true,
|
||||
onModifyMove(move, pokemon) {
|
||||
if (pokemon.hasAbility('megasol') && this.field.weather !== 'sunnyday') {
|
||||
// TODO: check in future patches
|
||||
delete move.boosts;
|
||||
} else if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) {
|
||||
move.boosts = { atk: 2, spa: 2 };
|
||||
}
|
||||
},
|
||||
type: "Grass",
|
||||
},
|
||||
gust: {
|
||||
|
|
@ -987,16 +969,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
isNonstandard: "Past",
|
||||
},
|
||||
stoneaxe: {
|
||||
inherit: true,
|
||||
onAfterHit(target, source, move) {
|
||||
if (!move.hasSheerForce && source.hp) {
|
||||
for (const side of source.side.foeSidesWithConditions()) {
|
||||
side.addSideCondition('stealthrock');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
stormthrow: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Weather
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
if (move.category === 'Physical' && !Math.floor(baseDamage)) {
|
||||
baseDamage = 1;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Weather
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
baseDamage += 2;
|
||||
|
||||
|
|
|
|||
|
|
@ -688,7 +688,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
|
|||
|
|
@ -2227,7 +2227,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
priority: 0,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, slicing: 1 },
|
||||
onAfterHit(target, source, move) {
|
||||
if (!move.hasSheerForce) {
|
||||
if (!move.hasSheerForce && source.hp) {
|
||||
for (const side of source.side.foeSidesWithConditions()) {
|
||||
side.addSideCondition('spikes');
|
||||
}
|
||||
|
|
@ -7867,7 +7867,11 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
priority: 0,
|
||||
flags: { snatch: 1, metronome: 1 },
|
||||
onModifyMove(move, pokemon) {
|
||||
if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) move.boosts = { atk: 2, spa: 2 };
|
||||
if (pokemon.hasAbility('megasol') && !this.field.isWeather('sunnyday')) {
|
||||
delete move.boosts;
|
||||
} else if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) {
|
||||
move.boosts = { atk: 2, spa: 2 };
|
||||
}
|
||||
},
|
||||
boosts: {
|
||||
atk: 1,
|
||||
|
|
@ -12252,7 +12256,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
flags: { snatch: 1, heal: 1, metronome: 1 },
|
||||
onHit(pokemon) {
|
||||
let factor = 0.5;
|
||||
switch (pokemon.effectiveWeather(true)) {
|
||||
switch (pokemon.effectiveWeather(undefined, true)) {
|
||||
case 'sunnyday':
|
||||
case 'desolateland':
|
||||
factor = 0.667;
|
||||
|
|
@ -12288,7 +12292,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
flags: { snatch: 1, heal: 1, metronome: 1 },
|
||||
onHit(pokemon) {
|
||||
let factor = 0.5;
|
||||
switch (pokemon.effectiveWeather(true)) {
|
||||
switch (pokemon.effectiveWeather(undefined, true)) {
|
||||
case 'sunnyday':
|
||||
case 'desolateland':
|
||||
factor = 0.667;
|
||||
|
|
@ -17236,7 +17240,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
return;
|
||||
}
|
||||
this.add('-prepare', attacker, move.name);
|
||||
if (['sunnyday', 'desolateland'].includes(attacker.effectiveWeather(true))) {
|
||||
if (['sunnyday', 'desolateland'].includes(attacker.effectiveWeather(undefined, true))) {
|
||||
this.attrLastMove('[still]');
|
||||
this.addMove('-anim', attacker, move.name, defender);
|
||||
return;
|
||||
|
|
@ -17272,7 +17276,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
return;
|
||||
}
|
||||
this.add('-prepare', attacker, move.name);
|
||||
if (['sunnyday', 'desolateland'].includes(attacker.effectiveWeather(true))) {
|
||||
if (['sunnyday', 'desolateland'].includes(attacker.effectiveWeather(undefined, true))) {
|
||||
this.attrLastMove('[still]');
|
||||
this.addMove('-anim', attacker, move.name, defender);
|
||||
return;
|
||||
|
|
@ -18082,7 +18086,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
priority: 0,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, slicing: 1 },
|
||||
onAfterHit(target, source, move) {
|
||||
if (!move.hasSheerForce) {
|
||||
if (!move.hasSheerForce && source.hp) {
|
||||
for (const side of source.side.foeSidesWithConditions()) {
|
||||
side.addSideCondition('stealthrock');
|
||||
}
|
||||
|
|
@ -18739,7 +18743,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
flags: { snatch: 1, heal: 1, metronome: 1 },
|
||||
onHit(pokemon) {
|
||||
let factor = 0.5;
|
||||
switch (pokemon.effectiveWeather(true)) {
|
||||
switch (pokemon.effectiveWeather(undefined, true)) {
|
||||
case 'sunnyday':
|
||||
case 'desolateland':
|
||||
factor = 0.667;
|
||||
|
|
|
|||
|
|
@ -1747,7 +1747,7 @@ export class BattleActions {
|
|||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
|
|||
|
|
@ -495,6 +495,7 @@ export interface EventMethods {
|
|||
onTryMovePriority?: number;
|
||||
onTryPrimaryHitPriority?: number;
|
||||
onTypePriority?: number;
|
||||
onWeatherModifyDamagePriority?: number;
|
||||
}
|
||||
|
||||
export interface PokemonEventMethods extends EventMethods {
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ interface ModdedBattlePokemon {
|
|||
this: Pokemon, move: string | Move, amount?: number | null, target?: Pokemon | null | false
|
||||
) => number;
|
||||
eatItem?: (this: Pokemon, force?: boolean, source?: Pokemon, sourceEffect?: Effect) => boolean;
|
||||
effectiveWeather?: (this: Pokemon, message?: string | boolean) => ID;
|
||||
effectiveWeather?: (this: Pokemon, sourceEffect?: Effect, message?: string | boolean) => ID;
|
||||
formeChange?: (
|
||||
this: Pokemon, speciesId: string | Species, source: Effect, isPermanent?: boolean, abilitySlot?: string,
|
||||
message?: string,
|
||||
|
|
|
|||
|
|
@ -2187,8 +2187,15 @@ export class Pokemon {
|
|||
* Like Field.effectiveWeather(), but ignores sun and rain if
|
||||
* the Utility Umbrella is active for the Pokemon.
|
||||
*/
|
||||
effectiveWeather(message?: string | boolean) {
|
||||
effectiveWeather(sourceEffect?: Effect, message?: string | boolean) {
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
const weather = this.battle.field.effectiveWeather();
|
||||
if (this.battle.activePokemon?.hasAbility('megasol') && sourceEffect &&
|
||||
(sourceEffect.id === 'megasol' || sourceEffect.effectType === 'Move' || sourceEffect.effectType === 'Weather') &&
|
||||
sourceEffect.id !== 'electroshot') {
|
||||
if (weather !== 'sunnyday' && message) this.battle.add('-activate', this, 'ability: Mega Sol');
|
||||
return 'sunnyday' as ID;
|
||||
}
|
||||
switch (weather) {
|
||||
case 'sunnyday':
|
||||
case 'raindance':
|
||||
|
|
@ -2196,11 +2203,6 @@ export class Pokemon {
|
|||
case 'primordialsea':
|
||||
if (this.hasItem('utilityumbrella')) return '';
|
||||
}
|
||||
// TODO: check interactions of Mega Sol with Utility Umbrella and Desolate Land
|
||||
if (this.hasAbility('megasol') && this.battle.activePokemon === this && weather !== 'sunnyday') {
|
||||
if (message) this.battle.add('-activate', this, 'ability: Mega Sol');
|
||||
return 'sunnyday' as ID;
|
||||
}
|
||||
return weather;
|
||||
}
|
||||
|
||||
|
|
|
|||
36
test/sim/abilities/megasol.js
Normal file
36
test/sim/abilities/megasol.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('./../../assert');
|
||||
const common = require('./../../common');
|
||||
|
||||
let battle;
|
||||
|
||||
describe('Mega Sol', () => {
|
||||
afterEach(() => {
|
||||
battle.destroy();
|
||||
});
|
||||
|
||||
it('should apply Sunny Day damage boosts', () => {
|
||||
battle = common.createBattle([[
|
||||
{ species: "Meganium", item: 'meganiumite', moves: ['weatherball'] },
|
||||
], [
|
||||
{ species: "Pelipper", ability: 'drizzle', moves: ['sleeptalk'] },
|
||||
]]);
|
||||
|
||||
battle.makeChoices('move weatherball mega', 'move sleeptalk');
|
||||
const pelipper = battle.p2.active[0];
|
||||
assert.bounded(pelipper.maxhp - pelipper.hp, [98, 116]);
|
||||
});
|
||||
|
||||
it('should bypass weather defensive boosts', () => {
|
||||
battle = common.createBattle([[
|
||||
{ species: "Meganium", item: 'meganiumite', moves: ['weatherball'] },
|
||||
], [
|
||||
{ species: "Tyranitar", item: 'tyranitarite', moves: ['sleeptalk'] },
|
||||
]]);
|
||||
|
||||
battle.makeChoices('move weatherball mega', 'move sleeptalk mega');
|
||||
const tyranitar = battle.p2.active[0];
|
||||
assert.bounded(tyranitar.maxhp - tyranitar.hp, [63, 75]);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user