File size: 35,992 Bytes
5c2ed06
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var randombattles_exports = {};
__export(randombattles_exports, {
  STAT_NAMES: () => STAT_NAMES,
  commands: () => commands,
  formatNature: () => formatNature
});
module.exports = __toCommonJS(randombattles_exports);
var import_lib = require("../../../lib");
function getHTMLCriteriaDescription(criteria) {
  const format = (list) => list.map((m) => import_lib.Utils.html`<strong>${m.name}</strong>`);
  const parts = [];
  const { moves, ability, item, nature, teraType } = criteria;
  if (moves.mustHave.length) {
    parts.push(`had the move${Chat.plural(moves.mustHave)} ${Chat.toListString(format(moves.mustHave))}`);
  }
  if (moves.mustNotHave.length) {
    parts.push(`did not have the move${Chat.plural(moves.mustNotHave)} ${Chat.toListString(format(moves.mustNotHave), "or")}`);
  }
  if (ability.mustHave) {
    parts.push(import_lib.Utils.html`had the ability <strong>${ability.mustHave.name}</strong>`);
  }
  if (ability.mustNotHave.length) {
    parts.push(`did not have the ${Chat.plural(ability.mustNotHave, "abilities", "ability")} ${Chat.toListString(format(ability.mustNotHave), "or")}`);
  }
  if (item.mustHave) {
    parts.push(import_lib.Utils.html`had the item <strong>${item.mustHave.name}</strong>`);
  }
  if (item.mustNotHave.length) {
    parts.push(`did not have the item${Chat.plural(item.mustNotHave)} ${Chat.toListString(format(item.mustNotHave), "or")}`);
  }
  if (nature.mustHave) {
    parts.push(import_lib.Utils.html`had the nature <strong>${nature.mustHave.name}</strong>`);
  }
  if (nature.mustNotHave.length) {
    parts.push(`did not have the nature${Chat.plural(nature.mustNotHave)} ${Chat.toListString(format(nature.mustNotHave), "or")}`);
  }
  if (teraType.mustHave) {
    parts.push(import_lib.Utils.html`had the Tera Type <strong>${teraType.mustHave.name}</strong>`);
  }
  if (teraType.mustNotHave.length) {
    parts.push(`did not have the Tera Type${Chat.plural(teraType.mustNotHave)} ${Chat.toListString(format(teraType.mustNotHave), "or")}`);
  }
  return Chat.toListString(parts, "and");
}
function setProbability(species, format, criteria, rounds = 700) {
  const results = { rounds, matches: 0 };
  const generator = Teams.getGenerator(format);
  for (let i = 0; i < rounds; i++) {
    const set = generator.randomSet(
      species,
      {},
      false,
      format.gameType !== "singles",
      format.ruleTable?.has("dynamaxclause")
    );
    if (criteria.item.mustHave && set.item !== criteria.item.mustHave.name)
      continue;
    if (criteria.item.mustNotHave.some((item) => item.name === set.item))
      continue;
    if (criteria.ability.mustHave && set.ability !== criteria.ability.mustHave.name)
      continue;
    if (criteria.ability.mustNotHave.some((ability) => ability.name === set.ability))
      continue;
    if (criteria.nature.mustHave && set.nature !== criteria.nature.mustHave.name)
      continue;
    if (criteria.nature.mustNotHave.some((nature) => nature.name === set.nature))
      continue;
    if (criteria.teraType.mustHave && set.teraType !== criteria.teraType.mustHave.name)
      continue;
    if (criteria.teraType.mustNotHave.some((type) => type.name === set.teraType))
      continue;
    const setHasMove = (move) => {
      const id = move.id === "hiddenpower" ? `${move.id}${toID(move.type)}` : move.id;
      return set.moves.includes(id);
    };
    if (!criteria.moves.mustHave.every(setHasMove))
      continue;
    if (criteria.moves.mustNotHave.some(setHasMove))
      continue;
    results.matches++;
  }
  return results;
}
const GEN_NAMES = {
  gen1: "[Gen 1]",
  gen2: "[Gen 2]",
  gen3: "[Gen 3]",
  gen4: "[Gen 4]",
  gen5: "[Gen 5]",
  gen6: "[Gen 6]",
  gen7: "[Gen 7]",
  gen8: "[Gen 8]",
  gen9: "[Gen 9]"
};
const STAT_NAMES = {
  hp: "HP",
  atk: "Atk",
  def: "Def",
  spa: "SpA",
  spd: "SpD",
  spe: "Spe"
};
const TIERS = {
  uber: "Uber",
  ubers: "Uber",
  ou: "OU",
  uu: "UU",
  ru: "RU",
  nu: "NU",
  pu: "PU",
  mono: "Mono",
  monotype: "Mono",
  lc: "LC",
  littlecup: "LC"
};
function formatAbility(ability) {
  ability = Dex.abilities.get(ability);
  return `<a href="https://${Config.routes.dex}/abilities/${ability.id}" target="_blank" class="subtle" style="white-space:nowrap">${ability.name}</a>`;
}
function formatNature(n) {
  const nature = Dex.natures.get(n);
  return nature.name;
}
function formatMove(move) {
  move = Dex.moves.get(move);
  return `<a href="https://${Config.routes.dex}/moves/${move.id}" target="_blank" class="subtle" style="white-space:nowrap">${move.name}</a>`;
}
function formatItem(item) {
  if (typeof item === "string" && item === "No Item") {
    return `No Item`;
  } else {
    item = Dex.items.get(item);
    return `<a href="https://${Config.routes.dex}/items/${item.id}" target="_blank" class="subtle" style="white-space:nowrap">${item.name}</a>`;
  }
}
function formatType(type) {
  type = Dex.types.get(type);
  return type.name;
}
function getSets(species, format = "gen9randombattle") {
  const dex = Dex.forFormat(format);
  format = Dex.formats.get(format);
  species = dex.species.get(species);
  const isDoubles = format.gameType === "doubles";
  let folderName = format.mod;
  if (format.team === "randomBaby")
    folderName += "baby";
  if (species.isNonstandard === "CAP")
    folderName += "cap";
  const setsFile = JSON.parse(
    (0, import_lib.FS)(`data/random-battles/${folderName}/${isDoubles ? "doubles-" : ""}sets.json`).readIfExistsSync() || "{}"
  );
  const data = setsFile[species.id];
  if (!data?.sets?.length)
    return null;
  return data;
}
function getData(species, format) {
  const dex = Dex.forFormat(format);
  format = Dex.formats.get(format);
  species = dex.species.get(species);
  const dataFile = JSON.parse(
    (0, import_lib.FS)(`data/random-battles/${format.mod}/data.json`).readIfExistsSync() || "{}"
  );
  const data = dataFile[species.id];
  if (!data)
    return null;
  return data;
}
function getLevel(species, format) {
  const dex = Dex.forFormat(format);
  format = Dex.formats.get(format);
  species = dex.species.get(species);
  switch (format.id) {
    case "gen2randombattle":
      const levelScale = {
        ZU: 81,
        ZUBL: 79,
        PU: 77,
        PUBL: 75,
        NU: 73,
        NUBL: 71,
        UU: 69,
        UUBL: 67,
        OU: 65,
        Uber: 61
      };
      return levelScale[species.tier] || 80;
  }
  return 0;
}
function getRBYMoves(species) {
  species = Dex.mod(`gen1`).species.get(species);
  const data = getData(species, "gen1randombattle");
  if (!data)
    return false;
  let buf = `<br/><b>Level</b>: ${data.level}`;
  if (data.comboMoves) {
    buf += `<br/><b>Combo moves</b>: `;
    buf += data.comboMoves.map(formatMove).sort().join(", ");
  }
  if (data.exclusiveMoves) {
    buf += `<br/><b>Exclusive moves</b>: `;
    buf += data.exclusiveMoves.map(formatMove).sort().join(", ");
  }
  if (data.essentialMoves) {
    buf += `<br/><b>Essential move${Chat.plural(data.essentialMoves)}</b>: `;
    buf += data.essentialMoves.map(formatMove).sort().join(", ");
  }
  if (data.moves) {
    buf += `<br/><b>Randomized moves</b>: `;
    buf += data.moves.map(formatMove).sort().join(", ");
  }
  if (!data.moves && !data.comboMoves && !data.exclusiveMoves && !data.essentialMove) {
    return false;
  }
  return buf;
}
function getLetsGoMoves(species) {
  species = Dex.species.get(species);
  const data = getData(species, "gen7letsgorandombattle");
  if (!data)
    return false;
  const isLetsGoLegal = (species.num <= 151 || ["Meltan", "Melmetal"].includes(species.name)) && (!species.forme || ["Alola", "Mega", "Mega-X", "Mega-Y", "Starter"].includes(species.forme));
  if (!isLetsGoLegal)
    return false;
  if (!data.moves?.length)
    return false;
  return data.moves.map(formatMove).sort().join(`, `);
}
function battleFactorySets(species, tier, gen = "gen9", isBSS = false) {
  species = Dex.species.get(species);
  if (typeof species.battleOnly === "string") {
    species = Dex.species.get(species.battleOnly);
  }
  gen = toID(gen);
  const genNum = parseInt(gen[3]);
  if (isNaN(genNum) || genNum < 6 || isBSS && genNum < 7)
    return null;
  const statsFile = JSON.parse(
    (0, import_lib.FS)(`data/random-battles/gen${genNum}/${isBSS ? `bss-` : ``}factory-sets.json`).readIfExistsSync() || "{}"
  );
  if (!Object.keys(statsFile).length)
    return null;
  let buf = ``;
  if (!isBSS) {
    if (!tier)
      throw new Chat.ErrorMessage(`Please provide a valid tier.`);
    if (!(toID(tier) in TIERS))
      throw new Chat.ErrorMessage(`That tier isn't supported.`);
    if (!(TIERS[toID(tier)] in statsFile)) {
      throw new Chat.ErrorMessage(`${TIERS[toID(tier)]} is not included in [Gen ${genNum}] Battle Factory.`);
    }
    const t = statsFile[TIERS[toID(tier)]];
    if (!(species.id in t)) {
      const formatName = Dex.formats.get(`${gen}battlefactory`).name;
      throw new Chat.ErrorMessage(`${species.name} doesn't have any sets in ${TIERS[toID(tier)]} for ${formatName}.`);
    }
    const setObj = t[species.id];
    if (genNum >= 9) {
      buf += `Species rarity: ${setObj.weight} (higher is more common, max 10)<br />`;
    }
    buf += `<span style="color:#999999;">Sets for ${species.name} in${genNum === 8 ? `` : ` ${GEN_NAMES[gen]}`} ${TIERS[toID(tier)]}:</span><br />`;
    for (const [i, set] of setObj.sets.entries()) {
      if (genNum >= 9) {
        buf += `<details><summary>Set ${i + 1} (${set.weight}%)</summary>`;
      } else {
        buf += `<details><summary>Set ${i + 1}</summary>`;
      }
      buf += `<ul style="list-style-type:none;">`;
      buf += `<li>${set.species}${set.gender ? ` (${set.gender})` : ``} @ ${Array.isArray(set.item) ? set.item.map(formatItem).join(" / ") : formatItem(set.item)}</li>`;
      buf += `<li>Ability: ${Array.isArray(set.ability) ? set.ability.map(formatAbility).join(" / ") : formatAbility(set.ability)}</li>`;
      if (TIERS[toID(tier)] === "LC" && !set.level)
        buf += `<li>Level: 5</li>`;
      if (set.level && set.level < 100)
        buf += `<li>Level: ${set.level}</li>`;
      if (set.shiny)
        buf += `<li>Shiny: Yes</li>`;
      if (set.happiness)
        buf += `<li>Happiness: ${set.happiness}</li>`;
      if (genNum === 9 && set.teraType) {
        buf += `<li>Tera Type: ${set.teraType.map(formatType).join(" / ")}</li>`;
      }
      if (set.evs) {
        buf += `<li>EVs: `;
        const evs = [];
        let ev;
        for (ev in set.evs) {
          if (set.evs[ev] === 0)
            continue;
          evs.push(`${set.evs[ev]} ${STAT_NAMES[ev]}`);
        }
        buf += `${evs.join(" / ")}</li>`;
      }
      buf += `<li>${Array.isArray(set.nature) ? set.nature.map(formatNature).join(" / ") : formatNature(set.nature)} Nature</li>`;
      if (set.ivs) {
        buf += `<li>IVs: `;
        const ivs = [];
        let iv;
        for (iv in set.ivs) {
          if (set.ivs[iv] === 31)
            continue;
          ivs.push(`${set.ivs[iv]} ${STAT_NAMES[iv]}`);
        }
        buf += `${ivs.join(" / ")}</li>`;
      }
      for (const moveid of set.moves) {
        buf += `<li>- ${Array.isArray(moveid) ? moveid.map(formatMove).join(" / ") : formatMove(moveid)}</li>`;
      }
      buf += `</ul></details>`;
    }
  } else {
    const format = Dex.formats.get(`${gen}bssfactory`);
    if (!(species.id in statsFile))
      throw new Chat.ErrorMessage(`${species.name} doesn't have any sets in ${format.name}.`);
    const setObj = statsFile[species.id];
    if (genNum >= 9) {
      buf += `Species rarity: ${setObj.weight} (higher is more common, max 10)<br />`;
      buf += `Sets for ${species.name} in ${format.name}:<br />`;
      for (const [i, set] of setObj.sets.entries()) {
        buf += `<details><summary>Set ${i + 1} (${set.weight}%)</summary>`;
        buf += `<ul style="list-style-type:none;padding-left:0;">`;
        buf += `<li>${Dex.forFormat(format).species.get(set.species).name} @ ${set.item.map(formatItem).join(" / ")}</li>`;
        buf += `<li>Ability: ${set.ability.map(formatAbility).join(" / ")}</li>`;
        buf += `<li>Level: 50</li>`;
        buf += `<li>Tera Type: ${set.teraType.map(formatType).join(" / ")}</li>`;
        if (set.evs) {
          buf += `<li>EVs: `;
          const evs = [];
          let ev;
          for (ev in set.evs) {
            if (!set.evs[ev])
              continue;
            evs.push(`${set.evs[ev]} ${STAT_NAMES[ev]}`);
          }
          buf += `${evs.join(" / ")}</li>`;
        }
        buf += `<li>${formatNature(set.nature)} Nature</li>`;
        if (set.ivs) {
          buf += `<li>IVs: `;
          const ivs = [];
          let iv;
          for (iv in set.ivs) {
            if (set.ivs[iv] === 31)
              continue;
            ivs.push(`${set.ivs[iv]} ${STAT_NAMES[iv]}`);
          }
          buf += `${ivs.join(" / ")}</li>`;
        }
        for (const moveSlot of set.moves) {
          buf += `<li>- ${moveSlot.map(formatMove).join(" / ")}</li>`;
        }
        buf += `</ul></details>`;
      }
    } else {
      buf += `<span style="color:#999999;">Sets for ${species.name} in ${format.name}:</span><br />`;
      for (const [i, set] of setObj.sets.entries()) {
        buf += `<details><summary>Set ${i + 1}</summary>`;
        buf += `<ul style="list-style-type:none;padding-left:0;">`;
        buf += `<li>${set.species}${set.gender ? ` (${set.gender})` : ``} @ ${Array.isArray(set.item) ? set.item.map(formatItem).join(" / ") : formatItem(set.item)}</li>`;
        buf += `<li>Ability: ${Array.isArray(set.ability) ? set.ability.map(formatAbility).join(" / ") : formatAbility(set.ability)}</li>`;
        if (!set.level)
          buf += `<li>Level: 50</li>`;
        if (set.level && set.level < 50)
          buf += `<li>Level: ${set.level}</li>`;
        if (set.shiny)
          buf += `<li>Shiny: Yes</li>`;
        if (set.happiness)
          buf += `<li>Happiness: ${set.happiness}</li>`;
        if (set.evs) {
          buf += `<li>EVs: `;
          const evs = [];
          let ev;
          for (ev in set.evs) {
            if (set.evs[ev] === 0)
              continue;
            evs.push(`${set.evs[ev]} ${STAT_NAMES[ev]}`);
          }
          buf += `${evs.join(" / ")}</li>`;
        }
        buf += `<li>${Array.isArray(set.nature) ? set.nature.map(formatNature).join(" / ") : formatNature(set.nature)} Nature</li>`;
        if (set.ivs) {
          buf += `<li>IVs: `;
          const ivs = [];
          let iv;
          for (iv in set.ivs) {
            if (set.ivs[iv] === 31)
              continue;
            ivs.push(`${set.ivs[iv]} ${STAT_NAMES[iv]}`);
          }
          buf += `${ivs.join(" / ")}</li>`;
        }
        for (const moveid of set.moves) {
          buf += `<li>- ${Array.isArray(moveid) ? moveid.map(formatMove).join(" / ") : formatMove(moveid)}</li>`;
        }
        buf += `</ul></details>`;
      }
    }
  }
  return buf;
}
function CAP1v1Sets(species) {
  species = Dex.species.get(species);
  const statsFile = JSON.parse(
    (0, import_lib.FS)(`data/random-battles/gen8/cap-1v1-sets.json`).readIfExistsSync() || "{}"
  );
  if (!Object.keys(statsFile).length)
    return null;
  if (species.isNonstandard !== "CAP") {
    return {
      e: `[Gen 8] CAP 1v1 only allows Pok\xE9mon created by the Create-A-Pok\xE9mon Project.`,
      parse: `/cap`
    };
  }
  if (species.isNonstandard === "CAP" && !(species.name in statsFile)) {
    return { e: `${species.name} doesn't have any sets in [Gen 8] CAP 1v1.` };
  }
  let buf = `<span style="color:#999999;">Sets for ${species.name} in [Gen 8] CAP 1v1:</span><br />`;
  for (const [i, set] of statsFile[species.name].entries()) {
    buf += `<details><summary>Set ${i + 1}</summary>`;
    buf += `<ul style="list-style-type:none;">`;
    buf += `<li>${set.species || species.name}${set.gender ? ` (${set.gender})` : ``} @ ${Array.isArray(set.item) ? set.item.map(formatItem).join(" / ") : formatItem(set.item)}</li>`;
    buf += `<li>Ability: ${Array.isArray(set.ability) ? set.ability.map(formatAbility).join(" / ") : formatAbility(set.ability)}</li>`;
    if (set.level && set.level < 100)
      buf += `<li>Level: ${set.level}</li>`;
    if (set.shiny)
      buf += `<li>Shiny: Yes</li>`;
    if (set.happiness)
      buf += `<li>Happiness: ${set.happiness}</li>`;
    if (set.evs) {
      buf += `<li>EVs: `;
      const evs = [];
      let ev;
      for (ev in set.evs) {
        if (set.evs[ev] === 0)
          continue;
        evs.push(`${set.evs[ev]} ${STAT_NAMES[ev]}`);
      }
      buf += `${evs.join(" / ")}</li>`;
    }
    buf += `<li>${Array.isArray(set.nature) ? set.nature.map(formatNature).join(" / ") : formatNature(set.nature)} Nature</li>`;
    if (set.ivs) {
      buf += `<li>IVs: `;
      const ivs = [];
      let iv;
      for (iv in set.ivs) {
        if (set.ivs[iv] === 31)
          continue;
        ivs.push(`${set.ivs[iv]} ${STAT_NAMES[iv]}`);
      }
      buf += `${ivs.join(" / ")}</li>`;
    }
    for (const moveid of set.moves) {
      buf += `<li>- ${Array.isArray(moveid) ? moveid.map(formatMove).join(" / ") : formatMove(moveid)}</li>`;
    }
    buf += `</ul></details>`;
  }
  return buf;
}
const commands = {
  randbats: "randombattles",
  randomdoublesbattle: "randombattles",
  randdubs: "randombattles",
  babyrandombattle: "randombattles",
  babyrands: "randombattles",
  // randombattlenodmax: 'randombattles',
  // randsnodmax: 'randombattles',
  randombattles(target, room, user, connection, cmd) {
    if (!this.runBroadcast())
      return;
    const battle = room?.battle;
    let isDoubles = cmd === "randomdoublesbattle" || cmd === "randdubs";
    let isBaby = cmd === "babyrandombattle" || cmd === "babyrands";
    let isNoDMax = cmd.includes("nodmax");
    if (battle) {
      if (battle.format.includes("nodmax"))
        isNoDMax = true;
      if (battle.format.includes("doubles") || battle.gameType === "freeforall")
        isDoubles = true;
      if (battle.format.includes("baby"))
        isBaby = true;
    }
    const args = target.split(",");
    if (!args[0])
      return this.parse(`/help randombattles`);
    const { dex } = this.splitFormat(target, true);
    const isLetsGo = dex.currentMod === "gen7letsgo";
    const searchResults = dex.dataSearch(args[0], ["Pokedex"]);
    if (!searchResults?.length) {
      this.errorReply(`No Pok\xE9mon named '${args[0]}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. (Check your spelling?)`);
      return;
    }
    let inexactMsg = "";
    if (searchResults[0].isInexact) {
      inexactMsg = `No Pok\xE9mon named '${args[0]}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. Searching for '${searchResults[0].name}' instead.`;
    }
    const species = dex.species.get(searchResults[0].name);
    const extraFormatModifier = isLetsGo ? "letsgo" : dex.currentMod === "gen8bdsp" ? "bdsp" : "";
    const babyModifier = isBaby ? "baby" : "";
    const doublesModifier = isDoubles ? "doubles" : "";
    const noDMaxModifier = isNoDMax ? "nodmax" : "";
    const formatName = `gen${dex.gen}${extraFormatModifier}${babyModifier}random${doublesModifier}battle${noDMaxModifier}`;
    const format = dex.formats.get(formatName);
    const movesets = [];
    let setCount = 0;
    if (dex.gen === 1) {
      const rbyMoves = getRBYMoves(species);
      if (!rbyMoves) {
        this.sendReply(inexactMsg);
        return this.errorReply(`Error: ${species.name} has no Random Battle data in ${GEN_NAMES[toID(args[1])]}`);
      }
      movesets.push(`<span style="color:#999999;">Moves for ${species.name} in ${format.name}:</span>${rbyMoves}`);
      setCount = 1;
    } else if (isLetsGo) {
      const lgpeMoves = getLetsGoMoves(species);
      if (!lgpeMoves) {
        this.sendReply(inexactMsg);
        return this.errorReply(`Error: ${species.name} has no Random Battle data in [Gen 7 Let's Go]`);
      }
      movesets.push(`<span style="color:#999999;">Moves for ${species.name} in ${format.name}:</span><br />${lgpeMoves}`);
      setCount = 1;
    } else {
      const setsToCheck = [species];
      if (dex.gen >= 8 && !isNoDMax)
        setsToCheck.push(dex.species.get(`${args[0]}gmax`));
      if (species.otherFormes)
        setsToCheck.push(...species.otherFormes.map((pkmn) => dex.species.get(pkmn)));
      if ([2, 3, 4, 5, 6, 7, 9].includes(dex.gen)) {
        for (const pokemon of setsToCheck) {
          const data = getSets(pokemon, format.id);
          if (!data)
            continue;
          const sets = data.sets;
          const level = data.level || getLevel(pokemon, format);
          let buf2 = `<span style="color:#999999;">Moves for ${pokemon.name} in ${format.name}:</span><br/>`;
          buf2 += `<b>Level</b>: ${level}`;
          for (const set of sets) {
            buf2 += `<details><summary>${set.role}</summary>`;
            if (dex.gen === 9) {
              buf2 += `<b>Tera Type${Chat.plural(set.teraTypes)}</b>: ${set.teraTypes.join(", ")}<br/>`;
            } else if ([2, 3, 4, 5, 6, 7].includes(dex.gen) && set.preferredTypes) {
              buf2 += `<b>Preferred Type${Chat.plural(set.preferredTypes)}</b>: ${set.preferredTypes.join(", ")}<br/>`;
            }
            buf2 += `<b>Moves</b>: ${set.movepool.sort().map(formatMove).join(", ")}<br/>`;
            if (set.abilities) {
              buf2 += `<b>Abilit${Chat.plural(set.abilities, "ies", "y")}</b>: ${set.abilities.sort().join(", ")}`;
            }
            buf2 += "</details>";
            setCount++;
          }
          movesets.push(buf2);
        }
      } else {
        for (let pokemon of setsToCheck) {
          let data = getData(pokemon, format.name);
          if (!data && isNoDMax) {
            pokemon = dex.species.get(pokemon.id + "gmax");
            data = getData(pokemon, format.name);
          }
          if (!data)
            continue;
          if (!data.moves || pokemon.isNonstandard === "Future")
            continue;
          let randomMoves = data.moves;
          const level = data.level || getLevel(pokemon, format);
          if (isDoubles && data.doublesMoves)
            randomMoves = data.doublesMoves;
          if (isNoDMax && data.noDynamaxMoves)
            randomMoves = data.noDynamaxMoves;
          const m = randomMoves.slice().sort().map(formatMove);
          movesets.push(
            `<details><summary><span style="color:#999999;">Moves for ${pokemon.name} in ${format.name}:<span style="color:#999999;"></summary>` + (level ? `<b>Level</b>: ${level}<br>` : "") + `${m.join(`, `)}</details>`
          );
          setCount++;
        }
      }
    }
    if (!movesets.length) {
      this.sendReply(inexactMsg);
      return this.errorReply(`Error: ${species.name} has no Random Battle data in ${format.name}`);
    }
    let buf = movesets.join("<hr/>");
    if (setCount <= 2) {
      buf = buf.replace(/<details>/g, "<details open>");
    }
    this.sendReply(inexactMsg);
    this.sendReplyBox(buf);
  },
  randombattleshelp: [
    `/randombattles OR /randbats [pokemon], [gen] - Displays a Pok\xE9mon's Random Battle Moves. Defaults to Gen 9. If used in a battle, defaults to the gen of that battle.`,
    `/randomdoublesbattle OR /randdubs [pokemon], [gen] - Same as above, but instead displays Random Doubles Battle moves.`
  ],
  bssfactory: "battlefactory",
  battlefactory(target, room, user, connection, cmd) {
    if (!this.runBroadcast())
      return;
    const isBSS = cmd === "bssfactory";
    if (isBSS) {
      const args = target.split(",");
      if (!args[0])
        return this.parse(`/help battlefactory`);
      const species = Dex.species.get(args[0]);
      if (!species.exists) {
        return this.errorReply(`Error: Pok\xE9mon '${args[0].trim()}' not found.`);
      }
      let mod = "gen9";
      if (args[1] && toID(args[1]) in Dex.dexes && Dex.dexes[toID(args[1])].gen >= 7)
        mod = toID(args[1]);
      const bssSets = battleFactorySets(species, null, mod, true);
      if (!bssSets)
        return this.parse(`/help battlefactory`);
      return this.sendReplyBox(bssSets);
    } else {
      const args = target.split(",");
      if (!args[0])
        return this.parse(`/help battlefactory`);
      const species = Dex.species.get(args[0]);
      if (!species.exists) {
        return this.errorReply(`Error: Pok\xE9mon '${args[0].trim()}' not found.`);
      }
      let tier = "";
      if (args[1] && toID(args[1]) in TIERS) {
        tier = TIERS[toID(args[1])];
      } else {
        tier = "ou";
      }
      const mod = args[2] || "gen9";
      let bfSets;
      if (species.name === "Necrozma-Ultra") {
        bfSets = battleFactorySets(Dex.species.get("necrozma-dawnwings"), tier, mod);
        if (bfSets) {
          bfSets += battleFactorySets(Dex.species.get("necrozma-duskmane"), tier, mod);
        }
      } else if (species.name === "Zygarde-Complete") {
        bfSets = battleFactorySets(Dex.species.get("zygarde"), tier, mod);
        if (bfSets) {
          bfSets += battleFactorySets(Dex.species.get("zygarde-10"), tier, mod);
        }
      } else {
        bfSets = battleFactorySets(species, tier, mod);
      }
      if (!bfSets)
        return this.parse(`/help battlefactory`);
      return this.sendReplyBox(bfSets);
    }
  },
  battlefactoryhelp: [
    `/battlefactory [pokemon], [tier], [gen] - Displays a Pok\xE9mon's Battle Factory sets. Supports Gens 6-8. Defaults to Gen 8. If no tier is provided, defaults to OU.`,
    `- Supported tiers: OU, Ubers, UU, RU, NU, PU, Monotype (Gen 7 only), LC (Gen 7 only)`,
    `/bssfactory [pokemon], [gen] - Displays a Pok\xE9mon's BSS Factory sets. Supports Gen 7-9. Defaults to Gen 9.`
  ],
  cap1v1(target, room, user) {
    if (!this.runBroadcast())
      return;
    if (!target)
      return this.parse(`/help cap1v1`);
    const species = Dex.species.get(target);
    if (!species.exists)
      return this.errorReply(`Error: Pok\xE9mon '${target.trim()}' not found.`);
    const cap1v1Set = CAP1v1Sets(species);
    if (!cap1v1Set)
      return this.parse(`/help cap1v1`);
    if (typeof cap1v1Set !== "string") {
      this.errorReply(`Error: ${cap1v1Set.e}`);
      if (cap1v1Set.parse)
        this.parse(cap1v1Set.parse);
      return;
    }
    return this.sendReplyBox(cap1v1Set);
  },
  cap1v1help: [
    `/cap1v1 [pokemon] - Displays a Pok\xE9mon's CAP 1v1 sets.`
  ],
  setodds: "randombattlesetprobabilities",
  randbatsodds: "randombattlesetprobabilities",
  randbatsprobabilities: "randombattlesetprobabilities",
  randombattlesetprobabilities(target, room, user) {
    const randbatsRoom = Rooms.get("randombattles");
    if (!randbatsRoom?.auth.has(user.id)) {
      this.checkCan("lock");
    }
    if (!target)
      return this.parse(`/help randombattlesetprobabilities`);
    this.runBroadcast();
    const args = target.split(",");
    if (args.length < 2)
      return this.parse(`/help randombattlesetprobabilities`);
    let format = Dex.formats.get("gen9randombattle");
    let formatOrSpecies = args.shift();
    const possibleFormat = Dex.formats.get(formatOrSpecies);
    if (possibleFormat.exists) {
      if (!possibleFormat.team) {
        throw new Chat.ErrorMessage(`${possibleFormat.name} does not have randomly-generated teams.`);
      }
      format = possibleFormat;
      formatOrSpecies = args.shift();
    }
    const dex = Dex.forFormat(format);
    const species = dex.species.get(formatOrSpecies);
    if (!species.exists) {
      throw new Chat.ErrorMessage(`Species ${species.name} does not exist in the specified format.`);
    }
    let setExists;
    if ([2, 3, 4, 5, 6, 7, 9].includes(dex.gen)) {
      setExists = !!getSets(species, format);
    } else {
      const data = getData(species, format);
      if (!data) {
        setExists = false;
      } else if (format.gameType === "doubles" || format.gameType === "freeforall") {
        setExists = !!data.doublesMoves;
      } else {
        setExists = !!data.moves;
      }
    }
    if (!setExists) {
      throw new Chat.ErrorMessage(`${species.name} does not have random battle moves in ${format.name}.`);
    }
    const criteria = {
      moves: { mustHave: [], mustNotHave: [] },
      item: { mustNotHave: [] },
      ability: { mustNotHave: [] },
      nature: { mustNotHave: [] },
      teraType: { mustNotHave: [] }
    };
    if (args.length < 1) {
      this.errorReply(`You must specify at least one condition.`);
      return this.parse(`/help randombattlesetprobabilities`);
    }
    for (const arg of args) {
      let [key, value] = arg.split("=");
      key = toID(key);
      if (!value || !key) {
        this.errorReply(`Invalid condition format: ${arg}`);
        return this.parse(`/help randombattlesetprobabilities`);
      }
      switch (key) {
        case "moves":
          for (const rawMove of value.split("&")) {
            const move = dex.moves.get(rawMove);
            if (!move.exists) {
              throw new Chat.ErrorMessage(`"${rawMove}" is not a move in the specified format.`);
            }
            const isNegation = rawMove.trim().startsWith("!");
            if (isNegation) {
              criteria.moves.mustNotHave.push(move);
            } else {
              criteria.moves.mustHave.push(move);
            }
          }
          break;
        case "item":
          const item = dex.items.get(value);
          if (!item.exists) {
            throw new Chat.ErrorMessage(`"${value}" is not an item in the specified format.`);
          }
          const itemNegation = value.trim().startsWith("!");
          if (itemNegation) {
            criteria.item.mustNotHave.push(item);
          } else {
            if (criteria.item.mustHave) {
              throw new Chat.ErrorMessage(`Impossible situation: two items (${criteria.item.mustHave.name} and ${item.name}) are required.`);
            }
            criteria.item.mustHave = item;
          }
          break;
        case "ability":
          const ability = dex.abilities.get(value);
          if (!ability.exists) {
            throw new Chat.ErrorMessage(`"${value}" is not an ability in the specified format.`);
          }
          const abilityNegation = value.trim().startsWith("!");
          if (abilityNegation) {
            criteria.ability.mustNotHave.push(ability);
          } else {
            if (criteria.ability.mustHave) {
              throw new Chat.ErrorMessage(`Impossible situation: two abilities (${criteria.ability.mustHave.name} and ${ability.name}) are required.`);
            }
            criteria.ability.mustHave = ability;
          }
          break;
        case "nature":
          const nature = dex.natures.get(value);
          if (!nature.exists) {
            throw new Chat.ErrorMessage(`"${value}" is not a nature in the specified format.`);
          }
          const natureNegation = value.trim().startsWith("!");
          if (natureNegation) {
            criteria.nature.mustNotHave.push(nature);
          } else {
            if (criteria.nature.mustHave) {
              throw new Chat.ErrorMessage(`Impossible situation: two natures (${criteria.nature.mustHave.name} and ${nature.name}) are required.`);
            }
            criteria.nature.mustHave = nature;
          }
          break;
        case "tera":
        case "teratype":
          if (dex.gen < 9)
            throw new Chat.ErrorMessage("Tera Types do not exist in the specified format.");
          const type = dex.types.get(value);
          if (!type.exists) {
            throw new Chat.ErrorMessage(`"${value}" is not a type in the specified format.`);
          }
          const typeNegation = value.trim().startsWith("!");
          if (typeNegation) {
            criteria.teraType.mustNotHave.push(type);
          } else {
            if (criteria.teraType.mustHave) {
              throw new Chat.ErrorMessage(`Impossible situation: two Tera Types (${criteria.teraType.mustHave.name} and ${type.name}) are required.`);
            }
            criteria.teraType.mustHave = type;
          }
          break;
        default:
          throw new Chat.ErrorMessage(`Invalid criterion: ${key}`);
      }
    }
    const results = setProbability(species, format, criteria);
    const percentage = Math.round(results.matches / results.rounds * 100);
    return this.sendReplyBox(
      import_lib.Utils.html`Generated ${results.rounds} sets for <strong>${species.name}</strong> in ${format.name}:<br />` + `Approximately <strong>${percentage}%</strong> (${results.matches} sets) ${getHTMLCriteriaDescription(criteria)}.`
    );
  },
  randombattlesetprobabilitieshelp() {
    return this.sendReplyBox(
      `<code>/randombattlesetprobabilities [optional format], [species], [conditions]</code>: Gives the probability of a set matching the conditions appearing for the given species.<br /><code>[conditions]</code> is a comma-separated list of conditions of the form <code>[component]=[matching value]</code>, where <code>[component]</code> can be any of the following: <ul><li><code>moves</code>: matches all generated sets that contain every move specified. <code>[matching value]</code> should be a list of moves separated with <code>&amp;</code>.<li><code>item</code>: matches all generated sets that have the specified item. <code>[matching value]</code> should be an item name.<li><code>ability</code>: matches all generated sets with the specified ability. <code>[matching value]</code> should be an ability name.<li><code>nature</code>: matches all generated sets with the specified nature. <code>[matching value]</code> should be a nature name.<li><code>tera</code>: matches all generated sets with the specified Tera Type. <code>[matching value]</code> should be a type. Gen 9 only.</ul>The given probability is for a set that matches EVERY provided condition. Conditions can be negated by prefixing the <code>[matching value]</code> with <code>!</code>.<br />Requires: % @ # ~ (globally or in the Random Battles room)`
    );
  },
  genteam: "generateteam",
  generateteam(target, room, user) {
    if (!Rooms.get("randombattles")?.auth.has(user.id))
      this.checkCan("lock");
    this.runBroadcast(true);
    if (!target)
      return this.parse("/help generateteam");
    const format = Dex.formats.get(target);
    if (format.effectType !== "Format")
      throw new Chat.ErrorMessage(`"${target}" is not a recognized format.`);
    if (!format.team)
      throw new Chat.ErrorMessage(`"${format.name}" requires you to bring your own team.`);
    const team = Teams.getGenerator(format).getTeam();
    const dex = Dex.forFormat(format);
    const teamHTML = team.map((set) => {
      set.moves = set.moves.map((m) => dex.moves.get(m).name);
      set.item = dex.items.get(set.item).name;
      return `<details><summary>${set.name}</summary>${import_lib.Utils.escapeHTML(Teams.exportSet(set))}<br /></details>`;
    }).join("");
    return this.sendReplyBox(`<strong>Team for ${format.name}</strong>:` + teamHTML);
  },
  generateteamhelp: [`/genteam [format] - Generates a team for the given format. Requires: % @ ~ or Random Battles room auth`]
};
//# sourceMappingURL=index.js.map