forked from smogon/pokemon-showdown-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild-learnsets
executable file
·202 lines (178 loc) · 7.61 KB
/
build-learnsets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#!/usr/bin/env node
/**
* This script parses index.html and sets the version query string of each
* resource to be the MD5 hash of that resource.
* It also updates news and the learnsets-g6.js file.
*
* On the live web server, this script is set as the following git hooks:
* post-commit, post-checkout, post-merge, post-rewrite
*/
"use strict";
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const exec = require('child_process').exec;
const thisFile = __filename;
const thisDir = __dirname;
const rootDir = path.resolve(thisDir, '..');
const Tools = require('../data/Pokemon-Showdown/sim/dex');
const toId = Tools.getId;
function updateLearnsets(callback) {
const reservedKeywords = ['return']; // `return` is the only ES3+ reserved keyword that (currently) raises conflicts
const numberRegExp = new RegExp('^[0-9]*');
const reservedRegExp = new RegExp('^(' + reservedKeywords.join('|') + '|\\d.*)$', 'g');
const alphabetize = (a, b) => a.localeCompare(b);
const getLsetGen = lset => lset.charAt(0);
const padNumString = function (str) {
switch (str.length) {
case 1: return '00' + str;
case 2: return '0' + str;
case 3: return '' + str;
}
};
const inLearnset = function (lset, learnset) {
const secondChar = lset.charAt(1);
if (secondChar !== 'L') return learnset.indexOf(lset) >= 0;
const firstFragment = lset.substr(0, 2);
const levelFragment = lset.substring(2, 5);
const paddedLevel = padNumString(levelFragment);
for (let i = 0, len = learnset.length; i < len; i++) {
if (learnset[i].substring(0, 2) !== firstFragment) continue;
// ignore PSdex starter moves sorting data
if (paddedLevel === padNumString(learnset[i].substring(2, 5))) return true;
}
return false;
};
const formatLset = function (lset) {
const secondChar = lset.charAt(1);
if (secondChar !== 'L') return lset;
const firstFragment = lset.substr(0, 2);
const levelFragment = lset.substr(2).match(numberRegExp)[0];
const sortFragment = lset.substr(2 + levelFragment.length);
return firstFragment + padNumString(levelFragment) + sortFragment;
};
const Pokedex = Tools.data.Pokedex;
const Learnsets = Tools.data.Learnsets;
const newLearnsetsG6 = {};
let oldLearnsetsG6;
try {
oldLearnsetsG6 = require(path.join(rootDir, 'data', 'learnsets-g6.js')).BattleLearnsets;
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') return callback(err);
oldLearnsetsG6 = {};
}
for (const speciesid in Learnsets) {
if (!oldLearnsetsG6[speciesid] || !oldLearnsetsG6[speciesid].learnset) {
if (!Pokedex[speciesid] && speciesid !== 'rockruffdusk') console.log("ERROR: " + speciesid + " not found in Pokedex");
console.log("NEW ENTRY at learnsets-g6.js: " + speciesid + ".");
oldLearnsetsG6[speciesid] = {learnset: {}};
}
}
for (const speciesid in oldLearnsetsG6) {
if (!oldLearnsetsG6[speciesid] || !oldLearnsetsG6[speciesid].learnset) return callback(new TypeError("Invalid `learnsets-g6.js` entry for " + speciesid + "."));
if (!Learnsets[speciesid]) {
console.log("REMOVED ENTRY at learnsets-g6.js: " + (Pokedex[speciesid] ? Pokedex[speciesid].species : speciesid) + ".");
continue;
}
const newLearnset = {};
const oldLearnset = oldLearnsetsG6[speciesid].learnset;
const fullLearnset = Learnsets[speciesid].learnset;
if (!fullLearnset) return callback(new TypeError("Invalid data at `learnsets.js` for " + speciesid + "."));
// copy, but ignore moves removed in main file
for (const moveid in oldLearnset) {
if (!Array.isArray(oldLearnset[moveid])) return callback(new TypeError("Invalid data at `learnsets-g6.js` for " + speciesid + ":" + moveid + "."));
if (!fullLearnset[moveid]) continue;
newLearnset[moveid] = [];
for (let i = 0, len = oldLearnset[moveid].length; i < len; i++) {
if (!inLearnset(oldLearnset[moveid][i], fullLearnset[moveid])) continue;
newLearnset[moveid].push(oldLearnset[moveid][i]);
}
}
for (const moveid in fullLearnset) {
if (!Array.isArray(fullLearnset[moveid])) return callback(new TypeError("Invalid data at `learnsets.js` for " + speciesid + ":" + moveid + "."));
if (!newLearnset[moveid]) newLearnset[moveid] = [];
newLearnset[moveid] = newLearnset[moveid].map(formatLset);
for (let i = 0, len = fullLearnset[moveid].length; i < len; i++) {
if (getLsetGen(fullLearnset[moveid][i]) !== '7') continue;
if (inLearnset(fullLearnset[moveid][i], newLearnset[moveid])) continue;
newLearnset[moveid].push(formatLset(fullLearnset[moveid][i]));
}
newLearnset[moveid].sort(alphabetize);
}
newLearnsetsG6[speciesid] = {learnset: newLearnset};
}
const buf = [];
const pokemonList = Object.keys(Pokedex).map(speciesId => Pokedex[speciesId]).sort(function (a, b) {
// Missingno. goes first (zeroth); afterwards, CAP in descending dex order (increasingly negative)
// Finally, standard Pokémon in ascending dex order
if (a.num <= 0 && b.num > 0) return -1;
if (b.num <= 0 && a.num > 0) return 1;
if (a.num <= 0 && b.num <= 0) return b.num - a.num;
return a.num - b.num;
}).map(template => toId(template.species));
for (let i = 0, len = pokemonList.length; i < len; i++) {
const entry = newLearnsetsG6[pokemonList[i]];
if (!entry || !entry.learnset) continue;
const lsetSerialized = '{' + Object.keys(entry.learnset).sort(alphabetize).map(function (moveid) {
return moveid.replace(reservedRegExp, '"$1"') + ':' + JSON.stringify(entry.learnset[moveid]);
}).join(',') + '}';
buf.push(pokemonList[i] + ':{learnset:' + lsetSerialized + '}');
}
const writeStream = fs.createWriteStream(path.join(rootDir, 'data', 'learnsets-g6.js')).on('error', callback);
writeStream.write('exports.BattleLearnsets = {\n\t' + buf.join(',\n\t') + '\n};\n');
writeStream.end(callback);
}
let indexStats, updateStats, indexMTime, updateMTime;
try {
indexStats = fs.statSync(path.join(rootDir, 'index.html'));
indexMTime = indexStats.mtime.getTime();
} catch (err) {
if (err.code !== 'ENOENT') throw err;
// It doesn't exist currently, but it will by the end of the script execution.
// Any other error is unacceptable and will throw.
}
try {
updateStats = fs.statSync(thisFile);
updateMTime = updateStats.mtime.getTime();
} catch (err) {
throw err; // !!
}
// update learnsets-g6
process.stdout.write("Updating file `data/learnsets-g6`... ");
let learnsetsStats;
let learnsetsG6Stats;
let learnsetsG6ToUpdate = true;
try {
learnsetsStats = fs.statSync(path.join(rootDir, 'data', 'learnsets.js'));
} catch (err) {
// Couldn't find learnsets.js, but that's not the end of the world: skip to next task.
console.error("Couldn't find `data/learnsets.js`. Task aborted.");
learnsetsG6ToUpdate = false;
}
if (learnsetsG6ToUpdate) {
try {
learnsetsG6Stats = fs.statSync(path.join(rootDir, 'data', 'learnsets-g6.js'));
} catch (err) {
if (err.code === 'ENOENT') {
// It doesn't exist currently, but it will by the end of the script execution.
} else {
// Any other error is unacceptable for learnsets-g6.js update: skip to next task.
console.error("Failed to read `data/learnsets-g6.js`. Task aborted.");
learnsetsG6ToUpdate = false;
}
}
}
if (learnsetsG6ToUpdate && (!indexStats || !learnsetsG6Stats || indexMTime < updateMTime || indexMTime < learnsetsStats.mtime.getTime() || indexMTime < learnsetsG6Stats.mtime.getTime())) {
// Only merge learnsets.js with learnsets-g6.js if any of those files, or this one, have been modified recently (or if we don't know what "recently" means)
updateLearnsets(function (err) {
if (err) {
let stack = err.stack || '';
stack = "File `data/learnsets-g6` failed to update.\n" + stack;
console.error(stack);
} else {
console.log("DONE");
}
});
} else {
console.log("CACHED");
}