Can you remove the send button, make typing impossible during the initial print phase and output the entire code?


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>MARKET: The Trading Game</title>
  
  <!-- Import Google Fonts -->
  <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&display=swap" rel="stylesheet">
  
  <!-- Include PyScript CSS and JS -->
  <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css">
  <script defer src="https://pyscript.net/latest/pyscript.js"></script>
  
  <style>
    /* Reset default margins and paddings */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      background-color: #1e1e2f;
      color: #f5f5f5;
      font-family: 'Press Start 2P', sans-serif;
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
      overflow: hidden;
    }

    /* Optional: Add a subtle background gradient to avoid external image loading */
    body::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: linear-gradient(135deg, #1e1e2f 25%, #2d2d3a 100%);
      opacity: 0.05;
      pointer-events: none;
    }

    #terminal {
      width: 95vw; /* Increased width from 90vw to 95vw */
      max-width: 1600px; /* Increased max-width from 800px to 1600px */
      height: 95vh; /* Increased height from 90vh to 95vh */
      background-color: #2d2d3a;
      padding: 25px;
      border: 2px solid #44475a;
      box-shadow: 0 0 20px rgba(255, 215, 0, 0.3); /* Gold glow */
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      border-radius: 10px;
      position: relative;
      animation: pulseGlow 5s ease-in-out infinite;
      font-family: 'Roboto Mono', monospace;
    }

    /* Pulsing Glow Animation */
    @keyframes pulseGlow {
      0% {
        box-shadow: 0 0 10px rgba(255, 215, 0, 0.3);
      }
      50% {
        box-shadow: 0 0 30px rgba(255, 215, 0, 0.6);
      }
      100% {
        box-shadow: 0 0 10px rgba(255, 215, 0, 0.3);
      }
    }

    /* Header with Game Title and Logo */
    #header {
      display: flex;
      align-items: center;
      margin-bottom: 10px;
    }

    #logo {
      /* Using an emoji for the logo */
      margin-right: 15px;
      font-size: 48px; /* Adjust font size to match original logo size */
      display: flex;
      align-items: center;
      justify-content: center;
    }

    #game-title {
      font-size: 1.5em;
      font-weight: 700;
      color: #ffd700; /* Gold color */
    }

    #output {
      color: #f1fa8c; /* Light yellow */
      background-color: #1e1e2f;
      padding: 15px;
      margin-bottom: 15px;
      overflow-y: auto;
      flex-grow: 1;
      border-radius: 5px;
      box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
      font-size: 1em;
      font-family: 'Roboto Mono', monospace; /* Ensure output uses monospace font */
    }

    #input-area {
      display: flex;
      flex-direction: column;
      align-items: stretch;
    }

    #user-input {
      width: 100%;
      height: 80px;
      background-color: #3e3e4a;
      color: #f1fa8c;
      border: 1px solid #44475a;
      padding: 10px;
      outline: none;
      resize: none;
      border-radius: 5px;
      font-size: 1em;
      font-family: 'Roboto Mono', monospace;
      margin-bottom: 10px;
    }

    #send-button {
      background-color: #44475a;
      color: #f1fa8c;
      border: none;
      padding: 10px 20px;
      font-size: 1em;
      cursor: pointer;
      border-radius: 5px;
      transition: background-color 0.3s, transform 0.2s;
      font-family: 'Roboto Mono', monospace;
    }

    #send-button:hover {
      background-color: #6272a4;
      transform: translateY(-2px);
    }

    #send-button:active {
      background-color: #44475a;
      transform: translateY(0);
    }

    #rulesButton {
      position: absolute;
      top: 15px;
      right: 15px;
      background-color: #44475a;
      color: #f1fa8c;
      border: none;
      padding: 8px 15px;
      font-size: 0.9em;
      cursor: pointer;
      border-radius: 5px;
      transition: background-color 0.3s, transform 0.2s;
      box-shadow: 0 0 5px rgba(255, 215, 0, 0.5);
      animation: pulseGlow 5s ease-in-out infinite;
      font-family: 'Roboto Mono', monospace;
    }

    #rulesButton:hover {
      background-color: #6272a4;
      transform: translateY(-2px);
    }

    #rulesButton:active {
      background-color: #44475a;
      transform: translateY(0);
    }

    #rulesPopup {
      display: none;
      position: fixed;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background-color: rgba(30, 30, 47, 0.95);
      z-index: 999;
      font-family: 'Roboto', sans-serif;
      padding: 50px;
      overflow-y: auto;
    }

    #rulesContent {
      position: relative;
      background-color: #3e3e4a;
      color: #f1fa8c;
      padding: 30px;
      border-radius: 10px;
      max-width: 800px;
      margin: auto;
      box-shadow: 0 0 20px rgba(255, 215, 0, 0.3);
    }

    .closeButton {
      position: absolute;
      top: 15px;
      right: 20px;
      background-color: transparent;
      color: #ff5555;
      border: none;
      font-size: 2em;
      cursor: pointer;
      font-family: 'Roboto Mono', monospace;
    }

    .closeButton:hover {
      color: #ff6e6e;
    }

    #rulesContent h1 {
      text-align: center;
      margin-bottom: 20px;
      color: #ffd700;
    }

    #rulesContent p, #rulesContent ul {
      font-size: 1em;
      line-height: 1.6;
    }

    #rulesContent ul {
      list-style-type: disc;
      margin-left: 20px;
    }

    /* Responsive Adjustments */
    @media (max-width: 1600px) {
      #terminal {
        max-width: 1400px; /* Adjust max-width for slightly smaller screens */
      }
    }

    @media (max-width: 1200px) {
      #terminal {
        width: 100vw;
        max-width: none;
        height: 100vh;
      }
    }

    @media (max-width: 600px) {
      #user-input {
        height: 60px;
      }

      #send-button, #rulesButton {
        padding: 8px 12px;
        font-size: 0.8em;
      }

      #game-title {
        font-size: 1.2em;
      }
    }
  </style>
</head>
<body>
  <div id="terminal">
    <div id="header">
      <!-- Replaced the img tag with a span containing a money bag emoji -->
      <span id="logo">💰</span>
      <div id="game-title">MARKET: The Trading Game</div>
    </div>
    <div id="output"></div>
    <div id="input-area">
      <textarea id="user-input" placeholder="Enter your trading commands..."></textarea>
      <button id="send-button" onclick="handleSend()">Send</button>
    </div>
  </div>
  <button id="rulesButton" onclick="toggleRules()">Rules</button>
  <div id="rulesPopup">
    <div id="rulesContent">
      <button class="closeButton" onclick="toggleRules()">×</button>
      <h1>Game Rules</h1>
      <p>Welcome to <strong>MARKET: The Trading Game</strong>! Your objective is to accumulate wealth by strategically buying and selling goods across various towns. Here's how to play:</p>
      <ul>
        <li><strong>Commands:</strong> Use commands like <code>BUY</code>, <code>SELL</code>, <code>TRAVEL</code>, <code>STATUS</code>, <code>HELP</code>, and <code>EXIT</code> to interact with the game.</li>
        <li><strong>BUY:</strong> Purchase goods from the current town's market. Ensure you have enough money and cargo space.</li>
        <li><strong>SELL:</strong> Sell goods from your inventory to the current town's market. Maximize your profits by selling high-demand items.</li>
        <li><strong>TRAVEL:</strong> Move to a different town to explore new markets and opportunities.</li>
        <li><strong>STATUS:</strong> View your current money, inventory, cargo space, and remaining turns.</li>
        <li><strong>HELP:</strong> View the game rules and instructions.</li>
        <li><strong>EXIT:</strong> Quit the game at any time.</li>
        <li><strong>Events:</strong> Random events like economic booms, market crashes, and AI traders will influence the market. Adapt your strategies accordingly.</li>
      </ul>
      <p>Good luck, trader! May your investments be prosperous.</p>
    </div>
  </div>

  <!-- JavaScript Section -->
  <script>
    document.addEventListener('DOMContentLoaded', (event) => {
      const rulesPopup = document.getElementById('rulesPopup');
      rulesPopup.style.display = 'none';
    });

    function toggleRules() {
      const rulesPopup = document.getElementById('rulesPopup');
      rulesPopup.style.display = rulesPopup.style.display === 'block' ? 'none' : 'block';
    }

    const userInput = document.getElementById('user-input');
    const outputDiv = document.getElementById('output');
    const sendButton = document.getElementById('send-button');

    function handleSend() {
      const commandText = userInput.value.trim();
      if (!commandText) {
        return;
      }
      userInput.disabled = true;
      sendButton.disabled = true;

      const newDiv = document.createElement('div');
      newDiv.innerHTML = `<span style="color: #ffd700;">&gt;</span> ${commandText}`;
      outputDiv.appendChild(newDiv);

      outputDiv.scrollTop = outputDiv.scrollHeight;

      // Dispatch Custom Event with Command Text
      document.dispatchEvent(new CustomEvent('input-received', { detail: commandText }));
      userInput.value = '';
    }

    function instaPrint(message) {
      const newDiv = document.createElement('div');
      newDiv.innerHTML = `<span style="color: #f1fa8c;">${message}</span>`;
      outputDiv.appendChild(newDiv);
      outputDiv.scrollTop = outputDiv.scrollHeight;
    }

    function slowPrint(message) {
      const newDiv = document.createElement('div');
      newDiv.innerHTML = `<span style="color: #f1fa8c;"></span>`;
      outputDiv.appendChild(newDiv);
      outputDiv.scrollTop = outputDiv.scrollHeight;

      let index = 0;
      const interval = setInterval(() => {
        if (index < message.length) {
          newDiv.innerHTML += message.charAt(index);
          index++;
          outputDiv.scrollTop = outputDiv.scrollHeight;
        } else {
          clearInterval(interval);
          userInput.disabled = false;
          sendButton.disabled = false;
          userInput.focus();
        }
      }, 30); // Adjust typing speed here
    }
  </script>

  <!-- PyScript Section -->
<py-script>
from js import document, window
import asyncio
import random
from pyodide.ffi import create_proxy

# HTML Elements
output_div = document.getElementById('output')
user_input = document.getElementById('user-input')
send_button = document.getElementById('send-button')

# Asynchronous Print Functions
async def print_message(message, delay, batch_size=7, color=None):
    lines = message.split('\n')
    for line in lines:
        temp_div = document.createElement('div')
        if color:
            temp_div.style.color = color
        temp_div.style.fontFamily = 'Roboto Mono, monospace'  # Ensure monospace font
        output_div.appendChild(temp_div)
        partial_message = ''
        i = 0
        while i < len(line):
            # Handle HTML entities (e.g., &lt;, &gt;)
            if line[i] == '&':
                semicolon_index = line.find(';', i)
                if semicolon_index != -1:
                    entity = line[i:semicolon_index+1]
                    partial_message += entity
                    i = semicolon_index + 1
                else:
                    partial_message += line[i]
                    i += 1
            else:
                partial_message += line[i]
                i += 1

            if (i % batch_size == 0) or (i == len(line)):
                temp_div.innerHTML += partial_message
                partial_message = ''
                await asyncio.sleep(delay)
        temp_div.innerHTML += '<br>'
        output_div.scrollTop = output_div.scrollHeight

async def insta_print(message, color=None):
    new_div = document.createElement('div')
    if color:
        new_div.style.color = color
    new_div.style.fontFamily = 'Roboto Mono, monospace'  # Ensure monospace font
    new_div.style.whiteSpace = 'pre-wrap'  # Preserve whitespace
    new_div.textContent = message  # Use textContent instead of innerHTML
    output_div.appendChild(new_div)
    output_div.scrollTop = output_div.scrollHeight

async def slow_print(message, color=None):
    await print_message(message, delay=0.07, batch_size=5, color=color)

async def fast_print(message, color=None):
    await print_message(message, delay=0.0025, batch_size=5, color=color)

async def medium_print(message, color=None):
    await print_message(message, delay=0.005, batch_size=5, color=color)

async def slow_input(prompt):
    await fast_print(prompt)
    user_input.disabled = False
    send_button.disabled = False
    user_input.value = ''
    user_input.focus()

    promise = asyncio.Future()

    def on_click(event):
        if user_input.value.strip() != '':
            promise.set_result(user_input.value.strip())
            send_button.disabled = True
            user_input.disabled = True

    input_handler = create_proxy(on_click)
    send_button.addEventListener('click', input_handler)

    def on_keypress(event):
        if event.key == 'Enter' and user_input.value.strip() != '':
            promise.set_result(user_input.value.strip())
            send_button.disabled = True
            user_input.disabled = True

    keypress_handler = create_proxy(on_keypress)
    user_input.addEventListener('keypress', keypress_handler)

    result = await promise
    send_button.removeEventListener('click', input_handler)
    user_input.removeEventListener('keypress', keypress_handler)
    return result.lower()

async def safe_int_input(prompt, min_val, max_val):
    while True:
        try:
            input_str = await slow_input(prompt)
            selected = int(input_str)
            if min_val <= selected <= max_val:
                return selected
            else:
                await fast_print(f"Please enter a number between {min_val} and {max_val}.")
        except ValueError:
            await fast_print("Invalid input. Please enter a valid number.")

# Game Constants and Data
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},
}

TOWNS = [
    "Amberville", "Brightstone", "Crimsonburg", "Dusktown",
    "Sunset City", "Northport", "Riverside", "Hilltop",
    "Lakeside", "Oakwood", "Stormhaven", "Fairview"
]

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

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

RELATIONSHIP_BASE = 0
RELATIONSHIP_MAX = 100
RELATIONSHIP_MIN = -100

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."""
        num_actions = random.randint(1, 3) if self.aggressiveness > 1.0 else random.randint(1, 2)
        for _ in range(num_actions):
            action = random.choices(["BUY", "SELL"], weights=[self.aggressiveness, 1.0])[0]
            good = random.choice(list(GOODS.keys()))
            quantity = random.randint(1, int(10 * self.aggressiveness))
            if action == "BUY":
                if market.supply[good] >= quantity:
                    market.supply[good] -= quantity
                    market.demand[good] += quantity * 0.5
            elif action == "SELL":
                market.supply[good] += quantity
                market.demand[good] -= quantity * 0.5
                if market.demand[good] < 50:
                    market.demand[good] = 50

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

    def __init__(self, town):
        self.town = town
        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()
        self.ai_traders = [AITrader(trader_id=i+1, aggressiveness=random.uniform(0.8, 1.2)) for i in range(10)]

    def generate_prices(self):
        """Calculates current prices based on supply and demand with elasticity and price constraints."""
        for good, info in GOODS.items():
            if self.supply[good] == 0:
                price_multiplier = 2
            else:
                ratio = self.demand[good] / self.supply[good]
                elasticity = random.uniform(0.90, 1.10)
                price_multiplier = ratio * elasticity
            new_price = int(GOODS[good]["base_price"] * price_multiplier)
            new_price = max(self.PRICE_FLOOR, min(new_price, self.PRICE_CEILING))
            self.prices[good] = new_price

    async def display_prices(self, relationship):
        """Displays the current prices, supply, demand, and relationship for all goods in the market."""
        status = Game.get_relationship_status(relationship)
        await slow_print(f"\nMarket Overview in {self.town}: Relationship: {relationship} ({status})", color='magenta')
        for good, price in self.prices.items():
            supply = int(self.supply[good])
            demand = int(self.demand[good])
            await fast_print(f"{good}: ${price} (Supply: {supply}, Demand: {demand})")
        await fast_print("")

    def process_ai_traders(self):
        """Processes all AI traders' actions for the market."""
        for trader in self.ai_traders:
            trader.perform_action(self)
        self.generate_prices()

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

    async def status(self):
        """Displays the player's current status."""
        await slow_print(f"\nPlayer Status:", color='blue')
        await fast_print(f"Location: {self.location}")
        await fast_print(f"Money: ${self.money}")
        await fast_print(f"Cargo: {self.current_cargo}/{self.max_cargo} units used")
        await fast_print("Inventory:")
        for good, qty in self.inventory.items():
            await fast_print(f"  {good}: {qty}")
        await fast_print("")

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

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

    async 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:
            await slow_print("Insufficient funds to upgrade cargo capacity.")
            return
        confirm = await slow_input(f"Upgrade cargo capacity by {upgrade_amount} for {upgrade_cost} gold? (Y/N): ")
        if confirm.upper() == 'y':
            self.money -= upgrade_cost
            self.max_cargo += upgrade_amount
            self.cargo_upgrades += 1
            await slow_print(f"Cargo capacity increased by {upgrade_amount}. New capacity: {self.max_cargo}")
            self.event_log.append(f"Upgraded cargo capacity by {upgrade_amount} for {upgrade_cost} gold.")

class Game:
    """Represents the main game loop and logic."""

    def __init__(self):
        self.difficulty = None
        self.player = None
        self.turns_total = 0
        self.markets = {}
        self.current_market = None
        self.current_event = None
        self.supply_decay_rate = 0.02
        self.demand_decay_rate = 0.02
        self.turn_counter = 1
        self.game_over = False
        self.key_events = []

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

    async def choose_difficulty(self):
        """Allows the player to choose a difficulty level."""
        await fast_print("Choose Difficulty Level:")
        for idx, level in enumerate(DIFFICULTIES.keys(), 1):
            await fast_print(f"{idx}. {level.capitalize()}")
        choice = await safe_int_input(f"Enter the number corresponding to your choice (1-{len(DIFFICULTIES)}): ", 1, len(DIFFICULTIES))
        selected = list(DIFFICULTIES.keys())[choice - 1]
        await fast_print(f"Selected {selected.capitalize()} difficulty.\n")
        self.difficulty = selected
        self.player = Player(
            starting_money=DIFFICULTIES[self.difficulty]["starting_money"],
            starting_cargo=DIFFICULTIES[self.difficulty]["starting_cargo"]
        )
        self.turns_total = DIFFICULTIES[self.difficulty]["turns"]
        self.markets = {town: Market(town) for town in TOWNS}
        self.current_market = self.markets[self.player.location]

    async def start(self):
        """Starts the game by displaying the title and welcome message."""
        ascii_art_lines = [
            r" __  __    _    ____  _  _______ _____ ",
            r"|  \/  |  / \  |  _ \| |/ / ____|_   _|",
            r"| |\/| | / _ \ | |_) | ' /|  _|   | |  ",
            r"| |  | |/ ___ \|  _ <| . \| |___  | |  ",
            r"|_|  |_/_/   \_\_| \_\_____| |_|  ",
        ]
        ascii_art = '\n'.join(ascii_art_lines)  # Use newline characters
        await insta_print(ascii_art, color='cyan')
        
        # Insta print lines of '=' signs
        await insta_print("=" * 60, color='yellow')
        await slow_print("Welcome to the Text-Based Trading Game!", color='yellow')
        await insta_print("=" * 60, color='yellow')
        
        # Slow print game introduction
        game_description = (
            "Your goal is to accumulate as much wealth as possible within a set number of turns.\n"
            "Explore a variety of goods, manage your cargo capacity, and navigate the dynamic market."
        )
        await slow_print(game_description, color='yellow')
        await self.choose_difficulty()
        await self.game_loop()

    async def game_loop(self):
        """Main game loop that runs until the player runs out of turns."""
        while self.turn_counter <= self.turns_total and not self.game_over:
            await medium_print(f"\n--- Turn {self.turn_counter}/{self.turns_total} ---")
            self.apply_decay()
            for market in self.markets.values():
                market.process_ai_traders()
            self.trigger_event()
            current_relationship = self.player.relationships[self.player.location]
            await self.current_market.display_prices(current_relationship)
            await self.player.status()
            command = await slow_input("Enter command (BUY/SELL/TRAVEL/STATUS/UPGRADE/OVERVIEW/HELP/EXIT): ")
            command = command.lower()
            if command == "buy":
                await self.buy()
            elif command == "sell":
                await self.sell()
            elif command == "travel":
                await self.travel()
            elif command == "status":
                await self.player.status()
                continue
            elif command == "upgrade":
                await self.player.upgrade_cargo()
                continue
            elif command == "overview":
                await self.market_overview()
                continue
            elif command == "help":
                await slow_print("""
Available Commands:
BUY - Purchase goods from the market.
SELL - Sell goods from your inventory.
TRAVEL - Move to a different town.
STATUS - View your current status.
UPGRADE - Upgrade your cargo capacity.
OVERVIEW - View market overview across all towns.
HELP - Display this help message.
EXIT - Exit the game.
""".strip(), color='yellow')
                continue
            elif command == "exit":
                await slow_print("Thank you for playing!")
                await self.end_game()
                return
            else:
                await fast_print("Invalid command.")
                continue
            self.turn_counter += 1
        await self.end_game()

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

        price = self.current_market.prices[good]
        max_affordable_quantity = self.player.money // price
        available_cargo_space = self.player.max_cargo - self.player.current_cargo
        max_cargo_quantity = available_cargo_space // GOODS[good]["weight"]
        max_supply = int(self.current_market.supply[good])
        max_quantity = min(max_affordable_quantity, max_cargo_quantity, max_supply)

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

        await fast_print(f"You can afford up to {max_quantity} units.")
        quantity = await safe_int_input(f"Enter the quantity of {good} to buy (max {max_quantity}): ", 1, max_quantity)

        cost = price * quantity
        success, added_weight = self.player.add_cargo(good, quantity)
        if not success:
            await slow_print("Not enough cargo space.")
            return

        self.player.money -= cost
        self.current_market.supply[good] -= quantity
        self.current_market.demand[good] += quantity * 0.3
        await slow_print(f"Bought {quantity} {good} for ${cost}.")

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

        max_sell_quantity = self.player.inventory[good]
        quantity = await safe_int_input(f"Enter the quantity of {good} to sell (max {max_sell_quantity}): ", 1, max_sell_quantity)

        price = self.current_market.prices[good]
        revenue = price * quantity

        self.player.money += revenue
        self.player.remove_cargo(good, quantity)
        self.current_market.supply[good] += quantity
        self.current_market.demand[good] -= quantity * 0.3
        await slow_print(f"Sold {quantity} {good} for ${revenue}.")

    async def travel(self):
        """Handles the travel process for the player."""
        available_towns = [town for town in TOWNS if town != self.player.location]
        await slow_print("Available towns to travel to:")
        for idx, town in enumerate(available_towns, 1):
            await fast_print(f"{idx}. {town}")
        choice = await safe_int_input("Enter the number of the town you want to travel to: ", 1, len(available_towns))
        new_location = available_towns[choice - 1]
        self.player.location = new_location
        self.current_market = self.markets[new_location]
        await slow_print(f"Traveled to {new_location}.")

    async def choose_good(self, action):
        """Prompts the player to choose a good to buy or sell."""
        await fast_print("Available goods:")
        for idx, good in enumerate(GOODS.keys(), 1):
            await fast_print(f"{idx}. {good}")
        choice = await safe_int_input(f"Enter the number of the good to {action}: ", 1, len(GOODS))
        return list(GOODS.keys())[choice - 1]

    async def end_game(self):
        """Displays the final game results and concludes the game."""
        await slow_print("\nGame Over!")
        await fast_print(f"Final Money: ${self.player.money}")
        total_goods = sum(self.player.inventory.values())
        await fast_print(f"Total Goods: {total_goods}")
        await slow_print("Thank you for playing the Text-Based Trading Game!")

    def apply_decay(self):
        """Applies decay to supply and demand in all markets."""
        for good, info in GOODS.items():
            for market in self.markets.values():
                market.supply[good] += (info["base_supply"] - market.supply[good]) * self.supply_decay_rate
                market.demand[good] += (info["base_demand"] - market.demand[good]) * self.demand_decay_rate

    def trigger_event(self):
        """Randomly triggers a global or local event."""
        event_chance = DIFFICULTIES[self.difficulty]["event_chance"]
        if random.random() < event_chance:
            event = random.choice(GLOBAL_EVENTS + LOCAL_EVENTS)
            asyncio.create_task(insta_print(f"\nEvent: {event}", color='red'))

# Initialize and start the game
game_instance = Game()
asyncio.create_task(game_instance.start())
</py-script>
</body> 
</html>