Can you make the relationship mechanic more meaningful?



import random
import sys
import time
from colorama import Fore, Style, init

# Initialize colorama with automatic reset and stripping for unsupported environments
init(autoreset=True, strip=True)

# ASCII Art Title
TITLE = f"""
{Fore.CYAN}  __  __    _    ____  _  _______ _____ 
 |  \/  |  / \  |  _ \| |/ / ____|_   _|
 | |\/| | / _ \ | |_) | ' /|  _|   | |  
 | |  | |/ ___ \|  _ <| . \| |___  | |  
 |_|  |_/_/   \_\_| \_\_|\_\_____| |_|  
                                        
{Style.RESET_ALL}
"""

WELCOME_MESSAGE = f"""
{Fore.YELLOW}{'='*60}
Welcome to the Text-Based Trading Game!
{Style.RESET_ALL}
Your goal is to accumulate as much wealth as possible within a set number of turns.
Explore a variety of goods, manage your cargo capacity, and navigate the dynamic market.
{Fore.YELLOW}{'='*60}
"""

# Print methods for different speeds
def fast_print(text):
    for char in text:
        print(char, end="", flush=True)
        time.sleep(0.0002)  # Fast typing speed
    print()

def medium_print(text):
    for char in text:
        print(char, end="", flush=True)
        time.sleep(0.005)  # Medium typing speed
    print()

def slow_print(text):
    for char in text:
        print(char, end="", flush=True)
        time.sleep(0.02)  # Slow typing speed
    print()

def get_relationship_status(relation):
    """Converts a numerical relationship score into a descriptive status."""
    if relation > 50:
        return "Friendly"
    elif relation >= -50:
        return "Neutral"
    else:
        return "Hostile"

# Goods and their base prices, weights, base supply, and base demand
GOODS = {
    "Spices": {"base_price": 100, "weight": 5, "base_supply": 500, "base_demand": 300},
    "Gems": {"base_price": 500, "weight": 10, "base_supply": 200, "base_demand": 150},
    "Food": {"base_price": 50, "weight": 3, "base_supply": 800, "base_demand": 600},
    "Silk": {"base_price": 200, "weight": 4, "base_supply": 300, "base_demand": 250},
    "Iron": {"base_price": 150, "weight": 15, "base_supply": 400, "base_demand": 350},
    "Wine": {"base_price": 120, "weight": 6, "base_supply": 350, "base_demand": 300},
    "Tea": {"base_price": 80, "weight": 2, "base_supply": 600, "base_demand": 500},
    "Herbs": {"base_price": 60, "weight": 3, "base_supply": 700, "base_demand": 550},
    "Cloth": {"base_price": 180, "weight": 8, "base_supply": 250, "base_demand": 200},
    "Gold": {"base_price": 1000, "weight": 20, "base_supply": 100, "base_demand": 80},
}

# Expanded list of Towns
TOWNS = [
    "Amberville", "Brightstone", "Crimsonburg", "Dusktown",
    "Sunset City", "Northport", "Riverside", "Hilltop",
    "Lakeside", "Oakwood", "Stormhaven", "Fairview"
]

# List of possible random events
GLOBAL_EVENTS = [
    "Economic boom affecting all markets.",
    "Global trade embargo reducing supply worldwide.",
    "Pandemic affecting demand for certain goods globally.",
    "Technological advancements altering trade dynamics.",
    "Global inflation increasing prices across the board.",
    "Global recession decreasing purchasing power.",
]

LOCAL_EVENTS = [
    "Thieves attacked your caravan and stole some goods!",
    "A storm ruined your goods during travel.",
    "A festival in town increased demand for certain goods.",
    "Disease outbreak decreased the demand for food.",
    "New trade routes discovered, affecting supply.",
    "Pirates disrupted trade in the seas.",
    "Economic boom in Crimsonburg raised prices.",
    "Market crash in Brightstone lowered prices.",
    "Government imposed a tax on trade.",
    "Discovery of a rare gem deposit increased gem supply.",
    "Locusts devastated the food supplies in Dusktown.",
    "Artisans in Amberville created new uses for spices, increasing their demand.",
    "Floods in Riverside increased the supply of iron.",
    "Harvest season in Lakeside boosted the demand for food.",
    "Gold rush in Hilltop increased the supply and demand for gold.",
    "Silk shortage in Sunset City raised silk prices.",
    "Herbal harvest in Oakwood decreased the supply of herbs.",
    "Tea festival in Fairview increased the demand for tea.",
    "Ironworks expansion in Northport increased the supply of iron.",
    "Wine tasting event in Stormhaven boosted wine prices.",
    "Cloth market crash in Fairview lowered cloth prices.",
    "Bandit attack in Oakwood stole some of your goods.",
    "Natural disaster in Dusktown affecting multiple goods.",
    "Town marketplace upgrade in Riverside lowered base prices for certain goods.",
]

# Player relationships with towns
RELATIONSHIP_BASE = 0  # Neutral
RELATIONSHIP_MAX = 100
RELATIONSHIP_MIN = -100

# Difficulty settings
DIFFICULTIES = {
    "EASY": {
        "event_chance": 0.15,
        "ai_aggressiveness": 0.8,
        "starting_money": 3000,
        "starting_cargo": 300,
        "turns": 40
    },
    "MEDIUM": {
        "event_chance": 0.2,
        "ai_aggressiveness": 1.0,
        "starting_money": 2000,
        "starting_cargo": 200,
        "turns": 30
    },
    "HARD": {
        "event_chance": 0.25,
        "ai_aggressiveness": 1.2,
        "starting_money": 1500,
        "starting_cargo": 150,
        "turns": 25
    }
}

class AITrader:
    """Represents an AI trader that interacts with the market each turn."""
    def __init__(self, trader_id, aggressiveness=1.0):
        self.trader_id = trader_id
        self.name = f"Trader_{trader_id}"
        self.aggressiveness = aggressiveness  # Determines transaction sizes and frequency

    def perform_action(self, market):
        """AI trader performs buy or sell actions based on strategy."""
        actions = []
        # Determine number of actions based on aggressiveness
        num_actions = random.randint(1, 3) if self.aggressiveness > 1.0 else random.randint(1, 2)
        for _ in range(num_actions):
            action = random.choices(["BUY", "SELL"], weights=[self.aggressiveness, 1.0])[0]
            good = random.choice(list(GOODS.keys()))
            # Vary transaction sizes more broadly
            quantity = random.randint(1, int(10 * self.aggressiveness))
            if action == "BUY":
                # AI trader buys goods: decrease supply, increase demand
                if market.supply[good] >= quantity:
                    market.supply[good] -= quantity
                    market.demand[good] += quantity * 0.5  # Increased impact
            elif action == "SELL":
                # AI trader sells goods: increase supply, decrease demand
                market.supply[good] += quantity
                market.demand[good] -= quantity * 0.5  # Increased impact
                if market.demand[good] < 50:  # Prevent demand from going too low
                    market.demand[good] = 50

class Market:
    """Represents the market of a specific town."""
    PRICE_FLOOR = 10
    PRICE_CEILING = 2000

    def __init__(self, town):
        self.town = town
        # Initialize supply and demand per good with slight random variations
        self.supply = {}
        self.demand = {}
        for good, info in GOODS.items():
            supply_variation = random.uniform(0.9, 1.1)
            demand_variation = random.uniform(0.9, 1.1)
            self.supply[good] = info["base_supply"] * supply_variation
            self.demand[good] = info["base_demand"] * demand_variation
        self.prices = {}
        self.generate_prices()
        # Initialize AI traders for the town
        self.ai_traders = [AITrader(trader_id=i+1, aggressiveness=random.uniform(0.8, 1.2)) for i in range(10)]  # 10 AI traders per town

    def generate_prices(self):
        """Calculates current prices based on supply and demand with elasticity and price constraints."""
        for good, info in GOODS.items():
            # Calculate price based on demand and supply with elasticity
            if self.supply[good] == 0:
                price_multiplier = 2  # High price if no supply
            else:
                # Calculate the ratio of demand to supply
                ratio = self.demand[good] / self.supply[good]
                # Elasticity factor to allow gradual changes
                elasticity = random.uniform(0.90, 1.10)
                price_multiplier = ratio * elasticity
            # Calculate new price
            new_price = int(GOODS[good]["base_price"] * price_multiplier)
            # Clamp price within floor and ceiling
            new_price = max(self.PRICE_FLOOR, min(new_price, self.PRICE_CEILING))
            self.prices[good] = new_price

    def display_prices(self, relationship):
        """Displays the current prices, supply, demand, and relationship for all goods in the market."""
        status = get_relationship_status(relationship)
        # Display Market Overview and Relationship Side by Side
        slow_print(f"\n{Fore.MAGENTA}Market Overview in {self.town}:{Style.RESET_ALL} {Fore.GREEN}Relationship: {relationship} ({status}){Style.RESET_ALL}")
        for good, price in self.prices.items():
            supply = int(self.supply[good])
            demand = int(self.demand[good])
            fast_print(f"{good}: ${price} (Supply: {supply}, Demand: {demand})")
        print()

    def process_ai_traders(self):
        """Processes all AI traders' actions for the market."""
        for trader in self.ai_traders:
            trader.perform_action(self)
        # After AI traders have acted, regenerate prices
        self.generate_prices()

class Player:
    """Represents the player with money, inventory, and cargo capacity."""
    def __init__(self, starting_money, starting_cargo):
        self.money = starting_money
        self.inventory = {good: 0 for good in GOODS}
        self.location = random.choice(TOWNS)
        self.turns = 0
        self.max_cargo = starting_cargo
        self.current_cargo = 0
        self.cargo_upgrades = 0
        self.relationships = {town: RELATIONSHIP_BASE for town in TOWNS}
        self.event_log = []  # To track key events per turn

    def status(self):
        """Displays the player's current status without general relationships."""
        slow_print(f"\n{Fore.BLUE}Player Status:{Style.RESET_ALL}")
        fast_print(f"Location: {self.location}")
        fast_print(f"Money: ${self.money}")
        fast_print(f"Cargo: {self.current_cargo}/{self.max_cargo} units used")
        fast_print("Inventory:")
        for good, qty in self.inventory.items():
            fast_print(f"  {good}: {qty}")
        print()

    def add_cargo(self, good, quantity):
        """Attempts to add cargo to the player's inventory."""
        weight = GOODS[good]["weight"]
        total_weight = weight * quantity
        if self.current_cargo + total_weight > self.max_cargo:
            return False, total_weight
        self.current_cargo += total_weight
        return True, total_weight

    def remove_cargo(self, good, quantity):
        """Removes cargo from the player's inventory."""
        weight = GOODS[good]["weight"]
        total_weight = weight * quantity
        self.current_cargo -= total_weight
        if self.current_cargo < 0:
            self.current_cargo = 0

    def upgrade_cargo(self):
        """Allows the player to upgrade cargo capacity."""
        upgrade_cost = 500 + (self.cargo_upgrades * 200)
        upgrade_amount = 50
        if self.money < upgrade_cost:
            slow_print("Insufficient funds to upgrade cargo capacity.")
            return
        confirm = input(f"Upgrade cargo capacity by {upgrade_amount} for {upgrade_cost} gold? (Y/N): ").strip().upper()
        if confirm == 'Y':
            self.money -= upgrade_cost
            self.max_cargo += upgrade_amount
            self.cargo_upgrades += 1
            slow_print(f"Cargo capacity increased by {upgrade_amount}. New capacity: {self.max_cargo}")
            self.event_log.append(f"Upgraded cargo capacity by {upgrade_amount} for {upgrade_cost} gold.")

class Game:
    """Represents the main game loop and logic."""
    def __init__(self):
        self.difficulty = self.choose_difficulty()
        self.player = Player(
            starting_money=DIFFICULTIES[self.difficulty]["starting_money"],
            starting_cargo=DIFFICULTIES[self.difficulty]["starting_cargo"]
        )
        self.turns_total = DIFFICULTIES[self.difficulty]["turns"]
        self.markets = {town: Market(town) for town in TOWNS}
        self.current_market = self.markets[self.player.location]
        self.current_event = None
        # Define decay rates to return supply and demand towards base values
        self.supply_decay_rate = 0.02  # 2% per turn
        self.demand_decay_rate = 0.02  # 2% per turn
        self.turn_counter = 1
        self.game_over = False
        self.key_events = []  # To track key events for summary

    def choose_difficulty(self):
        """Allows the player to choose a difficulty level."""
        fast_print("Choose Difficulty Level:")
        for idx, level in enumerate(DIFFICULTIES.keys(), 1):
            fast_print(f"{idx}. {level.capitalize()}")
        while True:
            choice = input(f"Enter the number corresponding to your choice (1-{len(DIFFICULTIES)}): ").strip()
            if choice.isdigit() and 1 <= int(choice) <= len(DIFFICULTIES):
                selected = list(DIFFICULTIES.keys())[int(choice)-1]
                fast_print(f"Selected {selected.capitalize()} difficulty.\n")
                return selected
            else:
                fast_print("Invalid choice. Please try again.")

    def start(self):
        """Starts the game by displaying the title and welcome message."""
        fast_print(TITLE)
        slow_print(WELCOME_MESSAGE)
        input("Press Enter to start your trading adventure...")
        self.game_loop()

    def game_loop(self):
        """Main game loop that runs until the player runs out of turns."""
        while self.turn_counter <= self.turns_total and not self.game_over:
            medium_print(f"\n--- Turn {self.turn_counter}/{self.turns_total} ---")
            self.apply_decay()
            # Process AI traders for all markets
            for market in self.markets.values():
                market.process_ai_traders()
            # Trigger event before displaying prices
            self.trigger_event()
            # Get player's relationship with the current town
            current_relationship = self.player.relationships[self.player.location]
            # Display prices for the current market after events, including relationship
            self.current_market.display_prices(current_relationship)
            self.player.status()
            command = input("Enter command (BUY/SELL/TRAVEL/STATUS/UPGRADE/OVERVIEW/HELP/EXIT): ").strip().upper()
            if command == "BUY":
                self.buy()
            elif command == "SELL":
                self.sell()
            elif command == "TRAVEL":
                self.travel()
            elif command == "STATUS":
                self.player.status()
                continue  # Do not decrement turn
            elif command == "UPGRADE":
                self.player.upgrade_cargo()
                continue  # Do not decrement turn
            elif command == "OVERVIEW":
                self.market_overview()
                continue  # Do not decrement turn
            elif command == "HELP":
                slow_print(WELCOME_MESSAGE)
                continue  # Do not decrement turn
            elif command == "EXIT":
                slow_print("Thank you for playing!")
                self.end_game()
            else:
                fast_print("Invalid command.")
                continue  # Do not decrement turn
            self.turn_counter += 1
        self.end_game()

    def buy(self):
        """Handles the buying process for the player."""
        good = self.choose_good("buy")
        if not good:
            return

        price = self.current_market.prices[good]
        # Calculate max affordable based on money
        max_affordable_quantity = self.player.money // price
        # Calculate max based on cargo
        available_cargo_space = self.player.max_cargo - self.player.current_cargo
        max_cargo_quantity = available_cargo_space // GOODS[good]["weight"]
        # Calculate max based on supply
        max_supply = int(self.current_market.supply[good])

        # Removed the transaction limit based on difficulty to allow unlimited purchases within constraints
        max_quantity = min(max_affordable_quantity, max_cargo_quantity, max_supply)

        if max_quantity <= 0:
            slow_print("You cannot buy any units of this good due to insufficient funds, cargo space, or supply.")
            return

        # Encourage bulk buying with discounts
        discount = 0
        if max_quantity >= 20:
            discount = 0.05  # 5% discount for buying 20 or more units
            discounted_price = int(price * (1 - discount))
            fast_print(f"Bulk purchase discount applied! Price per unit: ${discounted_price} (Original: ${price})")
        else:
            discounted_price = price

        fast_print(f"You can afford up to {max_quantity} units based on your constraints.")
        quantity_input = input(f"Enter the quantity of {good} to buy (max {max_quantity}): ").strip()
        if not quantity_input.isdigit() or int(quantity_input) <= 0 or int(quantity_input) > max_quantity:
            fast_print("Invalid quantity. Transaction canceled.")
            return

        quantity = int(quantity_input)
        cost = discounted_price * quantity

        success, added_weight = self.player.add_cargo(good, quantity)
        if not success:
            slow_print(f"Cannot buy {quantity} {good}. Exceeds cargo capacity.")
            return

        # Update player and market
        self.player.money -= cost
        self.player.inventory[good] += quantity
        self.current_market.supply[good] -= quantity
        self.current_market.demand[good] += quantity * 0.3  # Partial impact to prevent immediate price spikes
        slow_print(f"Bought {quantity} {good} for ${cost}.")
        fast_print(f"Cargo Updated: {self.player.current_cargo}/{self.player.max_cargo} units used.")
        self.player.event_log.append(f"Turn {self.turn_counter}: Bought {quantity} {good} for ${cost}.")
        self.key_events.append(f"Turn {self.turn_counter}: Bought {quantity} {good} for ${cost}.")

    def sell(self):
        """Handles the selling process for the player."""
        good = self.choose_good("sell")
        if not good:
            return
        if self.player.inventory[good] == 0:
            fast_print(f"You have no {good} to sell.")
            return

        # Removed the transaction limit based on difficulty to allow unlimited sales within constraints
        max_sell_quantity = int(self.player.inventory[good])

        fast_print(f"You can sell up to {max_sell_quantity} units based on your inventory.")
        quantity_input = input(f"Enter the quantity of {good} to sell (max {max_sell_quantity}): ").strip()
        if not quantity_input.isdigit() or int(quantity_input) <= 0 or int(quantity_input) > max_sell_quantity:
            fast_print("Invalid quantity. Transaction canceled.")
            return

        quantity = int(quantity_input)
        price = self.current_market.prices[good]
        revenue = price * quantity

        # Update player and market
        self.player.money += revenue
        self.player.inventory[good] -= quantity
        self.player.remove_cargo(good, quantity)
        self.current_market.supply[good] += quantity
        self.current_market.demand[good] -= quantity * 0.3  # Partial impact to prevent immediate price drops
        slow_print(f"Sold {quantity} {good} for ${revenue}.")
        fast_print(f"Cargo Updated: {self.player.current_cargo}/{self.player.max_cargo} units used.")
        self.player.event_log.append(f"Turn {self.turn_counter}: Sold {quantity} {good} for ${revenue}.")
        self.key_events.append(f"Turn {self.turn_counter}: Sold {quantity} {good} for ${revenue}.")

    def travel(self):
        """Handles the travel process for the player to move between towns."""
        available_towns = [town for town in TOWNS if town != self.player.location]
        slow_print("\nAvailable towns to travel to:")
        for idx, town in enumerate(available_towns, 1):
            fast_print(f"{idx}. {town}")
        choice = input(f"Enter the number of the town you want to travel to (1-{len(available_towns)}): ").strip()
        if not choice.isdigit() or not (1 <= int(choice) <= len(available_towns)):
            fast_print("Invalid choice. Travel canceled.")
            return
        new_location = available_towns[int(choice) - 1]
        self.player.location = new_location
        self.current_market = self.markets[new_location]
        slow_print(f"Traveled to {new_location}.")
        self.player.event_log.append(f"Turn {self.turn_counter}: Traveled to {new_location}.")
        self.key_events.append(f"Turn {self.turn_counter}: Traveled to {new_location}.")

    def choose_good(self, action):
        """Prompts the player to choose a good to buy or sell."""
        fast_print("Available goods:")
        for idx, good in enumerate(GOODS.keys(), 1):
            fast_print(f"{idx}. {good}")
        choice = input(f"Enter the number of the good to {action}: ").strip()
        if not choice.isdigit() or not (1 <= int(choice) <= len(GOODS)):
            fast_print("Invalid choice.")
            return None
        return list(GOODS.keys())[int(choice) - 1]

    def market_overview(self):
        """Provides a market overview of all towns."""
        slow_print(f"\n{Fore.GREEN}Market Overview Across All Towns:{Style.RESET_ALL}")
        for town, market in self.markets.items():
            avg_price = sum(market.prices.values()) / len(GOODS)
            fast_print(f"{town}: Average Price ${int(avg_price)}")
        print()

    def trigger_event(self):
        """Randomly triggers a global or local event based on difficulty settings."""
        event_chance = DIFFICULTIES[self.difficulty]["event_chance"]
        if random.random() < event_chance:
            event_type = random.choice(["GLOBAL", "LOCAL"])
            if event_type == "GLOBAL":
                event = random.choice(GLOBAL_EVENTS)
                slow_print(f"\n{Fore.RED}Global Event: {event}{Style.RESET_ALL}")
                self.apply_event(event, global_event=True)
                self.key_events.append(f"Turn {self.turn_counter}: Global Event - {event}")
            else:
                event = random.choice(LOCAL_EVENTS)
                slow_print(f"\n{Fore.RED}Local Event: {event}{Style.RESET_ALL}")
                self.apply_event(event, global_event=False)
                self.key_events.append(f"Turn {self.turn_counter}: Local Event - {event}")

    def apply_event(self, event, global_event=False):
        """Applies the effects of a triggered event to the game."""
        # Player-specific positive events (Example)
        if "found extra goods" in event:
            good = random.choice(list(GOODS.keys()))
            quantity = random.randint(5, 15)
            self.player.inventory[good] += quantity
            self.player.current_cargo += GOODS[good]["weight"] * quantity
            self.player.money += 100  # Bonus money
            slow_print(f"You found extra {quantity} units of {good} and gained $100!")
            self.player.event_log.append(f"Turn {self.turn_counter}: Found extra {quantity} {good} and gained $100.")
            return

        # Player reactions to events
        if "tax" in event:
            tax_amount = 50
            self.player.money = max(0, self.player.money - tax_amount)
            slow_print(f"The government imposed a tax on your trade. You lost ${tax_amount}.")
            self.player.event_log.append(f"Turn {self.turn_counter}: Imposed tax of ${tax_amount}.")
            return

        # Implement event effects
        if "Economic boom" in event:
            affected_good = "Gems"
            price_boost = int(GOODS[affected_good]["base_price"] * 0.4)
            self.current_market.demand[affected_good] += 50
            self.current_market.prices[affected_good] += price_boost
            slow_print(f"An economic boom raised the demand and price of {affected_good} by ${price_boost}.")
            self.player.relationships[self.player.location] += 10
            return
        elif "Market crash" in event:
            affected_good = "Spices"
            price_drop = int(GOODS[affected_good]["base_price"] * 0.35)
            self.current_market.demand[affected_good] = max(50, self.current_market.demand[affected_good] - 100)
            self.current_market.prices[affected_good] = max(Market.PRICE_FLOOR, self.current_market.prices[affected_good] - price_drop)
            slow_print(f"A market crash decreased the demand and price of {affected_good} by ${price_drop}.")
            self.player.relationships[self.player.location] -= 10
            return
        elif "thieves" in event or "bandit" in event:
            stolen_good = random.choice(list(GOODS.keys()))
            stolen_qty = random.randint(2, 10)
            actual_stolen = min(stolen_qty, self.player.inventory[stolen_good])
            self.player.inventory[stolen_good] -= actual_stolen
            self.player.remove_cargo(stolen_good, actual_stolen)
            # Partial impact on market
            self.current_market.supply[stolen_good] += actual_stolen * 0.2
            self.current_market.demand[stolen_good] -= actual_stolen * 0.2
            slow_print(f"Bandits stole {actual_stolen} units of {stolen_good} from your cargo!")
            self.player.relationships[self.player.location] -= 15
            return
        elif "storm" in event or "natural disaster" in event:
            damaged_good = random.choice(list(GOODS.keys()))
            damaged_qty = random.randint(2, 10)
            actual_damaged = min(damaged_qty, self.player.inventory[damaged_good])
            self.player.inventory[damaged_good] -= actual_damaged
            self.player.remove_cargo(damaged_good, actual_damaged)
            # Partial impact on market
            self.current_market.supply[damaged_good] += actual_damaged * 0.1
            self.current_market.demand[damaged_good] -= actual_damaged * 0.1
            slow_print(f"A storm damaged {actual_damaged} units of {damaged_good} in your cargo.")
            self.player.relationships[self.player.location] -= 5
            return
        elif "festival" in event:
            affected_good = random.choice(["Spices", "Wine", "Cloth"])
            price_boost = int(GOODS[affected_good]["base_price"] * 0.3)
            self.current_market.demand[affected_good] += 50
            self.current_market.prices[affected_good] += price_boost
            slow_print(f"The festival increased the demand for {affected_good}, boosting its price by ${price_boost}.")
            self.player.relationships[self.player.location] += 5
            return
        elif "disease" in event:
            affected_good = "Food"
            price_drop = int(GOODS[affected_good]["base_price"] * 0.2)
            self.current_market.demand[affected_good] = max(50, self.current_market.demand[affected_good] - 100)
            self.current_market.prices[affected_good] = max(Market.PRICE_FLOOR, self.current_market.prices[affected_good] - price_drop)
            slow_print(f"A disease outbreak decreased the demand for {affected_good}, lowering its price by ${price_drop}.")
            self.player.relationships[self.player.location] -= 10
            return
        elif "trade routes" in event:
            affected_good = random.choice(list(GOODS.keys()))
            supply_change = random.randint(-30, 30)
            self.current_market.supply[affected_good] = max(10, self.current_market.supply[affected_good] + supply_change)
            slow_print(f"New trade routes have altered the supply of {affected_good}, changing its supply by {supply_change} units.")
            return
        elif "pirates" in event:
            affected_good = random.choice(list(GOODS.keys()))
            price_drop = int(GOODS[affected_good]["base_price"] * 0.25)
            self.current_market.demand[affected_good] = max(50, self.current_market.demand[affected_good] - 50)
            self.current_market.prices[affected_good] = max(Market.PRICE_FLOOR, self.current_market.prices[affected_good] - price_drop)
            slow_print(f"Pirates disrupted trade, decreasing the demand and price of {affected_good} by ${price_drop}.")
            self.player.relationships[self.player.location] -= 10
            return
        elif "rare gem" in event:
            affected_good = "Gems"
            supply_increase = 50
            self.current_market.supply[affected_good] = max(10, self.current_market.supply[affected_good] + supply_increase)
            self.current_market.demand[affected_good] -= 30
            slow_print(f"Discovery of a rare gem deposit increased the supply of {affected_good}, lowering its price.")
            return
        elif "locusts" in event:
            affected_good = "Food"
            damage = random.randint(5, 10)
            actual_damaged = min(damage, self.player.inventory[affected_good])
            self.player.inventory[affected_good] -= actual_damaged
            self.player.remove_cargo(affected_good, actual_damaged)
            # Partial impact on market
            self.current_market.supply[affected_good] += actual_damaged * 0.2
            self.current_market.demand[affected_good] -= actual_damaged * 0.2
            slow_print(f"Locusts devastated your food supplies, destroying {actual_damaged} units of {affected_good}.")
            self.player.relationships[self.player.location] -= 5
            return
        elif "artisans" in event:
            affected_good = "Spices"
            price_boost = int(GOODS[affected_good]["base_price"] * 0.25)
            self.current_market.demand[affected_good] += 40
            self.current_market.prices[affected_good] += price_boost
            slow_print(f"Artisans in {self.player.location} created new uses for {affected_good}, increasing its demand and price by ${price_boost}.")
            self.player.relationships[self.player.location] += 10
            return
        elif "global" in event.lower():
            # Handle generic global events
            if "economic boom" in event.lower():
                for market in self.markets.values():
                    affected_good = "Gold"
                    price_boost = int(GOODS[affected_good]["base_price"] * 0.2)
                    market.demand[affected_good] += 30
                    market.prices[affected_good] += price_boost
                slow_print("A global economic boom has increased the demand and prices for Gold across all markets.")
            elif "global recession" in event.lower():
                for market in self.markets.values():
                    affected_good = "Food"
                    price_drop = int(GOODS[affected_good]["base_price"] * 0.15)
                    market.demand[affected_good] = max(50, market.demand[affected_good] - 50)
                    market.prices[affected_good] = max(Market.PRICE_FLOOR, market.prices[affected_good] - price_drop)
                slow_print("A global recession has decreased the demand and prices for Food across all markets.")

    def apply_decay(self):
        """Applies decay to supply and demand in all markets to move towards base values."""
        for good, info in GOODS.items():
            for market in self.markets.values():
                # Supply decay towards base_supply
                if market.supply[good] < info["base_supply"]:
                    market.supply[good] += info["base_supply"] * self.supply_decay_rate
                    if market.supply[good] > info["base_supply"]:
                        market.supply[good] = info["base_supply"]
                elif market.supply[good] > info["base_supply"]:
                    market.supply[good] -= info["base_supply"] * self.supply_decay_rate
                    if market.supply[good] < info["base_supply"]:
                        market.supply[good] = info["base_supply"]

                # Demand decay towards base_demand
                if market.demand[good] < info["base_demand"]:
                    market.demand[good] += info["base_demand"] * self.demand_decay_rate
                    if market.demand[good] > info["base_demand"]:
                        market.demand[good] = info["base_demand"]
                elif market.demand[good] > info["base_demand"]:
                    market.demand[good] -= info["base_demand"] * self.demand_decay_rate
                    if market.demand[good] < info["base_demand"]:
                        market.demand[good] = info["base_demand"]

    def end_game(self):
        """Displays the final game results and concludes the game."""
        slow_print("\nGame Over!")
        fast_print(f"Final Money: ${self.player.money}")
        total_goods = sum(self.player.inventory.values())
        fast_print(f"Total Goods: {total_goods}")
        net_worth = self.player.money + sum(
            self.player.inventory[good] * self.current_market.prices[good] for good in GOODS
        )
        fast_print(f"Net Worth: ${net_worth}")
        if net_worth >= 10000:
            slow_print("Congratulations! You became a legendary trader!")
        elif net_worth >= 5000:
            slow_print("Well done! You made a substantial profit.")
        elif net_worth >= 2000:
            slow_print("Good job! You made a respectable profit.")
        else:
            slow_print("Better luck next time. Your trading skills need improvement.")

        # Display key events summary
        slow_print("\nSummary of Your Journey:")
        for event in self.key_events:
            fast_print(event)

        slow_print("\nThank you for playing the Text-Based Trading Game!")
        sys.exit()

# Main execution block
if __name__ == "__main__":
    game_instance = Game()
    game_instance.start()