coh-content-db 2.0.0-rc.1 → 2.0.0-rc.11
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/.editorconfig +10 -11
- package/.github/workflows/build.yml +4 -2
- package/.github/workflows/pull-request.yml +1 -1
- package/.github/workflows/release.yml +2 -2
- package/CHANGELOG.md +43 -0
- package/README.md +52 -24
- package/dist/coh-content-db.d.ts +678 -279
- package/dist/coh-content-db.js +828 -371
- package/dist/coh-content-db.js.map +1 -1
- package/dist/coh-content-db.mjs +803 -362
- 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/alternate-data.ts +2 -2
- package/src/main/api/badge-data.ts +20 -48
- package/src/main/api/badge-requirement-data.ts +64 -0
- package/src/main/api/badge-requirement-type.ts +32 -0
- package/src/main/api/badge-type.ts +15 -15
- package/src/main/api/bundle-data.ts +47 -0
- package/src/main/api/bundle-header-data.ts +37 -0
- package/src/main/api/contact-data.ts +48 -0
- package/src/main/api/enhancement-category.ts +26 -26
- package/src/main/api/location-data.ts +28 -0
- package/src/main/api/markdown-string.ts +4 -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 +20 -0
- package/src/main/db/abstract-index.ts +37 -0
- package/src/main/db/alignment-list.ts +54 -0
- package/src/main/db/alternates.ts +28 -42
- package/src/main/db/badge-index.ts +60 -0
- package/src/main/db/badge-requirement.ts +81 -0
- package/src/main/db/badge-search-options.ts +47 -0
- package/src/main/db/badge.ts +76 -71
- package/src/main/db/bundle-header.ts +44 -0
- package/src/main/db/coh-content-database.ts +123 -14
- package/src/main/db/contact.ts +62 -0
- 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/paged.ts +7 -0
- package/src/main/db/zone.ts +28 -0
- package/src/main/index.ts +23 -15
- package/src/main/util.ts +108 -7
- package/src/test/api/alignment.test.ts +38 -4
- package/src/test/api/badge-data.fixture.ts +1 -15
- package/src/test/api/badge-data.test.ts +4 -4
- package/src/test/api/badge-requirement-data.fixture.ts +7 -0
- package/src/test/api/badge-requirement-type.test.ts +31 -0
- package/src/test/api/badge-type.test.ts +5 -5
- package/src/test/api/bundle-data.fixture.ts +6 -0
- package/src/test/api/bundle-header-data.fixture.ts +6 -0
- package/src/test/api/contact-data.fixture.ts +7 -0
- 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 +8 -0
- package/src/test/db/abstract-index.test.ts +55 -0
- package/src/test/db/alignment-list.test.ts +200 -0
- package/src/test/db/alternates.test.ts +82 -117
- package/src/test/db/badge-index.test.ts +547 -0
- package/src/test/db/badge-requirement.test.ts +145 -0
- package/src/test/db/badge.test.ts +322 -14
- package/src/test/db/bundle-header.test.ts +76 -0
- package/src/test/db/coh-content-database.test.ts +264 -24
- package/src/test/db/contact.test.ts +97 -0
- 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 +36 -0
- package/src/test/integration.test.ts +16 -0
- package/src/test/util.test.ts +144 -18
- package/src/main/api/badge-partial-data.ts +0 -65
- package/src/main/api/badge-partial-type.ts +0 -8
- package/src/main/api/change.ts +0 -14
- package/src/main/api/game-map-data.ts +0 -26
- package/src/main/api/plaque-type.ts +0 -6
- package/src/main/api/server-group-data.ts +0 -65
- package/src/main/api/vidiot-map-data.ts +0 -18
- package/src/main/api/vidiot-map-point-of-interest-data.ts +0 -30
- package/src/main/changelog.ts +0 -20
- package/src/main/db/badge-partial.ts +0 -35
- package/src/main/db/game-map.ts +0 -33
- package/src/main/db/server-group.ts +0 -112
- package/src/main/db/vidiot-map-point-of-interest.ts +0 -40
- package/src/main/db/vidiot-map.ts +0 -25
- package/src/test/api/badge-partial-data.fixture.ts +0 -17
- package/src/test/api/badge-partial-type.test.ts +0 -31
- package/src/test/api/game-map-data.fixture.ts +0 -10
- package/src/test/api/plaque-type.test.ts +0 -31
- package/src/test/api/server-group-data.fixture.ts +0 -23
- package/src/test/api/server-group-data.test.ts +0 -15
- package/src/test/api/vidiot-map-point-of-interest.fixture.ts +0 -10
- package/src/test/api/vidiot-map.fixture.ts +0 -9
- package/src/test/changelog.test.ts +0 -36
- package/src/test/db/server-group.test.ts +0 -124
- package/src/test/index.test.ts +0 -10
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BadgeType } from '../api/badge-type'
|
|
2
|
+
import { MoralityExtended } from '../api/morality'
|
|
3
|
+
|
|
4
|
+
export type BadgeQueryableField = 'name' | 'badge-text' | 'acquisition' | 'notes' | 'effect' | 'set-title-id'
|
|
5
|
+
export type BadgeSortableField = 'canonical' | 'badge-name' | 'zone-key'
|
|
6
|
+
|
|
7
|
+
export interface BadgeSearchOptions {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Text-based search.
|
|
11
|
+
*
|
|
12
|
+
* Case-insensitive. Defaults to searching on name only.
|
|
13
|
+
*/
|
|
14
|
+
query?: {
|
|
15
|
+
str?: string
|
|
16
|
+
fields?: BadgeQueryableField[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Filter results matching the given values.
|
|
21
|
+
*/
|
|
22
|
+
filter?: {
|
|
23
|
+
type?: BadgeType
|
|
24
|
+
zoneKey?: string
|
|
25
|
+
morality?: MoralityExtended
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sort results.
|
|
30
|
+
*
|
|
31
|
+
* Badges are assumed to be in canonical order in the content bundle, and should match the in-game display order.
|
|
32
|
+
*/
|
|
33
|
+
sort?: {
|
|
34
|
+
by?: BadgeSortableField
|
|
35
|
+
dir?: 'asc' | 'desc'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The page (1-based)
|
|
40
|
+
*/
|
|
41
|
+
page?: number
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* How many results per page
|
|
45
|
+
*/
|
|
46
|
+
pageSize?: number
|
|
47
|
+
}
|
package/src/main/db/badge.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { BadgeType } from '../api/badge-type'
|
|
2
|
-
import { Alignment } from '../api/alignment'
|
|
3
2
|
import { Link } from '../api/link'
|
|
4
3
|
import { BadgeData } from '../api/badge-data'
|
|
5
|
-
import {
|
|
4
|
+
import { BadgeRequirement } from './badge-requirement'
|
|
6
5
|
import { Key } from './key'
|
|
7
6
|
import { Alternates } from './alternates'
|
|
7
|
+
import { MarkdownString } from '../api/markdown-string'
|
|
8
|
+
import { coalesceToArray } from '../util'
|
|
9
|
+
import { MoralityList } from './morality-list'
|
|
10
|
+
import { AbstractIndex } from './abstract-index'
|
|
8
11
|
|
|
9
12
|
export class Badge {
|
|
10
|
-
readonly #
|
|
13
|
+
readonly #requirementsIndex: AbstractIndex<BadgeRequirement>
|
|
14
|
+
readonly #zoneKeys = new Set<string>()
|
|
11
15
|
|
|
12
16
|
/**
|
|
13
17
|
* The database key for this badge.
|
|
@@ -17,7 +21,7 @@ export class Badge {
|
|
|
17
21
|
/**
|
|
18
22
|
* The type of badge.
|
|
19
23
|
*/
|
|
20
|
-
readonly type: BadgeType
|
|
24
|
+
readonly type: BadgeType
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
27
|
* The name of this badge.
|
|
@@ -27,21 +31,19 @@ export class Badge {
|
|
|
27
31
|
readonly name: Alternates<string>
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
|
-
* The character
|
|
34
|
+
* The character moralities that this badge is available to.
|
|
31
35
|
*/
|
|
32
|
-
readonly
|
|
36
|
+
readonly morality: MoralityList
|
|
33
37
|
|
|
34
38
|
/**
|
|
35
39
|
* The badge text as it appears in-game. May vary by character sex or alignment.
|
|
36
40
|
*/
|
|
37
|
-
readonly badgeText: Alternates<
|
|
41
|
+
readonly badgeText: Alternates<MarkdownString>
|
|
38
42
|
|
|
39
43
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* Supports {@link https://www.markdownguide.org/|Markdown} format.
|
|
44
|
+
* Short description of how to acquire the badge. Detailed instructions will be in the notes field.
|
|
43
45
|
*/
|
|
44
|
-
readonly acquisition?:
|
|
46
|
+
readonly acquisition?: MarkdownString
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
49
|
* Absolute URL to this badge's icon.
|
|
@@ -52,90 +54,93 @@ export class Badge {
|
|
|
52
54
|
|
|
53
55
|
/**
|
|
54
56
|
* Freeform notes or tips about the badge.
|
|
55
|
-
*
|
|
56
|
-
* Supports {@link https://www.markdownguide.org/|Markdown} format.
|
|
57
57
|
*/
|
|
58
|
-
readonly notes?:
|
|
58
|
+
readonly notes?: MarkdownString
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* List of external links
|
|
61
|
+
* List of external links. Wiki, forums, etc.
|
|
62
62
|
*/
|
|
63
|
-
readonly links
|
|
63
|
+
readonly links: Link[]
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
66
|
+
* The id used with the in-game `/settitle` command to apply the badge.
|
|
67
|
+
* The first value is the id for primal characters and the (optional) second number is the id for praetorian characters.
|
|
67
68
|
*/
|
|
68
|
-
readonly
|
|
69
|
+
readonly setTitleId?: [number, number?]
|
|
69
70
|
|
|
70
71
|
/**
|
|
71
|
-
*
|
|
72
|
+
* A description of the effect the badge will have, such as a buff or granting a temporary power.
|
|
72
73
|
*/
|
|
73
|
-
readonly
|
|
74
|
+
readonly effect?: MarkdownString
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
|
-
*
|
|
77
|
+
* 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.
|
|
77
78
|
*/
|
|
78
|
-
readonly
|
|
79
|
+
readonly ignoreInTotals: boolean
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
constructor(badgeData: BadgeData) {
|
|
82
|
+
this.key = new Key(badgeData.key).value
|
|
83
|
+
this.type = badgeData.type
|
|
84
|
+
this.name = new Alternates(badgeData.name)
|
|
85
|
+
this.morality = new MoralityList(coalesceToArray(badgeData.morality))
|
|
86
|
+
this.badgeText = new Alternates(badgeData.badgeText ?? [])
|
|
87
|
+
this.acquisition = badgeData.acquisition
|
|
88
|
+
this.icon = new Alternates(badgeData.icon ?? [])
|
|
89
|
+
this.notes = badgeData.notes
|
|
90
|
+
this.links = badgeData.links ?? []
|
|
91
|
+
this.effect = badgeData.effect
|
|
92
|
+
this.setTitleId = badgeData.setTitleId
|
|
93
|
+
this.ignoreInTotals = badgeData.ignoreInTotals ?? false
|
|
94
|
+
|
|
95
|
+
this.#requirementsIndex = new AbstractIndex<BadgeRequirement>('key', badgeData.requirements?.map(x => new BadgeRequirement(x)))
|
|
96
|
+
|
|
97
|
+
for (const requirement of this.#requirementsIndex.values) {
|
|
98
|
+
if (requirement.location) for (const location of requirement.location) {
|
|
99
|
+
if (location.zoneKey) this.#zoneKeys.add(location.zoneKey)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
92
102
|
}
|
|
93
103
|
|
|
94
104
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* Supports {@link https://www.markdownguide.org/|Markdown} format.
|
|
105
|
+
* Represents the requirements for badges with multiple fulfillment steps, such as visiting monuments for history badges, completing missions, or collecting other badges.
|
|
98
106
|
*/
|
|
99
|
-
|
|
107
|
+
get requirements(): BadgeRequirement[] {
|
|
108
|
+
return this.#requirementsIndex.values
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
getRequirement(key: string): BadgeRequirement | undefined {
|
|
112
|
+
return this.#requirementsIndex.get(key)
|
|
113
|
+
}
|
|
100
114
|
|
|
101
115
|
/**
|
|
102
|
-
*
|
|
116
|
+
* Return a list of all the zone keys referenced by this badge.
|
|
103
117
|
*/
|
|
104
|
-
|
|
118
|
+
get zoneKeys(): string[] {
|
|
119
|
+
return [...this.#zoneKeys]
|
|
120
|
+
}
|
|
105
121
|
|
|
106
122
|
/**
|
|
107
|
-
*
|
|
123
|
+
* The zone key if this badge relates to a single zone.
|
|
108
124
|
*/
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
constructor(data: BadgeData) {
|
|
112
|
-
this.key = new Key(data.key).value
|
|
113
|
-
this.type = data.type
|
|
114
|
-
this.name = new Alternates(data.name)
|
|
115
|
-
this.alignment = data.alignment
|
|
116
|
-
this.badgeText = new Alternates(data.badgeText ?? [])
|
|
117
|
-
this.acquisition = data.acquisition
|
|
118
|
-
this.icon = new Alternates(data.icon ?? [])
|
|
119
|
-
this.notes = data.notes
|
|
120
|
-
this.links = data.links
|
|
121
|
-
this.mapKey = data.mapKey
|
|
122
|
-
this.loc = data.loc
|
|
123
|
-
this.effect = data.effect
|
|
124
|
-
this.vidiotMapKey = data.vidiotMapKey
|
|
125
|
-
this.setTitle = data.setTitle
|
|
126
|
-
this.ignoreInTotals = data.ignoreInTotals ?? false
|
|
127
|
-
|
|
128
|
-
this.partials = data.partials?.map((data) => {
|
|
129
|
-
if (this.#partialsIndex[data.key] !== undefined) throw new Error(`Duplicate badge partial key [${data.key}]`)
|
|
130
|
-
const badge = new BadgePartial(data)
|
|
131
|
-
this.#partialsIndex[badge.key] = badge
|
|
132
|
-
return badge
|
|
133
|
-
})
|
|
125
|
+
get zoneKey(): string | undefined {
|
|
126
|
+
return this.#zoneKeys.size === 1 ? this.#zoneKeys.values().next().value : undefined
|
|
134
127
|
}
|
|
128
|
+
}
|
|
135
129
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
export function compareByDefaultName(a?: Badge, b?: Badge): number {
|
|
131
|
+
const aName = a?.name.default?.value
|
|
132
|
+
const bName = b?.name.default?.value
|
|
133
|
+
if (!aName && !bName) return 0
|
|
134
|
+
if (!aName) return 1
|
|
135
|
+
if (!bName) return -1
|
|
136
|
+
return aName.localeCompare(bName)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function compareByZoneKey(a?: Badge, b?: Badge): number {
|
|
140
|
+
const aZone = a?.zoneKey
|
|
141
|
+
const bZone = b?.zoneKey
|
|
142
|
+
if (!aZone && !bZone) return 0
|
|
143
|
+
if (!aZone) return 1
|
|
144
|
+
if (!bZone) return -1
|
|
145
|
+
return aZone.localeCompare(bZone)
|
|
141
146
|
}
|
|
@@ -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
|
+
}
|
|
@@ -1,29 +1,138 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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'
|
|
3
12
|
|
|
4
13
|
export class CohContentDatabase {
|
|
5
|
-
readonly #
|
|
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
|
+
}
|
|
6
113
|
|
|
7
114
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @param data The data to load.
|
|
115
|
+
* List of badges.
|
|
10
116
|
*/
|
|
11
|
-
|
|
12
|
-
this.#
|
|
117
|
+
get badges(): Badge[] {
|
|
118
|
+
return this.#badgeIndex.values
|
|
13
119
|
}
|
|
14
120
|
|
|
15
121
|
/**
|
|
16
|
-
* Get
|
|
122
|
+
* Get badge by key.
|
|
123
|
+
* @param key The key.
|
|
17
124
|
*/
|
|
18
|
-
|
|
19
|
-
return
|
|
125
|
+
getBadge(key: string | undefined): Badge | undefined {
|
|
126
|
+
return this.#badgeIndex.get(key)
|
|
20
127
|
}
|
|
21
128
|
|
|
22
129
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
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}
|
|
25
134
|
*/
|
|
26
|
-
|
|
27
|
-
return this.#
|
|
135
|
+
searchBadges(options?: BadgeSearchOptions): Paged<Badge> {
|
|
136
|
+
return this.#badgeIndex.search(options)
|
|
28
137
|
}
|
|
29
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,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
|
+
}
|