@@ -632,23 +632,33 @@ function getMod(target: string) {
632
632
633
633
function getRule ( target : string ) {
634
634
const arr = target . split ( ',' ) . map ( x => x . trim ( ) ) ;
635
- const ruleTerm = arr . find ( x => {
636
- const sanitizedStr = x . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 = ] + / g, '' ) ;
637
- return sanitizedStr . startsWith ( 'rule=' ) && Dex . data . Rulesets [ toID ( sanitizedStr . split ( '=' ) [ 1 ] ) ] ;
638
- } ) ;
635
+ const ruleTerms : string [ ] = [ ] ;
636
+ for ( const term of arr ) {
637
+ const sanitizedStr = term . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 = ] + / g, '' ) ;
638
+ if ( sanitizedStr . startsWith ( 'rule=' ) && Dex . data . Rulesets [ toID ( sanitizedStr . split ( '=' ) [ 1 ] ) ] ) {
639
+ ruleTerms . push ( term ) ;
640
+ }
641
+ }
639
642
const count = arr . filter ( x => {
640
643
const sanitizedStr = x . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 = ] + / g, '' ) ;
641
644
return sanitizedStr . startsWith ( 'rule=' ) ;
642
645
} ) . length ;
643
- if ( ruleTerm ) arr . splice ( arr . indexOf ( ruleTerm ) , 1 ) ;
644
- return { splitTarget : arr , usedRule : ruleTerm ? toID ( ruleTerm . split ( / ? = ? / ) [ 1 ] ) : '' , count } ;
646
+ if ( ruleTerms . length > 0 ) {
647
+ for ( const rule of ruleTerms ) {
648
+ arr . splice ( arr . indexOf ( rule ) , 1 ) ;
649
+ }
650
+ }
651
+ return { splitTarget : arr , usedRules : ruleTerms . map (
652
+ x => x . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 = ] + / g, '' ) . split ( 'rule=' ) [ 1 ] ) , count } ;
645
653
}
646
654
647
- function prepareDexsearchValidator ( usedMod : string | undefined , rule : FormatData , nationalSearch : boolean | null ) {
655
+ function prepareDexsearchValidator ( usedMod : string | undefined , rules : FormatData [ ] , nationalSearch : boolean | null ) {
648
656
const format = Object . entries ( Dex . data . Rulesets ) . find ( ( [ a , f ] ) => f . mod === usedMod ) ?. [ 1 ] . name || 'gen9ou' ;
649
657
const ruleTable = Dex . formats . getRuleTable ( Dex . formats . get ( format ) ) ;
650
658
const additionalRules = [ ] ;
651
- if ( rule && ! ruleTable . has ( toID ( rule . name ) ) ) additionalRules . push ( toID ( rule . name ) ) ;
659
+ for ( const rule of rules ) {
660
+ if ( ! ruleTable . has ( toID ( rule . name ) ) ) additionalRules . push ( toID ( rule . name ) ) ;
661
+ }
652
662
if ( nationalSearch && ! ruleTable . has ( 'natdexmod' ) ) additionalRules . push ( 'natdexmod' ) ;
653
663
if ( nationalSearch && ruleTable . valueRules . has ( 'minsourcegen' ) ) additionalRules . push ( '!!minsourcegen=3' ) ;
654
664
return TeamValidator . get ( `${ format } ${ additionalRules . length ? `@@@${ additionalRules . join ( ',' ) } ` : '' } ` ) ;
@@ -657,28 +667,23 @@ function prepareDexsearchValidator(usedMod: string | undefined, rule: FormatData
657
667
function runDexsearch ( target : string , cmd : string , canAll : boolean , message : string , isTest : boolean ) {
658
668
const searches : DexOrGroup [ ] = [ ] ;
659
669
const { splitTarget : remainingTargets , usedMod, count : modCount } = getMod ( target ) ;
660
- const { splitTarget, usedRule , count : ruleCount } = getRule ( remainingTargets . join ( ',' ) ) ;
661
- if ( modCount > 1 || ruleCount > 1 ) {
662
- return { error : `You can't run searches for multiple mods or rules .` } ;
670
+ const { splitTarget, usedRules } = getRule ( remainingTargets . join ( ',' ) ) ;
671
+ if ( modCount > 1 ) {
672
+ return { error : `You can't run searches for multiple mods.` } ;
663
673
}
664
674
for ( const str of splitTarget ) {
665
675
const sanatizedStr = str . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 = ] + / g, '' ) ;
666
676
if ( sanatizedStr . startsWith ( 'mod=' ) || sanatizedStr . startsWith ( 'rule=' ) ) {
667
- return { error : `Invalid mod or rule, see /dexsearchhelp.` } ;
668
- }
669
- }
670
- const ruleType = [ ] ;
671
- for ( const key of Object . keys ( supportedDexsearchRules ) ) {
672
- if ( supportedDexsearchRules [ key ] . includes ( usedRule ) ) {
673
- ruleType . push ( key ) ;
674
- break ;
677
+ return { error : `${ sanatizedStr . split ( '=' ) [ 1 ] } is an invalid mod or rule, see /dexsearchhelp.` } ;
675
678
}
676
679
}
677
- if ( usedRule && ! ruleType . length ) {
678
- return { error : `Invalid rule, see /dexsearchhelp` } ;
679
- }
680
680
const mod = Dex . mod ( usedMod || 'base' ) ;
681
- const rule = Dex . data . Rulesets [ usedRule ] ;
681
+ const rules : FormatData [ ] = [ ] ;
682
+ for ( const rule of usedRules ) {
683
+ if ( ! dexsearchHelpRules . includes ( rule ) )
684
+ return { error : `${ rule } is an unsupported rule, see /dexsearchhelp` } ;
685
+ rules . push ( Dex . data . Rulesets [ rule ] ) ;
686
+ }
682
687
683
688
const allTiers : { [ k : string ] : TierTypes . Singles | TierTypes . Other } = Object . assign ( Object . create ( null ) , {
684
689
anythinggoes : 'AG' , ag : 'AG' ,
@@ -1205,28 +1210,30 @@ function runDexsearch(target: string, cmd: string, canAll: boolean, message: str
1205
1210
// These only ever get accessed if there are moves or banlists to filter by.
1206
1211
let validator ;
1207
1212
let pokemonSource ;
1208
- if ( Object . values ( searches ) . some ( search => Object . keys ( search . moves ) . length !== 0 ) ||
1209
- ruleType . includes ( 'movevalidation' ) || ruleType . includes ( 'banlist' ) ) {
1210
- validator = prepareDexsearchValidator ( usedMod , rule , nationalSearch ) ;
1213
+ if ( Object . values ( searches ) . some ( search => ! ! Object . keys ( search . moves ) . length ) ) {
1214
+ validator = prepareDexsearchValidator ( usedMod , rules , nationalSearch ) ;
1211
1215
}
1212
1216
1213
1217
const dex : { [ k : string ] : Species } = { } ;
1214
- for ( const species of mod . species . all ( ) ) {
1218
+ for ( let species of mod . species . all ( ) ) {
1215
1219
const megaSearchResult = megaSearch === null || megaSearch === ! ! species . isMega ;
1216
1220
const gmaxSearchResult = gmaxSearch === null || gmaxSearch === species . name . endsWith ( '-Gmax' ) ;
1217
1221
const fullyEvolvedSearchResult = fullyEvolvedSearch === null || fullyEvolvedSearch !== species . nfe ;
1218
1222
const restrictedSearchResult = restrictedSearch === null ||
1219
1223
restrictedSearch === species . tags . includes ( 'Restricted Legendary' ) ;
1220
- let ruleResult = ! rule ?. banlist ?. includes ( species . name ) ;
1221
1224
1222
1225
/**
1223
1226
* Not every ruleset with an onValidateSet function is specifically to exclude mons.
1224
1227
* In the current list of supported rules only the Pokedex rules do such which is
1225
1228
* why this step is ignored for other rules. Rules can be added for this functionality
1226
1229
* in the supportedDexSearchTypes mapping at the top of the function.
1227
1230
*/
1228
- if ( ruleResult && validator && ruleType . includes ( 'banlist' ) && rule ?. onValidateSet ) {
1229
- ruleResult = ! rule . onValidateSet . call ( validator ,
1231
+ let ruleResult = true ;
1232
+ for ( const rule of rules ) {
1233
+ if ( ! ruleResult ) break ;
1234
+ if ( ! supportedDexsearchRules [ 'banlist' ] . includes ( toID ( rule . name ) ) ) continue ;
1235
+ if ( ! validator ) validator = prepareDexsearchValidator ( usedMod , rules , nationalSearch ) ;
1236
+ ruleResult = ! rule . onValidateSet ?. call ( validator ,
1230
1237
{ name : species . name , species : species . id } as PokemonSet , validator . format , { } , { } ) ;
1231
1238
}
1232
1239
@@ -1243,8 +1250,11 @@ function runDexsearch(target: string, cmd: string, canAll: boolean, message: str
1243
1250
restrictedSearchResult &&
1244
1251
ruleResult
1245
1252
) {
1246
- dex [ species . id ] = rule ?. onModifySpecies ?. call ( { dex : mod , clampIntRange : Utils . clampIntRange , toID } as Battle ,
1247
- species ) || species ;
1253
+ for ( const rule of rules ) {
1254
+ species = rule ?. onModifySpecies ?. call ( { dex : mod , clampIntRange : Utils . clampIntRange , toID } as Battle ,
1255
+ species ) || species ;
1256
+ }
1257
+ dex [ species . id ] = species ;
1248
1258
}
1249
1259
}
1250
1260
@@ -1418,19 +1428,29 @@ function runDexsearch(target: string, cmd: string, canAll: boolean, message: str
1418
1428
}
1419
1429
if ( matched ) continue ;
1420
1430
1421
- for ( const move of altsMoves ) {
1422
- pokemonSource = validator ?. allSources ( ) ;
1423
- // Match rule must be tried first due to NOT searches providing failed hits
1424
- // when only checking vanilla legality first.
1425
- const matchRule = ruleType . includes ( 'movevalidation' ) &&
1426
- ! validator ?. omCheckCanLearn ( move , dex [ mon ] , pokemonSource , { } ) === alts . moves [ move . id ] ;
1427
- const matchNormally = ! matchRule && ! validator ?. checkCanLearn ( move , dex [ mon ] , pokemonSource ) === alts . moves [ move . id ] ;
1431
+ if ( validator ) {
1432
+ for ( const move of altsMoves ) {
1433
+ pokemonSource = validator . allSources ( ) ;
1434
+ const isNotSearch = ! alts . moves [ move . id ] ;
1435
+
1436
+ let matchRule = false ;
1437
+ let numMoveValidationRules = 0 ;
1438
+ for ( const rule of rules ) {
1439
+ if ( ! supportedDexsearchRules [ 'movevalidation' ] . includes ( toID ( rule . name ) ) ) continue ;
1440
+ else numMoveValidationRules ++ ;
1441
+ matchRule = ! rule . checkCanLearn ?. call (
1442
+ validator , move , dex [ mon ] , pokemonSource , { } as PokemonSet ) === ! isNotSearch ;
1443
+ if ( matchRule === ! isNotSearch ) break ;
1444
+ }
1445
+ const matchNormally = ! validator . checkCanLearn ( move , dex [ mon ] , pokemonSource ) === ! isNotSearch ;
1428
1446
1429
- if ( matchNormally || matchRule ) {
1430
- matched = true ;
1431
- break ;
1447
+ if ( ( ! isNotSearch && ( matchNormally || ( numMoveValidationRules > 0 && matchRule ) ) ) ||
1448
+ ( isNotSearch && matchNormally && ( numMoveValidationRules === 0 || matchRule ) ) ) {
1449
+ matched = true ;
1450
+ break ;
1451
+ }
1452
+ if ( pokemonSource && ! pokemonSource . size ( ) ) break ;
1432
1453
}
1433
- if ( pokemonSource && ! pokemonSource . size ( ) ) break ;
1434
1454
}
1435
1455
if ( matched ) continue ;
1436
1456
@@ -1441,9 +1461,9 @@ function runDexsearch(target: string, cmd: string, canAll: boolean, message: str
1441
1461
const stat = sort ?. slice ( 0 , - 1 ) ;
1442
1462
1443
1463
function getSortValue ( species : Species ) {
1444
- if ( ! stat ) return 0 ;
1445
-
1446
- if ( stat === 'bst' ) {
1464
+ if ( ! stat ) {
1465
+ return 0 ;
1466
+ } else if ( stat === 'bst' ) {
1447
1467
return species . bst ;
1448
1468
} else if ( stat === 'weight' ) {
1449
1469
return species . weighthg ;
@@ -1463,12 +1483,12 @@ function runDexsearch(target: string, cmd: string, canAll: boolean, message: str
1463
1483
mon . baseSpecies !== "Pikachu" ;
1464
1484
const maskForm = mon . baseSpecies === "Ogerpon" && ! mon . forme . endsWith ( "Tera" ) ;
1465
1485
const allowGmax = ( gmaxSearch || tierSearch ) ;
1466
- if ( ! isRegionalForm && ! maskForm && mon . baseSpecies && results . includes ( Dex . species . get ( mon . baseSpecies ) ) &&
1467
- getSortValue ( mon ) === getSortValue ( Dex . species . get ( mon . baseSpecies ) ) ) continue ;
1486
+ if ( ! isRegionalForm && ! maskForm && mon . baseSpecies && results . includes ( mod . species . get ( mon . baseSpecies ) ) &&
1487
+ getSortValue ( mon ) === getSortValue ( mod . species . get ( mon . baseSpecies ) ) ) continue ;
1468
1488
const teraFormeChangesFrom = mon . forme . endsWith ( "Tera" ) ? ! Array . isArray ( mon . battleOnly ) ?
1469
1489
mon . battleOnly ! : null : null ;
1470
- if ( teraFormeChangesFrom && results . includes ( Dex . species . get ( teraFormeChangesFrom ) ) &&
1471
- getSortValue ( mon ) === getSortValue ( Dex . species . get ( teraFormeChangesFrom ) ) ) continue ;
1490
+ if ( teraFormeChangesFrom && results . includes ( mod . species . get ( teraFormeChangesFrom ) ) &&
1491
+ getSortValue ( mon ) === getSortValue ( mod . species . get ( teraFormeChangesFrom ) ) ) continue ;
1472
1492
if ( mon . isNonstandard === 'Gigantamax' && ! allowGmax ) continue ;
1473
1493
results . push ( mon ) ;
1474
1494
}
0 commit comments