TraderX_Tools/docs/source-format.md
2026-09-06 22:47:27 +03:00

211 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Source file format (`traderx_build.py`)
The source is a single YAML (or JSON – identical keys) file with four top-level sections.
Everything is optional except `categories`.
```yaml
defaults: # global defaults
groups: # named, reusable lists of class names
items: # products that are NOT shown in any category (attachments, variants…)
categories: # what the traders sell
```
Class names are matched case-insensitively. Product and category ids are derived from
names automatically (`AKM` → `prod_akm_001`, `Assault Rifles` → `cat_assault_rifles_001`)
and are stable across builds as long as the name doesn't change. Set `id:` explicitly
to keep an id from an existing config (the reverse-importer does this for you).
---
## `defaults`
| Key | Default | Meaning |
|---|---|---|
| `stock` | `unlimited` | `unlimited` or an integer max stock |
| `coefficient` | `1.0` | Dynamic price factor; only has an effect with a finite `stock` |
| `sell_percent` | `25` | Sell price as % of buy price when `sell` isn't given |
| `buy` | `full` | Item quantity on purchase – see *Quantity words* |
| `sell` | `full` | Required quantity on sale |
| `restart` | `keep` | Stock behaviour at server restart: `keep` / `reset` / `random` |
| `destock` | `0` | Fraction (0–1) of stock removed at every restart |
| `attachment_price` | `50` | Buy price for attachments/variants that are not defined anywhere else (auto-created hidden products) |
| `attachment_sell_percent` | `25` | Sell % for those auto-created products |
Every key except the two `attachment_*` ones can be overridden per category and per item.
Resolution order is **item → category → defaults**.
---
## `groups`
```yaml
groups:
ak_optics: [PSO1Optic, KobraOptic, SNAFU_AKKahles]
ak_muzzle: [AK_Suppressor, SNAFU_AK19Muzzel]
ak_full_kit: [ak_optics, ak_muzzle, Mag_AKM_30Rnd] # groups can contain groups
```
A group name can be used anywhere a list of class names is expected: `attachments`,
`variants`, preset contents. Duplicates are removed; recursion is detected.
---
## `items`
Products that exist but are not listed in any category. Typical use: attachments and
variants that you price explicitly rather than relying on `attachment_price`.
```yaml
items:
- SNAFU_AKKahles: {price: 800}
- PSO1Optic: {price: 300, sell: 60}
- AKM_Tan # all defaults, price -1 (unbuyable) – only useful as variant
```
---
## `categories`
```yaml
categories:
- name: Assault Rifles # required, shown in the trader UI
id: cat_assault_rifles_001 # optional, otherwise derived from name
traders: [Boris, 3] # givenName or npcId from TraderXGeneralSettings.json
licenses: [Weapons License] # license *names*; created if missing
visible: true # false hides the category (products still work as attachments)
icon: "" # image path for the category card
price: 1200 # default buy price for items below
stock / coefficient / sell_percent / buy / sell / restart / destock # category defaults
items: [...]
```
`traders` controls `categoriesId` in `TraderXGeneralSettings.json`. Every trader that is
named by at least one category gets its list rebuilt in source order; traders not named
anywhere are left untouched (with a warning).
---
## Items
Three spellings are accepted:
```yaml
items:
- AKM # bare class, all defaults
- AKM: {price: 1000, stock: 5} # class as key
- {class: AKM, price: 1000} # explicit key
```
Item options:
| Key | Meaning |
|---|---|
| `id` | Keep a specific product id (`prod_…_NNN`). |
| `price` | Buy price. `-1` = cannot be bought. Required somewhere (item, category or `price` in defaults is *not* a thing – an item without a resolvable price is an error). |
| `sell` | Sell price (integer). `-1` = cannot be sold. If omitted, derived from `sell_percent`. |
| `sell_percent` | Override the percentage for this item. |
| `stock` | `unlimited` or integer. |
| `coefficient` | Dynamic price factor (see the configuration guide, §4.2). |
| `buy` | Purchase quantity word. |
| `sell_mode` | Sale quantity word (named `sell_mode` because `sell` is the price). At category/defaults level the key is `sell`. |
| `restart`, `destock` | Stock behaviour at restart. |
| `attachments` | List of class names / group names / `@compat` refs. |
| `variants` | List of class names / groups. Variants that don't define their own `attachments` inherit the base item's. |
| `presets` | Map of preset name → attachment list (see below). |
An item may appear in several categories; the first occurrence with options defines it,
later occurrences just add it to that category (a warning is printed if they carry
conflicting options).
---
## Quantity words
Used for `buy` (item state when purchased) and `sell` / `sell_mode` (state required when sold):
| Word | Buy | Sell |
|---|---|---|
| `full` | item spawns full | must be full |
| `empty` | spawns empty | must be empty |
| `any` | – | any amount accepted, paid pro-rata |
| `static N` | exactly N units | exactly N units |
| `coef 50%` (or `coef 0.5`) | 50 % of max | 50 % of max |
The build packs these into the mod's `tradeQuantity` bitfield using the layout the mod's
runtime actually reads (`TraderXTradeQuantity`), not the one in its CSV packer, which is
inconsistent.
---
## Presets
```yaml
- AKM:
attachments: [ak_optics, ak_muzzle, Mag_AKM_30Rnd]
presets:
"CQB*": [KobraOptic, AK_Suppressor, Mag_AKM_30Rnd] # * marks the default preset
"DMR": [PSO1Optic, Mag_AKM_30Rnd]
```
Each item with `presets` produces `TraderXPresets/presets_<productId>.json`. Rules enforced
at build time:
- every preset attachment must be in the item's own `attachments` list (the mod won't
let players select it otherwise) – error;
- exactly one preset can carry `*`; if none does, the first one becomes the default;
- preset ids are derived (`preset_akm_cqb_001`) and stable.
Player-saved presets live in the same folder and are not touched.
---
## `@compat` references
Require `build --compat FILE`. See [compat.md](compat.md).
| Ref | Expands to |
|---|---|
| `@compat` | every attachment the compat file lists for this weapon **that is defined as a product somewhere in the source** |
| `@compat_mags` | same, for magazines |
| `@compat_all` | everything compatible, auto-creating products that don't exist (rarely what you want) |
---
## What the build checks
Errors (nothing is written):
- item without a resolvable price
- unknown quantity/restart word, out-of-range values
- preset using a class not in the weapon's attachments, or not defined at all
- `@compat` used without `--compat`
- trader or category reference that doesn't exist
- trader `className` with the wrong `SurvivorM_`/`SurvivorF_` prefix for a known survivor name
- duplicate explicit ids
- with `--strict`: attachment/variant class not defined anywhere
Warnings:
- `coefficient` set while stock is unlimited (the mod ignores it)
- sell price higher than buy price
- attachment not attachable according to the compat file
- item listed twice in a category; item defined twice with options
- category with no items; trader not referenced by any category
- auto-created hidden products (as notes)
---
## Minimal complete example
```yaml
defaults:
sell_percent: 30
categories:
- name: Food
traders: [Eve]
price: 50
items: [Apple, Pear, BakedBeansCan]
```
builds three product files, one category file and sets Eve's `categoriesId`.