coh-content-db 2.0.0-rc.5 → 2.0.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +7 -7
  2. package/dist/coh-content-db.d.ts +493 -243
  3. package/dist/coh-content-db.js +675 -353
  4. package/dist/coh-content-db.js.map +1 -1
  5. package/dist/coh-content-db.mjs +655 -345
  6. package/dist/coh-content-db.mjs.map +1 -1
  7. package/eslint.config.mjs +1 -0
  8. package/package.json +1 -1
  9. package/src/main/api/alignment.ts +18 -2
  10. package/src/main/api/badge-data.ts +15 -38
  11. package/src/main/api/badge-requirement-data.ts +64 -0
  12. package/src/main/api/badge-requirement-type.ts +32 -0
  13. package/src/main/api/badge-type.ts +15 -15
  14. package/src/main/api/contact-data.ts +48 -0
  15. package/src/main/api/content-bundle.ts +16 -4
  16. package/src/main/api/enhancement-category.ts +26 -26
  17. package/src/main/api/location-data.ts +28 -0
  18. package/src/main/api/mission-data.ts +83 -0
  19. package/src/main/api/mission-type.ts +2 -0
  20. package/src/main/api/morality.ts +31 -0
  21. package/src/main/api/sex.ts +8 -1
  22. package/src/main/api/zone-data.ts +20 -0
  23. package/src/main/changelog.ts +8 -3
  24. package/src/main/db/alignment-list.ts +54 -0
  25. package/src/main/db/alternates.ts +15 -32
  26. package/src/main/db/badge-index.ts +17 -36
  27. package/src/main/db/badge-requirement.ts +81 -0
  28. package/src/main/db/badge-search-options.ts +5 -5
  29. package/src/main/db/badge.ts +73 -62
  30. package/src/main/db/bundle-metadata.ts +3 -3
  31. package/src/main/db/coh-content-database.ts +60 -23
  32. package/src/main/db/contact.ts +62 -0
  33. package/src/main/db/location.ts +30 -0
  34. package/src/main/db/mission.ts +107 -0
  35. package/src/main/db/morality-list.ts +99 -0
  36. package/src/main/db/zone.ts +28 -0
  37. package/src/main/index.ts +16 -13
  38. package/src/main/util.ts +85 -14
  39. package/src/test/api/alignment.test.ts +38 -4
  40. package/src/test/api/badge-data.fixture.ts +1 -15
  41. package/src/test/api/badge-data.test.ts +3 -3
  42. package/src/test/api/badge-requirement-data.fixture.ts +7 -0
  43. package/src/test/api/badge-requirement-type.test.ts +31 -0
  44. package/src/test/api/badge-type.test.ts +5 -5
  45. package/src/test/api/contact-data.fixture.ts +7 -0
  46. package/src/test/api/content-bundle.fixture.ts +1 -17
  47. package/src/test/api/content-bundle.test.ts +1 -1
  48. package/src/test/api/enhancement-category.test.ts +5 -5
  49. package/src/test/api/mission-data.fixture.ts +12 -0
  50. package/src/test/api/sex.test.ts +33 -1
  51. package/src/test/api/zone-data.fixture.ts +8 -0
  52. package/src/test/db/alignment-list.test.ts +200 -0
  53. package/src/test/db/alternates.test.ts +60 -56
  54. package/src/test/db/badge-index.test.ts +108 -66
  55. package/src/test/db/badge-requirement.test.ts +145 -0
  56. package/src/test/db/badge.test.ts +310 -14
  57. package/src/test/db/coh-content-database.test.ts +110 -29
  58. package/src/test/db/contact.test.ts +97 -0
  59. package/src/test/db/location.test.ts +51 -0
  60. package/src/test/db/mission.test.ts +171 -0
  61. package/src/test/db/morality-list.test.ts +457 -0
  62. package/src/test/db/zone.test.ts +36 -0
  63. package/src/test/index.test.ts +4 -2
  64. package/src/test/util.test.ts +112 -22
  65. package/src/main/api/badge-partial-data.ts +0 -66
  66. package/src/main/api/badge-partial-type.ts +0 -8
  67. package/src/main/api/game-map-data.ts +0 -26
  68. package/src/main/api/plaque-type.ts +0 -6
  69. package/src/main/api/vidiot-map-data.ts +0 -18
  70. package/src/main/api/vidiot-map-point-of-interest-data.ts +0 -30
  71. package/src/main/db/alignments.ts +0 -17
  72. package/src/main/db/badge-partial.ts +0 -83
  73. package/src/main/db/game-map.ts +0 -33
  74. package/src/main/db/vidiot-map-point-of-interest.ts +0 -39
  75. package/src/main/db/vidiot-map.ts +0 -25
  76. package/src/test/api/alignments.test.ts +0 -40
  77. package/src/test/api/badge-partial-data.fixture.ts +0 -17
  78. package/src/test/api/badge-partial-type.test.ts +0 -31
  79. package/src/test/api/game-map-data.fixture.ts +0 -10
  80. package/src/test/api/plaque-type.test.ts +0 -31
  81. package/src/test/api/vidiot-map-point-of-interest.fixture.ts +0 -10
  82. package/src/test/api/vidiot-map.fixture.ts +0 -9
@@ -1,108 +1,188 @@
1
1
  'use strict';
2
2
 
3
- const ALIGNMENT = ["H", "V", "P"];
3
+ const ALIGNMENT = ["hero", "villain", "praetorian"];
4
+ const ALIGNMENT_ORDER = Object.fromEntries(ALIGNMENT.map((x, index) => [x, index]));
5
+ function compareAlignment(a, b) {
6
+ const orderA = a ? ALIGNMENT_ORDER[a] : -1;
7
+ const orderB = b ? ALIGNMENT_ORDER[b] : -1;
8
+ return orderA - orderB;
9
+ }
4
10
 
5
- const BADGE_PARTIAL_TYPE = [
6
- "PLAQUE",
7
- "BADGE",
8
- "INVENTION",
9
- "INVENTION_PLUS_ONE"
10
- // Some invention badges require you to build x of two different invention levels, 'plus one of either level'.
11
+ const BADGE_REQUIREMENT_TYPE = [
12
+ /**
13
+ * Collect a badge.
14
+ */
15
+ "badge",
16
+ /**
17
+ * Craft an invention.
18
+ */
19
+ "invention",
20
+ /**
21
+ * Some invention badges require you to build x of two different invention levels, 'plus one of either level'.
22
+ */
23
+ "invention-plus-one",
24
+ /**
25
+ * Visit a location.
26
+ */
27
+ "location",
28
+ /**
29
+ * Click on a monument.
30
+ */
31
+ "monument",
32
+ /**
33
+ * Complete a mission.
34
+ */
35
+ "mission",
36
+ /**
37
+ * Complete an arbitrary task.
38
+ */
39
+ "task"
11
40
  ];
12
41
 
13
42
  const BADGE_TYPE = [
14
- "EXPLORATION",
15
- "HISTORY",
16
- "ACCOMPLISHMENT",
17
- "ACHIEVEMENT",
18
- "ACCOLADE",
19
- "GLADIATOR",
20
- "VETERAN",
21
- "PVP",
22
- "INVENTION",
23
- "DEFEAT",
24
- "EVENT",
25
- "OUROBOROS",
26
- "CONSIGNMENT",
27
- "DAY_JOB",
28
- "AE"
43
+ "exploration",
44
+ "history",
45
+ "accomplishment",
46
+ "achievement",
47
+ "accolade",
48
+ "gladiator",
49
+ "veteran",
50
+ "pvp",
51
+ "invention",
52
+ "defeat",
53
+ "event",
54
+ "ouroboros",
55
+ "consignment",
56
+ "day-job",
57
+ "architect-entertainment"
29
58
  ];
30
59
 
31
60
  const ENHANCEMENT_CATEGORY = [
32
- "DEFENSE_DEBUFF",
33
- "TO_HIT_DEBUFF",
34
- "TAUNT",
35
- "CONFUSE",
36
- "HEALING",
37
- "DEFENSE_BUFF",
38
- "RESIST_DAMAGE",
39
- "INTANGIBILITY",
40
- "SLEEP",
41
- "SLOW",
42
- "HOLD",
43
- "STUN",
44
- "IMMOBILIZE",
45
- "FEAR",
46
- "ENDURANCE_MODIFICATION",
47
- "ENDURANCE_REDUCTION",
48
- "RECHARGE_REDUCTION",
49
- "INTERRUPT_DURATION",
50
- "ACCURACY",
51
- "TO_HIT_BUFF",
52
- "DAMAGE",
53
- "KNOCKBACK",
54
- "RUN_SPEED",
55
- "JUMP",
56
- "FLY_SPEED",
57
- "RANGE"
61
+ "defense-debuff",
62
+ "to-hit-debuff",
63
+ "taunt",
64
+ "confuse",
65
+ "healing",
66
+ "defense-buff",
67
+ "resist-damage",
68
+ "intangibility",
69
+ "sleep",
70
+ "slow",
71
+ "hold",
72
+ "stun",
73
+ "immobilize",
74
+ "fear",
75
+ "endurance-modification",
76
+ "endurance-reduction",
77
+ "recharge-reduction",
78
+ "interrupt-duration",
79
+ "accuracy",
80
+ "to-hit-buff",
81
+ "damage",
82
+ "knockback",
83
+ "run-speed",
84
+ "jump",
85
+ "fly-speed",
86
+ "range"
58
87
  ];
59
88
 
60
- const PLAQUE_TYPE = [
61
- "WALL_PLAQUE",
62
- "MONUMENT"
63
- ];
89
+ const MISSION_TYPE = ["story-arc", "mission", "task-force", "strike-force", "trial", "personal-story"];
90
+
91
+ const MORALITY = ["hero", "vigilante", "villain", "rogue", "resistance", "loyalist"];
64
92
 
65
93
  const SEX = ["M", "F"];
94
+ const SEX_ORDER = Object.fromEntries(SEX.map((x, index) => [x, index]));
95
+ function compareSex(a, b) {
96
+ const orderA = a ? SEX_ORDER[a] : -1;
97
+ const orderB = b ? SEX_ORDER[b] : -1;
98
+ return orderA - orderB;
99
+ }
66
100
 
67
- var __defProp$8 = Object.defineProperty;
68
- var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
69
- var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
70
- class Alignments {
71
- constructor(raw) {
72
- __publicField$8(this, "items");
73
- __publicField$8(this, "hero");
74
- __publicField$8(this, "villain");
75
- __publicField$8(this, "praetorian");
76
- __publicField$8(this, "primal");
77
- this.items = raw;
78
- this.hero = raw.includes("H");
79
- this.villain = raw.includes("V");
80
- this.praetorian = raw.includes("P");
81
- this.primal = !this.praetorian && (this.hero || this.villain);
101
+ var __defProp$a = Object.defineProperty;
102
+ var __typeError$6 = (msg) => {
103
+ throw TypeError(msg);
104
+ };
105
+ var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
106
+ var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
107
+ var __accessCheck$6 = (obj, member, msg) => member.has(obj) || __typeError$6("Cannot " + msg);
108
+ var __privateGet$6 = (obj, member, getter) => (__accessCheck$6(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
109
+ var __privateAdd$6 = (obj, member, value) => member.has(obj) ? __typeError$6("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
110
+ var __privateSet$5 = (obj, member, value, setter) => (__accessCheck$6(obj, member, "write to private field"), member.set(obj, value), value);
111
+ var _items$1;
112
+ class AlignmentList {
113
+ constructor(items) {
114
+ __privateAdd$6(this, _items$1);
115
+ __publicField$a(this, "hero");
116
+ __publicField$a(this, "villain");
117
+ __publicField$a(this, "praetorian");
118
+ __publicField$a(this, "primal");
119
+ __publicField$a(this, "all");
120
+ const set = new Set(items ?? [...ALIGNMENT]);
121
+ this.hero = set.has("hero") || set.has("primal") || set.has("all");
122
+ this.villain = set.has("villain") || set.has("primal") || set.has("all");
123
+ this.praetorian = set.has("praetorian") || set.has("all");
124
+ this.primal = this.hero && this.villain;
125
+ this.all = this.hero && this.villain && this.praetorian;
126
+ __privateSet$5(this, _items$1, /* @__PURE__ */ new Set());
127
+ if (this.hero) __privateGet$6(this, _items$1).add("hero");
128
+ if (this.villain) __privateGet$6(this, _items$1).add("villain");
129
+ if (this.praetorian) __privateGet$6(this, _items$1).add("praetorian");
130
+ }
131
+ get items() {
132
+ return [...__privateGet$6(this, _items$1)];
133
+ }
134
+ has(alignment) {
135
+ switch (alignment) {
136
+ case "hero": {
137
+ return this.hero;
138
+ }
139
+ case "villain": {
140
+ return this.villain;
141
+ }
142
+ case "praetorian": {
143
+ return this.praetorian;
144
+ }
145
+ case "primal": {
146
+ return this.primal;
147
+ }
148
+ case "all": {
149
+ return this.all;
150
+ }
151
+ default: {
152
+ return false;
153
+ }
154
+ }
82
155
  }
83
156
  }
157
+ _items$1 = new WeakMap();
84
158
 
85
- var __typeError$4 = (msg) => {
159
+ var __typeError$5 = (msg) => {
86
160
  throw TypeError(msg);
87
161
  };
88
- var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Cannot " + msg);
89
- var __privateGet$4 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
90
- var __privateAdd$4 = (obj, member, value) => member.has(obj) ? __typeError$4("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
91
- var __privateSet$3 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
92
- var __privateMethod$2 = (obj, member, method) => (__accessCheck$4(obj, member, "access private method"), method);
93
- var _sortedValues, _Alternates_instances, compareAlternates_fn, compareAlignment_fn, compareSex_fn;
94
- const ALIGNMENT_SORT = { H: 2, V: 1, P: 0 };
95
- const SEX_SORT = { M: 1, F: 0 };
162
+ var __accessCheck$5 = (obj, member, msg) => member.has(obj) || __typeError$5("Cannot " + msg);
163
+ var __privateGet$5 = (obj, member, getter) => (__accessCheck$5(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
164
+ var __privateAdd$5 = (obj, member, value) => member.has(obj) ? __typeError$5("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
165
+ var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$5(obj, member, "write to private field"), member.set(obj, value), value);
166
+ var __privateMethod$2 = (obj, member, method) => (__accessCheck$5(obj, member, "access private method"), method);
167
+ var _sortedValues, _Alternates_instances, compareAlternates_fn;
96
168
  class Alternates {
97
- constructor(values) {
98
- __privateAdd$4(this, _Alternates_instances);
99
- __privateAdd$4(this, _sortedValues, []);
100
- __privateSet$3(this, _sortedValues, values.sort());
101
- __privateGet$4(this, _sortedValues).sort((a, b) => __privateMethod$2(this, _Alternates_instances, compareAlternates_fn).call(this, a, b));
169
+ /**
170
+ * Create an alternate set from either a list of categorized values, or a single value when there are no alternates.
171
+ * @param value List of alternates, or a single value.
172
+ */
173
+ constructor(value) {
174
+ __privateAdd$5(this, _Alternates_instances);
175
+ __privateAdd$5(this, _sortedValues, []);
176
+ if (Array.isArray(value)) {
177
+ __privateSet$4(this, _sortedValues, value.sort());
178
+ __privateGet$5(this, _sortedValues).sort((a, b) => __privateMethod$2(this, _Alternates_instances, compareAlternates_fn).call(this, a, b));
179
+ } else {
180
+ __privateSet$4(this, _sortedValues, [{ value }]);
181
+ }
102
182
  }
103
183
  getValue(alignment, sex) {
104
- for (let index = __privateGet$4(this, _sortedValues).length; index--; ) {
105
- const entry = __privateGet$4(this, _sortedValues)[index];
184
+ for (let index = __privateGet$5(this, _sortedValues).length; index--; ) {
185
+ const entry = __privateGet$5(this, _sortedValues)[index];
106
186
  if ((entry.alignment === void 0 || entry.alignment === alignment) && (entry.sex === void 0 || entry.sex === sex)) return entry.value;
107
187
  }
108
188
  return this.default?.value;
@@ -111,13 +191,13 @@ class Alternates {
111
191
  * Get the default value for this list of alternates, the value with the highest priority and lowest specificity.
112
192
  */
113
193
  get default() {
114
- return __privateGet$4(this, _sortedValues)[0];
194
+ return __privateGet$5(this, _sortedValues)[0];
115
195
  }
116
196
  /**
117
197
  * Get the list of alternates sorted in canonical order (alignment then sex, low to high specificity).
118
198
  */
119
199
  get canonical() {
120
- return __privateGet$4(this, _sortedValues);
200
+ return __privateGet$5(this, _sortedValues);
121
201
  }
122
202
  /**
123
203
  * Create a joined string from the alternate values in canonical order.
@@ -133,48 +213,32 @@ compareAlternates_fn = function(a, b) {
133
213
  const aSpecificity = (a.alignment ? 2 : 0) + (a.sex ? 1 : 0);
134
214
  const bSpecificity = (b.alignment ? 2 : 0) + (b.sex ? 1 : 0);
135
215
  if (aSpecificity !== bSpecificity) return aSpecificity - bSpecificity;
136
- const alignmentComparison = __privateMethod$2(this, _Alternates_instances, compareAlignment_fn).call(this, a.alignment, b.alignment);
216
+ const alignmentComparison = compareAlignment(a.alignment, b.alignment);
137
217
  if (alignmentComparison !== 0) return alignmentComparison;
138
- const sexComparison = __privateMethod$2(this, _Alternates_instances, compareSex_fn).call(this, a.sex, b.sex);
218
+ const sexComparison = compareSex(a.sex, b.sex);
139
219
  if (sexComparison !== 0) return sexComparison;
140
220
  return String(a.value).localeCompare(String(b.value));
141
221
  };
142
- compareAlignment_fn = function(a, b) {
143
- if (a === b) return 0;
144
- if (a === void 0 && b !== void 0) return -1;
145
- if (b === void 0 && a !== void 0) return 1;
146
- const aSort = a === void 0 ? -1 : ALIGNMENT_SORT[a] ?? -1;
147
- const bSort = b === void 0 ? -1 : ALIGNMENT_SORT[b] ?? -1;
148
- return bSort - aSort;
149
- };
150
- compareSex_fn = function(a, b) {
151
- if (a === b) return 0;
152
- if (a === void 0 && b !== void 0) return -1;
153
- if (b === void 0 && a !== void 0) return 1;
154
- const aSort = SEX_SORT[a ?? -1] ?? -1;
155
- const bSort = SEX_SORT[b ?? -1] ?? -1;
156
- return bSort - aSort;
157
- };
158
222
 
159
- var __typeError$3 = (msg) => {
223
+ var __typeError$4 = (msg) => {
160
224
  throw TypeError(msg);
161
225
  };
162
- var __accessCheck$3 = (obj, member, msg) => member.has(obj) || __typeError$3("Cannot " + msg);
163
- var __privateGet$3 = (obj, member, getter) => (__accessCheck$3(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
164
- var __privateAdd$3 = (obj, member, value) => member.has(obj) ? __typeError$3("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
165
- var __privateSet$2 = (obj, member, value, setter) => (__accessCheck$3(obj, member, "write to private field"), member.set(obj, value), value);
166
- var __privateMethod$1 = (obj, member, method) => (__accessCheck$3(obj, member, "access private method"), method);
226
+ var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Cannot " + msg);
227
+ var __privateGet$4 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
228
+ var __privateAdd$4 = (obj, member, value) => member.has(obj) ? __typeError$4("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
229
+ var __privateSet$3 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
230
+ var __privateMethod$1 = (obj, member, method) => (__accessCheck$4(obj, member, "access private method"), method);
167
231
  var _value, _Key_instances, validateKey_fn;
168
232
  const INVALID_KEY_PATTERN = /[^a-z0-9-]/;
169
233
  class Key {
170
234
  constructor(value) {
171
- __privateAdd$3(this, _Key_instances);
172
- __privateAdd$3(this, _value);
235
+ __privateAdd$4(this, _Key_instances);
236
+ __privateAdd$4(this, _value);
173
237
  __privateMethod$1(this, _Key_instances, validateKey_fn).call(this, value);
174
- __privateSet$2(this, _value, value);
238
+ __privateSet$3(this, _value, value);
175
239
  }
176
240
  get value() {
177
- return __privateGet$3(this, _value);
241
+ return __privateGet$4(this, _value);
178
242
  }
179
243
  }
180
244
  _value = new WeakMap();
@@ -183,198 +247,352 @@ validateKey_fn = function(key) {
183
247
  if (INVALID_KEY_PATTERN.test(key)) throw new Error(`Invalid key: [${key}]; Keys can only contain lowercase characters, numbers and dashes.`);
184
248
  };
185
249
 
186
- var __defProp$7 = Object.defineProperty;
187
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
188
- var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
250
+ var __defProp$9 = Object.defineProperty;
251
+ var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
252
+ var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
189
253
  class Archetype {
190
254
  constructor(data) {
191
- __publicField$7(this, "key");
192
- __publicField$7(this, "name");
193
- __publicField$7(this, "description");
255
+ __publicField$9(this, "key");
256
+ __publicField$9(this, "name");
257
+ __publicField$9(this, "description");
194
258
  this.key = new Key(data.key).value;
195
259
  this.name = data.name;
196
260
  this.description = data.description;
197
261
  }
198
262
  }
199
263
 
200
- var __defProp$6 = Object.defineProperty;
201
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
202
- var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
203
- class BadgePartial {
264
+ function badgeUri(target) {
265
+ const key = typeof target === "string" ? target : target.key;
266
+ return `badge://${key}`;
267
+ }
268
+ function badgeLink(target) {
269
+ const key = typeof target === "string" ? target : target.key;
270
+ return `[${key}](${badgeUri(target)})`;
271
+ }
272
+ function contactUri(target) {
273
+ const key = typeof target === "string" ? target : target.key;
274
+ return `contact://${key}`;
275
+ }
276
+ function contactLink(target) {
277
+ const key = typeof target === "string" ? target : target.key;
278
+ return `[${key}](${contactUri(target)})`;
279
+ }
280
+ function missionUri(target) {
281
+ const key = typeof target === "string" ? target : target.key;
282
+ return `mission://${key}`;
283
+ }
284
+ function missionLink(target) {
285
+ const key = typeof target === "string" ? target : target.key;
286
+ return `[${key}](${missionUri(target)})`;
287
+ }
288
+ function zoneUri(target) {
289
+ const key = typeof target === "string" ? target : target.key;
290
+ return `zone://${key}`;
291
+ }
292
+ function zoneLink(target) {
293
+ const key = typeof target === "string" ? target : target.key;
294
+ return `[${key}](${zoneUri(target)})`;
295
+ }
296
+ function coalesceToArray(value) {
297
+ if (!value) return void 0;
298
+ return Array.isArray(value) ? value : [value];
299
+ }
300
+
301
+ var __defProp$8 = Object.defineProperty;
302
+ var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
303
+ var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
304
+ class BadgeRequirement {
204
305
  constructor(data) {
205
306
  /**
206
- * Key.
207
- */
208
- __publicField$6(this, "key");
209
- /**
210
- * Type of partial.
307
+ * Unique key used to reference this badge requirement.
308
+ *
309
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
211
310
  */
212
- __publicField$6(this, "type");
311
+ __publicField$8(this, "key");
213
312
  /**
214
- * Map the partial is located on.
313
+ * The requirement type.
215
314
  */
216
- __publicField$6(this, "mapKey");
315
+ __publicField$8(this, "type");
217
316
  /**
218
- * /loc coordinates.
317
+ * If the requirement involves a location, where it is.
219
318
  */
220
- __publicField$6(this, "loc");
319
+ __publicField$8(this, "location");
221
320
  /**
222
- * Is it a wall plaque or a physical monument?
321
+ * If the requirement involves a badge, the badge key.
223
322
  */
224
- __publicField$6(this, "plaqueType");
323
+ __publicField$8(this, "badgeKey");
225
324
  /**
226
- * Plaque inscription.
325
+ * If the requirement involves a mission, the mission key.
227
326
  */
228
- __publicField$6(this, "plaqueInscription");
327
+ __publicField$8(this, "missionKey");
229
328
  /**
230
- * The number or letter the partial appears as on Vidiot Maps.
329
+ * If the requirement involves a monument, the text that is displayed thereon.
231
330
  */
232
- __publicField$6(this, "vidiotMapKey");
331
+ __publicField$8(this, "monumentText");
233
332
  /**
234
- * The badge required for this partial.
333
+ * If the requirement involves crafting an invention, the Level of the invention required.
235
334
  */
236
- __publicField$6(this, "badgeKey");
335
+ __publicField$8(this, "inventionLevel");
237
336
  /**
238
- * Level of the invention required.
337
+ * If the requirement involves crafting an invention, the types of enhancements that will qualify.
239
338
  */
240
- __publicField$6(this, "inventionLevel");
339
+ __publicField$8(this, "inventionTypes");
241
340
  /**
242
- * The types of enhancements required to be crafted.
341
+ * Number of times the task needs to be repeated.
243
342
  */
244
- __publicField$6(this, "inventionTypes");
343
+ __publicField$8(this, "count");
245
344
  /**
246
- * Number of invention crafts required.
345
+ * Additional information about the requirement.
247
346
  */
248
- __publicField$6(this, "inventionCount");
347
+ __publicField$8(this, "notes");
249
348
  /**
250
- * Any additional notes.
349
+ * List of external links. Wiki, forums, etc.
251
350
  */
252
- __publicField$6(this, "notes");
351
+ __publicField$8(this, "links");
253
352
  this.key = new Key(data.key).value;
254
353
  this.type = data.type;
255
- this.mapKey = data.mapKey;
256
- this.loc = data.loc;
257
- this.plaqueType = data.plaqueType;
258
- this.plaqueInscription = data.plaqueInscription;
259
- this.vidiotMapKey = data.vidiotMapKey;
354
+ this.location = coalesceToArray(data.location);
260
355
  this.badgeKey = data.badgeKey;
356
+ this.missionKey = data.missionKey;
357
+ this.monumentText = data.monumentText;
261
358
  this.inventionLevel = data.inventionLevel;
262
359
  this.inventionTypes = data.inventionTypes;
263
- this.inventionCount = data.inventionCount;
360
+ this.count = data.count;
264
361
  this.notes = data.notes;
362
+ this.links = data.links ?? [];
265
363
  }
266
364
  }
267
365
 
268
- var __defProp$5 = Object.defineProperty;
366
+ var __defProp$7 = Object.defineProperty;
367
+ var __typeError$3 = (msg) => {
368
+ throw TypeError(msg);
369
+ };
370
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
371
+ var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
372
+ var __accessCheck$3 = (obj, member, msg) => member.has(obj) || __typeError$3("Cannot " + msg);
373
+ var __privateGet$3 = (obj, member, getter) => (__accessCheck$3(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
374
+ var __privateAdd$3 = (obj, member, value) => member.has(obj) ? __typeError$3("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
375
+ var __privateSet$2 = (obj, member, value, setter) => (__accessCheck$3(obj, member, "write to private field"), member.set(obj, value), value);
376
+ var _items;
377
+ class MoralityList {
378
+ constructor(items) {
379
+ __privateAdd$3(this, _items);
380
+ __publicField$7(this, "hero");
381
+ __publicField$7(this, "vigilante");
382
+ __publicField$7(this, "villain");
383
+ __publicField$7(this, "rogue");
384
+ __publicField$7(this, "resistance");
385
+ __publicField$7(this, "loyalist");
386
+ __publicField$7(this, "primal");
387
+ __publicField$7(this, "praetorian");
388
+ __publicField$7(this, "heroic");
389
+ __publicField$7(this, "villainous");
390
+ __publicField$7(this, "paragonCityAccess");
391
+ __publicField$7(this, "rogueIslesAccess");
392
+ __publicField$7(this, "all");
393
+ const set = new Set(items ?? [...MORALITY]);
394
+ this.hero = set.has("hero") || set.has("primal") || set.has("heroic") || set.has("paragon-city-access") || set.has("all");
395
+ this.vigilante = set.has("vigilante") || set.has("primal") || set.has("heroic") || set.has("paragon-city-access") || set.has("rogue-isles-access") || set.has("all");
396
+ this.villain = set.has("villain") || set.has("primal") || set.has("villainous") || set.has("rogue-isles-access") || set.has("all");
397
+ this.rogue = set.has("rogue") || set.has("primal") || set.has("villainous") || set.has("paragon-city-access") || set.has("rogue-isles-access") || set.has("all");
398
+ this.resistance = set.has("resistance") || set.has("praetorian") || set.has("all");
399
+ this.loyalist = set.has("loyalist") || set.has("praetorian") || set.has("all");
400
+ this.primal = this.hero && this.vigilante && this.villain && this.rogue;
401
+ this.praetorian = this.loyalist && this.resistance;
402
+ this.heroic = this.hero && this.vigilante;
403
+ this.villainous = this.villain && this.rogue;
404
+ this.paragonCityAccess = this.heroic && this.rogue;
405
+ this.rogueIslesAccess = this.villainous && this.vigilante;
406
+ this.all = this.primal && this.praetorian;
407
+ __privateSet$2(this, _items, /* @__PURE__ */ new Set());
408
+ if (this.hero) __privateGet$3(this, _items).add("hero");
409
+ if (this.vigilante) __privateGet$3(this, _items).add("vigilante");
410
+ if (this.villain) __privateGet$3(this, _items).add("villain");
411
+ if (this.rogue) __privateGet$3(this, _items).add("rogue");
412
+ if (this.resistance) __privateGet$3(this, _items).add("resistance");
413
+ if (this.loyalist) __privateGet$3(this, _items).add("loyalist");
414
+ }
415
+ get items() {
416
+ return [...__privateGet$3(this, _items)];
417
+ }
418
+ has(morality) {
419
+ switch (morality) {
420
+ case "hero": {
421
+ return this.hero;
422
+ }
423
+ case "vigilante": {
424
+ return this.vigilante;
425
+ }
426
+ case "villain": {
427
+ return this.villain;
428
+ }
429
+ case "rogue": {
430
+ return this.rogue;
431
+ }
432
+ case "resistance": {
433
+ return this.resistance;
434
+ }
435
+ case "loyalist": {
436
+ return this.loyalist;
437
+ }
438
+ case "primal": {
439
+ return this.primal;
440
+ }
441
+ case "praetorian": {
442
+ return this.praetorian;
443
+ }
444
+ case "heroic": {
445
+ return this.hero;
446
+ }
447
+ case "paragon-city-access": {
448
+ return this.paragonCityAccess;
449
+ }
450
+ case "rogue-isles-access": {
451
+ return this.rogueIslesAccess;
452
+ }
453
+ case "villainous": {
454
+ return this.villainous;
455
+ }
456
+ case "all": {
457
+ return this.all;
458
+ }
459
+ default: {
460
+ return false;
461
+ }
462
+ }
463
+ }
464
+ }
465
+ _items = new WeakMap();
466
+
467
+ var __defProp$6 = Object.defineProperty;
269
468
  var __typeError$2 = (msg) => {
270
469
  throw TypeError(msg);
271
470
  };
272
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
273
- var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
471
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
472
+ var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
274
473
  var __accessCheck$2 = (obj, member, msg) => member.has(obj) || __typeError$2("Cannot " + msg);
275
474
  var __privateGet$2 = (obj, member, getter) => (__accessCheck$2(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
276
475
  var __privateAdd$2 = (obj, member, value) => member.has(obj) ? __typeError$2("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
277
- var _partialsIndex;
476
+ var _requirementsIndex, _zoneKeys;
278
477
  class Badge {
279
- constructor(data) {
280
- __privateAdd$2(this, _partialsIndex, {});
478
+ constructor(badgeData) {
479
+ __privateAdd$2(this, _requirementsIndex, {});
480
+ __privateAdd$2(this, _zoneKeys, /* @__PURE__ */ new Set());
281
481
  /**
282
482
  * The database key for this badge.
283
483
  */
284
- __publicField$5(this, "key");
484
+ __publicField$6(this, "key");
285
485
  /**
286
486
  * The type of badge.
287
487
  */
288
- __publicField$5(this, "type");
488
+ __publicField$6(this, "type");
289
489
  /**
290
490
  * The name of this badge.
291
491
  *
292
492
  * May vary by character sex or alignment.
293
493
  */
294
- __publicField$5(this, "name");
494
+ __publicField$6(this, "name");
295
495
  /**
296
- * The character alignments that this badge is available to.
496
+ * The character moralities that this badge is available to.
297
497
  */
298
- __publicField$5(this, "alignment");
498
+ __publicField$6(this, "morality");
299
499
  /**
300
500
  * The badge text as it appears in-game. May vary by character sex or alignment.
301
501
  */
302
- __publicField$5(this, "badgeText");
502
+ __publicField$6(this, "badgeText");
303
503
  /**
304
- * Description of how to acquire the badge.
504
+ * Short description of how to acquire the badge. Detailed instructions will be in the notes field.
305
505
  */
306
- __publicField$5(this, "acquisition");
506
+ __publicField$6(this, "acquisition");
307
507
  /**
308
508
  * Absolute URL to this badge's icon.
309
509
  *
310
510
  * May vary by character sex or alignment.
311
511
  */
312
- __publicField$5(this, "icon");
512
+ __publicField$6(this, "icon");
313
513
  /**
314
514
  * Freeform notes or tips about the badge.
315
515
  */
316
- __publicField$5(this, "notes");
317
- /**
318
- * List of external links for this Badge. Wiki, forums, etc.
319
- */
320
- __publicField$5(this, "links");
321
- /**
322
- * For exploration badges, the key of the {@link GameMap} that this badge is found on.
323
- */
324
- __publicField$5(this, "mapKey");
325
- /**
326
- * For exploration badges, the `/loc` coordinates of the badge on the in-game map.
327
- */
328
- __publicField$5(this, "loc");
516
+ __publicField$6(this, "notes");
329
517
  /**
330
- * For badges that appear on a Vidiot Map, the number or letter the badge appears as.
518
+ * List of external links. Wiki, forums, etc.
331
519
  */
332
- __publicField$5(this, "vidiotMapKey");
520
+ __publicField$6(this, "links");
333
521
  /**
334
- * ID used with the in-game `/settitle` command to apply the badge.
522
+ * The id used with the in-game `/settitle` command to apply the badge.
523
+ * The first value is the id for primal characters and the (optional) second number is the id for praetorian characters.
335
524
  */
336
- __publicField$5(this, "setTitle");
525
+ __publicField$6(this, "setTitleId");
337
526
  /**
338
527
  * A description of the effect the badge will have, such as a buff or granting a temporary power.
339
528
  */
340
- __publicField$5(this, "effect");
529
+ __publicField$6(this, "effect");
341
530
  /**
342
- * A list of requirements for badges that have partial fulfilment steps, such as visiting plaques for history badges, or collecting other badges for meta-badges like accolades.
531
+ * Represents the requirements for badges with multiple fulfillment steps, such as visiting monuments for history badges, completing missions, or collecting other badges.
343
532
  */
344
- __publicField$5(this, "partials");
533
+ __publicField$6(this, "requirements");
345
534
  /**
346
535
  * Some badges are not included in the badge total count... such as Flames of Prometheus, which can be removed by redeeming it for a Notice of the Well.
347
536
  */
348
- __publicField$5(this, "ignoreInTotals");
349
- this.key = new Key(data.key).value;
350
- this.type = data.type;
351
- this.name = new Alternates(data.name);
352
- this.alignment = new Alignments(data.alignment);
353
- this.badgeText = new Alternates(data.badgeText ?? []);
354
- this.acquisition = data.acquisition;
355
- this.icon = new Alternates(data.icon ?? []);
356
- this.notes = data.notes;
357
- this.links = data.links;
358
- this.mapKey = data.mapKey;
359
- this.loc = data.loc;
360
- this.effect = data.effect;
361
- this.vidiotMapKey = data.vidiotMapKey;
362
- this.setTitle = data.setTitle;
363
- this.ignoreInTotals = data.ignoreInTotals ?? false;
364
- this.partials = data.partials?.map((data2) => {
365
- if (__privateGet$2(this, _partialsIndex)[data2.key] !== void 0) throw new Error(`Duplicate badge partial key [${data2.key}]`);
366
- const badge = new BadgePartial(data2);
367
- __privateGet$2(this, _partialsIndex)[badge.key] = badge;
368
- return badge;
537
+ __publicField$6(this, "ignoreInTotals");
538
+ this.key = new Key(badgeData.key).value;
539
+ this.type = badgeData.type;
540
+ this.name = new Alternates(badgeData.name);
541
+ this.morality = new MoralityList(coalesceToArray(badgeData.morality));
542
+ this.badgeText = new Alternates(badgeData.badgeText ?? []);
543
+ this.acquisition = badgeData.acquisition;
544
+ this.icon = new Alternates(badgeData.icon ?? []);
545
+ this.notes = badgeData.notes;
546
+ this.links = badgeData.links ?? [];
547
+ this.effect = badgeData.effect;
548
+ this.setTitleId = badgeData.setTitleId;
549
+ this.ignoreInTotals = badgeData.ignoreInTotals ?? false;
550
+ this.requirements = badgeData.requirements?.map((requirementData) => {
551
+ if (__privateGet$2(this, _requirementsIndex)[requirementData.key]) throw new Error(`Duplicate badge requirement key [${badgeData.key}:${requirementData.key}]`);
552
+ const requirement = new BadgeRequirement(requirementData);
553
+ __privateGet$2(this, _requirementsIndex)[requirement.key] = requirement;
554
+ if (requirement.location) for (const location of requirement.location) {
555
+ if (location.zoneKey) __privateGet$2(this, _zoneKeys).add(location.zoneKey);
556
+ }
557
+ return requirement;
369
558
  });
370
559
  }
371
- getPartial(key) {
372
- const result = __privateGet$2(this, _partialsIndex)[key];
373
- if (result === void 0) throw new Error(`Unknown badge partial key [${key}]`);
560
+ getRequirement(key) {
561
+ const result = __privateGet$2(this, _requirementsIndex)[key];
562
+ if (result === void 0) throw new Error(`Unknown badge requirement key [${key}]`);
374
563
  return result;
375
564
  }
565
+ /**
566
+ * Return a list of all the zone keys referenced by this badge.
567
+ */
568
+ get zoneKeys() {
569
+ return [...__privateGet$2(this, _zoneKeys)];
570
+ }
571
+ /**
572
+ * The zone key if this badge relates to a single zone.
573
+ */
574
+ get zoneKey() {
575
+ return __privateGet$2(this, _zoneKeys).size === 1 ? __privateGet$2(this, _zoneKeys).values().next().value : void 0;
576
+ }
577
+ }
578
+ _requirementsIndex = new WeakMap();
579
+ _zoneKeys = new WeakMap();
580
+ function compareByDefaultName(a, b) {
581
+ const aName = a?.name.default?.value;
582
+ const bName = b?.name.default?.value;
583
+ if (!aName && !bName) return 0;
584
+ if (!aName) return 1;
585
+ if (!bName) return -1;
586
+ return aName.localeCompare(bName);
587
+ }
588
+ function compareByZoneKey(a, b) {
589
+ const aZone = a?.zoneKey;
590
+ const bZone = b?.zoneKey;
591
+ if (!aZone && !bZone) return 0;
592
+ if (!aZone) return 1;
593
+ if (!bZone) return -1;
594
+ return aZone.localeCompare(bZone);
376
595
  }
377
- _partialsIndex = new WeakMap();
378
596
 
379
597
  var __typeError$1 = (msg) => {
380
598
  throw TypeError(msg);
@@ -384,16 +602,12 @@ var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "rea
384
602
  var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
385
603
  var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
386
604
  var __privateMethod = (obj, member, method) => (__accessCheck$1(obj, member, "access private method"), method);
387
- var _badges, _badgeIndex$1, _mapOrder, _BadgeIndex_instances, satisfiesQueryPredicate_fn, satisfiesFilterPredicate_fn, sort_fn;
605
+ var _badges, _badgeIndex$1, _BadgeIndex_instances, satisfiesQueryPredicate_fn, satisfiesFilterPredicate_fn, sort_fn;
388
606
  class BadgeIndex {
389
- constructor(badges, maps) {
607
+ constructor(badges) {
390
608
  __privateAdd$1(this, _BadgeIndex_instances);
391
609
  __privateAdd$1(this, _badges, []);
392
610
  __privateAdd$1(this, _badgeIndex$1, {});
393
- __privateAdd$1(this, _mapOrder, {});
394
- __privateSet$1(this, _mapOrder, Object.fromEntries(
395
- maps?.sort((a, b) => a.name.localeCompare(b.name))?.map((x, index) => [x.key, index]) ?? []
396
- ));
397
611
  __privateSet$1(this, _badges, badges);
398
612
  for (const badge of badges) {
399
613
  if (__privateGet$1(this, _badgeIndex$1)[badge.key] !== void 0) throw new Error(`Duplicate badge key [${badge.key}]`);
@@ -401,74 +615,67 @@ class BadgeIndex {
401
615
  }
402
616
  }
403
617
  getBadge(key) {
404
- const result = __privateGet$1(this, _badgeIndex$1)[key];
405
- if (result === void 0) throw new Error(`Unknown badge key [${key}]`);
406
- return result;
618
+ if (!key) return void 0;
619
+ return __privateGet$1(this, _badgeIndex$1)[key];
407
620
  }
408
621
  searchBadges(options) {
409
622
  const filtered = options?.query || options?.filter ? __privateGet$1(this, _badges).filter((badge) => __privateMethod(this, _BadgeIndex_instances, satisfiesQueryPredicate_fn).call(this, badge, options?.query) && __privateMethod(this, _BadgeIndex_instances, satisfiesFilterPredicate_fn).call(this, badge, options?.filter)) : __privateGet$1(this, _badges);
410
- const paged = options?.pageSize ? filtered.slice(((options?.page ?? 1) - 1) * options.pageSize, (options?.page ?? 1) * options?.pageSize) : filtered;
623
+ const totalPages = options?.pageSize ? Math.ceil(filtered.length / options?.pageSize) : 1;
624
+ const page = Math.max(1, Math.min(totalPages, options?.page ?? 1));
625
+ const paged = options?.pageSize ? filtered.slice((page - 1) * options.pageSize, page * options?.pageSize) : filtered;
411
626
  const sorted = __privateMethod(this, _BadgeIndex_instances, sort_fn).call(this, paged, options?.sort);
412
627
  return {
413
628
  items: sorted,
414
- page: options?.page ?? 1,
629
+ page,
415
630
  pageSize: options?.pageSize,
416
631
  totalItems: filtered.length,
417
- totalPages: options?.pageSize ? Math.ceil(filtered.length / options?.pageSize) : 1
632
+ totalPages
418
633
  };
419
634
  }
420
635
  }
421
636
  _badges = new WeakMap();
422
637
  _badgeIndex$1 = new WeakMap();
423
- _mapOrder = new WeakMap();
424
638
  _BadgeIndex_instances = new WeakSet();
425
639
  satisfiesQueryPredicate_fn = function(badge, query) {
426
640
  const queryString = query?.str?.toLowerCase() ?? "";
427
- return !!((query?.on?.name ?? true) && badge.name.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || query?.on?.badgeText && badge.badgeText.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || query?.on?.acquisition && badge.acquisition?.toLowerCase().includes(queryString) || query?.on?.effect && badge.effect?.toLowerCase().includes(queryString) || query?.on?.notes && badge.notes?.toLowerCase().includes(queryString) || query?.on?.setTitle && (badge.setTitle?.id?.toString().includes(queryString) || badge.setTitle?.praetorianId?.toString().includes(queryString)));
641
+ return !!((query?.on?.name ?? true) && badge.name.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || query?.on?.badgeText && badge.badgeText.canonical.some((x) => x.value.toLowerCase().includes(queryString)) || query?.on?.acquisition && badge.acquisition?.toLowerCase().includes(queryString) || query?.on?.effect && badge.effect?.toLowerCase().includes(queryString) || query?.on?.notes && badge.notes?.toLowerCase().includes(queryString) || query?.on?.setTitle && badge.setTitleId?.some((x) => x?.toString().includes(queryString)));
428
642
  };
429
643
  satisfiesFilterPredicate_fn = function(badge, filter) {
430
- return (!filter?.type || badge.type === filter.type) && (!filter?.mapKey || badge.mapKey === filter.mapKey) && (!filter?.alignment || badge.alignment.items.includes(filter.alignment));
644
+ return (!filter?.type || badge.type === filter.type) && (!filter?.zoneKey || badge.zoneKey === filter.zoneKey) && (!filter?.morality || badge.morality.has(filter.morality));
431
645
  };
432
646
  sort_fn = function(badges, sort) {
433
647
  if (!sort) return badges;
434
- const ascending = sort.dir !== "DESC";
435
- if (!sort.by || sort.by === "CANONICAL") return sort.dir === "DESC" ? badges.reverse() : badges;
436
- if (sort.by === "BADGE_NAME") return ascending ? badges.sort((a, b) => a.name.default?.value.localeCompare(b.name.default?.value ?? "") ?? 0) : badges.sort((a, b) => b.name.default?.value.localeCompare(a.name.default?.value ?? "") ?? 0);
437
- return badges.sort((a, b) => {
438
- const aIndex = __privateGet$1(this, _mapOrder)[a.mapKey ?? ""];
439
- const bIndex = __privateGet$1(this, _mapOrder)[b.mapKey ?? ""];
440
- if (aIndex === bIndex) return 0;
441
- if (aIndex === void 0) return ascending ? 1 : -1;
442
- if (bIndex === void 0) return ascending ? -1 : 1;
443
- return ascending ? aIndex - bIndex : bIndex - aIndex;
444
- });
648
+ const ascending = sort.dir !== "desc";
649
+ if (sort.by === "badge-name") return badges.sort((a, b) => ascending ? compareByDefaultName(a, b) : compareByDefaultName(b, a));
650
+ if (sort.by === "zone-key") return badges.sort((a, b) => ascending ? compareByZoneKey(a, b) : compareByZoneKey(b, a));
651
+ return sort.dir === "desc" ? badges.reverse() : badges;
445
652
  };
446
653
 
447
- var __defProp$4 = Object.defineProperty;
448
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
449
- var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
654
+ var __defProp$5 = Object.defineProperty;
655
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
656
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
450
657
  class BundleMetadata {
451
658
  constructor(bundle) {
452
659
  /**
453
- * Name of the server group.
660
+ * Name of the content bundle.
454
661
  */
455
- __publicField$4(this, "name");
662
+ __publicField$5(this, "name");
456
663
  /**
457
- * Description of the server group.
664
+ * Description of the fork.
458
665
  */
459
- __publicField$4(this, "description");
666
+ __publicField$5(this, "description");
460
667
  /**
461
668
  * Repository where the db content package is maintained.
462
669
  */
463
- __publicField$4(this, "repository");
670
+ __publicField$5(this, "repository");
464
671
  /**
465
- * List of external links for this Server Group. Wiki, forums, etc.
672
+ * List of external links. Wiki, forums, etc.
466
673
  */
467
- __publicField$4(this, "links");
674
+ __publicField$5(this, "links");
468
675
  /**
469
676
  * Change log for this data package.
470
677
  */
471
- __publicField$4(this, "changelog");
678
+ __publicField$5(this, "changelog");
472
679
  this.name = bundle.name;
473
680
  this.description = bundle.description;
474
681
  this.repository = bundle.repository;
@@ -477,103 +684,159 @@ class BundleMetadata {
477
684
  }
478
685
  }
479
686
 
687
+ var __defProp$4 = Object.defineProperty;
688
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
689
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
690
+ class Zone {
691
+ constructor(data) {
692
+ /**
693
+ * Unique key used to reference this zone.
694
+ *
695
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
696
+ */
697
+ __publicField$4(this, "key");
698
+ /**
699
+ * The name of the zone as it appears in-game.
700
+ */
701
+ __publicField$4(this, "name");
702
+ /**
703
+ * List of external links. Wiki, forums, etc.
704
+ */
705
+ __publicField$4(this, "links");
706
+ this.key = new Key(data.key).value;
707
+ this.name = data.name;
708
+ this.links = data.links ?? [];
709
+ }
710
+ }
711
+
480
712
  var __defProp$3 = Object.defineProperty;
481
713
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
482
714
  var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
483
- class VidiotMapPointOfInterest {
715
+ class Contact {
484
716
  constructor(data) {
485
717
  /**
486
- * The pixel-space position of the PoI on the map graphic.
718
+ * Unique key used to reference this contact.
487
719
  *
488
- * Screen-space, pixels from top-left `[0, 0]`.
720
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
489
721
  */
490
- __publicField$3(this, "pos");
722
+ __publicField$3(this, "key");
491
723
  /**
492
- * Freeform notes about the PoI.
724
+ * The name of this contact.
493
725
  */
494
- __publicField$3(this, "notes");
726
+ __publicField$3(this, "name");
495
727
  /**
496
- * If the POI is a zone transfer, the map it transfers to.
728
+ * The contact's title.
497
729
  */
498
- __publicField$3(this, "mapKey");
730
+ __publicField$3(this, "title");
499
731
  /**
500
- * If the POI is a badge, the badge.
732
+ * The character moralities that this contact will interact with.
501
733
  */
502
- __publicField$3(this, "badgeKey");
734
+ __publicField$3(this, "morality");
503
735
  /**
504
- * If the POI is a partial for a badge, the partial key.
736
+ * The location of this contact.
505
737
  */
506
- __publicField$3(this, "badgePartialKey");
507
- this.pos = data.pos;
738
+ __publicField$3(this, "location");
739
+ /**
740
+ * The level range this contact will offer missions for.
741
+ */
742
+ __publicField$3(this, "levelRange");
743
+ /**
744
+ * Freeform notes or tips about the contact.
745
+ */
746
+ __publicField$3(this, "notes");
747
+ /**
748
+ * List of external links. Wiki, forums, etc.
749
+ */
750
+ __publicField$3(this, "links");
751
+ this.key = new Key(data.key).value;
752
+ this.name = data.name;
753
+ this.title = data.title;
754
+ this.morality = new MoralityList(coalesceToArray(data.morality));
755
+ this.location = data.location;
756
+ this.levelRange = data.levelRange;
508
757
  this.notes = data.notes;
509
- this.mapKey = data.mapKey;
510
- this.badgeKey = data.badgeKey;
511
- this.badgePartialKey = data.badgePartialKey;
758
+ this.links = data.links ?? [];
512
759
  }
513
760
  }
514
761
 
515
762
  var __defProp$2 = Object.defineProperty;
516
763
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
517
764
  var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
518
- class VidiotMap {
765
+ class Mission {
519
766
  constructor(data) {
520
767
  /**
521
- * URL of the map image.
768
+ * Unique key used to reference this mission.
769
+ *
770
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
522
771
  */
523
- __publicField$2(this, "imageUrl");
772
+ __publicField$2(this, "key");
524
773
  /**
525
- * Name to display for the Vidiot map.
774
+ * The name of the mission as it appears from the contact.
775
+ *
776
+ * The name may be different when viewed in Ouroboros as a Flashback.
526
777
  */
527
778
  __publicField$2(this, "name");
528
779
  /**
529
- * List of Points of Interest labelled on the image.
780
+ * The type of mission... Story arc, task force, trial, etc.
530
781
  */
531
- __publicField$2(this, "pointsOfInterest");
532
- this.imageUrl = data.imageUrl;
533
- this.name = data.name;
534
- this.pointsOfInterest = data.pointsOfInterest?.map((data2) => new VidiotMapPointOfInterest(data2));
535
- }
536
- }
537
-
538
- var __defProp$1 = Object.defineProperty;
539
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
540
- var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
541
- class GameMap {
542
- constructor(data) {
782
+ __publicField$2(this, "type");
783
+ /**
784
+ * The character moralities that may accept the mission.
785
+ */
786
+ __publicField$2(this, "morality");
543
787
  /**
544
- * The database key for this map.
788
+ * The keys of any contacts that provide this mission.
545
789
  */
546
- __publicField$1(this, "key");
790
+ __publicField$2(this, "contactKeys");
547
791
  /**
548
- * The name of the map as it appears in-game.
792
+ * The level range this mission is available for.
549
793
  */
550
- __publicField$1(this, "name");
794
+ __publicField$2(this, "levelRange");
551
795
  /**
552
- * List of external links for this Map. Wiki, forums, etc.
796
+ * Freeform notes or tips about the mission.
553
797
  */
554
- __publicField$1(this, "links");
798
+ __publicField$2(this, "notes");
555
799
  /**
556
- * List of Vidiot Map assets for this map.
800
+ * List of external links. Wiki, forums, etc.
557
801
  */
558
- __publicField$1(this, "vidiotMaps");
802
+ __publicField$2(this, "links");
803
+ /**
804
+ * If the mission is available in Ouroboros as a Flashback.
805
+ */
806
+ __publicField$2(this, "flashback");
559
807
  this.key = new Key(data.key).value;
560
808
  this.name = data.name;
561
- this.links = data.links;
562
- this.vidiotMaps = data.vidiotMaps?.map((data2) => new VidiotMap(data2));
809
+ this.type = data.type;
810
+ this.morality = new MoralityList(coalesceToArray(data.morality));
811
+ this.contactKeys = coalesceToArray(data.contactKeys);
812
+ this.levelRange = data.levelRange;
813
+ this.notes = data.notes;
814
+ this.links = data.links ?? [];
815
+ this.flashback = createFlashback(data);
563
816
  }
564
817
  }
818
+ function createFlashback(data) {
819
+ if (!data.flashback) return void 0;
820
+ return {
821
+ id: data.flashback.id,
822
+ levelRange: data.flashback.levelRange ?? data.levelRange,
823
+ name: data.flashback.name ?? data.name,
824
+ morality: new MoralityList(coalesceToArray(data.flashback.morality ?? data.morality)),
825
+ notes: data.flashback.notes
826
+ };
827
+ }
565
828
 
566
- var __defProp = Object.defineProperty;
829
+ var __defProp$1 = Object.defineProperty;
567
830
  var __typeError = (msg) => {
568
831
  throw TypeError(msg);
569
832
  };
570
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
571
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
833
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
834
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
572
835
  var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
573
836
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
574
837
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
575
838
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
576
- var _archetypeIndex, _mapIndex, _badgeIndex;
839
+ var _archetypeIndex, _zoneIndex, _contactIndex, _missionIndex, _badgeIndex;
577
840
  class CohContentDatabase {
578
841
  /**
579
842
  * Initialize the database with a content bundle.
@@ -581,55 +844,84 @@ class CohContentDatabase {
581
844
  */
582
845
  constructor(bundle) {
583
846
  __privateAdd(this, _archetypeIndex, {});
584
- __privateAdd(this, _mapIndex, {});
847
+ __privateAdd(this, _zoneIndex, {});
848
+ __privateAdd(this, _contactIndex, {});
849
+ __privateAdd(this, _missionIndex, {});
585
850
  __privateAdd(this, _badgeIndex);
586
851
  /**
587
852
  * Metadata about the content bundle.
588
853
  */
589
- __publicField(this, "metadata");
854
+ __publicField$1(this, "metadata");
590
855
  /**
591
- * List of the game server names in this server group.
856
+ * List of the game server names.
857
+ *
592
858
  * Torchbearer, Excelsior, etc.
593
859
  */
594
- __publicField(this, "servers");
860
+ __publicField$1(this, "servers");
861
+ /**
862
+ * List of archetypes.
863
+ */
864
+ __publicField$1(this, "archetypes");
865
+ /**
866
+ * List of game zones.
867
+ */
868
+ __publicField$1(this, "zones");
595
869
  /**
596
- * List of archetypes available in this server group.
870
+ * List of contacts.
597
871
  */
598
- __publicField(this, "archetypes");
872
+ __publicField$1(this, "contacts");
599
873
  /**
600
- * List of game maps supported by this server group.
874
+ * List of missions.
601
875
  */
602
- __publicField(this, "maps");
876
+ __publicField$1(this, "missions");
603
877
  /**
604
- * List of badges available on this server group.
878
+ * List of badges.
605
879
  */
606
- __publicField(this, "badges");
880
+ __publicField$1(this, "badges");
607
881
  this.metadata = new BundleMetadata(bundle);
608
882
  this.servers = bundle.servers ?? [];
609
883
  this.archetypes = bundle.archetypes?.map((data) => {
610
- if (__privateGet(this, _archetypeIndex)[data.key] !== void 0) throw new Error(`Duplicate archetype key [${data.key}]`);
884
+ if (__privateGet(this, _archetypeIndex)[data.key] !== void 0) throw new Error(`Duplicate archetype key '${data.key}'`);
611
885
  const archetype = new Archetype(data);
612
886
  __privateGet(this, _archetypeIndex)[archetype.key] = archetype;
613
887
  return archetype;
614
888
  }) ?? [];
615
- this.maps = bundle.maps?.map((data) => {
616
- if (__privateGet(this, _mapIndex)[data.key] !== void 0) throw new Error(`Duplicate map key [${data.key}]`);
617
- const map = new GameMap(data);
618
- __privateGet(this, _mapIndex)[map.key] = map;
619
- return map;
889
+ this.zones = bundle.zones?.map((data) => {
890
+ if (__privateGet(this, _zoneIndex)[data.key] !== void 0) throw new Error(`Duplicate zone key '${data.key}'`);
891
+ const zone = new Zone(data);
892
+ __privateGet(this, _zoneIndex)[zone.key] = zone;
893
+ return zone;
894
+ }) ?? [];
895
+ this.contacts = bundle.contacts?.map((data) => {
896
+ if (__privateGet(this, _contactIndex)[data.key] !== void 0) throw new Error(`Duplicate contact key '${data.key}'`);
897
+ const contact = new Contact(data);
898
+ __privateGet(this, _contactIndex)[contact.key] = contact;
899
+ return contact;
900
+ }) ?? [];
901
+ this.missions = bundle.missions?.map((data) => {
902
+ if (__privateGet(this, _missionIndex)[data.key] !== void 0) throw new Error(`Duplicate mission key '${data.key}'`);
903
+ const mission = new Mission(data);
904
+ __privateGet(this, _missionIndex)[mission.key] = mission;
905
+ return mission;
620
906
  }) ?? [];
621
907
  this.badges = bundle.badges?.map((data) => new Badge(data)) ?? [];
622
- __privateSet(this, _badgeIndex, new BadgeIndex(this.badges, this.maps));
908
+ __privateSet(this, _badgeIndex, new BadgeIndex(this.badges));
623
909
  }
624
910
  getArchetype(key) {
625
- const result = __privateGet(this, _archetypeIndex)[key];
626
- if (result === void 0) throw new Error(`Unknown archetype key [${key}]`);
627
- return result;
911
+ if (!key) return void 0;
912
+ return __privateGet(this, _archetypeIndex)[key];
628
913
  }
629
- getMap(key) {
630
- const result = __privateGet(this, _mapIndex)[key];
631
- if (result === void 0) throw new Error(`Unknown map key [${key}]`);
632
- return result;
914
+ getZone(key) {
915
+ if (!key) return void 0;
916
+ return __privateGet(this, _zoneIndex)[key];
917
+ }
918
+ getContact(key) {
919
+ if (!key) return void 0;
920
+ return __privateGet(this, _contactIndex)[key];
921
+ }
922
+ getMission(key) {
923
+ if (!key) return void 0;
924
+ return __privateGet(this, _missionIndex)[key];
633
925
  }
634
926
  getBadge(key) {
635
927
  return __privateGet(this, _badgeIndex).getBadge(key);
@@ -645,20 +937,55 @@ class CohContentDatabase {
645
937
  }
646
938
  }
647
939
  _archetypeIndex = new WeakMap();
648
- _mapIndex = new WeakMap();
940
+ _zoneIndex = new WeakMap();
941
+ _contactIndex = new WeakMap();
942
+ _missionIndex = new WeakMap();
649
943
  _badgeIndex = new WeakMap();
650
944
 
945
+ var __defProp = Object.defineProperty;
946
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
947
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
948
+ class Location {
949
+ constructor(data) {
950
+ /**
951
+ * Key of the {@link Zone} that the location references.
952
+ */
953
+ __publicField(this, "zoneKey");
954
+ /**
955
+ * In-game `/loc` coordinates of the location.
956
+ */
957
+ __publicField(this, "coords");
958
+ /**
959
+ * The type of icon to use if the location appears on a map. (Typically the Vidiot map icon).
960
+ */
961
+ __publicField(this, "icon");
962
+ /**
963
+ * The text that should appear in the location icon. (Typically a number or symbol from the Vidiot map).
964
+ */
965
+ __publicField(this, "iconText");
966
+ this.zoneKey = data.zoneKey;
967
+ this.coords = data.coords;
968
+ this.icon = data.icon;
969
+ this.iconText = data.iconText;
970
+ }
971
+ }
972
+
651
973
  const CHANGELOG = [
652
974
  {
653
975
  version: "2.0.0",
654
976
  date: /* @__PURE__ */ new Date("2025-03-12"),
655
977
  description: `* Replaced redundant interfaces with their concrete equivalents.
656
978
  * Server groups are now referred to as 'forks'.
657
- * Replaced enums with union types.
658
- * \`IServerGroupData\` is now \`ContentBundle\` and each database instance is now designed to accept only a single server group.
979
+ * Replaced enums with union types and changed values to \`kebab-case\`.
980
+ * \`IServerGroupData\` is now \`ContentBundle\` and each database instance is now designed to accept only a single bundle.
981
+ * \`GameMap\` is now \`Zone\`.
659
982
  * Removed the \`serverGroup\` property from entities to simplify the object tree given that only a single context can exist per db now.
660
983
  * Added a simple indexing and search function for badge names, text and acquisition info.
661
- * Map and badge references now follow a standard Markdown link format with a \`badge://\` or \`map://\` protocol.
984
+ * Zone and badge references now follow a standard Markdown link format with a \`badge://\` or \`map://\` protocol.
985
+ * Badge partials are now known as badge requirements.
986
+ * Removed the \`VidiotMap\` API as it was never used or fleshed out properly.
987
+ * Added formal support for Missions and Contacts in badge requirements.
988
+ * Move exploration badge locations into badge requirement list.
662
989
  * Standardized pluralization of some field names (name, icon).
663
990
  * Combined \`settitle\` ids into a single tuple field.
664
991
  * Change from GNU to The Unlicense.
@@ -671,44 +998,39 @@ const CHANGELOG = [
671
998
  }
672
999
  ];
673
1000
 
674
- function badgeUri(target) {
675
- const key = typeof target === "string" ? target : target.key;
676
- return `badge://${key}`;
677
- }
678
- function badgeLink(target) {
679
- const key = typeof target === "string" ? target : target.key;
680
- return `[${key}](${badgeUri(target)})`;
681
- }
682
- function mapUri(target) {
683
- const key = typeof target === "string" ? target : target.key;
684
- return `map://${key}`;
685
- }
686
- function mapLink(target) {
687
- const key = typeof target === "string" ? target : target.key;
688
- return `[${key}](${mapUri(target)})`;
689
- }
690
-
691
1001
  exports.ALIGNMENT = ALIGNMENT;
692
- exports.Alignments = Alignments;
1002
+ exports.AlignmentList = AlignmentList;
693
1003
  exports.Alternates = Alternates;
694
1004
  exports.Archetype = Archetype;
695
- exports.BADGE_PARTIAL_TYPE = BADGE_PARTIAL_TYPE;
1005
+ exports.BADGE_REQUIREMENT_TYPE = BADGE_REQUIREMENT_TYPE;
696
1006
  exports.BADGE_TYPE = BADGE_TYPE;
697
1007
  exports.Badge = Badge;
698
1008
  exports.BadgeIndex = BadgeIndex;
699
- exports.BadgePartial = BadgePartial;
1009
+ exports.BadgeRequirement = BadgeRequirement;
700
1010
  exports.BundleMetadata = BundleMetadata;
701
1011
  exports.CHANGELOG = CHANGELOG;
702
1012
  exports.CohContentDatabase = CohContentDatabase;
1013
+ exports.Contact = Contact;
703
1014
  exports.ENHANCEMENT_CATEGORY = ENHANCEMENT_CATEGORY;
704
- exports.GameMap = GameMap;
705
1015
  exports.Key = Key;
706
- exports.PLAQUE_TYPE = PLAQUE_TYPE;
1016
+ exports.Location = Location;
1017
+ exports.MISSION_TYPE = MISSION_TYPE;
1018
+ exports.MORALITY = MORALITY;
1019
+ exports.Mission = Mission;
1020
+ exports.MoralityList = MoralityList;
707
1021
  exports.SEX = SEX;
708
- exports.VidiotMap = VidiotMap;
709
- exports.VidiotMapPointOfInterest = VidiotMapPointOfInterest;
1022
+ exports.Zone = Zone;
710
1023
  exports.badgeLink = badgeLink;
711
1024
  exports.badgeUri = badgeUri;
712
- exports.mapLink = mapLink;
713
- exports.mapUri = mapUri;
1025
+ exports.coalesceToArray = coalesceToArray;
1026
+ exports.compareAlignment = compareAlignment;
1027
+ exports.compareByDefaultName = compareByDefaultName;
1028
+ exports.compareByZoneKey = compareByZoneKey;
1029
+ exports.compareSex = compareSex;
1030
+ exports.contactLink = contactLink;
1031
+ exports.contactUri = contactUri;
1032
+ exports.missionLink = missionLink;
1033
+ exports.missionUri = missionUri;
1034
+ exports.zoneLink = zoneLink;
1035
+ exports.zoneUri = zoneUri;
714
1036
  //# sourceMappingURL=coh-content-db.js.map