It's impossible to get a good final score for relations. Is there a way we could fix that?


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 Text without the '=' lines, with yellow coloring
WELCOME_TEXT = f"""{Fore.YELLOW}Welcome to the Text-Based Trading Game!
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.
Be mindful of your relationships with towns—they play a crucial role in your success.{Style.RESET_ALL}"""

# HELP Text with detailed rules and trading categories
HELP_TEXT = f"""
{Fore.GREEN}Game Rules and Instructions:{Style.RESET_ALL}

1. {Fore.YELLOW}Objective:{Style.RESET_ALL}
   Accumulate as much wealth as possible within the allotted number of turns.

2. {Fore.YELLOW}Commands:{Style.RESET_ALL}
   - {Fore.CYAN}BUY:{Style.RESET_ALL} Purchase goods from the market.
   - {Fore.CYAN}SELL:{Style.RESET_ALL} Sell goods from your inventory.
   - {Fore.CYAN}TRAVEL:{Style.RESET_ALL} Move to a different town.
   - {Fore.CYAN}STATUS:{Style.RESET_ALL} View your current status, inventory, and relationships.
   - {Fore.CYAN}UPGRADE:{Style.RESET_ALL} Upgrade your cargo capacity.
   - {Fore.CYAN}NETWORK:{Style.RESET_ALL} Get rumors and information about other towns.
   - {Fore.CYAN}HELP:{Style.RESET_ALL} View the game rules and trading categories.
   - {Fore.CYAN}EXIT:{Style.RESET_ALL} Exit the game.

3. {Fore.YELLOW}Goods Categories and Their Impact on Relationships:{Style.RESET_ALL}
   - {Fore.CYAN}Supportive Goods:{Style.RESET_ALL} Food, Herbs, Cloth, Tea
     - Buying or selling improves {Fore.CYAN}Reputation{Style.RESET_ALL}.
   - {Fore.CYAN}Strategic Goods:{Style.RESET_ALL} Gold, Gems, Iron
     - Buying or selling affects {Fore.CYAN}Trade Relations{Style.RESET_ALL}.
   - {Fore.CYAN}Luxury Goods:{Style.RESET_ALL} Silk, Wine, Spices
     - Buying or selling influences {Fore.CYAN}Favor{Style.RESET_ALL}.

4. {Fore.YELLOW}Trading Tips:{Style.RESET_ALL}
   - All trading actions significantly impact relationships.
   - Relationships affect prices and trading conditions.
   - Events can drastically alter your relationships.

5. {Fore.YELLOW}Relationships with Towns:{Style.RESET_ALL}
   - {Fore.CYAN}Trade:{Style.RESET_ALL} Reflects your trading history with the town.
   - {Fore.CYAN}Reputation:{Style.RESET_ALL} Represents your overall standing and trustworthiness.
   - {Fore.CYAN}Favor:{Style.RESET_ALL} Indicates personal favor and goodwill from the town.

6. {Fore.YELLOW}Events:{Style.RESET_ALL}
   - Random events may occur, impacting markets and relationships.
   - Your global reputation can influence the likelihood of events.

7. {Fore.YELLOW}Turn Mechanics:{Style.RESET_ALL}
   - Actions like {Fore.CYAN}BUY, SELL, TRAVEL,{Style.RESET_ALL} and {Fore.CYAN}UPGRADE{Style.RESET_ALL} consume a turn.
   - Viewing {Fore.CYAN}STATUS, NETWORK,{Style.RESET_ALL} or {Fore.CYAN}HELP{Style.RESET_ALL} does not consume a turn.
   - {Fore.CYAN}Note:{Style.RESET_ALL} You can only use {Fore.CYAN}NETWORK{Style.RESET_ALL} once per turn.

{Style.RESET_ALL}
"""

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

# Goods categories for relationship impact
SUPPORTIVE_GOODS = ["Food", "Herbs", "Cloth", "Tea"]
STRATEGIC_GOODS = ["Gold", "Gems", "Iron"]
LUXURY_GOODS = ["Silk", "Wine", "Spices"]

# Combined list of all goods for inventory and selection
ALL_GOODS = GOODS.copy()

# 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 = [
    # Existing negative global events
    "Global trade embargo reducing supply worldwide.",
    "Pandemic affecting demand for certain goods globally.",
    "Global inflation increasing prices across the board.",
    "Global recession decreasing purchasing power.",
    # Positive global events
    "A global trade agreement has been signed, reducing tariffs.",
    "Technological advancements have improved trade efficiency worldwide.",
    "A global festival increases demand for luxury goods.",
]

LOCAL_EVENTS = [
    # Existing negative local events
    "Thieves attacked your caravan and stole some goods!",
    "A storm ruined your goods during travel.",
    "Disease outbreak decreased the demand for food.",
    "Pirates disrupted trade in the seas.",
    "Government imposed a tax on trade.",
    "Locusts devastated the food supplies in Dusktown.",
    "Bandit attack in Oakwood stole some of your goods.",
    "Natural disaster in Dusktown affecting multiple goods.",
    # Positive local events
    "You found a hidden stash of goods in the market!",
    "A wealthy patron gifts you valuable items!",
    "Your reputation has earned you a local tax exemption!",
    "A local festival boosts demand and prices for certain goods.",
    "Favorable winds reduce travel times temporarily.",
    "Merchants admire your honesty, improving relationships.",
    "An influential guild offers you a partnership.",
    "An overstock in the market reduces prices for certain goods.",
    "Local artisans gift you exquisite items to trade.",
    "Successful mediation improves trade relations between towns.",
]

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

# Difficulty settings
DIFFICULTIES = {
    "EASY": {
        "event_chance": 0.12,
        "ai_aggressiveness": 0.7,
        "starting_money": 4000,
        "starting_cargo": 350,
        "turns": 50
    },
    "MEDIUM": {
        "event_chance": 0.2,
        "ai_aggressiveness": 1.0,
        "starting_money": 2500,
        "starting_cargo": 200,
        "turns": 35
    },
    "HARD": {
        "event_chance": 0.3,
        "ai_aggressiveness": 1.5,
        "starting_money": 1800,
        "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
            goods_choices = list(ALL_GOODS.keys())
            goods_prob = []
            total_goods = len(goods_choices)
            for good in goods_choices:
                if good == "Gold":
                    # Further reduce the probability for Gold
                    goods_prob.append(0.05)  # Very low probability
                elif good == "Gems":
                    # Slightly reduce the probability for Gems
                    goods_prob.append(0.1)
                else:
                    # Distribute the remaining probability among other goods
                    goods_prob.append(1.0)  # Assign higher weight to other goods

            # Normalize the weights
            total_weight = sum(goods_prob)
            normalized_weights = [w / total_weight for w in goods_prob]

            good = random.choices(goods_choices, weights=normalized_weights, k=1)[0]

            # Determine quantity based on aggressiveness
            quantity = random.randint(1, max(1, int(10 * self.aggressiveness)))  # Reduced max quantity
            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  # Reduced 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  # Reduced impact
                if market.demand.get(good, 0) < 50:  # Prevent demand from going too low
                    market.demand[good] = 50

class Player:
    def __init__(self, starting_money, starting_cargo, game):
        self.starting_money = starting_money
        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: {
            "Trade": RELATIONSHIP_BASE,
            "Reputation": RELATIONSHIP_BASE,
            "Favor": RELATIONSHIP_BASE
        } for town in TOWNS}
        self.event_log = []
        self.reputation = 0
        self.game = game  # Reference to the game instance

    def modify_relationship(self, town, aspect, amount):
        multiplier = self.game.relation_multiplier
        adjusted_amount = int(amount * multiplier)
        new_score = self.relationships[town][aspect] + adjusted_amount
        new_score = int(max(RELATIONSHIP_MIN, min(new_score, RELATIONSHIP_MAX)))
        change = new_score - self.relationships[town][aspect]
        self.relationships[town][aspect] = new_score
        # Notify the player about the change
        if change > 0:
            slow_print(f"[{town} - {aspect}] Improved by {change} points!")
        elif change < 0:
            slow_print(f"[{town} - {aspect}] Worsened by {-change} points!")

    def get_overall_relationship_status(self, town):
        """Determines the overall relationship status based on individual aspects."""
        aspects = self.relationships[town]
        # Calculate average of all aspects
        average = sum(aspects.values()) / len(aspects)
        return get_relationship_status(average)

    def status(self):
        """Displays the player's current status with detailed relationship aspects."""
        slow_print(f"\n{Fore.GREEN}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():
            if qty > 0:
                fast_print(f"  {good}: {qty}")
        # Display relationships with detailed aspects
        fast_print("\nRelationships:")
        for town, aspects in self.relationships.items():
            overall_status = self.get_overall_relationship_status(town)
            relationship_info = ', '.join([
                f"{Fore.CYAN}{aspect}: {score}{Style.RESET_ALL}" for aspect, score in aspects.items()
            ])
            if overall_status in ["Ally", "Friendly"]:
                status_color = Fore.GREEN
            elif overall_status in ["Hostile", "Enemy"]:
                status_color = Fore.RED
            else:
                status_color = Fore.YELLOW
            fast_print(f"  {town}: {relationship_info} | Overall: {status_color}{overall_status}{Style.RESET_ALL}")
        print()

    def status_short(self):
        """Displays the player's current status without relationship aspects."""
        slow_print(f"\n{Fore.GREEN}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():
            if qty > 0:
                fast_print(f"  {good}: {qty}")   
        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
        if good in GOODS:
            weight = 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
        if good in GOODS:
            weight = 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 False  # Indicate that no upgrade was made
        confirm = input(f"Upgrade cargo capacity by {upgrade_amount} for ${upgrade_cost}? (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}.")
            return True  # Indicate that upgrade was successful
        elif confirm == 'N':
            slow_print("Upgrade canceled.")
            return False  # Indicate that no upgrade was made
        else:
            slow_print("ERROR: Invalid Input")
            return False  # Indicate that no upgrade was made

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 increased random variations
        self.supply = {}
        self.demand = {}
        for good, info in GOODS.items():
            supply_variation = random.uniform(0.6, 1.4)  # Increased range from 0.6-1.4
            demand_variation = random.uniform(0.6, 1.4)  # Increased range from 0.6-1.4
            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.7, 1.5)) for i in range(10)]  # 10 AI traders per town

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

    def get_relationship_modifier(self, town):
        """Determines price modifiers based on multiple relationship aspects."""
        aspects = self.player.relationships[town]
        trade = aspects["Trade"]
        reputation = aspects["Reputation"]
        favor = aspects["Favor"]

        # Calculate individual modifiers
        if trade >= 80:
            trade_modifier = 0.60  # Increased discount: 40% discount
        elif trade >= 50:
            trade_modifier = 0.80  # 20% discount
        elif trade >= -20:
            trade_modifier = 1.00  # Neutral
        elif trade >= -60:
            trade_modifier = 1.25  # 25% price increase
        else:
            trade_modifier = 1.50  # 50% price increase

        if reputation >= 70:
            reputation_modifier = 0.85  # 15% discount
        elif reputation >= 40:
            reputation_modifier = 0.90  # 10% discount
        else:
            reputation_modifier = 1.00  # Neutral

        if favor >= 60:
            favor_modifier = 0.90  # 10% discount
        else:
            favor_modifier = 1.00  # Neutral

        # Combine modifiers by averaging
        overall_modifier = (trade_modifier + reputation_modifier + favor_modifier) / 3
        return overall_modifier

    def display_prices(self):
        """Displays the current prices, supply, and demand for all goods in the market."""
        slow_print(f"\n{Fore.GREEN}Market Overview in {self.town}:{Style.RESET_ALL}")
        for good, price in self.prices.items():
            supply = int(self.supply.get(good, 0))
            demand = int(self.demand.get(good, 0))
            fast_print(f"{Fore.YELLOW}{good}: ${price} (Supply: {supply}, Demand: {demand}){Style.RESET_ALL}")
        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):
        # Difficulty selection will be done in start()
        self.player = None
        self.difficulty = None
        self.starting_money = None  # Will be set during game start
        self.turns_total = 0
        self.markets = {}
        self.current_market = None
        self.current_event = None
        # Define decay rates to return supply and demand towards base values
        self.supply_decay_rate = 0.03  # Reduced decay rate for slower stabilization
        self.demand_decay_rate = 0.03  # Reduced decay rate for slower stabilization
        self.turn_counter = 1
        self.relation_multiplier = 1.5  # Adjust this value as desired
        self.game_over = False
        self.key_events = []  # To track key events for summary
        # New variables to track per-turn actions
        self.network_used = False  # To track if NETWORK command has been used in the current turn
        self.consecutive_travels = 0  # To track consecutive travels
        self.last_command = None  # To track the last command issued by the player

    def choose_difficulty(self):
        """Allows the player to choose a difficulty level."""
        fast_print("\nChoose 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)
        # Print the '=' lines separately in yellow without extra line breaks
        fast_print(f"""{Fore.YELLOW}{'='*60}{Style.RESET_ALL}""")
        medium_print(WELCOME_TEXT)
        fast_print(f"""{Fore.YELLOW}{'='*60}{Style.RESET_ALL}""")
        # Now choose difficulty
        self.difficulty = self.choose_difficulty()
        # Initialize player and markets after difficulty is chosen
        self.starting_money = DIFFICULTIES[self.difficulty]["starting_money"]
        self.player = Player(
            starting_money=self.starting_money,
            starting_cargo=DIFFICULTIES[self.difficulty]["starting_cargo"],
            game=self  # Pass the game instance
        )
        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]
        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:
            # Start of turn
            medium_print(f"\n--- Turn {self.turn_counter}/{self.turns_total} ---")
            # Reset per-turn flags
            self.network_used = False  # Reset NETWORK usage at the start of each turn

            # Handle consecutive traveling
            if self.last_command != "TRAVEL":
                self.consecutive_travels = 0  # Reset counter if player did something else

            self.last_command = None  # Reset last command at the start of the turn

            # Display player status (excluding relationships)
            self.player.status_short()
            # Display prices for the current market
            self.current_market.display_prices()

            turn_consumed = False
            while not turn_consumed and not self.game_over:
                command = input("Enter command (BUY/SELL/TRAVEL/STATUS/UPGRADE/NETWORK/HELP/EXIT): ").strip().upper()
                while command not in ["BUY", "SELL", "TRAVEL", "STATUS", "UPGRADE", "NETWORK", "HELP", "EXIT"]:
                    slow_print("ERROR: Invalid Input")
                    command = input("Enter command (BUY/SELL/TRAVEL/STATUS/UPGRADE/NETWORK/HELP/EXIT): ").strip().upper()
                self.last_command = command  # Store the last command

                if command == "STATUS":
                    self.player.status()
                elif command == "NETWORK":
                    if not self.network_used:
                        self.check_network()
                        self.network_used = True  # Mark as used for this turn
                    else:
                        slow_print("You have already used the NETWORK command this turn.")
                elif command == "HELP":
                    print(f"{Fore.YELLOW}{'='*60}{Style.RESET_ALL}")
                    fast_print(HELP_TEXT)
                    print(f"{Fore.YELLOW}{'='*60}{Style.RESET_ALL}")
                elif command == "EXIT":
                    slow_print("Thank you for playing!")
                    self.end_game()
                    return  # Exit the game loop
                elif command in ["BUY", "SELL", "TRAVEL", "UPGRADE"]:
                    # Process commands that consume a turn
                    if command == "BUY":
                        action_successful = self.buy()
                        turn_consumed = action_successful
                    elif command == "SELL":
                        action_successful = self.sell()
                        turn_consumed = action_successful
                    elif command == "TRAVEL":
                        action_successful, turn_consumed = self.travel()
                    elif command == "UPGRADE":
                        action_successful = self.player.upgrade_cargo()
                        turn_consumed = action_successful

                    if action_successful:
                        if turn_consumed:
                            # At this point, a turn has passed
                            # Process AI traders and events
                            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()
                            # Regenerate prices after events
                            self.current_market.generate_prices()
                            self.turn_counter += 1

                            # Decay relationships over time
                            self.apply_relationship_decay()

                            # Check if the game should end after the turn
                            if self.turn_counter > self.turns_total:
                                self.game_over = True  # Set game over to True
                                break  # Break out of the inner while loop
                        else:
                            # Action was successful, but turn was not consumed (e.g., free travel)
                            pass
                    else:
                        # Action failed; inform player and allow them to try again
                        slow_print("Action could not be completed. Please choose another action.")
                        # Do not consume turn
                else:
                    # Invalid command (shouldn't reach here due to earlier validation)
                    slow_print("ERROR: Invalid Input")
        # After the loop ends, call end_game
        self.end_game()
        return  # Ensure the method exits after ending the game
    
    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())
        while True:
            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)):
                slow_print("ERROR: Invalid Input. Please enter a valid number.")
                continue
            return all_goods[int(choice) - 1]

    def check_network(self):
        """Provides rumors about the status of other towns in the merchant network."""
        medium_print(f"\n{Fore.GREEN}Merchant Network Rumors:{Style.RESET_ALL}")
        for town, market in self.markets.items():
            status = self.player.get_overall_relationship_status(town)
            rumor = self.generate_rumor(town, market, status)
            if status in ["Ally", "Friendly"]:
                color = Fore.CYAN
            elif status in ["Hostile", "Enemy"]:
                color = Fore.RED
            else:
                color = Fore.YELLOW
            fast_print(f"{color}{town}:{Style.RESET_ALL}")
            fast_print(f" {rumor}")
        print()

    def generate_rumor(self, town, market, status):
        """Generates a rumor based on the town's market and relationship status."""
        # Base rumor based on relationship
        if status == "Ally":
            base_rumor = f"{Fore.BLUE}is thriving and their trade is booming.{Style.RESET_ALL}"
        elif status == "Friendly":
            base_rumor = f"{Fore.GREEN}is experiencing steady trade.{Style.RESET_ALL}"
        elif status == "Neutral":
            base_rumor = f"{Fore.YELLOW}has a balanced market with no major changes.{Style.RESET_ALL}"
        elif status == "Hostile":
            base_rumor = f"{Fore.RED}is facing some challenges, causing minor disruptions in trade.{Style.RESET_ALL}"
        else:  # Enemy
            base_rumor = f"{Fore.RED}is in turmoil, significantly affecting their market and relations.{Style.RESET_ALL}"

        # Select multiple goods to include in the rumor
        affected_goods = random.sample(list(ALL_GOODS.keys()), k=random.randint(1, 3))  # Affect 1 to 3 goods

        goods_rumors = []
        for good in affected_goods:
            supply = market.supply.get(good, 0)
            demand = market.demand.get(good, 0)
            good_colored = f"{Fore.CYAN}{good}{Style.RESET_ALL}"
            if demand > supply * 1.5:
                # High demand pushing prices up
                rumor_text = f"high demand for {good_colored} is pushing prices up"
                rumor_colored = f"{Fore.RED}{rumor_text}{Style.RESET_ALL}"
                goods_rumors.append(rumor_colored)
            elif demand < supply * 0.5:
                # Excess supply lowering prices
                rumor_text = f"excess supply of {good_colored} is lowering prices"
                rumor_colored = f"{Fore.GREEN}{rumor_text}{Style.RESET_ALL}"
                goods_rumors.append(rumor_colored)
            else:
                # Stable demand and supply
                rumor_text = f"stable demand and supply for {good_colored}"
                rumor_colored = f"{Fore.YELLOW}{rumor_text}{Style.RESET_ALL}"
                goods_rumors.append(rumor_colored)

        goods_rumor = "; ".join(goods_rumors)
        rumor = f"{base_rumor} Additionally, there's {goods_rumor}."
        return rumor

    def buy(self):
        """Handles the buying process for the player."""
        while True:
            good = self.choose_good("buy")
            if not good:
                return False  # Indicate that no transaction occurred

            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"]
            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 False  # Indicate that no transaction occurred

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

            fast_print(f"You can afford up to {max_quantity} units based on your constraints.")

            while True:
                quantity_input = input(f"Enter the quantity of {good} to buy (max {max_quantity}): ").strip()
                if not quantity_input.isdigit():
                    slow_print("ERROR: Invalid input. Please enter a valid number.")
                    continue  # Prompt again
                quantity = int(quantity_input)
                if quantity <= 0 or quantity > max_quantity:
                    slow_print("ERROR: Quantity must be a positive number within your maximum limit.")
                    continue  # Prompt again

                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 False  # Indicate that no transaction occurred

                # Update player and market
                self.player.money -= cost
                self.current_market.supply[good] -= quantity
                self.current_market.demand[good] += quantity * 0.4  # Increased impact
                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}.")

                # Relationship modifications based on goods categories
                self.update_relationships_after_purchase(good, quantity)

                return True  # Indicate that the transaction was successful

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

            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.")
            while True:
                quantity_input = input(f"Enter the quantity of {good} to sell (max {max_sell_quantity}): ").strip()
                if not quantity_input.isdigit():
                    slow_print("ERROR: Invalid input. Please enter a valid number.")
                    continue  # Prompt again
                quantity = int(quantity_input)
                if quantity <= 0 or quantity > max_sell_quantity:
                    slow_print("ERROR: Quantity must be a positive number within your maximum limit.")
                    continue  # Prompt again

                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.4  # Increased impact
                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}.")

                # Relationship modifications based on goods categories
                self.update_relationships_after_sale(good, quantity)

                return True  # Indicate that the transaction was successful
            
    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:")
        while True:
            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)):
                slow_print("ERROR: Invalid Input. Please enter a valid number.")
                continue
            new_location = available_towns[int(choice) - 1]
            break
        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}.")

        # Update consecutive travel counter
        self.consecutive_travels += 1

        # Apply penalties only if player has traveled multiple turns in a row
        if self.consecutive_travels >= 3:
            penalty_trade = -7  # Increased penalty
            penalty_reputation = -5
            penalty_favor = -3
            self.player.modify_relationship(new_location, "Trade", penalty_trade)
            self.player.modify_relationship(new_location, "Reputation", penalty_reputation)
            self.player.modify_relationship(new_location, "Favor", penalty_favor)
            slow_print(f"Frequent traveling has significantly strained your relationships with {new_location}.")
            self.player.event_log.append(f"Turn {self.turn_counter}: Frequent traveling strained relationships with {new_location}.")
            self.key_events.append(f"Turn {self.turn_counter}: Frequent traveling strained relationships with {new_location}.")
        else:
            # No penalty applied
            pass

        # Check for free travel
        if hasattr(self.player, 'free_travel') and self.player.free_travel:
            slow_print("Due to favorable winds, your travel didn't consume a turn!")
            self.player.free_travel = False  # Reset free travel
            return (True, False)  # Action successful, turn not consumed

        return (True, True)  # Action successful, turn consumed

    def apply_event(self, event, global_event=False):
        """Applies the effects of a triggered event to the game."""
        slow_print(f"\nEvent: {event}")

        # Positive Global Events
        if event == "A global trade agreement has been signed, reducing tariffs.":
            slow_print("Tariffs reduced globally! Prices for goods decrease significantly.")
            for market in self.markets.values():
                for good in GOODS:
                    market.prices[good] = int(market.prices[good] * 0.90)
            self.player.modify_relationship(self.player.location, "Trade", 15)  # Increased impact
            self.player.reputation += 10
            self.key_events.append(f"Turn {self.turn_counter}: Global trade agreement reduced tariffs.")
            return

        if event == "Technological advancements have improved trade efficiency worldwide.":
            slow_print("Trade efficiency improved globally! Increased supply of goods.")
            for market in self.markets.values():
                for good in GOODS:
                    market.supply[good] += 100
            self.player.modify_relationship(self.player.location, "Reputation", 15)  # Increased impact
            self.player.reputation += 10
            self.key_events.append(f"Turn {self.turn_counter}: Technological advancements improved trade efficiency.")
            return

        if event == "A global festival increases demand for luxury goods.":
            slow_print("Global festival! Demand and prices for luxury goods increase.")
            luxury_goods = ["Silk", "Wine", "Gold"]
            for market in self.markets.values():
                for good in luxury_goods:
                    market.demand[good] += 150
                    market.prices[good] = int(market.prices[good] * 1.3)
            self.player.modify_relationship(self.player.location, "Favor", 15)  # Increased impact
            self.player.reputation += 10
            self.key_events.append(f"Turn {self.turn_counter}: Global festival increased demand for luxury goods.")
            return

        # Positive Local Events
        if event == "You found a hidden stash of goods in the market!":
            found_good = random.choice(list(GOODS.keys()))
            found_quantity = random.randint(15, 25)
            added_weight = GOODS[found_good]["weight"] * found_quantity
            if self.player.current_cargo + added_weight <= self.player.max_cargo:
                self.player.add_cargo(found_good, found_quantity)
                slow_print(f"You found {found_quantity} units of {found_good} and added them to your inventory!")
                self.player.modify_relationship(self.player.location, "Favor", 15)  # Increased impact
                self.player.reputation += 10
                self.key_events.append(f"Turn {self.turn_counter}: Found {found_quantity} {found_good} in the market.")
            else:
                slow_print(f"You found {found_quantity} units of {found_good}, but lack the cargo space to carry them.")
            return

        if event == "A wealthy patron gifts you valuable items!":
            gifted_good = random.choice(["Gems", "Gold", "Silk"])
            gifted_quantity = random.randint(10, 15)
            added_weight = GOODS[gifted_good]["weight"] * gifted_quantity
            if self.player.current_cargo + added_weight <= self.player.max_cargo:
                self.player.add_cargo(gifted_good, gifted_quantity)
                slow_print(f"A wealthy patron gifted you {gifted_quantity} units of {gifted_good}!")
                self.player.modify_relationship(self.player.location, "Favor", 20)  # Increased impact
                self.player.reputation += 15
                self.key_events.append(f"Turn {self.turn_counter}: Received {gifted_quantity} {gifted_good} from a patron.")
            else:
                slow_print(f"A wealthy patron wanted to gift you {gifted_quantity} units of {gifted_good}, but you lacked the cargo space.")
            return

        if event == "Your reputation has earned you a local tax exemption!":
            saved_amount = 300
            self.player.money += saved_amount
            slow_print(f"You received a local tax exemption and saved ${saved_amount}!")
            self.player.modify_relationship(self.player.location, "Reputation", 20)  # Increased impact
            self.player.reputation += 15
            self.key_events.append(f"Turn {self.turn_counter}: Received tax exemption, saved ${saved_amount}.")
            return

        if event == "A local festival boosts demand and prices for certain goods.":
            festival_goods = random.sample(["Spices", "Wine", "Cloth", "Tea"], 2)
            for good in festival_goods:
                self.current_market.demand[good] += 120
                self.current_market.prices[good] = int(self.current_market.prices[good] * 1.5)
            slow_print(f"The local festival boosted demand and prices for {', '.join(festival_goods)}!")
            self.player.modify_relationship(self.player.location, "Favor", 15)  # Increased impact
            self.player.reputation += 10
            self.key_events.append(f"Turn {self.turn_counter}: Festival boosted prices for {', '.join(festival_goods)}.")
            return

        if event == "Favorable winds reduce travel times temporarily.":
            slow_print("Favorable winds! You can travel without consuming a turn next time.")
            self.player.free_travel = True  # Set attribute for free travel
            self.player.reputation += 5
            self.key_events.append(f"Turn {self.turn_counter}: Favorable winds will reduce next travel time.")
            return

        if event == "Merchants admire your honesty, improving relationships.":
            slow_print("Your honesty has impressed the merchants. Relationships have greatly improved.")
            self.player.modify_relationship(self.player.location, "Trade", 20)  # Increased impact
            self.player.modify_relationship(self.player.location, "Reputation", 20)
            self.player.reputation += 15
            self.key_events.append(f"Turn {self.turn_counter}: Honesty improved relationships in {self.player.location}.")
            return

        if event == "An influential guild offers you a partnership.":
            slow_print("An influential guild offers you a partnership, significantly increasing your cargo capacity.")
            self.player.max_cargo += 100  # Increased impact
            slow_print(f"Your cargo capacity increased to {self.player.max_cargo}.")
            self.player.modify_relationship(self.player.location, "Trade", 20)  # Increased impact
            self.player.reputation += 15
            self.key_events.append(f"Turn {self.turn_counter}: Guild partnership increased cargo capacity.")
            return

        if event == "An overstock in the market reduces prices for certain goods.":
            overstock_goods = random.sample(["Food", "Iron", "Herbs"], 2)
            for good in overstock_goods:
                self.current_market.supply[good] += 150
                self.current_market.prices[good] = int(self.current_market.prices[good] * 0.6)
            slow_print(f"Overstock in the market! Prices for {', '.join(overstock_goods)} have decreased.")
            self.player.modify_relationship(self.player.location, "Favor", 15)  # Increased impact
            self.player.reputation += 10
            self.key_events.append(f"Turn {self.turn_counter}: Overstock reduced prices for {', '.join(overstock_goods)}.")
            return

        if event == "Local artisans gift you exquisite items to trade.":
            gifted_good = random.choice(["Silk", "Cloth", "Wine"])
            gifted_quantity = random.randint(15, 25)
            added_weight = GOODS[gifted_good]["weight"] * gifted_quantity
            if self.player.current_cargo + added_weight <= self.player.max_cargo:
                self.player.add_cargo(gifted_good, gifted_quantity)
                slow_print(f"Local artisans gifted you {gifted_quantity} units of {gifted_good}!")
                self.player.modify_relationship(self.player.location, "Favor", 20)  # Increased impact
                self.player.reputation += 15
                self.key_events.append(f"Turn {self.turn_counter}: Artisans gifted {gifted_quantity} {gifted_good}.")
            else:
                slow_print(f"Local artisans wanted to gift you {gifted_quantity} units of {gifted_good}, but you lacked the cargo space.")
            return

        if event == "Successful mediation improves trade relations between towns.":
            slow_print("Your mediation greatly improved trade relations between towns.")
            for town in TOWNS:
                self.player.modify_relationship(town, "Trade", 15)  # Increased impact
            self.player.reputation += 20
            self.key_events.append(f"Turn {self.turn_counter}: Mediation improved trade relations universally.")
            return

        # Negative Global Events
        if event == "Global trade embargo reducing supply worldwide.":
            slow_print("A global trade embargo has been enacted. Supply of goods has decreased significantly worldwide.")
            for market in self.markets.values():
                for good in GOODS:
                    market.supply[good] = max(10, market.supply[good] - 100)
                    market.prices[good] = int(market.prices[good] * 1.2)
            self.player.modify_relationship(self.player.location, "Trade", -15)  # Increased impact
            self.player.reputation -= 10
            self.key_events.append(f"Turn {self.turn_counter}: Global trade embargo reduced supply.")
            return

        if event == "Pandemic affecting demand for certain goods globally.":
            slow_print("A pandemic has severely reduced global demand for certain goods.")
            affected_goods = ["Spices", "Wine", "Silk"]
            for market in self.markets.values():
                for good in affected_goods:
                    market.demand[good] = max(50, market.demand[good] - 150)
                    market.prices[good] = int(market.prices[good] * 0.7)
                self.player.modify_relationship(self.player.location, "Reputation", -15)  # Increased impact
                self.player.reputation -= 10
            self.key_events.append(f"Turn {self.turn_counter}: Pandemic reduced demand for certain goods.")
            return

        if event == "Global inflation increasing prices across the board.":
            slow_print("Global inflation is significantly increasing prices everywhere.")
            for market in self.markets.values():
                for good in GOODS:
                    market.prices[good] = int(market.prices[good] * 1.3)
            self.player.modify_relationship(self.player.location, "Trade", -15)  # Increased impact
            self.player.reputation -= 10
            self.key_events.append(f"Turn {self.turn_counter}: Global inflation increased prices.")
            return

        if event == "Global recession decreasing purchasing power.":
            slow_print("A global recession has severely decreased purchasing power.")
            for market in self.markets.values():
                for good in GOODS:
                    market.demand[good] = max(50, market.demand[good] - 120)
                    market.prices[good] = int(market.prices[good] * 0.8)
            self.player.modify_relationship(self.player.location, "Trade", -15)  # Increased impact
            self.player.reputation -= 10
            self.key_events.append(f"Turn {self.turn_counter}: Global recession decreased purchasing power.")
            return

        # Negative Local Events
        if event == "Thieves attacked your caravan and stole some goods!":
            affected_good = random.choice(list(ALL_GOODS.keys()))
            stolen_qty = random.randint(10, 20)
            actual_stolen = min(stolen_qty, self.player.inventory.get(affected_good, 0))
            self.player.remove_cargo(affected_good, actual_stolen)
            slow_print(f"Thieves stole {actual_stolen} units of {affected_good} from your caravan!")
            self.player.modify_relationship(self.player.location, "Trade", -20)  # Increased impact
            self.player.modify_relationship(self.player.location, "Reputation", -15)
            self.player.modify_relationship(self.player.location, "Favor", -10)
            self.player.reputation -= 25
            self.key_events.append(f"Turn {self.turn_counter}: Thieves stole {actual_stolen} {affected_good}.")
            return

        if event == "A storm ruined your goods during travel.":
            damaged_good = random.choice(list(ALL_GOODS.keys()))
            damaged_qty = random.randint(10, 20)
            actual_damaged = min(damaged_qty, self.player.inventory.get(damaged_good, 0))
            self.player.remove_cargo(damaged_good, actual_damaged)
            slow_print(f"A storm damaged {actual_damaged} units of {damaged_good} in your cargo.")
            self.player.modify_relationship(self.player.location, "Trade", -15)  # Increased impact
            self.player.modify_relationship(self.player.location, "Reputation", -10)
            self.player.modify_relationship(self.player.location, "Favor", -7)
            self.player.reputation -= 20
            self.key_events.append(f"Turn {self.turn_counter}: Storm damaged {actual_damaged} {damaged_good}.")
            return

        if event == "Disease outbreak decreased the demand for food.":
            affected_good = "Food"
            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) - 150)
            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 severely decreased the demand for {affected_good}, lowering its price by ${price_drop}.")
            self.player.modify_relationship(self.player.location, "Trade", -18)  # Increased impact
            self.player.modify_relationship(self.player.location, "Reputation", -12)
            self.player.reputation -= 25
            self.key_events.append(f"Turn {self.turn_counter}: Disease outbreak decreased demand for {affected_good}.")
            return

        if event == "Pirates disrupted trade in the seas.":
            affected_good = random.choice(list(ALL_GOODS.keys()))
            price_increase = int(GOODS[affected_good]["base_price"] * 0.45)
            self.current_market.supply[affected_good] = max(10, self.current_market.supply.get(affected_good, 0) - 100)
            self.current_market.prices[affected_good] = min(Market.PRICE_CEILING, self.current_market.prices.get(affected_good, 0) + price_increase)
            slow_print(f"Pirates severely disrupted trade, decreasing supply and increasing price of {affected_good} by ${price_increase}.")
            self.player.modify_relationship(self.player.location, "Trade", -18)  # Increased impact
            self.player.modify_relationship(self.player.location, "Reputation", -12)
            self.player.modify_relationship(self.player.location, "Favor", -8)
            self.player.reputation -= 25
            self.key_events.append(f"Turn {self.turn_counter}: Pirates disrupted trade, affected {affected_good}.")
            return

        if event == "Government imposed a tax on trade.":
            tax_amount = 200
            self.player.money = max(0, self.player.money - tax_amount)
            slow_print(f"The government imposed a heavy tax on your trade. You lost ${tax_amount}.")
            self.player.modify_relationship(self.player.location, "Trade", -18)  # Increased impact
            self.player.modify_relationship(self.player.location, "Reputation", -12)
            self.player.reputation -= 20
            self.key_events.append(f"Turn {self.turn_counter}: Government taxed you ${tax_amount}.")
            return

        if event == "Locusts devastated the food supplies in Dusktown.":
            affected_good = "Food"
            damage = random.randint(15, 25)
            actual_damaged = min(damage, self.player.inventory.get(affected_good, 0))
            if self.player.location == "Dusktown":
                self.player.remove_cargo(affected_good, actual_damaged)
                slow_print(f"Locusts devastated food supplies in Dusktown, destroying {actual_damaged} units of your {affected_good}.")
                self.player.modify_relationship(self.player.location, "Trade", -15)  # Increased impact
                self.player.modify_relationship(self.player.location, "Reputation", -10)
                self.player.modify_relationship(self.player.location, "Favor", -7)
                self.player.reputation -= 20
                self.key_events.append(f"Turn {self.turn_counter}: Locusts destroyed {actual_damaged} {affected_good} in Dusktown.")
            else:
                slow_print("Locusts devastated food supplies in Dusktown.")
            return

        if event == "Bandit attack in Oakwood stole some of your goods.":
            affected_good = random.choice(list(ALL_GOODS.keys()))
            stolen_qty = random.randint(10, 20)
            actual_stolen = min(stolen_qty, self.player.inventory.get(affected_good, 0))
            if self.player.location == "Oakwood":
                self.player.remove_cargo(affected_good, actual_stolen)
                slow_print(f"Bandits in Oakwood stole {actual_stolen} units of your {affected_good}.")
                self.player.modify_relationship(self.player.location, "Trade", -20)  # Increased impact
                self.player.modify_relationship(self.player.location, "Reputation", -15)
                self.player.modify_relationship(self.player.location, "Favor", -10)
                self.player.reputation -= 25
                self.key_events.append(f"Turn {self.turn_counter}: Bandits in Oakwood stole {actual_stolen} {affected_good}.")
            else:
                slow_print("Bandits attacked traders in Oakwood.")
            return

        if event == "Natural disaster in Dusktown affecting multiple goods.":
            affected_goods = random.sample(list(ALL_GOODS.keys()), k=3)
            if self.player.location == "Dusktown":
                for good in affected_goods:
                    damaged_qty = random.randint(10, 20)
                    actual_damaged = min(damaged_qty, self.player.inventory.get(good, 0))
                    self.player.remove_cargo(good, actual_damaged)
                slow_print(f"A natural disaster in Dusktown damaged a significant amount of your goods.")
                self.player.modify_relationship(self.player.location, "Trade", -25)  # Increased impact
                self.player.modify_relationship(self.player.location, "Reputation", -18)
                self.player.modify_relationship(self.player.location, "Favor", -12)
                self.player.reputation -= 30
                self.key_events.append(f"Turn {self.turn_counter}: Natural disaster damaged goods in Dusktown.")
            else:
                slow_print("A natural disaster struck Dusktown, severely affecting trade.")
            return

        # Fallback for unhandled events
        slow_print("An unusual event occurred, but nothing notable happened.")

    def trigger_event(self):
        """Randomly triggers a global or local event based on difficulty settings."""
        event_chance = DIFFICULTIES[self.difficulty]["event_chance"]
        # Reduce event chance based on reputation
        reputation_factor = 1 - (self.player.reputation / 200)  # Adjust as needed
        reputation_factor = max(0.5, reputation_factor)  # Ensure at least 50% of base chance
        adjusted_event_chance = event_chance * reputation_factor
        if random.random() < adjusted_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}")

        # Reset consecutive travels if not traveling this turn
        if self.last_command != "TRAVEL":
            self.consecutive_travels = 0  # Reset counter if player did something else

    def apply_relationship_decay(self):
        """Gradually decays the relationships over time."""
        medium_print("\nRelationships have naturally changed over time:")
        for town in TOWNS:
            aspects = self.player.relationships[town]
            for aspect in aspects:
                original_score = aspects[aspect]
                if aspects[aspect] > 0:
                    aspects[aspect] -= 2  # Increased decay rate
                elif aspects[aspect] < 0:
                    aspects[aspect] += 2  # Increased recovery rate
                # Clamp values
                aspects[aspect] = max(RELATIONSHIP_MIN, min(aspects[aspect], RELATIONSHIP_MAX))
                change = aspects[aspect] - original_score
                if change != 0:
                    # Notify the player about the change
                    if change > 0:
                        medium_print(f"[{town} - {aspect}] Improved by {change} point(s).")
                    else:
                        medium_print(f"[{town} - {aspect}] Decreased by {-change} point(s).")

    def update_relationships_after_purchase(self, good, quantity):
        town = self.player.location
        if good in SUPPORTIVE_GOODS:
            self.player.modify_relationship(town, "Reputation", int(quantity / 2))
        elif good in STRATEGIC_GOODS:
            self.player.modify_relationship(town, "Trade", int(quantity))
        elif good in LUXURY_GOODS:
            self.player.modify_relationship(town, "Favor", int(quantity))
        
    def update_relationships_after_sale(self, good, quantity):
        town = self.player.location
        if good in SUPPORTIVE_GOODS:
            self.player.modify_relationship(town, "Reputation", int(quantity / 2))
        elif good in STRATEGIC_GOODS:
            self.player.modify_relationship(town, "Trade", int(quantity))
        elif good in LUXURY_GOODS:
            self.player.modify_relationship(town, "Favor", int(quantity))
        
    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"]:
                    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.get(good, 0) > 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.get(good, 0) < 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.get(good, 0) > 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"]

                # Additional decay for Gold's value to prevent hoarding
                if good == "Gold":
                    market.prices["Gold"] = max(Market.PRICE_FLOOR, int(market.prices["Gold"] * 0.98))  # Increased depreciation per turn

    def end_game(self):
        """Displays the final game results and concludes the game."""
        # The end_game method remains the same

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

        # Calculate financial performance
        financial_performance = self.calculate_financial_performance(net_worth)
        # Calculate social performance
        social_performance = self.calculate_social_performance()

        # Display financial performance
        slow_print(f"\n{Fore.GREEN}Financial Performance:{Style.RESET_ALL}")
        fast_print(f" - Net Worth Score: {financial_performance['net_worth_score']} / 5")
        fast_print(f" - Liquidity Score: {financial_performance['liquidity_score']} / 5")
        financial_total = financial_performance['net_worth_score'] + financial_performance['liquidity_score']
        fast_print(f" - Total Financial Score: {financial_total} / 10")

        # Display social performance
        slow_print(f"\n{Fore.BLUE}Social Performance (Relationships):{Style.RESET_ALL}")
        fast_print(f" - Average Trade Relations Score: {social_performance['trade_score']} / 5")
        fast_print(f" - Average Reputation Score: {social_performance['reputation_score']} / 5")
        fast_print(f" - Average Favor Score: {social_performance['favor_score']} / 5")
        social_total = social_performance['trade_score'] + social_performance['reputation_score'] + social_performance['favor_score']
        fast_print(f" - Total Social Score: {social_total} / 15")

        # Calculate total score
        total_score = financial_total + social_total
        max_total_score = 10 + 15  # Financial max + Social max

        # Determine final rating based on total_score
        rating = self.determine_rating(total_score)
        rating_message = self.generate_final_message(financial_total, social_total, rating)

        slow_print(f"\nFinal Rating: {Fore.CYAN}{rating}{Style.RESET_ALL}")
        slow_print(rating_message)

        # Display key events summary
        slow_print("\nSummary of Your Journey:")
        for event in self.key_events[:50]:  # Limit to first 50 for readability
            fast_print(event)
        if len(self.key_events) > 50:
            fast_print("...")

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

    def generate_final_message(self, financial_total, social_total, rating):
        """Generates a final message based on financial and social performance."""
        messages = {
            "Legendary": "Incredible! You became an unmatched trading legend with stellar relationships and unmatched wealth.",
            "Great": "Congratulations! You became a legendary trader with excellent relationships and strong financials.",
            "Excellent": "Outstanding! You achieved impressive wealth and maintained excellent relationships.",
            "Good": "Well done! You made a substantial profit and maintained good relationships.",
            "Decent": "You made a respectable profit and kept decent relations.",
            "Poor": "You faced challenges in trading, with room to improve both financially and socially.",
            "Terrible": "Your trading journey was fraught with difficulties. Significant improvement is needed in both trading and relationships."
        }

        # Customize the message based on which performance was better
        if financial_total > social_total:
            messages["Good"] += " Your financial acumen outshined your social engagements."
            messages["Decent"] += " You did well financially but could improve your relationships."
            messages["Poor"] += " Financial setbacks affected your journey more than social aspects."
        elif social_total > financial_total:
            messages["Good"] += " Your strong relationships boosted your trading journey."
            messages["Decent"] += " Your social skills helped balance financial challenges."
            messages["Poor"] += " Despite good relations, financial challenges hindered progress."

        return messages.get(rating, "")

    def calculate_net_worth_score(self, net_worth):
        """Assigns a score based on net worth."""
        if net_worth >= 40000:
            return 5
        elif net_worth >= 30000:
            return 4
        elif net_worth >= 20000:
            return 3
        elif net_worth >= 15000:
            return 2
        elif net_worth >= 10000:
            return 1
        else:
            return 0

    def calculate_trade_score(self, average_trade):
        """Assigns a score based on average Trade Relations."""
        if average_trade >= 80:
            return 5
        elif average_trade >= 60:
            return 4
        elif average_trade >= 40:
            return 3
        elif average_trade >= 20:
            return 2
        elif average_trade >= 0:
            return 1
        else:
            return 0

    def calculate_reputation_score(self, average_reputation):
        """Assigns a score based on average Reputation."""
        if average_reputation >= 80:
            return 5
        elif average_reputation >= 60:
            return 4
        elif average_reputation >= 40:
            return 3
        elif average_reputation >= 20:
            return 2
        elif average_reputation >= 0:
            return 1
        else:
            return 0

    def calculate_favor_score(self, average_favor):
        """Assigns a score based on average Favor."""
        if average_favor >= 80:
            return 5
        elif average_favor >= 60:
            return 4
        elif average_favor >= 40:
            return 3
        elif average_favor >= 20:
            return 2
        elif average_favor >= 0:
            return 1
        else:
            return 0

    def calculate_social_performance(self):
        """Calculates social performance metrics."""
        # Calculate overall relationship scores
        total_trade = sum([self.player.relationships[town]["Trade"] for town in TOWNS])
        total_reputation = sum([self.player.relationships[town]["Reputation"] for town in TOWNS])
        total_favor = sum([self.player.relationships[town]["Favor"] for town in TOWNS])

        average_trade = total_trade / len(TOWNS)
        average_reputation = total_reputation / len(TOWNS)
        average_favor = total_favor / len(TOWNS)

        trade_score = self.calculate_trade_score(average_trade)
        reputation_score = self.calculate_reputation_score(average_reputation)
        favor_score = self.calculate_favor_score(average_favor)

        return {
            "trade_score": trade_score,
            "reputation_score": reputation_score,
            "favor_score": favor_score
        }

    def calculate_financial_performance(self, net_worth):
        """Calculates financial performance metrics."""
        # New liquidity ratio calculation based on starting money
        liquidity_ratio = self.player.money / self.player.starting_money
        liquidity_score = self.calculate_liquidity_score(liquidity_ratio)
        net_worth_score = self.calculate_net_worth_score(net_worth)

        return {
            "net_worth_score": net_worth_score,
            "liquidity_score": liquidity_score
        }

    def calculate_liquidity_score(self, liquidity_ratio):
        """Assigns a score based on liquidity_ratio."""
        if liquidity_ratio >= 2.0:  # Ending cash is at least double the starting cash
            return 5
        elif liquidity_ratio >= 1.5:
            return 4
        elif liquidity_ratio >= 1.2:
            return 3
        elif liquidity_ratio >= 1.0:
            return 2
        elif liquidity_ratio >= 0.8:
            return 1
        else:
            return 0

    def determine_rating(self, total_score):
        """Determines the final rating based on total_score."""
        if total_score >= 22:
            return "Legendary"
        elif total_score >= 18:
            return "Great"
        elif total_score >= 14:
            return "Excellent"
        elif total_score >= 10:
            return "Good"
        elif total_score >= 6:
            return "Decent"
        elif total_score >= 3:
            return "Poor"
        else:
            return "Terrible"

# Print methods for different speeds
def fast_print(text):
    for char in text:
        print(char, end="", flush=True)
        time.sleep(0.0005)
    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(average_score):
    """Converts a numerical relationship score into a descriptive status."""
    if average_score >= 80:
        return "Ally"
    elif average_score >= 50:
        return "Friendly"
    elif average_score >= -20:
        return "Neutral"
    elif average_score >= -60:
        return "Hostile"
    else:
        return "Enemy"

# 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)