pokemon-showdown-client/js/battle.js
Marty-D 4a6b10bd96 Fix the switch in message for the player's side.
- Makes sure the species name is recorded in the battle log as it was
previously.
2013-02-15 20:10:00 -05:00

4961 lines
156 KiB
JavaScript

/*
License: GPLv2
<http://www.gnu.org/licenses/gpl-2.0.html>
*/
// par: -webkit-filter: sepia(100%) hue-rotate(373deg) saturate(592%);
// -webkit-filter: sepia(100%) hue-rotate(22deg) saturate(820%) brightness(29%);
// psn: -webkit-filter: sepia(100%) hue-rotate(618deg) saturate(285%);
// brn: -webkit-filter: sepia(100%) hue-rotate(311deg) saturate(469%);
// slp: -webkit-filter: grayscale(100%);
// frz: -webkit-filter: sepia(100%) hue-rotate(154deg) saturate(759%) brightness(23%);
$.extend($.easing, {
ballisticUp: function (x, t, b, c, d) {
return -3 * x * x + 4 * x;
},
ballisticDown: function (x, t, b, c, d) {
x = 1 - x;
return 1 - (-3 * x * x + 4 * x);
},
quadUp: function (x, t, b, c, d) {
x = 1 - x;
return 1 - (x * x);
},
quadDown: function (x, t, b, c, d) {
return x * x;
}
});
function Pokemon(species) {
var selfP = this;
this.atk = 0;
this.def = 0;
this.spa = 0;
this.spd = 0;
this.spe = 0;
this.atkStat = 0;
this.defStat = 0;
this.spaStat = 0;
this.spdStat = 0;
this.speStat = 0;
this.boosts = {};
this.hp = 0;
this.maxhp = 0;
this.moves = [];
this.ability = '';
this.item = '';
this.species = species;
this.side = null;
this.fainted = false;
this.zerohp = false;
this.status = '';
this.statusStage = 0;
this.volatiles = {};
this.turnstatuses = {};
this.movestatuses = {};
this.lastmove = '';
this.name = '';
this.species = '';
this.id = '';
this.statbarElem = null;
this.healthParse = function (hpstring) {
if (!hpstring || !hpstring.length || hpstring.substr(hpstring.length-1) !== ')') return;
var parenIndex = hpstring.lastIndexOf('(');
if (parenIndex < 0) return;
var hp = hpstring.substr(parenIndex+1, hpstring.length-parenIndex-2).split(' ');
var status = hp[1];
hp = hp[0];
// status parse
if (!status) {
selfP.status = '';
} else if (status === 'par' || status === 'brn' || status === 'slp' || status === 'frz' || status === 'tox') {
selfP.status = status;
} else if (status === 'psn' && selfP.status !== 'tox') {
selfP.status = status;
} else if (status === 'fnt') {
selfP.hp = 0;
selfP.zerohp = true;
selfP.fainted = true;
}
// hp parse
if (hp === '0' || hp === '0.0') {
selfP.hp = 0;
selfP.zerohp = true;
} else if (hp.indexOf('/') > 0) {
var hp = hp.split('/');
if (isNaN(parseFloat(hp[0])) || isNaN(parseFloat(hp[1]))) return;
selfP.hp = parseFloat(hp[0]);
selfP.maxhp = parseFloat(hp[1]);
if (!selfP.hp) {
selfP.zerohp = true;
}
} else if (!isNaN(parseFloat(hp))) {
selfP.hp = selfP.maxhp * parseFloat(hp) / 100;
}
};
this.checkDetails = function(details, ident) {
if (details === selfP.details) return true;
if (selfP.details.indexOf('-*') >= 0) {
selfP.needsReplace = true;
details = details.replace(/-[A-Za-z0-9]+(, |$)/, '$1');
return (details === selfP.details.replace(/-[A-Za-z0-9*]+(, |$)/, '$1'));
}
return false;
};
this.getIdent = function() {
if (selfP.side.active.length === 1) return selfP.ident;
var slots = ['a','b','c','d','e','f'];
return selfP.ident.substr(0,2) + slots[selfP.slot] + selfP.ident.substr(2);
};
this.removeVolatile = function (volatile) {
if (!selfP.hasVolatile(volatile)) return;
if (volatile === 'formechange') {
selfP.sprite.removeTransform();
}
if (selfP.volatiles[volatile][1]) selfP.volatiles[volatile][1].remove();
delete selfP.volatiles[volatile];
};
this.addVolatile = function (volatile) {
var self = selfP.side.battle;
if (selfP.hasVolatile(volatile)) return;
selfP.volatiles[volatile] = [volatile, null];
if (volatile === 'leechseed') {
selfP.side.battle.spriteElemsFront[selfP.side.n].append('<img src="/fx/energyball.png" style="display:none;position:absolute" />');
var curelem = selfP.side.battle.spriteElemsFront[selfP.side.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfP.sprite.x - 30,
y: selfP.sprite.y - 40,
z: selfP.sprite.z,
scale: .2,
opacity: .6
}, BattleEffects.energyball));
var elem = curelem;
selfP.side.battle.spriteElemsFront[selfP.side.n].append('<img src="/fx/energyball.png" style="display:none;position:absolute" />');
curelem = selfP.side.battle.spriteElemsFront[selfP.side.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfP.sprite.x + 40,
y: selfP.sprite.y - 35,
z: selfP.sprite.z,
scale: .2,
opacity: .6
}, BattleEffects.energyball));
elem = elem.add(curelem);
selfP.side.battle.spriteElemsFront[selfP.side.n].append('<img src="/fx/energyball.png" style="display:none;position:absolute" />');
curelem = selfP.side.battle.spriteElemsFront[selfP.side.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfP.sprite.x + 20,
y: selfP.sprite.y - 25,
z: selfP.sprite.z,
scale: .2,
opacity: .6
}, BattleEffects.energyball));
elem = elem.add(curelem);
selfP.volatiles[volatile][1] = elem;
}
};
this.hasVolatile = function (volatile) {
return !!selfP.volatiles[volatile];
};
this.removeTurnstatus = function (volatile) {
if (!selfP.hasTurnstatus(volatile)) return;
if (selfP.turnstatuses[volatile][1]) selfP.turnstatuses[volatile][1].remove();
delete selfP.turnstatuses[volatile];
};
this.addTurnstatus = function (volatile) {
volatile = toId(volatile);
var self = selfP.side.battle;
if (selfP.hasTurnstatus(volatile)) {
if (volatile === 'protect' || volatile === 'magiccoat') {
selfP.turnstatuses[volatile][1].css(self.pos({
x: selfP.sprite.x,
y: selfP.sprite.y,
z: selfP.sprite.behind(-15),
xscale: 1 * 1.2,
yscale: .7 * 1.2,
opacity: 1
}, BattleEffects.none), 300).animate(self.pos({
x: selfP.sprite.x,
y: selfP.sprite.y,
z: selfP.sprite.behind(-15),
xscale: 1,
yscale: .7,
opacity: .4
}, BattleEffects.none), 300);
}
return;
}
selfP.turnstatuses[volatile] = [volatile, null];
if (volatile === 'protect' || volatile === 'magiccoat') {
selfP.side.battle.spriteElemsFront[selfP.side.n].append('<div class="turnstatus-protect" style="display:none;position:absolute" />');
var elem = selfP.side.battle.spriteElemsFront[selfP.side.n].children().last();
elem.css(self.pos({
display: 'block',
x: selfP.sprite.x,
y: selfP.sprite.y,
z: selfP.sprite.behind(-15),
xscale: 1,
yscale: 0,
opacity: .1
}, BattleEffects.none)).animate(self.pos({
x: selfP.sprite.x,
y: selfP.sprite.y,
z: selfP.sprite.behind(-15),
xscale: 1,
yscale: .7,
opacity: .9
}, BattleEffects.none), 300).animate({
opacity: .4
}, 300);
selfP.turnstatuses[volatile][1] = elem;
}
};
this.hasTurnstatus = function (volatile) {
return !!selfP.turnstatuses[volatile];
};
this.clearTurnstatuses = function () {
for (i in selfP.turnstatuses) {
selfP.removeTurnstatus(i);
}
selfP.turnstatuses = {};
};
this.removeMovestatus = function (volatile) {
if (!selfP.hasMovestatus(volatile)) return;
if (selfP.movestatuses[volatile][1]) selfP.movestatuses[volatile][1].remove();
delete selfP.movestatuses[volatile];
};
this.addMovestatus = function (volatile) {
volatile = toId(volatile);
var self = selfP.side.battle;
if (selfP.hasMovestatus(volatile)) {
return;
}
selfP.movestatuses[volatile] = [volatile, null];
};
this.hasMovestatus = function (volatile) {
return !!selfP.movestatuses[volatile];
};
this.clearMovestatuses = function () {
for (i in selfP.movestatuses) {
selfP.removeMovestatus(i);
}
selfP.movestatuses = {};
};
this.clearVolatiles = function () {
for (i in selfP.volatiles) {
selfP.removeVolatile(i);
}
selfP.volatiles = {};
selfP.clearTurnstatuses();
selfP.clearMovestatuses();
};
this.getName = function () {
if (selfP.side.n === 0) {
return sanitize(selfP.name);
} else {
return "The foe's " + sanitize(selfP.name);
}
};
this.getLowerName = function () {
if (selfP.side.n === 0) {
return sanitize(selfP.name);
} else {
return "the foe's " + sanitize(selfP.name);
}
};
this.getTitle = function () {
titlestring = '(' + selfP.ability + ') ';
for (var i = 0; i < selfP.moves.length; i++) {
if (i != 0) titlestring += ' / ';
titlestring += Tools.getMove(selfP.moves[i]).name;
}
return titlestring;
};
this.getFullName = function (plaintext) {
var name = sanitize(selfP.name);
if (selfP.name !== selfP.species) {
if (plaintext) {
name += ' (' + selfP.species + ')';
} else name += ' <small>(' + selfP.species + ')</small>';
}
if (plaintext) {
if (selfP === selfP.side.active[0]) {
name += ' (active)';
} else if (selfP.fainted) {
name += ' (fainted)';
} else {
var statustext = '';
if (selfP.hp !== selfP.maxhp) statustext = '' + parseInt(100 * selfP.hp / selfP.maxhp) + '%';
if (selfP.status) {
if (statustext) statustext += '|';
statustext += selfP.status;
}
if (statustext) {
name += ' (' + statustext + ')';
}
}
}
return name;
}
this.getBoost = function (boostStat) {
var boostStatTable = {
atk: 'Atk',
def: 'Def',
spa: 'SpA',
spd: 'SpD',
spe: 'Spe',
accuracy: 'Accuracy',
evasion: 'Evasion'
};
if (!selfP.boosts[boostStat]) {
return '1&times;&nbsp;' + boostStatTable[boostStat];
}
if (selfP.boosts[boostStat] > 6) selfP.boosts[boostStat] = 6;
if (selfP.boosts[boostStat] < -6) selfP.boosts[boostStat] = -6;
if (boostStat === 'accuracy' || boostStat === 'evasion') {
if (selfP.boosts[boostStat] > 0) {
var goodBoostTable = ['1&times;', '1.33&times;', '1.67&times;', '2&times;', '2.33&times;', '2.67&times;', '3&times;'];
//var goodBoostTable = ['Normal', '+1', '+2', '+3', '+4', '+5', '+6'];
return '' + goodBoostTable[selfP.boosts[boostStat]] + '&nbsp;' + boostStatTable[boostStat];
}
var badBoostTable = ['1&times;', '0.75&times;', '0.6&times;', '0.5&times;', '0.43&times;', '0.38&times;', '0.33&times;'];
//var badBoostTable = ['Normal', '&minus;1', '&minus;2', '&minus;3', '&minus;4', '&minus;5', '&minus;6'];
return '' + badBoostTable[-selfP.boosts[boostStat]] + '&nbsp;' + boostStatTable[boostStat];
}
if (selfP.boosts[boostStat] > 0) {
var goodBoostTable = ['1&times;', '1.5&times;', '2&times;', '2.5&times;', '3&times;', '3.5&times;', '4&times;'];
//var goodBoostTable = ['Normal', '+1', '+2', '+3', '+4', '+5', '+6'];
return '' + goodBoostTable[selfP.boosts[boostStat]] + '&nbsp;' + boostStatTable[boostStat];
}
var badBoostTable = ['1&times;', '0.67&times;', '0.5&times;', '0.4&times;', '0.33&times;', '0.29&times;', '0.25&times;'];
//var badBoostTable = ['Normal', '&minus;1', '&minus;2', '&minus;3', '&minus;4', '&minus;5', '&minus;6'];
return '' + badBoostTable[-selfP.boosts[boostStat]] + '&nbsp;' + boostStatTable[boostStat];
}
this.getBoostType = function (boostStat) {
if (!selfP.boosts[boostStat]) {
return 'neutral';
} else if (selfP.boosts[boostStat] > 0) {
return 'good';
}
return 'bad';
}
this.clearVolatile = function () {
selfP.atk = selfP.atkStat;
selfP.def = selfP.defStat;
selfP.spa = selfP.spaStat;
selfP.spd = selfP.spdStat;
selfP.spe = selfP.speStat;
selfP.boosts = {};
selfP.clearVolatiles();
//selfP.lastmove = '';
selfP.statusStage = 0;
};
this.copyVolatileFrom = function (pokemon, copyAll) {
selfP.boosts = pokemon.boosts;
selfP.volatiles = pokemon.volatiles;
//selfP.lastmove = pokemon.lastmove; // I think
if (!copyAll) {
selfP.removeVolatile('yawn');
selfP.removeVolatile('confusion');
selfP.removeVolatile('airballoon');
}
selfP.removeVolatile('transform');
selfP.removeVolatile('formechange');
pokemon.atk = pokemon.atkStat;
pokemon.def = pokemon.defStat;
pokemon.spa = pokemon.spaStat;
pokemon.spd = pokemon.spdStat;
pokemon.spe = pokemon.speStat;
pokemon.boosts = {};
pokemon.volatiles = {};
pokemon.sprite.removeTransform();
pokemon.statusStage = 0;
};
this.reset = function () {
selfP.clearVolatile();
selfP.hp = selfP.maxhp;
selfP.zerohp = false;
selfP.fainted = false;
selfP.status = '';
if (!selfP.name) {
selfP.name = selfP.species;
}
};
this.hpWidth = function (maxWidth) {
if (selfP.fainted || selfP.zerohp) {
return 0;
}
var w = parseInt(maxWidth * selfP.hp / selfP.maxhp);
if (w < 1) {
return 1;
}
return w;
}
};
function Battle(frame, logFrame, noPreload) {
var self = this;
frame.addClass('battle');
this.turn = 0;
this.done = 0;
this.weather = '';
this.pseudoWeather = [];
this.weatherTimeLeft = 0;
this.weatherMinTimeLeft = 0;
this.mySide = null;
this.yourSide = null;
this.p1 = null;
this.p2 = null;
this.sides = [];
this.lastMove = '';
this.gen = 5;
this.frameElem = frame;
this.logFrameElem = logFrame;
this.logElem = null;
this.weatherElem = null;
this.bgEffectElem = null;
this.bgElem = null;
this.spriteElem = null;
this.spriteElems = [null, null];
this.spriteElemsFront = [null, null];
this.statElem = null;
this.fxElem = null;
this.leftbarElem = null;
this.rightbarElem = null;
this.turnElem = null;
this.messagebarElem = null;
this.delayElem = null;
this.hiddenMessageElem = null;
this.paused = true;
this.playbackState = 0;
self.backdropImage = BattleBackdrops[0];
self.backdropImage = BattleBackdrops[Math.floor(Math.random() * BattleBackdrops.length)];
// 0 = uninitialized
// 1 = ready
// 2 = playing
// 3 = paused
// 4 = finished
// 5 = seeking
this.removePseudoWeather = function (weather) {
for (var i = 0; i < self.pseudoWeather.length; i++) {
if (self.pseudoWeather[i][0] === weather) {
self.pseudoWeather.splice(i, 1);
self.updateWeather();
return;
}
}
};
this.addPseudoWeather = function (weather, poke) {
self.pseudoWeather.push([weather, 5]);
self.updateWeather();
};
this.hasPseudoWeather = function (weather) {
for (var i = 0; i < self.pseudoWeather.length; i++) {
if (self.pseudoWeather[i][0] === weather) {
return true;
}
}
return false;
};
this.init = function () {
self.reset();
self.mySide = new self.Side(0);
self.yourSide = new self.Side(1);
self.mySide.foe = self.yourSide;
self.yourSide.foe = self.mySide;
self.sides = [self.mySide, self.yourSide];
self.p1 = self.mySide;
self.p2 = self.yourSide;
self.gen = 5;
};
this.reset = function () {
// battle state
self.turn = 0;
self.done = 0;
self.weather = '';
self.weatherTimeLeft = 0;
self.weatherMinTimeLeft = 0;
self.pseudoWeather = [];
self.lastMove = '';
// DOM state
self.frameElem.empty();
self.frameElem.html('<div class="innerbattle"></div>');
self.elem = self.frameElem.children();
logFrame.html('<div class="inner"></div>');
self.logElem = logFrame.children();
logFrame.append('<div class="inner-preempt"></div>');
self.logPreemptElem = logFrame.children().last();
logFrame.append('<div class="inner-after"></div>');
self.elem.append('<div class="backdrop" style="background-image:url(/fx/' + self.backdropImage + ');display:block;opacity:0"></div>');
self.bgElem = self.elem.children().last();
self.bgElem.animate({
opacity: 0.6
});
self.elem.append('<div class="weather"></div>');
self.weatherElem = self.elem.children().last();
self.elem.append('<div></div>');
self.bgEffectElem = self.elem.children().last();
self.elem.append('<div></div>');
self.spriteElem = self.elem.children().last();
self.spriteElem.append('<div></div>');
self.spriteElems[1] = self.spriteElem.children().last();
self.spriteElem.append('<div></div>');
self.spriteElemsFront[1] = self.spriteElem.children().last();
self.spriteElem.append('<div></div>');
self.spriteElemsFront[0] = self.spriteElem.children().last();
self.spriteElem.append('<div></div>');
self.spriteElems[0] = self.spriteElem.children().last();
self.elem.append('<div></div>');
self.statElem = self.elem.children().last();
self.elem.append('<div></div>');
self.fxElem = self.elem.children().last();
self.elem.append('<div class="leftbar"></div>');
self.leftbarElem = self.elem.children().last();
self.elem.append('<div class="rightbar"></div>');
self.rightbarElem = self.elem.children().last();
self.elem.append('<div></div>');
self.turnElem = self.elem.children().last();
self.elem.append('<div class="messagebar message"></div>');
self.messagebarElem = self.elem.children().last();
self.elem.append('<div></div>');
self.delayElem = self.elem.children().last();
self.elem.append('<div class="message" style="position:absolute;display:block;visibility:hidden"></div>');
self.hiddenMessageElem = self.elem.children().last();
if (self.mySide) self.mySide.reset();
if (self.yourSide) self.yourSide.reset();
// activity queue state
self.animationDelay = 0;
self.multiHitMove = null;
self.activityStep = 0;
self.activityDelay = 0;
self.activityAfter = null;
self.activityAnimations = $();
self.activityQueueActive = false;
self.fastForwardOff();
$.fx.off = false;
self.minorQueue = [];
self.resultWaiting = false;
self.paused = true;
if (self.playbackState !== 5) {
self.playbackState = (self.activityQueue.length ? 1 : 0);
self.soundStop();
}
};
this.dealloc = function () {
self.soundStop();
};
this.logConsole = function (text) {
if (window.console && console.log) console.log(text);
};
this.log = function (html, preempt) {
if (preempt) {
self.logPreemptElem.append(html);
} else {
self.logElem.append(html);
}
if (self.logFrameElem.scrollTop() + 60 >= self.logElem.height() + self.logPreemptElem.height() - self.logFrameElem.height()) {
self.logFrameElem.scrollTop(self.logElem.height() + self.logPreemptElem.height());
}
};
this.preemptCatchup = function () {
self.logElem.append(self.logPreemptElem.children().first());
};
this.pos = function (loc, obj) {
var left, top, scale, width, height;
if (!loc.scale && loc.scale !== 0) loc.scale = 1;
if (!loc.xscale && loc.xscale !== 0) loc.xscale = loc.scale;
if (!loc.yscale && loc.yscale !== 0) loc.yscale = loc.scale;
if (!loc.opacity && loc.opacity !== 0) loc.opacity = 1;
if (!loc.z) loc.z = 0;
if (!loc.x) loc.x = 0;
if (!loc.y) loc.y = 0;
left = 210;
top = 245;
scale = 1;
scale = 2 - 1 * (loc.z / 200);
if (scale < .1) scale = .1;
left += (410 - 190) * (loc.z / 200);
top += (135 - 245) * (loc.z / 200);
left += Math.floor(loc.x * scale);
top -= Math.floor(loc.y * scale /* - loc.x * scale / 4 */ );
width = Math.floor(obj.w * scale * loc.xscale);
height = Math.floor(obj.h * scale * loc.yscale);
left -= Math.floor(width / 2);
top -= Math.floor(height / 2);
var pos = {
left: left,
top: top,
width: width,
height: height,
opacity: loc.opacity
};
if (loc.display) pos.display = loc.display;
return pos;
};
this.posT = function (loc, obj, transition, oldloc) {
var pos = self.pos(loc, obj);
var oldpos = null;
if (oldloc) oldpos = self.pos(oldloc, obj);
var transitionMap = {
left: 'linear',
top: 'linear',
width: 'linear',
height: 'linear',
opacity: 'linear'
};
if (transition === 'ballistic') {
transitionMap.top = (pos.top < oldpos.top ? 'ballisticUp' : 'ballisticDown');
}
if (transition === 'ballisticUnder') {
transitionMap.top = (pos.top < oldpos.top ? 'ballisticDown' : 'ballisticUp');
}
if (transition === 'ballistic2') {
transitionMap.top = (pos.top < oldpos.top ? 'quadUp' : 'quadDown');
}
if (transition === 'ballistic2Under') {
transitionMap.top = (pos.top < oldpos.top ? 'quadDown' : 'quadUp');
}
if (transition === 'swing') {
transitionMap.left = 'swing';
transitionMap.top = 'swing';
transitionMap.width = 'swing';
transitionMap.height = 'swing';
}
if (transition === 'accel') {
transitionMap.left = 'quadDown';
transitionMap.top = 'quadDown';
transitionMap.width = 'quadDown';
transitionMap.height = 'quadDown';
}
if (transition === 'decel') {
transitionMap.left = 'quadUp';
transitionMap.top = 'quadUp';
transitionMap.width = 'quadUp';
transitionMap.height = 'quadUp';
}
return {
left: [pos.left, transitionMap.left],
top: [pos.top, transitionMap.top],
width: [pos.width, transitionMap.width],
height: [pos.height, transitionMap.height],
opacity: [pos.opacity, transitionMap.opacity]
};
};
this.Sprite = function (spriteData, x, y, z, siden) {
var selfS = this;
var sp = null;
var subsp = null;
this.forme = '';
this.elem = null;
this.cryurl = '';
if (spriteData) {
sp = spriteData;
self.spriteElems[siden].append('<img src="' + sp.url + '" style="display:none;position:absolute" />');
this.elem = self.spriteElems[siden].children().last();
this.cryurl = spriteData.cryurl;
} else {
sp = {
w: 0,
h: 0,
url: ''
};
}
this.sp = sp;
this.subsp = null;
this.oldsp = null;
this.subElem = null;
this.iw = sp.w;
this.ih = sp.h;
this.w = 0;
this.h = 0;
this.x = x;
this.y = y;
this.z = z;
this.statbarOffset = 0;
var pos = self.pos({
x: x,
y: y,
z: z
}, {
w: 0,
h: 96
});
this.top = parseInt(pos.top + 40);
this.left = parseInt(pos.left);
this.isBackSprite = !siden;
this.duringMove = false;
this.behindx = function (offset) {
return selfS.x + (selfS.isBackSprite ? -1 : 1) * offset;
}
this.behindy = function (offset) {
return selfS.y + (selfS.isBackSprite ? 1 : -1) * offset;
}
this.leftof = function (offset) {
return (selfS.isBackSprite ? -1 : 1) * offset;
};
this.behind = function (offset) {
return selfS.z + (selfS.isBackSprite ? -1 : 1) * offset;
};
this.animTransform = function (species) {
if (!selfS.oldsp) selfS.oldsp = selfS.sp;
if (species.volatiles && species.volatiles.formechange) species = species.volatiles.formechange[2];
sp = Tools.getSpriteData(species, selfS.isBackSprite ? 0 : 1);
selfS.sp = sp;
selfS.elem.animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.z,
yscale: 0,
xcale: 1,
opacity: .3
}, selfS.oldsp), 300, function () {
selfS.elem.attr('src', sp.url);
selfS.elem.animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.z,
opacity: 1
}, sp), 300);
});
self.activityWait(500);
};
this.destroy = function () {
if (selfS.elem) selfS.elem.remove();
if (selfS.subElem) selfS.subElem.remove();
};
this.removeTransform = function (species) {
if (selfS.oldsp) {
sp = selfS.oldsp;
selfS.sp = sp;
selfS.oldsp = null;
selfS.elem.attr('src', sp.url);
selfS.elem.css(self.pos({
x: selfS.x,
y: selfS.y,
z: (selfS.subElem ? selfS.behind(30) : selfS.z),
opacity: (selfS.subElem ? .3 : 1)
}, sp));
}
};
this.animSub = function () {
subsp = Tools.getSpriteData('substitute', siden);
selfS.subsp = subsp;
selfS.iw = subsp.w;
selfS.ih = subsp.h;
self.spriteElemsFront[siden].append('<img src="' + subsp.url + '" style="display:none;position:absolute" />');
selfS.subElem = self.spriteElemsFront[siden].children().last();
//temp//selfS.subElem.css({position: 'absolute', display: 'block'});
selfS.selfAnim({}, 500);
selfS.subElem.css({
position: 'absolute',
opacity: 0,
display: 'block'
});
selfS.subElem.css(self.pos({
x: selfS.x,
y: selfS.y + 50,
z: selfS.z,
opacity: 0
}, subsp));
selfS.subElem.animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.z
}, subsp), 500);
self.activityWait(selfS.subElem);
};
this.animSubFade = function () {
if (!selfS.subElem) return;
if (self.activityDelay) {
selfS.elem.delay(self.activityDelay);
selfS.subElem.delay(self.activityDelay);
}
selfS.subElem.animate(self.pos({
x: selfS.x,
y: selfS.y - 50,
z: selfS.z,
opacity: 0
}, selfS.subsp), 500);
selfS.subElem = null;
selfS.selfAnim({}, 500);
selfS.iw = selfS.sp.w;
selfS.ih = selfS.sp.h;
self.activityWait(selfS.elem);
};
this.beforeMove = function () {
if (selfS.subElem && !selfS.duringMove) {
selfS.duringMove = true;
selfS.selfAnim({}, 300);
selfS.subElem.animate(self.pos({
x: selfS.leftof(-50),
y: selfS.y,
z: selfS.z,
opacity: 0.5
}, selfS.subsp), 300);
if (self.sides[selfS.isBackSprite ? 1 : 0].active[0]) {
self.sides[selfS.isBackSprite ? 1 : 0].active[0].sprite.delay(300);
}
self.animationDelay = 300;
self.activityWait(selfS.elem);
return true;
}
return false;
};
this.afterMove = function () {
if (selfS.subElem && selfS.duringMove) {
selfS.subElem.delay(300);
selfS.duringMove = false;
selfS.elem.add(selfS.subElem).promise().done(function () {
if (!selfS.subElem || !selfS.elem) return;
selfS.selfAnim({}, 300);
selfS.subElem.animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.z,
opacity: 1
}, selfS.subsp), 300);
});
return true;
}
selfS.duringMove = false;
return false;
};
this.removeSub = function () {
if (selfS.subElem) {
var temp = selfS.subElem;
selfS.subElem.animate({
opacity: 0
}, function () {
temp.remove();
});
selfS.subElem = null;
}
};
this.animReset = function () {
if (selfS.subElem) {
selfS.elem.stop(true, false);
selfS.subElem.stop(true, false);
selfS.elem.css(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.behind(30),
opacity: .3
}, selfS.sp));
selfS.subElem.css(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.z
}, selfS.subsp));
} else {
selfS.elem.stop(true, false);
selfS.elem.css(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.z
}, selfS.sp));
}
};
this.animSummon = function (slot, instant) {
selfS.x = slot * (selfS.isBackSprite ? -1 : 1) * -50;
selfS.y = slot * (selfS.isBackSprite ? -1 : 1) * 10;
selfS.statbarOffset = 0;
if (!selfS.isBackSprite && slot == 1) selfS.statbarOffset = 17;
if (selfS.isBackSprite && slot == 1) selfS.statbarOffset = -7;
// make sure element is in the right z-order
if (!slot && selfS.isBackSprite || slot && !selfS.isBackSprite) {
selfS.elem.prependTo(selfS.elem.parent());
} else {
selfS.elem.appendTo(selfS.elem.parent());
}
var pos = self.pos(selfS, {
w: 0,
h: 96
});
selfS.top = parseInt(pos.top + 40);
selfS.left = parseInt(pos.left);
selfS.anim();
selfS.w = sp.w;
selfS.h = sp.h;
selfS.elem.css({
// 'z-index': (selfS.isBackSprite ? 1+slot : 4-slot),
position: 'absolute',
display: 'block'
});
if (self.fastForward || instant) {
selfS.elem.css(self.pos({
opacity: 1,
x: selfS.x,
y: selfS.y,
z: selfS.z
}, selfS.sp));
return;
}
if (selfS.cryurl) {
//self.logConsole('cry: '+selfS.cryurl);
self.playAudio(selfS.cryurl);
}
selfS.elem.css(self.pos({
x: selfS.x,
y: selfS.y - 10,
z: selfS.z,
scale: 0,
opacity: 0
}, selfS.sp));
self.showEffect('pokeball', {
opacity: 0,
x: selfS.x,
y: selfS.y + 30,
z: selfS.behind(50),
scale: .7
}, {
opacity: 1,
x: selfS.x,
y: selfS.y - 10,
z: selfS.z,
time: 300
}, 'ballistic2', 'fade');
selfS.elem.delay(300).animate(self.pos({
x: selfS.x,
y: selfS.y + 30,
z: selfS.z
}, selfS.sp), 400).animate(self.posT({
x: selfS.x,
y: selfS.y,
z: selfS.z
}, selfS.sp, 'accel'), 300);
self.activityWait(selfS.elem);
};
this.animDragIn = function (slot) {
if (self.fastForward) return selfS.animSummon(slot, true);
selfS.x = slot * (selfS.isBackSprite ? -1 : 1) * -50;
selfS.y = slot * (selfS.isBackSprite ? -1 : 1) * 10;
selfS.statbarOffset = 0;
if (!selfS.isBackSprite && slot == 1) selfS.statbarOffset = 17;
if (selfS.isBackSprite && slot == 1) selfS.statbarOffset = -7;
// make sure element is in the right z-order
if (!slot && selfS.isBackSprite || slot && !selfS.isBackSprite) {
selfS.elem.prependTo(selfS.elem.parent());
} else {
selfS.elem.appendTo(selfS.elem.parent());
}
var pos = self.pos(selfS, {
w: 0,
h: 96
});
selfS.top = parseInt(pos.top + 40);
selfS.left = parseInt(pos.left);
selfS.anim();
selfS.elem.css({
// 'z-index': (selfS.isBackSprite ? 1+slot : 4-slot),
position: 'absolute',
opacity: 0,
display: 'block'
});
selfS.elem.css(self.pos({
x: selfS.leftof(-50),
y: selfS.y,
z: selfS.z,
opacity: 0
}, selfS.sp));
selfS.elem.delay(300).animate(self.posT({
x: selfS.x,
y: selfS.y,
z: selfS.z
}, selfS.sp, 'decel'), 400);
selfS.w = sp.w;
selfS.h = sp.h;
self.activityWait(selfS.elem);
self.animationDelay = 700;
};
this.animDragOut = function () {
selfS.removeSub();
if (self.fastForward) return selfS.animUnsummon(true);
selfS.elem.animate(self.posT({
x: selfS.leftof(50),
y: selfS.y,
z: selfS.z,
opacity: 0
}, selfS.sp, 'accel'), 400);
};
this.animUnsummon = function (instant) {
selfS.removeSub();
if (self.fastForward || instant) {
selfS.elem.css('display', 'none');
return;
}
selfS.anim({
x: selfS.x,
y: selfS.y - 40,
z: selfS.z,
scale: 0,
opacity: 0,
time: 400
});
self.showEffect('pokeball', {
opacity: 1,
x: selfS.x,
y: selfS.y - 40,
z: selfS.z,
scale: .7,
time: 300
}, {
opacity: 0,
x: selfS.x,
y: selfS.y,
z: selfS.behind(50),
time: 700
}, 'ballistic2');
self.activityWait(selfS.elem);
};
this.animFaint = function () {
selfS.removeSub();
if (self.fastForward) {
selfS.elem.remove();
selfS.elem = null;
return;
}
selfS.anim({
y: selfS.y - 80,
opacity: 0
}, 'accel');
self.activityWait(selfS.elem);
};
this.delay = function (time) {
selfS.elem.delay(time);
if (selfS.subElem) {
selfS.subElem.delay(time);
};
return selfS;
};
this.selfAnim = function (end, transition) {
if (!end) return;
end = $.extend({
x: selfS.x,
y: selfS.y,
z: selfS.z,
scale: 1,
opacity: 1,
time: 500
}, end);
if (selfS.subElem && !selfS.duringMove) {
end.z += (selfS.isBackSprite ? -1 : 1) * 30;
end.opacity *= .3;
}
selfS.elem.animate(self.posT(end, selfS.sp, transition, selfS), end.time);
};
this.anim = function (end, transition) {
if (!end) return;
end = $.extend({
x: selfS.x,
y: selfS.y,
z: selfS.z,
scale: 1,
opacity: 1,
time: 500
}, end);
if (selfS.subElem && !selfS.duringMove) {
selfS.subElem.animate(self.posT(end, selfS.subsp, transition, selfS), end.time);
} else {
selfS.elem.animate(self.posT(end, selfS.sp, transition, selfS), end.time);
}
};
if (!spriteData) {
this.delay = function () {};
this.anim = function () {};
}
};
this.backgroundEffect = function (bg, duration, opacity, delay) {
if (!opacity) {
opacity = 1;
}
if (!delay) delay = 0;
self.bgEffectElem.append('<div class="background"></div>');
var elem = self.bgEffectElem.children().last();
elem.css({
background: bg,
display: 'block',
opacity: 0
});
elem.delay(delay).animate({
opacity: opacity
}, 250).delay(duration - 250);
elem.animate({
opacity: 0
}, 250);
}
this.showEffect = function (img, start, end, transition, after) {
var effect = img;
if (img && img.length) effect = BattleEffects[img];
if (!start.time) start.time = 0;
if (!end.time) end.time = start.time + 500;
start.time += self.animationDelay;
end.time += self.animationDelay;
if (!end.scale && end.scale !== 0) end.scale = start.scale;
if (!end.xscale && end.xscale !== 0) end.xscale = start.xscale;
if (!end.yscale && end.yscale !== 0) end.yscale = start.yscale;
end = $.extend({}, start, end);
var startpos = self.pos(start, effect);
var endpos = self.posT(end, effect, transition, start);
self.fxElem.append('<img src="' + effect.url + '" style="display:none;position:absolute" />');
var effectElem = self.fxElem.children().last();
effectElem.css({
display: 'block',
opacity: 0
});
effectElem.css(startpos);
effectElem.css({
opacity: 0
});
if (start.time) {
effectElem.delay(start.time).animate({
opacity: startpos.opacity
}, 1);
} else {
effectElem.css('opacity', startpos.opacity);
}
effectElem.animate(endpos, end.time - start.time);
if (after === 'fade') {
effectElem.animate({
opacity: 0
}, 100);
}
if (after === 'explode') {
if (end.scale) end.scale *= 3;
if (end.xscale) end.xscale *= 3;
if (end.yscale) end.yscale *= 3;
end.opacity = 0;
var endendpos = self.pos(end, effect);
effectElem.animate(endendpos, 200);
}
self.activityWait(effectElem);
};
this.Side = function (n) {
var selfS = this;
this.battle = self;
this.name = 'Player';
this.id = 'Player';
this.initialized = false;
this.n = n;
this.foe = null;
this.spriteid = 262;
this.totalPokemon = 6;
this.rollSprites = function () {
var sprites = [1, 2, 101, 102, 169, 170];
selfS.spriteid = sprites[parseInt(Math.random() * sprites.length)];
};
this.behindx = function (offset) {
return selfS.x + (!selfS.n ? -1 : 1) * offset;
}
this.behindy = function (offset) {
return selfS.y + (!selfS.n ? 1 : -1) * offset;
}
this.leftof = function (offset) {
return (!selfS.n ? -1 : 1) * offset;
};
this.behind = function (offset) {
return selfS.z + (!selfS.n ? -1 : 1) * offset;
};
if (n == 0) {
this.x = 0;
this.y = 0;
this.z = 0;
} else {
this.x = 0;
this.y = 0;
this.z = 200;
}
this.missedPokemon = {
sprite: new self.Sprite(null, selfS.leftof(-100), selfS.y, selfS.z, selfS.n)
};
this.sideConditions = {};
this.wisher = null;
this.active = [null];
this.lastPokemon = null;
this.pokemon = [];
this.reset = function () {
selfS.updateSprites();
selfS.sideConditions = {};
for (var i = 0; i < selfS.pokemon.length; i++) {
selfS.pokemon[i].reset();
}
};
this.updateSprites = function () {
selfS.z = (selfS.n ? 200 : 0);
selfS.missedPokemon.sprite.destroy();
selfS.missedPokemon = {
sprite: new self.Sprite(null, selfS.leftof(-100), selfS.y, selfS.z, selfS.n)
};
for (var i = 0; i < selfS.pokemon.length; i++) {
poke = selfS.pokemon[i];
poke.sprite.destroy();
poke.sprite = new self.Sprite(Tools.getSpriteData(poke, selfS.n), selfS.x, selfS.y, selfS.z, selfS.n);
}
};
this.setSprite = function (spriteid) {
selfS.spriteid = spriteid;
selfS.updateSidebar();
};
this.setName = function (name, spriteid) {
selfS.name = (name||'');
selfS.id = toId(selfS.name);
if (spriteid) selfS.spriteid = spriteid;
else if (selfS.id === "Serei") selfS.spriteid = 172;
else if (selfS.id === "Hob'sGoblin") selfS.spriteid = 52;
else if (selfS.id === "EtherealSol") selfS.spriteid = 1001;
else if (selfS.id === "Morty(GymLeader)") selfS.spriteid = 144;
else if (selfS.id === "aeo") selfS.spriteid = 167;
else if (selfS.id === "aeo1") selfS.spriteid = 167;
else if (selfS.id === "aeo2") selfS.spriteid = 166;
else if (selfS.id === "sharktamer") selfS.spriteid = 7;
else if (selfS.id === "bmelts") selfS.spriteid = 226;
else {
selfS.rollSprites();
if (selfS.foe && selfS.spriteid === selfS.foe.spriteid) selfS.rollSprites();
}
selfS.initialized = true;
if (!name) {
selfS.initialized = false;
}
selfS.updateSidebar();
if (self.stagnateCallback) self.stagnateCallback(self);
};
this.getTeamName = function () {
if (selfS === self.mySide) return "Your team";
return "The foe's team";
};
this.getLowerTeamName = function () {
if (selfS === self.mySide) return "your team";
return "the foe's team";
};
this.updateSidebar = function () {
var pokemonhtml = '';
for (var i = 0; i < 6; i++) {
poke = selfS.pokemon[i];
if (i >= selfS.totalPokemon) {
pokemonhtml += '<span class="pokemonicon" style="'+Tools.getIcon('pokeball-none')+'"></span>';
} else if (!poke) {
//pokemonhtml += '<img src="/fx/pokeball.png" title="Not revealed" />';
pokemonhtml += '<span class="pokemonicon" style="'+Tools.getIcon('pokeball')+'" title="Not revealed"></span>';
//} else if (poke.fainted) {
//pokemonhtml += '<img src="/fx/pokeball.png" style="opacity:0.3;filter:alpha(opacity=30)" title="' + poke.getFullName(true) + '" />';
} else {
//pokemonhtml += '<img src="/fx/pokeball.png" title="' + poke.getFullName(true) + '" />';
pokemonhtml += '<span class="pokemonicon" style="'+Tools.getIcon(poke)+'" title="' + poke.getFullName(true) + '"></span>';
}
if (i % 3 === 2) pokemonhtml += '</div><div class="teamicons">';
}
pokemonhtml = '<div class="teamicons">' + pokemonhtml + '</div>';
if (selfS.n === 1) {
if (selfS.initialized) self.rightbarElem.html('<div class="trainer"><strong>' + sanitize(selfS.name) + '</strong><div class="trainersprite" style="background-image:url(/sprites/trainers/' + selfS.spriteid + '.png)"></div>' + pokemonhtml + '</div>').find('.trainer').css('opacity',1);
else self.rightbarElem.find('.trainer').css('opacity',0.4);
} else {
if (selfS.initialized) self.leftbarElem.html('<div class="trainer"><strong>' + sanitize(selfS.name) + '</strong><div class="trainersprite" style="background-image:url(/sprites/trainers/' + selfS.spriteid + '.png)"></div>' + pokemonhtml + '</div>').find('.trainer').css('opacity',1);
else self.leftbarElem.find('.trainer').css('opacity',0.4);
}
};
this.addSideCondition = function (condition) {
condition = toId(condition);
if (selfS.sideConditions[condition]) {
if (condition === 'spikes' || condition === 'toxicspikes') {
selfS.sideConditions[condition][2]++;
if (condition === 'spikes' && selfS.sideConditions[condition][2] == 2) {
self.spriteElemsFront[selfS.n].append('<img src="' + BattleEffects.caltrop.url + '" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x + 50,
y: selfS.y - 40,
z: selfS.z,
scale: .3
}, BattleEffects.caltrop));
selfS.sideConditions['spikes'][1] = selfS.sideConditions['spikes'][1].add(curelem);
} else if (condition === 'spikes') {
self.spriteElemsFront[selfS.n].append('<img src="' + BattleEffects.caltrop.url + '" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x + 30,
y: selfS.y - 45,
z: selfS.z,
scale: .3
}, BattleEffects.caltrop));
selfS.sideConditions['spikes'][1] = selfS.sideConditions['spikes'][1].add(curelem);
} else if (condition === 'toxicspikes') {
self.spriteElemsFront[selfS.n].append('<img src="' + BattleEffects.poisoncaltrop.url + '" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x - 15,
y: selfS.y - 35,
z: selfS.z,
scale: .3
}, BattleEffects.poisoncaltrop));
selfS.sideConditions['toxicspikes'][1] = selfS.sideConditions['toxicspikes'][1].add(curelem);
}
}
return;
}
var elem, curelem;
switch (condition) {
case 'reflect':
self.spriteElemsFront[selfS.n].append('<div class="sidecondition-reflect" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x,
y: selfS.y,
z: selfS.behind(-17),
xscale: 1,
yscale: 0,
opacity: .1
}, BattleEffects.none)).animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.behind(-17),
xscale: 1,
yscale: .5,
opacity: .7
}, BattleEffects.none)).animate({
opacity: .3
}, 300);
elem = curelem;
selfS.sideConditions[condition] = [condition, elem, 5];
break;
case 'safeguard':
self.spriteElemsFront[selfS.n].append('<div class="sidecondition-safeguard" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x,
y: selfS.y,
z: selfS.behind(-20),
xscale: 1,
yscale: 0,
opacity: .1
}, BattleEffects.none)).animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.behind(-20),
xscale: 1,
yscale: .5,
opacity: .7
}, BattleEffects.none)).animate({
opacity: .2
}, 300);
elem = curelem;
selfS.sideConditions[condition] = [condition, elem, 5];
break;
case 'lightscreen':
self.spriteElemsFront[selfS.n].append('<div class="sidecondition-lightscreen" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x,
y: selfS.y,
z: selfS.behind(-23),
xscale: 1,
yscale: 0,
opacity: .1
}, BattleEffects.none)).animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.behind(-23),
xscale: 1,
yscale: .5,
opacity: .7
}, BattleEffects.none)).animate({
opacity: .3
}, 300);
elem = curelem;
selfS.sideConditions[condition] = [condition, elem, 5];
break;
case 'mist':
self.spriteElemsFront[selfS.n].append('<div class="sidecondition-mist" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x,
y: selfS.y,
z: selfS.behind(-27),
xscale: 1,
yscale: 0,
opacity: .1
}, BattleEffects.none)).animate(self.pos({
x: selfS.x,
y: selfS.y,
z: selfS.behind(-27),
xscale: 1,
yscale: .5,
opacity: .7
}, BattleEffects.none)).animate({
opacity: .2
}, 300);
elem = curelem;
selfS.sideConditions[condition] = [condition, elem, 5];
break;
case 'tailwind':
selfS.sideConditions[condition] = [condition, null, 5];
break;
case 'stealthrock':
self.spriteElemsFront[selfS.n].append('<img src="' + BattleEffects.rock1.url + '" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.leftof(-40),
y: selfS.y - 10,
z: selfS.z,
opacity: .5,
scale: .3
}, BattleEffects.rock1));
elem = curelem;
selfS.sideConditions[condition] = [condition, elem, 1];
break;
case 'spikes':
self.spriteElemsFront[selfS.n].append('<img src="' + BattleEffects.caltrop.url + '" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x - 25,
y: selfS.y - 40,
z: selfS.z,
scale: .3
}, BattleEffects.caltrop));
elem = curelem;
selfS.sideConditions[condition] = [condition, elem, 1];
break;
case 'toxicspikes':
self.spriteElemsFront[selfS.n].append('<img src="' + BattleEffects.poisoncaltrop.url + '" style="display:none;position:absolute" />');
curelem = self.spriteElemsFront[selfS.n].children().last();
curelem.css(self.pos({
display: 'block',
x: selfS.x + 5,
y: selfS.y - 40,
z: selfS.z,
scale: .3
}, BattleEffects.poisoncaltrop));
elem = curelem;
selfS.sideConditions[condition] = [condition, elem, 1];
break;
default:
selfS.sideConditions[condition] = [condition, null, 1];
}
};
this.removeSideCondition = function (condition) {
condition = toId(condition);
if (!selfS.sideConditions[condition]) return;
if (selfS.sideConditions[condition][1]) selfS.sideConditions[condition][1].remove();
delete selfS.sideConditions[condition];
};
this.newPokemon = function (species, replaceSlot) {
var id;
var pokeobj;
if (species.species) {
pokeobj = species;
species = pokeobj.species;
id = pokeobj.id;
}
var poke = Tools.getTemplate(species);
poke = $.extend(new Pokemon(species), poke);
poke.side = selfS;
poke.atkStat = 10;
poke.defStat = 10;
poke.spaStat = 10;
poke.spdStat = 10;
poke.maxhp = 1000;
if (self.gen === 5 && (species === 'Mienfoo' || species === 'Mienshao' || species === 'Tangrowth' || species === 'Slowking' || species === 'Slowbro')) {
poke.ability = '??Regenerator';
}
if (self.gen > 2 && (species === 'Staryu' || species === 'Starmie' || species === 'Shaymin' || species === 'Blissey' || species === 'Chansey' || species === 'Celebi')) {
poke.ability = '??NaturalCure';
}
if (pokeobj) poke = $.extend(poke, pokeobj);
if ((!poke.ability || poke.ability.substr(0,2) === '??') && poke.baseAbility) poke.ability = poke.baseAbility;
poke.id = id;
poke.reset();
poke.sprite = new self.Sprite(Tools.getSpriteData(poke, selfS.n), selfS.x, selfS.y, selfS.z, selfS.n);
if (typeof replaceSlot !== 'undefined') {
selfS.pokemon[replaceSlot] = poke;
} else {
selfS.pokemon.push(poke);
}
if (selfS.pokemon.length == 7) {
// something's wrong
self.logConsole('corruption');
// the other possibility is Illusion, which we'll assume
var existingTable = {};
for (var i=0; i<6; i++) {
var poke1 = selfS.pokemon[i];
if (existingTable[poke1.searchid]) {
var j = existingTable[poke1.searchid];
var poke2 = selfS.pokemon[j];
if (selfS.active.indexOf(poke1) >= 0) {
selfS.pokemon.splice(j,1);
} else if (selfS.active.indexOf(poke2) >= 0) {
selfS.pokemon.splice(i,1);
} else if (poke1.fainted && !poke2.fainted) {
selfS.pokemon.splice(j,1);
} else {
selfS.pokemon.splice(i,1);
}
break;
}
existingTable[poke1.searchid] = i;
}
}
selfS.updateSidebar();
return poke;
};
this.getStatbarHTML = function (pokemon) {
var gender = '';
if (pokemon.gender === 'F') gender = ' <small style="color:#C57575">&#9792;</small>';
if (pokemon.gender === 'M') gender = ' <small style="color:#7575C0">&#9794;</small>';
return '<div class="statbar' + (selfS.n ? ' lstatbar' : ' rstatbar') + '"><strong>' + sanitize(pokemon.name) + gender + (pokemon.level === 100 ? '' : ' <small>L' + pokemon.level + '</small>') + '</strong><div class="hpbar"><div class="hptext"></div><div class="hptextborder"></div><div class="prevhp"><div class="hp"></div></div><div class="status"></div></div>';
};
this.switchIn = function (pokemon, slot) {
if (slot === undefined) slot = pokemon.slot;
selfS.active[slot] = pokemon;
pokemon.slot = slot;
pokemon.clearVolatile();
pokemon.lastmove = '';
self.lastmove = 'switch-in';
if (selfS.lastPokemon && selfS.lastPokemon.lastmove === 'batonpass') {
pokemon.copyVolatileFrom(selfS.lastPokemon);
}
if (pokemon.side.n === 0) {
self.message('Go! ' + pokemon.getFullName() + '!');
} else {
self.message('' + sanitize(pokemon.side.name) + ' sent out ' + pokemon.getFullName() + '!');
}
pokemon.sprite.animSummon(slot);
if (pokemon.hasVolatile('substitute')) {
pokemon.sprite.animSub();
}
if (pokemon.statbarElem) {
pokemon.statbarElem.remove();
}
self.statElem.append(selfS.getStatbarHTML(pokemon));
pokemon.statbarElem = self.statElem.children().last();
selfS.updateStatbar(pokemon, true);
pokemon.side.updateSidebar();
if (self.fastForward) {
pokemon.statbarElem.css({
display: 'block',
left: pokemon.sprite.left - 80,
top: pokemon.sprite.top - 73 - pokemon.sprite.statbarOffset,
opacity: 1
});
if (self.switchCallback) self.switchCallback(self, selfS);
return;
}
pokemon.statbarElem.css({
display: 'block',
left: pokemon.sprite.left - 80,
top: pokemon.sprite.top - 53 - pokemon.sprite.statbarOffset,
opacity: 0
});
pokemon.statbarElem.delay(300).animate({
top: pokemon.sprite.top - 73 - pokemon.sprite.statbarOffset,
opacity: 1
}, 400);
if (self.switchCallback) self.switchCallback(self, selfS);
};
this.dragIn = function (pokemon, slot) {
if (slot === undefined) slot = pokemon.slot;
self.message('' + pokemon.getFullName() + ' was dragged out!');
if (pokemon === selfS.active[slot]) return;
var oldpokemon = selfS.active[slot];
selfS.lastPokemon = oldpokemon;
if (oldpokemon) oldpokemon.clearVolatile();
pokemon.clearVolatile();
pokemon.lastmove = '';
self.lastmove = 'switch-in';
selfS.active[slot] = pokemon;
if (oldpokemon === pokemon) return;
if (oldpokemon) {
oldpokemon.sprite.animDragOut();
}
pokemon.sprite.animDragIn(slot);
if (pokemon.statbarElem) {
pokemon.statbarElem.remove();
}
self.statElem.append(selfS.getStatbarHTML(pokemon));
pokemon.statbarElem = self.statElem.children().last();
selfS.updateStatbar(pokemon, true);
if (self.fastForward) {
if (oldpokemon) {
oldpokemon.statbarElem.remove();
oldpokemon.statbarElem = null;
}
pokemon.statbarElem.css({
display: 'block',
left: (selfS.n == 0 ? 100 : 340),
top: pokemon.sprite.top - 73 - pokemon.sprite.statbarOffset,
opacity: 1
});
if (self.dragCallback) self.dragCallback(self, selfS);
return;
}
if (selfS.n == 0) {
if (oldpokemon) {
oldpokemon.statbarElem.animate({
left: pokemon.sprite.left - 130,
opacity: 0
}, 400, function () {
oldpokemon.statbarElem.remove();
oldpokemon.statbarElem = null;
});
}
pokemon.statbarElem.css({
display: 'block',
left: pokemon.sprite.left - 30,
top: pokemon.sprite.top - 73 - pokemon.sprite.statbarOffset,
opacity: 0
});
pokemon.statbarElem.delay(300).animate({
left: pokemon.sprite.left - 80,
opacity: 1
}, 400);
} else {
if (oldpokemon) {
oldpokemon.statbarElem.animate({
left: pokemon.sprite.left - 30,
opacity: 0
}, 400, function () {
oldpokemon.statbarElem.remove();
oldpokemon.statbarElem = null;
});
}
pokemon.statbarElem.css({
display: 'block',
left: pokemon.sprite.left - 130,
top: pokemon.sprite.top - 73 - pokemon.sprite.statbarOffset,
opacity: 0
});
pokemon.statbarElem.delay(300).animate({
left: pokemon.sprite.left - 80,
opacity: 1
}, 400);
}
if (self.dragCallback) self.dragCallback(self, selfS);
};
this.replace = function (pokemon, slot) {
if (slot === undefined) slot = pokemon.slot;
var oldpokemon = selfS.active[slot];
if (pokemon === oldpokemon) return;
selfS.lastPokemon = oldpokemon;
pokemon.clearVolatile();
if (oldpokemon) {
pokemon.lastmove = oldpokemon.lastmove;
pokemon.hp = oldpokemon.hp;
pokemon.maxhp = oldpokemon.maxhp;
pokemon.status = oldpokemon.status;
pokemon.copyVolatileFrom(oldpokemon, true);
}
selfS.active[slot] = pokemon;
if (oldpokemon) {
oldpokemon.sprite.animUnsummon(true);
}
pokemon.sprite.animSummon(slot, true);
if (oldpokemon) {
oldpokemon.statbarElem.remove();
oldpokemon.statbarElem = null;
}
if (pokemon.statbarElem) {
pokemon.statbarElem.remove();
}
self.statElem.append(selfS.getStatbarHTML(pokemon));
pokemon.statbarElem = self.statElem.children().last();
selfS.updateStatbar(pokemon, true);
pokemon.statbarElem.css({
display: 'block',
left: pokemon.sprite.left - 80,
top: pokemon.sprite.top - 73 - pokemon.sprite.statbarOffset,
opacity: 1
});
// not sure if we want a different callback
if (self.dragCallback) self.dragCallback(self, selfS);
};
this.switchOut = function (pokemon, slot) {
if (slot === undefined) slot = pokemon.slot;
if (pokemon.lastmove !== 'batonpass') {
pokemon.clearVolatile();
} else {
pokemon.removeVolatile('transform');
pokemon.removeVolatile('formechange');
}
if (pokemon.lastmove === 'uturn' || pokemon.lastmove === 'voltswitch') {
self.message('' + pokemon.getName() + ' went back to ' + sanitize(pokemon.side.name) + '!');
} else if (pokemon.lastmove !== 'batonpass') {
if (pokemon.side.n === 0) {
self.message('' + pokemon.getName() + ', come back!');
} else {
self.message('' + sanitize(pokemon.side.name) + ' withdrew ' + pokemon.getFullName() + '!');
}
}
selfS.lastPokemon = pokemon;
selfS.active[slot] = null;
if ((pokemon.ability === 'Regenerator' || pokemon.ability === '??Regenerator') && pokemon.hp < pokemon.maxhp) {
var damage = 100 / 3;
pokemon.hp += pokemon.maxhp * damage / 100;
if (pokemon.hp > pokemon.maxhp) {
damage -= 100 * (pokemon.hp - pokemon.maxhp) / pokemon.maxhp;
pokemon.hp = pokemon.maxhp;
}
}
if ((pokemon.ability === 'NaturalCure' || pokemon.ability === '??NaturalCure') && pokemon.status) {
pokemon.status = '';
}
selfS.updateStatbar(pokemon, true);
pokemon.sprite.animUnsummon();
if (self.fastForward) {
pokemon.statbarElem.remove();
pokemon.statbarElem = null;
return;
}
pokemon.statbarElem.animate({
top: pokemon.sprite.top - 43 - pokemon.sprite.statbarOffset,
opacity: 0
}, 300, function () {
pokemon.statbarElem.remove();
pokemon.statbarElem = null;
});
//pokemon.statbarElem.done(pokemon.statbarElem.remove());
};
this.faint = function (pokemon, slot) {
if (slot === undefined) slot = pokemon.slot;
pokemon.clearVolatile();
selfS.lastPokemon = pokemon;
selfS.active[slot] = null;
self.message('' + pokemon.getName() + ' fainted!');
pokemon.fainted = true;
pokemon.zerohp = true;
pokemon.hp = 0;
pokemon.side.updateStatbar(pokemon, false, true);
pokemon.side.updateSidebar();
pokemon.sprite.animFaint();
pokemon.statbarElem.animate({
opacity: 0
}, 300, function () {
pokemon.statbarElem.remove();
pokemon.statbarElem = null;
});
if (self.faintCallback) self.faintCallback(self, selfS);
};
this.updateStatbar = function (pokemon, updatePrevhp, updateHp) {
if (!pokemon) {
if (selfS.active[0]) selfS.updateStatbar(selfS.active[0], updatePrevhp, updateHp);
if (selfS.active[1]) selfS.updateStatbar(selfS.active[1], updatePrevhp, updateHp);
return;
}
if (!pokemon || !pokemon.statbarElem) {
return;
}
if (updatePrevhp) {
pokemon.statbarElem.find('.prevhp').css('width', pokemon.hpWidth(150) + 1);
}
if (updatePrevhp || updateHp) {
var w = pokemon.hpWidth(150);
pokemon.statbarElem.find('.hp').css({
width: w,
'border-right-width': (w ? 1 : 0)
});
pokemon.statbarElem.find('.hptext').html('' + pokemon.hpWidth(100) + '%');
}
var status = '';
if (pokemon.status === 'brn') {
status += '<span class="brn">BRN</span> ';
} else if (pokemon.status === 'psn') {
status += '<span class="psn">PSN</span> ';
} else if (pokemon.status === 'tox') {
status += '<span class="psn">TOX</span> ';
} else if (pokemon.status === 'slp') {
status += '<span class="slp">SLP</span> ';
} else if (pokemon.status === 'par') {
status += '<span class="par">PAR</span> ';
} else if (pokemon.status === 'frz') {
status += '<span class="frz">FRZ</span> ';
}
for (x in pokemon.boosts) {
if (pokemon.boosts[x]) {
status += '<span class="' + pokemon.getBoostType(x) + '">' + pokemon.getBoost(x) + '</span> ';
}
}
var statusTable = {
confusion: '<span class="bad">Confused</span> ',
healblock: '<span class="bad">Heal&nbsp;Block</span> ',
yawn: '<span class="bad">Drowsy</span> ',
smackdown: '<span class="bad">Grounded</span> ',
flashfire: '<span class="good">Flash&nbsp;Fire</span> ',
imprison: '<span class="good">Imprisoning&nbsp;foe</span> ',
formechange: '',
typechange: '',
autotomize: '<span class="neutral">Lightened</span> ',
miracleeye: '<span class="bad">Miracle&nbsp;Eye</span> ',
foresight: '<span class="bad">Foresight</span> ',
telekinesis: '<span class="neutral">Telekinesis</span> ',
transform: '<span class="neutral">Transformed</span> ',
powertrick: '<span class="neutral">Power&nbsp;Trick</span> ',
curse: '<span class="bad">Curse</span> ',
nightmare: '<span class="bad">Nightmare</span> ',
attract: '<span class="bad">Attract</span> ',
torment: '<span class="bad">Torment</span> ',
taunt: '<span class="bad">Taunt</span> ',
disable: '<span class="bad">Disable</span> ',
embargo: '<span class="bad">Embargo</span> ',
ingrain: '<span class="good">Ingrain</span> ',
aquaring: '<span class="good">Aqua&nbsp;Ring</span> ',
stockpile1: '<span class="good">Stockpile</span> ',
stockpile2: '<span class="good">Stockpile&times;2</span> ',
stockpile3: '<span class="good">Stockpile&times;3</span> ',
perish1: '<span class="bad">Perish&nbsp;next&nbsp;turn</span> ',
perish2: '<span class="bad">Perish&nbsp;in&nbsp;2</span> ',
perish3: '<span class="bad">Perish&nbsp;in&nbsp;3</span> ',
airballoon: '<span class="good">Balloon</span> ',
leechseed: '<span class="bad">Leech&nbsp;Seed</span> ',
encore: '<span class="bad">Encore</span> ',
mustrecharge: '<span class="bad">Must&nbsp;recharge</span> ',
bide: '<span class="good">Bide</span> ',
magnetrise: '<span class="good">Magnet&nbsp;Rise</span> ',
smackdown: '<span class="bad">Smack&nbsp;Down</span> ',
focusenergy: '<span class="good">Focus&nbsp;Energy</span> ',
slowstart: '<span class="bad">Slow&nbsp;Start</span> ',
doomdesire: '',
futuresight: '',
mimic: '<span class="good">Mimic</span> ',
watersport: '<span class="good">Water&nbsp;Sport</span> ',
mudsport: '<span class="good">Mud&nbsp;Sport</span> ',
substitute: '',
// sub graphics are handled elsewhere, see Battle.Sprite.animSub()
uproar: '<span class="neutral">Uproar</span>',
roost: '<span class="neutral">Landed</span>',
protect: '<span class="good">Protect</span>',
quickguard: '<span class="good">Quick&nbsp;Guard</span>',
wideguard: '<span class="good">Wide&nbsp;Guard</span>',
helpinghand: '<span class="good">Helping&nbsp;Hand</span>',
magiccoat: '<span class="good">Magic&nbsp;Coat</span>',
destinybond: '<span class="good">Destiny&nbsp;Bond</span>',
snatch: '<span class="good">Snatch</span>',
grudge: '<span class="good">Grudge</span>',
endure: '<span class="good">Endure</span>',
focuspunch: '<span class="neutral">Focusing</span>'
};
for (i in pokemon.volatiles) {
if (typeof statusTable[i] === 'undefined') status += '<span class="neutral">[['+i+']]</span>';
else status += statusTable[i];
}
for (i in pokemon.turnstatuses) {
if (typeof statusTable[i] === 'undefined') status += '<span class="neutral">[['+i+']]</span>';
else status += statusTable[i];
}
for (i in pokemon.movestatuses) {
if (typeof statusTable[i] === 'undefined') status += '<span class="neutral">[['+i+']]</span>';
else status += statusTable[i];
}
var statusbar = pokemon.statbarElem.find('.status');
statusbar.html(status);
}
};
this.sidesSwitched = false;
this.switchSides = function () {
self.sidesSwitched = !self.sidesSwitched;
if (self.sidesSwitched) {
self.mySide = self.p2;
self.yourSide = self.p1;
} else {
self.mySide = self.p1;
self.yourSide = self.p2;
}
self.mySide.n = 0;
self.yourSide.n = 1;
self.sides[0] = self.mySide;
self.sides[1] = self.yourSide;
self.mySide.updateSidebar();
self.mySide.updateSprites();
self.yourSide.updateSidebar();
self.yourSide.updateSprites();
// nothing else should need updating - don't call this function after sending out pokemon
}
this.messageActive = false;
this.message = function (message, hiddenmessage) {
if (message && !self.messageActive) {
self.log('<div class="spacer"></div>');
}
if (message && !self.fastForward) {
if (!self.messageActive) {
self.messagebarElem.empty();
self.messagebarElem.css({
display: 'block',
opacity: 0,
height: 'auto'
});
self.messagebarElem.animate({
opacity: 1
}, 300);
}
self.hiddenMessageElem.append('<p></p>');
var messageElem = self.hiddenMessageElem.children().last();
messageElem.html(message);
messageElem.css({
display: 'block',
opacity: 0
});
messageElem.animate({
height: 'hide'
}, 1, function () {
messageElem.appendTo(self.messagebarElem);
messageElem.animate({
height: 'show',
'padding-bottom': 4,
opacity: 1
}, 300);
});
self.activityWait(messageElem);
}
self.messageActive = true;
self.log('<div>' + message + (hiddenmessage ? hiddenmessage : '') + '</div>');
}
this.endAction = function () {
if (self.messageActive) {
self.messageActive = false;
if (!self.fastForward) {
self.messagebarElem.delay(self.messageDelay).animate({
height: 'toggle',
opacity: 0
}, 300);
self.activityWait(self.messagebarElem);
}
}
}
//
// activities
//
this.start = function () {
self.log('<div>Battle between ' + sanitize(self.p1.name) + ' and ' + sanitize(self.p2.name) + ' started!</div>');
if (self.startCallback) self.startCallback(self);
}
this.winner = function (winner) {
if (self.fastForward !== -2) self.fastForwardOff();
if (winner) self.message('' + winner + ' won the battle!');
else self.message('Tie between ' + sanitize(self.p1.name) + ' and ' + sanitize(self.p2.name) + '!');
self.done = 1;
}
this.prematureEnd = function () {
if (self.fastForward !== -2) self.fastForwardOff();
self.message('This replay ends here.');
self.done = 1;
}
this.setTurn = function (turnnum) {
turnnum = parseInt(turnnum);
self.turn = turnnum;
self.updateWeatherLeft();
if (self.mySide.active[0]) self.mySide.active[0].clearTurnstatuses();
if (self.mySide.active[1]) self.mySide.active[1].clearTurnstatuses();
if (self.yourSide.active[0]) self.yourSide.active[0].clearTurnstatuses();
if (self.yourSide.active[1]) self.yourSide.active[1].clearTurnstatuses();
self.mySide.updateStatbar(null, true);
self.yourSide.updateStatbar(null, true);
self.log('<h2>Turn ' + turnnum + '</h2>');
var prevTurnElem = self.turnElem.children();
if (self.fastForward) {
if (prevTurnElem.length) prevTurnElem.html('Turn ' + turnnum);
else self.turnElem.append('<div class="turn" style="display:block;opacity:1;left:110px;">Turn ' + turnnum + '</div>');
if (self.turnCallback) self.turnCallback(self);
if (self.fastForward > -1 && turnnum >= self.fastForward) {
self.fastForwardOff();
}
return;
}
self.turnElem.append('<div class="turn">Turn ' + turnnum + '</div>');
var newTurnElem = self.turnElem.children().last();
newTurnElem.css({
display: 'block',
opacity: 0,
left: 160
});
newTurnElem.animate({
opacity: 1,
left: 110
}, 500).animate({
opacity: .4
}, 1500);
prevTurnElem.animate({
opacity: 0,
left: 60
}, 500, function () {
prevTurnElem.remove();
});
self.activityWait(500);
if (self.turnCallback) self.turnCallback(self);
}
this.changeWeather = function (weather, poke, isUpkeep) {
weather = toId(weather);
var weatherTable = {
sunnyday: {
name: 'Sun',
startMessage: 'The sunlight turned harsh!',
abilityMessage: "'s Drought intensified the sun's rays!",
//upkeepMessage: 'The sunlight is strong!',
endMessage: "The sunlight faded."
},
raindance: {
name: 'Rain',
startMessage: 'It started to rain!',
abilityMessage: "'s Drizzle made it rain!",
//upkeepMessage: 'Rain continues to fall!',
endMessage: 'The rain stopped.'
},
sandstorm: {
name: 'Sandstorm',
startMessage: 'A sandstorm kicked up!',
abilityMessage: "'s Sand Stream whipped up a sandstorm!",
upkeepMessage: 'The sandstorm rages.',
endMessage: 'The sandstorm subsided.'
},
hail: {
name: 'Hail',
startMessage: 'It started to hail!',
abilityMessage: "'s Snow Warning whipped up a hailstorm!",
upkeepMessage: 'The hail crashes down.',
endMessage: 'The hail stopped.'
}
};
if (!weather || weather === 'none') {
weather = '';
}
var newWeather = weatherTable[weather];
if (isUpkeep) {
if (!self.fastForward) {
self.weatherElem.animate({
opacity: 1.0
}, 400).animate({
opacity: .4
}, 400);
}
if (newWeather && newWeather.upkeepMessage) self.log('<div><small>' + newWeather.upkeepMessage + '</small></div>');
return;
}
if (newWeather) {
if (poke) {
self.message('<small>' + poke.getName() + newWeather.abilityMessage + '</small>');
self.weatherTimeLeft = 0;
self.weatherMinTimeLeft = 0;
} else if (isUpkeep) {
self.log('<div><small>' + newWeather.upkeepMessage + '</small></div>');
self.weatherTimeLeft = 0;
self.weatherMinTimeLeft = 0;
} else {
self.message('<small>' + newWeather.startMessage + '</small>');
if (self.turn === 0) {
self.weatherTimeLeft = 0;
self.weatherMinTimeLeft = 0;
} else {
self.weatherTimeLeft = 8;
self.weatherMinTimeLeft = 5;
}
}
}
if (self.weather && !newWeather) {
self.message(weatherTable[self.weather].endMessage);
}
self.updateWeather(weather);
}
this.updateWeatherLeft = function () {
for (var i = 0; i < self.pseudoWeather.length; i++) {
if (self.pseudoWeather[i][1] > 0) self.pseudoWeather[i][1]--;
}
if (self.weather && self.weatherTimeLeft) {
self.weatherTimeLeft--;
if (self.weatherMinTimeLeft != 0) self.weatherMinTimeLeft--;
}
self.updateWeather();
};
this.weatherLeft = function (weather) {
if (weather) {
for (var i = 0; i < self.pseudoWeather.length; i++) {
if (self.pseudoWeather[i][0] === weather) {
if (self.pseudoWeather[i][1]) {
return ' <small>(' + self.pseudoWeather[i][1] + ' turn' + (self.pseudoWeather[i][1] == 1 ? '' : 's') + ' left)</small>';
}
return '';
}
}
return ''; // weather doesn't exist
}
if (self.weatherMinTimeLeft != 0) {
return ' <small>(' + self.weatherMinTimeLeft + ' to ' + self.weatherTimeLeft + ' turns left)</small>';
}
if (self.weatherTimeLeft != 0) {
return ' <small>(' + self.weatherTimeLeft + ' turn' + (self.weatherTimeLeft == 1 ? '' : 's') + ' left)</small>';
}
return '';
}
this.updateWeather = function (weather) {
var weatherNameTable = {
sunnyday: 'Sun',
raindance: 'Rain',
sandstorm: 'Sandstorm',
hail: 'Hail'
};
if (typeof weather === 'undefined') {
weather = self.weather;
}
if (weather === '' || weather === 'none' || weather === 'pseudo') {
weather = (self.pseudoWeather.length ? 'pseudo' : '');
}
var oldweather = self.weather;
self.weather = weather;
var weatherhtml = '';
if (weather) {
if (weather !== 'pseudo') {
weatherhtml += weatherNameTable[weather] + self.weatherLeft();
}
for (var i = 0; i < self.pseudoWeather.length; i++) {
weatherhtml += '<br />' + Tools.getMove(self.pseudoWeather[i][0]).name + self.weatherLeft(self.pseudoWeather[i][0]);
}
}
if (weather === oldweather) {
if (weather) self.weatherElem.html('<em>' + weatherhtml + '</em>');
return;
}
if (oldweather) {
if (weather) {
self.weatherElem.animate({
opacity: 0
}, 300, function () {
self.weatherElem.css({
display: 'block'
});
self.weatherElem.attr('class', 'weather ' + weather + 'weather');
self.weatherElem.html('<em>' + weatherhtml + '</em>');
});
} else {
self.weatherElem.animate({
opacity: 0
}, 500);
}
} else if (weather) {
self.weatherElem.css({
display: 'block',
opacity: 0
});
self.weatherElem.attr('class', 'weather ' + weather + 'weather');
self.weatherElem.html('<em>' + weatherhtml + '</em>');
}
if (weather) {
if (self.fastForward) {
self.weatherElem.css({opacity:.4});
return;
}
self.weatherElem.animate({
opacity: 1.0
}, 400).animate({
opacity: .4
}, 400);
}
}
this.resultAnim = function (pokemon, result, type, i) {
if (self.fastForward) {
pokemon.side.updateStatbar(pokemon, false, true);
return;
}
if (!i) {
i = 0;
}
self.fxElem.append('<div class="result ' + type + 'result"><strong>' + result + '</strong></div>');
effectElem = self.fxElem.children().last();
effectElem.delay(i * 350 + self.animationDelay).css({
display: 'block',
opacity: 0,
top: pokemon.sprite.top - 5,
left: pokemon.sprite.left - 75
}).animate({
opacity: 1
}, 1);
effectElem.animate({
opacity: 0,
top: pokemon.sprite.top - 65
}, 1000, 'swing');
pokemon.side.updateStatbar(pokemon);
self.activityWait(effectElem);
}
this.damageAnim = function (pokemon, damage, i) {
if (!pokemon.statbarElem) return;
if (!i) {
i = 0;
}
var w = pokemon.hpWidth(150);
self.resultAnim(pokemon, '&minus;' + Math.round(damage) + '%', 'bad', i);
pokemon.statbarElem.find('.hptext').html('' + pokemon.hpWidth(100) + '%');
if (!self.fastForward) pokemon.statbarElem.find('div.hp').delay(self.animationDelay).animate({
width: w,
'border-right-width': w ? 1 : 0
}, 350);
}
this.healAnim = function (pokemon, damage, i) {
if (!pokemon.statbarElem) return;
if (!i) {
i = 0;
}
var w = pokemon.hpWidth(150);
self.resultAnim(pokemon, '+' + Math.round(damage) + '%', 'good', i);
pokemon.statbarElem.find('.hptext').html('' + pokemon.hpWidth(100) + '%');
if (!self.fastForward) pokemon.statbarElem.find('div.hp').animate({
width: w,
'border-right-width': w ? 1 : 0
}, 350);
}
this.useMove = function (pokemon, move, target, kwargs) {
var fromeffect = Tools.getEffect(kwargs.from);
pokemon.clearMovestatuses();
pokemon.side.updateStatbar(pokemon, true);
if (move.id === 'focuspunch') {
pokemon.removeTurnstatus('focuspunch');
pokemon.side.updateStatbar(pokemon);
}
if (!target) {
target = pokemon.side.foe.active[0];
}
if (!target) {
target = pokemon.side.foe.missedPokemon;
}
if (!self.fastForward) {
// skip
if (kwargs.miss && target.side) {
target = target.side.missedPokemon;
}
if (kwargs.notarget) {
target = pokemon.side.foe.missedPokemon;
}
if (kwargs.prepare || kwargs.anim === 'prepare') {
self.prepareMove(pokemon, move, target);
} else if (!kwargs.still && !kwargs.notarget) {
move.anim(self, [pokemon.sprite, target.sprite]);
}
}
if (!kwargs.silent) {
switch (fromeffect.id) {
case 'snatch':
break;
case 'metronome':
self.message('Waggling a finger let it use <strong>' + move.name + '</strong>!');
break;
case 'naturepower':
self.message('Nature Power turned into <strong>' + move.name + '</strong>!');
break;
case 'sleeptalk':
default:
self.message(pokemon.getName() + ' used <strong>' + move.name + '</strong>!');
break;
}
}
pokemon.lastmove = move.id;
self.lastmove = move.id;
if (move.id === 'wish' || move.id === 'healingwish') {
pokemon.side.wisher = pokemon;
}
if (move.id === 'hyperbeam' || move.id === 'gigaimpact' || move.id === 'rockwrecker' || move.id === 'roaroftime' || move.id === 'blastburn' || move.id === 'frenzyplant' || move.id === 'hydrocannon') {
if (!kwargs.miss && !kwargs.notarget) {
pokemon.addMovestatus('mustrecharge');
pokemon.side.updateStatbar();
self.animationDelay += 500;
}
}
};
this.cantUseMove = function (pokemon, effect, move, kwargs) {
pokemon.clearMovestatuses();
pokemon.side.updateStatbar(pokemon, true);
switch (effect.id)
{
case 'taunt':
self.message('' + pokemon.getName() + ' can\'t use ' + move.name + ' after the taunt!');
break;
case 'imprison':
self.message('' + pokemon.getName() + ' can\'t use the sealed ' + move.name + '!');
break;
case 'par':
self.resultAnim(pokemon, 'Paralyzed', 'par');
BattleOtherAnims['fullparalysis'].anim(self, [pokemon.sprite]);
self.message('' + pokemon.getName() + ' is paralyzed! It can\'t move!');
break;
case 'frz':
self.resultAnim(pokemon, 'Frozen', 'frz');
self.message('' + pokemon.getName() + ' is frozen solid!');
break;
case 'slp':
self.resultAnim(pokemon, 'Asleep', 'slp');
self.message('' + pokemon.getName() + ' is fast asleep.');
break;
case 'skydrop':
self.message('Sky Drop won\'t let ' + pokemon.getLowerName() + ' go!');
break;
case 'truant':
self.resultAnim(pokemon, 'Truant', 'neutral');
self.message('' + pokemon.getName() + ' is loafing around!');
break;
case 'recharge':
BattleOtherAnims['selfstatus'].anim(self, [pokemon.sprite]);
self.resultAnim(pokemon, 'Must recharge', 'neutral');
self.message('<small>' + pokemon.getName() + ' must recharge!</small>');
break;
case 'focuspunch':
self.resultAnim(pokemon, 'Lost focus', 'neutral');
self.message(pokemon.getName() + ' lost its focus and couldn\'t move!');
pokemon.removeTurnstatus('focuspunch');
break;
case 'flinch':
self.resultAnim(pokemon, 'Flinched', 'neutral');
self.message(pokemon.getName() + ' flinched!');
pokemon.removeTurnstatus('focuspunch');
break;
case 'attract':
self.resultAnim(pokemon, 'Immobilized', 'neutral');
self.message(pokemon.getName() + ' is immobilized by love!');
break;
default:
self.message('<small>' + pokemon.getName() + (move.name ? ' can\'t use ' + move.name + '' : ' can\'t move') + '!</small>');
break;
}
};
this.prepareMove = function (pokemon, move, target) {
if (!move.prepareAnim) return;
if (!target) {
target = pokemon.side.foe.active[0];
}
if (!target) {
target = pokemon;
}
if (!self.fastForward) move.prepareAnim(self, [pokemon.sprite, target.sprite]);
self.message('<small>'+move.prepareMessage(pokemon, target)+'</small>');
};
this.animMultiHitMove = function () {
if (self.multiHitMove && !self.fastForward) {
self.multiHitMove[0].anim(self, [self.multiHitMove[1], self.multiHitMove[2]]);
self.multiHitMove[3]++;
self.animationDelay += 500;
}
};
this.runMinor = function (args, kwargs, preempt, nextArgs, nextKwargs) {
var actions = '';
var hiddenactions = '';
var minors = self.minorQueue;
if (self.multiHitMove && minors.length) {
var lastMinor = minors[minors.length - 1];
//if (lastMinor[0][0] === '-damage' || lastMinor[0][1]['subdamage']) self.animMultiHitMove();
}
if (args) {
if (args[0] === '-crit' || args[0] === '-supereffective' || args[0] === '-resisted') args.then = '.';
if (args[0] === '-damage' && kwargs.from === 'Leech Seed' && nextArgs[0] === '-heal' && nextKwargs.silent) args.then = '.';
minors.push([args, kwargs]);
if (args.simult || args.then) {
return;
}
}
var animDelay = 0;
var nextAnimDelay = 0;
while (minors.length) {
var row = minors.shift();
args = row[0];
kwargs = row[1];
animDelay = nextAnimDelay;
if (!kwargs.simult) nextAnimDelay++;
switch (args[0]) {
case '-damage':
var poke = this.getPokemon(args[1]);
var damage = parseFloat(args[2]);
if (isNaN(damage)) damage = 50; // wtf
poke.hp -= poke.maxhp * damage / 100;
poke.healthParse(args[2]);
self.damageAnim(poke, damage, animDelay);
self.lastDamage = (damage || 1);
if (kwargs.silent) {
// do nothing
} else if (kwargs.from) {
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
switch (effect.id) {
case 'stealthrock':
actions += "Pointed stones dug into " + poke.getLowerName() + "!";
break;
case 'spikes':
actions += "" + poke.getName() + " is hurt by the spikes!";
break;
case 'brn':
actions += "" + poke.getName() + " was hurt by its burn!";
break;
case 'psn':
actions += "" + poke.getName() + " was hurt by poison!";
break;
case 'lifeorb':
hiddenactions += "" + poke.getName() + " lost some of its HP!";
break;
case 'recoil':
actions += "" + poke.getName() + " is damaged by recoil!";
break;
case 'sandstorm':
actions += "" + poke.getName() + " is buffeted by the sandstorm!";
break;
case 'hail':
actions += "" + poke.getName() + " is buffeted by the hail!";
break;
case 'baddreams':
actions += "" + poke.getName() + " is tormented!";
break;
case 'nightmare':
actions += "" + poke.getName() + " is locked in a nightmare!";
break;
case 'confusion':
actions += "It hurt itself in its confusion! ";
break;
case 'leechseed':
if (!self.fastForward) {
BattleOtherAnims.leech.anim(self, [ofpoke.sprite, poke.sprite]);
self.activityWait(500);
}
actions += "" + poke.getName() + "'s health is sapped by Leech Seed!";
break;
case 'flameburst':
actions += "The bursting flame hit " + poke.getLowerName() + "!";
break;
case 'grasspledge':
actions += "" + poke.getName() + " is hurt by the sea of fire!";
break;
case 'jumpkick':
case 'hijumpkick':
actions += "" + poke.getName() + " kept going and crashed!";
break;
default:
if (ofpoke) {
actions += "" + poke.getName() + " is hurt by " + ofpoke.getLowerName() + "'s " + effect.name + "!";
} else if (effect.effectType === 'Item' || effect.effectType === 'Ability') {
actions += "" + poke.getName() + " is hurt by its " + effect.name + "!";
} else if (kwargs.partiallytrapped) {
actions += "" + poke.getName() + ' is hurt by ' + effect.name + '!';
} else {
actions += "" + poke.getName() + " lost some HP because of " + effect.name + "!";
}
break;
}
} else {
hiddenactions += "" + poke.getName() + " lost " + damage + "% of its health!";
}
break;
case '-heal':
var poke = this.getPokemon(args[1]);
var damage = parseFloat(args[2]);
if (isNaN(damage)) damage = 50;
poke.hp += poke.maxhp * damage / 100;
if (poke.hp > poke.maxhp) {
poke.hp = poke.maxhp;
}
poke.healthParse(args[2]);
self.healAnim(poke, damage, animDelay);
if (kwargs.silent) {
// do nothing
} else if (kwargs.from) {
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
switch (effect.id) {
case 'ingrain':
actions += "" + poke.getName() + " absorbed nutrients with its roots!";
break;
case 'aquaring':
actions += "Aqua Ring restored " + poke.getLowerName() + "'s HP!";
break;
case 'raindish': case 'dryskin': case 'icebody':
actions += "" + poke.getName() + "'s " + effect.name + " heals it!";
break;
case 'healingwish':
actions += "The healing wish came true for "+poke.getLowerName()+"!";
self.lastmove = 'healing-wish';
Tools.getMove('healingwish').residualAnim(self, [poke.sprite]);
poke.side.wisher = null;
break;
case 'lunardance':
actions += ""+poke.getName()+" became cloaked in mystical moonlight!";
self.lastmove = 'healing-wish';
Tools.getMove('healingwish').residualAnim(self, [poke.sprite]);
poke.side.wisher = null;
break;
case 'wish':
actions += "" + kwargs.wisher + "'s wish came true!";
Tools.getMove('wish').residualAnim(self, [poke.sprite]);
self.animationDelay += 500;
break;
case 'drain':
actions += ofpoke.getName() + ' had its energy drained!';
break;
default:
if (kwargs.absorb) {
actions += "" + poke.getName() + "'s " + effect.name + " absorbs the attack!";
} else if (effect.id) {
actions += "" + poke.getName() + " restored HP using its " + effect.name + "!";
} else {
actions += poke.getName() + ' regained health!';
}
break;
}
} else {
actions += poke.getName() + ' regained health!';
}
break;
case '-sethp':
var effect = Tools.getEffect(kwargs.from);
var poke, ofpoke;
for (var k=0; k<2; k++)
{
var cpoke = self.getPokemon(args[1+2*k]);
if (cpoke) {
var oldhp = cpoke.hp;
cpoke.healthParse(args[2+2*k]);
var diff = parseFloat(args[2+2*k]);
if (isNaN(diff)) {
diff = cpoke.hp - oldhp;
}
if (diff > 0) {
self.healAnim(cpoke, diff, animDelay);
} else {
self.damageAnim(cpoke, -diff, animDelay);
}
}
if (k==0) poke = cpoke;
if (k==1) ofpoke = cpoke;
}
switch (effect.id) {
case 'painsplit':
actions += 'The battlers shared their pain!';
break;
}
break;
case '-boost':
var poke = this.getPokemon(args[1]);
var stat = args[2];
var amount = parseInt(args[3]);
if (!poke.boosts[stat]) {
poke.boosts[stat] = 0;
}
poke.boosts[stat] += amount;
self.resultAnim(poke, poke.getBoost(stat), 'good', animDelay);
var amountString = '';
if (amount === 2) amountString = ' sharply';
if (amount >= 3) amountString = ' drastically';
if (kwargs.silent) {
// do nothing
} else if (kwargs.from) {
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
switch (effect.id) {
default:
if (effect.effectType === 'Item') {
actions += "The " + effect.name + amountString+" raised " + poke.getLowerName() + "'s " + BattleStats[stat] + "!";
} else {
actions += "" + poke.getName() + "'s " + effect.name +amountString+" raised its " + BattleStats[stat] + "!";
}
break;
}
} else {
actions += "" + poke.getName() + "'s " + BattleStats[stat] + amountString + " rose" + "!";
}
break;
case '-unboost':
var poke = this.getPokemon(args[1]);
var stat = args[2];
var amount = parseInt(args[3]);
if (!poke.boosts[stat]) {
poke.boosts[stat] = 0;
}
poke.boosts[stat] -= amount;
self.resultAnim(poke, poke.getBoost(stat), 'bad', animDelay);
var amountString = '';
if (amount === 2) amountString = ' harshly';
if (amount >= 3) amountString = ' severely';
if (kwargs.silent) {
// do nothing
} else if (kwargs.from) {
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
switch (effect.id) {
default:
if (effect.effectType === 'Item') {
actions += "The " + effect.name + amountString+" lowered " + poke.getLowerName() + "'s " + BattleStats[stat] + "!";
} else {
actions += "" + poke.getName() + "'s " + effect.name +amountString+" lowered its " + BattleStats[stat] + "!";
}
break;
}
} else {
actions += "" + poke.getName() + "'s " + BattleStats[stat] + amountString + " fell!";
}
break;
case '-setboost':
var poke = this.getPokemon(args[1]);
var stat = args[2];
var amount = parseInt(args[3]);
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
poke.boosts[stat] = amount;
self.resultAnim(poke, poke.getBoost(stat), (amount>0?'good':'bad'), animDelay);
if (kwargs.silent) {
// do nothing
} else if (kwargs.from) {
switch (effect.id) {
case 'bellydrum':
actions += '' + poke.getName() + ' cut its own HP and maximized its Attack!';
break;
case 'angerpoint':
actions += '' + poke.getName() + ' maxed its Attack!';
break;
}
}
break;
case '-swapboost':
var poke = this.getPokemon(args[1]);
var poke2 = this.getPokemon(args[2]);
var stats = args[3]?args[3].split(', '):['atk','def','spa','spd','spe','accuracy','evasion'];
var effect = Tools.getEffect(kwargs.from);
for (var i=0; i<stats.length; i++)
{
var tmp = poke.boosts[stats[i]];
poke.boosts[stats[i]] = poke2.boosts[stats[i]];
if (!poke.boosts[stats[i]]) delete poke.boosts[stats[i]];
poke2.boosts[stats[i]] = tmp;
if (!poke2.boosts[stats[i]]) delete poke2.boosts[stats[i]];
}
self.resultAnim(poke, 'Stats swapped', 'neutral', animDelay);
self.resultAnim(poke2, 'Stats swapped', 'neutral', animDelay);
if (kwargs.silent) {
// do nothing
} else if (effect.id) {
switch (effect.id) {
case 'guardswap':
actions += '' + poke.getName() + ' switched all changes to its Defense and Sp. Def with the target!';
break;
case 'heartswap':
actions += '' + poke.getName() + ' switched stat changes with the target!';
break;
case 'powerswap':
actions += '' + poke.getName() + ' switched all changes to its Attack and Sp. Atk with the target!';
break;
}
}
break;
case '-restoreboost':
var poke = this.getPokemon(args[1]);
for (i in poke.boosts) {
if (poke.boosts[i] < 0) delete poke.boosts[i];
}
self.resultAnim(poke, 'Restored', 'good', animDelay);
if (kwargs.silent) {
// do nothing
}
break;
case '-copyboost':
var poke = this.getPokemon(args[1]);
var frompoke = this.getPokemon(args[2]);
var stats = args[3]?args[3].split(', '):['atk','def','spa','spd','spe','accuracy','evasion'];
var effect = Tools.getEffect(kwargs.from);
for (var i=0; i<stats.length; i++)
{
poke.boosts[stats[i]] = frompoke.boosts[stats[i]];
if (!poke.boosts[stats[i]]) delete poke.boosts[stats[i]];
}
//poke.boosts = $.extend({}, frompoke.boosts);
if (kwargs.silent) {
// do nothing
} else {
self.resultAnim(poke, 'Stats copied', 'neutral', animDelay);
actions += "" + poke.getName() + " copied " + frompoke.getLowerName() + "'s stat changes!";
}
break;
case '-clearboost':
var poke = this.getPokemon(args[1]);
poke.boosts = {};
self.resultAnim(poke, 'Stats reset', 'neutral', animDelay);
if (kwargs.silent) {
// do nothing
} else {
actions += '' + poke.getName() + '\'s stat changes were removed!';
}
break;
case '-clearallboost':
for (var slot=0; slot<self.mySide.active.length; slot++) {
if (self.mySide.active[slot]) {
self.mySide.active[slot].boosts = {};
self.resultAnim(self.mySide.active[slot], 'Stats reset', 'neutral', animDelay);
}
if (self.yourSide.active[slot]) {
self.yourSide.active[slot].boosts = {};
self.resultAnim(self.yourSide.active[slot], 'Stats reset', 'neutral', animDelay);
}
}
if (kwargs.silent) {
// do nothing
} else {
actions += 'All stat changes were eliminated!';
}
break;
case '-crit':
var poke = this.getPokemon(args[1]);
for (var j=1; !poke && j<10; j++) poke = this.getPokemon(minors[i+j][0][1]);
if (poke) self.resultAnim(poke, 'Critical hit', 'bad', animDelay);
actions += "A critical hit! ";
break;
case '-supereffective':
var poke = this.getPokemon(args[1]);
for (var j=1; !poke && j<10; j++) poke = this.getPokemon(minors[i+j][0][1]);
if (poke) self.resultAnim(poke, 'Super-effective', 'bad', animDelay);
actions += "It's super effective! ";
break;
case '-resisted':
var poke = this.getPokemon(args[1]);
for (var j=1; !poke && j<10; j++) poke = this.getPokemon(minors[i+j][0][1]);
if (poke) self.resultAnim(poke, 'Resisted', 'neutral', animDelay);
actions += "It's not very effective... ";
break;
case '-immune':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
self.resultAnim(poke, 'Immune', 'neutral', animDelay);
switch (effect.id) {
case 'confusion':
actions += "" + poke.getName() + " doesn't become confused! ";
break;
default:
if (kwargs.msg) {
actions += "It doesn't affect " + poke.getLowerName() + "... ";
} else {
actions += "It had no effect! ";
}
break;
}
break;
case '-miss':
var user = this.getPokemon(args[1]);
var target = this.getPokemon(args[2]);
if (target) {
actions += "" + target.getName() + " avoided the attack!";
} else {
actions += "" + user.getName() + "'s attack missed!";
}
break;
case '-fail':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
var fromeffect = Tools.getEffect(kwargs.from);
if (poke) {
self.resultAnim(poke, 'Failed', 'neutral', animDelay);
}
switch (effect.id) {
case 'brn':
self.resultAnim(poke, 'Already burned', 'neutral', animDelay);
actions += "" + poke.getName() + " is already burned.";
break;
case 'tox':
case 'psn':
self.resultAnim(poke, 'Already poisoned', 'neutral', animDelay);
actions += "" + poke.getName() + " is already poisoned.";
break;
case 'slp':
if (fromeffect.id === 'uproar') {
self.resultAnim(poke, 'Failed', 'neutral', animDelay);
if (kwargs.msg) {
actions += "But " + poke.getLowerName() + " can't sleep in an uproar!";
} else {
actions += "But the uproar kept " + poke.getLowerName() + " awake!";
}
} else {
self.resultAnim(poke, 'Already asleep', 'neutral', animDelay);
actions += "" + poke.getName() + " is already asleep.";
}
break;
case 'par':
self.resultAnim(poke, 'Already paralyzed', 'neutral', animDelay);
actions += "" + poke.getName() + " is already paralyzed.";
break;
case 'frz':
self.resultAnim(poke, 'Already frozen', 'neutral', animDelay);
actions += "" + poke.getName() + " is already frozen.";
break;
case 'substitute':
if (kwargs.weak) {
actions += "It was too weak to make a substitute!";
} else {
actions += '' + poke.getName() + ' already has a substitute!';
}
break;
case '':
default:
actions += "But it failed!";
break;
}
break;
case '-notarget':
actions += "But there was no target...";
break;
case '-ohko':
actions += "It's a one-hit KO!";
break;
case '-hitcount':
var hits = parseInt(args[2]);
if (self.multiHitMove && self.multiHitMove[3] === 0 && hits > 0) self.animMultiHitMove();
actions += 'Hit ' + hits + ' time(s)!';
break;
case '-nothing':
actions += "But nothing happened! ";
break;
case '-waiting':
var poke = this.getPokemon(args[1]);
var ofpoke = this.getPokemon(args[2]);
actions += "" + poke.getName() + " is waiting for " + ofpoke.getLowerName() + "'s move...";
break;
case '-combine':
actions += "The two moves are joined! It's a combined move!";
break;
case '-prepare':
var poke = this.getPokemon(args[1]);
var move = Tools.getMove(args[2]);
var target = this.getPokemon(args[3]);
self.prepareMove(poke, move, target);
break;
case '-status':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(kwargs.from);
poke.status = args[2];
poke.removeVolatile('yawn');
switch (args[2]) {
case 'brn':
self.resultAnim(poke, 'Burned', 'brn', animDelay);
actions += "" + poke.getName() + " was burned!";
break;
case 'tox':
self.resultAnim(poke, 'Toxic poison', 'psn', animDelay);
actions += "" + poke.getName() + " was badly poisoned!";
break;
case 'psn':
self.resultAnim(poke, 'Poisoned', 'psn', animDelay);
actions += "" + poke.getName() + " was poisoned!";
break;
case 'slp':
if (effect.id === 'rest') {
self.resultAnim(poke, 'Asleep', 'slp', animDelay);
actions += '' + poke.getName() + ' slept and became healthy!';
} else {
self.resultAnim(poke, 'Asleep', 'slp', animDelay);
actions += "" + poke.getName() + " fell asleep!";
}
break;
case 'par':
self.resultAnim(poke, 'Paralyzed', 'par', animDelay);
actions += "" + poke.getName() + " is paralyzed! It may be unable to move!";
break;
case 'frz':
self.resultAnim(poke, 'Frozen', 'frz', animDelay);
actions += "" + poke.getName() + " was frozen solid!";
break;
}
break;
case '-curestatus':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
poke.status = '';
if (effect.id) switch (effect.id) {
case 'psychoshift':
actions += '' + poke.getName() + ' moved its status onto ' + ofpoke.getLowerName() + '!';
self.resultAnim(poke, 'Cured', 'good', animDelay);
break;
default:
self.resultAnim(poke, 'Cured', 'good', animDelay);
actions += "" + poke.getName() + "'s "+effect.name+" heals its status!";
break;
} else switch (args[2]) {
case 'brn':
self.resultAnim(poke, 'Burn cured', 'good', animDelay);
if (poke.side.n === 0) actions += "" + poke.getName() + "'s burn was healed.";
else actions += "" + poke.getName() + " healed its burn!";
break;
case 'tox':
case 'psn':
self.resultAnim(poke, 'Poison cured', 'good', animDelay);
var n = poke.side.n; // hack for eliminating "the foe's"
poke.side.n = 0;
actions += "" + poke.getName() + " was cured of its poisoning.";
poke.side.n = n;
break;
case 'slp':
self.resultAnim(poke, 'Woke up', 'good', animDelay);
actions += "" + poke.getName() + " woke up!";
break;
case 'par':
self.resultAnim(poke, 'Paralysis cured', 'good', animDelay);
actions += "" + poke.getName() + " was cured of paralysis.";
break;
case 'frz':
self.resultAnim(poke, 'Thawed', 'good', animDelay);
actions += "" + poke.getName() + " thawed out!";
break;
default:
poke.removeVolatile('confusion');
self.resultAnim(poke, 'Cured', 'good', animDelay);
actions += "" + poke.getName() + "'s status cleared!";
}
break;
case '-cureteam':
var poke = this.getPokemon(args[1]);
for (var k = 0; k < poke.side.pokemon.length; k++) {
poke.side.pokemon[k].status = '';
}
self.resultAnim(poke, 'Team Cured', 'good', animDelay);
var effect = Tools.getEffect(kwargs.from);
switch (effect.id) {
case 'aromatherapy':
actions += 'A soothing aroma wafted through the area!';
break;
case 'healbell':
actions += 'A bell chimed!';
break;
default:
actions += "" + poke.getName() + "'s team was cured!";
break;
}
break;
case '-item':
var poke = this.getPokemon(args[1]);
var item = Tools.getItem(args[2]);
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
poke.item = item.name;
poke.removeVolatile('airballoon');
if (item.id === 'airballoon') poke.addVolatile('airballoon');
if (effect.id) switch (effect.id) {
case 'recycle':
case 'pickup':
actions += '' + poke.getName() + ' found one ' + item.name + '!';
self.resultAnim(poke, item.name, 'neutral', animDelay);
break;
case 'frisk':
actions += "" + ofpoke.getName() + " frisked its target and found one " + item.name + "!";
break;
case 'thief':
case 'covet':
actions += '' + poke.getName() + ' stole ' + ofpoke.getLowerName() + "'s " + item.name + "!";
self.resultAnim(poke, item.name, 'neutral', animDelay);
self.resultAnim(ofpoke, 'Item Stolen', 'bad', animDelay);
break;
case 'harvest':
actions += '' + poke.getName() + ' harvested one ' + item.name + '!';
self.resultAnim(poke, item.name, 'neutral', animDelay);
break;
case 'bestow':
actions += '' + poke.getName() + ' received ' + item.name + ' from ' + ofpoke.getLowerName() + '!';
self.resultAnim(poke, item.name, 'neutral', animDelay);
break;
default:
actions += '' + poke.getName() + ' obtained one ' + item.name + '.';
self.resultAnim(poke, item.name, 'neutral', animDelay);
break;
} else switch (item.id) {
case 'airballoon':
self.resultAnim(poke, 'Balloon', 'good', animDelay);
actions += "" + poke.getName() + " floats in the air with its Air Balloon!";
break;
default:
actions += "" + poke.getName() + " has " + item.name + "!";
break;
}
break;
case '-enditem':
var poke = this.getPokemon(args[1]);
var item = Tools.getItem(args[2]);
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
poke.item = '';
poke.removeVolatile('airballoon');
if (kwargs.silent) {
// do nothing
} else if (kwargs.eat) {
actions += '' + poke.getName() + ' ate its ' + item.name + '!';
self.lastmove = item.id;
} else if (kwargs.weaken) {
actions += 'The ' + item.name + ' weakened the damage to '+poke.getLowerName();
self.lastmove = item.id;
} else if (effect.id) switch (effect.id) {
case 'fling':
actions += "" + poke.getName() + ' flung its ' + item.name + '!';
break;
case 'knockoff':
actions += '' + ofpoke.getName() + ' knocked off ' + poke.getLowerName() + '\'s ' + item.name + '!';
self.resultAnim(poke, 'Item knocked off', 'neutral', animDelay);
break;
case 'stealeat':
actions += '' + ofpoke.getName() + ' stole and ate its target\'s ' + item.name + '!';
break;
case 'gem':
actions += 'The ' + item.name + ' strengthened ' + Tools.getMove(kwargs.move).name + '\'s power!';
break;
case 'incinerate':
actions += "" + poke.getName() + "'s " + item.name + " was burnt up!";
break;
default:
actions += "" + poke.getName() + ' lost its ' + item.name + '!';
break;
} else switch (item.id) {
case 'airballoon':
poke.removeVolatile('airballoon');
self.resultAnim(poke, 'Balloon popped', 'neutral', animDelay);
actions += "" + poke.getName() + "'s Air Balloon popped!";
break;
case 'focussash':
self.resultAnim(poke, 'Sash', 'neutral', animDelay);
actions += "" + poke.getName() + ' hung on using its Focus Sash!';
break;
case 'focusband':
self.resultAnim(poke, 'Focus Band', 'neutral', animDelay);
actions += "" + poke.getName() + ' hung on using its Focus Band!';
break;
case 'mentalherb':
poke.removeVolatile('taunt');
poke.removeVolatile('encore');
poke.removeVolatile('torment');
self.resultAnim(poke, 'Cured', 'good', animDelay);
actions += "" + poke.getName() + " used its " + item.name + " to come back to its senses!";
break;
case 'whiteherb':
actions += "" + poke.getName() + " restored its status using its White Herb!";
break;
case 'ejectbutton':
actions += "" + poke.getName() + " is switched out with the Eject Button!";
break;
case 'redcard':
actions += "" + poke.getName() + " held up its Red Card against " + ofpoke.getLowerName() + "!";
break;
default:
actions += "" + poke.getName() + "'s " + item.name + " activated!";
break;
}
break;
case '-ability':
var poke = this.getPokemon(args[1]);
var ability = Tools.getAbility(args[2]);
var effect = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
poke.ability = ability.name;
if (kwargs.silent) {
// do nothing
} else if (effect.id) switch (effect.id) {
case 'trace':
actions += '' + poke.getName() + ' traced ' + ofpoke.getLowerName() + '\'s ' + ability.name + '!';
break;
case 'roleplay':
actions += '' + poke.getName() + ' copied ' + ofpoke.getLowerName() + '\'s ' + ability.name + '!';
break;
case 'mummy':
actions += "" + poke.getName() + "'s Ability became Mummy!";
break;
default:
actions += "" + poke.getName() + " acquired " + ability.name + "!";
break;
} else switch (ability.id) {
case 'pressure':
actions += "" + poke.getName() + " is exerting its pressure!";
break;
case 'moldbreaker':
actions += "" + poke.getName() + " breaks the mold!";
break;
case 'turboblaze':
actions += "" + poke.getName() + " is radiating a blazing aura!";
break;
case 'teravolt':
actions += "" + poke.getName() + " is radiating a bursting aura!";
break;
case 'intimidate':
actions += '' + poke.getName() + ' intimidates ' + ofpoke.getLowerName() + '!';
break;
case 'unnerve':
actions += "" + poke.getName() + "'s Unnerve makes " + args[3] + "'s team too nervous to eat Berries!";
break;
default:
actions += "" + poke.getName() + " has " + ability.name + "!";
break;
}
break;
case '-endability':
var poke = this.getPokemon(args[1]);
var ability = Tools.getAbility(args[2]);
var effect = Tools.getEffect(kwargs.from);
poke.ability = '';
if (kwargs.silent) {
// do nothing
} else switch (effect.id) {
default:
actions += "" + poke.getName() + "\'s Ability was suppressed!";
break;
}
break;
case '-transform':
var poke = this.getPokemon(args[1]);
var tpoke = this.getPokemon(args[2]);
actions += '' + poke.getName() + ' transformed into ' + tpoke.species + '!';
poke.sprite.animTransform(tpoke);
poke.boosts = $.extend({}, tpoke.boosts);
poke.addVolatile('transform');
poke.addVolatile('formechange'); // the formechange volatile reminds us to revert the sprite change on switch-out
//poke.removeVolatile('typechange'); // does this happen??
poke.ability = tpoke.ability;
poke.volatiles.formechange[2] = (tpoke.volatiles.formechange ? tpoke.volatiles.formechange[2] : tpoke.species);
self.resultAnim(poke, 'Transformed', 'good', animDelay);
break;
case '-formechange':
var poke = this.getPokemon(args[1]);
var template = Tools.getTemplate(args[2]);
if (poke.sprite.sp.shiny) template.shiny = true;
poke.sprite.animTransform(template);
poke.addVolatile('formechange'); // the formechange volatile reminds us to revert the sprite change on switch-out
poke.volatiles.formechange[2] = template.species;
poke.side.updateStatbar();
break;
case '-start':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
var ofpoke = this.getPokemon(kwargs.of);
var fromeffect = Tools.getEffect(kwargs.from);
poke.addVolatile(effect.id);
switch (effect.id) {
case 'typechange':
poke.volatiles.typechange[2] = args[3];
if (fromeffect.id) {
if (fromeffect.id === 'reflecttype') {
actions += "" + poke.getName() + "'s type changed to match " + ofpoke.getLowerName() + "'s!";
} else {
actions += "" + poke.getName() + "'s " + fromeffect.name + " made it the " + args[3] + " type!";
}
} else {
actions += "" + poke.getName() + " transformed into the " + args[3] + " type!";
}
break;
case 'powertrick':
self.resultAnim(poke, 'Power Trick', 'neutral', animDelay);
actions += "" + poke.getName() + " switched its Attack and Defense!";
break;
case 'foresight':
case 'miracleeye':
self.resultAnim(poke, 'Identified', 'bad', animDelay);
actions += "" + poke.getName() + " was identified!";
break;
case 'telekinesis':
self.resultAnim(poke, 'Telekinesis', 'neutral', animDelay);
actions += "" + poke.getName() + " was hurled into the air!";
break;
case 'confusion':
if (kwargs.already) {
actions += "" + poke.getName() + " is already confused!";
} else {
self.resultAnim(poke, 'Confused', 'bad', animDelay);
actions += "" + poke.getName() + " became confused!";
}
break;
case 'leechseed':
poke.side.updateStatbar(poke);
actions += '' + poke.getName() + ' was seeded!';
break;
case 'healblock':
self.resultAnim(poke, 'Heal Block', 'bad', animDelay);
actions += "" + poke.getName() + " was prevented from healing!";
break;
case 'mudsport':
self.resultAnim(poke, 'Mud Sport', 'neutral', animDelay);
actions += "Electricity's power was weakened!";
break;
case 'watersport':
self.resultAnim(poke, 'Water Sport', 'neutral', animDelay);
actions += "Fire's power was weakened!";
break;
case 'yawn':
self.resultAnim(poke, 'Drowsy', 'slp', animDelay);
actions += "" + poke.getName() + ' grew drowsy!';
break;
case 'smackdown':
self.resultAnim(poke, 'Grounded', 'bad', animDelay);
actions += "" + poke.getName() + ' fell straight down!';
break;
case 'flashfire':
self.resultAnim(poke, 'Flash Fire', 'good', animDelay);
actions += 'The power of ' + poke.getLowerName() + '\'s Fire-type moves rose!';
break;
case 'taunt':
self.resultAnim(poke, 'Taunted', 'bad', animDelay);
actions += '' + poke.getName() + ' fell for the taunt!';
break;
case 'imprison':
self.resultAnim(poke, 'Imprisoning', 'good', animDelay);
actions += "" + poke.getName() + " sealed the opponent's move(s)!";
break;
case 'disable':
self.resultAnim(poke, 'Disabled', 'bad', animDelay);
actions += "" + poke.getName() + "'s " + args[3] + " was disabled!";
break;
case 'embargo':
self.resultAnim(poke, 'Embargo', 'bad', animDelay);
actions += "" + poke.getName() + " can't use items anymore!";
break;
case 'torment':
self.resultAnim(poke, 'Tormented', 'bad', animDelay);
actions += '' + poke.getName() + ' was subjected to torment!';
break;
case 'ingrain':
self.resultAnim(poke, 'Ingrained', 'good', animDelay);
actions += '' + poke.getName() + ' planted its roots!';
break;
case 'aquaring':
self.resultAnim(poke, 'Aqua Ring', 'good', animDelay);
actions += '' + poke.getName() + ' surrounded itself with a veil of water!';
break;
case 'stockpile1':
self.resultAnim(poke, 'Stockpile', 'good', animDelay);
actions += '' + poke.getName() + ' stockpiled 1!';
break;
case 'stockpile2':
poke.removeVolatile('stockpile1');
self.resultAnim(poke, 'Stockpile&times;2', 'good', animDelay);
actions += '' + poke.getName() + ' stockpiled 2!';
break;
case 'stockpile3':
poke.removeVolatile('stockpile2');
self.resultAnim(poke, 'Stockpile&times;3', 'good', animDelay);
actions += '' + poke.getName() + ' stockpiled 3!';
break;
case 'perish0':
poke.removeVolatile('perish1');
actions += '' + poke.getName() + "'s perish count fell to 0.";
break;
case 'perish1':
poke.removeVolatile('perish2');
self.resultAnim(poke, 'Perish next turn', 'bad', animDelay);
actions += '' + poke.getName() + "'s perish count fell to 1.";
break;
case 'perish2':
poke.removeVolatile('perish3');
self.resultAnim(poke, 'Perish in 2', 'bad', animDelay);
actions += '' + poke.getName() + "'s perish count fell to 2.";
break;
case 'perish3':
self.resultAnim(poke, 'Perish in 3', 'bad', animDelay);
actions += '' + poke.getName() + "'s perish count fell to 3.";
break;
case 'encore':
self.resultAnim(poke, 'Encored', 'bad', animDelay);
actions += '' + poke.getName() + ' received an encore!';
break;
case 'bide':
self.resultAnim(poke, 'Bide', 'good', animDelay);
actions += "" + poke.getName() + " is storing energy!";
break;
case 'slowstart':
self.resultAnim(poke, 'Slow Start', 'bad', animDelay);
actions += "" + poke.getName() + " can't get it going because of its Slow Start!";
break;
case 'attract':
self.resultAnim(poke, 'Attracted', 'bad', animDelay);
if (fromeffect.id) {
actions += "" + poke.getName() + " fell in love from the " + fromeffect.name + "!";
} else {
actions += "" + poke.getName() + " fell in love!";
}
break;
case 'autotomize':
self.resultAnim(poke, 'Lightened', 'good', animDelay);
actions += "" + poke.getName() + " became nimble!";
break;
case 'focusenergy':
self.resultAnim(poke, '+Crit rate', 'good', animDelay);
actions += "" + poke.getName() + " is getting pumped!";
break;
case 'curse':
self.resultAnim(poke, 'Cursed', 'bad', animDelay);
actions += "" + ofpoke.getName() + " cut its own HP and laid a curse on " + poke.getLowerName() + "!";
break;
case 'nightmare':
self.resultAnim(poke, 'Nightmare', 'bad', animDelay);
actions += "" + poke.getName() + " began having a nightmare!";
break;
case 'magnetrise':
self.resultAnim(poke, 'Magnet Rise', 'good', animDelay);
actions += "" + poke.getName() + " levitated with electromagnetism!";
break;
case 'smackdown':
self.resultAnim(poke, 'Smacked Down', 'bad', animDelay);
actions += "" + poke.getName() + " fell straight down!";
break;
case 'substitute':
if (kwargs.damage) {
self.resultAnim(poke, 'Damage', 'bad', animDelay);
actions += "The substitute took damage for "+poke.getLowerName()+"!";
} else if (kwargs.block) {
self.resultAnim(poke, 'Blocked', 'neutral', animDelay);
actions += 'But it failed!';
} else if (kwargs.already) {
actions += '' + poke.getName() + ' already has a substitute!';
} else {
poke.sprite.animSub();
actions += '' + poke.getName() + ' put in a substitute!';
}
break;
case 'uproar':
if (kwargs.upkeep) {
actions += "" + poke.getName() + " is making an uproar!";
} else {
actions += "" + poke.getName() + " caused an uproar!";
}
break;
case 'doomdesire':
actions += '' + poke.getName() + ' chose Doom Desire as its destiny!';
break;
case 'futuresight':
actions += '' + poke.getName() + ' foresaw an attack!';
break;
case 'mimic':
actions += '' + poke.getName() + ' learned ' + args[3] + '!';
break;
default:
actions += "" + poke.getName() + "'s " + effect.name + " started!";
}
break;
case '-end':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
var fromeffect = Tools.getEffect(kwargs.from);
poke.removeVolatile(effect.id);
switch (effect.id) {
case 'powertrick':
self.resultAnim(poke, 'Power Trick', 'neutral', animDelay);
actions += "" + poke.getName() + " switched its Attack and Defense!";
break;
case 'telekinesis':
self.resultAnim(poke, 'Telekinesis&nbsp;ended', 'neutral', animDelay);
actions += "" + poke.getName() + " was freed from the telekinesis!";
break;
case 'confusion':
self.resultAnim(poke, 'Confusion&nbsp;ended', 'good', animDelay);
if (!kwargs.silent) {
if (poke.side.n === 0) actions += "" + poke.getName() + " snapped out of its confusion.";
else actions += "" + poke.getName() + " snapped out of confusion!";
}
break;
case 'leechseed':
if (fromeffect.id === 'rapidspin') {
self.resultAnim(poke, 'De-seeded', 'good', animDelay);
actions += "" + poke.getName() + " was freed from Leech Seed!";
}
break;
case 'healblock':
self.resultAnim(poke, 'Heal Block ended', 'good', animDelay);
actions += "" + poke.getName() + "'s Heal Block wore off!";
break;
case 'taunt':
self.resultAnim(poke, 'Taunt&nbsp;ended', 'good', animDelay);
actions += '' + poke.getName() + "'s taunt wore off!";
break;
case 'disable':
self.resultAnim(poke, 'Disable&nbsp;ended', 'good', animDelay);
actions += '' + poke.getName() + " is no longer disabled!";
break;
case 'embargo':
self.resultAnim(poke, 'Embargo ended', 'good', animDelay);
actions += "" + poke.getName() + " can use items again!";
break;
case 'torment':
self.resultAnim(poke, 'Torment&nbsp;ended', 'good', animDelay);
actions += '' + poke.getName() + "'s torment wore off!";
break;
case 'encore':
self.resultAnim(poke, 'Encore&nbsp;ended', 'good', animDelay);
actions += '' + poke.getName() + "'s encore ended!";
break;
case 'bide':
actions += "" + poke.getName() + " unleashed energy!";
break;
case 'magnetrise':
if (poke.side.n === 0) actions += "" + poke.getName() + "'s electromagnetism wore off!";
else actions += "The electromagnetism of "+poke.getLowerName()+" wore off!";
break;
case 'perishsong':
poke.removeVolatile('perish3');
break;
case 'substitute':
poke.sprite.animSubFade();
self.resultAnim(poke, 'Faded', 'bad', animDelay);
actions += '' + poke.getName() + "'s substitute faded!";
break;
case 'uproar':
actions += "" + poke.getName() + " calmed down.";
break;
default:
if (effect.effectType === 'Move') {
actions += '' + poke.getName() + " took the " + effect.name + " attack!";
} else {
actions += "" + poke.getName() + "'s " + effect.name + " ended!";
}
}
break;
case '-singleturn':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
var ofpoke = this.getPokemon(kwargs.of);
var fromeffect = Tools.getEffect(kwargs.from);
poke.addTurnstatus(effect.id);
switch (effect.id) {
case 'roost':
self.resultAnim(poke, 'Landed', 'neutral', animDelay);
//actions += '' + poke.getName() + ' landed on the ground!';
break;
case 'quickguard':
self.resultAnim(poke, 'Quick Guard', 'good', animDelay);
actions += "Quick Guard protected " + poke.side.getLowerTeamName() + "!";
break;
case 'wideguard':
self.resultAnim(poke, 'Wide Guard', 'good', animDelay);
actions += "Wide Guard protected " + poke.side.getLowerTeamName() + "!";
break;
case 'protect':
self.resultAnim(poke, 'Protected', 'good', animDelay);
actions += '' + poke.getName() + ' protected itself!';
break;
case 'endure':
self.resultAnim(poke, 'Enduring', 'good', animDelay);
actions += '' + poke.getName() + ' braced itself!';
break;
case 'helpinghand':
self.resultAnim(poke, 'Helping Hand', 'good', animDelay);
actions += '' + ofpoke.getName() + " is ready to help " + poke.getLowerName() + "!";
break;
case 'focuspunch':
self.resultAnim(poke, 'Focusing', 'neutral', animDelay);
actions += '' + poke.getName() + ' is tightening its focus!';
break;
case 'snatch':
actions += '' + poke.getName() + ' waits for a target to make a move!';
break;
case 'magiccoat':
actions += '' + poke.getName() + ' shrouded itself with Magic Coat!';
break;
}
break;
case '-singlemove':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
var ofpoke = this.getPokemon(kwargs.of);
var fromeffect = Tools.getEffect(kwargs.from);
poke.addMovestatus(effect.id);
switch (effect.id) {
case 'grudge':
actions += '' + poke.getName() + ' wants its target to bear a grudge!';
break;
case 'destinybond':
actions += '' + poke.getName() + ' is trying to take its foe down with it!';
break;
}
break;
case '-activate':
var poke = this.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
var ofpoke = this.getPokemon(kwargs.of);
switch (effect.id) {
case 'calm':
actions += '' + poke.getName() + ' calmed down.';
break;
case 'confusion':
actions += "" + poke.getName() + " is confused!";
break;
case 'destinybond':
actions += '' + poke.getName() + ' took its attacker down with it!';
break;
case 'snatch':
actions += "" + poke.getName() + " snatched " + ofpoke.getLowerName() + "'s move!";
break;
case 'grudge':
actions += "" + poke.getName() + "'s " + args[3] + " lost all its PP due to the grudge!";
break;
case 'quickguard':
poke.addTurnstatus('quickguard');
self.resultAnim(poke, 'Quick Guard', 'good', animDelay);
actions += "Quick Guard protected " + poke.getLowerName() + "!";
break;
case 'wideguard':
poke.addTurnstatus('wideguard');
self.resultAnim(poke, 'Wide Guard', 'good', animDelay);
actions += "Wide Guard protected " + poke.getLowerName() + "!";
break;
case 'protect':
poke.addTurnstatus('protect');
self.resultAnim(poke, 'Protected', 'good', animDelay);
actions += '' + poke.getName() + ' protected itself!';
break;
case 'substitute':
if (kwargs.damage) {
self.resultAnim(poke, 'Damage', 'bad', animDelay);
actions += 'The substitute took damage for ' + poke.getLowerName() + '!';
} else if (kwargs.block) {
self.resultAnim(poke, 'Blocked', 'neutral', animDelay);
actions += '' + poke.getName() + "'s Substitute blocked " + Tools.getMove(kwargs.block || args[3]).name + '!';
}
break;
case 'skillswap':
actions += '' + poke.getName() + ' swapped Abilities with its target!';
break;
case 'attract':
actions += '' + poke.getName() + ' is in love with ' + ofpoke.getLowerName() + '!';
break;
case 'bide':
actions += "" + poke.getName() + " is storing energy!";
break;
case 'mist':
actions += "" + poke.getName() + " is protected by the mist!";
break;
// move activations
case 'trick':
case 'switcheroo':
actions += '' + poke.getName() + ' switched items with its target!';
break;
case 'brickbreak':
actions += poke.getName() + " shattered " + ofpoke.getTeamName() + " protections!";
ofpoke.removeSideCondition('Reflect');
ofpoke.removeSideCondition('LightScreen');
break;
case 'pursuit':
actions += "" + poke.getName() + " is being sent back!";
break;
case 'feint':
actions += "" + poke.getName() + " fell for the feint!";
break;
case 'spite':
actions += "It reduced the PP of " + poke.getLowerName() + "'s " + Tools.getMove(args[3]).name + " by " + args[4] + "!";
break;
case 'gravity':
actions += "" + poke.getName() + " couldn't stay airborne because of gravity!";
break;
case 'magnitude':
actions += "Magnitude " + args[3] + "!";
break;
case 'sketch':
actions += "" + poke.getName() + " sketched " + args[3] + "!";
break;
case 'skillswap':
actions += "" + poke.getName() + " swapped Abilities with its target!";
break;
case 'charge':
actions += "" + poke.getName() + " began charging power!";
break;
case 'struggle':
actions += "" + poke.getName() + " has no moves left!";
break;
case 'bind':
actions += '' + poke.getName() + ' was squeezed by ' + ofpoke.getLowerName() + '!';
break;
case 'wrap':
actions += '' + poke.getName() + ' was wrapped by ' + ofpoke.getLowerName() + '!';
break;
case 'clamp':
actions += '' + ofpoke.getName() + ' clamped ' + poke.getLowerName() + '!';
break;
case 'whirlpool':
actions += '' + poke.getName() + ' became trapped in the vortex!';
break;
case 'firespin':
actions += '' + poke.getName() + ' became trapped in the fiery vortex!';
break;
case 'magmastorm':
actions += '' + poke.getName() + ' became trapped by swirling magma!';
break;
case 'sandtomb':
actions += '' + poke.getName() + ' became trapped by Sand Tomb!';
break;
case 'afteryou':
actions += '' + poke.getName() + ' took the kind offer!';
break;
case 'quash':
actions += "" + poke.getName() + "'s move was postponed!";
break;
case 'powersplit':
actions += '' + poke.getName() + ' shared its power with the target!';
break;
case 'guardsplit':
actions += '' + poke.getName() + ' shared its guard with the target!';
break;
case 'ingrain':
actions += '' + poke.getName() + ' anchored itself with its roots!';
break;
// ability activations
case 'sturdy':
actions += '' + poke.getName() + ' held on thanks to Sturdy!';
break;
case 'magicbounce':
case 'magiccoat':
case 'rebound':
self.resultAnim(poke, 'Magic Coat', 'good', animDelay);
if (effect.id === 'magiccoat') {
poke.addTurnstatus('magiccoat');
}
actions += "" + ofpoke.getName() + "'s " + args[3] + " was bounced back by " + effect.name + "!";
Tools.getMove(args[3]).anim(self, [poke.sprite, ofpoke.sprite]);
break;
case 'wonderguard':
self.resultAnim(poke, 'Immune', 'neutral', animDelay);
actions += '' + poke.getName() + '\'s Wonder Guard evades the attack!';
break;
case 'speedboost':
actions += "" + poke.getName() + "'s' Speed Boost increases its speed!";
break;
case 'forewarn':
actions += "" + poke.getName() + "'s Forewarn alerted it to " + args[3] + "!";
break;
case 'anticipation':
actions += "" + poke.getName() + " shuddered!";
break;
case 'telepathy':
actions += "" + poke.getName() + " avoids attacks by its ally Pok&#xE9;mon!";
break;
case 'suctioncups':
actions += '' + poke.getName() + ' anchors itself!';
break;
// item activations
case 'custapberry':
case 'quickclaw':
//actions += ''+poke.getName()+' is already preparing its next move!';
actions += '' + poke.getName() + '\'s ' + effect.name + ' let it move first!';
break;
case 'leppaberry':
actions += '' + poke.getName() + " restored " + args[3] + "'s PP using its Leppa Berry!";
break;
default:
actions += "" + poke.getName() + "'s " + effect.name + " activated!";
}
break;
case '-sidestart':
var side = this.getSide(args[1]);
var effect = Tools.getEffect(args[2]);
side.addSideCondition(effect.name);
switch (effect.id) {
case 'stealthrock':
actions += "Pointed stones float in the air around " + side.getLowerTeamName() + "!";
break;
case 'spikes':
actions += "Spikes were scattered all around the feet of " + side.getLowerTeamName() + "!";
break;
case 'toxicspikes':
actions += "Poison spikes were scattered all around the feet of " + side.getLowerTeamName() + "!";
break;
case 'tailwind':
actions += "The tailwind blew from behind " + side.getLowerTeamName() + "!";
break;
case 'reflect':
actions += "Reflect raised " + side.getLowerTeamName() + "'s Defense!";
break;
case 'lightscreen':
actions += "Light Screen raised " + side.getLowerTeamName() + "'s Special Defense!";
break;
case 'safeguard':
actions += "" + side.getTeamName() + " became cloaked in a mystical veil!";
break;
case 'mist':
actions += "" + side.getTeamName() + " became shrouded in mist!";
break;
case 'luckychant':
actions += 'The Lucky Chant shielded ' + side.getLowerTeamName() + ' from critical hits!';
break;
case 'firepledge':
actions += "A rainbow appeared in the sky on " + side.getLowerTeamName() + "'s side!";
break;
case 'waterpledge':
actions += "A swamp enveloped " + side.getLowerTeamName() + "!";
break;
case 'grasspledge':
actions += "A sea of fire enveloped " + side.getLowerTeamName() + "!";
break;
default:
actions += "" + effect.name + " started!";
break;
}
break;
case '-sideend':
var side = this.getSide(args[1]);
var effect = Tools.getEffect(args[2]);
var from = Tools.getEffect(kwargs.from);
var ofpoke = this.getPokemon(kwargs.of);
side.removeSideCondition(effect.name);
switch (effect.id) {
case 'stealthrock':
actions += "The pointed stones disappeared from around " + side.getLowerTeamName() + "!";
break;
case 'spikes':
actions += "The spikes disappeared from around " + side.getLowerTeamName() + "'s feet!";
break;
case 'toxicspikes':
actions += "The poison spikes disappeared from around " + side.getLowerTeamName() + "'s feet!";
break;
case 'tailwind':
actions += "" + side.getTeamName() + "'s tailwind petered out!";
break;
case 'reflect':
actions += "" + side.getTeamName() + "'s Reflect wore off!";
break;
case 'lightscreen':
actions += "" + side.getTeamName() + "'s Light Screen wore off!";
break;
case 'safeguard':
actions += "" + side.getTeamName() + " is no longer protected by Safeguard!";
break;
case 'mist':
actions += "" + side.getTeamName() + " is no longer protected by mist!";
break;
case 'luckychant':
actions += "" + side.getTeamName() + "'s Lucky Chant wore off!";
break;
case 'firepledge':
actions += "The rainbow on " + side.getLowerTeamName() + "'s side disappeared!";
break;
case 'waterpledge':
actions += "The swamp around " + side.getLowerTeamName() + " disappeared!";
break;
case 'grasspledge':
actions += "The sea of fire around " + side.getLowerTeamName() + " disappeared!";
break;
default:
actions += "" + effect.name + " ended!";
break;
}
break;
case '-weather':
var effect = Tools.getEffect(args[1]);
var poke = this.getPokemon(kwargs.of);
self.changeWeather(effect.name, poke, kwargs.upkeep);
break;
case '-fieldstart':
var effect = Tools.getEffect(args[1]);
var poke = this.getPokemon(kwargs.of);
self.addPseudoWeather(effect.name, poke);
switch (effect.id) {
case 'trickroom':
actions += "" + poke.getName() + ' twisted the dimensions!';
break;
case 'wonderroom':
actions += "It created a bizarre area in which the Defense and Sp. Def stats are swapped!";
break;
case 'magicroom':
actions += "It created a bizarre area in which Pok&#xE9;mon's held items lose their effects!";
break;
case 'gravity':
actions += "Gravity intensified!";
break;
}
break;
case '-fieldend':
var effect = Tools.getEffect(args[1]);
var poke = this.getPokemon(kwargs.of);
self.removePseudoWeather(effect.name, poke);
switch (effect.id) {
case 'trickroom':
actions += 'The twisted dimensions returned to normal!';
break;
case 'wonderroom':
actions += 'Wonder Room wore off, and the Defense and Sp. Def stats returned to normal!';
break;
case 'magicroom':
actions += "Magic Room wore off, and the held items' effects returned to normal!";
break;
case 'gravity':
actions += 'Gravity returned to normal!';
break;
}
break;
case '-fieldactivate':
var effect = Tools.getEffect(args[1]);
switch (effect.id) {
case 'perishsong':
actions += 'All Pok&#xE9;mon hearing the song will faint in three turns!';
if (self.mySide.active[0]) self.mySide.active[0].addVolatile('perish3');
if (self.yourSide.active[0]) self.yourSide.active[0].addVolatile('perish3');
self.mySide.updateStatbar();
self.yourSide.updateStatbar();
break;
case 'payday':
actions += 'Coins were scattered everywhere!';
break;
default:
actions += ''+effect.name+' hit!';
break;
}
break;
case '-message':
actions += self.sanitize(args[1]);
break;
case '-anim':
var poke = self.getPokemon(args[1]);
var move = Tools.getMove(args[2]);
if (self.checkActive(poke)) return;
poke2 = self.getPokemon(args[3]);
poke.sprite.beforeMove();
kwargs.silent = true;
self.useMove(poke, move, poke2, kwargs);
poke.sprite.afterMove();
break;
case '-hint':
hiddenactions += '('+args[1]+')';
break;
default:
self.logConsole('Unknown minor: ' + args[0]);
break;
}
}
if (actions) {
self.message('<small>' + actions + '</small>', hiddenactions ? '<small>' + hiddenactions + '</small>' : '');
} else if (hiddenactions) {
self.message('', '<small>' + hiddenactions + '</small>');
}
}
/* this.parseSpriteData = function (name) {
var siden = 0,
foe = false;
while (true) {
if (name.substr(0, 6) === 'foeof-') {
foe = true;
name = name.substr(6);
} else if (name.substr(0, 9) === 'switched-') name = name.substr(9);
else if (name.substr(0, 9) === 'existing-') name = name.substr(9);
else if (name.substr(0, 4) === 'foe-') {
siden = self.p2.n;
name = name.substr(4);
} else if (name.substr(0, 5) === 'ally-') {
siden = self.p1.n;
name = name.substr(5);
} else break;
}
if (name.substr(name.length - 1) === ')') {
var parenIndex = name.lastIndexOf('(');
if (parenIndex > 0) {
var species = name.substr(parenIndex + 1);
name = species.substr(0, species.length - 1);
}
}
if (foe) siden = (siden ? 0 : 1);
var data = Tools.getTemplate(name);
return data.spriteData[siden];
} */
this.parseDetails = function (name, pokemonid, details, output) {
if (!output) output = {};
output.details = details;
output.name = name;
output.species = name;
output.level = 100;
output.shiny = false;
output.gender = '';
output.ident = (name?pokemonid:'');
output.searchid = (name?(pokemonid + '|' + details):'');
var splitDetails = details.split(', ');
if (splitDetails[splitDetails.length-1] === 'shiny')
{
output.shiny = true;
splitDetails.pop();
}
if (splitDetails[splitDetails.length-1] === 'M' || splitDetails[splitDetails.length-1] === 'F')
{
output.gender = splitDetails[splitDetails.length-1];
splitDetails.pop();
}
if (splitDetails[1])
{
output.level = parseInt(splitDetails[1].substr(1)) || 100;
}
if (splitDetails[0])
{
output.species = splitDetails[0];
}
return output;
};
this.getPokemon = function (pokemonid, details) {
var siden = -1;
var name = pokemonid;
var isNew = false; // if yes, don't match any pokemon that already exists (for Team Preview)
var isOld = false; // if yes, match only pokemon that have been revealed, and can match fainted pokemon (now default)
var isOther = false; // if yes, don't match an active pokemon (for switching)
//var position = 0; // todo: use for position in doubles/triples
var getfoe = false;
var slot; // if there is an explicit slot for this pokemon
var slotChart = {a:0,b:1,c:2,d:3,e:4,f:5};
if (typeof pokemonid === 'undefined' || name === '??') return null;
if (name.substr(0, 5) === 'foe: ') {
name = name.substr(5);
pokemonid = name;
getfoe = true;
}
if (name.substr(0, 5) === 'new: ') {
name = name.substr(5);
pokemonid = name;
isNew = true;
isOther = true;
}
if (name.substr(0, 7) === 'other: ') {
name = name.substr(7);
pokemonid = name;
isOther = true;
}
if (name.substr(0, 5) === 'old: ') {
name = name.substr(5);
pokemonid = name;
isOld = true;
}
if (name.substr(0, 4) === 'p2: ' || name === 'p2') {
siden = self.p2.n;
name = name.substr(4);
species = name;
} else if (name.substr(0, 4) === 'p1: ' || name === 'p1') {
siden = self.p1.n;
name = name.substr(4);
species = name;
} else if (name.substr(0, 2) === 'p2' && name.substr(3, 2) === ': ') {
slot = slotChart[name.substr(2,1)];
siden = self.p2.n;
name = name.substr(5);
pokemonid = 'p2: '+name;
species = name;
} else if (name.substr(0, 2) === 'p1' && name.substr(3, 2) === ': ') {
slot = slotChart[name.substr(2,1)];
siden = self.p1.n;
name = name.substr(5);
pokemonid = 'p1: '+name;
species = name;
}
if (!slot) slot = 0;
if (!details) {
if (siden < 0) return null;
if (self.sides[siden].active[slot]) return self.sides[siden].active[slot];
}
var species = name;
var gender = '';
var level = 100;
var shiny = false;
var searchid = '';
if (details) searchid = pokemonid+'|'+details;
var bestMatchName = null;
if (siden !== self.p2.n && !isNew) {
if (self.p1.active[slot] && self.p1.active[slot].searchid === searchid && !isOther) {
self.p1.active[slot].slot = slot;
return self.p1.active[slot];
}
for (var i = 0; i < self.p1.pokemon.length; i++) {
var pokemon = self.p1.pokemon[i];
if (pokemon.fainted && (isNew || isOther)) continue;
if (isOther) {
if (self.p1.active.indexOf(pokemon) >= 0) continue;
if (pokemon == self.p1.lastPokemon && !self.p1.active[slot]) continue;
}
if (pokemon.searchid === searchid || (!pokemon.searchid && pokemon.checkDetails(details)) || (!searchid && pokemon.ident === pokemonid)) {
if (!pokemon.searchid)
{
pokemon.name = name;
pokemon.searchid = searchid;
pokemon.ident = pokemonid;
if (pokemon.needsReplace) {
pokemon = self.p1.newPokemon(self.parseDetails(name, pokemonid, details), i);
}
}
pokemon.slot = slot;
return pokemon;
}
}
}
if (siden !== self.p1.n && !isNew) {
if (self.p2.active[slot] && self.p2.active[slot].searchid === searchid && !isOther) {
self.p2.active[slot].slot = slot;
return self.p2.active[slot];
}
for (var i = 0; i < self.p2.pokemon.length; i++) {
var pokemon = self.p2.pokemon[i];
if (pokemon.fainted && (isNew || isOther)) continue;
if (isOther) {
if (self.p2.active.indexOf(pokemon) >= 0) continue;
if (pokemon == self.p2.lastPokemon && !self.p2.active[slot]) continue;
}
if (pokemon.searchid === searchid || (!pokemon.searchid && pokemon.checkDetails(details)) || (!searchid && pokemon.ident === pokemonid)) {
if (!pokemon.searchid)
{
pokemon.name = name;
pokemon.searchid = searchid;
pokemon.ident = pokemonid;
if (pokemon.needsReplace) {
pokemon = self.p2.newPokemon(self.parseDetails(name, pokemonid, details), i);
}
}
pokemon.slot = slot;
return pokemon;
}
}
}
if (!isNew && !isOther && !details) {
return false;
}
if (siden < 0) siden = self.p1.n;
if (details) {
var splitDetails = details.split(', ');
if (splitDetails[splitDetails.length-1] === 'shiny') {
shiny = true;
splitDetails.pop();
}
if (splitDetails[splitDetails.length-1] === 'M' || splitDetails[splitDetails.length-1] === 'F') {
gender = splitDetails[splitDetails.length-1];
splitDetails.pop();
}
if (splitDetails[1]) {
level = parseInt(splitDetails[1].substr(1)) || 100;
}
if (splitDetails[0]) {
species = splitDetails[0];
}
}
var pokemon = self.sides[siden].newPokemon({
species: species,
details: details,
name: name,
ident: (name?pokemonid:''),
searchid: (name?(pokemonid + '|' + details):''),
level: level,
gender: gender,
shiny: shiny,
slot: slot
});
return pokemon;
}
this.getSide = function (sidename) {
if (sidename === 'p1' || sidename.substr(0,3)==='p1:') return self.p1;
if (sidename === 'p2' || sidename.substr(0,3)==='p2:') return self.p2;
if (self.mySide.id == sidename) return self.mySide;
if (self.yourSide.id == sidename) return self.yourSide;
if (self.mySide.name == sidename) return self.mySide;
if (self.yourSide.name == sidename) return self.yourSide;
return {
name: sidename,
id: sidename.replace(/ /g, '')
};
}
this.add = function (command) {
if (self.playbackState === 0) {
self.playbackState = 1;
self.activityQueue.push(command);
} else if (self.playbackState === 4) {
self.playbackState = 2;
self.paused = false;
self.activityQueue.push(command);
self.activityQueueActive = true;
self.soundStart();
self.nextActivity();
} else {
self.activityQueue.push(command);
}
}
this.instantAdd = function (command) {
self.run(command, true);
self.preemptActivityQueue.push(command);
self.add(command);
}
this.sanitize = function (str) {
return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
this.teamPreview = function (start) {
for (var k = 0; k < 2; k++) {
var teamText = '';
var text = '';
self.spriteElems[k].empty();
if (!start) {
self.sides[k].updateSprites();
continue;
}
for (var i = 0; i < self.sides[k].pokemon.length; i++) {
var pokemon = self.sides[k].pokemon[i];
var spriteData = Tools.getSpriteData(pokemon, k);
var y = 0;
var x = 0;
if (k) {
y = Math.floor(96-spriteData.h)/2 + 50 + 3 * (i + 6 - self.sides[k].pokemon.length);
x = Math.floor(96-spriteData.w)/2 + 180 + 50 * (i + 6 - self.sides[k].pokemon.length);
} else {
y = Math.floor(96-spriteData.h)/2 + 200 + 3 * i;
x = Math.floor(96-spriteData.w)/2 + 100 + 50 * i;
}
if (teamText) teamText += ' / ';
teamText += pokemon.species;
text += '<img src="' + spriteData.url + '" width="'+spriteData.w+'" height="'+spriteData.h+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px" />';
}
self.sides[k].totalPokemon = i;
self.sides[k].updateSidebar();
if (teamText) {
self.log('<div class="chat"><strong>' + self.sanitize(self.sides[k].name) + '\'s team:</strong> <em style="color:#445566;display:block;">' + self.sanitize(teamText) + '</em></div>');
}
self.spriteElems[k].html(text);
}
};
this.runMajor = function(args, kwargs, preempt) {
switch (args[0]) {
case 'start':
self.teamPreview(false);
self.mySide.active[0] = null;
self.yourSide.active[0] = null;
if (self.waitForResult()) return;
self.start();
break;
case 'turn':
if (self.endPrevAction()) return;
self.setTurn(args[1]);
break;
case 'tier':
if (!args[1]) args[1] = '';
for (var i in kwargs) args[1] += '['+i+'] '+kwargs[i];
self.log('<div style="padding:5px 0"><small>Format:</small> <br /><strong>' + self.sanitize(args[1]) + '</strong></div>');
break;
case 'gametype':
self.gameType = args[1];
if (args[1] === 'doubles') {
if (self.mySide.active.length < 2) self.mySide.active.push(null);
if (self.yourSide.active.length < 2) self.yourSide.active.push(null);
}
break;
case 'variation':
self.log('<div><small>Variation: <em>' + self.sanitize(args[1]) + '</em></small></div>');
break;
case 'rule':
var ruleArgs = args[1].split(': ');
self.log('<div><small><em>' + self.sanitize(ruleArgs[0]) + (ruleArgs[1]?':':'') + '</em> ' + self.sanitize(ruleArgs[1]||'') + '</div>');
break;
case 'rated':
self.rated = true;
self.log('<div class="rated"><strong>Rated battle</strong></div>');
break;
case 'chat':
case 'c':
name = args[1];
args.shift();
args.shift();
var message = args.join('|');
if (message.substr(0,2) === '//') {
self.log('<div class="chat"><strong style="' + hashColor(toUserid(self.getSide(name).name)) + '">' + self.sanitize(name) + ':</strong> <em>' + messageSanitize(message.substr(1)) + '</em></div>', preempt);
} else if (message.substr(0,4).toLowerCase() === '/me ') {
self.log('<div class="chat"><strong style="' + hashColor(toUserid(self.getSide(name).name)) + '">&bull;</strong> <em>' + self.sanitize(name) + ' <i>' + messageSanitize(message.substr(4)) + '</i></em></div>', preempt);
} else if (message.substr(0,14).toLowerCase() === '/data-pokemon ') {
self.log('<div class="chat"><ul class=\"utilichart\">'+Chart.pokemonRow(Tools.getTemplate(message.substr(14)),'',{})+'<li style=\"clear:both\"></li></ul></div>', preempt);
} else if (message.substr(0,11).toLowerCase() === '/data-item ') {
self.log('<div class="chat"><ul class=\"utilichart\">'+Chart.itemRow(Tools.getItem(message.substr(11)),'',{})+'<li style=\"clear:both\"></li></ul></div>', preempt);
} else if (message.substr(0,14).toLowerCase() === '/data-ability ') {
self.log('<div class="chat"><ul class=\"utilichart\">'+Chart.abilityRow(Tools.getAbility(message.substr(14)),'',{})+'<li style=\"clear:both\"></li></ul></div>', preempt);
} else if (message.substr(0,11).toLowerCase() === '/data-move ') {
self.log('<div class="chat"><ul class=\"utilichart\">'+Chart.moveRow(Tools.getMove(message.substr(11)),'',{})+'<li style=\"clear:both\"></li></ul></div>', preempt);
} else {
self.log('<div class="chat"><strong style="' + hashColor(toUserid(self.getSide(name).name)) + '">' + self.sanitize(name) + ':</strong> <em>' + messageSanitize(message) + '</em></div>', preempt);
}
break;
case 'chatmsg':
args.shift();
list = args.join('|');
self.log('<div class="chat">' + self.sanitize(list) + '</div>', preempt);
break;
case 'chatmsg-raw':
case 'raw':
args.shift();
list = args.join('|');
var m = /<div style="background-color:#6688AA;color:white;padding:2px 4px"><b>Register an account to protect your ladder rating!<\/b><br \/><button onclick="overlay\('register',{ifuserid:'[a-z0-9]*'}\);return false"><b>Register<\/b><\/button><\/div>/.exec(list);
if (m) {
// This is a temporary hack so that this keeps working for old servers.
// This check can be removed later.
self.log('<div class="chat">' + m[0] + '</div>');
} else {
// TODO: Sanitise for safe URIs only, after we bring in the safe URI list.
self.log('<div class="chat">' + Tools.htmlSanitize(list) + '</div>', preempt);
}
break;
case 'pm':
self.log('<div class="chat"><strong>' + sanitize(args[1]) + ':</strong> <span class="message-pm"><i style="cursor:pointer" onclick="selectTab(\'lobby\');rooms.lobby.popupOpen(\'' + args[2] + '\')">(Private to ' + sanitize(args[3]) + ')</i> ' + messageSanitize(args[4]) + '</span>');
break;
case 'askreg':
self.log('<div class="message-register-account"><b>Register an account to protect your ladder rating!</b><br /><button onclick="overlay(\'register\',{ifuserid:\''+args[1]+'\'});return false"><b>Register</b></button></div>');
break;
case 'inactive':
self.kickingInactive = true;
args.shift();
list = args.join('|');
self.log('<div class="chat" style="color:#992222">' + self.sanitize(list) + '</div>', preempt);
break;
case 'inactiveoff':
self.kickingInactive = false;
args.shift();
list = args.join('|');
self.log('<div class="chat" style="color:#992222">' + self.sanitize(list) + '</div>', preempt);
break;
case 'join':
case 'j':
case 'J':
self.log('<div class="chat"><small>' + self.sanitize(args[1]) + ' joined.</small></div>', preempt);
break;
case 'leave':
case 'l':
case 'L':
self.log('<div class="chat"><small>' + self.sanitize(args[1]) + ' left.</small></div>', preempt);
break;
case 'spectator':
case 'spectatorleave':
break;
case 'player':
self.getSide(args[1]).setName(args[2]);
self.getSide(args[1]).setSprite(parseInt(args[3]));
break;
case 'win':
self.winner(args[1]);
break;
case 'tie':
self.winner();
break;
case 'prematureend':
self.prematureEnd();
break;
case 'clearpoke':
self.p1.pokemon = [];
self.p2.pokemon = [];
for (var i=0; i<self.p1.active.length; i++) {
self.p1.active[i] = null;
self.p2.active[i] = null;
}
break;
case 'poke':
self.getPokemon('new: '+args[1], args[2]);
break;
case 'teampreview':
self.teamPreview(true);
self.teamPreviewCount = args[1];
break;
case 'switch':
case 'drag':
case 'replace':
if (self.waitForResult()) return;
var poke = self.getPokemon('other: '+args[1], args[2]);
var slot = poke.slot;
poke.healthParse(args[3]);
if (args[0] === 'switch') {
if (poke.side.active[slot])
{
poke.side.switchOut(poke.side.active[slot]);
if (self.waitForResult()) return;
}
poke.side.switchIn(poke);
} else if (args[0] === 'replace') {
poke.side.replace(poke);
} else {
poke.side.dragIn(poke);
}
break;
case 'faint':
if (self.waitForResult()) return;
var poke = self.getPokemon(args[1]);
poke.side.faint(poke);
break;
case 'move':
if (!kwargs.from && self.waitForResult()) return;
var poke = self.getPokemon(args[1]);
var move = Tools.getMove(args[2]);
if (self.checkActive(poke)) return;
poke2 = self.getPokemon(args[3]);
poke.sprite.beforeMove();
self.useMove(poke, move, poke2, kwargs);
poke.sprite.afterMove();
break;
case 'cant':
if (self.waitForResult()) return;
var poke = self.getPokemon(args[1]);
var effect = Tools.getEffect(args[2]);
var move = Tools.getMove(args[3]);
self.cantUseMove(poke, effect, move, kwargs);
break;
case 'message':
self.message(self.sanitize(args[1]));
break;
case 'done':
case '':
if (self.done || self.endPrevAction()) return;
break;
case 'error':
args.shift();
self.message('<strong>Error:</strong> ' + self.sanitize(args.join('|')));
self.message('Bug? Report it to <a href="http://www.smogon.com/forums/showthread.php?t=3453192">the replay viewer\'s Smogon thread</a>');
break;
case 'warning':
args.shift();
self.message('<strong>Warning:</strong> ' + self.sanitize(args.join('|')));
self.message('Bug? Report it to <a href="http://www.smogon.com/forums/showthread.php?t=3453192">the replay viewer\'s Smogon thread</a>');
self.activityWait(1000);
break;
case 'gen':
self.gen = parseInt(args[1]);
break;
case 'callback':
args.shift();
if (self.customCallback) self.customCallback(self, args[0], args, kwargs);
break;
case 'debug':
args.shift();
name = args.join(' ');
self.log('<div class="chat"><small style="color:#999">[DEBUG] ' + self.sanitize(name) + '.</small></div>', preempt);
break;
default:
self.logConsole('unknown command: ' + args[0]);
self.log('<div>Unknown command: ' + self.sanitize(args[0]) + '</div>');
break;
}
};
this.run = function (str, preempt) {
if (self.preemptActivityQueue.length && str === self.preemptActivityQueue[0]) {
self.preemptActivityQueue.shift();
self.preemptCatchup();
return;
}
str = $.trim(str);
if (str.substr(0,1) === '|') {
var args = ['done'], kwargs = {};
str = $.trim(str.substr(1));
if (str !== '') {
args = str.split('|');
for (var i=0,len=args.length; i<len; i++) args[i] = $.trim(args[i]);
}
while (args[args.length-1] && args[args.length-1].substr(0,1) === '[') {
var bracketPos = args[args.length-1].indexOf(']');
if (bracketPos <= 0) break;
var argstr = args.pop();
// default to '.' so it evaluates to boolean true
kwargs[argstr.substr(1,bracketPos-1)] = ($.trim(argstr.substr(bracketPos+1)) || '.');
}
// parse the next line if it's a minor: runMinor needs it parsed to determine when to merge minors
var nextLine = '', nextArgs = [''], nextKwargs = {};
nextLine = self.activityQueue[self.activityStep+1];
if (nextLine && nextLine.substr(0,2) === '|-') {
nextLine = $.trim(nextLine.substr(1));
nextArgs = nextLine.split('|');
while (nextArgs[nextArgs.length-1] && nextArgs[nextArgs.length-1].substr(0,1) === '[') {
var bracketPos = nextArgs[nextArgs.length-1].indexOf(']');
if (bracketPos <= 0) break;
var argstr = nextArgs.pop();
// default to '.' so it evaluates to boolean true
nextKwargs[argstr.substr(1,bracketPos-1)] = ($.trim(argstr.substr(bracketPos+1)) || '.');
}
}
if (self.debug) {
if (args[0].substr(0,1) === '-') {
self.runMinor(args, kwargs, preempt, nextArgs, nextKwargs);
} else {
self.runMajor(args, kwargs, preempt);
}
} else try {
if (args[0].substr(0,1) === '-') {
self.runMinor(args, kwargs, preempt, nextArgs, nextKwargs);
} else {
self.runMajor(args, kwargs, preempt);
}
} catch (e) {
self.log('<div class="chat">Error parsing: ' + self.sanitize(str) + '</div>', preempt);
if (e.stack) {
var stack = ''+e.stack;
stack = stack.split("\n").slice(0,2).join("\n");
self.log('<div class="chat" style="white-space:pre-wrap">' + self.sanitize(stack) + '</div>', preempt);
} else {
self.log('<div class="chat">Error: ' + self.sanitize(''+e) + '</div>', preempt);
}
}
} else {
self.log('<div class="chat">' + self.sanitize(str) + '</div>', preempt);
}
}
this.endPrevAction = function () {
if (self.minorQueue.length) {
self.runMinor();
self.activityStep--;
return true;
}
if (self.resultWaiting || self.messageActive) {
self.endAction();
self.activityStep--;
self.resultWaiting = false;
self.multiHitMove = null;
return true;
}
return false;
}
this.checkActive = function (poke) {
if (!poke.side.active[poke.slot]) {
// SOMEONE jumped in in the middle of a replay. <_<
poke.side.replace(poke);
}
return false;
}
this.waitForResult = function () {
if (self.endPrevAction()) return true;
self.resultWaiting = true;
return false;
}
this.doBeforeThis = function (act) {
if (act()) {
self.activityStep--;
return true;
}
return false;
}
this.doAfterThis = function (act) {
this.activityAfter = act;
}
// activity queue
this.animationDelay = 0;
this.activityStep = 0;
this.activityDelay = 0;
this.activityQueue = [];
this.preemptActivityQueue = [];
this.activityAfter = null;
this.activityAnimations = $();
this.activityQueueActive = false;
this.fastForward = false;
this.minorQueue = [];
this.resultWaiting = false;
this.multiHitMove = null;
this.queue1 = function () {
if (self.activeQueue === self.queue1) self.nextActivity();
};
this.queue2 = function () {
if (self.activeQueue === self.queue2) self.nextActivity();
};
this.swapQueues = function () {
if (self.activeQueue === self.queue1) self.activeQueue = self.queue2;
else self.activeQueue = self.queue2;
};
this.activeQueue = this.queue1;
this.pause = function () {
self.paused = true;
self.playbackState = 3;
if (self.resumeButton) {
self.frameElem.append('<div class="playbutton"><button>Resume</button></div>');
self.frameElem.find('div.playbutton button').click(self.resumeButton);
}
self.soundPause();
}
this.play = function () {
if (self.fastForward) {
self.paused = false;
self.playbackState = 5;
} else if (self.paused) {
self.paused = false;
if (self.playbackState === 1) {
self.soundStop();
}
self.playbackState = 2;
if (!self.done) {
self.soundStart();
}
self.nextActivity();
}
self.frameElem.find('div.playbutton').remove();
}
this.skipTurn = function () {
self.fastForwardTo(self.turn + 1);
};
this.fastForwardTo = function (time) {
self.playbackState = 5;
if (self.fastForward) return;
time = parseInt(time);
if (isNaN(time)) return;
if (self.activityStep >= self.activityQueue.length - 1 && time >= self.turn + 1 && !self.activityQueueActive) return;
if (self.done && time >= self.turn + 1) return;
self.messagebarElem.empty().css({
opacity: 0,
height: 0
});
if (time <= self.turn && time !== -1) {
var paused = self.paused;
self.reset();
self.activityQueueActive = true;
if (paused) self.pause();
else self.paused = false;
self.fastForward = time;
self.elem.append('<div class="seeking"><strong>seeking...</strong></div>');
$.fx.off = true;
self.swapQueues();
self.nextActivity();
return;
}
self.fxElem.empty();
self.fastForward = time;
self.elem.append('<div class="seeking"><strong>seeking...</strong></div>');
$.fx.off = true;
if (self.yourSide.active[0] && self.yourSide.active[0].sprite) {
self.yourSide.active[0].sprite.animReset();
}
if (self.mySide.active[0] && self.mySide.active[0].sprite) {
self.mySide.active[0].sprite.animReset();
}
self.swapQueues();
self.nextActivity();
};
this.fastForwardOff = function () {
self.fastForward = false;
self.elem.find('.seeking').remove();
$.fx.off = false;
self.playbackState = 2;
};
this.nextActivity = function () {
if (self.paused && !self.fastForward) {
return;
}
self.activityQueueActive = true;
self.fxElem.empty();
self.animationDelay = 0;
while (true) {
self.activityAnimations = $();
if (self.activityStep == self.activityQueue.length) {
self.activityQueueActive = false;
self.paused = true;
self.fastForwardOff();
if (self.done) {
self.soundStop();
}
self.playbackState = 4;
if (self.endCallback) self.endCallback(self);
return;
}
var ret;
if (self.activityAfter) {
ret = self.activityAfter();
self.activityAfter = null;
}
if (self.paused && !self.fastForward) return;
if (!ret) {
self.run(self.activityQueue[self.activityStep]);
self.activityStep++;
}
if (self.activityDelay) {
self.delayElem.delay(self.activityDelay);
self.activityWait(self.delayElem);
self.activityDelay = 0;
}
if (self.activityAnimations.length) break;
}
self.activityAnimations.promise().done(self.activeQueue);
}
this.activityWait = function (elem) {
if (typeof elem === 'number' && elem > self.activityDelay) {
self.activityDelay = elem;
return;
}
self.activityAnimations = self.activityAnimations.add(elem);
}
this.newBattle = function () {
self.reset();
self.activityQueue = [];
}
this.setQueue = function (queue) {
self.reset();
self.activityQueue = queue;
/* for (var i = 0; i < queue.length && i < 20; i++) {
if (queue[i].substr(0, 8) === 'pokemon ') {
var sp = self.parseSpriteData(queue[i].substr(8));
self.preloadAudio(sp.cryurl);
self.preloadImage(sp.url);
if (sp.url === '/sprites/bwani/meloetta.gif') {
self.preloadImage('/sprites/bwani/meloetta-pirouette.gif');
}
if (sp.url === '/sprites/bwani-back/meloetta.gif') {
self.preloadImage('/sprites/bwani-back/meloetta-pirouette.gif');
}
}
} */
self.playbackState = 1;
}
// callback
this.faintCallback = null;
this.switchCallback = null;
this.dragCallback = null;
this.turnCallback = null;
this.startCallback = null;
this.stagnateCallback = null;
this.endCallback = null;
this.customCallback = null;
// external
this.resumeButton = this.play;
this.preloadCache = {};
this.preloadDone = 0;
this.preloadNeeded = 0;
this.bgm = null;
this.mute = false;
this.preloadImage = function (url) {
if (noPreload) return;
var token = url.replace(/\.(gif|png)$/, '').replace(/\//g, '-');
if (self.preloadCache[token]) {
return;
}
self.preloadNeeded++;
self.preloadCache[token] = new Image();
self.preloadCache[token].onload = function () {
self.preloadDone++;
self.preloadCallback(self.preloadNeeded === self.preloadDone, self.preloadDone, self.preloadNeeded);
};
self.preloadCache[token].src = url;
};
this.preloadCallback = function () {};
this.preloadEffects = function () {
if (noPreload) return;
for (i in BattleEffects) {
if (BattleEffects[i].url) self.preloadImage(BattleEffects[i].url);
}
self.preloadImage('/fx/weather-raindance.jpg'); // rain is used often enough to precache
self.preloadImage('/sprites/bw/substitute.png');
self.preloadImage('/sprites/bw-back/substitute.png');
//self.preloadImage('/fx/bg.jpg');
};
this.preloadSounds = function () {
//self.preloadAudio('audio/bw-trainer-battle.mp3');
}
this.preloadAudio = function (url, autoplay) {
if (noPreload) return;
var token = url.replace(/\.(wav|mp3)$/, '').replace(/\//g, '-');
if (self.preloadCache[token]) {
return;
}
self.preloadNeeded++;
if ((sound = soundManager.getSoundById(token))) {
self.preloadCache[token] = sound;
sound.play();
self.preloadDone++;
self.preloadCallback(self.preloadNeeded === self.preloadDone, self.preloadDone, self.preloadNeeded);
} else {
self.preloadCache[token] = soundManager.createSound({
id: token,
url: url,
autoPlay: autoplay,
volume: 50,
onload: function () {
self.preloadDone++;
self.preloadCallback(self.preloadNeeded === self.preloadDone, self.preloadDone, self.preloadNeeded);
}
});
}
if (!self.preloadCache[token]) {
// error
return;
}
if (!autoplay) {
self.preloadCache[token].load();
}
};
this.preloadBgm = function (url, autoplay, loopstart, loopend) {
if (!url) {
var bgmNum = Math.floor(Math.random() * 7);
if (window.forceBgm) bgmNum = window.forceBgm;
switch (bgmNum) {
case -1:
self.preloadBgm('/audio/bw2-homika-dogars.mp3', true, 1661, 68131);
break;
case 0:
self.preloadBgm('/audio/hgss-kanto-trainer.mp3', true, 13003, 94656);
break;
case 1:
self.preloadBgm('/audio/bw-subway-trainer.mp3', true, 15503, 110984);
break;
case 2:
self.preloadBgm('/audio/bw-trainer.mp3', true, 14629, 110109);
break;
case 3:
self.preloadBgm('/audio/bw-rival.mp3', true, 19180, 57373);
break;
case 4:
self.preloadBgm('/audio/dpp-trainer.mp3', true, 13440, 96959);
break;
case 5:
self.preloadBgm('/audio/hgss-johto-trainer.mp3', true, 23731, 125086);
break;
case 6:
default:
self.preloadBgm('/audio/dpp-rival.mp3', true, 13888, 66352);
break;
}
return;
}
if (noPreload) return;
var token = url.replace(/\.(wav|mp3)$/, '').replace(/\//g, '-');
if (self.preloadCache[token]) {
if (autoplay) {
self.preloadCache[token].play();
}
return;
}
self.preloadNeeded++;
var sound;
if ((sound = soundManager.getSoundById(token))) {
self.preloadCache[token] = sound;
sound.play();
self.preloadDone++;
self.preloadCallback(self.preloadNeeded === self.preloadDone, self.preloadDone, self.preloadNeeded);
} else {
self.preloadCache[token] = soundManager.createSound({
id: token,
url: url,
autoPlay: autoplay,
volume: 50,
onload: function () {
self.preloadDone++;
self.preloadCallback(self.preloadNeeded === self.preloadDone, self.preloadDone, self.preloadNeeded);
}
});
}
if (!self.preloadCache[token]) {
// error
return;
}
self.bgm = self.preloadCache[token];
self.preloadCache[token].onposition(loopend, function () {
// loop music
self.preloadCache[token].setPosition(loopstart);
//$('#loopcount').html(''+(++self.loopcount));
});
if (!autoplay) {
self.preloadCache[token].load();
}
};
this.getToken = function (url) {
return url.replace(/\.(wav|mp3)$/, '').replace(/\//g, '-');
};
this.playAudio = function (url) {
if (self.mute) return;
var token = url.replace(/\.(wav|mp3)$/, '').replace(/\//g, '-');
if (!self.preloadCache[token]) {
self.preloadAudio(url, true);
} else {
self.preloadCache[token].play();
}
};
this.setMute = function (mute) {
self.mute = mute;
if (!mute) {
if (self.playbackState === 2 || self.playbackState === 5) {
self.soundStart();
}
if (self.playbackState === 4 && !self.done) {
self.soundStart();
}
} else {
self.soundPause();
}
};
self.soundState = 0;
self.bgm = null;
self.loopcount = 0;
// 0 = stopped
// 1 = playing
// 2 = paused
this.soundStart = function () {
if (self.mute) return;
if (self.soundState === 0) {
self.soundState = 1;
self.preloadBgm();
//self.playAudio('audio/bw-trainer-battle.mp3');
//self.bgm = self.preloadCache[self.getToken('audio/bw-trainer-battle.mp3')];
} else if (self.soundState === 2) {
self.soundState = 1;
if (self.bgm) self.bgm.resume();
}
};
this.soundStop = function () {
soundManager.stopAll();
self.soundState = 0;
};
this.soundPause = function () {
if (self.soundState === 1) {
if (self.bgm) self.bgm.pause();
self.soundState = 2;
}
};
this.messageDelay = 8;
this.preloadEffects();
self.init();
}
/*
self.lastmove = 'healing-wish';
Tools.getMove('HealingWish').residualAnim(self, [pokemon.sprite]);
pokemon.side.wisher = null;
*/