coh-content-db 1.4.1 → 2.0.0-rc.10

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 (101) hide show
  1. package/.editorconfig +24 -0
  2. package/.github/workflows/build.yml +38 -0
  3. package/.github/workflows/pull-request.yml +32 -0
  4. package/.github/workflows/release.yml +52 -0
  5. package/CHANGELOG.md +42 -0
  6. package/LICENSE +24 -674
  7. package/README.md +101 -16
  8. package/dist/coh-content-db.d.ts +988 -22
  9. package/dist/coh-content-db.js +1044 -2
  10. package/dist/coh-content-db.js.map +1 -0
  11. package/dist/coh-content-db.mjs +1009 -0
  12. package/dist/coh-content-db.mjs.map +1 -0
  13. package/eslint.config.mjs +31 -0
  14. package/jest.config.mjs +7 -0
  15. package/package.json +31 -23
  16. package/rollup.config.mjs +27 -0
  17. package/src/main/api/alignment.ts +19 -0
  18. package/src/main/api/alternate-data.ts +22 -0
  19. package/src/main/api/archetype-data.ts +5 -0
  20. package/src/main/api/badge-data.ts +81 -0
  21. package/src/main/api/badge-requirement-data.ts +64 -0
  22. package/src/main/api/badge-requirement-type.ts +32 -0
  23. package/src/main/api/badge-type.ts +19 -0
  24. package/src/main/api/bundle-data.ts +47 -0
  25. package/src/main/api/bundle-header-data.ts +37 -0
  26. package/src/main/api/contact-data.ts +48 -0
  27. package/src/main/api/enhancement-category.ts +30 -0
  28. package/src/main/api/link.ts +4 -0
  29. package/src/main/api/location-data.ts +28 -0
  30. package/src/main/api/markdown-string.ts +4 -0
  31. package/src/main/api/mission-data.ts +83 -0
  32. package/src/main/api/mission-type.ts +2 -0
  33. package/src/main/api/morality.ts +31 -0
  34. package/src/main/api/sex.ts +10 -0
  35. package/src/main/api/zone-data.ts +20 -0
  36. package/src/main/db/abstract-index.ts +37 -0
  37. package/src/main/db/alignment-list.ts +54 -0
  38. package/src/main/db/alternates.ts +67 -0
  39. package/src/main/db/archetype.ts +14 -0
  40. package/src/main/db/badge-index.ts +57 -0
  41. package/src/main/db/badge-requirement.ts +81 -0
  42. package/src/main/db/badge-search-options.ts +51 -0
  43. package/src/main/db/badge.ts +147 -0
  44. package/src/main/db/bundle-header.ts +44 -0
  45. package/src/main/db/coh-content-database.ts +138 -0
  46. package/src/main/db/contact.ts +62 -0
  47. package/src/main/db/key.ts +18 -0
  48. package/src/main/db/location.ts +30 -0
  49. package/src/main/db/mission.ts +107 -0
  50. package/src/main/db/morality-list.ts +99 -0
  51. package/src/main/db/paged.ts +7 -0
  52. package/src/main/db/zone.ts +28 -0
  53. package/src/main/index.ts +41 -0
  54. package/src/main/util.ts +118 -0
  55. package/src/test/api/alignment.test.ts +65 -0
  56. package/src/test/api/archetype-data.fixture.ts +8 -0
  57. package/src/test/api/badge-data.fixture.ts +8 -0
  58. package/src/test/api/badge-data.test.ts +15 -0
  59. package/src/test/api/badge-requirement-data.fixture.ts +7 -0
  60. package/src/test/api/badge-requirement-type.test.ts +31 -0
  61. package/src/test/api/badge-type.test.ts +35 -0
  62. package/src/test/api/bundle-data.fixture.ts +6 -0
  63. package/src/test/api/bundle-header-data.fixture.ts +6 -0
  64. package/src/test/api/contact-data.fixture.ts +7 -0
  65. package/src/test/api/enhancement-category.test.ts +35 -0
  66. package/src/test/api/mission-data.fixture.ts +12 -0
  67. package/src/test/api/sex.test.ts +63 -0
  68. package/src/test/api/zone-data.fixture.ts +8 -0
  69. package/src/test/db/abstract-index.test.ts +55 -0
  70. package/src/test/db/alignment-list.test.ts +200 -0
  71. package/src/test/db/alternates.test.ts +188 -0
  72. package/src/test/db/archetype.test.ts +38 -0
  73. package/src/test/db/badge-index.test.ts +519 -0
  74. package/src/test/db/badge-requirement.test.ts +145 -0
  75. package/src/test/db/badge.test.ts +337 -0
  76. package/src/test/db/bundle-header.test.ts +76 -0
  77. package/src/test/db/coh-content-database.test.ts +282 -0
  78. package/src/test/db/contact.test.ts +97 -0
  79. package/src/test/db/key.test.ts +22 -0
  80. package/src/test/db/location.test.ts +51 -0
  81. package/src/test/db/mission.test.ts +171 -0
  82. package/src/test/db/morality-list.test.ts +457 -0
  83. package/src/test/db/zone.test.ts +36 -0
  84. package/src/test/integration.test.ts +16 -0
  85. package/src/test/util.test.ts +165 -0
  86. package/tsconfig.json +117 -0
  87. package/dist/_changelog.d.ts +0 -3
  88. package/dist/coh-content-db.nomin.js +0 -635
  89. package/dist/content-refence-utils.d.ts +0 -4
  90. package/dist/index.d.ts +0 -8
  91. package/dist/internal/_common.d.ts +0 -4
  92. package/dist/internal/archetype.d.ts +0 -10
  93. package/dist/internal/badge.d.ts +0 -44
  94. package/dist/internal/game-map.d.ts +0 -33
  95. package/dist/internal/server-group.d.ts +0 -24
  96. package/dist/types/archetype.d.ts +0 -9
  97. package/dist/types/badge.d.ts +0 -192
  98. package/dist/types/enhancement.d.ts +0 -28
  99. package/dist/types/game-map.d.ts +0 -47
  100. package/dist/types/link.d.ts +0 -4
  101. package/dist/types/server-group.d.ts +0 -75
@@ -0,0 +1,147 @@
1
+ import { BadgeType } from '../api/badge-type'
2
+ import { Link } from '../api/link'
3
+ import { BadgeData } from '../api/badge-data'
4
+ import { BadgeRequirement } from './badge-requirement'
5
+ import { Key } from './key'
6
+ import { Alternates } from './alternates'
7
+ import { MarkdownString } from '../api/markdown-string'
8
+ import { coalesceToArray } from '../util'
9
+ import { MoralityList } from './morality-list'
10
+
11
+ export class Badge {
12
+ readonly #requirementsIndex: Record<string, BadgeRequirement> = {}
13
+ readonly #zoneKeys = new Set<string>()
14
+
15
+ /**
16
+ * The database key for this badge.
17
+ */
18
+ readonly key: string
19
+
20
+ /**
21
+ * The type of badge.
22
+ */
23
+ readonly type: BadgeType
24
+
25
+ /**
26
+ * The name of this badge.
27
+ *
28
+ * May vary by character sex or alignment.
29
+ */
30
+ readonly name: Alternates<string>
31
+
32
+ /**
33
+ * The character moralities that this badge is available to.
34
+ */
35
+ readonly morality: MoralityList
36
+
37
+ /**
38
+ * The badge text as it appears in-game. May vary by character sex or alignment.
39
+ */
40
+ readonly badgeText: Alternates<MarkdownString>
41
+
42
+ /**
43
+ * Short description of how to acquire the badge. Detailed instructions will be in the notes field.
44
+ */
45
+ readonly acquisition?: MarkdownString
46
+
47
+ /**
48
+ * Absolute URL to this badge's icon.
49
+ *
50
+ * May vary by character sex or alignment.
51
+ */
52
+ readonly icon: Alternates<string>
53
+
54
+ /**
55
+ * Freeform notes or tips about the badge.
56
+ */
57
+ readonly notes?: MarkdownString
58
+
59
+ /**
60
+ * List of external links. Wiki, forums, etc.
61
+ */
62
+ readonly links: Link[]
63
+
64
+ /**
65
+ * The id used with the in-game `/settitle` command to apply the badge.
66
+ * The first value is the id for primal characters and the (optional) second number is the id for praetorian characters.
67
+ */
68
+ readonly setTitleId?: [number, number?]
69
+
70
+ /**
71
+ * A description of the effect the badge will have, such as a buff or granting a temporary power.
72
+ */
73
+ readonly effect?: MarkdownString
74
+
75
+ /**
76
+ * Represents the requirements for badges with multiple fulfillment steps, such as visiting monuments for history badges, completing missions, or collecting other badges.
77
+ */
78
+ readonly requirements?: BadgeRequirement[]
79
+
80
+ /**
81
+ * 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.
82
+ */
83
+ readonly ignoreInTotals: boolean
84
+
85
+ constructor(badgeData: BadgeData) {
86
+ this.key = new Key(badgeData.key).value
87
+ this.type = badgeData.type
88
+ this.name = new Alternates(badgeData.name)
89
+ this.morality = new MoralityList(coalesceToArray(badgeData.morality))
90
+ this.badgeText = new Alternates(badgeData.badgeText ?? [])
91
+ this.acquisition = badgeData.acquisition
92
+ this.icon = new Alternates(badgeData.icon ?? [])
93
+ this.notes = badgeData.notes
94
+ this.links = badgeData.links ?? []
95
+ this.effect = badgeData.effect
96
+ this.setTitleId = badgeData.setTitleId
97
+ this.ignoreInTotals = badgeData.ignoreInTotals ?? false
98
+
99
+ this.requirements = badgeData.requirements?.map((requirementData) => {
100
+ if (this.#requirementsIndex[requirementData.key]) throw new Error(`Duplicate badge requirement key [${badgeData.key}:${requirementData.key}]`)
101
+ const requirement = new BadgeRequirement(requirementData)
102
+ this.#requirementsIndex[requirement.key] = requirement
103
+ if (requirement.location) for (const location of requirement.location) {
104
+ if (location.zoneKey) this.#zoneKeys.add(location.zoneKey)
105
+ }
106
+ return requirement
107
+ })
108
+ }
109
+
110
+ getRequirement(key: string): BadgeRequirement {
111
+ const result = this.#requirementsIndex[key]
112
+ if (result === undefined) throw new Error(`Unknown badge requirement key [${key}]`)
113
+ return result
114
+ }
115
+
116
+ /**
117
+ * Return a list of all the zone keys referenced by this badge.
118
+ */
119
+ get zoneKeys(): string[] {
120
+ return [...this.#zoneKeys]
121
+ }
122
+
123
+ /**
124
+ * The zone key if this badge relates to a single zone.
125
+ */
126
+ get zoneKey(): string | undefined {
127
+ return this.#zoneKeys.size === 1 ? this.#zoneKeys.values().next().value : undefined
128
+ }
129
+ }
130
+
131
+ export function compareByDefaultName(a?: Badge, b?: Badge): number {
132
+ const aName = a?.name.default?.value
133
+ const bName = b?.name.default?.value
134
+ if (!aName && !bName) return 0
135
+ if (!aName) return 1
136
+ if (!bName) return -1
137
+ return aName.localeCompare(bName)
138
+ }
139
+
140
+ export function compareByZoneKey(a?: Badge, b?: Badge): number {
141
+ const aZone = a?.zoneKey
142
+ const bZone = b?.zoneKey
143
+ if (!aZone && !bZone) return 0
144
+ if (!aZone) return 1
145
+ if (!bZone) return -1
146
+ return aZone.localeCompare(bZone)
147
+ }
@@ -0,0 +1,44 @@
1
+ import { Link } from '../api/link'
2
+ import { MarkdownString } from '../api/markdown-string'
3
+ import { BundleHeaderData } from '../api/bundle-header-data'
4
+
5
+ export class BundleHeader {
6
+ /**
7
+ * Name of the content bundle.
8
+ */
9
+ readonly name?: string
10
+
11
+ /**
12
+ * Description of the fork.
13
+ */
14
+ readonly description?: MarkdownString
15
+
16
+ /**
17
+ * Url for the repository where the bundle is maintained.
18
+ */
19
+ readonly repositoryUrl?: string
20
+
21
+ /**
22
+ * Url for the location of the changelog.
23
+ */
24
+ readonly changelogUrl?: string
25
+
26
+ /**
27
+ * List of external links. Wiki, forums, etc.
28
+ */
29
+ readonly links?: Link[]
30
+
31
+ /**
32
+ * The current version of the data package.
33
+ */
34
+ readonly version?: string
35
+
36
+ constructor(data: BundleHeaderData | undefined) {
37
+ this.name = data?.name
38
+ this.description = data?.description
39
+ this.repositoryUrl = data?.repositoryUrl
40
+ this.changelogUrl = data?.changelogUrl
41
+ this.links = data?.links ?? []
42
+ this.version = data?.version
43
+ }
44
+ }
@@ -0,0 +1,138 @@
1
+ import { BundleData } from '../api/bundle-data'
2
+ import { Archetype } from './archetype'
3
+ import { Zone } from './zone'
4
+ import { Badge } from './badge'
5
+ import { BundleHeader } from './bundle-header'
6
+ import { BadgeSearchOptions } from './badge-search-options'
7
+ import { Paged } from './paged'
8
+ import { Contact } from './contact'
9
+ import { Mission } from './mission'
10
+ import { AbstractIndex } from './abstract-index'
11
+ import { BadgeIndex } from './badge-index'
12
+
13
+ export class CohContentDatabase {
14
+ readonly #archetypeIndex
15
+ readonly #zoneIndex
16
+ readonly #contactIndex
17
+ readonly #missionIndex
18
+ readonly #badgeIndex
19
+
20
+ readonly #header: BundleHeader
21
+ readonly #servers: string[]
22
+
23
+ /**
24
+ * Create a db instance from the given content bundle.
25
+ * @param bundle The bundle to load.
26
+ */
27
+ constructor(bundle: BundleData) {
28
+ this.#header = new BundleHeader(bundle.header)
29
+ this.#servers = bundle.servers ?? []
30
+
31
+ this.#archetypeIndex = new AbstractIndex<Archetype>('key', bundle.archetypes?.map(x => new Archetype(x)))
32
+ this.#zoneIndex = new AbstractIndex<Zone>('key', bundle.zones?.map(x => new Zone(x)))
33
+ this.#contactIndex = new AbstractIndex<Contact>('key', bundle.contacts?.map(x => new Contact(x)))
34
+ this.#missionIndex = new AbstractIndex<Mission>('key', bundle.missions?.map(x => new Mission(x)))
35
+ this.#badgeIndex = new BadgeIndex(bundle.badges?.map(x => new Badge(x)))
36
+ }
37
+
38
+ /**
39
+ * Header information about the content bundle.
40
+ */
41
+ get header(): BundleHeader {
42
+ return this.#header
43
+ }
44
+
45
+ /**
46
+ * List of the game server names.
47
+ *
48
+ * Torchbearer, Excelsior, etc.
49
+ */
50
+ get servers(): string[] {
51
+ return this.#servers
52
+ }
53
+
54
+ /**
55
+ * List of archetypes.
56
+ */
57
+ get archetypes(): Archetype[] {
58
+ return this.#archetypeIndex.values
59
+ }
60
+
61
+ /**
62
+ * Get archetype by key.
63
+ * @param key The key.
64
+ */
65
+ getArchetype(key: string | undefined): Archetype | undefined {
66
+ return this.#archetypeIndex.get(key)
67
+ }
68
+
69
+ /**
70
+ * List of game zones.
71
+ */
72
+ get zones(): Zone[] {
73
+ return this.#zoneIndex.values
74
+ }
75
+
76
+ /**
77
+ * Get zone by key.
78
+ * @param key The key.
79
+ */
80
+ getZone(key: string | undefined): Zone | undefined {
81
+ return this.#zoneIndex.get(key)
82
+ }
83
+
84
+ /**
85
+ * List of contacts.
86
+ */
87
+ get contacts(): Contact[] {
88
+ return this.#contactIndex.values
89
+ }
90
+
91
+ /**
92
+ * Get contact by key.
93
+ * @param key The key.
94
+ */
95
+ getContact(key: string | undefined): Contact | undefined {
96
+ return this.#contactIndex.get(key)
97
+ }
98
+
99
+ /**
100
+ * List of missions.
101
+ */
102
+ get missions(): Mission[] {
103
+ return this.#missionIndex.values
104
+ }
105
+
106
+ /**
107
+ * Get mission by key.
108
+ * @param key The key.
109
+ */
110
+ getMission(key: string | undefined): Mission | undefined {
111
+ return this.#missionIndex.get(key)
112
+ }
113
+
114
+ /**
115
+ * List of badges.
116
+ */
117
+ get badges(): Badge[] {
118
+ return this.#badgeIndex.values
119
+ }
120
+
121
+ /**
122
+ * Get badge by key.
123
+ * @param key The key.
124
+ */
125
+ getBadge(key: string | undefined): Badge | undefined {
126
+ return this.#badgeIndex.get(key)
127
+ }
128
+
129
+ /**
130
+ * Search, sort and filter the badge list.
131
+ * This is a fairly brute-forced approach and will not be as performant as loading the badge data into a traditional
132
+ * database engine, but is sufficient for most operations.
133
+ * @param options {@link BadgeSearchOptions}
134
+ */
135
+ searchBadges(options?: BadgeSearchOptions): Paged<Badge> {
136
+ return this.#badgeIndex.search(options)
137
+ }
138
+ }
@@ -0,0 +1,62 @@
1
+ import { Link } from '../api/link'
2
+ import { Key } from './key'
3
+ import { MarkdownString } from '../api/markdown-string'
4
+ import { ContactData } from '../api/contact-data'
5
+ import { Location } from './location'
6
+ import { MoralityList } from './morality-list'
7
+ import { coalesceToArray } from '../util'
8
+
9
+ export class Contact {
10
+ /**
11
+ * Unique key used to reference this contact.
12
+ *
13
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
14
+ */
15
+ readonly key: string
16
+
17
+ /**
18
+ * The name of this contact.
19
+ */
20
+ readonly name: string
21
+
22
+ /**
23
+ * The contact's title.
24
+ */
25
+ readonly title?: string
26
+
27
+ /**
28
+ * The character moralities that this contact will interact with.
29
+ */
30
+ readonly morality?: MoralityList
31
+
32
+ /**
33
+ * The location of this contact.
34
+ */
35
+ readonly location?: Location
36
+
37
+ /**
38
+ * The level range this contact will offer missions for.
39
+ */
40
+ readonly levelRange?: [number, number?]
41
+
42
+ /**
43
+ * Freeform notes or tips about the contact.
44
+ */
45
+ readonly notes?: MarkdownString
46
+
47
+ /**
48
+ * List of external links. Wiki, forums, etc.
49
+ */
50
+ readonly links: Link[]
51
+
52
+ constructor(data: ContactData) {
53
+ this.key = new Key(data.key).value
54
+ this.name = data.name
55
+ this.title = data.title
56
+ this.morality = new MoralityList(coalesceToArray(data.morality))
57
+ this.location = data.location
58
+ this.levelRange = data.levelRange
59
+ this.notes = data.notes
60
+ this.links = data.links ?? []
61
+ }
62
+ }
@@ -0,0 +1,18 @@
1
+ const INVALID_KEY_PATTERN = /[^a-z0-9-]/
2
+
3
+ export class Key {
4
+ readonly #value: string
5
+
6
+ constructor(value: string) {
7
+ this.#validateKey(value)
8
+ this.#value = value
9
+ }
10
+
11
+ get value(): string {
12
+ return this.#value
13
+ }
14
+
15
+ #validateKey(key: string): void {
16
+ if (INVALID_KEY_PATTERN.test(key)) throw new Error(`Invalid key: [${key}]; Keys can only contain lowercase characters, numbers and dashes.`)
17
+ }
18
+ }
@@ -0,0 +1,30 @@
1
+ import { Coords, LocationData, LocationIcon } from '../api/location-data'
2
+
3
+ export class Location {
4
+ /**
5
+ * Key of the {@link Zone} that the location references.
6
+ */
7
+ readonly zoneKey?: string
8
+
9
+ /**
10
+ * In-game `/loc` coordinates of the location.
11
+ */
12
+ readonly coords?: Coords
13
+
14
+ /**
15
+ * The type of icon to use if the location appears on a map. (Typically the Vidiot map icon).
16
+ */
17
+ readonly icon?: LocationIcon
18
+
19
+ /**
20
+ * The text that should appear in the location icon. (Typically a number or symbol from the Vidiot map).
21
+ */
22
+ readonly iconText?: string
23
+
24
+ constructor(data: LocationData) {
25
+ this.zoneKey = data.zoneKey
26
+ this.coords = data.coords
27
+ this.icon = data.icon
28
+ this.iconText = data.iconText
29
+ }
30
+ }
@@ -0,0 +1,107 @@
1
+ import { MissionType } from '../api/mission-type'
2
+ import { MarkdownString } from '../api/markdown-string'
3
+ import { Link } from '../api/link'
4
+ import { MissionData } from '../api/mission-data'
5
+ import { Key } from './key'
6
+ import { coalesceToArray } from '../util'
7
+ import { MoralityList } from './morality-list'
8
+
9
+ export class Mission {
10
+ /**
11
+ * Unique key used to reference this mission.
12
+ *
13
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
14
+ */
15
+ readonly key: string
16
+
17
+ /**
18
+ * The name of the mission as it appears from the contact.
19
+ *
20
+ * The name may be different when viewed in Ouroboros as a Flashback.
21
+ */
22
+ readonly name: string
23
+
24
+ /**
25
+ * The type of mission... Story arc, task force, trial, etc.
26
+ */
27
+ readonly type: MissionType
28
+
29
+ /**
30
+ * The character moralities that may accept the mission.
31
+ */
32
+ readonly morality: MoralityList
33
+
34
+ /**
35
+ * The keys of any contacts that provide this mission.
36
+ */
37
+ readonly contactKeys?: string[]
38
+
39
+ /**
40
+ * The level range this mission is available for.
41
+ */
42
+ readonly levelRange?: [number, number?]
43
+
44
+ /**
45
+ * Freeform notes or tips about the mission.
46
+ */
47
+ readonly notes?: MarkdownString
48
+
49
+ /**
50
+ * List of external links. Wiki, forums, etc.
51
+ */
52
+ readonly links: Link[]
53
+
54
+ /**
55
+ * If the mission is available in Ouroboros as a Flashback.
56
+ */
57
+ readonly flashback?: {
58
+
59
+ /**
60
+ * The id of the mission as seen in the Flashback menu, i.e. '14.01'.
61
+ */
62
+ readonly id: string
63
+
64
+ /**
65
+ * The level range this mission appears under as a Flashback. Leave undefined if the same as the base mission.
66
+ */
67
+ readonly levelRange?: [number, number?]
68
+
69
+ /**
70
+ * The name as it appears in the Flashback list. Leave undefined if the same as the base mission.
71
+ */
72
+ readonly name?: string
73
+
74
+ /**
75
+ * The character moralities that the mission will appear for in the Flashback list. Leave undefined if the same as the base mission.
76
+ */
77
+ readonly morality?: MoralityList
78
+
79
+ /**
80
+ * Freeform notes or tips about the Flashback version of the mission.
81
+ */
82
+ readonly notes?: MarkdownString
83
+ }
84
+
85
+ constructor(data: MissionData) {
86
+ this.key = new Key(data.key).value
87
+ this.name = data.name
88
+ this.type = data.type
89
+ this.morality = new MoralityList(coalesceToArray(data.morality))
90
+ this.contactKeys = coalesceToArray(data.contactKeys)
91
+ this.levelRange = data.levelRange
92
+ this.notes = data.notes
93
+ this.links = data.links ?? []
94
+ this.flashback = createFlashback(data)
95
+ }
96
+ }
97
+
98
+ function createFlashback(data: MissionData): Mission['flashback'] {
99
+ if (!data.flashback) return undefined
100
+ return {
101
+ id: data.flashback.id,
102
+ levelRange: data.flashback.levelRange ?? data.levelRange,
103
+ name: data.flashback.name ?? data.name,
104
+ morality: new MoralityList(coalesceToArray(data.flashback.morality ?? data.morality)),
105
+ notes: data.flashback.notes,
106
+ }
107
+ }
@@ -0,0 +1,99 @@
1
+ import { MORALITY, Morality, MoralityExtended } from '../api/morality'
2
+
3
+ export class MoralityList {
4
+ readonly #items: Set<Morality>
5
+
6
+ readonly hero: boolean
7
+ readonly vigilante: boolean
8
+ readonly villain: boolean
9
+ readonly rogue: boolean
10
+ readonly resistance: boolean
11
+ readonly loyalist: boolean
12
+
13
+ readonly primal: boolean
14
+ readonly praetorian: boolean
15
+ readonly heroic: boolean
16
+ readonly villainous: boolean
17
+ readonly paragonCityAccess: boolean
18
+ readonly rogueIslesAccess: boolean
19
+
20
+ readonly all: boolean
21
+
22
+ constructor(items?: MoralityExtended[]) {
23
+ const set = new Set(items ?? [...MORALITY])
24
+ this.hero = set.has('hero') || set.has('primal') || set.has('heroic') || set.has('paragon-city-access') || set.has('all')
25
+ this.vigilante = set.has('vigilante') || set.has('primal') || set.has('heroic') || set.has('paragon-city-access') || set.has('rogue-isles-access') || set.has('all')
26
+ this.villain = set.has('villain') || set.has('primal') || set.has('villainous') || set.has('rogue-isles-access') || set.has('all')
27
+ this.rogue = set.has('rogue') || set.has('primal') || set.has('villainous') || set.has('paragon-city-access') || set.has('rogue-isles-access') || set.has('all')
28
+ this.resistance = set.has('resistance') || set.has('praetorian') || set.has('all')
29
+ this.loyalist = set.has('loyalist') || set.has('praetorian') || set.has('all')
30
+
31
+ this.primal = this.hero && this.vigilante && this.villain && this.rogue
32
+ this.praetorian = this.loyalist && this.resistance
33
+ this.heroic = this.hero && this.vigilante
34
+ this.villainous = this.villain && this.rogue
35
+ this.paragonCityAccess = this.heroic && this.rogue
36
+ this.rogueIslesAccess = this.villainous && this.vigilante
37
+
38
+ this.all = this.primal && this.praetorian
39
+
40
+ this.#items = new Set()
41
+ if (this.hero) this.#items.add('hero')
42
+ if (this.vigilante) this.#items.add('vigilante')
43
+ if (this.villain) this.#items.add('villain')
44
+ if (this.rogue) this.#items.add('rogue')
45
+ if (this.resistance) this.#items.add('resistance')
46
+ if (this.loyalist) this.#items.add('loyalist')
47
+ }
48
+
49
+ get items(): Morality[] {
50
+ return [...this.#items]
51
+ }
52
+
53
+ has(morality?: MoralityExtended): boolean {
54
+ switch (morality) {
55
+ case 'hero': {
56
+ return this.hero
57
+ }
58
+ case 'vigilante': {
59
+ return this.vigilante
60
+ }
61
+ case 'villain': {
62
+ return this.villain
63
+ }
64
+ case 'rogue': {
65
+ return this.rogue
66
+ }
67
+ case 'resistance': {
68
+ return this.resistance
69
+ }
70
+ case 'loyalist': {
71
+ return this.loyalist
72
+ }
73
+ case 'primal' : {
74
+ return this.primal
75
+ }
76
+ case 'praetorian': {
77
+ return this.praetorian
78
+ }
79
+ case 'heroic': {
80
+ return this.hero
81
+ }
82
+ case 'paragon-city-access': {
83
+ return this.paragonCityAccess
84
+ }
85
+ case 'rogue-isles-access': {
86
+ return this.rogueIslesAccess
87
+ }
88
+ case 'villainous': {
89
+ return this.villainous
90
+ }
91
+ case 'all': {
92
+ return this.all
93
+ }
94
+ default: {
95
+ return false
96
+ }
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,7 @@
1
+ export interface Paged<T> {
2
+ items: T[]
3
+ page: number
4
+ pageSize?: number
5
+ totalItems: number
6
+ totalPages: number
7
+ }
@@ -0,0 +1,28 @@
1
+ import { Link } from '../api/link'
2
+ import { ZoneData } from '../api/zone-data'
3
+ import { Key } from './key'
4
+
5
+ export class Zone {
6
+ /**
7
+ * Unique key used to reference this zone.
8
+ *
9
+ * Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
10
+ */
11
+ readonly key: string
12
+
13
+ /**
14
+ * The name of the zone as it appears in-game.
15
+ */
16
+ readonly name: string
17
+
18
+ /**
19
+ * List of external links. Wiki, forums, etc.
20
+ */
21
+ readonly links: Link[]
22
+
23
+ constructor(data: ZoneData) {
24
+ this.key = new Key(data.key).value
25
+ this.name = data.name
26
+ this.links = data.links ?? []
27
+ }
28
+ }