# **Marketplace Specification: The Gilded Bazaar**

This document defines the architecture, logic, and UI for the Hub Marketplace. It acts as the primary gold sink and progression accelerator.

## **1. System Architecture**

The Marketplace is managed by a new singleton logic controller: **MarketManager**.

- **Location:** src/managers/MarketManager.js
- **Owner:** GameStateManager (instantiated alongside RosterManager).
- **Persistence:** The current stock and buyback queue are saved to IndexedDB (market_state) to prevent players from reloading the game to re-roll shop inventory.

### **Integration Flow**

1. **Mission Complete:** MissionManager triggers an event. MarketManager listens and sets a needsRefresh flag.
2. **Hub Entry:** Player enters Hub. MarketManager checks flag. If true, generates new stock and saves immediately.
3. **UI Render:** HubScreen passes the MarketManager instance to the <marketplace-screen> component.

## **2. TypeScript Interfaces (Data Model)**

```typescript
// src/types/Marketplace.ts

import { ItemType, Rarity, ItemInstance } from "./Inventory";

export type MerchantType = "SMITH" | "TAILOR" | "ALCHEMIST" | "SCAVENGER";

export interface MarketState {
  /** Timestamp or Mission Count when this stock was generated */
  generationId: string;
  /** The active inventory for sale */
  stock: MarketItem[];
  /** Items sold by the player this session (can be bought back) */
  buyback: MarketItem[]; // Price is usually equal to sell price
  /*_ Daily Deal or Special logic */
  specialOffer?: string; // ID of a specific item
}

export interface MarketItem {
  id: string; // Unique Stock ID (e.g. "STOCK_001")
  defId: string; // Reference to ItemRegistry (e.g. "ITEM_RUSTY_BLADE")
  type: ItemType; // Cached for filtering
  rarity: Rarity; // Cached for sorting/styling
  price: number;
  discount: number; // 0.0 to 1.0 (percent off)
  purchased: boolean; // If true, show as "Sold Out"

  /** If this is a specific instance (e.g. Buyback), store the data here */
  instanceData?: ItemInstance;
}

/** _ Configuration for what a merchant sells at a specific Game Stage.
 */
export interface StockTable {
  minItems: number;
  maxItems: number;
  rarityWeights: {
    COMMON: number;
    UNCOMMON: number;
    RARE: number;
    ANCIENT: number;
  };
  allowedTypes: ItemType[];
}
```

## **3. Logic & Algorithms**

### **A. Stock Generation (`generateStock(tier)`)**

Triggered only when a run is completed.

**Tier 1 (Early Game):**

- **Smith:** 5 Common Weapons, 3 Common Armor.
- **Alchemist:** 5 Potions (Stacked), 2 Grenades.

**Tier 2 (Mid Game - After Mission 3):**

- **Weights:** Common (60%), Uncommon (30%), Rare (10%).
- **Scavenger:** Unlocks. Sells 3 "Mystery Box" items (Unidentified Relics).

**Algorithm:**

1. Filter `ItemRegistry` by `allowedTypes` and `Tier`.
2. Roll `RNG` against `rarityWeights`.
3. Select random Item ID.
4. Calculate Price: `BaseValue * (1 + RandomVariance(0.1))`.
5. Create `MarketItem`.

### **B. Transaction Processing (`buyItem`, `sellItem`)**

Transactions must be atomic to prevent item duplication or currency desync.

**Buy Logic:**

1. Check `Wallet >= Price`.
2. Deduct Currency.
3. **Generate Instance:** Create a new `ItemInstance` with a fresh UID (`ITEM_{TIMESTAMP}`).
4. Add to `InventoryManager.hubStash`.
5. Mark `MarketItem` as `purchased: true`.
6. Save State.

**Sell Logic:**

1. Remove `ItemInstance` from `hubStash`.
2. Calculate Value (`BasePrice * 0.25`).
3. Add Currency.
4. **Create Buyback:** Convert instance to `MarketItem` and add to `buyback` array (Limit 10).
5. Save State.

---

## **4. UI Implementation (LitElement)**

**Component:** `src/ui/screens/MarketplaceScreen.js`

### **Visual Layout**

- **Grid Container:** CSS Grid `250px 1fr`.
- **Sidebar (Merchants):** Vertical tabs.
  - [⚔️ Smith]
  - [🧥 Tailor]
  - [⚗️ Alchemist]
  - [♻️ Buyback]
- **Main Content:**
  - **Filter Bar:** "Show All", "Weapons Only", etc.
  - **Item Grid:** Flex-wrap container of Item Cards.
- **Player Panel (Right overlay or bottom slide-up):**
  - Shows current Inventory. Drag-and-drop to "Sell Zone" or Right-Click to sell.

### **Interactive States**

- **Affordable:** Price Text is White/Green.
- **Unaffordable:** Price Text is Red. Button Disabled.
- **Sold Out:** Card is dimmed, overlay text "SOLD".

---

## **5. Conditions of Acceptance (CoA)**

**CoA 1: Persistence Integrity**

- Buying an item, saving, and reloading the page must result in the item being in the Inventory and the Shop still showing "Sold Out".
- The shop stock **must not change** upon reload.

**CoA 2: Currency Math**

- Buying an item costs exactly the listed price.
- Selling an item refunds exactly the calculated sell price.
- Buyback allows repurchasing a sold item for the _exact amount it was sold for_ (Undo button logic).

**CoA 3: Class Filtering**

- (Optional Polish) The shop should visually flag items that cannot be equipped by _anyone_ in the current Roster (e.g. "No Sapper recruited").
