Fix validator precedence bugs

This commit is contained in:
Guangcong Luo 2021-04-30 00:45:12 -07:00
parent 751ab2c587
commit 68edac35b5
3 changed files with 33 additions and 20 deletions

View File

@ -97,6 +97,11 @@ export class RuleTable extends Map<string, string> {
return this.has(`*pokemontag:allpokemon`);
}
/**
* - non-empty string: banned, string is the reason
* - '': whitelisted
* - null: neither whitelisted nor banned
*/
check(thing: string, setHas: {[id: string]: true} | null = null) {
if (this.has(`+${thing}`)) return '';
if (setHas) setHas[thing] = true;
@ -619,8 +624,6 @@ export class DexFormats {
getTagRules(ruleTable: RuleTable) {
const tagRules = [];
const specificExistenceTagRules = [];
const existenceTagRules = [];
for (const ruleid of ruleTable.keys()) {
if (/^[+*-]pokemontag:/.test(ruleid)) {
const banid = ruleid.slice(12);
@ -629,25 +632,14 @@ export class DexFormats {
banid === 'allabilities' || banid === 'allnatures'
) {
// hardcoded and not a part of the ban rule system
} else if (!ruleid.startsWith('+') && (
banid === 'past' || banid === 'future' || banid === 'lgpe' ||
banid === 'unobtainable' || banid === 'cap' || banid === 'custom'
)) {
specificExistenceTagRules.push(ruleid);
} else if (!ruleid.startsWith('+') && banid === 'nonexistent') {
existenceTagRules.push(ruleid);
} else {
tagRules.push(ruleid);
}
} else if ('+*-'.includes(ruleid.charAt(0)) && ruleid.slice(1) === 'nonexistent') {
if (!ruleid.startsWith('+')) {
existenceTagRules.push(ruleid.charAt(0) + 'pokemontag:nonexistent');
} else {
tagRules.push('+pokemontag:nonexistent');
}
tagRules.push(ruleid.charAt(0) + 'pokemontag:nonexistent');
}
}
ruleTable.tagRules = [...tagRules, ...existenceTagRules, ...specificExistenceTagRules].reverse();
ruleTable.tagRules = tagRules.reverse();
}
validateRule(rule: string, format: Format | null = null) {

View File

@ -1334,15 +1334,25 @@ export class TeamValidator {
}
}
// We can't return here because the `-nonexistent` rule is a bit
// complicated in terms of what trumps it. We don't want e.g.
// +Mythical to unban Shaymin in Gen 1, for instance.
const nonexistentCheck = Tags.nonexistent.genericFilter!(tierSpecies) && ruleTable.check('nonexistent');
const EXISTENCE_TAG = ['past', 'future', 'lgpe', 'unobtainable', 'cap', 'custom', 'nonexistent'];
console.log(ruleTable.tagRules);
for (const ruleid of ruleTable.tagRules) {
if (ruleid.startsWith('*')) continue;
const tagid = ruleid.slice(12);
const tag = Tags[tagid];
if ((tag.speciesFilter || tag.genericFilter)!(tierSpecies)) {
if (ruleid.startsWith('+')) return null;
if (EXISTENCE_TAG.includes(tagid)) {
const existenceTag = EXISTENCE_TAG.includes(tagid);
if (ruleid.startsWith('+')) {
// we want rules like +CAP to trump -Nonexistent, but most tags shouldn't
if (!existenceTag && nonexistentCheck) continue;
return null;
}
if (existenceTag) {
if (tierSpecies.isNonstandard === 'Past' || tierSpecies.isNonstandard === 'Future') {
return `${tierSpecies.name} does not exist in Gen ${dex.gen}.`;
}
@ -1363,6 +1373,11 @@ export class TeamValidator {
}
}
if (nonexistentCheck) {
return `Despite being whitelisted by a tag, ${tierSpecies.name} does not exist in this game.`;
}
if (nonexistentCheck === '') return null;
// Special casing for Pokemon that can Gmax, but their Gmax factor cannot be legally obtained
if (tierSpecies.gmaxUnreleased && set.gigantamax) {
banReason = ruleTable.check('pokemontag:unobtainable');

View File

@ -767,16 +767,22 @@ describe('Team Validator', function () {
it('should support banning/unbanning tag combinations', function () {
let team = [
{species: 'Blaziken-Mega', ability: 'Speed Boost', moves: ['protect'], evs: {hp: 1}},
{species: 'Crucibelle-Mega', ability: 'Regenerator', moves: ['protect'], evs: {hp: 1}},
];
let illegal = TeamValidator.get('gen8customgame@@@-nonexistent,+mega').validateTeam(team);
assert(illegal, "Nonexistent should override all tags that aren't existence-related");
team = [
{species: 'Blaziken-Mega', ability: 'Speed Boost', moves: ['protect'], evs: {hp: 1}},
{species: 'Crucibelle-Mega', ability: 'Regenerator', moves: ['protect'], evs: {hp: 1}},
];
illegal = TeamValidator.get('gen8customgame@@@+mega,-nonexistent').validateTeam(team);
assert(illegal, "Nonexistent should override all tags that aren't existence-related");
team = [
{species: 'Crucibelle-Mega', ability: 'Regenerator', moves: ['protect'], evs: {hp: 1}},
];
illegal = TeamValidator.get('gen8customgame@@@-nonexistent,+crucibellemega').validateTeam(team);
assert.equal(illegal, null, "Nonexistent should override all tags that aren't existence-related");
});
it('should allow moves to be banned', function () {