aether-shards/specs/Marketplace.spec.md

156 lines
4.9 KiB
Markdown
Raw Permalink Normal View History

# **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").