coh-content-db 2.0.0-rc.6 → 2.0.0-rc.8
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.
- package/.github/workflows/build.yml +1 -1
- package/.github/workflows/pull-request.yml +1 -1
- package/.github/workflows/release.yml +1 -1
- package/README.md +3 -3
- package/dist/coh-content-db.d.ts +444 -194
- package/dist/coh-content-db.js +720 -413
- package/dist/coh-content-db.js.map +1 -1
- package/dist/coh-content-db.mjs +708 -412
- package/dist/coh-content-db.mjs.map +1 -1
- package/eslint.config.mjs +1 -0
- package/package.json +1 -1
- package/src/main/api/alignment.ts +18 -2
- package/src/main/api/badge-data.ts +12 -42
- package/src/main/api/badge-requirement-data.ts +17 -35
- package/src/main/api/badge-requirement-type.ts +28 -7
- package/src/main/api/badge-type.ts +15 -15
- package/src/main/api/contact-data.ts +7 -5
- package/src/main/api/content-bundle.ts +6 -0
- package/src/main/api/enhancement-category.ts +26 -26
- package/src/main/api/location-data.ts +28 -0
- package/src/main/api/mission-data.ts +83 -0
- package/src/main/api/mission-type.ts +2 -0
- package/src/main/api/morality.ts +31 -0
- package/src/main/api/sex.ts +8 -1
- package/src/main/api/zone-data.ts +1 -1
- package/src/main/changelog.ts +5 -4
- package/src/main/db/abstract-index.ts +41 -0
- package/src/main/db/alignment-list.ts +54 -0
- package/src/main/db/alternates.ts +15 -32
- package/src/main/db/badge-index.ts +14 -50
- package/src/main/db/badge-requirement.ts +22 -43
- package/src/main/db/badge-search-options.ts +4 -4
- package/src/main/db/badge.ts +53 -54
- package/src/main/db/bundle-metadata.ts +8 -2
- package/src/main/db/coh-content-database.ts +80 -67
- package/src/main/db/contact.ts +17 -14
- package/src/main/db/location.ts +30 -0
- package/src/main/db/mission.ts +107 -0
- package/src/main/db/morality-list.ts +99 -0
- package/src/main/db/zone.ts +1 -1
- package/src/main/index.ts +8 -3
- package/src/main/util.ts +43 -3
- package/src/test/api/alignment.test.ts +38 -4
- package/src/test/api/badge-data.fixture.ts +1 -17
- package/src/test/api/badge-data.test.ts +3 -3
- package/src/test/api/badge-requirement-data.fixture.ts +1 -11
- package/src/test/api/badge-requirement-type.test.ts +3 -3
- package/src/test/api/badge-type.test.ts +5 -5
- package/src/test/api/contact-data.fixture.ts +0 -6
- package/src/test/api/content-bundle.fixture.ts +1 -17
- package/src/test/api/enhancement-category.test.ts +5 -5
- package/src/test/api/mission-data.fixture.ts +12 -0
- package/src/test/api/sex.test.ts +33 -1
- package/src/test/api/zone-data.fixture.ts +1 -1
- package/src/test/db/abstract-index.test.ts +86 -0
- package/src/test/db/alignment-list.test.ts +200 -0
- package/src/test/db/alternates.test.ts +60 -56
- package/src/test/db/badge-index.test.ts +220 -183
- package/src/test/db/badge-requirement.test.ts +35 -70
- package/src/test/db/badge.test.ts +185 -64
- package/src/test/db/bundle-metadata.test.ts +17 -0
- package/src/test/db/coh-content-database.test.ts +193 -119
- package/src/test/db/contact.test.ts +25 -24
- package/src/test/db/location.test.ts +51 -0
- package/src/test/db/mission.test.ts +171 -0
- package/src/test/db/morality-list.test.ts +457 -0
- package/src/test/db/zone.test.ts +4 -4
- package/src/test/util.test.ts +54 -1
- package/src/main/api/plaque-type.ts +0 -6
- package/src/main/db/alignments.ts +0 -17
- package/src/test/api/alignments.test.ts +0 -40
- package/src/test/api/plaque-type.test.ts +0 -31
|
@@ -1,79 +1,62 @@
|
|
|
1
1
|
import { BadgeRequirementData } from '../api/badge-requirement-data'
|
|
2
|
-
import { PlaqueType } from '../api/plaque-type'
|
|
3
2
|
import { BadgeRequirementType } from '../api/badge-requirement-type'
|
|
4
3
|
import { EnhancementCategory } from '../api/enhancement-category'
|
|
5
4
|
import { Key } from './key'
|
|
6
5
|
import { MarkdownString } from '../api/markdown-string'
|
|
7
6
|
import { Link } from '../api/link'
|
|
7
|
+
import { Location } from './location'
|
|
8
|
+
import { coalesceToArray } from '../util'
|
|
8
9
|
|
|
9
10
|
export class BadgeRequirement {
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
+
* Unique key used to reference this badge requirement.
|
|
13
|
+
*
|
|
14
|
+
* Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
|
|
12
15
|
*/
|
|
13
16
|
readonly key: string
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
|
-
*
|
|
19
|
+
* The requirement type.
|
|
17
20
|
*/
|
|
18
21
|
readonly type: BadgeRequirementType
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
|
-
*
|
|
24
|
+
* If the requirement involves a location, where it is.
|
|
22
25
|
*/
|
|
23
|
-
readonly
|
|
26
|
+
readonly location?: Location[]
|
|
24
27
|
|
|
25
28
|
/**
|
|
26
|
-
*
|
|
27
|
-
*/
|
|
28
|
-
readonly loc?: number[]
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Is it a wall plaque or a physical monument?
|
|
32
|
-
*/
|
|
33
|
-
readonly plaqueType?: PlaqueType
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Plaque inscription.
|
|
37
|
-
*/
|
|
38
|
-
readonly plaqueInscription?: string
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* The number or letter the plaque appears as on Vidiot Maps.
|
|
42
|
-
*/
|
|
43
|
-
readonly vidiotMapKey?: string
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The key of the badge for this requirement.
|
|
29
|
+
* If the requirement involves a badge, the badge key.
|
|
47
30
|
*/
|
|
48
31
|
readonly badgeKey?: string
|
|
49
32
|
|
|
50
33
|
/**
|
|
51
|
-
*
|
|
34
|
+
* If the requirement involves a mission, the mission key.
|
|
52
35
|
*/
|
|
53
|
-
readonly
|
|
36
|
+
readonly missionKey?: string
|
|
54
37
|
|
|
55
38
|
/**
|
|
56
|
-
*
|
|
39
|
+
* If the requirement involves a monument, the text that is displayed thereon.
|
|
57
40
|
*/
|
|
58
|
-
readonly
|
|
41
|
+
readonly monumentText?: string
|
|
59
42
|
|
|
60
43
|
/**
|
|
61
|
-
* Level of the invention required.
|
|
44
|
+
* If the requirement involves crafting an invention, the Level of the invention required.
|
|
62
45
|
*/
|
|
63
46
|
readonly inventionLevel?: number
|
|
64
47
|
|
|
65
48
|
/**
|
|
66
|
-
*
|
|
49
|
+
* If the requirement involves crafting an invention, the types of enhancements that will qualify.
|
|
67
50
|
*/
|
|
68
51
|
readonly inventionTypes?: EnhancementCategory[]
|
|
69
52
|
|
|
70
53
|
/**
|
|
71
|
-
* Number of
|
|
54
|
+
* Number of times the task needs to be repeated.
|
|
72
55
|
*/
|
|
73
|
-
readonly
|
|
56
|
+
readonly count?: number
|
|
74
57
|
|
|
75
58
|
/**
|
|
76
|
-
*
|
|
59
|
+
* Additional information about the requirement.
|
|
77
60
|
*/
|
|
78
61
|
readonly notes?: MarkdownString
|
|
79
62
|
|
|
@@ -85,17 +68,13 @@ export class BadgeRequirement {
|
|
|
85
68
|
constructor(data: BadgeRequirementData) {
|
|
86
69
|
this.key = new Key(data.key).value
|
|
87
70
|
this.type = data.type
|
|
88
|
-
this.
|
|
89
|
-
this.loc = data.loc
|
|
90
|
-
this.plaqueType = data.plaqueType
|
|
91
|
-
this.plaqueInscription = data.plaqueInscription
|
|
92
|
-
this.vidiotMapKey = data.vidiotMapKey
|
|
71
|
+
this.location = coalesceToArray(data.location)
|
|
93
72
|
this.badgeKey = data.badgeKey
|
|
94
|
-
this.
|
|
95
|
-
this.
|
|
73
|
+
this.missionKey = data.missionKey
|
|
74
|
+
this.monumentText = data.monumentText
|
|
96
75
|
this.inventionLevel = data.inventionLevel
|
|
97
76
|
this.inventionTypes = data.inventionTypes
|
|
98
|
-
this.
|
|
77
|
+
this.count = data.count
|
|
99
78
|
this.notes = data.notes
|
|
100
79
|
this.links = data.links ?? []
|
|
101
80
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BadgeType } from '../api/badge-type'
|
|
2
|
-
import {
|
|
2
|
+
import { MoralityExtended } from '../api/morality'
|
|
3
3
|
|
|
4
4
|
export interface BadgeSearchOptions {
|
|
5
5
|
|
|
@@ -26,7 +26,7 @@ export interface BadgeSearchOptions {
|
|
|
26
26
|
filter?: {
|
|
27
27
|
type?: BadgeType
|
|
28
28
|
zoneKey?: string
|
|
29
|
-
|
|
29
|
+
morality?: MoralityExtended
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -35,8 +35,8 @@ export interface BadgeSearchOptions {
|
|
|
35
35
|
* Badges are assumed to be in canonical order in the content bundle, and should match the in-game display order.
|
|
36
36
|
*/
|
|
37
37
|
sort?: {
|
|
38
|
-
by?: '
|
|
39
|
-
dir?: '
|
|
38
|
+
by?: 'canonical' | 'badge-name' | 'zone-key'
|
|
39
|
+
dir?: 'asc' | 'desc'
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
package/src/main/db/badge.ts
CHANGED
|
@@ -4,11 +4,13 @@ import { BadgeData } from '../api/badge-data'
|
|
|
4
4
|
import { BadgeRequirement } from './badge-requirement'
|
|
5
5
|
import { Key } from './key'
|
|
6
6
|
import { Alternates } from './alternates'
|
|
7
|
-
import { Alignments } from './alignments'
|
|
8
7
|
import { MarkdownString } from '../api/markdown-string'
|
|
8
|
+
import { coalesceToArray } from '../util'
|
|
9
|
+
import { MoralityList } from './morality-list'
|
|
9
10
|
|
|
10
11
|
export class Badge {
|
|
11
12
|
readonly #requirementsIndex: Record<string, BadgeRequirement> = {}
|
|
13
|
+
readonly #zoneKeys = new Set<string>()
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* The database key for this badge.
|
|
@@ -28,14 +30,14 @@ export class Badge {
|
|
|
28
30
|
readonly name: Alternates<string>
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
|
-
* The character
|
|
33
|
+
* The character moralities that this badge is available to.
|
|
32
34
|
*/
|
|
33
|
-
readonly
|
|
35
|
+
readonly morality: MoralityList
|
|
34
36
|
|
|
35
37
|
/**
|
|
36
38
|
* The badge text as it appears in-game. May vary by character sex or alignment.
|
|
37
39
|
*/
|
|
38
|
-
readonly badgeText: Alternates<
|
|
40
|
+
readonly badgeText: Alternates<MarkdownString>
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* Short description of how to acquire the badge. Detailed instructions will be in the notes field.
|
|
@@ -60,33 +62,10 @@ export class Badge {
|
|
|
60
62
|
readonly links: Link[]
|
|
61
63
|
|
|
62
64
|
/**
|
|
63
|
-
*
|
|
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.
|
|
64
67
|
*/
|
|
65
|
-
readonly
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* For exploration badges, the `/loc` coordinates of the badge.
|
|
69
|
-
*/
|
|
70
|
-
readonly loc?: [number, number, number]
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* For plaques that appear on a Vidiot Map, the number or letter the badge appears as.
|
|
74
|
-
*/
|
|
75
|
-
readonly vidiotMapKey?: string
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* ID used with the in-game `/settitle` command to apply the badge.
|
|
79
|
-
*/
|
|
80
|
-
readonly setTitle?: {
|
|
81
|
-
/**
|
|
82
|
-
* `/settitle` id.
|
|
83
|
-
*/
|
|
84
|
-
id?: number
|
|
85
|
-
/**
|
|
86
|
-
* `/settitle` id if different for praetorian characters.
|
|
87
|
-
*/
|
|
88
|
-
praetorianId?: number
|
|
89
|
-
}
|
|
68
|
+
readonly setTitleId?: [number, number?]
|
|
90
69
|
|
|
91
70
|
/**
|
|
92
71
|
* A description of the effect the badge will have, such as a buff or granting a temporary power.
|
|
@@ -94,16 +73,9 @@ export class Badge {
|
|
|
94
73
|
readonly effect?: MarkdownString
|
|
95
74
|
|
|
96
75
|
/**
|
|
97
|
-
* Represents the
|
|
98
|
-
* such as visiting plaques for history badges or collecting other badges.
|
|
99
|
-
*
|
|
100
|
-
* The outer array represents groups of requirements evaluated with OR logic —
|
|
101
|
-
* fulfilling any group satisfies the badge.
|
|
102
|
-
*
|
|
103
|
-
* Each inner array represents individual requirements evaluated with AND logic —
|
|
104
|
-
* all conditions in the group must be met.
|
|
76
|
+
* Represents the requirements for badges with multiple fulfillment steps, such as visiting monuments for history badges, completing missions, or collecting other badges.
|
|
105
77
|
*/
|
|
106
|
-
readonly requirements?: BadgeRequirement[]
|
|
78
|
+
readonly requirements?: BadgeRequirement[]
|
|
107
79
|
|
|
108
80
|
/**
|
|
109
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.
|
|
@@ -114,29 +86,24 @@ export class Badge {
|
|
|
114
86
|
this.key = new Key(badgeData.key).value
|
|
115
87
|
this.type = badgeData.type
|
|
116
88
|
this.name = new Alternates(badgeData.name)
|
|
117
|
-
this.
|
|
89
|
+
this.morality = new MoralityList(coalesceToArray(badgeData.morality))
|
|
118
90
|
this.badgeText = new Alternates(badgeData.badgeText ?? [])
|
|
119
91
|
this.acquisition = badgeData.acquisition
|
|
120
92
|
this.icon = new Alternates(badgeData.icon ?? [])
|
|
121
93
|
this.notes = badgeData.notes
|
|
122
94
|
this.links = badgeData.links ?? []
|
|
123
|
-
this.zoneKey = badgeData.zoneKey
|
|
124
|
-
this.loc = badgeData.loc
|
|
125
95
|
this.effect = badgeData.effect
|
|
126
|
-
this.
|
|
127
|
-
this.setTitle = badgeData.setTitle
|
|
96
|
+
this.setTitleId = badgeData.setTitleId
|
|
128
97
|
this.ignoreInTotals = badgeData.ignoreInTotals ?? false
|
|
129
98
|
|
|
130
|
-
this.requirements = badgeData.requirements?.map((
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return badge
|
|
139
|
-
})
|
|
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
|
|
140
107
|
})
|
|
141
108
|
}
|
|
142
109
|
|
|
@@ -145,4 +112,36 @@ export class Badge {
|
|
|
145
112
|
if (result === undefined) throw new Error(`Unknown badge requirement key [${key}]`)
|
|
146
113
|
return result
|
|
147
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)
|
|
148
147
|
}
|
|
@@ -22,12 +22,17 @@ export class BundleMetadata {
|
|
|
22
22
|
/**
|
|
23
23
|
* List of external links. Wiki, forums, etc.
|
|
24
24
|
*/
|
|
25
|
-
readonly links
|
|
25
|
+
readonly links?: Link[]
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Change log for this data package.
|
|
29
29
|
*/
|
|
30
|
-
readonly changelog
|
|
30
|
+
readonly changelog?: Change[]
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The current version of the data package.
|
|
34
|
+
*/
|
|
35
|
+
readonly version?: string
|
|
31
36
|
|
|
32
37
|
constructor(bundle: ContentBundle) {
|
|
33
38
|
this.name = bundle.name
|
|
@@ -35,5 +40,6 @@ export class BundleMetadata {
|
|
|
35
40
|
this.repository = bundle.repository
|
|
36
41
|
this.links = bundle.links ?? []
|
|
37
42
|
this.changelog = bundle.changelog ?? []
|
|
43
|
+
this.version = this.changelog?.at(-1)?.version
|
|
38
44
|
}
|
|
39
45
|
}
|
|
@@ -7,110 +7,123 @@ import { BadgeIndex } from './badge-index'
|
|
|
7
7
|
import { BadgeSearchOptions } from './badge-search-options'
|
|
8
8
|
import { Paged } from './paged'
|
|
9
9
|
import { Contact } from './contact'
|
|
10
|
+
import { Mission } from './mission'
|
|
11
|
+
import { AbstractIndex } from './abstract-index'
|
|
10
12
|
|
|
11
13
|
export class CohContentDatabase {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
#archetypeIndex = new AbstractIndex<Archetype>('key')
|
|
15
|
+
#zoneIndex = new AbstractIndex<Zone>('key')
|
|
16
|
+
#contactIndex = new AbstractIndex<Contact>('key')
|
|
17
|
+
#missionIndex = new AbstractIndex<Mission>('key')
|
|
18
|
+
#badgeIndex = new BadgeIndex()
|
|
19
|
+
|
|
20
|
+
#metadata?: BundleMetadata
|
|
21
|
+
#servers?: string[]
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Load the given content bundle, resetting the db if a bundle is already loaded.
|
|
25
|
+
* @param bundle The bundle to load.
|
|
26
|
+
*/
|
|
27
|
+
load(bundle: ContentBundle): void {
|
|
28
|
+
this.#metadata = new BundleMetadata(bundle)
|
|
29
|
+
this.#servers = bundle.servers ?? []
|
|
30
|
+
|
|
31
|
+
this.#archetypeIndex.load(bundle.archetypes?.map(x => new Archetype(x)))
|
|
32
|
+
this.#zoneIndex.load(bundle.zones?.map(x => new Zone(x)))
|
|
33
|
+
this.#contactIndex.load(bundle.contacts?.map(x => new Contact(x)))
|
|
34
|
+
this.#missionIndex.load(bundle.missions?.map(x => new Mission(x)))
|
|
35
|
+
this.#badgeIndex.load(bundle.badges?.map(x => new Badge(x)))
|
|
36
|
+
}
|
|
16
37
|
|
|
17
38
|
/**
|
|
18
39
|
* Metadata about the content bundle.
|
|
19
40
|
*/
|
|
20
|
-
|
|
41
|
+
get metadata(): BundleMetadata | undefined {
|
|
42
|
+
return this.#metadata
|
|
43
|
+
}
|
|
21
44
|
|
|
22
45
|
/**
|
|
23
46
|
* List of the game server names.
|
|
24
47
|
*
|
|
25
48
|
* Torchbearer, Excelsior, etc.
|
|
26
49
|
*/
|
|
27
|
-
|
|
50
|
+
get servers(): string[] {
|
|
51
|
+
return this.#servers ?? []
|
|
52
|
+
}
|
|
28
53
|
|
|
29
54
|
/**
|
|
30
55
|
* List of archetypes.
|
|
31
56
|
*/
|
|
32
|
-
|
|
57
|
+
get archetypes(): Archetype[] {
|
|
58
|
+
return this.#archetypeIndex.values
|
|
59
|
+
}
|
|
33
60
|
|
|
34
61
|
/**
|
|
35
|
-
*
|
|
62
|
+
* Get archetype by key.
|
|
63
|
+
* @param key The key.
|
|
36
64
|
*/
|
|
37
|
-
|
|
65
|
+
getArchetype(key: string | undefined): Archetype | undefined {
|
|
66
|
+
return this.#archetypeIndex.get(key)
|
|
67
|
+
}
|
|
38
68
|
|
|
39
69
|
/**
|
|
40
|
-
* List of
|
|
70
|
+
* List of game zones.
|
|
41
71
|
*/
|
|
42
|
-
|
|
72
|
+
get zones(): Zone[] {
|
|
73
|
+
return this.#zoneIndex.values
|
|
74
|
+
}
|
|
43
75
|
|
|
44
76
|
/**
|
|
45
|
-
*
|
|
77
|
+
* Get zone by key.
|
|
78
|
+
* @param key The key.
|
|
46
79
|
*/
|
|
47
|
-
|
|
80
|
+
getZone(key: string | undefined): Zone | undefined {
|
|
81
|
+
return this.#zoneIndex.get(key)
|
|
82
|
+
}
|
|
48
83
|
|
|
49
84
|
/**
|
|
50
|
-
*
|
|
51
|
-
* @param bundle The data to load.
|
|
85
|
+
* List of contacts.
|
|
52
86
|
*/
|
|
53
|
-
|
|
54
|
-
this.
|
|
55
|
-
this.servers = bundle.servers ?? []
|
|
56
|
-
|
|
57
|
-
this.archetypes = bundle.archetypes?.map((data) => {
|
|
58
|
-
if (this.#archetypeIndex[data.key] !== undefined) throw new Error(`Duplicate archetype key '${data.key}'`)
|
|
59
|
-
const archetype = new Archetype(data)
|
|
60
|
-
this.#archetypeIndex[archetype.key] = archetype
|
|
61
|
-
return archetype
|
|
62
|
-
}) ?? []
|
|
63
|
-
|
|
64
|
-
this.zones = bundle.zones?.map((data) => {
|
|
65
|
-
if (this.#zoneIndex[data.key] !== undefined) throw new Error(`Duplicate zone key '${data.key}'`)
|
|
66
|
-
const zone = new Zone(data)
|
|
67
|
-
this.#zoneIndex[zone.key] = zone
|
|
68
|
-
return zone
|
|
69
|
-
}) ?? []
|
|
70
|
-
|
|
71
|
-
this.contacts = bundle.contacts?.map((data) => {
|
|
72
|
-
if (this.#contactIndex[data.key] !== undefined) throw new Error(`Duplicate contact key '${data.key}'`)
|
|
73
|
-
const contact = new Contact(data)
|
|
74
|
-
this.#contactIndex[contact.key] = contact
|
|
75
|
-
return contact
|
|
76
|
-
}) ?? []
|
|
77
|
-
|
|
78
|
-
this.badges = bundle.badges?.map(data => new Badge(data)) ?? []
|
|
79
|
-
this.#badgeIndex = new BadgeIndex(this.badges, this.zones)
|
|
87
|
+
get contacts(): Contact[] {
|
|
88
|
+
return this.#contactIndex.values
|
|
80
89
|
}
|
|
81
90
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
getZone(key: string): Zone {
|
|
89
|
-
const result = this.#zoneIndex[key]
|
|
90
|
-
if (result === undefined) throw new Error(`Unknown zone key '${key}'`)
|
|
91
|
-
return result
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
getContact(key: string): Contact {
|
|
95
|
-
const result = this.#contactIndex[key]
|
|
96
|
-
if (result === undefined) throw new Error(`Unknown contact key '${key}'`)
|
|
97
|
-
return result
|
|
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)
|
|
98
97
|
}
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
/**
|
|
100
|
+
* List of missions.
|
|
101
|
+
*/
|
|
102
|
+
get missions(): Mission[] {
|
|
103
|
+
return this.#missionIndex.values
|
|
102
104
|
}
|
|
103
105
|
|
|
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)
|
|
106
112
|
}
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
/**
|
|
115
|
+
* List of badges.
|
|
116
|
+
*/
|
|
117
|
+
get badges(): Badge[] {
|
|
118
|
+
return this.#badgeIndex.values
|
|
110
119
|
}
|
|
111
120
|
|
|
112
|
-
|
|
113
|
-
|
|
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)
|
|
114
127
|
}
|
|
115
128
|
|
|
116
129
|
/**
|
|
@@ -120,6 +133,6 @@ export class CohContentDatabase {
|
|
|
120
133
|
* @param options {@link BadgeSearchOptions}
|
|
121
134
|
*/
|
|
122
135
|
searchBadges(options?: BadgeSearchOptions): Paged<Badge> {
|
|
123
|
-
return this.#badgeIndex.
|
|
136
|
+
return this.#badgeIndex.search(options)
|
|
124
137
|
}
|
|
125
138
|
}
|
package/src/main/db/contact.ts
CHANGED
|
@@ -2,12 +2,15 @@ import { Link } from '../api/link'
|
|
|
2
2
|
import { Key } from './key'
|
|
3
3
|
import { MarkdownString } from '../api/markdown-string'
|
|
4
4
|
import { ContactData } from '../api/contact-data'
|
|
5
|
+
import { Location } from './location'
|
|
6
|
+
import { MoralityList } from './morality-list'
|
|
7
|
+
import { coalesceToArray } from '../util'
|
|
5
8
|
|
|
6
9
|
export class Contact {
|
|
7
10
|
/**
|
|
8
11
|
* Unique key used to reference this contact.
|
|
9
12
|
*
|
|
10
|
-
* Keys can only contain lowercase letters, numbers and hyphens (`-`).
|
|
13
|
+
* Keys must be unique and can only contain lowercase letters, numbers and hyphens (`-`).
|
|
11
14
|
*/
|
|
12
15
|
readonly key: string
|
|
13
16
|
|
|
@@ -22,14 +25,14 @@ export class Contact {
|
|
|
22
25
|
readonly title?: string
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
|
-
* The
|
|
28
|
+
* The character moralities that this contact will interact with.
|
|
26
29
|
*/
|
|
27
|
-
readonly
|
|
30
|
+
readonly morality?: MoralityList
|
|
28
31
|
|
|
29
32
|
/**
|
|
30
|
-
* The
|
|
33
|
+
* The location of this contact.
|
|
31
34
|
*/
|
|
32
|
-
readonly
|
|
35
|
+
readonly location?: Location
|
|
33
36
|
|
|
34
37
|
/**
|
|
35
38
|
* The level range this contact will offer missions for.
|
|
@@ -46,14 +49,14 @@ export class Contact {
|
|
|
46
49
|
*/
|
|
47
50
|
readonly links: Link[]
|
|
48
51
|
|
|
49
|
-
constructor(
|
|
50
|
-
this.key = new Key(
|
|
51
|
-
this.name =
|
|
52
|
-
this.title =
|
|
53
|
-
this.
|
|
54
|
-
this.
|
|
55
|
-
this.levelRange =
|
|
56
|
-
this.notes =
|
|
57
|
-
this.links =
|
|
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 ?? []
|
|
58
61
|
}
|
|
59
62
|
}
|
|
@@ -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
|
+
}
|