@shipload/sdk 0.7.1 → 1.0.0-beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/lib/shipload.d.ts +2730 -287
  2. package/lib/shipload.js +10862 -2229
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +10434 -2171
  5. package/lib/shipload.m.js.map +1 -1
  6. package/package.json +11 -20
  7. package/src/capabilities/crafting.ts +22 -0
  8. package/src/capabilities/gathering.ts +36 -0
  9. package/src/capabilities/guards.ts +38 -0
  10. package/src/capabilities/hauling.ts +22 -0
  11. package/src/capabilities/index.ts +8 -0
  12. package/src/capabilities/loading.ts +8 -0
  13. package/src/capabilities/modules.ts +86 -0
  14. package/src/capabilities/movement.ts +29 -0
  15. package/src/capabilities/storage.ts +159 -0
  16. package/src/contracts/server.ts +1389 -285
  17. package/src/data/capabilities.ts +408 -0
  18. package/src/data/catalog.ts +135 -0
  19. package/src/data/categories.ts +55 -0
  20. package/src/data/colors.ts +84 -0
  21. package/src/data/entities.json +50 -0
  22. package/src/data/item-ids.ts +75 -0
  23. package/src/data/items.json +252 -0
  24. package/src/data/locations.ts +53 -0
  25. package/src/data/metadata.ts +208 -0
  26. package/src/data/nebula-adjectives.json +211 -0
  27. package/src/data/nebula-nouns.json +151 -0
  28. package/src/data/recipes-runtime.ts +65 -0
  29. package/src/data/recipes.json +878 -0
  30. package/src/data/syllables.json +1790 -0
  31. package/src/data/tiers.ts +45 -0
  32. package/src/derivation/crafting.ts +350 -0
  33. package/src/derivation/index.ts +32 -0
  34. package/src/derivation/location-size.ts +15 -0
  35. package/src/derivation/resources.ts +112 -0
  36. package/src/derivation/stats.ts +146 -0
  37. package/src/derivation/strata.ts +43 -0
  38. package/src/derivation/stratum.ts +134 -0
  39. package/src/derivation/tiers.ts +54 -0
  40. package/src/entities/cargo-utils.ts +84 -0
  41. package/src/entities/container.ts +108 -0
  42. package/src/entities/entity-inventory.ts +39 -0
  43. package/src/entities/gamestate.ts +152 -0
  44. package/src/entities/inventory-accessor.ts +42 -0
  45. package/src/entities/location.ts +60 -0
  46. package/src/entities/makers.ts +196 -0
  47. package/src/entities/player.ts +15 -0
  48. package/src/entities/ship-deploy.ts +258 -0
  49. package/src/entities/ship.ts +204 -0
  50. package/src/entities/warehouse.ts +119 -0
  51. package/src/errors.ts +100 -9
  52. package/src/format.ts +12 -0
  53. package/src/index-module.ts +317 -7
  54. package/src/managers/actions.ts +250 -0
  55. package/src/managers/base.ts +25 -0
  56. package/src/managers/context.ts +114 -0
  57. package/src/managers/entities.ts +103 -0
  58. package/src/managers/epochs.ts +47 -0
  59. package/src/managers/index.ts +9 -0
  60. package/src/managers/locations.ts +68 -0
  61. package/src/managers/players.ts +13 -0
  62. package/src/nft/description.ts +176 -0
  63. package/src/nft/deserializers.ts +83 -0
  64. package/src/nft/index.ts +2 -0
  65. package/src/resolution/describe-module.ts +166 -0
  66. package/src/resolution/display-name.ts +39 -0
  67. package/src/resolution/resolve-item.ts +358 -0
  68. package/src/scheduling/accessor.ts +82 -0
  69. package/src/{epoch.ts → scheduling/epoch.ts} +1 -1
  70. package/src/scheduling/projection.ts +463 -0
  71. package/src/scheduling/schedule.ts +179 -0
  72. package/src/shipload.ts +47 -160
  73. package/src/subscriptions/connection.ts +154 -0
  74. package/src/subscriptions/debug.ts +17 -0
  75. package/src/subscriptions/index.ts +5 -0
  76. package/src/subscriptions/manager.ts +240 -0
  77. package/src/subscriptions/mappers.ts +28 -0
  78. package/src/subscriptions/types.ts +143 -0
  79. package/src/travel/travel.ts +500 -0
  80. package/src/types/capabilities.ts +76 -0
  81. package/src/types/entity-traits.ts +69 -0
  82. package/src/types/entity.ts +39 -0
  83. package/src/types/index.ts +3 -0
  84. package/src/types.ts +140 -35
  85. package/src/{hash.ts → utils/hash.ts} +2 -2
  86. package/src/utils/system.ts +168 -0
  87. package/src/goods.ts +0 -124
  88. package/src/market.ts +0 -214
  89. package/src/rolls.ts +0 -8
  90. package/src/ship.ts +0 -36
  91. package/src/state.ts +0 -0
  92. package/src/syllables.ts +0 -1184
  93. package/src/system.ts +0 -37
  94. package/src/travel.ts +0 -259
package/package.json CHANGED
@@ -1,25 +1,27 @@
1
1
  {
2
2
  "name": "@shipload/sdk",
3
3
  "description": "SDKs for Shipload",
4
- "version": "0.7.1",
4
+ "version": "1.0.0-beta1",
5
5
  "homepage": "https://github.com/shipload/sdk",
6
6
  "license": "MIT",
7
7
  "main": "lib/shipload.js",
8
8
  "module": "lib/shipload.m.js",
9
9
  "types": "lib/shipload.d.ts",
10
- "unpkg": "lib/shipload.bundle.js",
11
10
  "sideEffects": false,
12
11
  "files": [
13
12
  "lib/*",
14
13
  "src/*"
15
14
  ],
16
15
  "scripts": {
17
- "prepare": "make"
16
+ "prepare": "make",
17
+ "check": "tsc --noEmit",
18
+ "build": "make build",
19
+ "test": "make test"
18
20
  },
19
21
  "dependencies": {
20
- "@wharfkit/antelope": "^1.0.2",
21
- "@wharfkit/contract": "^1.1.5",
22
- "@wharfkit/session": "^1.3.1",
22
+ "@wharfkit/antelope": "1.2.0",
23
+ "@wharfkit/common": "1.5.0",
24
+ "@wharfkit/contract": "1.2.1",
23
25
  "tslib": "^2.1.0"
24
26
  },
25
27
  "devDependencies": {
@@ -30,34 +32,23 @@
30
32
  "@rollup/plugin-json": "^4.1.0",
31
33
  "@rollup/plugin-node-resolve": "^14.1.0",
32
34
  "@rollup/plugin-replace": "^5.0.1",
33
- "@rollup/plugin-typescript": "^10.0.1",
35
+ "@rollup/plugin-typescript": "^12.1.0",
34
36
  "@rollup/plugin-virtual": "^2.0.3",
37
+ "@types/bun": "latest",
35
38
  "@types/chai": "^4.3.1",
36
- "@types/mocha": "^9.0.0",
37
39
  "@types/node": "^18.7.18",
38
- "@typescript-eslint/eslint-plugin": "^5.20.0",
39
- "@typescript-eslint/parser": "^5.20.0",
40
40
  "@wharfkit/mock-data": "^1.3.0",
41
41
  "@wharfkit/wallet-plugin-privatekey": "^1.1.0",
42
42
  "chai": "^4.3.4",
43
- "eslint": "^8.13.0",
44
- "eslint-config-prettier": "^8.1.0",
45
- "eslint-plugin-prettier": "^4.0.0",
46
43
  "gh-pages": "^4.0.0",
47
- "mocha": "^10.0.0",
48
44
  "node-fetch": "^2.6.1",
49
- "nyc": "^15.1.0",
50
45
  "onchange": "^7.1.0",
51
- "prettier": "^2.2.1",
52
46
  "rollup": "^2.70.2",
53
47
  "rollup-plugin-cleanup": "^3.2.1",
54
48
  "rollup-plugin-dts": "^4.2.1",
55
49
  "rollup-plugin-terser": "^7.0.2",
56
- "ts-node": "^10.9.1",
57
- "tsconfig-paths": "^4.1.1",
58
50
  "typedoc": "^0.23.14",
59
51
  "typedoc-plugin-mermaid": "^1.10.0",
60
- "typescript": "^4.1.2",
61
- "yarn-deduplicate": "^6.0.2"
52
+ "typescript": "^5.4.0"
62
53
  }
63
54
  }
@@ -0,0 +1,22 @@
1
+ import {UInt16, UInt32} from '@wharfkit/antelope'
2
+ import {CRAFT_ENERGY_DIVISOR} from '../types'
3
+ import type {EntityCapabilities} from '../types/capabilities'
4
+ import type {ServerContract} from '../contracts'
5
+
6
+ export interface CrafterCapability {
7
+ crafter: ServerContract.Types.crafter_stats
8
+ }
9
+
10
+ export function capsHasCrafter(caps: EntityCapabilities): boolean {
11
+ return caps.crafter !== undefined
12
+ }
13
+
14
+ export function calc_craft_duration(speed: number, totalInputMass: number): UInt32 {
15
+ const duration = Math.floor(totalInputMass / speed)
16
+ return UInt32.from(Math.max(duration, 1))
17
+ }
18
+
19
+ export function calc_craft_energy(drain: number, totalInputMass: number): UInt16 {
20
+ const raw = Math.floor((totalInputMass * drain) / CRAFT_ENERGY_DIVISOR)
21
+ return UInt16.from(Math.min(raw, 65535))
22
+ }
@@ -0,0 +1,36 @@
1
+ import {UInt16, UInt32} from '@wharfkit/antelope'
2
+ import type {ServerContract} from '../contracts'
3
+ import {PRECISION} from '../types'
4
+
5
+ const GATHER_TIME_SCALE = 100
6
+ const DEPTH_PENALTY_DIVISOR = 5000
7
+ const SPEED_TIME_SCALE = 300
8
+
9
+ export function calc_gather_duration(
10
+ gatherer: ServerContract.Types.gatherer_stats,
11
+ itemMass: number,
12
+ quantity: number,
13
+ stratum: number,
14
+ richness: number
15
+ ): UInt32 {
16
+ const yieldValue = gatherer.yield.toNumber()
17
+ const speed = gatherer.speed.toNumber()
18
+
19
+ if (yieldValue === 0 || speed === 0 || richness === 0) return UInt32.from(0)
20
+
21
+ const massFactor = Math.sqrt(itemMass)
22
+ const depthPenalty = 1 + stratum / DEPTH_PENALTY_DIVISOR
23
+ const richnessMul = richness / 1000
24
+ const gatherTime =
25
+ (quantity * massFactor * GATHER_TIME_SCALE * depthPenalty) / (yieldValue * richnessMul)
26
+ const speedTime = SPEED_TIME_SCALE * Math.log(1 + stratum / speed)
27
+ return UInt32.from(Math.floor(gatherTime + speedTime))
28
+ }
29
+
30
+ export function calc_gather_energy(
31
+ gatherer: ServerContract.Types.gatherer_stats,
32
+ duration: number
33
+ ): UInt16 {
34
+ const energy = Math.floor((duration * gatherer.drain.toNumber()) / PRECISION)
35
+ return UInt16.from(energy)
36
+ }
@@ -0,0 +1,38 @@
1
+ import type {
2
+ EnergyCapability,
3
+ GathererCapability,
4
+ LoaderCapability,
5
+ MassCapability,
6
+ MovementCapability,
7
+ ScheduleCapability,
8
+ StorageCapability,
9
+ } from '../types/capabilities'
10
+ import type {Entity} from '../types/entity'
11
+
12
+ export function canMove(e: Entity): e is Entity & MovementCapability & EnergyCapability {
13
+ return 'engines' in e && 'generator' in e && 'energy' in e
14
+ }
15
+
16
+ export function hasEnergy(e: Entity): e is Entity & EnergyCapability {
17
+ return 'energy' in e
18
+ }
19
+
20
+ export function hasStorage(e: Entity): e is Entity & StorageCapability {
21
+ return 'capacity' in e && 'cargo' in e
22
+ }
23
+
24
+ export function hasLoaders(e: Entity): e is Entity & LoaderCapability {
25
+ return 'loaders' in e && e.loaders !== undefined
26
+ }
27
+
28
+ export function hasMass(e: Entity): e is Entity & MassCapability {
29
+ return 'hullmass' in e
30
+ }
31
+
32
+ export function hasSchedule(e: Entity): e is Entity & ScheduleCapability {
33
+ return 'schedule' in e
34
+ }
35
+
36
+ export function hasGatherer(e: Entity): e is Entity & GathererCapability {
37
+ return 'gatherer' in e && e.gatherer !== undefined
38
+ }
@@ -0,0 +1,22 @@
1
+ const BASE_HAUL_PENALTY_MILLI = 300
2
+ const HAULER_EFFICIENCY_DENOM = 10000
3
+ const PRECISION = 10000
4
+
5
+ export function computeHaulPenalty(
6
+ totalThrust: number,
7
+ haulCount: number,
8
+ avgEfficiency: number
9
+ ): number {
10
+ if (haulCount === 0) return totalThrust
11
+ const penaltyMilli =
12
+ 1000 +
13
+ Math.floor(
14
+ (haulCount * BASE_HAUL_PENALTY_MILLI * (HAULER_EFFICIENCY_DENOM - avgEfficiency)) /
15
+ HAULER_EFFICIENCY_DENOM
16
+ )
17
+ return Math.floor((totalThrust * 1000) / penaltyMilli)
18
+ }
19
+
20
+ export function computeHaulerDrain(distance: number, drain: number, haulCount: number): number {
21
+ return Math.floor(distance / PRECISION) * drain * haulCount
22
+ }
@@ -0,0 +1,8 @@
1
+ export * from './guards'
2
+ export * from './movement'
3
+ export * from './storage'
4
+ export * from './loading'
5
+ export * from './gathering'
6
+ export * from './crafting'
7
+ export * from './modules'
8
+ export * from './hauling'
@@ -0,0 +1,8 @@
1
+ import {UInt32, type UInt64} from '@wharfkit/antelope'
2
+ import type {LoaderCapability} from '../types/capabilities'
3
+
4
+ export function calcLoadDuration(entity: LoaderCapability, cargoMass: UInt64): UInt32 {
5
+ const totalThrust = entity.loaders.thrust.toNumber() * entity.loaders.quantity.toNumber()
6
+ if (totalThrust === 0) return UInt32.from(0)
7
+ return UInt32.from(Math.ceil(Number(cargoMass) / totalThrust))
8
+ }
@@ -0,0 +1,86 @@
1
+ import {
2
+ ITEM_CRAFTER_T1,
3
+ ITEM_ENGINE_T1,
4
+ ITEM_GATHERER_T1,
5
+ ITEM_GENERATOR_T1,
6
+ ITEM_HAULER_T1,
7
+ ITEM_LOADER_T1,
8
+ ITEM_STORAGE_T1,
9
+ } from '../data/item-ids'
10
+
11
+ export const MODULE_ANY = 0
12
+ export const MODULE_ENGINE = 1
13
+ export const MODULE_GENERATOR = 2
14
+ export const MODULE_GATHERER = 3
15
+ export const MODULE_LOADER = 4
16
+ export const MODULE_WARP = 5
17
+ export const MODULE_CRAFTER = 6
18
+ export const MODULE_LAUNCHER = 7
19
+ export const MODULE_STORAGE = 8
20
+ export const MODULE_HAULER = 9
21
+
22
+ export interface PackedModule {
23
+ itemId: number
24
+ stats: bigint
25
+ }
26
+
27
+ export interface ModuleEntry {
28
+ type: number
29
+ installed?: PackedModule
30
+ }
31
+
32
+ export function moduleAccepts(slotType: number, moduleType: number): boolean {
33
+ return slotType === MODULE_ANY || slotType === moduleType
34
+ }
35
+
36
+ export function getModuleCapabilityType(itemId: number): number {
37
+ switch (itemId) {
38
+ case ITEM_ENGINE_T1:
39
+ return MODULE_ENGINE
40
+ case ITEM_GENERATOR_T1:
41
+ return MODULE_GENERATOR
42
+ case ITEM_GATHERER_T1:
43
+ return MODULE_GATHERER
44
+ case ITEM_LOADER_T1:
45
+ return MODULE_LOADER
46
+ case ITEM_CRAFTER_T1:
47
+ return MODULE_CRAFTER
48
+ case ITEM_STORAGE_T1:
49
+ return MODULE_STORAGE
50
+ case ITEM_HAULER_T1:
51
+ return MODULE_HAULER
52
+ default:
53
+ return 0xff
54
+ }
55
+ }
56
+
57
+ export function isModuleItem(itemId: number): boolean {
58
+ return getModuleCapabilityType(itemId) !== 0xff
59
+ }
60
+
61
+ export function moduleSlotTypeToCode(slotType: string): number {
62
+ switch (slotType) {
63
+ case 'any':
64
+ return MODULE_ANY
65
+ case 'engine':
66
+ return MODULE_ENGINE
67
+ case 'generator':
68
+ return MODULE_GENERATOR
69
+ case 'gatherer':
70
+ return MODULE_GATHERER
71
+ case 'loader':
72
+ return MODULE_LOADER
73
+ case 'warp':
74
+ return MODULE_WARP
75
+ case 'crafter':
76
+ return MODULE_CRAFTER
77
+ case 'launcher':
78
+ return MODULE_LAUNCHER
79
+ case 'storage':
80
+ return MODULE_STORAGE
81
+ case 'hauler':
82
+ return MODULE_HAULER
83
+ default:
84
+ return MODULE_ANY
85
+ }
86
+ }
@@ -0,0 +1,29 @@
1
+ import {UInt32, UInt64} from '@wharfkit/antelope'
2
+ import type {EnergyCapability, MovementCapability} from '../types/capabilities'
3
+ import {PRECISION} from '../types'
4
+
5
+ export function maxTravelDistance(entity: MovementCapability): UInt32 {
6
+ return UInt32.from(entity.generator.capacity)
7
+ .dividing(entity.engines.drain)
8
+ .multiplying(PRECISION)
9
+ }
10
+
11
+ export function calcEnergyUsage(entity: MovementCapability, distance: UInt64): UInt64 {
12
+ return distance.dividing(PRECISION).multiplying(entity.engines.drain)
13
+ }
14
+
15
+ export function hasEnergyForDistance(
16
+ entity: MovementCapability & EnergyCapability,
17
+ distance: UInt64
18
+ ): boolean {
19
+ const usage = calcEnergyUsage(entity, distance)
20
+ return UInt64.from(entity.energy).gte(usage)
21
+ }
22
+
23
+ export function energyPercent(entity: MovementCapability & EnergyCapability): number {
24
+ return (Number(entity.energy) / Number(entity.generator.capacity)) * 100
25
+ }
26
+
27
+ export function needsRecharge(entity: MovementCapability & EnergyCapability): boolean {
28
+ return UInt64.from(entity.energy).lt(entity.generator.capacity)
29
+ }
@@ -0,0 +1,159 @@
1
+ import {UInt16, UInt32, UInt64, type UInt64Type} from '@wharfkit/antelope'
2
+ import {ServerContract} from '../contracts'
3
+ import type {StorageCapability} from '../types/capabilities'
4
+ import {getItem} from '../data/catalog'
5
+ import {INSUFFICIENT_ITEM_QUANTITY} from '../errors'
6
+
7
+ export interface HasCargo {
8
+ cargo: ServerContract.Types.cargo_item[]
9
+ }
10
+
11
+ export interface HasCapacity {
12
+ capacity: UInt32
13
+ }
14
+
15
+ export interface HasCargomass {
16
+ cargomass: UInt32
17
+ }
18
+
19
+ interface MassInput {
20
+ item_id: UInt16
21
+ quantity: UInt32
22
+ modules: ServerContract.Types.module_entry[]
23
+ }
24
+
25
+ export function calcCargoItemMass(item: MassInput): UInt64 {
26
+ const itemDef = getItem(item.item_id)
27
+ let mass = UInt64.from(itemDef.mass).multiplying(item.quantity)
28
+
29
+ for (const mod of item.modules) {
30
+ if (mod.installed) {
31
+ const modDef = getItem(mod.installed.item_id)
32
+ mass = mass.adding(UInt64.from(modDef.mass))
33
+ }
34
+ }
35
+
36
+ return mass
37
+ }
38
+
39
+ export function calcCargoMass(entity: HasCargo): UInt64 {
40
+ let mass = UInt64.from(0)
41
+ for (const item of entity.cargo) {
42
+ mass = mass.adding(calcCargoItemMass(item))
43
+ }
44
+ return mass
45
+ }
46
+
47
+ export function calcStacksMass(stacks: CargoStack[]): UInt64 {
48
+ let mass = UInt64.from(0)
49
+ for (const s of stacks) {
50
+ mass = mass.adding(calcCargoItemMass(s))
51
+ }
52
+ return mass
53
+ }
54
+
55
+ export function availableCapacity(entity: StorageCapability): UInt64 {
56
+ const cargoMass = calcCargoMass(entity)
57
+ return entity.capacity.gt(cargoMass)
58
+ ? UInt64.from(entity.capacity).subtracting(cargoMass)
59
+ : UInt64.from(0)
60
+ }
61
+
62
+ export function availableCapacityFromMass(capacity: UInt64Type, cargoMass: UInt64Type): UInt64 {
63
+ const cap = UInt64.from(capacity)
64
+ const mass = UInt64.from(cargoMass)
65
+ return cap.gt(mass) ? cap.subtracting(mass) : UInt64.from(0)
66
+ }
67
+
68
+ export function hasSpace(entity: StorageCapability, goodMass: UInt64, quantity: number): boolean {
69
+ const additional = goodMass.multiplying(quantity)
70
+ return availableCapacity(entity).gte(additional)
71
+ }
72
+
73
+ export function hasSpaceForMass(
74
+ capacity: UInt64Type,
75
+ currentMass: UInt64Type,
76
+ additionalMass: UInt64Type
77
+ ): boolean {
78
+ return UInt64.from(currentMass).adding(additionalMass).lte(capacity)
79
+ }
80
+
81
+ export function isFull(entity: HasCapacity & HasCargomass): boolean {
82
+ return UInt64.from(entity.cargomass).gte(entity.capacity)
83
+ }
84
+
85
+ export function isFullFromMass(capacity: UInt64Type, cargoMass: UInt64Type): boolean {
86
+ return UInt64.from(cargoMass).gte(capacity)
87
+ }
88
+
89
+ export interface CargoStack {
90
+ item_id: UInt16
91
+ quantity: UInt32
92
+ stats: UInt64
93
+ modules: ServerContract.Types.module_entry[]
94
+ }
95
+
96
+ export function cargoItemToStack(item: ServerContract.Types.cargo_item): CargoStack {
97
+ return {
98
+ item_id: UInt16.from(item.item_id),
99
+ quantity: UInt32.from(item.quantity),
100
+ stats: item.stats,
101
+ modules: item.modules ?? [],
102
+ }
103
+ }
104
+
105
+ export function stackToCargoItem(stack: CargoStack): ServerContract.Types.cargo_item {
106
+ return ServerContract.Types.cargo_item.from({
107
+ item_id: stack.item_id,
108
+ quantity: stack.quantity,
109
+ stats: stack.stats,
110
+ modules: stack.modules,
111
+ })
112
+ }
113
+
114
+ function statsEquals(a: UInt64, b: UInt64): boolean {
115
+ return a.equals(b)
116
+ }
117
+
118
+ function stackIdentityEqual(a: CargoStack, b: CargoStack): boolean {
119
+ return a.item_id.equals(b.item_id) && statsEquals(a.stats, b.stats)
120
+ }
121
+
122
+ export function stackKey(s: CargoStack): string {
123
+ return `${s.item_id.toNumber()}:${s.stats.toString()}`
124
+ }
125
+
126
+ export function stacksEqual(a: CargoStack, b: CargoStack): boolean {
127
+ return stackIdentityEqual(a, b) && a.quantity.equals(b.quantity)
128
+ }
129
+
130
+ export function mergeStacks(stacks: CargoStack[], add: CargoStack): CargoStack[] {
131
+ const idx = stacks.findIndex((s) => stackIdentityEqual(s, add))
132
+ if (idx === -1) {
133
+ return [...stacks, {...add}]
134
+ }
135
+ const result = stacks.slice()
136
+ result[idx] = {
137
+ ...result[idx],
138
+ quantity: UInt32.from(result[idx].quantity.adding(add.quantity)),
139
+ }
140
+ return result
141
+ }
142
+
143
+ export function removeFromStacks(stacks: CargoStack[], remove: CargoStack): CargoStack[] {
144
+ const idx = stacks.findIndex((s) => stackIdentityEqual(s, remove))
145
+ if (idx === -1) {
146
+ throw new Error(INSUFFICIENT_ITEM_QUANTITY)
147
+ }
148
+ const target = stacks[idx]
149
+ if (target.quantity.lt(remove.quantity)) {
150
+ throw new Error(INSUFFICIENT_ITEM_QUANTITY)
151
+ }
152
+ const remaining = UInt32.from(target.quantity.subtracting(remove.quantity))
153
+ if (remaining.equals(UInt32.from(0))) {
154
+ return [...stacks.slice(0, idx), ...stacks.slice(idx + 1)]
155
+ }
156
+ const result = stacks.slice()
157
+ result[idx] = {...target, quantity: remaining}
158
+ return result
159
+ }