mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-05-06 13:47:24 -05:00
Overhaul old-gen random team builders
Mainly follow-up for 1deedc595, but also fixes a few bugs.
- BW/GSC/RBY - randomSet: fixed and renamed slot argument.
- BW - randomTeam: crashlogger relative path was set incorrectly.
- BW - randomTeam: PotD Magikarp and Delibird used outdated randomBattleMoves data format.
- RBY - randomTeam: builder was too reject-happy regarding weaknesses (counters prematurely updated).
An improvement of 130% more op/s is observed for RBY randomCCTeam,
with no significative performance regression for randomTeam in any gen.
This commit is contained in:
parent
207cb41957
commit
baadd0a92f
|
|
@ -942,26 +942,33 @@ exports.BattleScripts = {
|
|||
var teamdexno = [];
|
||||
var team = [];
|
||||
|
||||
var hasDexNumber = {};
|
||||
var formes = [[], [], [], [], [], []];
|
||||
|
||||
// Pick six random Pokémon, no repeats.
|
||||
var num;
|
||||
for (var i = 0; i < 6; i++) {
|
||||
while (true) {
|
||||
var x = Math.floor(Math.random() * 151) + 1;
|
||||
if (teamdexno.indexOf(x) < 0) {
|
||||
teamdexno.push(x);
|
||||
break;
|
||||
}
|
||||
do {
|
||||
num = this.random(151) + 1;
|
||||
} while (num in hasDexNumber);
|
||||
hasDexNumber[num] = i;
|
||||
}
|
||||
|
||||
var formeCounter = 0;
|
||||
for (var id in this.data.Pokedex) {
|
||||
if (!(this.data.Pokedex[id].num in hasDexNumber)) continue;
|
||||
var template = this.getTemplate(id);
|
||||
if (!template.learnset || template.forme) continue;
|
||||
formes[hasDexNumber[template.num]].push(template.species);
|
||||
if (++formeCounter >= 6) {
|
||||
// Gen 1 had no alternate formes, so we can break out of the loop already.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 6; i++) {
|
||||
// Choose forme.
|
||||
var formes = [];
|
||||
for (var j in this.data.Pokedex) {
|
||||
if (this.data.Pokedex[j].num === teamdexno[i] && this.getTemplate(this.data.Pokedex[j].species).learnset && this.data.Pokedex[j].species.substr(0, 8) !== 'Pikachu-') {
|
||||
formes.push(this.data.Pokedex[j].species);
|
||||
}
|
||||
}
|
||||
var poke = formes.sample();
|
||||
var poke = formes[i][this.random(formes[i].length)];
|
||||
var template = this.getTemplate(poke);
|
||||
|
||||
// Level balance: calculate directly from stats rather than using some silly lookup table.
|
||||
|
|
@ -992,23 +999,16 @@ exports.BattleScripts = {
|
|||
|
||||
// Random DVs.
|
||||
var ivs = {
|
||||
hp: Math.floor(Math.random() * 30),
|
||||
atk: Math.floor(Math.random() * 30),
|
||||
def: Math.floor(Math.random() * 30),
|
||||
spa: Math.floor(Math.random() * 30),
|
||||
spd: Math.floor(Math.random() * 30),
|
||||
spe: Math.floor(Math.random() * 30)
|
||||
hp: this.random(30),
|
||||
atk: this.random(30),
|
||||
def: this.random(30),
|
||||
spa: this.random(30),
|
||||
spd: this.random(30),
|
||||
spe: this.random(30)
|
||||
};
|
||||
|
||||
// All EVs.
|
||||
var evs = {
|
||||
hp: 255,
|
||||
atk: 255,
|
||||
def: 255,
|
||||
spa: 255,
|
||||
spd: 255,
|
||||
spe: 255
|
||||
};
|
||||
// Maxed EVs.
|
||||
var evs = {hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255};
|
||||
|
||||
// Four random unique moves from movepool. don't worry about "attacking" or "viable".
|
||||
// Since Gens 1 and 2 learnsets are shared, we need to weed out Gen 2 moves.
|
||||
|
|
@ -1017,12 +1017,10 @@ exports.BattleScripts = {
|
|||
for (var move in template.learnset) {
|
||||
if (this.getMove(move).gen === 1) pool.push(move);
|
||||
}
|
||||
if (pool.length > 4) {
|
||||
moves = pool.sample(4);
|
||||
} else if (pool.length > 0) {
|
||||
if (pool.length <= 4) {
|
||||
moves = pool;
|
||||
} else {
|
||||
moves = ['struggle'];
|
||||
moves = [this.sampleNoReplace(pool), this.sampleNoReplace(pool), this.sampleNoReplace(pool), this.sampleNoReplace(pool)];
|
||||
}
|
||||
|
||||
team.push({
|
||||
|
|
@ -1044,64 +1042,78 @@ exports.BattleScripts = {
|
|||
// Random team generation for Gen 1 Random Battles.
|
||||
randomTeam: function (side) {
|
||||
// Get what we need ready.
|
||||
var keys = [];
|
||||
var pokemonLeft = 0;
|
||||
var pokemon = [];
|
||||
var i = 1;
|
||||
|
||||
// We need to check it's one of the first 151 because formats data are installed onto main format data, not replaced.
|
||||
for (var n in this.data.FormatsData) {
|
||||
if (this.data.FormatsData[n].randomBattleMoves && i < 152) {
|
||||
keys.push(n);
|
||||
}
|
||||
i++;
|
||||
var handicapMons = {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1};
|
||||
var nuTiers = {'UU':1, 'BL':1, 'NFE':1, 'LC':1};
|
||||
var uuTiers = {'NFE':1, 'UU':1, 'BL':1};
|
||||
|
||||
var n = 1;
|
||||
var pokemonPool = [];
|
||||
for (var id in this.data.FormatsData) {
|
||||
// FIXME: Not ES-compliant
|
||||
if (n > 151 || !this.data.FormatsData[id].randomBattleMoves) continue;
|
||||
pokemonPool.push(id);
|
||||
n++;
|
||||
}
|
||||
keys = keys.randomize();
|
||||
|
||||
// Now let's store what we are getting.
|
||||
var typeCount = {};
|
||||
var weaknessCount = {'electric':0, 'psychic':0, 'water':0, 'ice':0};
|
||||
var weaknessCount = {'Electric':0, 'Psychic':0, 'Water':0, 'Ice':0};
|
||||
var uberCount = 0;
|
||||
var nuCount = 0;
|
||||
var hasShitmon = false;
|
||||
|
||||
for (var i = 0; i < keys.length && pokemonLeft < 6; i++) {
|
||||
var template = this.getTemplate(keys[i]);
|
||||
if (!template || !template.name || !template.types) continue;
|
||||
while (pokemonPool.length && pokemonLeft < 6) {
|
||||
var template = this.getTemplate(this.sampleNoReplace(pokemonPool));
|
||||
if (!template.exists) continue;
|
||||
|
||||
// Bias the tiers so you get less shitmons and only one of the two Ubers.
|
||||
// If you have a shitmon, you're covered in OUs and Ubers if possible
|
||||
var tier = template.tier;
|
||||
if (tier === 'LC' && (nuCount > 1 || hasShitmon)) continue;
|
||||
if ((tier === 'NFE' || tier === 'UU' || tier === 'NU') && (hasShitmon || (nuCount > 2 && this.random(1)))) continue;
|
||||
// Unless you have one of the worst mons, in that case we allow luck to give you both Mew and Mewtwo.
|
||||
if (tier === 'Uber' && uberCount >= 1 && !hasShitmon) continue;
|
||||
switch (tier) {
|
||||
case 'LC':
|
||||
if (nuCount > 1 || hasShitmon) continue;
|
||||
break;
|
||||
case 'Uber':
|
||||
// Unless you have one of the worst mons, in that case we allow luck to give you all Ubers.
|
||||
if (uberCount >= 1 && !hasShitmon) continue;
|
||||
break;
|
||||
default:
|
||||
if (uuTiers[tier] && (hasShitmon || (nuCount > 2 && this.random(2) >= 1))) continue;
|
||||
}
|
||||
|
||||
// We need a weakness count of spammable attacks to avoid being swept by those.
|
||||
// Spammable attacks are: Thunderbolt, Psychic, Surf, Blizzard.
|
||||
var skip = false;
|
||||
Object.keys(weaknessCount).forEach(function (type) {
|
||||
var notImmune = Tools.getImmunity(type, template);
|
||||
if (notImmune && Tools.getEffectiveness(type, template) > 0) {
|
||||
weaknessCount[type]++;
|
||||
}
|
||||
if (weaknessCount[type] > 2) skip = true;
|
||||
});
|
||||
if (skip) continue;
|
||||
|
||||
// Limit 2 of any type as well. Diversity and minor weakness count.
|
||||
// The second of a same type has halved chance of being added.
|
||||
var types = template.types;
|
||||
for (var t = 0; t < types.length; t++) {
|
||||
if (typeCount[types[t]] > 1 || (typeCount[types[t]] === 1 && this.random(1))) {
|
||||
if (typeCount[types[t]] > 1 || (typeCount[types[t]] === 1 && this.random(2))) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
// We need a weakness count of spammable attacks to avoid being swept by those.
|
||||
// Spammable attacks are: Thunderbolt, Psychic, Surf, Blizzard.
|
||||
var pokemonWeaknesses = [];
|
||||
for (var type in weaknessCount) {
|
||||
var increaseCount = Tools.getImmunity(type, template) && Tools.getEffectiveness(type, template) > 0;
|
||||
if (!increaseCount) continue;
|
||||
if (weaknessCount[type] >= 2) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
pokemonWeaknesses.push(type);
|
||||
}
|
||||
|
||||
if (skip) continue;
|
||||
|
||||
// The set passes the limitations.
|
||||
var set = this.randomSet(template, i);
|
||||
var set = this.randomSet(template, pokemon.length);
|
||||
pokemon.push(set);
|
||||
|
||||
// Now let's increase the counters. First, the Pokémon left.
|
||||
|
|
@ -1109,34 +1121,38 @@ exports.BattleScripts = {
|
|||
|
||||
// Type counter.
|
||||
for (var t = 0; t < types.length; t++) {
|
||||
if (types[t] in typeCount) {
|
||||
if (typeCount[types[t]]) {
|
||||
typeCount[types[t]]++;
|
||||
} else {
|
||||
typeCount[types[t]] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment type bias counters.
|
||||
// Weakness counter.
|
||||
for (var t = 0; t < pokemonWeaknesses.length; t++) {
|
||||
weaknessCount[pokemonWeaknesses[t]]++;
|
||||
}
|
||||
|
||||
// Increment tier bias counters.
|
||||
if (tier === 'Uber') {
|
||||
uberCount++;
|
||||
} else if (tier === 'UU' || tier === 'NU' || tier === 'NFE' || tier === 'LC') {
|
||||
} else if (nuTiers[tier]) {
|
||||
nuCount++;
|
||||
}
|
||||
|
||||
// Is it Magikarp?
|
||||
if (keys[i] in {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1}) hasShitmon = true;
|
||||
if (template.speciesid in handicapMons) hasShitmon = true;
|
||||
}
|
||||
|
||||
return pokemon;
|
||||
},
|
||||
// Random set generation for Gen 1 Random Battles.
|
||||
randomSet: function (template, i) {
|
||||
if (i === undefined) i = 1;
|
||||
randomSet: function (template, slot) {
|
||||
if (slot === undefined) slot = 1;
|
||||
template = this.getTemplate(template);
|
||||
if (!template.exists) template = this.getTemplate('pikachu'); // Because Gen 1.
|
||||
|
||||
var moveKeys = template.randomBattleMoves;
|
||||
moveKeys = moveKeys.randomize();
|
||||
var movePool = template.randomBattleMoves.slice();
|
||||
var moves = [];
|
||||
var hasType = {};
|
||||
hasType[template.types[0]] = true;
|
||||
|
|
@ -1145,24 +1161,28 @@ exports.BattleScripts = {
|
|||
var counter = {};
|
||||
var setupType = '';
|
||||
|
||||
var j = 0;
|
||||
// Moves that boost Attack:
|
||||
var PhysicalSetup = {
|
||||
swordsdance:1, sharpen:1
|
||||
};
|
||||
// Moves which boost Special Attack:
|
||||
var SpecialSetup = {
|
||||
amnesia:1, growth:1
|
||||
};
|
||||
|
||||
// Add the mandatory move
|
||||
if (template.essentialMove) {
|
||||
moves.push(template.essentialMove);
|
||||
}
|
||||
do {
|
||||
// Choose next 4 moves from learnset/viable moves and add them to moves list:
|
||||
var howMany = (template.essentialMove) ? 3 : 4;
|
||||
while (moves.length < howMany && j < moveKeys.length) {
|
||||
var moveid = toId(moveKeys[j]);
|
||||
j++;
|
||||
while (moves.length < 4 && movePool.length) {
|
||||
var moveid = this.sampleNoReplace(movePool);
|
||||
moves.push(moveid);
|
||||
}
|
||||
|
||||
// Add now the mandatory move
|
||||
if (template.essentialMove) {
|
||||
moves.unshift(template.essentialMove);
|
||||
j++;
|
||||
}
|
||||
|
||||
// Only do move choosing if we have more than four on the moveset...
|
||||
if (moveKeys.length > howMany) {
|
||||
// Only do move choosing if we have backup moves in the pool...
|
||||
if (movePool.length) {
|
||||
hasMove = {};
|
||||
counter = {Physical: 0, Special: 0, Status: 0, physicalsetup: 0, specialsetup: 0};
|
||||
for (var k = 0; k < moves.length; k++) {
|
||||
|
|
@ -1172,10 +1192,10 @@ exports.BattleScripts = {
|
|||
if (!move.damage && !move.damageCallback) {
|
||||
counter[move.category]++;
|
||||
}
|
||||
if ({swordsdance:1, sharpen:1}[moveid]) {
|
||||
if (PhysicalSetup[moveid]) {
|
||||
counter['physicalsetup']++;
|
||||
}
|
||||
if ({amnesia:1, growth:1}[moveid]) {
|
||||
if (SpecialSetup[moveid]) {
|
||||
counter['specialsetup']++;
|
||||
}
|
||||
}
|
||||
|
|
@ -1188,6 +1208,7 @@ exports.BattleScripts = {
|
|||
|
||||
for (var k = 0; k < moves.length; k++) {
|
||||
var moveid = moves[k];
|
||||
if (moveid === template.essentialMove) continue;
|
||||
var move = this.getMove(moveid);
|
||||
var rejected = false;
|
||||
if (hasMove[moveid]) rejected = true;
|
||||
|
|
@ -1300,14 +1321,14 @@ exports.BattleScripts = {
|
|||
break;
|
||||
} // End of switch for moveid
|
||||
}
|
||||
if (rejected && j < moveKeys.length) {
|
||||
if (rejected) {
|
||||
moves.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
counter[move.category]++;
|
||||
} // End of for
|
||||
} // End of the check for more than 4 moves on moveset.
|
||||
} while (moves.length < 4 && j < moveKeys.length);
|
||||
} while (moves.length < 4 && movePool.length);
|
||||
|
||||
var levelScale = {
|
||||
LC: 96,
|
||||
|
|
|
|||
|
|
@ -520,47 +520,54 @@ exports.BattleScripts = {
|
|||
|
||||
return damage;
|
||||
},
|
||||
// Random team generation for Gen 2 Random Battles.
|
||||
randomTeam: function (side) {
|
||||
// Get what we need ready.
|
||||
var keys = [];
|
||||
var pokemonLeft = 0;
|
||||
var pokemon = [];
|
||||
var i = 1;
|
||||
|
||||
// We need to check it's one of the first 251 because formats data are installed onto main format data, not replaced.
|
||||
for (var n in this.data.FormatsData) {
|
||||
if (this.data.FormatsData[n].randomBattleMoves && i < 252) {
|
||||
keys.push(n);
|
||||
}
|
||||
i++;
|
||||
var handicapMons = {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1};
|
||||
var nuTiers = {'UU':1, 'BL':1, 'NFE':1, 'LC':1};
|
||||
var uuTiers = {'NFE':1, 'UU':1, 'BL':1};
|
||||
|
||||
var n = 1;
|
||||
var pokemonPool = [];
|
||||
for (var id in this.data.FormatsData) {
|
||||
// FIXME: Not ES-compliant
|
||||
if (n > 251 || !this.data.FormatsData[id].randomBattleMoves) continue;
|
||||
pokemonPool.push(id);
|
||||
n++;
|
||||
}
|
||||
keys = keys.randomize();
|
||||
|
||||
// Now let's store what we are getting.
|
||||
// Setup storage.
|
||||
var typeCount = {};
|
||||
var uberCount = 0;
|
||||
var nuCount = 0;
|
||||
var hasShitmon = false;
|
||||
|
||||
for (var i = 0; i < keys.length && pokemonLeft < 6; i++) {
|
||||
var template = this.getTemplate(keys[i]);
|
||||
if (!template || !template.name || !template.types) continue;
|
||||
while (pokemonPool.length && pokemonLeft < 6) {
|
||||
var template = this.getTemplate(this.sampleNoReplace(pokemonPool));
|
||||
if (!template.exists) continue;
|
||||
|
||||
// Bias the tiers so you get less shitmons and only one of the two Ubers.
|
||||
// If you have a shitmon, you're covered in OUs and Ubers if possible
|
||||
var tier = template.tier;
|
||||
if (tier === 'LC' && (nuCount > 1 || hasShitmon)) continue;
|
||||
if ((tier === 'NFE' || tier === 'UU' || tier === 'BL') && (hasShitmon || (nuCount > 2 && this.random(1)))) continue;
|
||||
// Unless you have one of the worst mons, in that case we allow luck to give you all Ubers.
|
||||
if (tier === 'Uber' && uberCount >= 1 && !hasShitmon) continue;
|
||||
switch (tier) {
|
||||
case 'LC':
|
||||
if (nuCount > 1 || hasShitmon) continue;
|
||||
break;
|
||||
case 'Uber':
|
||||
// Unless you have one of the worst mons, in that case we allow luck to give you all Ubers.
|
||||
if (uberCount >= 1 && !hasShitmon) continue;
|
||||
break;
|
||||
default:
|
||||
if (uuTiers[tier] && (hasShitmon || (nuCount > 2 && this.random(2) >= 1))) continue;
|
||||
}
|
||||
|
||||
// Limit 2 of any type as well. Diversity and minor weakness count.
|
||||
// Limit 2 of any type. Diversity and minor weakness count.
|
||||
// The second of a same type has halved chance of being added.
|
||||
var types = template.types;
|
||||
var skip = false;
|
||||
for (var t = 0; t < types.length; t++) {
|
||||
if (typeCount[types[t]] > 1 || (typeCount[types[t]] === 1 && this.random(1))) {
|
||||
if (typeCount[types[t]] > 1 || (typeCount[types[t]] === 1 && this.random(2) >= 1)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -568,7 +575,7 @@ exports.BattleScripts = {
|
|||
if (skip) continue;
|
||||
|
||||
// The set passes the limitations.
|
||||
var set = this.randomSet(template, i);
|
||||
var set = this.randomSet(template, pokemon.length);
|
||||
pokemon.push(set);
|
||||
|
||||
// Now let's increase the counters. First, the Pokémon left.
|
||||
|
|
@ -576,7 +583,7 @@ exports.BattleScripts = {
|
|||
|
||||
// Type counter.
|
||||
for (var t = 0; t < types.length; t++) {
|
||||
if (types[t] in typeCount) {
|
||||
if (typeCount[types[t]]) {
|
||||
typeCount[types[t]]++;
|
||||
} else {
|
||||
typeCount[types[t]] = 1;
|
||||
|
|
@ -586,24 +593,23 @@ exports.BattleScripts = {
|
|||
// Increment type bias counters.
|
||||
if (tier === 'Uber') {
|
||||
uberCount++;
|
||||
} else if (tier === 'UU' || tier === 'BL' || tier === 'NFE' || tier === 'LC') {
|
||||
} else if (nuTiers[tier]) {
|
||||
nuCount++;
|
||||
}
|
||||
|
||||
// Is it a shitmon?
|
||||
if (keys[i] in {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1}) hasShitmon = true;
|
||||
if (handicapMons[template.speciesid]) hasShitmon = true;
|
||||
}
|
||||
|
||||
return pokemon;
|
||||
},
|
||||
// Random set generation for Gen 2 Random Battles.
|
||||
randomSet: function (template, i) {
|
||||
if (i === undefined) i = 1;
|
||||
randomSet: function (template, slot) {
|
||||
if (slot === undefined) slot = 1;
|
||||
template = this.getTemplate(template);
|
||||
if (!template.exists) template = this.getTemplate('unown');
|
||||
|
||||
var moveKeys = template.randomBattleMoves;
|
||||
moveKeys = moveKeys.randomize();
|
||||
var movePool = template.randomBattleMoves.slice();
|
||||
var moves = [];
|
||||
var hasType = {};
|
||||
hasType[template.types[0]] = true;
|
||||
|
|
@ -614,7 +620,15 @@ exports.BattleScripts = {
|
|||
var item = 'leftovers';
|
||||
var ivs = {hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30};
|
||||
|
||||
var j = 0;
|
||||
// Moves that boost Attack:
|
||||
var PhysicalSetup = {
|
||||
swordsdance:1, sharpen:1
|
||||
};
|
||||
// Moves which boost Special Attack:
|
||||
var SpecialSetup = {
|
||||
amnesia:1, growth:1
|
||||
};
|
||||
|
||||
do {
|
||||
// Keep track of all moves we have:
|
||||
hasMove = {};
|
||||
|
|
@ -627,8 +641,8 @@ exports.BattleScripts = {
|
|||
}
|
||||
|
||||
// Choose next 4 moves from learnset/viable moves and add them to moves list:
|
||||
while (moves.length < 4 && moveKeys.length) {
|
||||
var moveid = this.sampleNoReplace(moveKeys);
|
||||
while (moves.length < 4 && movePool.length) {
|
||||
var moveid = this.sampleNoReplace(movePool);
|
||||
if (moveid.substr(0, 11) === 'hiddenpower') {
|
||||
if (hasMove['hiddenpower']) continue;
|
||||
hasMove['hiddenpower'] = true;
|
||||
|
|
@ -645,10 +659,10 @@ exports.BattleScripts = {
|
|||
if (!move.damage && !move.damageCallback) {
|
||||
counter[move.category]++;
|
||||
}
|
||||
if ({swordsdance:1, sharpen:1}[moveid]) {
|
||||
if (PhysicalSetup[moveid]) {
|
||||
counter['physicalsetup']++;
|
||||
}
|
||||
if ({amnesia:1, growth:1}[moveid]) {
|
||||
if (SpecialSetup[moveid]) {
|
||||
counter['specialsetup']++;
|
||||
}
|
||||
}
|
||||
|
|
@ -774,13 +788,13 @@ exports.BattleScripts = {
|
|||
break;
|
||||
} // End of switch for moveid
|
||||
}
|
||||
if (rejected && j < moveKeys.length - 1) {
|
||||
if (rejected && movePool.length) {
|
||||
moves.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
counter[move.category]++;
|
||||
} // End of for
|
||||
} while (moves.length < 4 && j < moveKeys.length);
|
||||
} while (moves.length < 4 && movePool.length);
|
||||
|
||||
// Add specific items.
|
||||
switch (template.species) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
exports.BattleScripts = {
|
||||
gen: 5,
|
||||
randomSet: function (template, i) {
|
||||
if (i === undefined) i = 1;
|
||||
randomSet: function (template, slot) {
|
||||
if (slot === undefined) slot = 1;
|
||||
template = this.getTemplate(template);
|
||||
var name = template.name;
|
||||
|
||||
|
|
@ -11,10 +11,10 @@ exports.BattleScripts = {
|
|||
|
||||
var stack = 'Template incompatible with random battles: ' + name;
|
||||
var fakeErr = {stack: stack};
|
||||
require('../crashlogger.js')(fakeErr, 'The randbat set generator');
|
||||
require('./../../crashlogger.js')(fakeErr, 'The randbat set generator');
|
||||
}
|
||||
|
||||
var moveKeys = (template.randomBattleMoves || Object.keys(template.learnset)).randomize();
|
||||
var movePool = (template.randomBattleMoves ? template.randomBattleMoves.slice() : Object.keys(template.learnset));
|
||||
var moves = [];
|
||||
var ability = '';
|
||||
var item = '';
|
||||
|
|
@ -49,12 +49,10 @@ exports.BattleScripts = {
|
|||
var counter = {};
|
||||
var setupType = '';
|
||||
|
||||
var j = 0;
|
||||
do {
|
||||
// Choose next 4 moves from learnset/viable moves and add them to moves list:
|
||||
while (moves.length < 4 && j < moveKeys.length) {
|
||||
var moveid = toId(moveKeys[j]);
|
||||
j++;
|
||||
while (moves.length < 4 && movePool.length) {
|
||||
var moveid = this.sampleNoReplace(movePool);
|
||||
if (moveid.substr(0, 11) === 'hiddenpower') {
|
||||
if (!hasMove['hiddenpower']) {
|
||||
hasMove['hiddenpower'] = true;
|
||||
|
|
@ -404,7 +402,7 @@ exports.BattleScripts = {
|
|||
}
|
||||
|
||||
// Remove rejected moves from the move list.
|
||||
if (rejected && j < moveKeys.length) {
|
||||
if (rejected && movePool.length) {
|
||||
moves.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -417,7 +415,7 @@ exports.BattleScripts = {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (j < moveKeys.length && moves.length === 4) {
|
||||
if (movePool.length && moves.length === 4) {
|
||||
// Move post-processing:
|
||||
if (damagingMoves.length === 0) {
|
||||
// Have a 60% chance of rejecting one move at random:
|
||||
|
|
@ -475,7 +473,7 @@ exports.BattleScripts = {
|
|||
if (!isStab) moves.splice(Math.floor(Math.random() * moves.length), 1);
|
||||
}
|
||||
}
|
||||
} while (moves.length < 4 && j < moveKeys.length);
|
||||
} while (moves.length < 4 && movePool.length);
|
||||
|
||||
// any moveset modification goes here
|
||||
//moves[0] = 'Safeguard';
|
||||
|
|
@ -666,14 +664,13 @@ exports.BattleScripts = {
|
|||
item = 'Life Orb';
|
||||
} else if (ability === 'Unburden' && (counter['Physical'] || counter['Special'])) {
|
||||
// Give Unburden mons a random Gem of the type of one of their damaging moves
|
||||
var shuffledMoves = moves.randomize();
|
||||
for (var m in shuffledMoves) {
|
||||
var move = this.getMove(shuffledMoves[m]);
|
||||
if (move.basePower || move.basePowerCallback) {
|
||||
item = move.type + ' Gem';
|
||||
break;
|
||||
}
|
||||
var eligibleTypes = [];
|
||||
for (var i = 0; i < moves.length; i++) {
|
||||
var move = this.getMove(moves[i]);
|
||||
if (!move.basePower && !move.basePowerCallback) continue;
|
||||
eligibleTypes.push(move.type);
|
||||
}
|
||||
item = eligibleTypes[this.random(eligibleTypes.length)] + ' Gem';
|
||||
} else if (ability === 'Guts') {
|
||||
if (hasMove['drainpunch']) {
|
||||
item = 'Flame Orb';
|
||||
|
|
@ -711,14 +708,13 @@ exports.BattleScripts = {
|
|||
} else if ((hasMove['eruption'] || hasMove['waterspout']) && !counter['Status']) {
|
||||
item = 'Choice Scarf';
|
||||
} else if (hasMove['substitute'] && hasMove['reversal']) {
|
||||
var shuffledMoves = moves.randomize();
|
||||
for (var m in shuffledMoves) {
|
||||
var move = this.getMove(shuffledMoves[m]);
|
||||
if (move.basePower || move.basePowerCallback) {
|
||||
item = move.type + ' Gem';
|
||||
break;
|
||||
}
|
||||
var eligibleTypes = [];
|
||||
for (var i = 0; i < moves.length; i++) {
|
||||
var move = this.getMove(moves[i]);
|
||||
if (!move.basePower && !move.basePowerCallback) continue;
|
||||
eligibleTypes.push(move.type);
|
||||
}
|
||||
item = eligibleTypes[this.random(eligibleTypes.length)] + ' Gem';
|
||||
} else if (hasMove['substitute'] || hasMove['detect'] || hasMove['protect'] || ability === 'Moody') {
|
||||
item = 'Leftovers';
|
||||
} else if ((hasMove['flail'] || hasMove['reversal']) && !hasMove['endure'] && ability !== 'Sturdy') {
|
||||
|
|
@ -735,7 +731,7 @@ exports.BattleScripts = {
|
|||
item = 'Life Orb';
|
||||
} else if (counter.Physical + counter.Special >= 4) {
|
||||
item = 'Expert Belt';
|
||||
} else if (i === 0 && ability !== 'Sturdy' && !counter['recoil']) {
|
||||
} else if (slot === 0 && ability !== 'Sturdy' && !counter['recoil']) {
|
||||
item = 'Focus Sash';
|
||||
} else if (hasMove['outrage']) {
|
||||
item = 'Lum Berry';
|
||||
|
|
@ -813,19 +809,19 @@ exports.BattleScripts = {
|
|||
};
|
||||
},
|
||||
randomTeam: function (side) {
|
||||
var keys = [];
|
||||
var pokemonLeft = 0;
|
||||
var pokemon = [];
|
||||
for (var i in this.data.FormatsData) {
|
||||
if (this.data.FormatsData[i].randomBattleMoves && this.getTemplate(i).gen < 6) {
|
||||
keys.push(i);
|
||||
}
|
||||
|
||||
var pokemonPool = [];
|
||||
for (var id in this.data.FormatsData) {
|
||||
var template = this.getTemplate(id);
|
||||
if (template.gen >= this.gen || !template.randomBattleMoves) continue;
|
||||
pokemonPool.push(id);
|
||||
}
|
||||
keys = keys.randomize();
|
||||
|
||||
// PotD stuff
|
||||
var potd = {};
|
||||
if ('Rule:potd' in this.getBanlistTable(this.getFormat())) {
|
||||
var potd;
|
||||
if (Config.potd && 'Rule:potd' in this.getBanlistTable(this.getFormat())) {
|
||||
potd = this.getTemplate(Config.potd);
|
||||
}
|
||||
|
||||
|
|
@ -834,52 +830,68 @@ exports.BattleScripts = {
|
|||
var uberCount = 0;
|
||||
var nuCount = 0;
|
||||
|
||||
for (var i = 0; i < keys.length && pokemonLeft < 6; i++) {
|
||||
var template = this.getTemplate(keys[i]);
|
||||
if (!template || !template.name || !template.types) continue;
|
||||
while (pokemonPool.length && pokemonLeft < 6) {
|
||||
var template = this.getTemplate(this.sampleNoReplace(pokemonPool));
|
||||
if (!template.exists) continue;
|
||||
|
||||
// Not available on BW
|
||||
if (template.species === 'Pichu-Spiky-eared') continue;
|
||||
|
||||
var tier = template.tier;
|
||||
// This tries to limit the amount of Ubers and NUs on one team to promote "fun":
|
||||
// LC Pokemon have a hard limit in place at 2; NFEs/NUs/Ubers are also limited to 2 but have a 20% chance of being added anyway.
|
||||
// LC/NFE/NU Pokemon all share a counter (so having one of each would make the counter 3), while Ubers have a counter of their own.
|
||||
if (tier === 'LC' && nuCount > 1) continue;
|
||||
if ((tier === 'NFE' || tier === 'NU') && nuCount > 1 && Math.random() * 5 > 1) continue;
|
||||
if (tier === 'Uber' && uberCount > 1 && Math.random() * 5 > 1) continue;
|
||||
switch (tier) {
|
||||
case 'LC':
|
||||
if (nuCount > 1) continue;
|
||||
break;
|
||||
case 'NFE': case 'NU':
|
||||
if (nuCount > 1 && this.random(5) >= 1) continue;
|
||||
break;
|
||||
case 'Uber':
|
||||
if (uberCount > 1 && this.random(5) >= 1) continue;
|
||||
break;
|
||||
case 'CAP':
|
||||
// CAPs have 20% the normal rate
|
||||
if (this.random(5) >= 1) continue;
|
||||
}
|
||||
|
||||
// CAPs have 20% the normal rate
|
||||
if (tier === 'CAP' && Math.random() * 5 > 1) continue;
|
||||
// Arceus formes have 1/17 the normal rate each (so Arceus as a whole has a normal rate)
|
||||
if (keys[i].substr(0, 6) === 'arceus' && Math.random() * 17 > 1) continue;
|
||||
// Basculin formes have 1/2 the normal rate each (so Basculin as a whole has a normal rate)
|
||||
if (keys[i].substr(0, 8) === 'basculin' && Math.random() * 2 > 1) continue;
|
||||
// Not available on BW
|
||||
if (template.species === 'Pichu-Spiky-eared') continue;
|
||||
// Adjust rate for species with multiple formes
|
||||
switch (template.baseSpecies) {
|
||||
case 'Arceus':
|
||||
if (this.random(17) >= 1) continue;
|
||||
break;
|
||||
case 'Basculin':
|
||||
if (this.random(2) >= 1) continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// Limit 2 of any type
|
||||
var types = template.types;
|
||||
var skip = false;
|
||||
for (var t = 0; t < types.length; t++) {
|
||||
if (typeCount[types[t]] > 1 && Math.random() * 5 > 1) {
|
||||
if (typeCount[types[t]] > 1 && this.random(5) >= 1) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
if (potd && potd.name && potd.types) {
|
||||
if (potd && potd.exists) {
|
||||
// The Pokemon of the Day belongs in slot 2
|
||||
if (i === 1) {
|
||||
if (pokemon.length === 1) {
|
||||
template = potd;
|
||||
if (template.species === 'Magikarp') {
|
||||
template.randomBattleMoves = {magikarpsrevenge:1, splash:1, bounce:1};
|
||||
template.randomBattleMoves = ['magikarpsrevenge', 'splash', 'bounce'];
|
||||
} else if (template.species === 'Delibird') {
|
||||
template.randomBattleMoves = {present:1, bestow:1};
|
||||
template.randomBattleMoves = ['present', 'bestow'];
|
||||
}
|
||||
} else if (template.species === potd.species) {
|
||||
continue; // No, thanks, I've already got one
|
||||
}
|
||||
}
|
||||
|
||||
var set = this.randomSet(template, i);
|
||||
var set = this.randomSet(template, pokemon.length);
|
||||
|
||||
// Limit 1 of any type combination
|
||||
var typeCombo = types.join();
|
||||
|
|
@ -892,8 +904,10 @@ exports.BattleScripts = {
|
|||
// Okay, the set passes, add it to our team
|
||||
pokemon.push(set);
|
||||
|
||||
// Now that our Pokemon has passed all checks, we can increment our counters
|
||||
pokemonLeft++;
|
||||
// Now that our Pokemon has passed all checks, we can increment the type counter
|
||||
|
||||
// Increment type counters
|
||||
for (var t = 0; t < types.length; t++) {
|
||||
if (types[t] in typeCount) {
|
||||
typeCount[types[t]]++;
|
||||
|
|
@ -902,7 +916,8 @@ exports.BattleScripts = {
|
|||
}
|
||||
}
|
||||
typeComboCount[typeCombo] = 1;
|
||||
// Increment Uber/NU counter
|
||||
|
||||
// Increment Uber/NU counters
|
||||
if (tier === 'Uber') {
|
||||
uberCount++;
|
||||
} else if (tier === 'NU' || tier === 'NFE' || tier === 'LC') {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user