@adatechnology/game-items 0.0.0-stage → 0.1.1
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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/create-items.ts","../src/categories.ts","../src/types.ts","../src/check-items.ts","../src/rules.ts","../src/decay.ts","../src/protection.ts","../src/carry.ts","../src/use-effect.ts","../src/recipes.ts","../src/finds/depletion.ts","../src/finds/rarity-pool.ts","../src/finds/category-roll.ts","../src/finds/explicit-pool.ts","../src/finds/provider.ts","../src/finds/spawn-state.ts","../src/finds/place-finds.ts","../src/finds/loot-tables.ts","../src/arsenal-items.ts"],"sourcesContent":["import { applyPatches, deepMerge, mergeById, removeIds } from '@adatechnology/game-contracts'\n\nimport { ITEM_CATEGORIES } from './categories'\nimport type { ItemsCatalog, ItemsOptions } from './catalog-types'\nimport { checkItems, findDuplicateIds } from './check-items'\nimport { DEFAULT_RULES } from './rules'\nimport type { RecipeDef } from './recipe-types'\nimport type { ContainerDef, ItemDef, PlaceDef, PoolEntry } from './types'\nimport type { UseEffectDef } from './use-types'\n\nconst LITRES_PER_CUBIC_METRE = 1000\n\n/** Fills what a pack leaves out: the volume comes from the size. */\nconst withDerivedFields = (item: ItemDef): ItemDef => (item.volume === undefined ? { ...item, volume: item.size[0] * item.size[1] * item.size[2] * LITRES_PER_CUBIC_METRE } : item)\n\nconst buildPools = (options: ItemsOptions, packs: NonNullable<ItemsOptions['packs']>): Map<string, readonly PoolEntry[]> => {\n const pools = new Map<string, readonly PoolEntry[]>()\n for (const source of [...packs, options]) for (const [key, entries] of Object.entries(source.pools ?? {})) pools.set(key, entries)\n const problems: string[] = []\n for (const source of [...packs, options]) {\n for (const [alias, key] of Object.entries(source.poolAliases ?? {})) {\n const entries = pools.get(key)\n if (entries) pools.set(alias, entries)\n else problems.push(`pool alias \"${alias}\" points to unknown pool \"${key}\"`)\n }\n }\n if (problems.length > 0) throw new Error(`game-items: the catalog is not consistent:\\n${problems.map((problem) => ` - ${problem}`).join('\\n')}`)\n return pools\n}\n\nconst groupBy = (items: Iterable<ItemDef>, keysOf: (item: ItemDef) => readonly string[]): Map<string, ItemDef[]> => {\n const groups = new Map<string, ItemDef[]>()\n for (const item of items) for (const key of keysOf(item)) groups.set(key, [...(groups.get(key) ?? []), item])\n return groups\n}\n\n/**\n * Create the catalog. Order: the packs in order (added or replaced by id), then `patch`, then `remove`, then `include`; categories, places and\n * containers are those of the packs plus the options, by id. Every inconsistency found is reported in one error.\n */\nexport const createItems = (options: ItemsOptions = {}): ItemsCatalog => {\n const packs = options.packs ?? []\n const items = mergeById([] as ItemDef[], packs.flatMap((pack) => pack.items))\n applyPatches<ItemDef>(items, options.patch)\n removeIds(items, options.remove)\n if (options.include) for (const [id, item] of items) if (!options.include(item)) items.delete(id)\n for (const [id, item] of items) items.set(id, withDerivedFields(item))\n\n const categories = mergeById(ITEM_CATEGORIES, [...packs.flatMap((pack) => pack.categories ?? []), ...(options.categories ?? [])])\n const places = mergeById<PlaceDef>([], [...packs.flatMap((pack) => pack.places ?? []), ...(options.places ?? [])])\n const containers = mergeById<ContainerDef>([], [...packs.flatMap((pack) => pack.containers ?? []), ...(options.containers ?? [])])\n const useEffects = [...mergeById<UseEffectDef>([], [...packs.flatMap((pack) => pack.useEffects ?? []), ...(options.useEffects ?? [])]).values()]\n const recipes = mergeById<RecipeDef>([], [...packs.flatMap((pack) => pack.recipes ?? []), ...(options.recipes ?? [])])\n const pools = buildPools(options, packs)\n const rules = deepMerge(DEFAULT_RULES, options.rules)\n\n const problems = [\n ...packs.flatMap((pack) => findDuplicateIds(`item in pack \"${pack.id}\"`, pack.items)),\n ...findDuplicateIds('category', options.categories),\n ...findDuplicateIds('place', options.places),\n ...findDuplicateIds('container', options.containers),\n ...findDuplicateIds('use effect', options.useEffects),\n ...findDuplicateIds('recipe', options.recipes),\n ...checkItems({ items, categories, places, containers, rules }),\n ]\n if (problems.length > 0) throw new Error(`game-items: the catalog is not consistent:\\n${problems.map((problem) => ` - ${problem}`).join('\\n')}`)\n\n const byCategory = groupBy(items.values(), (item) => [item.category])\n const byPlace = groupBy(items.values(), (item) => item.finds?.places ?? [])\n const byTag = groupBy(items.values(), (item) => item.tags ?? [])\n\n return {\n items,\n categories,\n places,\n containers,\n pools,\n useEffects,\n recipes,\n rules,\n has: (id) => items.has(id),\n get(id) {\n const item = items.get(id)\n if (!item) throw new Error(`game-items: unknown item \"${id}\"`)\n return item\n },\n list: () => [...items.values()],\n byCategory: (category) => [...(byCategory.get(category) ?? [])],\n byPlace: (place) => [...(byPlace.get(place) ?? [])],\n byTag: (tag) => [...(byTag.get(tag) ?? [])],\n }\n}\n","import type { CategoryDef } from './types'\n\n/** The 14 categories of the team's catalog; always registered. */\nexport const ITEM_CATEGORIES: readonly CategoryDef[] = [\n { id: 'food', name: 'Food' },\n { id: 'drink', name: 'Drink' },\n { id: 'medical', name: 'Medical' },\n { id: 'tools', name: 'Tools' },\n { id: 'melee', name: 'Melee' },\n { id: 'materials', name: 'Materials' },\n { id: 'clothing', name: 'Clothing' },\n { id: 'bags', name: 'Bags' },\n { id: 'electronics', name: 'Electronics' },\n { id: 'fuel', name: 'Fuel' },\n { id: 'outdoors', name: 'Outdoors' },\n { id: 'books', name: 'Books' },\n { id: 'collectibles', name: 'Collectibles' },\n { id: 'keys', name: 'Keys' },\n]\n","/**\n * Public types of @adatechnology/game-items.\n *\n * An `ItemDef` is a real-world thing (a can of beans, a hammer, a jacket) with its true size and weight; the rest of the fields are optional groups that\n * only the categories that need them fill (nutrition for food, protection for clothing, carry for bags). Units: metres, kilograms, litres, days.\n */\nimport type { BodySlot } from '@adatechnology/game-contracts'\nimport type { ItemDef as BaseItemDef } from '@adatechnology/game-interactables'\n\nimport type { RecipeDef } from './recipe-types'\nimport type { UseEffectDef } from './use-types'\n\nexport type { BaseItemDef }\n\nexport const RARITIES = ['common', 'uncommon', 'rare', 'very_rare', 'legendary', 'unique'] as const\nexport type Rarity = (typeof RARITIES)[number]\n\n/** The body slots an item covers: the vocabulary is `BodySlot` of game-contracts (`over` is a layer worn over the others, such as a coat or a vest). */\nexport type { BodySlot } from '@adatechnology/game-contracts'\nexport const BODY_SLOTS: readonly BodySlot[] = ['head', 'eyes', 'torso', 'arms', 'hands', 'legs', 'feet', 'over']\n\nexport const DURABILITY_KINDS = ['uses', 'portions', 'doses', 'hits', 'cuts', 'shots', 'condition', 'charges', 'seconds', 'days', 'infinite', 'container'] as const\nexport type DurabilityKind = (typeof DURABILITY_KINDS)[number]\n\n/** How long an item lasts, read from the source text (\"10 uses\", \"4 portions\", \"300 hits\", \"infinite\"). */\nexport interface Durability {\n kind: DurabilityKind\n amount?: number\n /** Source qualifier when the amount alone is not enough (for example the voltage of a battery). */\n per?: string\n}\n\n/** Id of a place where items turn up (house, hospital, farm...). Places are a registry: a pack or the game declares the ones it uses. */\nexport type PlaceTag = string\n\n/** Id of an item category. The 14 of `ITEM_CATEGORIES` are always present; a game adds its own through `createItems({ categories })`. */\nexport type ItemCategory = string\n\nexport interface CategoryDef {\n id: ItemCategory\n /** Display name in English; games translate by id. */\n name?: string\n}\n\nexport interface PlaceDef {\n id: PlaceTag\n name?: string\n}\n\n/**\n * Where items are found inside a place (a fridge, a drawer, a locker): which categories it draws from and how many stacks. The finds roll reads `count`,\n * `categories` (or `categoriesByPlace`, with `*` for any other place) and `places`; other fields of a pack's container are kept and ignored.\n */\nexport interface ContainerDef {\n id: string\n name?: string\n /** Places the container turns up in (`toLootTables` only); empty or missing means any. */\n places?: readonly PlaceTag[]\n /** Weight of each category when a stack is drawn for this container. */\n categories?: Readonly<Record<ItemCategory, number>>\n /** When `categories` is missing: the weights by place (a shop shelf stocks what the shop sells). */\n categoriesByPlace?: Readonly<Record<PlaceTag, Readonly<Record<ItemCategory, number>>>>\n /** Range of stacks a container holds when it is filled. */\n count?: readonly [number, number]\n}\n\n/** One thing an explicit pool can hold (a fridge: water bottle, milk, eggs...): `item` is the catalog id, `weight` the odds, `qty` the range. */\nexport interface PoolEntry {\n item: string\n weight: number\n qty: readonly [number, number]\n /** Supplies (food, water, medicine, tools) are what a fortified house stocks up on. */\n isSupply?: boolean\n}\n\nexport interface ItemDef extends BaseItemDef {\n category: ItemCategory\n /** The old household category (`kitchen`, `hygiene`, `office`...), `perishable` or `craft_only`. */\n tags?: readonly string[]\n rarity: Rarity\n /** Litres. Derived from `size` when the pack does not give it. */\n volume?: number\n durability?: Durability\n /** Days to spoil at room temperature. */\n shelfLife?: number\n portions?: number\n cookable?: boolean\n nutrition?: { satiety?: number; hydration?: number }\n /** Fractions 0..1 per attack, per body slot covered. */\n protection?: {\n slots: readonly BodySlot[]\n bite?: number\n scratch?: number\n warmth?: number\n /** Against projectiles (read by game-characters): `resistance` in penetration units; a stopped projectile does `blunt` of its damage, one that goes through `pass`. */\n ballistic?: { resistance: number; blunt?: number; pass?: number; consumable?: boolean }\n }\n carry?: { capacityKg: number; weightReduction: number; quickSlots: number; wheels?: boolean }\n /** Id of the weapon in the arsenal when the item is also one. */\n weapon?: string\n /** Id of the liquid (`game-fluids`) when the item holds one. */\n fluid?: { liquid: string; liters: number }\n uses?: readonly string[]\n finds?: { places: readonly PlaceTag[] }\n /** Battery-like items: share of the charge lost per month. */\n charge?: { lossPerMonth: number }\n /** Fuel-like items: after `afterDays` each use fails with probability `chance`. */\n agingFault?: { afterDays: number; chance: number }\n /** Key of the 3D model in `game-items-three`; without it a simple shape from `shape` is drawn. */\n model?: string\n}\n\n/** A bundle of content: items plus the categories, places and containers they rely on. */\nexport interface ItemPack {\n id: string\n items: readonly ItemDef[]\n categories?: readonly CategoryDef[]\n places?: readonly PlaceDef[]\n containers?: readonly ContainerDef[]\n /** What using an item does, in priority order (`resolveUse`). */\n useEffects?: readonly UseEffectDef[]\n recipes?: readonly RecipeDef[]\n /** Explicit pools of what a kind of furniture holds, by key (`fridge`, `sink`...); they win over the category roll of a container. */\n pools?: Readonly<Record<string, readonly PoolEntry[]>>\n /** Keys that share another key's pool (`garage_wardrobe` -> `wardrobe`). */\n poolAliases?: Readonly<Record<string, string>>\n}\n","import type { ItemRules } from './rules-types'\nimport type { CategoryDef, ContainerDef, ItemDef, PlaceDef } from './types'\nimport { BODY_SLOTS, DURABILITY_KINDS, RARITIES } from './types'\n\nexport interface ItemsParts {\n readonly items: ReadonlyMap<string, ItemDef>\n readonly categories: ReadonlyMap<string, CategoryDef>\n readonly places: ReadonlyMap<string, PlaceDef>\n readonly containers: ReadonlyMap<string, ContainerDef>\n readonly rules: ItemRules\n}\n\n/** Ids that appear more than once in a list a game passed in. */\nexport const findDuplicateIds = (kind: string, entries: readonly { readonly id: string }[] | undefined): string[] => {\n const seen = new Set<string>()\n const problems: string[] = []\n for (const { id } of entries ?? []) {\n if (seen.has(id)) problems.push(`${kind} \"${id}\" is listed more than once`)\n seen.add(id)\n }\n return problems\n}\n\nconst isFraction = (value: number | undefined): boolean => value === undefined || (value >= 0 && value <= 1)\nconst isPositive = (value: number): boolean => Number.isFinite(value) && value > 0\n\nconst checkItem = (item: ItemDef, { categories, places }: ItemsParts): string[] => {\n const problems: string[] = []\n const issue = (text: string): number => problems.push(`item \"${item.id}\" ${text}`)\n if (!categories.has(item.category)) issue(`has unknown category \"${item.category}\"`)\n if (!RARITIES.includes(item.rarity)) issue(`has unknown rarity \"${item.rarity}\"`)\n if (item.size.length !== 3 || !item.size.every(isPositive)) issue(`has an invalid size [${item.size.join(', ')}]`)\n if (!(item.weight >= 0) || !Number.isFinite(item.weight)) issue(`has a weight of ${item.weight} kg`)\n if (item.volume !== undefined && !isPositive(item.volume)) issue(`has a volume of ${item.volume} L`)\n if (item.shelfLife !== undefined && !isPositive(item.shelfLife)) issue(`has a shelf life of ${item.shelfLife} days`)\n if (item.portions !== undefined && !(Number.isInteger(item.portions) && item.portions > 0)) issue(`has ${item.portions} portions`)\n if (item.durability && !DURABILITY_KINDS.includes(item.durability.kind)) issue(`has unknown durability kind \"${item.durability.kind}\"`)\n const { protection } = item\n if (protection) {\n for (const slot of protection.slots) if (!BODY_SLOTS.includes(slot)) issue(`protects unknown body slot \"${slot}\"`)\n if (protection.slots.length === 0) issue('has protection but covers no body slot')\n if (![protection.bite, protection.scratch, protection.warmth].every(isFraction)) issue('has a protection value outside 0..1')\n }\n if (item.carry && !(item.carry.capacityKg > 0 && isFraction(item.carry.weightReduction))) issue('has an invalid carry (capacity above 0, reduction within 0..1)')\n if (places.size > 0) for (const place of item.finds?.places ?? []) if (!places.has(place)) issue(`is found in unknown place \"${place}\"`)\n return problems\n}\n\nconst checkContainer = (container: ContainerDef, { categories }: ItemsParts): string[] => {\n const problems: string[] = []\n for (const category of Object.keys(container.categories ?? {})) {\n if (!categories.has(category)) problems.push(`container \"${container.id}\" draws from unknown category \"${category}\"`)\n }\n const [low, high] = container.count ?? [0, 0]\n if (low < 0 || high < low) problems.push(`container \"${container.id}\" has an invalid count [${low}, ${high}]`)\n return problems\n}\n\nconst checkRules = ({ rarity, freshness, storage, carry, protection }: ItemRules): string[] => {\n const problems: string[] = []\n const hasNegativeWeight = RARITIES.some((id) => !(rarity.weights[id] >= 0))\n if (hasNegativeWeight || !RARITIES.some((id) => rarity.weights[id] > 0 && !rarity.fixedOnly.includes(id))) {\n problems.push('rules.rarity.weights must be non-negative with at least one rollable rarity above 0')\n }\n if (!(freshness.stale > 0 && freshness.stale < freshness.spoiled && freshness.spoiled < freshness.rotten)) problems.push('rules.freshness must rise: 0 < stale < spoiled < rotten')\n for (const [id, rule] of Object.entries(storage)) if (!isPositive(rule.multiplier) || (rule.limitDays !== undefined && !isPositive(rule.afterLimit ?? 0))) problems.push(`rules.storage \"${id}\" is invalid`)\n if (!(isPositive(carry.baseKg) && carry.perStrengthKg >= 0 && isPositive(carry.factor) && carry.encumbered > 0 && carry.overloaded > carry.encumbered)) problems.push('rules.carry is invalid')\n if (!(protection.cap > 0 && protection.cap <= 1 && isFraction(protection.tornShare))) problems.push('rules.protection is invalid')\n return problems\n}\n\n/** Every inconsistency of a catalog, one line each; empty when it is sound. */\nexport const checkItems = (parts: ItemsParts): string[] => [\n ...[...parts.items.values()].flatMap((item) => checkItem(item, parts)),\n ...[...parts.containers.values()].flatMap((container) => checkContainer(container, parts)),\n ...checkRules(parts.rules),\n]\n","import type { ItemRules } from './rules-types'\n\n/**\n * The numbers of the rules, from the team's Vale Cinzento delivery. `storage` was read by hand from its table (Validade e apodrecimento) so the\n * skeleton runs; the source test of the catalog tool proves it against the HTML (legendary and unique are never rolled: L276). Every field is an option of `createItems({ rules })`.\n */\nexport const DEFAULT_RULES: ItemRules = {\n rarity: {\n weights: { common: 60, uncommon: 28, rare: 9, very_rare: 2.5, legendary: 0.5, unique: 0 },\n fixedOnly: ['legendary', 'unique'],\n },\n freshness: { stale: 0.5, spoiled: 1, rotten: 1.5 },\n storage: {\n fridge: { multiplier: 0.33, needsPower: true },\n freezer: { multiplier: 0.1, needsPower: true },\n cooler: { multiplier: 0.5, limitDays: 2, afterLimit: 1 },\n delivery_bag: { multiplier: 0.8 },\n cellar: { multiplier: 0.66 },\n ambient: { multiplier: 1 },\n hot: { multiplier: 2 },\n },\n carry: { baseKg: 8, perStrengthKg: 2.5, factor: 1.2, encumbered: 1, overloaded: 1.5 },\n protection: { cap: 0.9, wear: { bite: 8, scratch: 3 }, tornShare: 0.25, repairMargin: 10 },\n aging: { thawShelfDays: { freezer: 2 } },\n inventory: { defaultSlots: 10, encumberedRunFactor: 0.75 },\n use: {\n freshness: {\n stale: { satietyFactor: 0.7, poisonChance: 0.1, morale: 0, isEdible: true },\n spoiled: { satietyFactor: 0.7, poisonChance: 0.5, morale: -20, isEdible: true },\n rotten: { satietyFactor: 0, poisonChance: 0, morale: 0, isEdible: false },\n },\n cookedPoisonFactor: 0.25,\n },\n spawn: {\n retailNew: true,\n retailPlaces: ['supermarket', 'pharmacy', 'mall', 'gas_station', 'gun_shop'],\n retailContainers: ['store_shelf', 'stockroom'],\n condition: { common: [30, 90], uncommon: [40, 90], rare: [50, 100], very_rare: [50, 100], legendary: [50, 100], unique: [50, 100] },\n ageShare: [0, 0.6],\n charge: [0.2, 1],\n fillable: ['fuel_jerrycan'],\n fill: [0, 0.6],\n },\n finds: {\n fallbackContainer: 'zombie_corpse',\n rollExcluded: ['ammo_7_62x39'],\n depletion: [\n { places: ['pharmacy', 'gun_shop', 'police_station'], perDay: 0.05, floor: 0.3 },\n { places: ['supermarket', 'gas_station'], perDay: 0.04, floor: 0.35 },\n { places: ['mall', 'hospital'], perDay: 0.025, floor: 0.5 },\n { places: ['house', 'apartment'], perDay: 0.01, floor: 0.7 },\n { places: ['farm', 'warehouse', 'mine', 'dam', 'lodge', 'church'], perDay: 0.005, floor: 0.85 },\n { places: ['military_base'], perDay: 0, floor: 1 },\n ],\n regionMultiplier: {},\n states: { normal: 'normal', fortified: 'fortified', abandoned: 'abandoned' },\n pool: {\n defaultFootprint: 0.5,\n offset: 1.5,\n perSquareMetre: 3,\n jitter: 1.5,\n min: 2,\n max: 5,\n fortifiedExtra: 2,\n supplyWeight: 2.5,\n supplyExtraQty: 1,\n abandonedEmptyChance: 0.4,\n abandonedKept: 1,\n junkChance: 0.5,\n junkItem: 'food_packaging',\n spoiledFoodItem: 'leftover_meal',\n coldContainers: ['geladeira', 'refrig_exp', 'freezer'],\n },\n },\n}\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules, StorageId } from './rules-types'\nimport type { ItemDef } from './types'\n\nexport type Freshness = 'fresh' | 'stale' | 'spoiled' | 'rotten'\n\n/**\n * What an item remembers about its age. Nothing ticks: the account is closed lazily, when the item moves or someone looks at it.\n * Times are in days on the host's clock.\n */\nexport interface AgeState {\n /** Effective age: days at room temperature. */\n ageDays: number\n /** Time at which `ageDays` was last closed. */\n since: number\n storage: StorageId\n /** Time at which the item entered `storage` (a cooler only helps for its first days). */\n storedAt: number\n /** Replaces the item's shelf life (a thawed freezer leaves 2 days). */\n shelfLife?: number\n}\n\nexport interface AgeOptions {\n /** Whether the storage has power right now (fridge, freezer). Default true. */\n powered?: boolean\n rules?: ItemRules\n}\n\nconst storageRuleOf = (rules: ItemRules, storage: StorageId) => {\n const rule = rules.storage[storage]\n if (!rule) throw new Error(`game-items: unknown storage \"${storage}\"`)\n return rule\n}\n\n/** The multiplier of the age at one instant: `heldDays` is how long the item has been in `storage`. */\nexport const storageMultiplier = (storage: StorageId, options: AgeOptions & { heldDays?: number } = {}): number => {\n const { powered = true, rules = DEFAULT_RULES, heldDays = 0 } = options\n const rule = storageRuleOf(rules, storage)\n if (rule.needsPower && !powered) return 1\n if (rule.limitDays !== undefined && heldDays >= rule.limitDays) return rule.afterLimit ?? 1\n return rule.multiplier\n}\n\n/** Days of effective age accrued between `from` and `to` in a storage the item entered at `storedAt`. */\nconst accruedDays = (storage: StorageId, window: { storedAt: number; from: number; to: number }, options: AgeOptions): number => {\n const { powered = true, rules = DEFAULT_RULES } = options\n const rule = storageRuleOf(rules, storage)\n const elapsed = window.to - window.from\n if (elapsed <= 0) return 0\n if (rule.needsPower && !powered) return elapsed\n if (rule.limitDays === undefined) return elapsed * rule.multiplier\n const limitEnd = window.storedAt + rule.limitDays\n const early = Math.max(0, Math.min(window.to, limitEnd) - Math.max(window.from, window.storedAt))\n return early * rule.multiplier + (elapsed - early) * (rule.afterLimit ?? 1)\n}\n\n/** Closes the account up to `now`: `ageDays += (now - since) x multiplier`. Pure: returns the new state. */\nexport const advanceAge = (state: AgeState, now: number, options: AgeOptions = {}): AgeState => {\n const { powered = true, rules = DEFAULT_RULES } = options\n const rule = storageRuleOf(rules, state.storage)\n const thawDays = rules.aging.thawShelfDays[state.storage]\n const isThawing = rule.needsPower === true && !powered && thawDays !== undefined && state.shelfLife === undefined\n const base = isThawing ? { ...state, ageDays: 0, shelfLife: thawDays } : state\n const ageDays = base.ageDays + accruedDays(state.storage, { storedAt: state.storedAt, from: state.since, to: now }, options)\n return { ...base, ageDays, since: Math.max(now, state.since) }\n}\n\n/** Moves the item to another storage: closes the account in the old one, then the new multiplier applies from `now`. */\nexport const moveToStorage = (state: AgeState, now: number, storage: StorageId, options: AgeOptions = {}): AgeState => ({\n ...advanceAge(state, now, options),\n storage,\n storedAt: now,\n})\n\n/** Age as a share of the shelf life; 0 for an item that does not spoil. */\nexport const shelfRatio = (item: ItemDef, state: AgeState): number => {\n const shelfLife = state.shelfLife ?? item.shelfLife\n return shelfLife === undefined ? 0 : state.ageDays / shelfLife\n}\n\n/** `fresh`, `stale`, `spoiled` or `rotten` at 0.5, 1 and 1.5 of the shelf life (the rule's `freshness`). Closes the account up to `now` first. */\nexport const freshness = (item: ItemDef, state: AgeState, now: number, options: AgeOptions = {}): Freshness => {\n const { rules = DEFAULT_RULES } = options\n const ratio = shelfRatio(item, advanceAge(state, now, options))\n if (ratio >= rules.freshness.rotten) return 'rotten'\n if (ratio >= rules.freshness.spoiled) return 'spoiled'\n if (ratio >= rules.freshness.stale) return 'stale'\n return 'fresh'\n}\n\n/** Charge left (0..1) of a battery-like item: it loses `charge.lossPerMonth` of the full charge per 30 days of effective age. */\nexport const chargeLevel = (item: ItemDef, initialCharge: number, ageDays: number): number => {\n if (!item.charge) return initialCharge\n return Math.max(0, initialCharge - item.charge.lossPerMonth * (ageDays / 30))\n}\n\n/** True when one use of an old fuel-like item fails: past `agingFault.afterDays` each use fails with probability `chance`. Draws once, only when it can fail. */\nexport const failsToStart = (item: ItemDef, ageDays: number, random: () => number): boolean => {\n if (!item.agingFault || ageDays <= item.agingFault.afterDays) return false\n return random() < item.agingFault.chance\n}\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { BodySlot, ItemDef } from './types'\n\nexport type AttackKind = 'bite' | 'scratch'\n\n/** A piece of clothing on a body: the item and its condition, 0 (torn) to 100 (new). */\nexport interface WornPiece {\n item: ItemDef\n condition: number\n}\n\nconst FULL_CONDITION = 100\n\nconst covers = (piece: WornPiece, slot: BodySlot): boolean => piece.item.protection?.slots.includes(slot) ?? false\n\n/** What one piece blocks of an attack: its value times its condition; a torn piece (condition 0) keeps `tornShare` of the value. */\nexport const pieceBlock = (piece: WornPiece, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): number => {\n const value = piece.item.protection?.[attack] ?? 0\n const share = piece.condition <= 0 ? rules.protection.tornShare : piece.condition / FULL_CONDITION\n return value * share\n}\n\n/** Share of an attack on `slot` that clothing blocks: `1 - PROD(1 - value x condition)`, never above the cap (there is always some risk). */\nexport const blockChance = (pieces: readonly WornPiece[], slot: BodySlot, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): number => {\n const unblocked = pieces.filter((piece) => covers(piece, slot)).reduce((product, piece) => product * (1 - pieceBlock(piece, attack, rules)), 1)\n return Math.min(rules.protection.cap, 1 - unblocked)\n}\n\n/** A blocked attack wears every piece that covers the slot and blocks something: bite -8, scratch -3 (never below 0). */\nexport const wearBlocked = (pieces: readonly WornPiece[], slot: BodySlot, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): WornPiece[] =>\n pieces.map((piece) => {\n if (!covers(piece, slot) || pieceBlock(piece, attack, rules) <= 0) return piece\n return { ...piece, condition: Math.max(0, piece.condition - rules.protection.wear[attack]) }\n })\n\n/** A repair kit restores up to the maximum condition minus the margin (10); a piece already better is left alone. */\nexport const repairPiece = (piece: WornPiece, rules: ItemRules = DEFAULT_RULES, maxCondition: number = FULL_CONDITION): WornPiece => ({\n ...piece,\n condition: Math.max(piece.condition, maxCondition - rules.protection.repairMargin),\n})\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { ItemDef } from './types'\n\nexport interface CarryEntry {\n item: ItemDef\n count: number\n}\n\nexport type LoadLevel = 'normal' | 'encumbered' | 'overloaded'\n\nexport interface LoadState {\n /** Load as a share of the maximum. */\n ratio: number\n level: LoadLevel\n /** Multiplier of running speed and breath. */\n runFactor: number\n canRun: boolean\n}\n\n/** What a character can carry, kg: `(8 + 2.5 x strength) x 1.2` with the default rules. */\nexport const maxLoadKg = (strength: number, rules: ItemRules = DEFAULT_RULES): number => (rules.carry.baseKg + rules.carry.perStrengthKg * strength) * rules.carry.factor\n\nconst sumKg = (entries: readonly CarryEntry[]): number => entries.reduce((total, entry) => total + entry.item.weight * entry.count, 0)\n\n/** Weight carried: what is outside the bag counts in full, what is inside counts times `(1 - weightReduction)`. */\nexport const carriedKg = (parts: { loose: readonly CarryEntry[]; packed?: readonly CarryEntry[]; weightReduction?: number }): number =>\n sumKg(parts.loose) + sumKg(parts.packed ?? []) * (1 - (parts.weightReduction ?? 0))\n\n/** Above 100% of the maximum, running and breath drop 25%; above 150% the character cannot run. */\nexport const loadState = (loadKg: number, maxKg: number, rules: ItemRules = DEFAULT_RULES): LoadState => {\n const ratio = maxKg > 0 ? loadKg / maxKg : Number.POSITIVE_INFINITY\n if (ratio > rules.carry.overloaded) return { ratio, level: 'overloaded', runFactor: 0, canRun: false }\n if (ratio > rules.carry.encumbered) return { ratio, level: 'encumbered', runFactor: rules.inventory.encumberedRunFactor, canRun: true }\n return { ratio, level: 'normal', runFactor: 1, canRun: true }\n}\n\n/** The bag of a character: how many item slots it has and how much it holds. */\nexport interface BagOption {\n slots: number\n capacityKg: number\n}\n\n/** The bag a bag item gives: its `carry.capacityKg` is the slot count the team's game reads from `cap`; the weight limit is the character's. */\nexport const bagOption = (bag: ItemDef | undefined, characterMaxKg: number, rules: ItemRules = DEFAULT_RULES): BagOption => ({\n slots: bag?.carry ? Math.round(bag.carry.capacityKg) : rules.inventory.defaultSlots,\n capacityKg: characterMaxKg,\n})\n\nexport type TakeResult = 'ok' | 'bag_full' | 'too_heavy'\n\n/** Whether `item` can go into the bag now: first the slots, then the weight. */\nexport const canTake = (item: ItemDef, bag: BagOption, used: { slots: number; loadKg: number }): TakeResult => {\n if (used.slots >= bag.slots) return 'bag_full'\n if (used.loadKg + item.weight > bag.capacityKg) return 'too_heavy'\n return 'ok'\n}\n","import type { Freshness } from './decay'\nimport { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { ItemDef } from './types'\nimport type { UseEffectDef } from './use-types'\n\nexport interface UseContext {\n /** State of the food, from `freshness()`. Default `fresh`. */\n freshness?: Freshness\n /** The food was cooked: it keeps only `cookedPoisonFactor` of its poison chance. */\n isCooked?: boolean\n}\n\nexport interface NutritionResult {\n satiety: number\n hydration: number\n morale: number\n poisonChance: number\n isEdible: boolean\n}\n\nexport interface UseResult {\n useId: string\n effect: string\n params: Readonly<Record<string, unknown>>\n /** The item is spent (false for food too rotten to eat). */\n consumes: boolean\n /** Only for `consume_nutrition`. */\n nutrition?: NutritionResult\n}\n\nconst FRESH_NUTRITION = { satietyFactor: 1, poisonChance: 0, morale: 0, isEdible: true }\n\nconst nutritionOf = (item: ItemDef, context: UseContext, rules: ItemRules): NutritionResult => {\n const state = context.freshness ?? 'fresh'\n const effect = state === 'fresh' ? FRESH_NUTRITION : rules.use.freshness[state]\n const poisonShare = context.isCooked ? rules.use.cookedPoisonFactor : 1\n return {\n satiety: (item.nutrition?.satiety ?? 0) * effect.satietyFactor,\n hydration: item.nutrition?.hydration ?? 0,\n morale: effect.morale,\n poisonChance: effect.poisonChance * poisonShare,\n isEdible: effect.isEdible,\n }\n}\n\nconst findEffect = (item: ItemDef, effects: readonly UseEffectDef[]): UseEffectDef | undefined =>\n effects.find((entry) => entry.items?.includes(item.id)) ?? effects.find((entry) => entry.category?.includes(item.category))\n\n/**\n * What using `item` does, as data: the host applies it (the player, the needs, the world). Pure. The first effect that lists the item wins, then the first\n * that lists its category; `undefined` when nothing happens. Food past its best follows `rules.use.freshness`.\n */\nexport const resolveUse = (item: ItemDef, effects: readonly UseEffectDef[], context: UseContext = {}, rules: ItemRules = DEFAULT_RULES): UseResult | undefined => {\n const def = findEffect(item, effects)\n if (!def) return undefined\n const base = { useId: def.id, effect: def.effect, params: def.params ?? {}, consumes: def.consumes }\n if (def.effect !== 'consume_nutrition') return base\n const nutrition = nutritionOf(item, context, rules)\n return { ...base, consumes: def.consumes && nutrition.isEdible, nutrition }\n}\n","import type { ItemsCatalog } from './catalog-types'\nimport type { RecipeDef, RecipeInput, RecipeOutput } from './recipe-types'\n\nexport interface CraftContext {\n catalog: ItemsCatalog\n /** Count of each item the character has, by id. */\n inventory: ReadonlyMap<string, number>\n /** Litres of each fluid at hand, by fluid id. */\n fluids?: Readonly<Record<string, number>>\n /** Stations and things of the world that are near (`fire`, `table`, `soil`). */\n world?: ReadonlySet<string>\n /** Skill levels by id. Without it the skill requirement is ignored. */\n skills?: Readonly<Record<string, number>>\n /** Ids unlocked so far. Without it `unlockedBy` is ignored. */\n unlocked?: ReadonlySet<string>\n}\n\nexport interface CraftCheck {\n isPossible: boolean\n /** One entry per unmet requirement: `item:nails`, `any:salt|sugar`, `match:cookable`, `fluid:water`, `world:fire`, `tool:hammer|axe`, `skill:carpentry:2`, `unlock:magazine`. */\n missing: string[]\n}\n\nexport type Consumption = { item: string; count: number; meters?: number } | { fluid: string; liters: number }\n\nexport type CraftOutcome = { item: string; count: number } | { effect: string; params: Readonly<Record<string, unknown>>; text?: string }\n\nexport type CraftResult = { isCrafted: true; seconds: number; consumed: Consumption[]; output: CraftOutcome } | { isCrafted: false; missing: string[] }\n\nconst countOf = (context: CraftContext, id: string): number => context.inventory.get(id) ?? 0\n\n/** Ids that satisfy an item input, in the order they are used. */\nconst candidatesOf = (input: RecipeInput, context: CraftContext): string[] => {\n if (input.item !== undefined) return [input.item]\n if (input.any) return [...input.any]\n if (!input.match) return []\n const { category, cookable } = input.match\n return context.catalog.list().filter((item) => (category === undefined || item.category === category) && (cookable === undefined || item.cookable === cookable)).map((item) => item.id)\n}\n\nconst describeInput = (input: RecipeInput): string => {\n if (input.item !== undefined) return `item:${input.item}`\n if (input.any) return `any:${input.any.join('|')}`\n if (input.match) return `match:${input.match.category ?? 'cookable'}`\n if (input.fluid !== undefined) return `fluid:${input.fluid}`\n return `world:${(input.world ?? []).join('|')}`\n}\n\n/** Takes `needed` units from the candidates in order; returns what was taken, or undefined when there is not enough. */\nconst takeUnits = (candidates: readonly string[], needed: number, context: CraftContext): Consumption[] | undefined => {\n const taken: Consumption[] = []\n let remaining = needed\n for (const id of candidates) {\n if (remaining <= 0) break\n const count = Math.min(remaining, countOf(context, id))\n if (count > 0) taken.push({ item: id, count })\n remaining -= count\n }\n return remaining > 0 ? undefined : taken\n}\n\nconst consumptionFor = (input: RecipeInput, context: CraftContext): Consumption[] | undefined => {\n if (input.world) return input.world.some((thing) => context.world?.has(thing)) ? [] : undefined\n if (input.fluid !== undefined) {\n const liters = input.liters ?? 1\n return (context.fluids?.[input.fluid] ?? 0) >= liters ? [{ fluid: input.fluid, liters }] : undefined\n }\n const taken = takeUnits(candidatesOf(input, context), input.qty ?? 1, context)\n if (!taken || input.meters === undefined) return taken\n return taken.map((entry) => ('item' in entry ? { ...entry, meters: input.meters as number } : entry))\n}\n\nconst toolMissing = (recipe: RecipeDef, context: CraftContext): string[] =>\n recipe.tools.flatMap((tool) => {\n const missing: string[] = []\n if (tool.anyOf.length > 0 && !tool.anyOf.some((id) => countOf(context, id) > 0)) missing.push(`tool:${tool.anyOf.join('|')}`)\n if (tool.world && !tool.world.some((station) => context.world?.has(station))) missing.push(`world:${tool.world.join('|')}`)\n return missing\n })\n\nconst gateMissing = (recipe: RecipeDef, context: CraftContext): string[] => {\n const missing: string[] = []\n if (context.skills && recipe.skill && (context.skills[recipe.skill.id] ?? 0) < recipe.skill.level) missing.push(`skill:${recipe.skill.id}:${recipe.skill.level}`)\n if (context.unlocked && recipe.unlockedBy !== undefined && !context.unlocked.has(recipe.unlockedBy)) missing.push(`unlock:${recipe.unlockedBy}`)\n return missing\n}\n\n/** Whether the character can make the recipe now, and what is missing when not. Skill and `unlockedBy` are ignored when the host does not pass `skills` or `unlocked`. */\nexport const canCraft = (recipe: RecipeDef, context: CraftContext): CraftCheck => {\n const missing = [\n ...gateMissing(recipe, context),\n ...toolMissing(recipe, context),\n ...recipe.inputs.filter((input) => consumptionFor(input, context) === undefined).map(describeInput),\n ]\n return { isPossible: missing.length === 0, missing }\n}\n\nconst outcomeOf = (output: RecipeOutput, random: () => number): CraftOutcome => {\n if ('effect' in output) return { effect: output.effect, params: output.params, ...(output.text === undefined ? {} : { text: output.text }) }\n const [low, high] = output.qty\n return { item: output.item, count: low + Math.floor(random() * (high - low + 1)) }\n}\n\n/**\n * Makes the recipe: what is consumed and what comes out. Pure: the host takes the consumed things from its inventory and applies the output (an item is\n * added, an effect such as \"window with 200 life\" is the host's to handle). Draws one number only when the output quantity is a range.\n */\nexport const craft = (recipe: RecipeDef, context: CraftContext, random: () => number): CraftResult => {\n const check = canCraft(recipe, context)\n if (!check.isPossible) return { isCrafted: false, missing: check.missing }\n const consumed = recipe.inputs.flatMap((input) => consumptionFor(input, context) ?? [])\n return { isCrafted: true, seconds: recipe.seconds, consumed, output: outcomeOf(recipe.output, random) }\n}\n","import type { DepletionRule } from '../rules-types'\nimport type { ItemRules } from '../rules-types'\nimport type { PlaceTag } from '../types'\n\n/** Share of the normal stock a place still has `day` days into the outbreak: `max(floor, 1 - perDay x day)`; 1 on day 0 and where no rule names the place. */\nexport const depletionFactor = (place: PlaceTag, day: number, rules: ItemRules): number => {\n if (day <= 0) return 1\n const rule: DepletionRule | undefined = rules.finds.depletion.find((entry) => entry.places.includes(place))\n return rule ? Math.max(rule.floor, 1 - rule.perDay * day) : 1\n}\n\n/** The count of stacks after the days of the outbreak and the region: the roll is drawn first, so day 0 and an unknown region leave it as it was. */\nexport const scaleCount = (count: number, scale: { place: PlaceTag; day: number; region?: string }, rules: ItemRules): number => {\n const region = scale.region === undefined ? 1 : (rules.finds.regionMultiplier[scale.region] ?? 1)\n return Math.round(count * depletionFactor(scale.place, scale.day, rules) * region)\n}\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemCategory, ItemDef, PlaceTag } from '../types'\n\n/** The items of `category` a roll can draw in `place`: no fixed-spot rarity, nothing excluded; when none lists the place, every one of the category (the game's recuo). */\nexport const rollableItems = (catalog: ItemsCatalog, category: ItemCategory, place: PlaceTag): ItemDef[] => {\n const { rules } = catalog\n const rollable = catalog.byCategory(category).filter((item) => !rules.rarity.fixedOnly.includes(item.rarity) && !rules.finds.rollExcluded.includes(item.id))\n const here = rollable.filter((item) => item.finds?.places.includes(place))\n return here.length > 0 ? here : rollable\n}\n\nexport const rarityWeight = (catalog: ItemsCatalog, item: ItemDef): number => catalog.rules.rarity.weights[item.rarity]\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemCategory } from '../types'\n\nimport { scaleCount } from './depletion'\nimport { rarityWeight, rollableItems } from './rarity-pool'\nimport type { FindsQuery } from './types'\n\nconst pickCategory = (weights: Readonly<Record<ItemCategory, number>>, random: () => number): ItemCategory | undefined => {\n let remaining = random()\n const categories = Object.keys(weights)\n for (const category of categories) {\n remaining -= weights[category] as number\n if (remaining <= 0) return category\n }\n return categories[0]\n}\n\n/**\n * Port of the team game's `rollItems` (jogo.js L68796-68812) on the container table (`CONT_TAB`) and the rarity weights (`RAR_W`).\n *\n * Order of the random draws, the contract the golden test holds: one for the count; then for each stack one to pick the category, and (unless the category\n * has nothing to draw) one to pick the item among those of the place, by rarity weight. Nothing else draws. The count is scaled by the day and the region\n * after it is drawn, so day 0 gives exactly the game's rolls. Returns the item ids, one per stack.\n */\nexport const rollByCategory = (catalog: ItemsCatalog, query: FindsQuery): string[] => {\n const { rules } = catalog\n const table = catalog.containers.get(query.container) ?? catalog.containers.get(rules.finds.fallbackContainer)\n if (!table) return []\n const [low, high] = table.count ?? [0, 0]\n const drawn = low + Math.floor(query.rng() * (high - low + 1))\n const count = scaleCount(drawn, { place: query.place, day: query.day ?? 0, ...(query.region === undefined ? {} : { region: query.region }) }, rules)\n const weights = table.categories ?? table.categoriesByPlace?.[query.place] ?? table.categoriesByPlace?.['*']\n if (!weights) return []\n\n const picked: string[] = []\n for (let stack = 0; stack < count; stack++) {\n const category = pickCategory(weights, query.rng)\n const pool = category === undefined ? [] : rollableItems(catalog, category, query.place)\n if (pool.length === 0) continue\n const total = pool.reduce((sum, item) => sum + rarityWeight(catalog, item), 0)\n let remaining = query.rng() * total\n for (const item of pool) {\n remaining -= rarityWeight(catalog, item)\n if (remaining <= 0) {\n picked.push(item.id)\n break\n }\n }\n }\n return picked\n}\n","import type { ItemRules } from '../rules-types'\nimport type { FindState } from '../rules-types'\nimport type { PoolEntry } from '../types'\n\nimport type { FindsQuery } from './types'\n\nexport interface PoolPick {\n itemId: string\n count: number\n /** The pool entry it came from; none for the junk an abandoned container leaves. */\n entry?: PoolEntry\n}\n\ninterface Candidate {\n entry: PoolEntry\n weight: number\n}\n\n/** Draws without replacement by weight (the viewer's `ordemPonderada`): one draw per candidate, all of them, before anything is cut. */\nconst weightedOrder = (candidates: readonly Candidate[], random: () => number): Candidate[] => {\n const remaining = [...candidates]\n const ordered: Candidate[] = []\n while (remaining.length > 0) {\n const total = remaining.reduce((sum, candidate) => sum + candidate.weight, 0)\n let x = random() * total\n let index = 0\n for (; index < remaining.length - 1; index++) {\n x -= (remaining[index] as Candidate).weight\n if (x < 0) break\n }\n ordered.push(...remaining.splice(index, 1))\n }\n return ordered\n}\n\nconst countFor = (pool: readonly PoolEntry[], state: FindState, footprint: number, query: FindsQuery, rules: ItemRules): number => {\n const settings = rules.finds.pool\n const base = Math.max(settings.min, Math.min(settings.max, Math.round(settings.offset + footprint * settings.perSquareMetre + query.rng() * settings.jitter)))\n if (state === 'fortified') return Math.min(pool.length, base + settings.fortifiedExtra)\n if (state === 'abandoned') return query.rng() < settings.abandonedEmptyChance ? 0 : settings.abandonedKept\n return base\n}\n\n/**\n * Port of the 3D house viewer's `sorteiaConteudo` (visor-casas-3d.js L10837-10863) over a pool of what a kind of furniture holds.\n *\n * Order of the random draws, the contract the golden test holds: one for the count (`base`); for an abandoned container one more (empty or not); then a full\n * weighted order of the pool (one draw per entry, before the cut to the count); then one per kept entry for its quantity; and only for an abandoned and empty\n * container one last draw for the junk. Fortified: more entries, supplies weigh x2.5 and give +1. Abandoned: 40% empty, otherwise one entry, plus junk and,\n * in a fridge or freezer, spoiled food.\n */\nexport const rollExplicitPool = (pool: readonly PoolEntry[], state: FindState, query: FindsQuery, rules: ItemRules): PoolPick[] => {\n const settings = rules.finds.pool\n const n = countFor(pool, state, query.footprint ?? settings.defaultFootprint, query, rules)\n const isFortified = state === 'fortified'\n const candidates = pool.map((entry) => ({ entry, weight: isFortified && entry.isSupply ? entry.weight * settings.supplyWeight : entry.weight }))\n\n const picks: PoolPick[] = []\n for (const { entry } of weightedOrder(candidates, query.rng).slice(0, n)) {\n const [low, high] = entry.qty\n const bonus = isFortified && entry.isSupply ? settings.supplyExtraQty : 0\n picks.push({ itemId: entry.item, count: low + Math.floor(query.rng() * (high - low + 1)) + bonus, entry })\n }\n if (state === 'abandoned') {\n if (picks.length === 0 && query.rng() < settings.junkChance) picks.push({ itemId: settings.junkItem, count: 1 })\n if (settings.coldContainers.includes(query.container) || (query.key !== undefined && settings.coldContainers.includes(query.key))) picks.push({ itemId: settings.spoiledFoodItem, count: 1 })\n }\n return picks\n}\n","import { deepMerge } from '@adatechnology/game-contracts'\nimport type { DeepPartial } from '@adatechnology/game-contracts'\n\nimport type { ItemsCatalog } from '../catalog-types'\nimport type { ItemRules } from '../rules-types'\n\nimport { rollByCategory } from './category-roll'\nimport { rollExplicitPool } from './explicit-pool'\nimport { spawnData } from './spawn-state'\nimport type { FindStack, FindsProvider, FindsQuery } from './types'\n\nexport interface FindsProviderOptions {\n /** `team` (default): a container with an explicit pool in the catalog uses it; `none`: always the category roll. */\n pools?: 'team' | 'none'\n /** Changes to the `finds` and `spawn` rules for this provider. */\n rules?: DeepPartial<Pick<ItemRules, 'finds' | 'spawn'>>\n /** Names a host uses for a place, mapped to the place tags of the catalog (a floorplan `cabin` is a `lodge`). */\n placeAliases?: Readonly<Record<string, string>>\n /** Places where the explicit pools apply (the viewer's pools describe dwellings); the others use the category roll. Default: every place. */\n poolPlaces?: readonly string[]\n /** A container with neither a pool nor a table: `fallback` (default) uses the table of `rules.finds.fallbackContainer`, like the game; `pass` answers `null` so the host's own default applies. */\n unknownContainers?: 'fallback' | 'pass'\n}\n\n/**\n * What a container holds, as the floorplan's `FindsProvider` asks it. A container with an explicit pool (`query.key` or the container id) draws from it\n * (port of the viewer); otherwise the category roll of the game draws on the container table. Every stack is chosen first, in the order of the sources, and\n * only then each gets its state (age, condition, charge, fill) from the same generator. Items the catalog no longer has (removed by a game) are dropped\n * after the draws, so the others do not change.\n */\nexport function createFindsProvider(catalog: ItemsCatalog, options: FindsProviderOptions & { unknownContainers: 'pass' }): FindsProvider\nexport function createFindsProvider(catalog: ItemsCatalog, options?: FindsProviderOptions): { findsFor(query: FindsQuery): readonly FindStack[] }\nexport function createFindsProvider(catalog: ItemsCatalog, options: FindsProviderOptions = {}): FindsProvider {\n const rules = options.rules ? deepMerge(catalog.rules, options.rules) : catalog.rules\n const scoped: ItemsCatalog = rules === catalog.rules ? catalog : { ...catalog, rules }\n const usesPools = (options.pools ?? 'team') === 'team'\n\n const aliases = options.placeAliases ?? {}\n const poolPlaces = options.poolPlaces\n\n const passes = options.unknownContainers === 'pass'\n\n const choose = (query: FindsQuery): FindStack[] | null => {\n const pool = usesPools && (poolPlaces === undefined || poolPlaces.includes(query.place)) ? (scoped.pools.get(query.key ?? query.container) ?? scoped.pools.get(query.container)) : undefined\n if (!pool && passes && !scoped.containers.has(query.container)) return null\n if (!pool) return rollByCategory(scoped, query).map((itemId) => ({ itemId, count: 1 }))\n return rollExplicitPool(pool, rules.finds.states[query.state] ?? 'normal', query, rules).map(({ itemId, count }) => ({ itemId, count }))\n }\n\n return {\n findsFor(asked) {\n const query = aliases[asked.place] === undefined ? asked : { ...asked, place: aliases[asked.place] as string }\n const chosen = choose(query)\n if (chosen === null) return null\n return chosen\n .filter((stack) => scoped.has(stack.itemId))\n .map((stack) => {\n const data = spawnData(scoped.get(stack.itemId), query, scoped)\n return data ? { ...stack, data } : stack\n })\n },\n }\n}\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemDef } from '../types'\n\nimport type { FindData, FindsQuery } from './types'\n\nconst WEARING_DURABILITY = ['condition', 'hits', 'cuts']\n\nconst hasCondition = (item: ItemDef): boolean => item.protection !== undefined || item.weapon !== undefined || WEARING_DURABILITY.includes(item.durability?.kind ?? '')\n\nconst between = (range: readonly [number, number], random: () => number): number => range[0] + random() * (range[1] - range[0])\n\n/** Age of food when it turns up: the days since the outbreak plus 0 to 60% of the shelf life. On day 0 that is the normal turnover of the shelf. One draw. */\nexport const spawnAgeDays = (item: ItemDef, outbreakDays: number, random: () => number, catalog: ItemsCatalog): number | undefined =>\n item.shelfLife === undefined ? undefined : outbreakDays + between(catalog.rules.spawn.ageShare, random) * item.shelfLife\n\nconst isRetailStock = (query: FindsQuery, catalog: ItemsCatalog): boolean => {\n const { spawn } = catalog.rules\n const isRetail = spawn.retailNew && (query.day ?? 0) <= 0 && spawn.retailPlaces.includes(query.place)\n return isRetail && (spawn.retailContainers.length === 0 || spawn.retailContainers.includes(query.container))\n}\n\n/**\n * The state an item has when it turns up, drawn after all the stacks of a container were chosen (so the choice itself matches the sources): food age, condition\n * by rarity (100 for shop stock on day 0), battery charge and how full a jerrycan is. Draws in that order, only what applies.\n */\nexport const spawnData = (item: ItemDef, query: FindsQuery, catalog: ItemsCatalog): FindData | undefined => {\n const { spawn } = catalog.rules\n const data: { ageDays?: number; condition?: number; charge?: number; fill?: number } = {}\n const ageDays = spawnAgeDays(item, query.day ?? 0, query.rng, catalog)\n if (ageDays !== undefined) data.ageDays = ageDays\n if (hasCondition(item)) data.condition = isRetailStock(query, catalog) ? 100 : Math.round(between(spawn.condition[item.rarity], query.rng))\n if (item.charge) data.charge = between(spawn.charge, query.rng)\n if (spawn.fillable.includes(item.id)) data.fill = between(spawn.fill, query.rng)\n return Object.keys(data).length > 0 ? data : undefined\n}\n","import { fitsSize } from '@adatechnology/game-interactables'\nimport type { ItemStack, SlotSpec } from '@adatechnology/game-interactables'\n\nimport type { ItemsCatalog } from '../catalog-types'\n\nimport type { FindStack } from './types'\n\nexport interface PlacedFinds {\n /** One entry per slot, in the order of `slots`; null is empty. */\n contents: Array<ItemStack | null>\n /** Stacks that fit no free slot. */\n leftover: FindStack[]\n}\n\n/**\n * Puts the stacks in the slots of a container: each in the first free slot its item fits (`fitsSize`, width and depth may swap), a stack larger than the\n * item's `stack` splits over several slots. Pure and in order, so the same finds always land in the same slots. The result is the floorplan's `contents`.\n */\nexport const placeFinds = (stacks: readonly FindStack[], slots: readonly SlotSpec[], catalog: ItemsCatalog): PlacedFinds => {\n const contents: Array<ItemStack | null> = slots.map(() => null)\n const leftover: FindStack[] = []\n for (const stack of stacks) {\n const item = catalog.get(stack.itemId)\n const stackMax = item.stack ?? 1\n let remaining = stack.count\n while (remaining > 0) {\n const index = slots.findIndex((slot, position) => contents[position] === null && fitsSize(item.size, slot.max))\n if (index < 0) break\n const qty = Math.min(remaining, stackMax)\n contents[index] = { type: item.id, qty, ...(stack.data ? { data: { ...stack.data } } : {}) }\n remaining -= qty\n }\n if (remaining > 0) leftover.push({ ...stack, count: remaining })\n }\n return { contents, leftover }\n}\n","import type { LootTable, LootTables } from '@adatechnology/game-interactables'\n\nimport type { ItemsCatalog } from '../catalog-types'\nimport type { ContainerDef } from '../types'\n\nimport { depletionFactor } from './depletion'\nimport { rarityWeight, rollableItems } from './rarity-pool'\n\nexport interface LootTablesQuery {\n place: string\n /** Outbreak days; 0 is the normal world. */\n day?: number\n region?: string\n}\n\nconst weightsOf = (container: ContainerDef, place: string): Readonly<Record<string, number>> | undefined => container.categories ?? container.categoriesByPlace?.[place] ?? container.categoriesByPlace?.['*']\n\nconst tableFor = (catalog: ItemsCatalog, container: ContainerDef, query: LootTablesQuery): LootTable | undefined => {\n const weights = weightsOf(container, query.place)\n if (!weights) return undefined\n const entries = Object.entries(weights).flatMap(([category, categoryWeight]) => {\n const pool = rollableItems(catalog, category, query.place)\n const total = pool.reduce((sum, item) => sum + rarityWeight(catalog, item), 0)\n return total > 0 ? pool.map((item) => ({ type: item.id, weight: (categoryWeight * rarityWeight(catalog, item)) / total })) : []\n })\n const [low, high] = container.count ?? [0, 0]\n const region = query.region === undefined ? 1 : (catalog.rules.finds.regionMultiplier[query.region] ?? 1)\n const expected = ((low + high) / 2) * depletionFactor(query.place, query.day ?? 0, catalog.rules) * region\n return entries.length > 0 && high > 0 ? { fill: Math.min(1, expected / high), entries } : undefined\n}\n\n/**\n * The finds as the loot tables of `game-interactables`, for worlds that have no floorplan: one table per container of the place, named by the container id.\n * A table has one entry per rollable item, weighted by the container's category weight and the rarity (60/28/9/2.5). A slot is filled with probability\n * `fill` = expected count / most stacks, taking the container to have as many slots as its largest count; the day and the region scale the expected count.\n */\nexport const toLootTables = (catalog: ItemsCatalog, query: LootTablesQuery): LootTables => {\n const tables: LootTables = {}\n for (const container of catalog.containers.values()) {\n if (container.places && container.places.length > 0 && !container.places.includes(query.place)) continue\n const table = tableFor(catalog, container, query)\n if (table) tables[container.id] = table\n }\n return tables\n}\n","import type { CategoryDef, ItemDef, ItemPack, Rarity } from './types'\n\n/** The part of a weapon definition the bridge reads; `WeaponDef` of `@adatechnology/game-weapons` fits it without importing the package. */\nexport interface ArsenalWeaponLike {\n readonly id: string\n readonly mass: number\n readonly action: { readonly kind: string; readonly explosive?: string }\n readonly dimensions?: { readonly length: number }\n}\n\n/** The part of a calibre definition the bridge reads; `CaliberDef` fits it. */\nexport interface ArsenalCaliberLike {\n readonly id: string\n readonly bulletGrams: number\n readonly pellets?: number\n readonly caseType?: string\n readonly cartridge?: { readonly caseDiameter: number; readonly overallLength: number }\n}\n\n/** The part of an `Arsenal` the bridge reads. */\nexport interface ArsenalLike {\n readonly weapons: ReadonlyMap<string, ArsenalWeaponLike>\n readonly calibers: ReadonlyMap<string, ArsenalCaliberLike>\n}\n\n/** What the team's game says of a box or an arsenal item (`ammo-boxes.json`, from its `EXTRA` table); it wins over the estimates below. */\nexport interface ArsenalItemRecord {\n /** Id of the item; without it the bridge uses `ammo_<caliber>`, `firearm_<weapon>` or `throwable_<weapon>`. */\n id?: string\n kind: 'ammo_box' | 'firearm' | 'throwable'\n /** Calibre id of a box. */\n caliber?: string\n /** Weapon id of a firearm or throwable; for a throwable also the explosive it uses. */\n weapon?: string\n rounds?: number\n weight: number\n rarity: Rarity\n}\n\nexport interface ArsenalItemsOptions {\n records?: readonly ArsenalItemRecord[]\n}\n\nexport const ARSENAL_CATEGORIES: readonly CategoryDef[] = [\n { id: 'ammo', name: 'Ammo' },\n { id: 'firearms', name: 'Firearms' },\n { id: 'throwables', name: 'Throwables' },\n]\n\nconst MM = 0.001\nconst BOX_TARE_KG = 0.03\nconst BOX_WALL = 6 * MM\nconst ROUNDS_BY_CASE: Readonly<Record<string, number>> = { tiny: 50, pistol: 50, rifle: 20, shell: 25, big: 10 }\nconst DEFAULT_ROUNDS = 12\nconst CARTRIDGE_MASS_FACTOR = 2.3\nconst SHELL_MASS_FACTOR = 1.5\nconst BOX_DENSITY_KG_PER_M3 = 600\nconst THROWABLE_DENSITY_KG_PER_M3 = 1500\n\nconst cubeSide = (mass: number, density: number): number => Math.cbrt(mass / density)\n\n/** Estimates (REF) for a calibre the game has no box for: rounds by case type, mass of the rounds plus a tare, a box that packs them in a near-square tray. */\nconst estimateBox = (caliber: ArsenalCaliberLike): { rounds: number; weight: number; size: [number, number, number] } => {\n const rounds = ROUNDS_BY_CASE[caliber.caseType ?? ''] ?? DEFAULT_ROUNDS\n const factor = caliber.caseType === 'shell' ? SHELL_MASS_FACTOR : CARTRIDGE_MASS_FACTOR\n const weight = Number((rounds * caliber.bulletGrams * (caliber.pellets ?? 1) * factor * 0.001 + BOX_TARE_KG).toFixed(3))\n return { rounds, weight, size: boxSize(caliber, rounds, weight) }\n}\n\nconst boxSize = (caliber: ArsenalCaliberLike, rounds: number, weight: number): [number, number, number] => {\n if (!caliber.cartridge) {\n const side = cubeSide(weight, BOX_DENSITY_KG_PER_M3)\n return [side, side, side]\n }\n const rows = Math.ceil(Math.sqrt(rounds))\n const columns = Math.ceil(rounds / rows)\n const { caseDiameter, overallLength } = caliber.cartridge\n return [rows * caseDiameter * MM + BOX_WALL, overallLength * MM + BOX_WALL, columns * caseDiameter * MM + BOX_WALL]\n}\n\nconst ammoItem = (caliber: ArsenalCaliberLike, record: ArsenalItemRecord | undefined): ItemDef => {\n const estimate = estimateBox(caliber)\n const weight = record?.weight ?? estimate.weight\n return {\n id: record?.id ?? `ammo_${caliber.id}`,\n category: 'ammo',\n size: record?.weight === undefined ? estimate.size : boxSize(caliber, record.rounds ?? estimate.rounds, weight),\n weight,\n stack: 4,\n shape: 'box',\n rarity: record?.rarity ?? 'uncommon',\n }\n}\n\n/** A firearm's size from its length: height and thickness grow with it (a pistol 0.2 m is 0.10 x 0.03, a rifle 1 m is 0.20 x 0.05). Without a length, one from the mass. */\nconst firearmSize = (weapon: ArsenalWeaponLike): [number, number, number] => {\n const length = weapon.dimensions?.length ?? 0.15 + 0.2 * weapon.mass\n return [length, 0.08 + 0.12 * length, 0.02 + 0.03 * length]\n}\n\nconst weaponItem = (weapon: ArsenalWeaponLike, record: ArsenalItemRecord | undefined): ItemDef => {\n const isFirearm = weapon.action.kind === 'firearm'\n const side = cubeSide(weapon.mass, THROWABLE_DENSITY_KG_PER_M3)\n return {\n id: record?.id ?? `${isFirearm ? 'firearm' : 'throwable'}_${weapon.id}`,\n category: isFirearm ? 'firearms' : 'throwables',\n size: isFirearm ? firearmSize(weapon) : [side, side, side],\n weight: record?.weight ?? weapon.mass,\n stack: 1,\n shape: isFirearm ? 'long_tool' : 'jar',\n rarity: record?.rarity ?? 'unique',\n weapon: weapon.id,\n }\n}\n\nconst recordFor = (records: readonly ArsenalItemRecord[], match: (record: ArsenalItemRecord) => boolean): ArsenalItemRecord | undefined => records.find(match)\n\n/**\n * The arsenal as items, so a bag can carry it: a box `ammo_<caliber>` for every calibre, `firearm_<id>` for every firearm and `throwable_<id>` for every\n * throwable, with the mass and the real dimensions of the `WeaponDef` (`mass`, `dimensions.length`). A record from the team's game (`records`) gives the rounds\n * per box, the weight and the rarity of what it listed (9x19: 20 rounds, 0.24 kg); the rest are estimated from the calibre (REF): rounds by case type,\n * weight from the bullet. Returns a pack (with the `ammo`, `firearms` and `throwables` categories) for `createItems({ packs })`.\n */\nexport const itemsFromArsenal = (arsenal: ArsenalLike, options: ArsenalItemsOptions = {}): ItemPack => {\n const records = options.records ?? []\n const items: ItemDef[] = []\n for (const caliber of arsenal.calibers.values()) items.push(ammoItem(caliber, recordFor(records, (record) => record.kind === 'ammo_box' && record.caliber === caliber.id)))\n for (const weapon of arsenal.weapons.values()) {\n const kind = weapon.action.kind\n if (kind !== 'firearm' && kind !== 'throwable') continue\n items.push(weaponItem(weapon, recordFor(records, (record) => record.kind === kind && (record.weapon === weapon.id || record.weapon === weapon.action.explosive))))\n }\n return { id: 'arsenal', items, categories: ARSENAL_CATEGORIES }\n}\n"],"mappings":"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","names":["freshness","deepMerge","deepMerge"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,57 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adatechnology/game-items",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Engine-agnostic item catalog engine: item definitions (category, size, weight, rarity, durability, shelf life, protection, carry), an extensible registry with patch/remove/include, and the default rules for finds, freshness, storage, carry weight and protection. No content and no renderer.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"game",
|
|
8
|
+
"items",
|
|
9
|
+
"inventory",
|
|
10
|
+
"loot",
|
|
11
|
+
"catalog",
|
|
12
|
+
"survival"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/Andersonfrfilho/adatechnology-game-kit.git",
|
|
17
|
+
"directory": "packages/game-items"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "dist/index.js",
|
|
24
|
+
"module": "dist/index.js",
|
|
25
|
+
"types": "dist/index.d.ts",
|
|
26
|
+
"unpkg": "dist/index.global.js",
|
|
27
|
+
"jsdelivr": "dist/index.global.js",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./global": "./dist/index.global.js"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@adatechnology/game-contracts": "0.9.0",
|
|
41
|
+
"@adatechnology/game-interactables": "0.2.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.10.7",
|
|
45
|
+
"tsup": "^8.5.1",
|
|
46
|
+
"typescript": "^5.7.3",
|
|
47
|
+
"vitest": "^3.2.4",
|
|
48
|
+
"@adatechnology/game-weapons": "0.4.1",
|
|
49
|
+
"@adatechnology/golden-tool": "0.0.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsup",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"record:team-golden": "node scripts/record-team-golden.mjs"
|
|
56
|
+
}
|
|
6
57
|
}
|