@shipload/sdk 1.0.0-next.71 → 1.0.0-next.72
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/lib/shipload.d.ts +41 -21
- package/lib/shipload.js +517 -348
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +510 -345
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +1 -6
- package/lib/testing.js +59 -43
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +59 -43
- package/lib/testing.m.js.map +1 -1
- package/package.json +1 -1
- package/src/contracts/server.ts +3 -17
- package/src/data/capability-formulas.ts +4 -4
- package/src/data/entities.json +84 -68
- package/src/data/item-ids.ts +5 -4
- package/src/data/items.json +30 -24
- package/src/data/kind-registry.json +75 -39
- package/src/data/kind-registry.ts +13 -0
- package/src/data/metadata.ts +35 -0
- package/src/data/recipes.json +194 -155
- package/src/derivation/build-methods.test.ts +4 -4
- package/src/derivation/capabilities.test.ts +14 -10
- package/src/derivation/capabilities.ts +8 -10
- package/src/derivation/capability-mappings.ts +4 -4
- package/src/derivation/capacity-fn-registry.test.ts +9 -0
- package/src/derivation/capacity-fn-registry.ts +18 -0
- package/src/derivation/recipe-usage.test.ts +7 -11
- package/src/index-module.ts +6 -0
- package/src/influence/influence.test.ts +1 -1
- package/src/managers/actions.ts +5 -0
- package/src/managers/context.ts +9 -0
- package/src/managers/fund.ts +49 -0
- package/src/managers/index.ts +3 -0
- package/src/nft/description.ts +5 -10
- package/src/resolution/resolve-item.test.ts +15 -10
- package/src/shipload.ts +5 -0
package/src/data/recipes.json
CHANGED
|
@@ -861,161 +861,6 @@
|
|
|
861
861
|
],
|
|
862
862
|
"blendWeights": []
|
|
863
863
|
},
|
|
864
|
-
{
|
|
865
|
-
"outputItemId": 10202,
|
|
866
|
-
"outputMass": 32000,
|
|
867
|
-
"inputs": [
|
|
868
|
-
{
|
|
869
|
-
"itemId": 10001,
|
|
870
|
-
"quantity": 1000
|
|
871
|
-
},
|
|
872
|
-
{
|
|
873
|
-
"itemId": 10008,
|
|
874
|
-
"quantity": 1000
|
|
875
|
-
}
|
|
876
|
-
],
|
|
877
|
-
"statSlots": [
|
|
878
|
-
{
|
|
879
|
-
"sources": [
|
|
880
|
-
{
|
|
881
|
-
"inputIndex": 0,
|
|
882
|
-
"statIndex": 0
|
|
883
|
-
}
|
|
884
|
-
]
|
|
885
|
-
},
|
|
886
|
-
{
|
|
887
|
-
"sources": [
|
|
888
|
-
{
|
|
889
|
-
"inputIndex": 0,
|
|
890
|
-
"statIndex": 1
|
|
891
|
-
}
|
|
892
|
-
]
|
|
893
|
-
},
|
|
894
|
-
{
|
|
895
|
-
"sources": [
|
|
896
|
-
{
|
|
897
|
-
"inputIndex": 1,
|
|
898
|
-
"statIndex": 0
|
|
899
|
-
}
|
|
900
|
-
]
|
|
901
|
-
},
|
|
902
|
-
{
|
|
903
|
-
"sources": [
|
|
904
|
-
{
|
|
905
|
-
"inputIndex": 1,
|
|
906
|
-
"statIndex": 1
|
|
907
|
-
}
|
|
908
|
-
]
|
|
909
|
-
}
|
|
910
|
-
],
|
|
911
|
-
"blendWeights": []
|
|
912
|
-
},
|
|
913
|
-
{
|
|
914
|
-
"outputItemId": 10203,
|
|
915
|
-
"outputMass": 19000,
|
|
916
|
-
"inputs": [
|
|
917
|
-
{
|
|
918
|
-
"itemId": 10008,
|
|
919
|
-
"quantity": 600
|
|
920
|
-
},
|
|
921
|
-
{
|
|
922
|
-
"itemId": 10006,
|
|
923
|
-
"quantity": 600
|
|
924
|
-
}
|
|
925
|
-
],
|
|
926
|
-
"statSlots": [
|
|
927
|
-
{
|
|
928
|
-
"sources": []
|
|
929
|
-
},
|
|
930
|
-
{
|
|
931
|
-
"sources": [
|
|
932
|
-
{
|
|
933
|
-
"inputIndex": 0,
|
|
934
|
-
"statIndex": 1
|
|
935
|
-
}
|
|
936
|
-
]
|
|
937
|
-
},
|
|
938
|
-
{
|
|
939
|
-
"sources": [
|
|
940
|
-
{
|
|
941
|
-
"inputIndex": 0,
|
|
942
|
-
"statIndex": 0
|
|
943
|
-
}
|
|
944
|
-
]
|
|
945
|
-
},
|
|
946
|
-
{
|
|
947
|
-
"sources": []
|
|
948
|
-
}
|
|
949
|
-
],
|
|
950
|
-
"blendWeights": []
|
|
951
|
-
},
|
|
952
|
-
{
|
|
953
|
-
"outputItemId": 10204,
|
|
954
|
-
"outputMass": 19000,
|
|
955
|
-
"inputs": [
|
|
956
|
-
{
|
|
957
|
-
"itemId": 10008,
|
|
958
|
-
"quantity": 600
|
|
959
|
-
},
|
|
960
|
-
{
|
|
961
|
-
"itemId": 10007,
|
|
962
|
-
"quantity": 600
|
|
963
|
-
}
|
|
964
|
-
],
|
|
965
|
-
"statSlots": [
|
|
966
|
-
{
|
|
967
|
-
"sources": []
|
|
968
|
-
},
|
|
969
|
-
{
|
|
970
|
-
"sources": [
|
|
971
|
-
{
|
|
972
|
-
"inputIndex": 0,
|
|
973
|
-
"statIndex": 1
|
|
974
|
-
}
|
|
975
|
-
]
|
|
976
|
-
},
|
|
977
|
-
{
|
|
978
|
-
"sources": [
|
|
979
|
-
{
|
|
980
|
-
"inputIndex": 0,
|
|
981
|
-
"statIndex": 0
|
|
982
|
-
}
|
|
983
|
-
]
|
|
984
|
-
},
|
|
985
|
-
{
|
|
986
|
-
"sources": []
|
|
987
|
-
}
|
|
988
|
-
],
|
|
989
|
-
"blendWeights": []
|
|
990
|
-
},
|
|
991
|
-
{
|
|
992
|
-
"outputItemId": 10207,
|
|
993
|
-
"outputMass": 24000,
|
|
994
|
-
"inputs": [
|
|
995
|
-
{
|
|
996
|
-
"itemId": 10005,
|
|
997
|
-
"quantity": 200
|
|
998
|
-
},
|
|
999
|
-
{
|
|
1000
|
-
"itemId": 10010,
|
|
1001
|
-
"quantity": 200
|
|
1002
|
-
}
|
|
1003
|
-
],
|
|
1004
|
-
"statSlots": [
|
|
1005
|
-
{
|
|
1006
|
-
"sources": []
|
|
1007
|
-
},
|
|
1008
|
-
{
|
|
1009
|
-
"sources": [
|
|
1010
|
-
{
|
|
1011
|
-
"inputIndex": 1,
|
|
1012
|
-
"statIndex": 1
|
|
1013
|
-
}
|
|
1014
|
-
]
|
|
1015
|
-
}
|
|
1016
|
-
],
|
|
1017
|
-
"blendWeights": []
|
|
1018
|
-
},
|
|
1019
864
|
{
|
|
1020
865
|
"outputItemId": 10210,
|
|
1021
866
|
"outputMass": 16000,
|
|
@@ -2615,6 +2460,200 @@
|
|
|
2615
2460
|
"blendWeights": [],
|
|
2616
2461
|
"sourceSubclass": 10200
|
|
2617
2462
|
},
|
|
2463
|
+
{
|
|
2464
|
+
"outputItemId": 11202,
|
|
2465
|
+
"outputMass": 51200,
|
|
2466
|
+
"inputs": [
|
|
2467
|
+
{
|
|
2468
|
+
"itemId": 11001,
|
|
2469
|
+
"quantity": 1000
|
|
2470
|
+
},
|
|
2471
|
+
{
|
|
2472
|
+
"itemId": 11008,
|
|
2473
|
+
"quantity": 1000
|
|
2474
|
+
}
|
|
2475
|
+
],
|
|
2476
|
+
"statSlots": [
|
|
2477
|
+
{
|
|
2478
|
+
"sources": [
|
|
2479
|
+
{
|
|
2480
|
+
"inputIndex": 0,
|
|
2481
|
+
"statIndex": 0
|
|
2482
|
+
}
|
|
2483
|
+
]
|
|
2484
|
+
},
|
|
2485
|
+
{
|
|
2486
|
+
"sources": [
|
|
2487
|
+
{
|
|
2488
|
+
"inputIndex": 0,
|
|
2489
|
+
"statIndex": 1
|
|
2490
|
+
}
|
|
2491
|
+
]
|
|
2492
|
+
},
|
|
2493
|
+
{
|
|
2494
|
+
"sources": [
|
|
2495
|
+
{
|
|
2496
|
+
"inputIndex": 1,
|
|
2497
|
+
"statIndex": 0
|
|
2498
|
+
}
|
|
2499
|
+
]
|
|
2500
|
+
},
|
|
2501
|
+
{
|
|
2502
|
+
"sources": [
|
|
2503
|
+
{
|
|
2504
|
+
"inputIndex": 1,
|
|
2505
|
+
"statIndex": 1
|
|
2506
|
+
}
|
|
2507
|
+
]
|
|
2508
|
+
}
|
|
2509
|
+
],
|
|
2510
|
+
"blendWeights": []
|
|
2511
|
+
},
|
|
2512
|
+
{
|
|
2513
|
+
"outputItemId": 11203,
|
|
2514
|
+
"outputMass": 30400,
|
|
2515
|
+
"inputs": [
|
|
2516
|
+
{
|
|
2517
|
+
"itemId": 11008,
|
|
2518
|
+
"quantity": 600
|
|
2519
|
+
},
|
|
2520
|
+
{
|
|
2521
|
+
"itemId": 11006,
|
|
2522
|
+
"quantity": 600
|
|
2523
|
+
}
|
|
2524
|
+
],
|
|
2525
|
+
"statSlots": [
|
|
2526
|
+
{
|
|
2527
|
+
"sources": []
|
|
2528
|
+
},
|
|
2529
|
+
{
|
|
2530
|
+
"sources": [
|
|
2531
|
+
{
|
|
2532
|
+
"inputIndex": 0,
|
|
2533
|
+
"statIndex": 1
|
|
2534
|
+
}
|
|
2535
|
+
]
|
|
2536
|
+
},
|
|
2537
|
+
{
|
|
2538
|
+
"sources": [
|
|
2539
|
+
{
|
|
2540
|
+
"inputIndex": 0,
|
|
2541
|
+
"statIndex": 0
|
|
2542
|
+
}
|
|
2543
|
+
]
|
|
2544
|
+
},
|
|
2545
|
+
{
|
|
2546
|
+
"sources": []
|
|
2547
|
+
}
|
|
2548
|
+
],
|
|
2549
|
+
"blendWeights": []
|
|
2550
|
+
},
|
|
2551
|
+
{
|
|
2552
|
+
"outputItemId": 11204,
|
|
2553
|
+
"outputMass": 30400,
|
|
2554
|
+
"inputs": [
|
|
2555
|
+
{
|
|
2556
|
+
"itemId": 11008,
|
|
2557
|
+
"quantity": 600
|
|
2558
|
+
},
|
|
2559
|
+
{
|
|
2560
|
+
"itemId": 11007,
|
|
2561
|
+
"quantity": 600
|
|
2562
|
+
}
|
|
2563
|
+
],
|
|
2564
|
+
"statSlots": [
|
|
2565
|
+
{
|
|
2566
|
+
"sources": []
|
|
2567
|
+
},
|
|
2568
|
+
{
|
|
2569
|
+
"sources": [
|
|
2570
|
+
{
|
|
2571
|
+
"inputIndex": 0,
|
|
2572
|
+
"statIndex": 1
|
|
2573
|
+
}
|
|
2574
|
+
]
|
|
2575
|
+
},
|
|
2576
|
+
{
|
|
2577
|
+
"sources": [
|
|
2578
|
+
{
|
|
2579
|
+
"inputIndex": 0,
|
|
2580
|
+
"statIndex": 0
|
|
2581
|
+
}
|
|
2582
|
+
]
|
|
2583
|
+
},
|
|
2584
|
+
{
|
|
2585
|
+
"sources": []
|
|
2586
|
+
}
|
|
2587
|
+
],
|
|
2588
|
+
"blendWeights": []
|
|
2589
|
+
},
|
|
2590
|
+
{
|
|
2591
|
+
"outputItemId": 11207,
|
|
2592
|
+
"outputMass": 38400,
|
|
2593
|
+
"inputs": [
|
|
2594
|
+
{
|
|
2595
|
+
"itemId": 11005,
|
|
2596
|
+
"quantity": 200
|
|
2597
|
+
},
|
|
2598
|
+
{
|
|
2599
|
+
"itemId": 11010,
|
|
2600
|
+
"quantity": 200
|
|
2601
|
+
}
|
|
2602
|
+
],
|
|
2603
|
+
"statSlots": [
|
|
2604
|
+
{
|
|
2605
|
+
"sources": []
|
|
2606
|
+
},
|
|
2607
|
+
{
|
|
2608
|
+
"sources": [
|
|
2609
|
+
{
|
|
2610
|
+
"inputIndex": 1,
|
|
2611
|
+
"statIndex": 1
|
|
2612
|
+
}
|
|
2613
|
+
]
|
|
2614
|
+
}
|
|
2615
|
+
],
|
|
2616
|
+
"blendWeights": []
|
|
2617
|
+
},
|
|
2618
|
+
{
|
|
2619
|
+
"outputItemId": 11209,
|
|
2620
|
+
"outputMass": 30400,
|
|
2621
|
+
"inputs": [
|
|
2622
|
+
{
|
|
2623
|
+
"itemId": 11001,
|
|
2624
|
+
"quantity": 600
|
|
2625
|
+
},
|
|
2626
|
+
{
|
|
2627
|
+
"itemId": 11003,
|
|
2628
|
+
"quantity": 600
|
|
2629
|
+
}
|
|
2630
|
+
],
|
|
2631
|
+
"statSlots": [
|
|
2632
|
+
{
|
|
2633
|
+
"sources": [
|
|
2634
|
+
{
|
|
2635
|
+
"inputIndex": 0,
|
|
2636
|
+
"statIndex": 0
|
|
2637
|
+
}
|
|
2638
|
+
]
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
"sources": [
|
|
2642
|
+
{
|
|
2643
|
+
"inputIndex": 0,
|
|
2644
|
+
"statIndex": 1
|
|
2645
|
+
}
|
|
2646
|
+
]
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
"sources": []
|
|
2650
|
+
},
|
|
2651
|
+
{
|
|
2652
|
+
"sources": []
|
|
2653
|
+
}
|
|
2654
|
+
],
|
|
2655
|
+
"blendWeights": []
|
|
2656
|
+
},
|
|
2618
2657
|
{
|
|
2619
2658
|
"outputItemId": 11212,
|
|
2620
2659
|
"outputMass": 43200,
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
import {getRecipe} from '../data/recipes-runtime'
|
|
12
12
|
import {
|
|
13
13
|
ITEM_DEPOT_T1_PACKED,
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
ITEM_HUB_T2_PACKED,
|
|
15
|
+
ITEM_WAREHOUSE_T2_PACKED,
|
|
16
16
|
ITEM_WORKSHOP_T1_PACKED,
|
|
17
17
|
} from '../data/item-ids'
|
|
18
18
|
|
|
@@ -30,11 +30,11 @@ function planetaryStructures(): {itemId: number; capabilityFlags: number}[] {
|
|
|
30
30
|
|
|
31
31
|
describe('availableBuildMethods', () => {
|
|
32
32
|
test('orbital structures build via craft+deploy or plot', () => {
|
|
33
|
-
expect(availableBuildMethods(
|
|
33
|
+
expect(availableBuildMethods(ITEM_WAREHOUSE_T2_PACKED)).toEqual(['craft+deploy', 'plot'])
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
test('hub is craft+deploy only — excluded from the plot path', () => {
|
|
37
|
-
expect(availableBuildMethods(
|
|
37
|
+
expect(availableBuildMethods(ITEM_HUB_T2_PACKED)).toEqual(['craft+deploy'])
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
test('planetary structures are charter-granted and carry no build method', () => {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
computeLoaderCapabilities,
|
|
11
11
|
computeBaseCapacity,
|
|
12
12
|
computeContainerCapabilities,
|
|
13
|
+
applyCapacityTier,
|
|
13
14
|
GATHERER_YIELD_TIER_TABLE,
|
|
14
15
|
ENGINE_THRUST_TIER_PCT,
|
|
15
16
|
GENERATOR_CAPACITY_TIER_PCT,
|
|
@@ -30,10 +31,11 @@ import {
|
|
|
30
31
|
computeLoaderThrust,
|
|
31
32
|
} from '../nft/description'
|
|
32
33
|
import {applySlotMultiplier, U16_MAX} from '../entities/slot-multiplier'
|
|
34
|
+
import {getItem} from '../data/catalog'
|
|
33
35
|
import {encodeStats} from './crafting'
|
|
34
36
|
import {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
ITEM_EXTRACTOR_T2_PACKED,
|
|
38
|
+
ITEM_FACTORY_T2_PACKED,
|
|
37
39
|
ITEM_MASS_DRIVER_T1_PACKED,
|
|
38
40
|
ITEM_MASS_CATCHER_T1_PACKED,
|
|
39
41
|
ITEM_GATHERER_T1,
|
|
@@ -74,14 +76,16 @@ function makeBuilderStats(resonance: number, fineness: number): bigint {
|
|
|
74
76
|
|
|
75
77
|
test('computeBaseCapacity uses container formula for all container-class entities', () => {
|
|
76
78
|
const stats = {strength: 300, hardness: 400, density: 100}
|
|
77
|
-
const
|
|
79
|
+
const base = computeContainerCapabilities(stats).capacity
|
|
78
80
|
for (const itemId of [
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
ITEM_EXTRACTOR_T2_PACKED,
|
|
82
|
+
ITEM_FACTORY_T2_PACKED,
|
|
81
83
|
ITEM_MASS_DRIVER_T1_PACKED,
|
|
82
84
|
ITEM_MASS_CATCHER_T1_PACKED,
|
|
83
85
|
]) {
|
|
84
|
-
expect(computeBaseCapacity(itemId, stats)).toBe(
|
|
86
|
+
expect(computeBaseCapacity(itemId, stats)).toBe(
|
|
87
|
+
applyCapacityTier(base, getItem(itemId).tier)
|
|
88
|
+
)
|
|
85
89
|
}
|
|
86
90
|
})
|
|
87
91
|
|
|
@@ -117,7 +121,7 @@ test('computeEntityCapabilities emits gathererLanes alongside legacy gatherer su
|
|
|
117
121
|
{type: 'gatherer', outputPct: 100, maxTier: 1},
|
|
118
122
|
]
|
|
119
123
|
|
|
120
|
-
const result = computeEntityCapabilities({},
|
|
124
|
+
const result = computeEntityCapabilities({}, ITEM_EXTRACTOR_T2_PACKED, modules, layout)
|
|
121
125
|
|
|
122
126
|
// Lane lists must exist
|
|
123
127
|
expect(result.gathererLanes).toBeDefined()
|
|
@@ -160,7 +164,7 @@ test('computeEntityCapabilities emits crafterLanes alongside legacy crafter sum'
|
|
|
160
164
|
|
|
161
165
|
const layout: EntitySlot[] = [{type: 'crafter', outputPct: 120, maxTier: 1}]
|
|
162
166
|
|
|
163
|
-
const result = computeEntityCapabilities({},
|
|
167
|
+
const result = computeEntityCapabilities({}, ITEM_EXTRACTOR_T2_PACKED, modules, layout)
|
|
164
168
|
|
|
165
169
|
expect(result.crafterLanes).toBeDefined()
|
|
166
170
|
expect(result.crafterLanes!.length).toBe(1)
|
|
@@ -189,7 +193,7 @@ test('computeEntityCapabilities emits a Builder lane from resonance and fineness
|
|
|
189
193
|
{slotIndex: 0, itemId: ITEM_BUILDER_T1, stats: makeBuilderStats(500, 330)},
|
|
190
194
|
]
|
|
191
195
|
const layout: EntitySlot[] = [{type: 'builder', outputPct: 80, maxTier: 1}]
|
|
192
|
-
const result = computeEntityCapabilities({},
|
|
196
|
+
const result = computeEntityCapabilities({}, ITEM_EXTRACTOR_T2_PACKED, modules, layout)
|
|
193
197
|
|
|
194
198
|
expect(result.builderLanes).toEqual([{slotIndex: 0, speed: 400, drain: 20_000, outputPct: 80}])
|
|
195
199
|
expect(result.builder).toEqual({speed: 400, drain: 20_000})
|
|
@@ -202,7 +206,7 @@ test('computeEntityCapabilities emits loaderLanes alongside legacy loaders sum',
|
|
|
202
206
|
|
|
203
207
|
const layout: EntitySlot[] = [{type: 'loader', outputPct: 80, maxTier: 1}]
|
|
204
208
|
|
|
205
|
-
const result = computeEntityCapabilities({},
|
|
209
|
+
const result = computeEntityCapabilities({}, ITEM_EXTRACTOR_T2_PACKED, modules, layout)
|
|
206
210
|
|
|
207
211
|
expect(result.loaderLanes).toBeDefined()
|
|
208
212
|
expect(result.loaderLanes!.length).toBe(1)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {getEntityLayout} from '../data/recipes-runtime'
|
|
2
2
|
import {ENTITY_SHIP, getPackedEntityType} from '../data/kind-registry'
|
|
3
3
|
import {computeEffectiveModuleStat} from './stat-scaling'
|
|
4
|
+
import {resolveCapacityFnName, type CapacityFnName} from './capacity-fn-registry'
|
|
4
5
|
|
|
5
6
|
export const DEFAULT_BASE_HULLMASS = 1_000
|
|
6
7
|
|
|
@@ -235,7 +236,7 @@ import {
|
|
|
235
236
|
ITEM_CONTAINER_T1_PACKED,
|
|
236
237
|
ITEM_DEPOT_T1_PACKED,
|
|
237
238
|
ITEM_SHIP_T1_PACKED,
|
|
238
|
-
|
|
239
|
+
ITEM_WAREHOUSE_T2_PACKED,
|
|
239
240
|
ITEM_WORKSHOP_T1_PACKED,
|
|
240
241
|
} from '../data/item-ids'
|
|
241
242
|
import {
|
|
@@ -314,15 +315,12 @@ export function computeGathererYield(str: number, tier: number): number {
|
|
|
314
315
|
return Math.floor(((200 + str) * pct) / 100)
|
|
315
316
|
}
|
|
316
317
|
|
|
317
|
-
const
|
|
318
|
+
const CAPACITY_FN_BY_NAME: Partial<
|
|
319
|
+
Record<CapacityFnName, (stats: Record<string, number>) => number>
|
|
320
|
+
> = {
|
|
318
321
|
warehouse: (stats) => computeWarehouseHullCapabilities(stats).capacity,
|
|
319
322
|
depot: (stats) => computeDepotHullCapabilities(stats).capacity,
|
|
320
323
|
workshop: (stats) => computeWorkshopHullCapabilities(stats).capacity,
|
|
321
|
-
extractor: (stats) => computeContainerCapabilities(stats).capacity,
|
|
322
|
-
factory: (stats) => computeContainerCapabilities(stats).capacity,
|
|
323
|
-
builddock: (stats) => computeContainerCapabilities(stats).capacity,
|
|
324
|
-
mdriver: (stats) => computeContainerCapabilities(stats).capacity,
|
|
325
|
-
mcatcher: (stats) => computeContainerCapabilities(stats).capacity,
|
|
326
324
|
container: (stats) => computeContainerCapabilities(stats).capacity,
|
|
327
325
|
}
|
|
328
326
|
|
|
@@ -331,8 +329,8 @@ export function computeBaseCapacity(itemId: number, stats: Record<string, number
|
|
|
331
329
|
if (isShipHull(itemId)) {
|
|
332
330
|
base = computeShipHullCapabilities(stats, itemId).capacity
|
|
333
331
|
} else {
|
|
334
|
-
const
|
|
335
|
-
const capacityFn =
|
|
332
|
+
const fnName = resolveCapacityFnName(itemId)
|
|
333
|
+
const capacityFn = fnName ? CAPACITY_FN_BY_NAME[fnName] : undefined
|
|
336
334
|
if (!capacityFn) return 0
|
|
337
335
|
base = capacityFn(stats)
|
|
338
336
|
}
|
|
@@ -358,7 +356,7 @@ export function computeWarehouseHullCapabilities(stats: Record<string, number>):
|
|
|
358
356
|
const statSum = (stats.strength ?? 0) + (stats.hardness ?? 0)
|
|
359
357
|
const exponent = statSum / 1998.0
|
|
360
358
|
return {
|
|
361
|
-
hullmass: computeBaseHullmass(
|
|
359
|
+
hullmass: computeBaseHullmass(ITEM_WAREHOUSE_T2_PACKED, stats),
|
|
362
360
|
capacity: Math.floor(1000000 * 6 ** exponent),
|
|
363
361
|
}
|
|
364
362
|
}
|
|
@@ -4,7 +4,7 @@ import {getRecipe, type Recipe} from '../data/recipes-runtime'
|
|
|
4
4
|
import {getItem} from '../data/catalog'
|
|
5
5
|
import {
|
|
6
6
|
ITEM_ENGINE_T1,
|
|
7
|
-
|
|
7
|
+
ITEM_EXTRACTOR_T2_PACKED,
|
|
8
8
|
ITEM_GENERATOR_T1,
|
|
9
9
|
ITEM_GATHERER_T1,
|
|
10
10
|
ITEM_LOADER_T1,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
ITEM_BATTERY_T1,
|
|
17
17
|
ITEM_SHIP_T1_PACKED,
|
|
18
18
|
ITEM_CONTAINER_T1_PACKED,
|
|
19
|
-
|
|
19
|
+
ITEM_WAREHOUSE_T2_PACKED,
|
|
20
20
|
ITEM_CONTAINER_T2_PACKED,
|
|
21
21
|
} from '../data/item-ids'
|
|
22
22
|
import type {StatMapping, CapabilityAttributeRow} from '../data/capabilities'
|
|
@@ -35,8 +35,8 @@ export const KIND_TO_ITEM_ID: Record<SlotConsumerKind, number> = {
|
|
|
35
35
|
battery: ITEM_BATTERY_T1,
|
|
36
36
|
'ship-t1': ITEM_SHIP_T1_PACKED,
|
|
37
37
|
'container-t1': ITEM_CONTAINER_T1_PACKED,
|
|
38
|
-
'warehouse-
|
|
39
|
-
'extractor-
|
|
38
|
+
'warehouse-t2': ITEM_WAREHOUSE_T2_PACKED,
|
|
39
|
+
'extractor-t2': ITEM_EXTRACTOR_T2_PACKED,
|
|
40
40
|
'container-t2': ITEM_CONTAINER_T2_PACKED,
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {expect, test} from 'bun:test'
|
|
2
|
+
import {resolveCapacityFnName} from './capacity-fn-registry'
|
|
3
|
+
import kindRegistryJson from '../data/kind-registry.json'
|
|
4
|
+
|
|
5
|
+
test('every template in the catalog resolves to a known capacity function', () => {
|
|
6
|
+
for (const t of kindRegistryJson.templates as {itemId: number}[]) {
|
|
7
|
+
expect(() => resolveCapacityFnName(t.itemId)).not.toThrow()
|
|
8
|
+
}
|
|
9
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {getBaseCapacityFnName} from '../data/kind-registry'
|
|
2
|
+
|
|
3
|
+
export const CAPACITY_FN_NAMES = ['ship', 'warehouse', 'depot', 'container', 'workshop'] as const
|
|
4
|
+
|
|
5
|
+
export type CapacityFnName = (typeof CAPACITY_FN_NAMES)[number]
|
|
6
|
+
|
|
7
|
+
function isCapacityFnName(name: string): name is CapacityFnName {
|
|
8
|
+
return (CAPACITY_FN_NAMES as readonly string[]).includes(name)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function resolveCapacityFnName(itemId: number): CapacityFnName | undefined {
|
|
12
|
+
const name = getBaseCapacityFnName(itemId)
|
|
13
|
+
if (!name) return undefined
|
|
14
|
+
if (!isCapacityFnName(name)) {
|
|
15
|
+
throw new Error(`unrecognized base capacity function "${name}" for item ${itemId}`)
|
|
16
|
+
}
|
|
17
|
+
return name
|
|
18
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from './recipe-usage'
|
|
8
8
|
import {
|
|
9
9
|
ITEM_SENSOR,
|
|
10
|
+
ITEM_SENSOR_T2,
|
|
10
11
|
ITEM_RESIN,
|
|
11
12
|
ITEM_FRAME,
|
|
12
13
|
ITEM_PLATE,
|
|
@@ -14,7 +15,7 @@ import {
|
|
|
14
15
|
ITEM_GATHERER_T1,
|
|
15
16
|
ITEM_CRAFTER_T1,
|
|
16
17
|
ITEM_BUILDER_T1,
|
|
17
|
-
|
|
18
|
+
ITEM_EXTRACTOR_T2_PACKED,
|
|
18
19
|
ITEM_ROUSTABOUT_T1A_PACKED,
|
|
19
20
|
ITEM_PROSPECTOR_T1A_PACKED,
|
|
20
21
|
ITEM_TENDER_T1A_PACKED,
|
|
@@ -32,12 +33,7 @@ test('getRecipeConsumers lists every recipe that consumes Sensor', () => {
|
|
|
32
33
|
const consumers = getRecipeConsumers(ITEM_SENSOR)
|
|
33
34
|
const ids = consumers.map((c) => c.outputItemId).sort((a, b) => a - b)
|
|
34
35
|
expect(ids).toEqual(
|
|
35
|
-
[
|
|
36
|
-
ITEM_CRAFTER_T1,
|
|
37
|
-
ITEM_BUILDER_T1,
|
|
38
|
-
ITEM_EXTRACTOR_T1_PACKED,
|
|
39
|
-
ITEM_ROUSTABOUT_T1A_PACKED,
|
|
40
|
-
].sort((a, b) => a - b)
|
|
36
|
+
[ITEM_CRAFTER_T1, ITEM_BUILDER_T1, ITEM_ROUSTABOUT_T1A_PACKED].sort((a, b) => a - b)
|
|
41
37
|
)
|
|
42
38
|
})
|
|
43
39
|
|
|
@@ -52,8 +48,8 @@ test('Frame feeds the gatherer drain stat', () => {
|
|
|
52
48
|
})
|
|
53
49
|
|
|
54
50
|
test('Sensor is a mass-only sink in the Extractor recipe', () => {
|
|
55
|
-
const consumers = getRecipeConsumers(
|
|
56
|
-
const extractor = consumers.find((c) => c.outputItemId ===
|
|
51
|
+
const consumers = getRecipeConsumers(ITEM_SENSOR_T2)
|
|
52
|
+
const extractor = consumers.find((c) => c.outputItemId === ITEM_EXTRACTOR_T2_PACKED)
|
|
57
53
|
expect(extractor).toBeDefined()
|
|
58
54
|
expect(extractor?.statFlows).toHaveLength(0)
|
|
59
55
|
})
|
|
@@ -80,9 +76,9 @@ test('getResourceDemand scales by quantity', () => {
|
|
|
80
76
|
expect(getResourceDemand(ITEM_PLATE, 3)).toEqual({ore: 30})
|
|
81
77
|
})
|
|
82
78
|
|
|
83
|
-
test('getComponentDemand reports Resin as consumed by
|
|
79
|
+
test('getComponentDemand reports Resin as consumed by seven recipes', () => {
|
|
84
80
|
const demand = getComponentDemand()
|
|
85
81
|
const resin = demand.find((d) => d.itemId === ITEM_RESIN)
|
|
86
82
|
expect(resin).toBeDefined()
|
|
87
|
-
expect(resin?.consumerCount).toBe(
|
|
83
|
+
expect(resin?.consumerCount).toBe(7)
|
|
88
84
|
})
|
package/src/index-module.ts
CHANGED
|
@@ -57,6 +57,7 @@ export {
|
|
|
57
57
|
computeFreeCells,
|
|
58
58
|
NftManager,
|
|
59
59
|
BalancesManager,
|
|
60
|
+
FundManager,
|
|
60
61
|
ConstructionManager,
|
|
61
62
|
JobsManager,
|
|
62
63
|
InfluenceManager,
|
|
@@ -80,6 +81,9 @@ export type {
|
|
|
80
81
|
NftConfigForItem,
|
|
81
82
|
WrapConfig,
|
|
82
83
|
WrapGate,
|
|
84
|
+
FundBeneficiary,
|
|
85
|
+
FundToken,
|
|
86
|
+
FundAccrued,
|
|
83
87
|
DepositConfig,
|
|
84
88
|
PlatformBalance,
|
|
85
89
|
TokenBalance,
|
|
@@ -413,6 +417,7 @@ export {
|
|
|
413
417
|
ENTITY_NEXUS,
|
|
414
418
|
ENTITY_HUB,
|
|
415
419
|
ENTITY_DEPOT,
|
|
420
|
+
ENTITY_ASSEMBLY_YARD,
|
|
416
421
|
getEntityClass,
|
|
417
422
|
getPackedEntityType,
|
|
418
423
|
getKindMeta,
|
|
@@ -438,6 +443,7 @@ export {
|
|
|
438
443
|
isPlot,
|
|
439
444
|
isHub,
|
|
440
445
|
isDepot,
|
|
446
|
+
isAssemblyYard,
|
|
441
447
|
} from './data/kind-registry'
|
|
442
448
|
export type {EntityTypeName, KindMeta, TemplateMeta} from './data/kind-registry'
|
|
443
449
|
export * from './capabilities'
|
|
@@ -136,7 +136,7 @@ describe('decomposition', () => {
|
|
|
136
136
|
for (let i = 1; i < DECOMP_REGISTRY.length; i++) {
|
|
137
137
|
expect(DECOMP_REGISTRY[i].itemId).toBeGreaterThan(DECOMP_REGISTRY[i - 1].itemId)
|
|
138
138
|
}
|
|
139
|
-
expect(DECOMP_REGISTRY.length).toBe(
|
|
139
|
+
expect(DECOMP_REGISTRY.length).toBe(57)
|
|
140
140
|
})
|
|
141
141
|
|
|
142
142
|
test('the retired Workshop has no decomposition entry', () => {
|
package/src/managers/actions.ts
CHANGED
|
@@ -1038,6 +1038,11 @@ export class ActionsManager extends BaseManager {
|
|
|
1038
1038
|
})
|
|
1039
1039
|
}
|
|
1040
1040
|
|
|
1041
|
+
/** Pays every nonzero accrued token balance to the beneficiary. */
|
|
1042
|
+
claimFund(beneficiary: NameType): Action {
|
|
1043
|
+
return this.fund.action('claim', {beneficiary_account: Name.from(beneficiary)})
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1041
1046
|
collectFund(): Action {
|
|
1042
1047
|
return this.fund.action('collect', {})
|
|
1043
1048
|
}
|