@adatechnology/game-items 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +83 -2
- package/dist/index.d.ts +755 -0
- package/dist/index.global.js +790 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +737 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anderson Fernandes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,84 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @adatechnology/game-items
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Engine-agnostic item catalog engine. It defines what an item is (category, real size in metres, weight in kg, rarity, durability, shelf life, nutrition,
|
|
4
|
+
protection, carry capacity, weapon link, where it is found), a registry that games extend and patch, and the default rules for finds, freshness, storage,
|
|
5
|
+
carry weight and clothing protection. It has no content (the catalog lives in `@adatechnology/game-items-goods`) and no renderer (3D lives in
|
|
6
|
+
`@adatechnology/game-items-three`), and it knows nothing about any game.
|
|
7
|
+
|
|
8
|
+
> Status: engine complete (T3.1a and T3.1e of spec 001): registry, rules, lazy aging, carry, protection, use effects, recipes, finds and the arsenal bridge. Everything is pure; the host keeps the state.
|
|
9
|
+
|
|
10
|
+
Units: metres, kilograms, litres, days.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pnpm add @adatechnology/game-items
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
A plain `<script src=".../dist/index.global.js">` exposes the `GameItems` global.
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { createItems } from '@adatechnology/game-items'
|
|
24
|
+
import type { ItemDef } from '@adatechnology/game-items'
|
|
25
|
+
|
|
26
|
+
const beans: ItemDef = { id: 'canned_beans', category: 'food', size: [0.075, 0.11, 0.075], weight: 0.43, rarity: 'common', shelfLife: 1460, portions: 2 }
|
|
27
|
+
|
|
28
|
+
const items = createItems({
|
|
29
|
+
packs: [{ id: 'mine', items: [beans], places: [{ id: 'house' }] }],
|
|
30
|
+
patch: { canned_beans: { weight: 0.45 } }, // field by field; arrays replace
|
|
31
|
+
rules: { carry: { baseKg: 10 } }, // merged over DEFAULT_RULES
|
|
32
|
+
})
|
|
33
|
+
items.get('canned_beans').volume // 0.928 L, derived from size
|
|
34
|
+
items.byCategory('food')
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Order: packs (a later item with the same id replaces), `patch`, `remove`, `include`. Every inconsistency (unknown category, rarity or place, invalid size,
|
|
38
|
+
weight, shelf life, protection, carry or rule) is reported in one error.
|
|
39
|
+
|
|
40
|
+
## Logic
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { createFindsProvider, freshness, blockChance, maxLoadKg, placeFinds } from '@adatechnology/game-items'
|
|
44
|
+
|
|
45
|
+
freshness(milk, { ageDays: 0, since: 0, storage: 'fridge', storedAt: 0 }, 20) // closes the account lazily, then 'fresh' | 'stale' | 'spoiled' | 'rotten'
|
|
46
|
+
blockChance(pieces, 'arms', 'bite') // 1 - PROD(1 - value x condition), capped at 90%
|
|
47
|
+
maxLoadKg(strength) // (8 + 2.5 x strength) x 1.2
|
|
48
|
+
const stacks = createFindsProvider(items).findsFor({ place: 'house', container: 'fridge', state: 'fortified', rng, day: 12 })
|
|
49
|
+
const { contents, leftover } = placeFinds(stacks, slots, items) // the floorplan's `contents`
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **Aging is lazy.** Nothing ticks: `advanceAge` closes `ageDays += (now - since) x multiplier` when an item moves or is looked at. Fridge and freezer need power (the host passes
|
|
53
|
+
`powered`); a freezer without power makes the food fresh with 2 days to go; a cooler ages at x0.5 for its first 2 days; batteries lose 10% of charge per month; gasoline past 180 days fails 10% of the starts.
|
|
54
|
+
- **Finds are two ports behind one provider.** A container with an explicit pool (the 3D viewer's `sorteiaConteudo`: count by footprint, weighted order, fortified x2.5 and +1 on supplies,
|
|
55
|
+
abandoned 40% empty plus junk) draws from it; any other draws like the game's `rollItems` (count range, category weights, rarity 60/28/9/2.5 among the items of the place). Both keep the
|
|
56
|
+
order of the random draws of their source; the stacks are chosen first and the state of each (age, condition, charge, fill) is drawn after. The count falls with the days of the outbreak
|
|
57
|
+
(`max(floor, 1 - perDay x days)`, none on day 0) and can be scaled by region.
|
|
58
|
+
- **The provider is the floorplan's `FindsProvider` by shape** (`findsFor(query) -> FindStack[]`); this package does not import `game-floorplan`.
|
|
59
|
+
- **The arsenal becomes items:** `itemsFromArsenal(arsenal, { records })` makes `ammo_<caliber>`, `firearm_<id>` and `throwable_<id>`; the game's boxes (`records`) give rounds, weight and rarity, the rest is estimated.
|
|
60
|
+
- Packs also carry `pools` (what a kind of furniture holds), `poolAliases`, `useEffects` and `recipes`; `resolveUse`, `canCraft` and `craft` read them and leave applying the result to the host.
|
|
61
|
+
|
|
62
|
+
## API
|
|
63
|
+
|
|
64
|
+
| Name | What it is |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `createItems(options?)` | `ItemsCatalog`: maps `items`, `categories`, `places`, `containers`, `pools`, `recipes`, `useEffects`, `rules`; `has`, `get` (throws on unknown), `list`, `byCategory`, `byPlace`, `byTag` |
|
|
67
|
+
| `ItemDef` | extends the interactables `ItemDef`; fields in `src/types.ts` |
|
|
68
|
+
| `ITEM_CATEGORIES` | the 14 categories (`food`, `drink`, `medical`, `tools`, `melee`, `materials`, `clothing`, `bags`, `electronics`, `fuel`, `outdoors`, `books`, `collectibles`, `keys`); games add more with `categories` |
|
|
69
|
+
| `DEFAULT_RULES`, `ItemRules` | rarity weights 60/28/9/2.5/0.5 (legendary and unique only at fixed spots), freshness 0.5/1/1.5, storage multipliers, carry `(8 + 2.5 × strength) × 1.2` with 100% / 150%, protection cap 90%, wear -8 / -3, torn 25%, `aging`, `inventory`, `use` (past-its-best food), `spawn` (new shop stock, condition by rarity, age, charge, fill), `finds` (depletion by day, states, pool numbers) |
|
|
70
|
+
| `advanceAge`, `moveToStorage`, `storageMultiplier`, `freshness`, `shelfRatio`, `chargeLevel`, `failsToStart` | aging and decay |
|
|
71
|
+
| `blockChance`, `wearBlocked`, `repairPiece`, `pieceBlock` | layered clothing protection |
|
|
72
|
+
| `maxLoadKg`, `carriedKg`, `loadState`, `bagOption`, `canTake` | carry weight and slots |
|
|
73
|
+
| `resolveUse` | what using an item does, as data |
|
|
74
|
+
| `canCraft`, `craft` | recipes |
|
|
75
|
+
| `createFindsProvider`, `rollByCategory`, `rollExplicitPool`, `spawnData`, `depletionFactor`, `placeFinds`, `toLootTables` | finds |
|
|
76
|
+
| `itemsFromArsenal` | the arsenal as items |
|
|
77
|
+
| `checkItems(parts)` | the consistency check `createItems` runs |
|
|
78
|
+
| `RARITIES`, `BODY_SLOTS`, `DURABILITY_KINDS` | the closed vocabularies |
|
|
79
|
+
|
|
80
|
+
Places are a registry too: none ships, the pack or the game declares them; `finds.places` is checked only when at least one place is registered.
|
|
81
|
+
|
|
82
|
+
## Goldens against the team's code
|
|
83
|
+
|
|
84
|
+
`tests/team-golden.test.ts` compares the two ports with what the team's own code answers: `rollByCategory` with the game's `rollItems` (2400 cases) and `rollExplicitPool` with the 3D house viewer's `sorteiaConteudo` (1875 cases), same result and same number of random draws. The fixtures in `tests/fixtures/team-golden/` are recorded once by `pnpm --filter @adatechnology/game-items record:team-golden`, which cuts the functions out of the delivered sources and runs them in a `vm` with a seeded random stream.
|