Skip to content

Instantly share code, notes, and snippets.

@MathyFurret
Last active May 15, 2018 17:28
Show Gist options
  • Save MathyFurret/ac5e73578e234bd17c9decd26665be32 to your computer and use it in GitHub Desktop.
Save MathyFurret/ac5e73578e234bd17c9decd26665be32 to your computer and use it in GitHub Desktop.
Tentative code for the Status Hazard meta https://www.smogon.com/forums/threads/status-hazard.3571986/
'use strict';
exports.Formats = [
//...
{
name: "[Gen 7] Status Hazard",
desc: [
`Status moves in a Pokemon's first and second move slots can become hazard-setting moves.`,
`&bullet; <a href="https://www.smogon.com/forums/threads/status-hazard.3571986/">Status Hazard</a>`,
],
mod: 'statushazard',
ruleset: ['[Gen 7] OU'],
restrictedMoves: [
'Block', 'Mean Look', 'Spider Web',
'Roar', 'Whirlwind',
'Taunt',
],
maxHazards: 2,
onStart: function() {
this.add('-message', "Remember, status moves in your first two move slots can become status hazards!");
let maxHazards = this.getFormat().maxHazards;
if (maxHazards) {
this.add('-message', `Only ${maxHazards} may be set at once per side.`);
}
},
onModifyMovePriority: -999,
onModifyMove: function(move, pokemon, target) {
if (move.category === 'Status'
&& ["normal","allAdjacentFoes","allAdjacent","adjacentFoe"].includes(move.target)
&& pokemon.moves.indexOf(move.id) < 2
&& !this.getFormat().restrictedMoves.map(toId).includes(move.id))
{
move.statusHazard = true;
move.target = "foeSide";
move.flags['reflectable'] = true;
//anything else?
}
},
onTryHitSidePriority: -999,
onTryHitSide: function(target, source, move) {
if (move.statusHazard) {
target.side.addSideCondition('statushazard');
let s = target.side.sideConditions['statushazard'];
let currentHazards = s.hazards.map(a => a.id);
if (currentHazards.includes(move.id)) return false;
//accuracy check time!
let boostTable = [1, 4 / 3, 5 / 3, 2, 7 / 3, 8 / 3, 3];
let accuracy = move.accuracy;
let boosts, boost;
if (accuracy !== true) {
if (!move.ignoreAccuracy) {
boosts = this.runEvent('ModifyBoost', source, null, null, Object.assign({}, source.boosts));
boost = this.clampIntRange(boosts['accuracy'], -6, 6);
if (boost > 0) {
accuracy *= boostTable[boost];
} else {
accuracy /= boostTable[-boost];
}
}
}
//run accuracy modifiers! but we don't have a target...
//The hack is to run the ModifyAccuracy event with no target (global modifiers like Gravity)
//and then pretend SourceModifyAccuracy is an event in its own right (source modifiers like CompoundEyes).
//There are many ways this could go wrong, like if the user's ally had an onAllyModifyAccuracy,
//or if a foe sideCondition had a ModifyAccuracy. We would want to account for both of these.
//Thankfully, I don't believe these cases exist.
accuracy = this.runEvent('ModifyAccuracy', null, null, move, accuracy);
accuracy = this.runEvent('SourceModifyAccuracy', source, null, move, accuracy);
if (move.alwaysHit || source.hasAbility('noguard') || (move.id === 'toxic' && source.hasType('Poison'))) {
accuracy = true;
} else {
//i dont think either of these do anything
accuracy = this.runEvent('Accuracy', null, null, move, accuracy);
accuracy = this.runEvent('SourceAccuracy', source, null, move, accuracy);
}
if (accuracy !== true && this.random(100) >= accuracy) {
this.add('-miss', source, target);
return false;
}
//---hit line---
move.target = 'normal';
if (move.selfdestruct === 'ifHit') { //Memento case
this.faint(source);
delete move.selfdestruct;
}
if (move.selfSwitch) { //Parting Shot case
source.switchFlag = move.fullname;
delete move.selfSwitch;
}
if (['defog', 'curse'].includes(move.id)) { //super-special cases
this.singleEvent('Hit', move, null, target, source, move);
delete move.onHit;
}
let maxHazards = this.getFormat().maxHazards;
if (maxHazards && s.hazards.length === maxHazards) {
let removedHazard = s.hazards.shift();
s.sources.shift();
this.add('-message', `The ${removedHazard.name} hazard vanished!`);
this.add('-sideend', target.side, `hazard:${removedHazard.id}`, '[silent]');
}
this.add('-message', `A ${move.name} hazard was set!`);
this.add('-sidestart', target.side, `hazard:${move.id}`, '[silent]');
s.hazards.push(move);
s.sources.push(source);
return null;
}
},
},
//...
};
'use strict';
exports.BattleMovedex = {
'defog': {
inherit: true,
boosts: {evasion: -1},
onHit: function (target, source, move) {
let removeTarget = ['reflect', 'lightscreen', 'auroraveil', 'safeguard', 'mist', 'spikes', 'toxicspikes', 'stealthrock', 'stickyweb'];
let removeAll = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb'];
for (let targetCondition of removeTarget) {
if (target.side.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
this.add('-sideend', target.side, this.getEffect(targetCondition).name, '[from] move: Defog', '[of] ' + target);
}
}
for (let sideCondition of removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.getEffect(sideCondition).name, '[from] move: Defog', '[of] ' + source);
}
}
target.side.removeSideCondition('statushazard');
source.side.removeSideCondition('statushazard');
},
},
'rapidspin': {
inherit: true,
self: {
onHit: function (pokemon) {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + pokemon);
}
let sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb'];
for (const condition of sideConditions) {
if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.getEffect(condition).name, '[from] move: Rapid Spin', '[of] ' + pokemon);
}
}
if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
pokemon.removeVolatile('partiallytrapped');
}
if (pokemon.hp) pokemon.side.removeSideCondition('statushazard');
},
},
},
};
'use strict';
exports.BattleStatuses = {
'statushazard': {
onStart: function(side, source, sourceEffect) {
this.effectData.hazards = [];
this.effectData.sources = [];
},
onSwitchInPriority: -999, //run after other SwitchIn events
onSwitchIn: function(pokemon) {
for (let i = this.effectData.hazards.length - 1; i >= 0; i--) {
//Status hazards take effect in order from newest to oldest.
let hazard = this.effectData.hazards[i];
let removed = [];
if (hazard.status && !this.getImmunity(hazard.status, pokemon) && !pokemon.hasType('Steel')) {
//Remember, we only remove hazards if the type of the target is naturally immune to a major status, Steel types excepted.
this.add('-message', `The ${hazard.name} hazard vanished!`);
this.add('-sideend', `hazard:${hazard.id}`, '[silent]');
removed.push(i);
} else {
this.add('-message', `The Pokemon was affected by the ${hazard.name} hazard!`);
this.moveHit(pokemon, this.effectData.sources[i], hazard); //i doubt we need isSelf or isSecondary flags
}
this.effectData.hazards = this.effectData.hazards.filter((v, i) => !removed.includes(i));
this.effectData.sources = this.effectData.hazards.filter((v, i) => !removed.includes(i));
}
},
onEnd: function(side) {
this.add('-message', 'The status hazards vanished from the battlefield!');
for (let hazard of this.effectData.hazards) {
this.add('-sideend', side, `hazard:${hazard.id}`, '[silent]');
}
},
},
};
@MathyFurret
Copy link
Author

The alpha release of Status Hazard is finished as of March 4. This code is untested, therefore there are no known bugs yet. Some bugs I predict will happen, however:

  • Moves that call another move (Metronome, Assist, etc) will not have their moves upgraded to Status Hazards even if they are eligible
  • Misc. weird behavior when the Pokemon that set a hazard is not active when the hazard triggers

@MathyFurret
Copy link
Author

Wow, Status Hazard is suddenly playable on R.O.M.! I do not know how long it has been there, but I was alerted to this last week.

Actually, this worries me a bit. I have neither changed nor tested the code since early March, and nobody has given me feedback, either. If my code had errors, I would have liked to know about them so that either 1. I could try to fix them myself, or 2. someone else could fix them and I could learn from them. Because I can't find the server source for ROM, I have no way of telling if my code or someone else's was used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment