Make classes for dex data

Template, Item, Move, and Ability are now classes. This guarantees that
`getTemplate`, `getItem` etc return objects that implement their
interfaces (they didn't before).

As of their current implementation, they require trusted resource
files. The plan is, whenever we support custom resource files, to pass
all their strings through `sanitizeName`. This won't prevent servers
from causing the client to behave unexpectedly, but it should prevent
any actual vulnerabilities.

In addition, pokemon forme icon index tables have been moved to
`battle-dex-data.ts`.
This commit is contained in:
Guangcong Luo
2018-12-16 17:43:32 -06:00
parent 553cffa93e
commit e5dfba6797
3 changed files with 868 additions and 615 deletions

View File

@@ -152,7 +152,7 @@ const BattleStats = {
spc: 'Special',
};
const baseSpeciesChart = [
const BattleBaseSpeciesChart = [
'pikachu',
'pichu',
'unown',
@@ -209,52 +209,761 @@ const baseSpeciesChart = [
// others are hardcoded by ending with 'mega'
];
const BattlePokemonIconIndexes: {[id: string]: number} = {
egg: 816 + 1,
pikachubelle: 816 + 2,
pikachulibre: 816 + 3,
pikachuphd: 816 + 4,
pikachupopstar: 816 + 5,
pikachurockstar: 816 + 6,
pikachucosplay: 816 + 7,
// unown gap
castformrainy: 816 + 35,
castformsnowy: 816 + 36,
castformsunny: 816 + 37,
deoxysattack: 816 + 38,
deoxysdefense: 816 + 39,
deoxysspeed: 816 + 40,
burmysandy: 816 + 41,
burmytrash: 816 + 42,
wormadamsandy: 816 + 43,
wormadamtrash: 816 + 44,
cherrimsunshine: 816 + 45,
shelloseast: 816 + 46,
gastrodoneast: 816 + 47,
rotomfan: 816 + 48,
rotomfrost: 816 + 49,
rotomheat: 816 + 50,
rotommow: 816 + 51,
rotomwash: 816 + 52,
giratinaorigin: 816 + 53,
shayminsky: 816 + 54,
unfezantf: 816 + 55,
basculinbluestriped: 816 + 56,
darmanitanzen: 816 + 57,
deerlingautumn: 816 + 58,
deerlingsummer: 816 + 59,
deerlingwinter: 816 + 60,
sawsbuckautumn: 816 + 61,
sawsbucksummer: 816 + 62,
sawsbuckwinter: 816 + 63,
frillishf: 816 + 64,
jellicentf: 816 + 65,
tornadustherian: 816 + 66,
thundurustherian: 816 + 67,
landorustherian: 816 + 68,
kyuremblack: 816 + 69,
kyuremwhite: 816 + 70,
keldeoresolute: 816 + 71,
meloettapirouette: 816 + 72,
vivillonarchipelago: 816 + 73,
vivilloncontinental: 816 + 74,
vivillonelegant: 816 + 75,
vivillonfancy: 816 + 76,
vivillongarden: 816 + 77,
vivillonhighplains: 816 + 78,
vivillonicysnow: 816 + 79,
vivillonjungle: 816 + 80,
vivillonmarine: 816 + 81,
vivillonmodern: 816 + 82,
vivillonmonsoon: 816 + 83,
vivillonocean: 816 + 84,
vivillonpokeball: 816 + 85,
vivillonpolar: 816 + 86,
vivillonriver: 816 + 87,
vivillonsandstorm: 816 + 88,
vivillonsavanna: 816 + 89,
vivillonsun: 816 + 90,
vivillontundra: 816 + 91,
pyroarf: 816 + 92,
flabebeblue: 816 + 93,
flabebeorange: 816 + 94,
flabebewhite: 816 + 95,
flabebeyellow: 816 + 96,
floetteblue: 816 + 97,
floetteeternal: 816 + 98,
floetteorange: 816 + 99,
floettewhite: 816 + 100,
floetteyellow: 816 + 101,
florgesblue: 816 + 102,
florgesorange: 816 + 103,
florgeswhite: 816 + 104,
florgesyellow: 816 + 105,
furfroudandy: 816 + 106,
furfroudebutante: 816 + 107,
furfroudiamond: 816 + 108,
furfrouheart: 816 + 109,
furfroukabuki: 816 + 110,
furfroulareine: 816 + 111,
furfroumatron: 816 + 112,
furfroupharaoh: 816 + 113,
furfroustar: 816 + 114,
meowsticf: 816 + 115,
aegislashblade: 816 + 116,
hoopaunbound: 816 + 118,
rattataalola: 816 + 119,
raticatealola: 816 + 120,
raichualola: 816 + 121,
sandshrewalola: 816 + 122,
sandslashalola: 816 + 123,
vulpixalola: 816 + 124,
ninetalesalola: 816 + 125,
diglettalola: 816 + 126,
dugtrioalola: 816 + 127,
meowthalola: 816 + 128,
persianalola: 816 + 129,
geodudealola: 816 + 130,
graveleralola: 816 + 131,
golemalola: 816 + 132,
grimeralola: 816 + 133,
mukalola: 816 + 134,
exeggutoralola: 816 + 135,
marowakalola: 816 + 136,
greninjaash: 816 + 137,
zygarde10: 816 + 138,
zygardecomplete: 816 + 139,
oricoriopompom: 816 + 140,
oricoriopau: 816 + 141,
oricoriosensu: 816 + 142,
lycanrocmidnight: 816 + 143,
wishiwashischool: 816 + 144,
miniormeteor: 816 + 145,
miniororange: 816 + 146,
minioryellow: 816 + 147,
miniorgreen: 816 + 148,
miniorblue: 816 + 149,
miniorviolet: 816 + 150,
miniorindigo: 816 + 151,
magearnaoriginal: 816 + 152,
pikachuoriginal: 816 + 153,
pikachuhoenn: 816 + 154,
pikachusinnoh: 816 + 155,
pikachuunova: 816 + 156,
pikachukalos: 816 + 157,
pikachualola: 816 + 158,
pikachupartner: 816 + 159,
lycanrocdusk: 816 + 160,
necrozmaduskmane: 816 + 161,
necrozmadawnwings: 816 + 162,
necrozmaultra: 816 + 163,
pikachustarter: 816 + 164,
eeveestarter: 816 + 165,
gumshoostotem: 735,
raticatealolatotem: 816 + 120,
marowakalolatotem: 816 + 136,
araquanidtotem: 752,
lurantistotem: 754,
salazzletotem: 758,
vikavolttotem: 738,
togedemarutotem: 777,
mimikyutotem: 778,
mimikyubustedtotem: 778,
ribombeetotem: 743,
kommoototem: 784,
venusaurmega: 984 + 0,
charizardmegax: 984 + 1,
charizardmegay: 984 + 2,
blastoisemega: 984 + 3,
beedrillmega: 984 + 4,
pidgeotmega: 984 + 5,
alakazammega: 984 + 6,
slowbromega: 984 + 7,
gengarmega: 984 + 8,
kangaskhanmega: 984 + 9,
pinsirmega: 984 + 10,
gyaradosmega: 984 + 11,
aerodactylmega: 984 + 12,
mewtwomegax: 984 + 13,
mewtwomegay: 984 + 14,
ampharosmega: 984 + 15,
steelixmega: 984 + 16,
scizormega: 984 + 17,
heracrossmega: 984 + 18,
houndoommega: 984 + 19,
tyranitarmega: 984 + 20,
sceptilemega: 984 + 21,
blazikenmega: 984 + 22,
swampertmega: 984 + 23,
gardevoirmega: 984 + 24,
sableyemega: 984 + 25,
mawilemega: 984 + 26,
aggronmega: 984 + 27,
medichammega: 984 + 28,
manectricmega: 984 + 29,
sharpedomega: 984 + 30,
cameruptmega: 984 + 31,
altariamega: 984 + 32,
banettemega: 984 + 33,
absolmega: 984 + 34,
glaliemega: 984 + 35,
salamencemega: 984 + 36,
metagrossmega: 984 + 37,
latiasmega: 984 + 38,
latiosmega: 984 + 39,
kyogreprimal: 984 + 40,
groudonprimal: 984 + 41,
rayquazamega: 984 + 42,
lopunnymega: 984 + 43,
garchompmega: 984 + 44,
lucariomega: 984 + 45,
abomasnowmega: 984 + 46,
gallademega: 984 + 47,
audinomega: 984 + 48,
dianciemega: 984 + 49,
syclant: 1152 + 0,
revenankh: 1152 + 1,
pyroak: 1152 + 2,
fidgit: 1152 + 3,
stratagem: 1152 + 4,
arghonaut: 1152 + 5,
kitsunoh: 1152 + 6,
cyclohm: 1152 + 7,
colossoil: 1152 + 8,
krilowatt: 1152 + 9,
voodoom: 1152 + 10,
tomohawk: 1152 + 11,
necturna: 1152 + 12,
mollux: 1152 + 13,
aurumoth: 1152 + 14,
malaconda: 1152 + 15,
cawmodore: 1152 + 16,
volkraken: 1152 + 17,
plasmanta: 1152 + 18,
naviathan: 1152 + 19,
crucibelle: 1152 + 20,
crucibellemega: 1152 + 21,
kerfluffle: 1152 + 22,
pajantom: 1152 + 23,
jumbao: 1152 + 24,
caribolt: 1152 + 25,
smokomodo: 1152 + 26,
snaelstrom: 1152 + 27,
syclar: 1188 + 0,
embirch: 1188 + 1,
flarelm: 1188 + 2,
breezi: 1188 + 3,
scratchet: 1188 + 4,
necturine: 1188 + 5,
cupra: 1188 + 6,
argalis: 1188 + 7,
brattler: 1188 + 8,
cawdet: 1188 + 9,
volkritter: 1188 + 10,
snugglow: 1188 + 11,
floatoy: 1188 + 12,
caimanoe: 1188 + 13,
pluffle: 1188 + 14,
rebble: 1188 + 15,
tactite: 1188 + 16,
privatyke: 1188 + 17,
nohface: 1188 + 18,
monohm: 1188 + 19,
duohm: 1188 + 20,
// protowatt: 1188 + 21,
voodoll: 1188 + 22,
mumbao: 1188 + 23,
};
const BattlePokemonIconIndexesLeft: {[id: string]: number} = {
pikachubelle: 1044 + 0,
pikachupopstar: 1044 + 1,
clefairy: 1044 + 2,
clefable: 1044 + 3,
jigglypuff: 1044 + 4,
wigglytuff: 1044 + 5,
dugtrioalola: 1044 + 6,
poliwhirl: 1044 + 7,
poliwrath: 1044 + 8,
mukalola: 1044 + 9,
kingler: 1044 + 10,
croconaw: 1044 + 11,
cleffa: 1044 + 12,
igglybuff: 1044 + 13,
politoed: 1044 + 14,
// unown gap
sneasel: 1044 + 35,
teddiursa: 1044 + 36,
roselia: 1044 + 37,
zangoose: 1044 + 38,
seviper: 1044 + 39,
castformrainy: 1044 + 40,
absolmega: 1044 + 41,
absol: 1044 + 42,
regirock: 1044 + 43,
torterra: 1044 + 44,
budew: 1044 + 45,
roserade: 1044 + 46,
magmortar: 1044 + 47,
togekiss: 1044 + 48,
rotomwash: 1044 + 49,
shayminsky: 1044 + 50,
emboar: 1044 + 51,
pansear: 1044 + 52,
simisear: 1044 + 53,
drilbur: 1044 + 54,
excadrill: 1044 + 55,
sawk: 1044 + 56,
lilligant: 1044 + 57,
garbodor: 1044 + 58,
solosis: 1044 + 59,
vanilluxe: 1044 + 60,
amoonguss: 1044 + 61,
klink: 1044 + 62,
klang: 1044 + 63,
klinklang: 1044 + 64,
litwick: 1044 + 65,
golett: 1044 + 66,
golurk: 1044 + 67,
kyuremblack: 1044 + 68,
kyuremwhite: 1044 + 69,
kyurem: 1044 + 70,
keldeoresolute: 1044 + 71,
meloetta: 1044 + 72,
greninja: 1044 + 73,
greninjaash: 1044 + 74,
furfroudebutante: 1044 + 75,
barbaracle: 1044 + 76,
clauncher: 1044 + 77,
clawitzer: 1044 + 78,
sylveon: 1044 + 79,
klefki: 1044 + 80,
zygarde: 1044 + 81,
zygarde10: 1044 + 82,
zygardecomplete: 1044 + 83,
dartrix: 1044 + 84,
steenee: 1044 + 85,
tsareena: 1044 + 86,
comfey: 1044 + 87,
miniormeteor: 1044 + 88,
minior: 1044 + 89,
miniororange: 1044 + 90,
minioryellow: 1044 + 91,
miniorgreen: 1044 + 92,
miniorblue: 1044 + 93,
miniorviolet: 1044 + 94,
miniorindigo: 1044 + 95,
dhelmise: 1044 + 96,
necrozma: 1044 + 97,
marshadow: 1044 + 98,
pikachuoriginal: 1044 + 99,
pikachupartner: 1044 + 100,
necrozmaduskmane: 1044 + 101,
necrozmadawnwings: 1044 + 102,
necrozmaultra: 1044 + 103,
stakataka: 1044 + 104,
blacephalon: 1044 + 105,
};
type StatName = 'hp' | 'atk' | 'def' | 'spa' | 'spd' | 'spe';
type TypeName = 'Normal' | 'Fighting' | 'Flying' | 'Poison' | 'Ground' | 'Rock' | 'Bug' | 'Ghost' | 'Steel' |
'Fire' | 'Water' | 'Grass' | 'Electric' | 'Psychic' | 'Ice' | 'Dragon' | 'Dark' | 'Fairy' | '???';
type StatusName = 'par' | 'psn' | 'frz' | 'slp' | 'brn';
type BoostStatName = 'atk' | 'def' | 'spa' | 'spd' | 'spe' | 'evasion' | 'accuracy' | 'spc';
type GenderName = 'M' | 'F' | '';
type GenderName = 'M' | 'F' | 'N';
interface Effect {
readonly id: ID;
readonly name: string;
readonly gen: number;
readonly effectType: 'Item' | 'Move' | 'Ability' | 'Template';
readonly effectType: 'Item' | 'Move' | 'Ability' | 'Template' | 'PureEffect';
/**
* Do we have data on this item/move/ability/template?
* WARNING: Always false if the relevant data files aren't loaded.
*/
readonly exists: boolean;
}
interface Item extends Effect {
readonly effectType: 'Item';
readonly zMoveFrom?: string;
class PureEffect implements Effect {
readonly effectType = 'PureEffect';
readonly id: ID;
readonly name: string;
readonly gen: number;
readonly exists: boolean;
constructor(id: ID, name: string) {
this.id = id;
this.name = name;
this.gen = 0;
this.exists = false;
}
}
interface Move extends Effect {
readonly effectType: 'Move';
readonly type: string;
readonly category: string;
readonly isZ?: string;
class Item implements Effect {
// effect
readonly effectType = 'Item';
readonly id: ID;
readonly name: string;
readonly gen: number;
readonly exists: boolean;
readonly num: number;
readonly spritenum: number;
readonly desc: string;
readonly shortDesc: string;
readonly megaStone: string;
readonly megaEvolves: string;
readonly zMove: string | true | null;
readonly zMoveType: TypeName | '';
readonly zMoveFrom: string;
readonly zMoveUser: string[] | null;
constructor(id: ID, name: string, data: any) {
if (!data || typeof data !== 'object') data = {};
if (data.name) name = data.name;
this.name = Dex.sanitizeName(name);
this.id = id;
this.gen = data.gen || 0;
this.exists = ('exists' in data ? !!data.exists : true);
this.num = data.num || 0;
this.spritenum = data.spritenum || 0;
this.desc = data.desc || data.shortDesc || '';
this.shortDesc = data.shortDesc || this.desc;
this.megaStone = data.megaStone || '';
this.megaEvolves = data.megaEvolves || '';
this.zMove = data.zMove || null;
this.zMoveType = data.zMoveType || '';
this.zMoveFrom = data.zMoveFrom || '';
this.zMoveUser = data.zMoveUser || null;
if (!this.gen) {
if (this.num >= 577) {
this.gen = 6;
} else if (this.num >= 537) {
this.gen = 5;
} else if (this.num >= 377) {
this.gen = 4;
} else {
this.gen = 3;
}
}
}
}
interface Ability extends Effect {
readonly effectType: 'Ability';
interface MoveFlags {
/** Ignores a target's substitute. */
authentic?: 1 | 0;
/** Power is multiplied by 1.5 when used by a Pokemon with the Strong Jaw Ability. */
bite?: 1 | 0;
/** Has no effect on Pokemon with the Bulletproof Ability. */
bullet?: 1 | 0;
/** The user is unable to make a move between turns. */
charge?: 1 | 0;
/** Makes contact. */
contact?: 1 | 0;
/** When used by a Pokemon, other Pokemon with the Dancer Ability can attempt to execute the same move. */
dance?: 1 | 0;
/** Thaws the user if executed successfully while the user is frozen. */
defrost?: 1 | 0;
/** Can target a Pokemon positioned anywhere in a Triple Battle. */
distance?: 1 | 0;
/** Prevented from being executed or selected during Gravity's effect. */
gravity?: 1 | 0;
/** Prevented from being executed or selected during Heal Block's effect. */
heal?: 1 | 0;
/** Can be copied by Mirror Move. */
mirror?: 1 | 0;
/** Unknown effect. */
mystery?: 1 | 0;
/** Prevented from being executed or selected in a Sky Battle. */
nonsky?: 1 | 0;
/** Has no effect on Grass-type Pokemon, Pokemon with the Overcoat Ability, and Pokemon holding Safety Goggles. */
powder?: 1 | 0;
/** Blocked by Detect, Protect, Spiky Shield, and if not a Status move, King's Shield. */
protect?: 1 | 0;
/** Power is multiplied by 1.5 when used by a Pokemon with the Mega Launcher Ability. */
pulse?: 1 | 0;
/** Power is multiplied by 1.2 when used by a Pokemon with the Iron Fist Ability. */
punch?: 1 | 0;
/** If this move is successful, the user must recharge on the following turn and cannot make a move. */
recharge?: 1 | 0;
/** Bounced back to the original user by Magic Coat or the Magic Bounce Ability. */
reflectable?: 1 | 0;
/** Can be stolen from the original user and instead used by another Pokemon using Snatch. */
snatch?: 1 | 0;
/** Has no effect on Pokemon with the Soundproof Ability. */
sound?: 1 | 0;
}
interface Template extends Effect {
readonly effectType: 'Template';
class Move implements Effect {
// effect
readonly effectType = 'Move';
readonly id: ID;
readonly name: string;
readonly gen: number;
readonly exists: boolean;
readonly basePower: number;
readonly accuracy: number | true;
readonly pp: number;
readonly type: TypeName;
readonly category: 'Physical' | 'Special' | 'Status';
readonly priority: number;
readonly target:
'normal' | 'any' | 'adjacentAlly' | 'adjacentFoe' | 'adjacentAllyOrSelf' | // single-target
'self' | 'randomNormal' | // single-target, automatic
'allAdjacent' | 'allAdjacentFoes' | // spread
'allySide' | 'foeSide' | 'all'; // side and field
readonly flags: Readonly<MoveFlags>;
readonly critRatio: number;
readonly desc: string;
readonly shortDesc: string;
readonly isViable: boolean;
readonly isNonstandard: boolean;
readonly isZ: ID;
readonly zMovePower: number;
readonly zMoveEffect: string;
readonly zMoveBoost: {[stat in StatName]?: number} | null;
readonly num: number;
constructor(id: ID, name: string, data: any) {
if (!data || typeof data !== 'object') data = {};
if (data.name) name = data.name;
this.name = Dex.sanitizeName(name);
this.id = id;
this.gen = data.gen || 0;
this.exists = ('exists' in data ? !!data.exists : true);
this.basePower = data.basePower || 0;
this.accuracy = data.accuracy || 0;
this.pp = data.pp || 1;
this.type = data.type || '???';
this.category = data.category || 'Physical';
this.priority = data.priority || 0;
this.target = data.target || 'normal';
this.flags = data.flags || {};
this.critRatio = data.critRatio === 0 ? 0 : (data.critRatio || 1);
// TODO: move to text.js
this.desc = data.desc;
this.shortDesc = data.shortDesc;
this.isViable = !!data.isViable;
this.isNonstandard = !!data.isNonstandard;
this.isZ = data.isZ || '';
this.zMovePower = data.zMovePower || 0;
this.zMoveEffect = data.zMoveEffect || '';
this.zMoveBoost = data.zMoveBoost || null;
this.num = data.num || 0;
if (!this.gen) {
if (this.num >= 560) {
this.gen = 6;
} else if (this.num >= 468) {
this.gen = 5;
} else if (this.num >= 355) {
this.gen = 4;
} else if (this.num >= 252) {
this.gen = 3;
} else if (this.num >= 166) {
this.gen = 2;
} else if (this.num >= 1) {
this.gen = 1;
}
}
}
}
class Ability implements Effect {
// effect
readonly effectType = 'Ability';
readonly id: ID;
readonly name: string;
readonly gen: number;
readonly exists: boolean;
readonly num: number;
readonly desc: string;
constructor(id: ID, name: string, data: any) {
if (!data || typeof data !== 'object') data = {};
if (data.name) name = data.name;
this.name = Dex.sanitizeName(name);
this.id = id;
this.gen = data.gen || 0;
this.exists = ('exists' in data ? !!data.exists : true);
this.num = data.num || 0;
this.desc = data.desc || data.shortDesc || '';
if (!this.gen) {
if (this.num >= 165) {
this.gen = 6;
} else if (this.num >= 124) {
this.gen = 5;
} else if (this.num >= 77) {
this.gen = 4;
} else if (this.num >= 1) {
this.gen = 3;
}
}
}
}
class Template implements Effect {
// effect
readonly effectType = 'Template';
readonly id: ID;
readonly name: string;
readonly gen: number;
readonly exists: boolean;
// name
readonly species: string;
readonly speciesid: ID;
readonly baseSpecies: string;
readonly forme: string;
readonly formeLetter: string;
readonly formeid: string;
readonly spriteid: string;
readonly types: string[];
readonly abilities: {0: string, 1?: string, H?: string, S?: string};
readonly baseStats: {hp: number, atk: number, def: number, spa: number, spd: number, spe: number};
readonly unreleasedHidden: boolean;
readonly tier: string;
// basic data
readonly num: number;
readonly types: ReadonlyArray<TypeName>;
readonly abilities: Readonly<{
0: string, 1?: string, H?: string, S?: string,
}>;
readonly baseStats: Readonly<{
hp: number, atk: number, def: number, spa: number, spd: number, spe: number,
}>;
readonly weightkg: number;
// flavor data
readonly heightm: number;
readonly gender: GenderName;
readonly color: string;
readonly genderRatio: Readonly<{M: number, F: number}> | null;
readonly eggGroups: ReadonlyArray<string>;
// format data
readonly otherFormes: ReadonlyArray<ID> | null;
// TODO: rename to cosmeticForms
readonly otherForms: ReadonlyArray<ID> | null;
readonly evos: ReadonlyArray<ID> | null;
readonly prevo: ID;
readonly requiredItem: string;
readonly tier: string;
readonly isTotem: boolean;
readonly isMega: boolean;
readonly isPrimal: boolean;
readonly battleOnly: boolean;
readonly isNonstandard: boolean;
readonly isTotem?: boolean;
readonly isMega?: boolean;
readonly unreleasedHidden: boolean;
constructor(id: ID, name: string, data: any) {
if (!data || typeof data !== 'object') data = {};
if (data.name || data.species) name = data.name || data.species;
this.name = Dex.sanitizeName(name);
this.id = id;
this.gen = data.gen || 0;
this.exists = ('exists' in data ? !!data.exists : true);
this.species = this.name;
this.speciesid = this.id;
if (!data.abilities &&
!['hooh', 'hakamoo', 'jangmoo', 'kommoo', 'porygonz'].includes(this.id)) {
const dashIndex = name.indexOf('-');
if (this.id === 'kommoototem') {
data.baseSpecies = 'Kommo-o';
data.forme = 'Totem';
} else if (dashIndex > 0) {
data.baseSpecies = name.slice(0, dashIndex);
data.forme = name.slice(dashIndex + 1);
}
}
if (!data.abilities) {
// deprecated BattleBaseSpeciesChart
for (const baseid of BattleBaseSpeciesChart) {
if (this.id.length > baseid.length && this.id.slice(0, baseid.length) === baseid) {
data.baseSpecies = baseid;
data.forme = this.id.slice(baseid.length);
}
}
if (this.id !== 'yanmega' && this.id.slice(-4) === 'mega') {
data.baseSpecies = this.id.slice(0, -4);
data.forme = this.id.slice(-4);
} else if (this.id.slice(-6) === 'primal') {
data.baseSpecies = this.id.slice(0, -6);
data.forme = this.id.slice(-6);
} else if (this.id.slice(-5) === 'alola') {
data.baseSpecies = this.id.slice(0, -5);
data.forme = this.id.slice(-5);
}
}
this.baseSpecies = data.baseSpecies || name;
this.forme = data.forme || '';
const baseId = toId(this.baseSpecies);
this.formeid = (baseId === this.id ? '' : '-' + toId(this.forme));
this.spriteid = baseId + this.formeid;
if (this.spriteid.slice(-5) === 'totem') this.spriteid = this.spriteid.slice(0, -5);
if (this.spriteid.slice(-1) === '-') this.spriteid = this.spriteid.slice(0, -1);
this.num = data.num || 0;
this.types = data.types || ['???'];
let abilities: any = {0: "No Ability"};
this.abilities = data.abilities || {0: "No Ability"};
this.baseStats = data.baseStats || {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0};
this.weightkg = data.weightkg || 0;
this.heightm = data.heightm || 0;
this.gender = data.gender || '';
this.color = data.color || '';
this.genderRatio = data.genderRatio || null;
this.eggGroups = data.eggGroups || [];
this.otherFormes = data.otherFormes || null;
this.otherForms = data.otherForms || null;
this.evos = data.evos || null;
this.prevo = data.prevo || '';
this.requiredItem = data.requiredItem || '';
this.tier = data.tier || '';
this.isTotem = false;
this.isMega = false;
this.isPrimal = false;
this.battleOnly = false;
this.isNonstandard = !!data.isNonstandard;
this.unreleasedHidden = !!data.unreleasedHidden;
if (!this.gen) {
if (this.forme && ['-mega', '-megax', '-megay'].includes(this.formeid)) {
this.gen = 6;
this.isMega = true;
this.battleOnly = true;
} else if (this.formeid === '-primal') {
this.gen = 6;
this.isPrimal = true;
this.battleOnly = true;
} else if (this.formeid === '-totem' || this.formeid === '-alolatotem') {
this.gen = 7;
this.isTotem = true;
} else if (this.formeid === '-alola') {
this.gen = 7;
} else if (this.num >= 722) {
this.gen = 7;
} else if (this.num >= 650) {
this.gen = 6;
} else if (this.num >= 494) {
this.gen = 5;
} else if (this.num >= 387) {
this.gen = 4;
} else if (this.num >= 252) {
this.gen = 3;
} else if (this.num >= 152) {
this.gen = 2;
} else if (this.num >= 1) {
this.gen = 1;
}
}
}
}
if (typeof require === 'function') {
// in Node
(global as any).baseSpeciesChart = baseSpeciesChart;
(global as any).BattleBaseSpeciesChart = BattleBaseSpeciesChart;
(global as any).PureEffect = PureEffect;
(global as any).Template = Template;
(global as any).Ability = Ability;
(global as any).Item = Item;
(global as any).Move = Move;
}

View File

@@ -221,8 +221,20 @@ const Dex = {
return Dex.resolveAvatar(sprites[Math.floor(Math.random() * sprites.length)]);
},
sanitizeName(name: string) {
return ('' + name).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
/**
* This is used to sanitize strings from data files like `moves.js` and
* `teambuilder-tables.js`.
*
* This makes sure untrusted strings can't wreak havoc if someone forgets to
* escape it before putting it in HTML.
*
* None of these characters belong in these files, anyway. (They can be used
* in move descriptions, but those are served from `text.js`, which are
* definitely always treated as unsanitized.)
*/
sanitizeName(name: any) {
if (!name) return '';
return ('' + name).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').slice(0, 50);
},
prefs(prop: string, value?: any, save?: boolean) {
@@ -239,99 +251,57 @@ const Dex = {
return shortName;
},
getEffect(effect: any): Effect {
if (!effect || typeof effect === 'string') {
let name = (effect || '').trim();
if (name.substr(0, 5) === 'item:') {
return Dex.getItem(name.substr(5));
} else if (name.substr(0, 8) === 'ability:') {
return Dex.getAbility(name.substr(8));
} else if (name.substr(0, 5) === 'move:') {
return Dex.getMove(name.substr(5));
}
let id = toId(name);
effect = {};
if (id && window.BattleStatuses && BattleStatuses[id]) {
effect = BattleStatuses[id];
effect.exists = true;
} else if (id && window.BattleMovedex && BattleMovedex[id] && BattleMovedex[id].effect) {
effect = BattleMovedex[id].effect;
effect.exists = true;
} else if (id && window.BattleAbilities && BattleAbilities[id] && BattleAbilities[id].effect) {
effect = BattleAbilities[id].effect;
effect.exists = true;
} else if (id && window.BattleItems && BattleItems[id] && BattleItems[id].effect) {
effect = BattleItems[id].effect;
effect.exists = true;
} else if (id === 'recoil') {
effect = {
effectType: 'Recoil',
};
effect.exists = true;
} else if (id === 'drain') {
effect = {
effectType: 'Drain',
};
effect.exists = true;
}
if (!effect.id) effect.id = id;
if (!effect.name) effect.name = Dex.sanitizeName(name);
if (!effect.category) effect.category = 'Effect';
if (!effect.effectType) effect.effectType = 'Effect';
getEffect(name: string | null | undefined): PureEffect | Item | Ability | Move {
name = (name || '').trim();
if (name.substr(0, 5) === 'item:') {
return Dex.getItem(name.substr(5));
} else if (name.substr(0, 8) === 'ability:') {
return Dex.getAbility(name.substr(8));
} else if (name.substr(0, 5) === 'move:') {
return Dex.getMove(name.substr(5));
}
return effect;
let id = toId(name);
return new PureEffect(id, name);
},
getMove(move: any): Move {
if (!move || typeof move === 'string') {
let name = (move || '').trim();
let id = toId(name);
move = (window.BattleMovedex && window.BattleMovedex[id]) || {};
if (move.name) move.exists = true;
if (!move.exists && id.substr(0, 11) === 'hiddenpower' && id.length > 11) {
let matches = /([a-z]*)([0-9]*)/.exec(id)!;
move = (window.BattleMovedex && window.BattleMovedex[matches[1]]) || {};
move = {...move};
move.basePower = matches[2];
}
if (!move.exists && id.substr(0, 6) === 'return' && id.length > 6) {
move = (window.BattleMovedex && window.BattleMovedex['return']) || {};
move = {...move};
move.basePower = id.slice(6);
}
if (!move.exists && id.substr(0, 11) === 'frustration' && id.length > 11) {
move = (window.BattleMovedex && window.BattleMovedex['frustration']) || {};
move = {...move};
move.basePower = id.slice(11);
}
if (!move.id) move.id = id;
if (!move.name) move.name = Dex.sanitizeName(name);
if (!move.critRatio) move.critRatio = 1;
if (!move.baseType) move.baseType = move.type;
if (!move.effectType) move.effectType = 'Move';
if (!move.secondaries && move.secondary) move.secondaries = [move.secondary];
if (!move.flags) move.flags = {};
if (!move.gen) {
if (move.num >= 560) {
move.gen = 6;
} else if (move.num >= 468) {
move.gen = 5;
} else if (move.num >= 355) {
move.gen = 4;
} else if (move.num >= 252) {
move.gen = 3;
} else if (move.num >= 166) {
move.gen = 2;
} else if (move.num >= 1) {
move.gen = 1;
} else {
move.gen = 0;
}
}
getMove(nameOrMove: string | Move | null | undefined): Move {
if (nameOrMove && typeof nameOrMove !== 'string') {
// TODO: don't accept Moves here
return nameOrMove;
}
let name = nameOrMove || '';
let id = toId(nameOrMove);
if (window.BattleAliases && id in BattleAliases) {
name = BattleAliases[id];
id = toId(name);
}
if (!window.BattleMovedex) window.BattleMovedex = {};
let data = window.BattleMovedex[id];
if (data && typeof data.exists === 'boolean') return data;
if (!data && id.substr(0, 11) === 'hiddenpower' && id.length > 11) {
let [, hpWithType, hpPower] = /([a-z]*)([0-9]*)/.exec(id)!;
data = {
...(window.BattleMovedex[hpWithType] || {}),
basePower: Number(hpPower) || 60,
};
}
if (!data && id.substr(0, 6) === 'return' && id.length > 6) {
data = {
...(window.BattleMovedex['return'] || {}),
basePower: Number(id.slice(6)),
};
}
if (!data && id.substr(0, 11) === 'frustration' && id.length > 11) {
data = {
...(window.BattleMovedex['frustration'] || {}),
basePower: Number(id.slice(11)),
};
}
if (!data) data = {exists: false};
let move = new Move(id, name, data);
window.BattleMovedex[id] = move;
return move;
},
@@ -344,156 +314,77 @@ const Dex = {
return move.category;
},
getItem(item: any): Item {
if (!item || typeof item === 'string') {
let name = (item || '').trim();
let id = toId(name);
item = (window.BattleItems && window.BattleItems[id]) || {};
if (item.name) item.exists = true;
if (!item.id) item.id = id;
if (!item.name) item.name = Dex.sanitizeName(name);
if (!item.category) item.category = 'Effect';
if (!item.effectType) item.effectType = 'Item';
if (!item.gen) {
if (item.num >= 577) {
item.gen = 6;
} else if (item.num >= 537) {
item.gen = 5;
} else if (item.num >= 377) {
item.gen = 4;
} else {
item.gen = 3;
}
}
getItem(nameOrItem: string | Item | null | undefined): Item {
if (nameOrItem && typeof nameOrItem !== 'string') {
// TODO: don't accept Items here
return nameOrItem;
}
let name = nameOrItem || '';
let id = toId(nameOrItem);
if (window.BattleAliases && id in BattleAliases) {
name = BattleAliases[id];
id = toId(name);
}
if (!window.BattleItems) window.BattleItems = {};
let data = window.BattleItems[id];
if (data && typeof data.exists === 'boolean') return data;
if (!data) data = {exists: false};
let item = new Item(id, name, data);
window.BattleItems[id] = item;
return item;
},
getAbility(ability: any): Ability {
if (!ability || typeof ability === 'string') {
let name = (ability || '').trim();
let id = toId(name);
ability = (window.BattleAbilities && window.BattleAbilities[id]) || {};
if (ability.name) ability.exists = true;
if (!ability.id) ability.id = id;
if (!ability.name) ability.name = Dex.sanitizeName(name);
if (!ability.category) ability.category = 'Effect';
if (!ability.effectType) ability.effectType = 'Ability';
if (!ability.gen) {
if (ability.num >= 165) {
ability.gen = 6;
} else if (ability.num >= 124) {
ability.gen = 5;
} else if (ability.num >= 77) {
ability.gen = 4;
} else if (ability.num >= 1) {
ability.gen = 3;
} else {
ability.gen = 0;
}
}
getAbility(nameOrAbility: string | Ability | null | undefined): Ability {
if (nameOrAbility && typeof nameOrAbility !== 'string') {
// TODO: don't accept Abilities here
return nameOrAbility;
}
let name = nameOrAbility || '';
let id = toId(nameOrAbility);
if (window.BattleAliases && id in BattleAliases) {
name = BattleAliases[id];
id = toId(name);
}
if (!window.BattleAbilities) window.BattleAbilities = {};
let data = window.BattleAbilities[id];
if (data && typeof data.exists === 'boolean') return data;
if (!data) data = {exists: false};
let ability = new Ability(id, name, data);
window.BattleAbilities[id] = ability;
return ability;
},
getTemplate(template: any): Template {
if (!template || typeof template === 'string') {
let name = template;
let id = toId(name);
let speciesid = id;
if (window.BattleAliases && BattleAliases[id]) {
name = BattleAliases[id];
id = toId(name);
}
if (!id) name = '';
if (!window.BattlePokedex) window.BattlePokedex = {};
if (!window.BattlePokedex[id]) {
template = window.BattlePokedex[id] = {};
for (const baseid of baseSpeciesChart) {
if (id.length > baseid.length && id.substr(0, baseid.length) === baseid) {
template.baseSpecies = baseid;
template.forme = id.substr(baseid.length);
}
}
if (id !== 'yanmega' && id.slice(-4) === 'mega') {
template.baseSpecies = id.slice(0, -4);
template.forme = id.slice(-4);
} else if (id.slice(-6) === 'primal') {
template.baseSpecies = id.slice(0, -6);
template.forme = id.slice(-6);
} else if (id.slice(-5) === 'alola') {
template.baseSpecies = id.slice(0, -5);
template.forme = id.slice(-5);
}
template.exists = false;
}
template = window.BattlePokedex[id];
if (template.species) name = template.species;
if (template.exists === undefined) template.exists = true;
if (!template.id) template.id = id;
if (!template.name) template.name = name = Dex.sanitizeName(name);
if (!template.speciesid) template.speciesid = id;
if (!template.species) template.species = name;
if (!template.baseSpecies) template.baseSpecies = name;
if (!template.forme) template.forme = '';
if (!template.formeLetter) template.formeLetter = '';
if (!template.formeid) {
let formeid = '';
if (template.baseSpecies !== name) {
formeid = '-' + toId(template.forme);
}
template.formeid = formeid;
}
if (!template.spriteid) template.spriteid = toId(template.baseSpecies) + template.formeid;
if (!template.effectType) template.effectType = 'Template';
if (!template.gen) {
if (template.forme && ['-mega', '-megax', '-megay'].includes(template.formeid)) {
template.gen = 6;
template.isMega = true;
template.battleOnly = true;
} else if (template.formeid === '-primal') {
template.gen = 6;
template.isPrimal = true;
template.battleOnly = true;
} else if (template.formeid.slice(-5) === 'totem') {
template.gen = 7;
template.isTotem = true;
} else if (template.formeid === '-alola') {
template.gen = 7;
} else if (template.num >= 722) {
template.gen = 7;
} else if (template.num >= 650) {
template.gen = 6;
} else if (template.num >= 494) {
template.gen = 5;
} else if (template.num >= 387) {
template.gen = 4;
} else if (template.num >= 252) {
template.gen = 3;
} else if (template.num >= 152) {
template.gen = 2;
} else if (template.num >= 1) {
template.gen = 1;
} else {
template.gen = 0;
}
}
if (template.otherForms && template.otherForms.indexOf(speciesid) >= 0) {
if (!window.BattlePokedexAltForms) window.BattlePokedexAltForms = {};
if (!window.BattlePokedexAltForms[speciesid]) {
template = window.BattlePokedexAltForms[speciesid] = {...template};
let form = speciesid.slice(template.baseSpecies.length);
let formid = '-' + form;
form = form[0].toUpperCase() + form.slice(1);
template.form = form;
template.species = template.baseSpecies + (form ? '-' + form : '');
template.speciesid = toId(template.species);
template.spriteid = toId(template.baseSpecies) + formid;
}
template = window.BattlePokedexAltForms[speciesid];
}
if (template.spriteid.slice(-5) === 'totem') template.spriteid = template.spriteid.slice(0, -5);
if (template.spriteid.slice(-1) === '-') template.spriteid = template.spriteid.slice(0, -1);
getTemplate(nameOrTemplate: string | Template | null | undefined): Template {
if (nameOrTemplate && typeof nameOrTemplate !== 'string') {
// TODO: don't accept Templates here
return nameOrTemplate;
}
let name = nameOrTemplate || '';
let id = toId(nameOrTemplate);
let formid = id;
if (!window.BattlePokedexAltForms) window.BattlePokedexAltForms = {};
if (formid in window.BattlePokedexAltForms) return window.BattlePokedexAltForms[formid];
if (window.BattleAliases && id in BattleAliases) {
name = BattleAliases[id];
id = toId(name);
}
if (!window.BattlePokedex) window.BattlePokedex = {};
let data = window.BattlePokedex[id];
if (data && typeof data.exists === 'boolean') return data;
if (!data) data = {exists: false};
let template = new Template(id, name, data);
window.BattlePokedex[id] = template;
if (formid !== id && template.otherForms && template.otherForms.includes(formid)) {
id = formid;
let forme = formid.slice(id.length);
forme = forme[0].toUpperCase() + forme.slice(1);
name = template.baseSpecies + (forme ? '-' + forme : '');
template = window.BattlePokedexAltForms[formid] = new Template(id, name, {
...template,
name,
forme,
});
}
return template;
},
@@ -721,367 +612,20 @@ const Dex = {
else if (window.BattlePokedex && window.BattlePokedex[id] && BattlePokedex[id].num) num = BattlePokedex[id].num;
if (num < 0) num = 0;
if (num > 809) num = 0;
let altNums: {[id: string]: number} = {
egg: 816 + 1,
pikachubelle: 816 + 2,
pikachulibre: 816 + 3,
pikachuphd: 816 + 4,
pikachupopstar: 816 + 5,
pikachurockstar: 816 + 6,
pikachucosplay: 816 + 7,
// unown gap
castformrainy: 816 + 35,
castformsnowy: 816 + 36,
castformsunny: 816 + 37,
deoxysattack: 816 + 38,
deoxysdefense: 816 + 39,
deoxysspeed: 816 + 40,
burmysandy: 816 + 41,
burmytrash: 816 + 42,
wormadamsandy: 816 + 43,
wormadamtrash: 816 + 44,
cherrimsunshine: 816 + 45,
shelloseast: 816 + 46,
gastrodoneast: 816 + 47,
rotomfan: 816 + 48,
rotomfrost: 816 + 49,
rotomheat: 816 + 50,
rotommow: 816 + 51,
rotomwash: 816 + 52,
giratinaorigin: 816 + 53,
shayminsky: 816 + 54,
unfezantf: 816 + 55,
basculinbluestriped: 816 + 56,
darmanitanzen: 816 + 57,
deerlingautumn: 816 + 58,
deerlingsummer: 816 + 59,
deerlingwinter: 816 + 60,
sawsbuckautumn: 816 + 61,
sawsbucksummer: 816 + 62,
sawsbuckwinter: 816 + 63,
frillishf: 816 + 64,
jellicentf: 816 + 65,
tornadustherian: 816 + 66,
thundurustherian: 816 + 67,
landorustherian: 816 + 68,
kyuremblack: 816 + 69,
kyuremwhite: 816 + 70,
keldeoresolute: 816 + 71,
meloettapirouette: 816 + 72,
vivillonarchipelago: 816 + 73,
vivilloncontinental: 816 + 74,
vivillonelegant: 816 + 75,
vivillonfancy: 816 + 76,
vivillongarden: 816 + 77,
vivillonhighplains: 816 + 78,
vivillonicysnow: 816 + 79,
vivillonjungle: 816 + 80,
vivillonmarine: 816 + 81,
vivillonmodern: 816 + 82,
vivillonmonsoon: 816 + 83,
vivillonocean: 816 + 84,
vivillonpokeball: 816 + 85,
vivillonpolar: 816 + 86,
vivillonriver: 816 + 87,
vivillonsandstorm: 816 + 88,
vivillonsavanna: 816 + 89,
vivillonsun: 816 + 90,
vivillontundra: 816 + 91,
pyroarf: 816 + 92,
flabebeblue: 816 + 93,
flabebeorange: 816 + 94,
flabebewhite: 816 + 95,
flabebeyellow: 816 + 96,
floetteblue: 816 + 97,
floetteeternal: 816 + 98,
floetteorange: 816 + 99,
floettewhite: 816 + 100,
floetteyellow: 816 + 101,
florgesblue: 816 + 102,
florgesorange: 816 + 103,
florgeswhite: 816 + 104,
florgesyellow: 816 + 105,
furfroudandy: 816 + 106,
furfroudebutante: 816 + 107,
furfroudiamond: 816 + 108,
furfrouheart: 816 + 109,
furfroukabuki: 816 + 110,
furfroulareine: 816 + 111,
furfroumatron: 816 + 112,
furfroupharaoh: 816 + 113,
furfroustar: 816 + 114,
meowsticf: 816 + 115,
aegislashblade: 816 + 116,
hoopaunbound: 816 + 118,
rattataalola: 816 + 119,
raticatealola: 816 + 120,
raichualola: 816 + 121,
sandshrewalola: 816 + 122,
sandslashalola: 816 + 123,
vulpixalola: 816 + 124,
ninetalesalola: 816 + 125,
diglettalola: 816 + 126,
dugtrioalola: 816 + 127,
meowthalola: 816 + 128,
persianalola: 816 + 129,
geodudealola: 816 + 130,
graveleralola: 816 + 131,
golemalola: 816 + 132,
grimeralola: 816 + 133,
mukalola: 816 + 134,
exeggutoralola: 816 + 135,
marowakalola: 816 + 136,
greninjaash: 816 + 137,
zygarde10: 816 + 138,
zygardecomplete: 816 + 139,
oricoriopompom: 816 + 140,
oricoriopau: 816 + 141,
oricoriosensu: 816 + 142,
lycanrocmidnight: 816 + 143,
wishiwashischool: 816 + 144,
miniormeteor: 816 + 145,
miniororange: 816 + 146,
minioryellow: 816 + 147,
miniorgreen: 816 + 148,
miniorblue: 816 + 149,
miniorviolet: 816 + 150,
miniorindigo: 816 + 151,
magearnaoriginal: 816 + 152,
pikachuoriginal: 816 + 153,
pikachuhoenn: 816 + 154,
pikachusinnoh: 816 + 155,
pikachuunova: 816 + 156,
pikachukalos: 816 + 157,
pikachualola: 816 + 158,
pikachupartner: 816 + 159,
lycanrocdusk: 816 + 160,
necrozmaduskmane: 816 + 161,
necrozmadawnwings: 816 + 162,
necrozmaultra: 816 + 163,
pikachustarter: 816 + 164,
eeveestarter: 816 + 165,
gumshoostotem: 735,
raticatealolatotem: 816 + 120,
marowakalolatotem: 816 + 136,
araquanidtotem: 752,
lurantistotem: 754,
salazzletotem: 758,
vikavolttotem: 738,
togedemarutotem: 777,
mimikyutotem: 778,
mimikyubustedtotem: 778,
ribombeetotem: 743,
kommoototem: 784,
venusaurmega: 984 + 0,
charizardmegax: 984 + 1,
charizardmegay: 984 + 2,
blastoisemega: 984 + 3,
beedrillmega: 984 + 4,
pidgeotmega: 984 + 5,
alakazammega: 984 + 6,
slowbromega: 984 + 7,
gengarmega: 984 + 8,
kangaskhanmega: 984 + 9,
pinsirmega: 984 + 10,
gyaradosmega: 984 + 11,
aerodactylmega: 984 + 12,
mewtwomegax: 984 + 13,
mewtwomegay: 984 + 14,
ampharosmega: 984 + 15,
steelixmega: 984 + 16,
scizormega: 984 + 17,
heracrossmega: 984 + 18,
houndoommega: 984 + 19,
tyranitarmega: 984 + 20,
sceptilemega: 984 + 21,
blazikenmega: 984 + 22,
swampertmega: 984 + 23,
gardevoirmega: 984 + 24,
sableyemega: 984 + 25,
mawilemega: 984 + 26,
aggronmega: 984 + 27,
medichammega: 984 + 28,
manectricmega: 984 + 29,
sharpedomega: 984 + 30,
cameruptmega: 984 + 31,
altariamega: 984 + 32,
banettemega: 984 + 33,
absolmega: 984 + 34,
glaliemega: 984 + 35,
salamencemega: 984 + 36,
metagrossmega: 984 + 37,
latiasmega: 984 + 38,
latiosmega: 984 + 39,
kyogreprimal: 984 + 40,
groudonprimal: 984 + 41,
rayquazamega: 984 + 42,
lopunnymega: 984 + 43,
garchompmega: 984 + 44,
lucariomega: 984 + 45,
abomasnowmega: 984 + 46,
gallademega: 984 + 47,
audinomega: 984 + 48,
dianciemega: 984 + 49,
syclant: 1152 + 0,
revenankh: 1152 + 1,
pyroak: 1152 + 2,
fidgit: 1152 + 3,
stratagem: 1152 + 4,
arghonaut: 1152 + 5,
kitsunoh: 1152 + 6,
cyclohm: 1152 + 7,
colossoil: 1152 + 8,
krilowatt: 1152 + 9,
voodoom: 1152 + 10,
tomohawk: 1152 + 11,
necturna: 1152 + 12,
mollux: 1152 + 13,
aurumoth: 1152 + 14,
malaconda: 1152 + 15,
cawmodore: 1152 + 16,
volkraken: 1152 + 17,
plasmanta: 1152 + 18,
naviathan: 1152 + 19,
crucibelle: 1152 + 20,
crucibellemega: 1152 + 21,
kerfluffle: 1152 + 22,
pajantom: 1152 + 23,
jumbao: 1152 + 24,
caribolt: 1152 + 25,
smokomodo: 1152 + 26,
snaelstrom: 1152 + 27,
syclar: 1188 + 0,
embirch: 1188 + 1,
flarelm: 1188 + 2,
breezi: 1188 + 3,
scratchet: 1188 + 4,
necturine: 1188 + 5,
cupra: 1188 + 6,
argalis: 1188 + 7,
brattler: 1188 + 8,
cawdet: 1188 + 9,
volkritter: 1188 + 10,
snugglow: 1188 + 11,
floatoy: 1188 + 12,
caimanoe: 1188 + 13,
pluffle: 1188 + 14,
rebble: 1188 + 15,
tactite: 1188 + 16,
privatyke: 1188 + 17,
nohface: 1188 + 18,
monohm: 1188 + 19,
duohm: 1188 + 20,
// protowatt: 1188 + 21,
voodoll: 1188 + 22,
mumbao: 1188 + 23,
};
if (altNums[id]) {
num = altNums[id];
if (BattlePokemonIconIndexes[id]) {
num = BattlePokemonIconIndexes[id];
}
if (pokemon && pokemon.gender === 'F') {
if (id === 'unfezant' || id === 'frillish' || id === 'jellicent' || id === 'meowstic' || id === 'pyroar') {
num = altNums[id + 'f'];
num = BattlePokemonIconIndexes[id + 'f'];
}
}
if (facingLeft) {
altNums = {
pikachubelle: 1044 + 0,
pikachupopstar: 1044 + 1,
clefairy: 1044 + 2,
clefable: 1044 + 3,
jigglypuff: 1044 + 4,
wigglytuff: 1044 + 5,
dugtrioalola: 1044 + 6,
poliwhirl: 1044 + 7,
poliwrath: 1044 + 8,
mukalola: 1044 + 9,
kingler: 1044 + 10,
croconaw: 1044 + 11,
cleffa: 1044 + 12,
igglybuff: 1044 + 13,
politoed: 1044 + 14,
// unown gap
sneasel: 1044 + 35,
teddiursa: 1044 + 36,
roselia: 1044 + 37,
zangoose: 1044 + 38,
seviper: 1044 + 39,
castformrainy: 1044 + 40,
absolmega: 1044 + 41,
absol: 1044 + 42,
regirock: 1044 + 43,
torterra: 1044 + 44,
budew: 1044 + 45,
roserade: 1044 + 46,
magmortar: 1044 + 47,
togekiss: 1044 + 48,
rotomwash: 1044 + 49,
shayminsky: 1044 + 50,
emboar: 1044 + 51,
pansear: 1044 + 52,
simisear: 1044 + 53,
drilbur: 1044 + 54,
excadrill: 1044 + 55,
sawk: 1044 + 56,
lilligant: 1044 + 57,
garbodor: 1044 + 58,
solosis: 1044 + 59,
vanilluxe: 1044 + 60,
amoonguss: 1044 + 61,
klink: 1044 + 62,
klang: 1044 + 63,
klinklang: 1044 + 64,
litwick: 1044 + 65,
golett: 1044 + 66,
golurk: 1044 + 67,
kyuremblack: 1044 + 68,
kyuremwhite: 1044 + 69,
kyurem: 1044 + 70,
keldeoresolute: 1044 + 71,
meloetta: 1044 + 72,
greninja: 1044 + 73,
greninjaash: 1044 + 74,
furfroudebutante: 1044 + 75,
barbaracle: 1044 + 76,
clauncher: 1044 + 77,
clawitzer: 1044 + 78,
sylveon: 1044 + 79,
klefki: 1044 + 80,
zygarde: 1044 + 81,
zygarde10: 1044 + 82,
zygardecomplete: 1044 + 83,
dartrix: 1044 + 84,
steenee: 1044 + 85,
tsareena: 1044 + 86,
comfey: 1044 + 87,
miniormeteor: 1044 + 88,
minior: 1044 + 89,
miniororange: 1044 + 90,
minioryellow: 1044 + 91,
miniorgreen: 1044 + 92,
miniorblue: 1044 + 93,
miniorviolet: 1044 + 94,
miniorindigo: 1044 + 95,
dhelmise: 1044 + 96,
necrozma: 1044 + 97,
marshadow: 1044 + 98,
pikachuoriginal: 1044 + 99,
pikachupartner: 1044 + 100,
necrozmaduskmane: 1044 + 101,
necrozmadawnwings: 1044 + 102,
necrozmaultra: 1044 + 103,
stakataka: 1044 + 104,
blacephalon: 1044 + 105,
};
if (altNums[id]) {
num = altNums[id];
if (BattlePokemonIconIndexesLeft[id]) {
num = BattlePokemonIconIndexesLeft[id];
}
}

View File

@@ -76,7 +76,7 @@ class Pokemon {
hp = 0;
maxhp = 1000;
level = 100;
gender: GenderName = '';
gender: GenderName = 'N';
shiny = false;
hpcolor: HPColor = 'g';
@@ -807,7 +807,7 @@ class Side {
this.battle.scene.animUnsummon(pokemon);
}
swapTo(pokemon: Pokemon, slot: number, kwArgs: {[k: string]: string}) {
swapTo(pokemon: Pokemon, slot: number, kwArgs: KWArgs) {
if (pokemon.slot === slot) return;
let target = this.active[slot];
@@ -825,7 +825,7 @@ class Side {
this.battle.scene.animSummon(pokemon, slot, true);
if (target) this.battle.scene.animSummon(target, oslot, true);
}
swapWith(pokemon: Pokemon, target: Pokemon, kwArgs: {[k: string]: string}) {
swapWith(pokemon: Pokemon, target: Pokemon, kwArgs: KWArgs) {
// method provided for backwards compatibility only
if (pokemon === target) return;
@@ -1189,7 +1189,7 @@ class Battle {
}
this.scene.updateWeather();
}
useMove(pokemon: Pokemon, move: Move, target: Pokemon | null, kwArgs: {[k: string]: string}) {
useMove(pokemon: Pokemon, move: Move, target: Pokemon | null, kwArgs: KWArgs) {
let fromeffect = Dex.getEffect(kwArgs.from);
pokemon.clearMovestatuses();
if (move.id === 'focuspunch') {
@@ -1222,7 +1222,7 @@ class Battle {
pokemon.side.wisher = pokemon;
}
}
animateMove(pokemon: Pokemon, move: Move, target: Pokemon | null, kwArgs: {[k: string]: string}) {
animateMove(pokemon: Pokemon, move: Move, target: Pokemon | null, kwArgs: KWArgs) {
if (this.fastForward || kwArgs.still) return;
if (!target) target = pokemon.side.foe.active[0];
@@ -1258,7 +1258,7 @@ class Battle {
this.scene.runMoveAnim(usedMove.id, targets);
}
cantUseMove(pokemon: Pokemon, effect: Effect, move: Move, kwArgs: {[k: string]: string}) {
cantUseMove(pokemon: Pokemon, effect: Effect, move: Move, kwArgs: KWArgs) {
pokemon.clearMovestatuses();
this.scene.updateStatbar(pokemon);
if (effect.id in BattleStatusAnims) {