Skip to content

Commit

Permalink
Implement Stadium format
Browse files Browse the repository at this point in the history
This commit implements at its full the Stadium format.
Stadium is a half-generation between Gen 1 and Gen 2, widely regarded as a Gen 1 game without the major gen 1 bugs.

The main changes of this game are:
Sleep lasts between 1 and 3 turns.
Hyper Beam does recharge after a faint.
Critical hits happen way less.
Substitute now blocks all status ailments and draining.
It allows tradebacks.
Partial trapping moves miss and stop their duration upon target switch.
Focus Energy actually works.
Stat calculations are done properly, burn and para drop are lost if you lose status.
  • Loading branch information
Joimer committed Jan 9, 2015
1 parent 2a3c4e7 commit defedeb
Show file tree
Hide file tree
Showing 6 changed files with 1,036 additions and 0 deletions.
12 changes: 12 additions & 0 deletions config/formats.js
Expand Up @@ -1024,6 +1024,18 @@ exports.Formats = [
team: 'random',
ruleset: ['Pokemon', 'Sleep Clause Mod', 'Freeze Clause Mod', 'HP Percentage Mod']
},
{
name: "[Gen 1] Stadium",
section: "Past Generations",

mod: 'stadium',
searchShow: false,
ruleset: ['Pokemon', 'Standard'],
banlist: ['Uber',
'Nidoking + Fury Attack + Thrash', 'Exeggutor + Poison Powder + Stomp', 'Exeggutor + Sleep Powder + Stomp',
'Exeggutor + Stun Spore + Stomp', 'Jolteon + Focus Energy + Thunder Shock', 'Flareon + Focus Energy + Ember'
]
},
{
name: "[Gen 1] Custom Game",
section: "Past Generations",
Expand Down
14 changes: 14 additions & 0 deletions mods/stadium/README.md
@@ -0,0 +1,14 @@
Stadium
====================

This mod inherits from gen 1, which inherits from gen 2, and then applies the Stadium changes upon the gen 1 engine.

List of major changes:
*Sleep lasts between 1 and 3 turns.
*Hyper Beam does recharge after a faint.
*Critical hits happen way less.
*Substitute now blocks all status ailments and draining.
*It allows tradebacks.
*Partial trapping moves miss and stop their duration upon target switch.
*Focus Energy actually works.
*Stat calculations are done properly, burn and para drop are lost if you lose status.
178 changes: 178 additions & 0 deletions mods/stadium/moves.js
@@ -0,0 +1,178 @@
exports.BattleMovedex = {
bind: {
inherit: true,
onBeforeMove: function () {}
},
clamp: {
inherit: true,
onBeforeMove: function () {}
},
firespin: {
inherit: true,
onBeforeMove: function () {}
},
highjumpkick: {
inherit: true,
desc: "If this attack misses the target, the user takes 1 HP of damage.",
shortDesc: "User takes 1 HP damage it would have dealt if miss.",
onMoveFail: function (target, source, move) {
if (target.type !== 'ghost') {
this.directDamage(1, source);
}
}
},
jumpkick: {
inherit: true,
desc: "If this attack misses the target, the user 1HP of damage.",
shortDesc: "User takes 1 HP damage if miss.",
onMoveFail: function (target, source, move) {
this.damage(1, source);
}
},
leechseed: {
inherit: true,
onHit: function () {},
effect: {
onStart: function (target) {
this.add('-start', target, 'move: Leech Seed');
},
onAfterMoveSelfPriority: 1,
onAfterMoveSelf: function (pokemon) {
var leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
if (!leecher || leecher.fainted || leecher.hp <= 0) {
this.debug('Nothing to leech into');
return;
}
var toLeech = this.clampIntRange(Math.floor(pokemon.maxhp / 16), 1);
var damage = this.damage(toLeech, pokemon, leecher);
if (damage) this.heal(damage, leecher, pokemon);
}
}
},
rage: {
inherit: true,
self: {
volatileStatus: 'rage'
},
effect: {
// Rage lock
duration: 255,
onStart: function (target, source, effect) {
this.effectData.move = 'rage';
},
onLockMove: 'rage',
onTryHit: function (target, source, move) {
if (target.boosts.atk < 6 && move.id === 'disable') {
this.boost({atk:1});
}
},
onHit: function (target, source, move) {
if (target.boosts.atk < 6 && move.category !== 'Status') {
this.boost({atk:1});
}
},
onMoveFail: function () {}
}
},
recover: {
inherit: true,
heal: null,
onHit: function (target) {
if (target.hp === target.maxhp) {
return false;
}
this.heal(Math.floor(target.maxhp / 2), target, target);
}
},
rest: {
inherit: true,
onHit: function (target) {
// Fails if the difference between
// max HP and current HP is 0, 255, or 511
if (target.hp >= target.maxhp) return false;
if (!target.setStatus('slp')) return false;
target.statusData.time = 2;
target.statusData.startTime = 2;
this.heal(target.maxhp); // Aeshetic only as the healing happens after you fall asleep in-game
this.add('-status', target, 'slp', '[from] move: Rest');
}
},
softboiled: {
inherit: true,
heal: null,
onHit: function (target) {
// Fail when health is 255 or 511 less than max
if (target.hp === target.maxhp) {
return false;
}
this.heal(Math.floor(target.maxhp / 2), target, target);
}
},
substitute: {
inherit: true,
effect: {
onStart: function (target) {
this.add('-start', target, 'Substitute');
this.effectData.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
onTryPrimaryHit: function (target, source, move) {
if (target === source) {
this.debug('sub bypass: self hit');
return;
}
if (move.drain) {
this.add('-miss', source);
return null;
}
if (move.category === 'Status') {
var SubBlocked = {
leechseed:1, lockon:1, mindreader:1, nightmare:1
};
if (move.status || move.boosts || move.volatileStatus === 'confusion' || SubBlocked[move.id]) {
this.add('-activate', target, 'Substitute', '[block] ' + move.name);
return null;
}
return;
}
if (move.volatileStatus && target === source) return;
var damage = this.getDamage(source, target, move);
if (!damage) return null;
damage = this.runEvent('SubDamage', target, source, move, damage);
if (!damage) return damage;
target.volatiles['substitute'].hp -= damage;
source.lastDamage = damage;
if (target.volatiles['substitute'].hp <= 0) {
this.debug('Substitute broke');
target.removeVolatile('substitute');
target.subFainted = true;
} else {
this.add('-activate', target, 'Substitute', '[damage]');
}
if (move.recoil) {
this.damage(Math.round(damage * move.recoil[0] / move.recoil[1]), source, target, 'recoil');
}
if (move.drain) {
this.heal(Math.ceil(damage * move.drain[0] / move.drain[1]), source, target, 'drain');
}
this.runEvent('AfterSubDamage', target, source, move, damage);
// Add here counter damage
if (!target.lastAttackedBy) target.lastAttackedBy = {pokemon: source, thisTurn: true};
target.lastAttackedBy.move = move.id;
target.lastAttackedBy.damage = damage;
return 0;
},
onEnd: function (target) {
this.add('-end', target, 'Substitute');
}
},
secondary: false,
target: "self",
type: "Normal"
},
wrap: {
inherit: true,
onBeforeMove: function () {}
}
};
22 changes: 22 additions & 0 deletions mods/stadium/rulesets.js
@@ -0,0 +1,22 @@
exports.BattleFormats = {
standard: {
effectType: 'Banlist',
ruleset: ['Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'OHKO Clause', 'Evasion Moves Clause', 'HP Percentage Mod'],
banlist: ['Unreleased', 'Illegal'],
validateSet: function (set) {
// limit one of each move in Standard
var moves = [];
if (set.moves) {
var hasMove = {};
for (var i = 0; i < set.moves.length; i++) {
var move = this.getMove(set.moves[i]);
var moveid = move.id;
if (hasMove[moveid]) continue;
hasMove[moveid] = true;
moves.push(set.moves[i]);
}
}
set.moves = moves;
}
}
};

0 comments on commit defedeb

Please sign in to comment.