Remove black market goods and add other ways that significantly impact relations negatively.


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

# 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 >= 80:
        return "Ally"
    elif relation >= 50:
        return "Friendly"
    elif relation >= -20:
        return "Neutral"
    elif relation >= -60:
        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},
    # Adding more goods for negative impact possibilities
    "Black Market Goods": {"base_price": 300, "weight": 10, "base_supply": 50, "base_demand": 40},
    "Contraband": {"base_price": 800, "weight": 25, "base_supply": 20, "base_demand": 15},
}

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

# List of goods that can negatively impact relationships when traded excessively
NEGATIVE_GOODS = ["Black Market Goods", "Contraband"]

# 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.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
            good = random.choice(list(ALL_GOODS.keys()))
            # Determine quantity based on aggressiveness
            quantity = random.randint(1, max(1, int(15 * 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.7  # 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.7  # 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 regular goods
        self.inventory = {good: 0 for good in GOODS}
        self.location = random.choice(TOWNS)
        self.turns = 0
        self.max_cargo = starting_cargo
        self.current_cargo = 0
        self.cargo_upgrades = 0
        self.relationships = {town: RELATIONSHIP_BASE for town in TOWNS}
        self.event_log = []  # To track key events per turn
        self.reputation = 0  # Global reputation

    def modify_relationship(self, town, amount):
        """Modifies the relationship with a specific town."""
        # Introduce randomness to relationship changes to prevent extreme shifts
        variation = random.randint(-2, 2)  # Small random variation
        adjusted_amount = int(amount * 0.5) + variation  # Reduce effect by half
        self.relationships[town] += adjusted_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}")
        # Display relationships
        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
        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
        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
        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 = 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, 0) / self.supply.get(good, 0)
                elasticity = random.uniform(0.85, 1.15)
                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

    def get_relationship_modifier(self, relation):
        """Determines price modifiers based on the relationship status."""
        status = get_relationship_status(relation)
        if status == "Ally":
            return 0.75  # 25% discount for buying, 25% bonus for selling
        elif status == "Friendly":
            return 0.85  # 15% discount
        elif status == "Hostile":
            return 1.20  # 20% price increase
        elif status == "Enemy":
            return 1.40  # 40% price increase
        else:
            return 1.00  # 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}")
        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.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  # 3% per turn
        self.demand_decay_rate = 0.03  # 3% 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("\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}""")
        slow_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.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]
        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.generate_prices()  # Ensure prices are updated after events
            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":
                # Print the '=' lines separately in yellow without extra line breaks
                print(f"{Fore.YELLOW}{'='*60}{Style.RESET_ALL}")
                slow_print(WELCOME_TEXT)
                print(f"{Fore.YELLOW}{'='*60}{Style.RESET_ALL}")
                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"]
        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
        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.")
        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.4  # Increased impact to relationship
        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"]
        strategic_goods = ["Gold", "Gems", "Iron"]
        negative_buy_goods = NEGATIVE_GOODS

        if good in supportive_goods and quantity >= max_quantity * 0.5:
            self.player.modify_relationship(self.player.location, 10)  # Reduced impact
            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.")
        elif good in strategic_goods and quantity >= max_quantity * 0.4:
            self.player.modify_relationship(self.player.location, 7)  # Reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Bought significant amount of {good}, improved relationship.")
            self.key_events.append(f"Turn {self.turn_counter}: Bought significant amount of {good}, improved relationship.")
        elif good in negative_buy_goods and quantity >= max_quantity * 0.3:
            self.player.modify_relationship(self.player.location, -10)  # Negative impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Bought {quantity} {good}, harmed relationship.")
            self.key_events.append(f"Turn {self.turn_counter}: Bought {quantity} {good}, harmed 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

        # Risky Selling: If selling more than a threshold, relationships may decrease
        risky_threshold = max_sell_quantity * 0.75  # 75% of inventory
        negative_sell_goods = NEGATIVE_GOODS
        relationship_decrement = 7  # Reduced impact

        if quantity > risky_threshold:
            risk = random.random()
            if risk < 0.4:  # 40% chance of negative impact
                self.player.modify_relationship(self.player.location, -relationship_decrement)  # Reduced impact
                slow_print(f"Over-selling {good} has slightly upset the local merchants.")
                self.player.event_log.append(f"Turn {self.turn_counter}: Over-sold {good}, relationship decreased.")
                self.key_events.append(f"Turn {self.turn_counter}: Over-sold {good}, relationship decreased.")
        elif good in negative_sell_goods and quantity >= max_sell_quantity * 0.3:
            self.player.modify_relationship(self.player.location, -relationship_decrement)  # Negative impact
            slow_print(f"Selling {quantity} units of {good} has displeased the local merchants.")
            self.player.event_log.append(f"Turn {self.turn_counter}: Sold {quantity} {good}, harmed relationship.")
            self.key_events.append(f"Turn {self.turn_counter}: Sold {quantity} {good}, harmed relationship.")

        # 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 to relationship
        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"]
        desired_goods = ["Food", "Herbs", "Cloth"]
        negative_sell_goods = NEGATIVE_GOODS

        if good in needed_goods and quantity >= max_sell_quantity * 0.5:
            self.player.modify_relationship(self.player.location, 10)  # Reduced impact
            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.")
        elif good in desired_goods and quantity >= max_sell_quantity * 0.4:
            self.player.modify_relationship(self.player.location, 7)  # Reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Sold significant amount of {good}, improved relationship.")
            self.key_events.append(f"Turn {self.turn_counter}: Sold significant amount of {good}, improved relationship.")
        elif good in negative_sell_goods and quantity >= max_sell_quantity * 0.3:
            # Already handled above
            pass

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

        # Impact relationships by choosing to travel frequently without significant trades
        if random.random() < 0.3:  # 30% chance to slightly reduce relationship
            self.player.modify_relationship(new_location, -3)  # Slight decrease
            slow_print(f"Frequent traveling has slightly strained your relationship with {new_location}.")
            self.player.event_log.append(f"Turn {self.turn_counter}: Frequent traveling strained relationship with {new_location}.")
            self.key_events.append(f"Turn {self.turn_counter}: Frequent traveling strained relationship with {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
            relation = self.player.relationships[town]
            status = get_relationship_status(relation)
            fast_print(f"{town}: Average Price ${int(avg_price)} | Relationship: {relation} ({status})")
        print()

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

    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 "extra goods" in event.lower():
            good = random.choice(list(ALL_GOODS.keys()))
            quantity = random.randint(5, 15)
            # Check if adding these goods exceeds cargo capacity
            added_weight = GOODS[good]["weight"] * quantity
            if self.player.current_cargo + added_weight <= self.player.max_cargo:
                self.player.inventory[good] += quantity
                self.player.current_cargo += added_weight
                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)  # Further reduced impact
                self.player.event_log.append(f"Turn {self.turn_counter}: Found extra {quantity} {good} and gained $100.")
                self.key_events.append(f"Turn {self.turn_counter}: Found extra {quantity} {good} and gained $100.")
                self.player.reputation += 5
            else:
                slow_print(f"You found extra {quantity} units of {good}, but don't have enough cargo space to carry them.")
            return

        # Player reactions to events
        if "tax" in event.lower():
            tax_amount = 100  # Increased impact
            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)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Imposed tax of ${tax_amount}.")
            self.key_events.append(f"Turn {self.turn_counter}: Imposed tax of ${tax_amount}.")
            self.player.reputation -= 10
            return

        # Implement event effects with relationship modifications
        if "economic boom" in event.lower():
            affected_good = "Gems"
            price_boost = int(GOODS[affected_good]["base_price"] * 0.4)
            self.current_market.demand[affected_good] += 100  # Increased impact
            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)  # Further reduced impact
            self.player.reputation += 15
            return
        elif "market crash" in event.lower():
            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) - 150)  # Increased impact
            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)  # Further reduced impact
            self.player.reputation -= 15
            return
        elif "thieves" in event.lower() or "bandit" in event.lower():
            stolen_good = random.choice(list(ALL_GOODS.keys()))
            stolen_qty = random.randint(5, 15)  # Increased impact
            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.3  # Increased impact
            self.current_market.demand[stolen_good] = self.current_market.demand.get(stolen_good, 0) - actual_stolen * 0.3  # Increased impact
            slow_print(f"Bandits stole {actual_stolen} units of {stolen_good} from your cargo!")
            self.player.modify_relationship(self.player.location, -12)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Bandits stole {actual_stolen} {stolen_good}.")
            self.key_events.append(f"Turn {self.turn_counter}: Bandits stole {actual_stolen} {stolen_good}.")
            self.player.reputation -= 20
            return
        elif "storm" in event.lower() or "natural disaster" in event.lower():
            damaged_good = random.choice(list(ALL_GOODS.keys()))
            damaged_qty = random.randint(5, 15)  # Increased impact
            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.2  # Increased impact
            self.current_market.demand[damaged_good] = self.current_market.demand.get(damaged_good, 0) - actual_damaged * 0.2  # Increased impact
            slow_print(f"A storm damaged {actual_damaged} units of {damaged_good} in your cargo.")
            self.player.modify_relationship(self.player.location, -5)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Storm damaged {actual_damaged} {damaged_good}.")
            self.key_events.append(f"Turn {self.turn_counter}: Storm damaged {actual_damaged} {damaged_good}.")
            self.player.reputation -= 10
            return
        elif "festival" in event.lower():
            affected_good = random.choice(["Spices", "Wine", "Cloth"])
            price_boost = int(GOODS[affected_good]["base_price"] * 0.3)
            self.current_market.demand[affected_good] += 80  # Increased impact
            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, 10)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Festival boosted {affected_good} prices.")
            self.key_events.append(f"Turn {self.turn_counter}: Festival boosted {affected_good} prices.")
            self.player.reputation += 10
            return
        elif "disease" in event.lower():
            affected_good = "Food"
            price_drop = int(GOODS[affected_good]["base_price"] * 0.25)  # Increased impact
            self.current_market.demand[affected_good] = max(50, self.current_market.demand.get(affected_good, 0) - 120)  # Increased impact
            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)  # Further reduced impact
            self.player.reputation -= 15
            return
        elif "trade routes" in event.lower():
            affected_good = random.choice(list(ALL_GOODS.keys()))
            supply_change = random.randint(-40, 40)  # Increased impact
            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.")
            # Minor impact on relationships
            if supply_change < 0:
                self.player.modify_relationship(self.player.location, -5)
                self.player.event_log.append(f"Turn {self.turn_counter}: Trade routes negatively affected {affected_good} supply.")
                self.key_events.append(f"Turn {self.turn_counter}: Trade routes negatively affected {affected_good} supply.")
                self.player.reputation -= 5
            return
        elif "pirates" in event.lower():
            affected_good = random.choice(list(ALL_GOODS.keys()))
            price_drop = int(GOODS[affected_good]["base_price"] * 0.35)  # Increased impact
            self.current_market.demand[affected_good] = max(50, self.current_market.demand.get(affected_good, 0) - 70)  # Increased impact
            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)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Pirates disrupted trade, decreased {affected_good} price.")
            self.key_events.append(f"Turn {self.turn_counter}: Pirates disrupted trade, decreased {affected_good} price.")
            self.player.reputation -= 15
            return
        elif "rare gem" in event.lower():
            affected_good = "Gems"
            supply_increase = 70  # Increased impact
            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) - 40)  # Increased impact
            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, 10)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Discovered rare gem deposit, affected {affected_good}.")
            self.key_events.append(f"Turn {self.turn_counter}: Discovered rare gem deposit, affected {affected_good}.")
            self.player.reputation += 10
            return
        elif "locusts" in event.lower():
            affected_good = "Food"
            damage = random.randint(10, 20)  # Increased impact
            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.3  # Increased impact
            self.current_market.demand[affected_good] = self.current_market.demand.get(affected_good, 0) - actual_damaged * 0.3  # Increased impact
            slow_print(f"Locusts devastated your food supplies, destroying {actual_damaged} units of {affected_good}.")
            self.player.modify_relationship(self.player.location, -8)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Locusts destroyed {actual_damaged} {affected_good}.")
            self.key_events.append(f"Turn {self.turn_counter}: Locusts destroyed {actual_damaged} {affected_good}.")
            self.player.reputation -= 10
            return
        elif "artisans" in event.lower():
            affected_good = "Spices"
            price_boost = int(GOODS[affected_good]["base_price"] * 0.35)  # Increased impact
            self.current_market.demand[affected_good] += 60  # Increased impact
            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)  # Further reduced impact
            self.player.event_log.append(f"Turn {self.turn_counter}: Artisans boosted {affected_good} demand.")
            self.key_events.append(f"Turn {self.turn_counter}: Artisans boosted {affected_good} demand.")
            self.player.reputation += 20
            return
        elif "global economic boom" in event.lower():
            for market in self.markets.values():
                affected_good = "Gold"
                price_boost = int(GOODS[affected_good]["base_price"] * 0.3)  # Increased impact
                market.demand[affected_good] += 50  # Increased impact
                market.prices[affected_good] += price_boost
            slow_print("A global economic boom has increased the demand and prices for Gold across all markets.")
            self.player.reputation += 20
            return
        elif "global recession" in event.lower() or "economic recession" in event.lower():
            for market in self.markets.values():
                affected_good = "Food"
                price_drop = int(GOODS[affected_good]["base_price"] * 0.25)  # Increased impact
                market.demand[affected_good] = max(50, market.demand.get(affected_good, 0) - 80)  # Increased impact
                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 -= 20
            return

    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"]

    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}")
        
        # Calculate overall relationship score
        total_relationship = sum(self.player.relationships.values())
        average_relationship = total_relationship / len(self.player.relationships)
        
        # Calculate liquidity vs stock ratio
        total_stock_value = sum(
            self.player.inventory.get(good, 0) * self.current_market.prices.get(good, 0) for good in ALL_GOODS
        )
        if total_stock_value == 0:
            liquidity_ratio = float('inf')
        else:
            liquidity_ratio = self.player.money / total_stock_value
        
        # Determine endgame rating with more granular categories
        rating = ""
        if net_worth >= 40000 and average_relationship >= 85 and liquidity_ratio > 4:
            rating = "Legendary"
        elif net_worth >= 30000 and average_relationship >= 75 and liquidity_ratio > 3:
            rating = "Great"
        elif net_worth >= 20000 and average_relationship >= 60 and liquidity_ratio > 2.5:
            rating = "Excellent"
        elif net_worth >= 15000 and average_relationship >= 50 and liquidity_ratio > 2:
            rating = "Good"
        elif net_worth >= 10000 and average_relationship >= 30 and liquidity_ratio > 1.5:
            rating = "Decent"
        elif net_worth >= 7000 and average_relationship >= 10 and liquidity_ratio > 1:
            rating = "Neutral"
        elif net_worth >= 5000 and average_relationship >= -10 and liquidity_ratio > 0.8:
            rating = "Poor"
        elif net_worth >= 3000 and average_relationship >= -20 and liquidity_ratio > 0.5:
            rating = "Bad"
        else:
            rating = "Terrible"

        rating_messages = {
            "Legendary": "Incredible! You became an unmatched trading legend with stellar relationships and unmatched liquidity.",
            "Great": "Congratulations! You became a legendary trader with excellent relationships and strong liquidity.",
            "Excellent": "Outstanding! You achieved impressive wealth and maintained excellent relationships.",
            "Good": "Well done! You made a substantial profit and maintained good relationships.",
            "Decent": "Good job! You made a respectable profit and kept decent relations.",
            "Neutral": "Good job! You made a respectable profit and kept neutral relations.",
            "Poor": "You struggled to make a significant profit and had poor relationships.",
            "Bad": "You struggled to make a profit and had poor relationships.",
            "Terrible": "Better luck next time. Your trading skills and relationships need significant improvement."
        }

        slow_print(f"Final Rating: {Fore.BLUE}{rating}{Style.RESET_ALL}")
        slow_print(rating_messages.get(rating, ""))

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

        # Optionally, provide more detailed summaries based on performance metrics
        if rating in ["Legendary", "Great", "Excellent"]:
            slow_print("\nYou excelled in trading, made strategic decisions, and built strong alliances with the towns.")
        elif rating in ["Good", "Decent", "Neutral"]:
            slow_print("\nYou had a successful trading journey with some notable achievements and maintained balanced relations.")
        elif rating in ["Poor", "Bad", "Terrible"]:
            slow_print("\nYour trading endeavors faced challenges, resulting in limited profits and strained relationships.")

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

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