Make the difficulty selection after the initial messages and and split up the initial messages so that the = signs are printed instantly.


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.
Build relationships with towns to unlock exclusive opportunities.
{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 >= 70:
        return "Ally"
    elif relation >= 30:
        return "Friendly"
    elif relation >= -30:
        return "Neutral"
    elif relation >= -70:
        return "Hostile"
    else:
        return "Enemy"

# 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},
}

# Exclusive Goods (Do not modify during runtime)
EXCLUSIVE_GOODS = {
    "Luxury Silk": {"base_price": 2000, "weight": 15, "base_supply": 50, "base_demand": 30},
    "Ancient Relics": {"base_price": 3000, "weight": 25, "base_supply": 30, "base_demand": 20},
    "Exquisite Artwork": {"base_price": 2500, "weight": 10, "base_supply": 40, "base_demand": 25},
}

# Combined list of all goods for inventory and selection
ALL_GOODS = {**GOODS, **EXCLUSIVE_GOODS}

# 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."""
        # 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):
            # Decide action based on aggressiveness
            action = random.choices(["BUY", "SELL"], weights=[self.aggressiveness, 1.0])[0]
            # Choose a good to buy or sell, including exclusive goods
            good = random.choice(list(ALL_GOODS.keys()))
            # Determine quantity based on aggressiveness
            quantity = random.randint(1, max(1, int(10 * self.aggressiveness)))
            if action == "BUY":
                # AI trader buys goods: decrease supply, increase demand
                if market.supply.get(good, 0) >= 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] = market.supply.get(good, 0) + quantity
                market.demand[good] = market.demand.get(good, 0) - quantity * 0.5  # Increased impact
                if market.demand.get(good, 0) < 50:  # Prevent demand from going too low
                    market.demand[good] = 50

class Player:
    """Represents the player with money, inventory, and cargo capacity."""
    def __init__(self, starting_money, starting_cargo):
        self.money = starting_money
        # Initialize inventory with both regular and exclusive goods
        self.inventory = {good: 0 for good in GOODS}
        self.inventory.update({good: 0 for good in EXCLUSIVE_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
        self.reputation = 0  # Global reputation

    def modify_relationship(self, town, amount):
        """Modifies the relationship with a specific town."""
        self.relationships[town] += amount
        if self.relationships[town] > RELATIONSHIP_MAX:
            self.relationships[town] = RELATIONSHIP_MAX
        elif self.relationships[town] < RELATIONSHIP_MIN:
            self.relationships[town] = RELATIONSHIP_MIN

    def status(self):
        """Displays the player's current status with relationship details."""
        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}")
        fast_print("\nRelationships:")
        for town, relation in self.relationships.items():
            status = get_relationship_status(relation)
            fast_print(f"  {town}: {relation} ({status})")
        print()

    def add_cargo(self, good, quantity):
        """Attempts to add cargo to the player's inventory."""
        # Determine weight based on whether the good is regular or exclusive
        if good in GOODS:
            weight = GOODS[good]["weight"]
        elif good in EXCLUSIVE_GOODS:
            weight = EXCLUSIVE_GOODS[good]["weight"]
        else:
            weight = 5  # Default weight
        total_weight = weight * quantity
        if self.current_cargo + total_weight > self.max_cargo:
            return False, total_weight
        self.current_cargo += total_weight
        if good not in self.inventory:
            self.inventory[good] = 0
        self.inventory[good] += quantity
        return True, total_weight

    def remove_cargo(self, good, quantity):
        """Removes cargo from the player's inventory."""
        if good not in self.inventory:
            return
        # Determine weight based on whether the good is regular or exclusive
        if good in GOODS:
            weight = GOODS[good]["weight"]
        elif good in EXCLUSIVE_GOODS:
            weight = EXCLUSIVE_GOODS[good]["weight"]
        else:
            weight = 5  # Default weight
        total_weight = weight * quantity
        self.inventory[good] -= quantity
        self.current_cargo -= total_weight
        if self.inventory[good] < 0:
            self.inventory[good] = 0
        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 Market:
    """Represents the market of a specific town."""
    PRICE_FLOOR = 10
    PRICE_CEILING = 2000

    def __init__(self, town, player):
        self.town = town
        self.player = player
        # 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
        for good, info in EXCLUSIVE_GOODS.items():
            self.supply[good] = info["base_supply"] * random.uniform(0.9, 1.1)
            self.demand[good] = info["base_demand"] * random.uniform(0.9, 1.1)
        self.prices = {}
        self.exclusive_goods = []
        self.generate_exclusive_goods()
        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_exclusive_goods(self):
        """Assigns exclusive goods to towns based on relationships."""
        relationship_status = get_relationship_status(self.player.relationships[self.town])
        if relationship_status in ["Friendly", "Ally"]:
            # Assign exclusive goods
            possible_exclusives = list(EXCLUSIVE_GOODS.keys())
            # To ensure uniqueness, avoid reassigning already exclusive
            available_exclusives = [goods for goods in possible_exclusives if goods not in self.exclusive_goods]
            if available_exclusives:
                self.exclusive_goods = [random.choice(available_exclusives)]
            else:
                self.exclusive_goods = []
        else:
            self.exclusive_goods = []

    def generate_prices(self):
        """Calculates current prices based on supply, demand, and relationship with the player."""
        relation = self.player.relationships[self.town]
        relationship_modifier = self.get_relationship_modifier(relation)
        for good, info in GOODS.items():
            # Calculate price based on demand and supply with elasticity
            if self.supply.get(good, 0) == 0:
                price_multiplier = 2  # High price if no supply
            else:
                ratio = self.demand.get(good, 1) / self.supply.get(good, 1)
                elasticity = random.uniform(0.90, 1.10)
                price_multiplier = ratio * elasticity
            new_price = int(GOODS[good]["base_price"] * price_multiplier * relationship_modifier)
            new_price = max(self.PRICE_FLOOR, min(new_price, self.PRICE_CEILING))
            self.prices[good] = new_price

        # Set prices for exclusive goods
        for good in self.exclusive_goods:
            exclusive_info = EXCLUSIVE_GOODS.get(good, {})
            if exclusive_info:
                # Pricing exclusive goods higher, perhaps with slight variation
                base_price = exclusive_info["base_price"]
                # Apply relationship_modifier if needed
                new_price = int(base_price * relationship_modifier)
                new_price = max(self.PRICE_FLOOR, min(new_price, self.PRICE_CEILING))
                self.prices[good] = new_price

    def get_relationship_modifier(self, relation):
        """Determines price modifiers based on the relationship status."""
        status = get_relationship_status(relation)
        if status == "Ally":
            return 0.85  # 15% discount for buying, 15% bonus for selling
        elif status == "Friendly":
            return 0.90  # 10% discount
        elif status == "Hostile":
            return 1.10  # 10% price increase
        elif status == "Enemy":
            return 1.25  # 25% price increase
        else:
            return 1.0  # Neutral

    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.get(good, 0))
            demand = int(self.demand.get(good, 0))
            color = Fore.GREEN if status in ["Ally", "Friendly"] else Fore.RED if status in ["Hostile", "Enemy"] else Fore.YELLOW
            fast_print(f"{color}{good}: ${price} (Supply: {supply}, Demand: {demand}){Style.RESET_ALL}")
        # Display Exclusive Goods
        if self.exclusive_goods:
            slow_print(f"\n{Fore.CYAN}Exclusive Goods Available:{Style.RESET_ALL}")
            for good in self.exclusive_goods:
                price = self.prices.get(good, EXCLUSIVE_GOODS.get(good, {}).get("base_price", 2000))
                supply = int(self.supply.get(good, 0))
                demand = int(self.demand.get(good, 0))
                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 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, self.player) 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 or exits."""
        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.get(good, GOODS.get(good, {}).get("base_price", 100))
        # Calculate max affordable based on money
        max_affordable_quantity = self.player.money // price
        # Calculate max based on cargo
        if good in GOODS:
            good_weight = GOODS[good]["weight"]
        elif good in EXCLUSIVE_GOODS:
            good_weight = EXCLUSIVE_GOODS[good]["weight"]
        else:
            good_weight = 5  # Default weight
        available_cargo_space = self.player.max_cargo - self.player.current_cargo
        max_cargo_quantity = available_cargo_space // good_weight
        # Calculate max based on supply
        max_supply = int(self.current_market.supply.get(good, 0))

        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.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}.")

        # Modify relationship based on trade
        supportive_goods = ["Food", "Herbs", "Cloth"]
        if good in supportive_goods and quantity >= max_quantity * 0.5:
            self.player.modify_relationship(self.player.location, 5)
            self.player.event_log.append(f"Turn {self.turn_counter}: Bought large quantity of {good}, improved relationship.")
            self.key_events.append(f"Turn {self.turn_counter}: Bought large quantity of {good}, improved relationship.")

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

        max_sell_quantity = int(self.player.inventory.get(good, 0))

        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.get(good, GOODS.get(good, {}).get("base_price", 100))
        revenue = price * quantity

        # Update player and market
        self.player.money += revenue
        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}.")

        # Modify relationship based on trade
        needed_goods = ["Gems", "Iron", "Gold"]
        if good in needed_goods and quantity >= max_sell_quantity * 0.5:
            self.player.modify_relationship(self.player.location, 5)
            self.player.event_log.append(f"Turn {self.turn_counter}: Sold large quantity of {good}, improved relationship.")
            self.key_events.append(f"Turn {self.turn_counter}: Sold large quantity of {good}, improved relationship.")

    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:")
        all_goods = list(ALL_GOODS.keys())
        for idx, good in enumerate(all_goods, 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(all_goods)):
            fast_print("Invalid choice.")
            return None
        return all_goods[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(market.prices) if market.prices else 0
            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."""
        # Handle events based on their descriptions
        # This implementation assumes event strings contain specific keywords
        # Adjust based on actual event descriptions

        # Player-specific positive events (Example)
        if "found extra goods" in event:
            good = random.choice(list(ALL_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.modify_relationship(self.player.location, 5)
            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.modify_relationship(self.player.location, -10)
            self.player.event_log.append(f"Turn {self.turn_counter}: Imposed tax of ${tax_amount}.")
            return

        # Implement event effects with relationship modifications
        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.modify_relationship(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.get(affected_good, 0) - 100)
            self.current_market.prices[affected_good] = max(Market.PRICE_FLOOR, self.current_market.prices.get(affected_good, 0) - price_drop)
            slow_print(f"A market crash decreased the demand and price of {affected_good} by ${price_drop}.")
            self.player.modify_relationship(self.player.location, -10)
            return
        elif "thieves" in event or "bandit" in event:
            stolen_good = random.choice(list(ALL_GOODS.keys()))
            stolen_qty = random.randint(2, 10)
            actual_stolen = min(stolen_qty, self.player.inventory.get(stolen_good, 0))
            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] = self.current_market.supply.get(stolen_good, 0) + actual_stolen * 0.2
            self.current_market.demand[stolen_good] = self.current_market.demand.get(stolen_good, 0) - actual_stolen * 0.2
            slow_print(f"Bandits stole {actual_stolen} units of {stolen_good} from your cargo!")
            self.player.modify_relationship(self.player.location, -15)
            return
        elif "storm" in event or "natural disaster" in event:
            damaged_good = random.choice(list(ALL_GOODS.keys()))
            damaged_qty = random.randint(2, 10)
            actual_damaged = min(damaged_qty, self.player.inventory.get(damaged_good, 0))
            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] = self.current_market.supply.get(damaged_good, 0) + actual_damaged * 0.1
            self.current_market.demand[damaged_good] = self.current_market.demand.get(damaged_good, 0) - actual_damaged * 0.1
            slow_print(f"A storm damaged {actual_damaged} units of {damaged_good} in your cargo.")
            self.player.modify_relationship(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.modify_relationship(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.get(affected_good, 0) - 100)
            self.current_market.prices[affected_good] = max(Market.PRICE_FLOOR, self.current_market.prices.get(affected_good, 0) - price_drop)
            slow_print(f"A disease outbreak decreased the demand for {affected_good}, lowering its price by ${price_drop}.")
            self.player.modify_relationship(self.player.location, -10)
            return
        elif "trade routes" in event:
            affected_good = random.choice(list(ALL_GOODS.keys()))
            supply_change = random.randint(-30, 30)
            self.current_market.supply[affected_good] = max(10, self.current_market.supply.get(affected_good, 0) + supply_change)
            slow_print(f"New trade routes have altered the supply of {affected_good}, changing its supply by {supply_change} units.")
            # Neutral impact on relationships
            return
        elif "pirates" in event:
            affected_good = random.choice(list(ALL_GOODS.keys()))
            price_drop = int(GOODS[affected_good]["base_price"] * 0.25)
            self.current_market.demand[affected_good] = max(50, self.current_market.demand.get(affected_good, 0) - 50)
            self.current_market.prices[affected_good] = max(Market.PRICE_FLOOR, self.current_market.prices.get(affected_good, 0) - price_drop)
            slow_print(f"Pirates disrupted trade, decreasing the demand and price of {affected_good} by ${price_drop}.")
            self.player.modify_relationship(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.get(affected_good, 0) + supply_increase)
            self.current_market.demand[affected_good] = max(50, self.current_market.demand.get(affected_good, 0) - 30)
            slow_print(f"Discovery of a rare gem deposit increased the supply of {affected_good}, lowering its price.")
            self.player.modify_relationship(self.player.location, 5)
            return
        elif "locusts" in event:
            affected_good = "Food"
            damage = random.randint(5, 10)
            actual_damaged = min(damage, self.player.inventory.get(affected_good, 0))
            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] = self.current_market.supply.get(affected_good, 0) + actual_damaged * 0.2
            self.current_market.demand[affected_good] = self.current_market.demand.get(affected_good, 0) - actual_damaged * 0.2
            slow_print(f"Locusts devastated your food supplies, destroying {actual_damaged} units of {affected_good}.")
            self.player.modify_relationship(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.modify_relationship(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.")
                # Potential global reputation impact
                self.player.reputation += 5
            elif "economic 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.get(affected_good, 0) - 50)
                    market.prices[affected_good] = max(Market.PRICE_FLOOR, market.prices.get(affected_good, 0) - price_drop)
                slow_print("A global recession has decreased the demand and prices for Food across all markets.")
                self.player.reputation -= 5

    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.get(good, 0) < info["base_supply"]:
                    increment = info["base_supply"] * self.supply_decay_rate
                    market.supply[good] += increment
                    if market.supply[good] > info["base_supply"]:
                        market.supply[good] = info["base_supply"]
                elif market.supply.get(good, 0) > info["base_supply"]:
                    decrement = info["base_supply"] * self.supply_decay_rate
                    market.supply[good] -= decrement
                    if market.supply[good] < info["base_supply"]:
                        market.supply[good] = info["base_supply"]

                # Demand decay towards base_demand
                if market.demand.get(good, 0) < info["base_demand"]:
                    increment = info["base_demand"] * self.demand_decay_rate
                    market.demand[good] += increment
                    if market.demand[good] > info["base_demand"]:
                        market.demand[good] = info["base_demand"]
                elif market.demand.get(good, 0) > info["base_demand"]:
                    decrement = info["base_demand"] * self.demand_decay_rate
                    market.demand[good] -= decrement
                    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.get(good, 0) * self.current_market.prices.get(good, 0) for good in ALL_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()

    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 or exits."""
        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 apply_decay(self):
        """Applies decay to supply and demand in all markets to move towards base values."""
        # Implementation already exists above
        # To avoid duplication, ensure we're not redefining this method
        pass  # Placeholder to prevent duplication

    # To ensure that the apply_decay logic within Game is correctly implemented,
    # we'll redefine it here as a class method.

    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.get(good, 0) < info["base_supply"]:
                    increment = info["base_supply"] * self.supply_decay_rate
                    market.supply[good] += increment
                    if market.supply[good] > info["base_supply"]:
                        market.supply[good] = info["base_supply"]
                elif market.supply.get(good, 0) > info["base_supply"]:
                    decrement = info["base_supply"] * self.supply_decay_rate
                    market.supply[good] -= decrement
                    if market.supply[good] < info["base_supply"]:
                        market.supply[good] = info["base_supply"]

                # Demand decay towards base_demand
                if market.demand.get(good, 0) < info["base_demand"]:
                    increment = info["base_demand"] * self.demand_decay_rate
                    market.demand[good] += increment
                    if market.demand[good] > info["base_demand"]:
                        market.demand[good] = info["base_demand"]
                elif market.demand.get(good, 0) > info["base_demand"]:
                    decrement = info["base_demand"] * self.demand_decay_rate
                    market.demand[good] -= decrement
                    if market.demand[good] < info["base_demand"]:
                        market.demand[good] = info["base_demand"]

# Main execution block with error handling
if __name__ == "__main__":
    try:
        game_instance = Game()
        game_instance.start()
    except Exception as e:
        print(f"\n{Fore.RED}An unexpected error occurred: {e}{Style.RESET_ALL}")
        sys.exit(1)