issun 0.10.0

A mini game engine for logic-focused games - Build games in ISSUN (一寸) of time
Documentation
# Economy Plugin

Complete economy system with multi-currency support, resource management, and currency exchange.

## Features

### 1. Multi-Currency System
- Define multiple currencies with metadata (name, symbol, decimals)
- Wallet system for tracking currency balances
- Safe arithmetic operations (saturating add/sub)

### 2. Root Resource System
- Define resources with flexible types:
  - **Stock**: Accumulated resources (Gold, Food, Iron)
  - **Flow**: Per-turn generation capacity (GDP, Production)
  - **Abstract**: Abstract values (National Power, Influence)
  - **Hybrid**: Complex multi-aspect resources
- Infinite or finite resource support
- Resource inventory tracking

### 3. Currency Exchange
- Define exchange rates between currencies
- Static or dynamic rate support
- Automatic conversion calculations

### 4. Resource-to-Currency Conversion
- Define conversion rules from resources to currencies
- One resource can convert to multiple currencies
- Automatic resource consumption and currency generation

## Usage Examples

### Example 1: Medieval Fantasy (Stock-based Economy)

```rust
use issun::prelude::*;
use issun::plugin::economy::*;

async fn setup_medieval_economy(game: &mut Game) {
    // Define currencies
    let mut currencies = game.resources.get_mut::<CurrencyDefinitions>().await.unwrap();
    currencies.register(CurrencyDefinition {
        id: CurrencyId::new("gold_coin"),
        name: "Gold Coin".into(),
        symbol: "G".into(),
        decimals: 0,
    });
    currencies.register(CurrencyDefinition {
        id: CurrencyId::new("silver_coin"),
        name: "Silver Coin".into(),
        symbol: "S".into(),
        decimals: 0,
    });
    drop(currencies);

    // Define resources
    let mut resources = game.resources.get_mut::<ResourceDefinitions>().await.unwrap();
    resources.register(
        ResourceDefinition::new(
            "gold_ore",
            "Gold Ore",
            "Raw gold extracted from mines",
            ResourceType::Stock,
        )
        .with_finite()  // Gold ore is finite
    );
    drop(resources);

    // Define conversion: Gold Ore -> Gold Coins
    let mut rules = game.resources.get_mut::<ConversionRules>().await.unwrap();
    rules.register(ConversionRule::new(
        ResourceId::new("gold_ore"),
        CurrencyId::new("gold_coin"),
        10.0,  // 1 Gold Ore = 10 Gold Coins
    ));
    drop(rules);

    // Define exchange: Gold Coins <-> Silver Coins
    let mut rates = game.resources.get_mut::<ExchangeRates>().await.unwrap();
    rates.register(ExchangeRate::new(
        CurrencyId::new("gold_coin"),
        CurrencyId::new("silver_coin"),
        10.0,  // 1 Gold = 10 Silver
    ));
    drop(rates);

    // Initialize inventory with some gold ore
    let mut inventory = game.resources.get_mut::<ResourceInventory>().await.unwrap();
    inventory.insert(ResourceId::new("gold_ore"), 100);
}

async fn mine_and_mint(game: &mut Game) {
    let service = game.services.get::<EconomyService>().unwrap();

    let mut inventory = game.resources.get_mut::<ResourceInventory>().await.unwrap();
    let mut wallet = game.resources.get_mut::<Wallet>().await.unwrap();
    let resource_defs = game.resources.get::<ResourceDefinitions>().await.unwrap();
    let conversion_rules = game.resources.get::<ConversionRules>().await.unwrap();

    // Convert 10 Gold Ore to Gold Coins
    let gold_gained = service.convert_resource_to_currency(
        &mut inventory,
        &mut wallet,
        &resource_defs,
        &conversion_rules,
        &ResourceId::new("gold_ore"),
        &CurrencyId::new("gold_coin"),
        10,
    ).unwrap();

    println!("Minted {} gold coins!", gold_gained.amount());
}
```

### Example 2: Modern Nation Economy (Flow-based)

```rust
use issun::prelude::*;
use issun::plugin::economy::*;

async fn setup_modern_economy(game: &mut Game) {
    // Define currencies
    let mut currencies = game.resources.get_mut::<CurrencyDefinitions>().await.unwrap();
    currencies.register(CurrencyDefinition {
        id: CurrencyId::new("tax_revenue"),
        name: "Tax Revenue".into(),
        symbol: "$".into(),
        decimals: 2,
    });
    currencies.register(CurrencyDefinition {
        id: CurrencyId::new("investment_pool"),
        name: "Investment Pool".into(),
        symbol: "INV".into(),
        decimals: 2,
    });
    drop(currencies);

    // Define Flow-type resource (GDP)
    let mut resources = game.resources.get_mut::<ResourceDefinitions>().await.unwrap();
    resources.register(
        ResourceDefinition::new(
            "gdp",
            "GDP",
            "Gross Domestic Product - Economic capacity",
            ResourceType::Flow { per_turn: true },
        )
        // Infinite by default - GDP is a conceptual measure
    );
    drop(resources);

    // Define conversion: GDP -> Tax Revenue (25% tax rate)
    let mut rules = game.resources.get_mut::<ConversionRules>().await.unwrap();
    rules.register(ConversionRule::new(
        ResourceId::new("gdp"),
        CurrencyId::new("tax_revenue"),
        0.25,  // 25% of GDP becomes tax revenue
    ));
    rules.register(ConversionRule::new(
        ResourceId::new("gdp"),
        CurrencyId::new("investment_pool"),
        0.15,  // 15% of GDP becomes investment capital
    ));
    drop(rules);

    // Initialize GDP capacity
    let mut inventory = game.resources.get_mut::<ResourceInventory>().await.unwrap();
    inventory.insert(ResourceId::new("gdp"), 10000);  // GDP of 10,000
}

async fn collect_taxes(game: &mut Game) {
    let service = game.services.get::<EconomyService>().unwrap();

    let mut inventory = game.resources.get_mut::<ResourceInventory>().await.unwrap();
    let mut wallet = game.resources.get_mut::<Wallet>().await.unwrap();
    let resource_defs = game.resources.get::<ResourceDefinitions>().await.unwrap();
    let conversion_rules = game.resources.get::<ConversionRules>().await.unwrap();

    let gdp = service.resource_quantity(&inventory, &ResourceId::new("gdp"));

    // Convert GDP to tax revenue
    let tax_collected = service.convert_resource_to_currency(
        &mut inventory,
        &mut wallet,
        &resource_defs,
        &conversion_rules,
        &ResourceId::new("gdp"),
        &CurrencyId::new("tax_revenue"),
        gdp,
    ).unwrap();

    println!("Collected {} in taxes from GDP of {}", tax_collected.amount(), gdp);
}
```

### Example 3: Currency Exchange

```rust
use issun::prelude::*;
use issun::plugin::economy::*;

async fn exchange_currencies(game: &mut Game) {
    let service = game.services.get::<EconomyService>().unwrap();

    let mut wallet = game.resources.get_mut::<Wallet>().await.unwrap();
    let rates = game.resources.get::<ExchangeRates>().await.unwrap();

    // Player has 100 USD and wants to exchange to JPY
    wallet.insert(CurrencyId::new("usd"), Currency::new(100));

    let jpy_received = service.exchange(
        &mut wallet,
        &rates,
        &CurrencyId::new("usd"),
        &CurrencyId::new("jpy"),
        Currency::new(50),  // Exchange 50 USD
    ).unwrap();

    println!("Exchanged 50 USD for {} JPY", jpy_received.amount());
}
```

## Architecture

Following the [Plugin Design Principles](../../docs/architecture/plugin-design-principles.md):

### Resources (ReadOnly)
- `CurrencyDefinitions`: Currency metadata registry
- `ResourceDefinitions`: Resource metadata registry
- `ExchangeRates`: Currency exchange rate registry
- `ConversionRules`: Resource-to-currency conversion rules
- `EconomyConfig`: Global economy configuration

### Runtime State (Mutable)
- `Wallet`: Currency balances (`Store<CurrencyId, Currency>`)
- `ResourceInventory`: Resource quantities (`Store<ResourceId, i64>`)

### Service (Stateless)
- `EconomyService`: Pure functions for:
  - Currency operations (deposit, withdraw, transfer)
  - Currency exchange
  - Resource operations (add, consume)
  - Resource-to-currency conversion

## Design Philosophy

### Stock vs Flow Resources

**Stock Resources** represent accumulated quantities:
- Gold, Food, Iron
- Consumed when used
- Can be stored indefinitely
- Finite or infinite

**Flow Resources** represent generation capacity:
- GDP, Production Capacity
- Represent "per turn" generation
- Used as a basis for currency generation
- Typically infinite (conceptual measures)

**Abstract Resources** represent intangible concepts:
- National Power, Influence, Prestige
- May or may not decrease when used
- Game-specific interpretation

**Hybrid Resources** combine multiple aspects:
- Industrial Capacity (Stock count + Flow effect)
- Technology Level (Abstract value + Flow multiplier)

### Infinite vs Finite Resources

- **Infinite Resources**: No consumption check, represents unlimited capacity
  - Default behavior
  - Good for: GDP, abstract concepts, Flow-type resources

- **Finite Resources**: Consumption requires availability check
  - Must explicitly set with `.with_finite()`
  - Good for: Gold, Food, physical Stock-type resources

## Error Handling

The `EconomyService` returns `EconomyResult<T>` which can contain:
- `EconomyError::InsufficientFunds`: Not enough currency for exchange
- `EconomyError::InsufficientResource`: Not enough resource for conversion (finite only)
- `EconomyError::ExchangeRateNotFound`: No rate defined for currency pair
- `EconomyError::ConversionRuleNotFound`: No conversion rule for resource->currency

## Future Enhancements

Potential additions (not yet implemented):
- Events for exchange/conversion operations
- System for automatic per-turn resource generation (Flow types)
- Hooks for custom exchange rate calculations
- Market dynamics for dynamic exchange rates
- Transaction history tracking
- Multi-wallet support (per-entity wallets)