@shipload/sdk 2.0.0-rc5 → 2.0.0-rc7
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/README.md +1 -349
- package/lib/shipload.d.ts +607 -1113
- package/lib/shipload.js +1482 -2077
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +1421 -2038
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/crafting.ts +28 -0
- package/src/capabilities/extraction.ts +14 -8
- package/src/capabilities/guards.ts +0 -5
- package/src/capabilities/index.ts +2 -0
- package/src/capabilities/modules.ts +49 -0
- package/src/capabilities/storage.ts +0 -8
- package/src/contracts/server.ts +231 -313
- package/src/data/colors.ts +28 -0
- package/src/data/items.json +15 -15
- package/src/data/recipes.ts +351 -0
- package/src/derivation/crafting.ts +142 -0
- package/src/derivation/index.ts +1 -0
- package/src/derivation/stats.ts +91 -15
- package/src/derivation/stratum.ts +2 -2
- package/src/entities/cargo-utils.ts +6 -64
- package/src/entities/container.ts +18 -0
- package/src/entities/entity-inventory.ts +0 -4
- package/src/entities/inventory-accessor.ts +0 -4
- package/src/entities/location.ts +2 -197
- package/src/entities/makers.ts +10 -9
- package/src/entities/player.ts +1 -274
- package/src/entities/ship-deploy.ts +89 -0
- package/src/entities/ship.ts +14 -27
- package/src/entities/warehouse.ts +0 -4
- package/src/index-module.ts +66 -41
- package/src/managers/actions.ts +77 -88
- package/src/managers/context.ts +0 -9
- package/src/managers/index.ts +0 -1
- package/src/managers/locations.ts +2 -85
- package/src/market/items.ts +0 -1
- package/src/resolution/resolve-item.ts +242 -0
- package/src/scheduling/projection.ts +0 -10
- package/src/shipload.ts +0 -5
- package/src/travel/travel.ts +3 -3
- package/src/types/capabilities.ts +1 -9
- package/src/types/entity-traits.ts +3 -4
- package/src/types/entity.ts +3 -4
- package/src/types.ts +6 -43
- package/src/utils/system.ts +5 -4
- package/src/managers/trades.ts +0 -119
- package/src/market/market.ts +0 -195
- package/src/market/rolls.ts +0 -8
- package/src/trading/collect.ts +0 -938
- package/src/trading/deal.ts +0 -207
- package/src/trading/trade.ts +0 -203
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type {ResourceCategory, ResourceTier} from '../types'
|
|
2
|
+
|
|
3
|
+
export const categoryColors: Record<ResourceCategory, string> = {
|
|
4
|
+
metal: '#7B8D9E',
|
|
5
|
+
precious: '#D4A843',
|
|
6
|
+
gas: '#7EC8E3',
|
|
7
|
+
mineral: '#B8A9C9',
|
|
8
|
+
organic: '#6B8E5A',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const tierColors: Record<ResourceTier, string> = {
|
|
12
|
+
t1: '#8b8b8b',
|
|
13
|
+
t2: '#4ade80',
|
|
14
|
+
t3: '#818cf8',
|
|
15
|
+
t4: '#c084fc',
|
|
16
|
+
t5: '#fbbf24',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const categoryIcons: Record<ResourceCategory, string> = {
|
|
20
|
+
metal: '⬡',
|
|
21
|
+
precious: '◈',
|
|
22
|
+
gas: '◎',
|
|
23
|
+
mineral: '◇',
|
|
24
|
+
organic: '❋',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const componentIcon = '▣'
|
|
28
|
+
export const moduleIcon = '⬢'
|
package/src/data/items.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
[
|
|
2
|
-
{"id": 26, "name": "Iron", "description": "A versatile metal used in hulls and structures.", "
|
|
3
|
-
{"id": 13, "name": "Aluminum", "description": "A lightweight metal for structural components.", "
|
|
4
|
-
{"id": 24, "name": "Chromium", "description": "A hard, corrosion-resistant alloy metal.", "
|
|
5
|
-
{"id": 29, "name": "Copper", "description": "A conductive metal for electronics and wiring.", "
|
|
6
|
-
{"id": 47, "name": "Silver", "description": "A high-conductivity metal for precision components.", "
|
|
7
|
-
{"id": 79, "name": "Gold", "description": "A corrosion-proof metal for advanced electronics.", "
|
|
8
|
-
{"id": 1, "name": "Hydrogen", "description": "A lightweight gas used for fuel cells and propulsion.", "
|
|
9
|
-
{"id": 2, "name": "Helium", "description": "An inert noble gas used in energy systems.", "
|
|
10
|
-
{"id": 18, "name": "Argon", "description": "A noble gas used in industrial and energy applications.", "
|
|
11
|
-
{"id": 14, "name": "Silicon", "description": "A semiconductor used in sensors and computing.", "
|
|
12
|
-
{"id": 1000, "name": "Quartz", "description": "A crystalline mineral for sensors and optics.", "
|
|
13
|
-
{"id": 1001, "name": "Sapphire", "description": "A precious crystal for precision instruments.", "
|
|
14
|
-
{"id": 6, "name": "Carbon", "description": "A versatile element for life support and coatings.", "
|
|
15
|
-
{"id": 1003, "name": "Biomass", "description": "Organic matter for life support systems.", "
|
|
16
|
-
{"id": 1002, "name": "Resin", "description": "A fossilized organic compound for coatings and sealants.", "
|
|
2
|
+
{"id": 26, "name": "Iron", "description": "A versatile metal used in hulls and structures.", "mass": 30000, "category": "metal", "tier": "t1", "color": "#B7410E"},
|
|
3
|
+
{"id": 13, "name": "Aluminum", "description": "A lightweight metal for structural components.", "mass": 27000, "category": "metal", "tier": "t2", "color": "#A8B5C2"},
|
|
4
|
+
{"id": 24, "name": "Chromium", "description": "A hard, corrosion-resistant alloy metal.", "mass": 52000, "category": "metal", "tier": "t3", "color": "#D4E6F1"},
|
|
5
|
+
{"id": 29, "name": "Copper", "description": "A conductive metal for electronics and wiring.", "mass": 40000, "category": "precious", "tier": "t1", "color": "#B87333"},
|
|
6
|
+
{"id": 47, "name": "Silver", "description": "A high-conductivity metal for precision components.", "mass": 55000, "category": "precious", "tier": "t2", "color": "#C0C0C0"},
|
|
7
|
+
{"id": 79, "name": "Gold", "description": "A corrosion-proof metal for advanced electronics.", "mass": 70000, "category": "precious", "tier": "t3", "color": "#FFD700"},
|
|
8
|
+
{"id": 1, "name": "Hydrogen", "description": "A lightweight gas used for fuel cells and propulsion.", "mass": 15000, "category": "gas", "tier": "t1", "color": "#7EC8E3"},
|
|
9
|
+
{"id": 2, "name": "Helium", "description": "An inert noble gas used in energy systems.", "mass": 2000, "category": "gas", "tier": "t2", "color": "#F5E6CC"},
|
|
10
|
+
{"id": 18, "name": "Argon", "description": "A noble gas used in industrial and energy applications.", "mass": 8000, "category": "gas", "tier": "t3", "color": "#9B59B6"},
|
|
11
|
+
{"id": 14, "name": "Silicon", "description": "A semiconductor used in sensors and computing.", "mass": 22000, "category": "mineral", "tier": "t1", "color": "#B8A9C9"},
|
|
12
|
+
{"id": 1000, "name": "Quartz", "description": "A crystalline mineral for sensors and optics.", "mass": 35000, "category": "mineral", "tier": "t2", "color": "#E8D5B7"},
|
|
13
|
+
{"id": 1001, "name": "Sapphire", "description": "A precious crystal for precision instruments.", "mass": 45000, "category": "mineral", "tier": "t3", "color": "#0F52BA"},
|
|
14
|
+
{"id": 6, "name": "Carbon", "description": "A versatile element for life support and coatings.", "mass": 15000, "category": "organic", "tier": "t1", "color": "#4A4A4A"},
|
|
15
|
+
{"id": 1003, "name": "Biomass", "description": "Organic matter for life support systems.", "mass": 30000, "category": "organic", "tier": "t2", "color": "#8B4513"},
|
|
16
|
+
{"id": 1002, "name": "Resin", "description": "A fossilized organic compound for coatings and sealants.", "mass": 25000, "category": "organic", "tier": "t3", "color": "#DAA520"}
|
|
17
17
|
]
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import {MODULE_ENGINE, MODULE_GENERATOR, MODULE_EXTRACTOR, MODULE_LOADER, MODULE_CRAFTER, ITEM_ENGINE_T1, ITEM_GENERATOR_T1, ITEM_EXTRACTOR_T1, ITEM_LOADER_T1, ITEM_MANUFACTURING_T1} from '../capabilities/modules'
|
|
2
|
+
import type {ResourceCategory} from '../types'
|
|
3
|
+
|
|
4
|
+
export {ITEM_ENGINE_T1, ITEM_GENERATOR_T1, ITEM_EXTRACTOR_T1, ITEM_LOADER_T1, ITEM_MANUFACTURING_T1}
|
|
5
|
+
|
|
6
|
+
export const ITEM_DRILL_SHAFT = 10009
|
|
7
|
+
export const ITEM_EXTRACTION_PROBE = 10010
|
|
8
|
+
export const ITEM_CARGO_ARM = 10011
|
|
9
|
+
export const ITEM_TOOL_BIT = 10012
|
|
10
|
+
export const ITEM_REACTION_CHAMBER = 10013
|
|
11
|
+
|
|
12
|
+
export const ITEM_HULL_PLATES = 10001
|
|
13
|
+
export const ITEM_CARGO_LINING = 10002
|
|
14
|
+
export const ITEM_CONTAINER_PACKED = 10003
|
|
15
|
+
export const ITEM_THRUSTER_CORE = 10004
|
|
16
|
+
export const ITEM_POWER_CELL = 10005
|
|
17
|
+
export const ITEM_SHIP_T1_PACKED = 10008
|
|
18
|
+
|
|
19
|
+
export interface RecipeInput {
|
|
20
|
+
category?: ResourceCategory
|
|
21
|
+
itemId?: number
|
|
22
|
+
quantity: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ComponentStat {
|
|
26
|
+
key: string
|
|
27
|
+
source: ResourceCategory
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ComponentDefinition {
|
|
31
|
+
id: number
|
|
32
|
+
name: string
|
|
33
|
+
description: string
|
|
34
|
+
color: string
|
|
35
|
+
mass: number
|
|
36
|
+
stats: ComponentStat[]
|
|
37
|
+
recipe: RecipeInput[]
|
|
38
|
+
usedIn: {type: 'entity' | 'module'; name: string}[]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface EntityRecipe {
|
|
42
|
+
id: string
|
|
43
|
+
name: string
|
|
44
|
+
description: string
|
|
45
|
+
color: string
|
|
46
|
+
packedItemId: number
|
|
47
|
+
recipe: RecipeInput[]
|
|
48
|
+
stats: {key: string; sourceComponentId: number; sourceStatKey: string}[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface CraftableItem {
|
|
52
|
+
type: 'component' | 'entity' | 'module'
|
|
53
|
+
id: number | string
|
|
54
|
+
name: string
|
|
55
|
+
description: string
|
|
56
|
+
color: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const components: ComponentDefinition[] = [
|
|
60
|
+
{
|
|
61
|
+
id: ITEM_HULL_PLATES,
|
|
62
|
+
name: 'Hull Plates',
|
|
63
|
+
description: 'Structural plating formed from metal. Used in hulls, containers, and frames.',
|
|
64
|
+
color: '#7B8D9E',
|
|
65
|
+
mass: 50000,
|
|
66
|
+
stats: [
|
|
67
|
+
{key: 'strength', source: 'metal'},
|
|
68
|
+
{key: 'density', source: 'metal'},
|
|
69
|
+
],
|
|
70
|
+
recipe: [{category: 'metal', quantity: 15}],
|
|
71
|
+
usedIn: [{type: 'entity', name: 'Container'}, {type: 'entity', name: 'Ship T1'}],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: ITEM_CARGO_LINING,
|
|
75
|
+
name: 'Cargo Lining',
|
|
76
|
+
description:
|
|
77
|
+
'Precision-formed composite lining for cargo storage. Combines precious metal shaping with organic sealing.',
|
|
78
|
+
color: '#D4A843',
|
|
79
|
+
mass: 30000,
|
|
80
|
+
stats: [
|
|
81
|
+
{key: 'ductility', source: 'precious'},
|
|
82
|
+
{key: 'purity', source: 'organic'},
|
|
83
|
+
],
|
|
84
|
+
recipe: [
|
|
85
|
+
{category: 'precious', quantity: 6},
|
|
86
|
+
{category: 'organic', quantity: 14},
|
|
87
|
+
],
|
|
88
|
+
usedIn: [{type: 'entity', name: 'Container'}, {type: 'entity', name: 'Ship T1'}],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: ITEM_THRUSTER_CORE,
|
|
92
|
+
name: 'Thruster Core',
|
|
93
|
+
description: 'High-energy propulsion component formed from volatile gases.',
|
|
94
|
+
color: '#E86344',
|
|
95
|
+
mass: 50000,
|
|
96
|
+
stats: [
|
|
97
|
+
{key: 'volatility', source: 'gas'},
|
|
98
|
+
{key: 'thermal', source: 'gas'},
|
|
99
|
+
],
|
|
100
|
+
recipe: [{category: 'gas' as ResourceCategory, quantity: 32}],
|
|
101
|
+
usedIn: [{type: 'module', name: 'Engine Module T1'}],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: ITEM_POWER_CELL,
|
|
105
|
+
name: 'Power Cell',
|
|
106
|
+
description: 'Crystalline energy storage matrix formed from resonant minerals.',
|
|
107
|
+
color: '#7B5AE8',
|
|
108
|
+
mass: 30000,
|
|
109
|
+
stats: [
|
|
110
|
+
{key: 'resonance', source: 'mineral'},
|
|
111
|
+
{key: 'clarity', source: 'mineral'},
|
|
112
|
+
],
|
|
113
|
+
recipe: [{category: 'mineral' as ResourceCategory, quantity: 20}],
|
|
114
|
+
usedIn: [{type: 'module', name: 'Generator Module T1'}],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: ITEM_DRILL_SHAFT,
|
|
118
|
+
name: 'Drill Shaft',
|
|
119
|
+
description: 'Heavy-duty metal shaft used in extraction equipment.',
|
|
120
|
+
color: '#7B8D9E',
|
|
121
|
+
mass: 50000,
|
|
122
|
+
stats: [
|
|
123
|
+
{key: 'strength', source: 'metal'},
|
|
124
|
+
{key: 'tolerance', source: 'metal'},
|
|
125
|
+
],
|
|
126
|
+
recipe: [{category: 'metal' as ResourceCategory, quantity: 15}],
|
|
127
|
+
usedIn: [{type: 'module', name: 'Extractor Module T1'}],
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: ITEM_EXTRACTION_PROBE,
|
|
131
|
+
name: 'Extraction Probe',
|
|
132
|
+
description: 'Precious metal sensor array for deep resource detection.',
|
|
133
|
+
color: '#D4A843',
|
|
134
|
+
mass: 30000,
|
|
135
|
+
stats: [
|
|
136
|
+
{key: 'conductivity', source: 'precious'},
|
|
137
|
+
{key: 'reflectivity', source: 'precious'},
|
|
138
|
+
],
|
|
139
|
+
recipe: [{category: 'precious' as ResourceCategory, quantity: 10}],
|
|
140
|
+
usedIn: [{type: 'module', name: 'Extractor Module T1'}],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: ITEM_CARGO_ARM,
|
|
144
|
+
name: 'Cargo Arm',
|
|
145
|
+
description: 'Flexible organic composite arm for cargo handling.',
|
|
146
|
+
color: '#6B8E5A',
|
|
147
|
+
mass: 30000,
|
|
148
|
+
stats: [
|
|
149
|
+
{key: 'plasticity', source: 'organic'},
|
|
150
|
+
{key: 'insulation', source: 'organic'},
|
|
151
|
+
],
|
|
152
|
+
recipe: [{category: 'organic' as ResourceCategory, quantity: 32}],
|
|
153
|
+
usedIn: [{type: 'module', name: 'Loader Module T1'}],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: ITEM_TOOL_BIT,
|
|
157
|
+
name: 'Tool Bit',
|
|
158
|
+
description: 'Dense mineral cutting head for manufacturing operations.',
|
|
159
|
+
color: '#B8A9C9',
|
|
160
|
+
mass: 30000,
|
|
161
|
+
stats: [
|
|
162
|
+
{key: 'hardness', source: 'mineral'},
|
|
163
|
+
{key: 'clarity', source: 'mineral'},
|
|
164
|
+
],
|
|
165
|
+
recipe: [{category: 'mineral' as ResourceCategory, quantity: 20}],
|
|
166
|
+
usedIn: [{type: 'module', name: 'Manufacturing Module T1'}],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: ITEM_REACTION_CHAMBER,
|
|
170
|
+
name: 'Reaction Chamber',
|
|
171
|
+
description: 'Gas-pressurized vessel for controlled manufacturing reactions.',
|
|
172
|
+
color: '#7EC8E3',
|
|
173
|
+
mass: 50000,
|
|
174
|
+
stats: [
|
|
175
|
+
{key: 'reactivity', source: 'gas'},
|
|
176
|
+
{key: 'thermal', source: 'gas'},
|
|
177
|
+
],
|
|
178
|
+
recipe: [{category: 'gas' as ResourceCategory, quantity: 32}],
|
|
179
|
+
usedIn: [{type: 'module', name: 'Manufacturing Module T1'}],
|
|
180
|
+
},
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
export const entityRecipes: EntityRecipe[] = [
|
|
184
|
+
{
|
|
185
|
+
id: 'container',
|
|
186
|
+
name: 'Container',
|
|
187
|
+
description: 'Passive floating cargo storage in space. Towed by ships.',
|
|
188
|
+
color: '#7B8D9E',
|
|
189
|
+
packedItemId: ITEM_CONTAINER_PACKED,
|
|
190
|
+
recipe: [
|
|
191
|
+
{itemId: ITEM_HULL_PLATES, quantity: 6},
|
|
192
|
+
{itemId: ITEM_CARGO_LINING, quantity: 2},
|
|
193
|
+
],
|
|
194
|
+
stats: [
|
|
195
|
+
{key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
|
|
196
|
+
{key: 'density', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'density'},
|
|
197
|
+
{key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
|
|
198
|
+
{key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: 'ship-t1',
|
|
203
|
+
name: 'Ship T1',
|
|
204
|
+
description: 'General-purpose vessel with 5 module slots.',
|
|
205
|
+
color: '#4AE898',
|
|
206
|
+
packedItemId: ITEM_SHIP_T1_PACKED,
|
|
207
|
+
recipe: [
|
|
208
|
+
{itemId: ITEM_HULL_PLATES, quantity: 8},
|
|
209
|
+
{itemId: ITEM_CARGO_LINING, quantity: 4},
|
|
210
|
+
],
|
|
211
|
+
stats: [
|
|
212
|
+
{key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
|
|
213
|
+
{key: 'density', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'density'},
|
|
214
|
+
{key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
|
|
215
|
+
{key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
export interface ModuleRecipe {
|
|
221
|
+
id: string
|
|
222
|
+
name: string
|
|
223
|
+
description: string
|
|
224
|
+
color: string
|
|
225
|
+
itemId: number
|
|
226
|
+
moduleType: number
|
|
227
|
+
recipe: RecipeInput[]
|
|
228
|
+
stats: {key: string; sourceComponentId: number; sourceStatKey: string}[]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export const moduleRecipes: ModuleRecipe[] = [
|
|
232
|
+
{
|
|
233
|
+
id: 'engine-t1',
|
|
234
|
+
name: 'Engine Module T1',
|
|
235
|
+
description: 'Basic propulsion system. Converts volatile gases into thrust.',
|
|
236
|
+
color: '#E86344',
|
|
237
|
+
itemId: ITEM_ENGINE_T1,
|
|
238
|
+
moduleType: MODULE_ENGINE,
|
|
239
|
+
recipe: [{itemId: ITEM_THRUSTER_CORE, quantity: 6}],
|
|
240
|
+
stats: [
|
|
241
|
+
{key: 'volatility', sourceComponentId: ITEM_THRUSTER_CORE, sourceStatKey: 'volatility'},
|
|
242
|
+
{key: 'thermal', sourceComponentId: ITEM_THRUSTER_CORE, sourceStatKey: 'thermal'},
|
|
243
|
+
],
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
id: 'generator-t1',
|
|
247
|
+
name: 'Generator Module T1',
|
|
248
|
+
description: 'Basic energy system. Stores and recharges energy from resonant minerals.',
|
|
249
|
+
color: '#7B5AE8',
|
|
250
|
+
itemId: ITEM_GENERATOR_T1,
|
|
251
|
+
moduleType: MODULE_GENERATOR,
|
|
252
|
+
recipe: [{itemId: ITEM_POWER_CELL, quantity: 5}],
|
|
253
|
+
stats: [
|
|
254
|
+
{key: 'resonance', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'resonance'},
|
|
255
|
+
{key: 'clarity', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'clarity'},
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
id: 'extractor-t1',
|
|
260
|
+
name: 'Extractor Module T1',
|
|
261
|
+
description: 'Basic extraction system. Drills and probes for raw resources.',
|
|
262
|
+
color: '#7B8D9E',
|
|
263
|
+
itemId: ITEM_EXTRACTOR_T1,
|
|
264
|
+
moduleType: MODULE_EXTRACTOR,
|
|
265
|
+
recipe: [
|
|
266
|
+
{itemId: ITEM_DRILL_SHAFT, quantity: 4},
|
|
267
|
+
{itemId: ITEM_EXTRACTION_PROBE, quantity: 3},
|
|
268
|
+
],
|
|
269
|
+
stats: [
|
|
270
|
+
{key: 'strength', sourceComponentId: ITEM_DRILL_SHAFT, sourceStatKey: 'strength'},
|
|
271
|
+
{key: 'tolerance', sourceComponentId: ITEM_DRILL_SHAFT, sourceStatKey: 'tolerance'},
|
|
272
|
+
{key: 'reflectivity', sourceComponentId: ITEM_EXTRACTION_PROBE, sourceStatKey: 'reflectivity'},
|
|
273
|
+
{key: 'conductivity', sourceComponentId: ITEM_EXTRACTION_PROBE, sourceStatKey: 'conductivity'},
|
|
274
|
+
{key: 'reflectivity_drill', sourceComponentId: ITEM_EXTRACTION_PROBE, sourceStatKey: 'reflectivity'},
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: 'loader-t1',
|
|
279
|
+
name: 'Loader Module T1',
|
|
280
|
+
description: 'Basic cargo handling system. Loads and unloads cargo with articulated arms.',
|
|
281
|
+
color: '#6B8E5A',
|
|
282
|
+
itemId: ITEM_LOADER_T1,
|
|
283
|
+
moduleType: MODULE_LOADER,
|
|
284
|
+
recipe: [
|
|
285
|
+
{itemId: ITEM_CARGO_LINING, quantity: 3},
|
|
286
|
+
{itemId: ITEM_CARGO_ARM, quantity: 3},
|
|
287
|
+
],
|
|
288
|
+
stats: [
|
|
289
|
+
{key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
|
|
290
|
+
{key: 'plasticity', sourceComponentId: ITEM_CARGO_ARM, sourceStatKey: 'plasticity'},
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: 'manufacturing-t1',
|
|
295
|
+
name: 'Manufacturing Module T1',
|
|
296
|
+
description: 'Basic crafting system. Processes materials using reaction chambers and cutting tools.',
|
|
297
|
+
color: '#7EC8E3',
|
|
298
|
+
itemId: ITEM_MANUFACTURING_T1,
|
|
299
|
+
moduleType: MODULE_CRAFTER,
|
|
300
|
+
recipe: [
|
|
301
|
+
{itemId: ITEM_TOOL_BIT, quantity: 3},
|
|
302
|
+
{itemId: ITEM_REACTION_CHAMBER, quantity: 3},
|
|
303
|
+
],
|
|
304
|
+
stats: [
|
|
305
|
+
{key: 'reactivity', sourceComponentId: ITEM_REACTION_CHAMBER, sourceStatKey: 'reactivity'},
|
|
306
|
+
{key: 'clarity', sourceComponentId: ITEM_TOOL_BIT, sourceStatKey: 'clarity'},
|
|
307
|
+
],
|
|
308
|
+
},
|
|
309
|
+
]
|
|
310
|
+
|
|
311
|
+
export function getModuleRecipe(id: string): ModuleRecipe | undefined {
|
|
312
|
+
return moduleRecipes.find((r) => r.id === id)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function getModuleRecipeByItemId(itemId: number): ModuleRecipe | undefined {
|
|
316
|
+
return moduleRecipes.find((r) => r.itemId === itemId)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export function getComponentById(id: number): ComponentDefinition | undefined {
|
|
320
|
+
return components.find((c) => c.id === id)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export function getEntityRecipe(id: string): EntityRecipe | undefined {
|
|
324
|
+
return entityRecipes.find((r) => r.id === id)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export function getEntityRecipeByItemId(itemId: number): EntityRecipe | undefined {
|
|
328
|
+
return entityRecipes.find((r) => r.packedItemId === itemId)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function getAllCraftableItems(): CraftableItem[] {
|
|
332
|
+
const items: CraftableItem[] = []
|
|
333
|
+
for (const comp of components) {
|
|
334
|
+
items.push({type: 'component', id: comp.id, name: comp.name, description: comp.description, color: comp.color})
|
|
335
|
+
}
|
|
336
|
+
for (const entity of entityRecipes) {
|
|
337
|
+
items.push({type: 'entity', id: entity.id, name: entity.name, description: entity.description, color: entity.color})
|
|
338
|
+
}
|
|
339
|
+
for (const mod of moduleRecipes) {
|
|
340
|
+
items.push({type: 'module', id: mod.id, name: mod.name, description: mod.description, color: mod.color})
|
|
341
|
+
}
|
|
342
|
+
return items
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export function getComponentsForCategory(category: ResourceCategory): ComponentDefinition[] {
|
|
346
|
+
return components.filter((c) => c.recipe.some((r) => r.category === category))
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export function getComponentsForStat(statKey: string): ComponentDefinition[] {
|
|
350
|
+
return components.filter((c) => c.stats.some((s) => s.key === statKey))
|
|
351
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {UInt64} from '@wharfkit/antelope'
|
|
2
|
+
import type {ResourceCategory} from '../types'
|
|
3
|
+
import {
|
|
4
|
+
entityRecipes,
|
|
5
|
+
getComponentById,
|
|
6
|
+
getEntityRecipe,
|
|
7
|
+
getModuleRecipe,
|
|
8
|
+
moduleRecipes,
|
|
9
|
+
} from '../data/recipes'
|
|
10
|
+
import {deriveResourceStats} from './stratum'
|
|
11
|
+
|
|
12
|
+
export interface StackInput {
|
|
13
|
+
quantity: number
|
|
14
|
+
stats: Record<string, number>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CategoryStacks {
|
|
18
|
+
category: ResourceCategory
|
|
19
|
+
stacks: StackInput[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function encodeStats(values: number[]): bigint {
|
|
23
|
+
let seed = 0n
|
|
24
|
+
for (let i = 0; i < values.length && i < 6; i++) {
|
|
25
|
+
seed |= BigInt(values[i] & 0x3ff) << BigInt(i * 10)
|
|
26
|
+
}
|
|
27
|
+
return seed
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function decodeStats(seed: bigint, count: number): number[] {
|
|
31
|
+
const stats: number[] = []
|
|
32
|
+
for (let i = 0; i < count; i++) {
|
|
33
|
+
stats.push(Number((seed >> BigInt(i * 10)) & 0x3ffn))
|
|
34
|
+
}
|
|
35
|
+
return stats
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function mapStatsToKeys(seed: bigint, statDefs: {key: string}[]): Record<string, number> {
|
|
39
|
+
const values = decodeStats(seed, statDefs.length)
|
|
40
|
+
const result: Record<string, number> = {}
|
|
41
|
+
for (let i = 0; i < statDefs.length; i++) {
|
|
42
|
+
result[statDefs[i].key] = values[i]
|
|
43
|
+
}
|
|
44
|
+
return result
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function decodeCraftedItemStats(itemId: number, seed: bigint): Record<string, number> {
|
|
48
|
+
const comp = getComponentById(itemId)
|
|
49
|
+
if (comp) return mapStatsToKeys(seed, comp.stats)
|
|
50
|
+
|
|
51
|
+
const entityRecipe = entityRecipes.find((r) => r.packedItemId === itemId)
|
|
52
|
+
if (entityRecipe) return mapStatsToKeys(seed, entityRecipe.stats)
|
|
53
|
+
|
|
54
|
+
const moduleRecipe = moduleRecipes.find((r) => r.itemId === itemId)
|
|
55
|
+
if (moduleRecipe) return mapStatsToKeys(seed, moduleRecipe.stats)
|
|
56
|
+
|
|
57
|
+
return {}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function blendStacks(stacks: StackInput[], statKey: string): number {
|
|
61
|
+
let totalQty = 0
|
|
62
|
+
let weightedSum = 0
|
|
63
|
+
for (const stack of stacks) {
|
|
64
|
+
const val = stack.stats[statKey] ?? 0
|
|
65
|
+
weightedSum += val * stack.quantity
|
|
66
|
+
totalQty += stack.quantity
|
|
67
|
+
}
|
|
68
|
+
if (totalQty === 0) return 0
|
|
69
|
+
return Math.floor(weightedSum / totalQty)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function computeComponentStats(
|
|
73
|
+
componentId: number,
|
|
74
|
+
categoryStacks: CategoryStacks[]
|
|
75
|
+
): {key: string; value: number}[] {
|
|
76
|
+
const comp = getComponentById(componentId)
|
|
77
|
+
if (!comp) return []
|
|
78
|
+
|
|
79
|
+
return comp.stats.map((statDef) => {
|
|
80
|
+
const matching = categoryStacks.find((cs) => cs.category === statDef.source)
|
|
81
|
+
const value = matching ? blendStacks(matching.stacks, statDef.key) : 0
|
|
82
|
+
return {key: statDef.key, value: Math.max(1, Math.min(999, value))}
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function blendComponentStacks(
|
|
87
|
+
stacks: {quantity: number; stats: Record<string, number>}[]
|
|
88
|
+
): Record<string, number> {
|
|
89
|
+
if (stacks.length === 0) return {}
|
|
90
|
+
const allKeys = new Set<string>()
|
|
91
|
+
for (const s of stacks) {
|
|
92
|
+
for (const k of Object.keys(s.stats)) allKeys.add(k)
|
|
93
|
+
}
|
|
94
|
+
const result: Record<string, number> = {}
|
|
95
|
+
for (const key of allKeys) {
|
|
96
|
+
result[key] = blendStacks(
|
|
97
|
+
stacks.map((s) => ({quantity: s.quantity, stats: s.stats})),
|
|
98
|
+
key
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
return result
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function computeEntityStats(
|
|
105
|
+
entityRecipeId: string,
|
|
106
|
+
componentStacks: Record<number, {quantity: number; stats: Record<string, number>}[]>
|
|
107
|
+
): {key: string; value: number}[] {
|
|
108
|
+
const recipe = getEntityRecipe(entityRecipeId) ?? getModuleRecipe(entityRecipeId)
|
|
109
|
+
if (!recipe) return []
|
|
110
|
+
|
|
111
|
+
const blendedByComponent: Record<number, Record<string, number>> = {}
|
|
112
|
+
for (const [compId, stacks] of Object.entries(componentStacks)) {
|
|
113
|
+
blendedByComponent[Number(compId)] = blendComponentStacks(stacks)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return recipe.stats.map((stat) => {
|
|
117
|
+
const blended = blendedByComponent[stat.sourceComponentId] ?? {}
|
|
118
|
+
const value = blended[stat.sourceStatKey] ?? 0
|
|
119
|
+
return {key: stat.key, value: Math.max(1, Math.min(999, value))}
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function decodeStackStats(itemId: number, seed: UInt64): Record<string, number> {
|
|
124
|
+
if (itemId >= 10000) {
|
|
125
|
+
return decodeCraftedItemStats(itemId, BigInt(seed.toString()))
|
|
126
|
+
}
|
|
127
|
+
const raw = deriveResourceStats(BigInt(seed.toString()))
|
|
128
|
+
return {stat1: raw.stat1, stat2: raw.stat2, stat3: raw.stat3}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function blendCargoStacks(
|
|
132
|
+
itemId: number,
|
|
133
|
+
stacks: {quantity: number; seed: UInt64}[]
|
|
134
|
+
): UInt64 {
|
|
135
|
+
const decoded = stacks.map((s) => ({
|
|
136
|
+
quantity: s.quantity,
|
|
137
|
+
stats: decodeStackStats(itemId, s.seed),
|
|
138
|
+
}))
|
|
139
|
+
const allKeys = Object.keys(decoded[0]?.stats ?? {})
|
|
140
|
+
const blended = allKeys.map((key) => Math.max(1, Math.min(999, blendStacks(decoded, key))))
|
|
141
|
+
return UInt64.from(encodeStats(blended))
|
|
142
|
+
}
|
package/src/derivation/index.ts
CHANGED