Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

UTM Format (Merchant Blueprint)

Description: The Merchant (.utm) blueprint natively handles the interactive storefront data for merchants and shops. Because shops strictly behave as container interfaces that dynamically buy, sell, and map economic value onto spawned .uti items, the structure of a .utm is highly compact, primarily consisting of economic markups and inventory sorting parameters.

At a Glance

PropertyValue
Extension(s).utm
Magic SignatureUTM / V3.2
TypeMerchant Blueprint
Rust ReferenceView rakata_generics::Utm in Rustdocs

Data Model Structure

Rakata maps the Merchant definition directly into the rakata_generics::Utm struct. To view the exhaustive binary schema and strict GFF field mappings, please refer to the Rustdocs for this struct, where each field is explicitly documented.

A Merchant breaks down into three main categories:

  1. Core Identity: The basic identifiers providing the shop’s name and tag (e.g., Tag, LocName).
  2. Economic Metrics: The percentages controlling price scaling when buying or selling items, alongside basic shop rules (e.g., MarkUp, MarkDown, BuySellFlag).
  3. Store Inventory (ItemList): The list of items actively available in the shop’s stock, including rules for infinite regeneration.
  • Typestate Extraction: By mapping the raw GFF structure into the strict rakata_generics::Utm struct, fields like MarkUp, BuySellFlag, and inventory lists are safely constrained to proper domain types (e.g., bounds-checked i32 or strictly formatted ResRef).

Engine Audits & Decompilation

Because .utm evaluating is structurally straightforward, the engine bypasses heavy memory allocations and maps fields in an incredibly fast iteration.

(Decompilation logic for this section was entirely audited and verified via native Ghidra pipeline against swkotor.exe, explicitly pulling from CSWSStore::LoadStore at 0x005c7180.)

Structural Load Phasing

FunctionSizeBehavior
LoadStore1341 BThe primary parser that pulls the merchant’s basic identity, economic constraints (MarkUp/MarkDown), and buying capabilities.
ItemList ReadIterates through the list of store stock, actively pulling either explicitly saved item instances or generating them freshly from templates (InventoryRes).
AddItemToInventoryPushes the fully sorted loot stack into the physical storefront container so the player can actually interact with and purchase them.

Core Structural Findings

Engine RuleRuntime Behavior
Cost SortingWhen building the store inventory, the engine actively sorts the merchant’s final stock from cheapest to most expensive by checking the cost of each item. This completely overrides whatever custom display order you try to dictate statically.
Dynamic EconomicsThe engine relies entirely on the MarkUp and MarkDown integers to control shop prices. These act as simple percentages that mathematically bump or slash the base cost of every item the merchant sells or buys.
Buy/Sell Bit FlagsBuySellFlag is split into basic toggles: bit 0 controls whether you are allowed to sell your gear to the merchant, and bit 1 controls whether the merchant will actually sell anything to you.
Infinite StackingIf an item is flagged as Infinite, the engine specifically locks that item in memory so that no matter how many times a player buys it, the shop never physically runs out of stock.

Legacy & Ignored Data

Finding TypeExplanation
Legacy Interface ConfigurationsSome older tools expose positional values like Repos_PosX or Repos_PosY inherited from other Odyssey games, but the engine completely ignores them. The game physically builds its shop UI dynamically when you open it, rendering those grid coordinates totally useless.

Implemented Linter Rules (Rakata-Lint)

Phase 1 (intra-resource, no context)

Implemented under rakata_lint::rules::utm.

  1. UTM-001 (Legacy Grid Coordinates): Informs when inventory items contain non-zero Repos_PosX or Repos_PosY; the engine builds its shop UI dynamically and ignores these coordinates.
  2. UTM-002 (Unknown Buy/Sell Flags): Warns when BuySellFlag has bits set outside the canonical buy (bit 0) and sell (bit 1) toggles.
  3. UTM-003 (Legacy Store UI Fallback): Warns when BuySellFlag == 0 (missing or empty); the engine falls back to legacy UI behaviors and forcefully clamps MarkUp to 100.

Phase 2 (resource existence, requires LintContext)

Implemented under rakata_lint::rules::utm_range.

  1. UTM-004 (Resref Existence): Warns when OnOpenStore (.ncs) or any ItemList[i].InventoryRes (.uti) does not resolve in the configured resource sources. The toolset-only top-level ResRef (merchant template) is intentionally skipped – it is never read by the engine.