Flesh this out with an advanced economy system and more towns.



#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import random
import time
import sys
import os

try:
    from colorama import init, Fore, Style
except ImportError:
    print("Please install the 'colorama' module to run this game.")
    sys.exit()

# Initialize colorama
init(autoreset=True)

# ASCII Art and Flourishes
GAME_TITLE = r"""
   ________________________________________________________
  /                                                        \
  |   _______          _          _____      _             |
  |  |__   __|        | |        / ____|    | |            |
  |     | | ___   ___ | | __    | |     __ _| | ___        |
  |     | |/ _ \ / _ \| |/ /    | |    / _` | |/ _ \       |
  |     | | (_) | (_) |   <     | |___| (_| | |  __/       |
  |     |_|\___/ \___/|_|\_\     \_____\__,_|_|\___|       |
  |                                                        |
  |________________________________________________________|
"""

WELCOME_ART = r"""
    _____________________________________________________________
   /                                                             \
   |  Welcome to the Text-Based Trading Game!                    |
   |  Your goal is to accumulate wealth by trading goods         |
   |  across various towns. Beware of fluctuating prices and     |
   |  random events that may impact your journey.                |
   |_____________________________________________________________|
"""

GOOD_LUCK = r"""
  _____                 _      _   _             
 |  __ \               | |    | | (_)            
 | |  | | ___  ___  ___| | ___| |_ _  ___  _ __  
 | |  | |/ _ \/ __|/ _ \ |/ _ \ __| |/ _ \| '_ \ 
 | |__| |  __/\__ \  __/ |  __/ |_| | (_) | | | |
 |_____/ \___||___/\___|_|\___|\__|_|\___/|_| |_|
"""

# Game Data
TOWNS = ['Eastvale', 'Westport', 'Northwich', 'Southvale', 'Central City']
GOODS = ['Spices', 'Gems', 'Food', 'Textiles', 'Metals']
EVENTS = ['Thieves', 'Bad Weather', 'Bandits', 'Market Crash', 'Steady Market', 'Nothing Happens']

# Player Class
class Player:
    def __init__(self):
        self.gold = 100
        self.inventory = {good: 0 for good in GOODS}
        self.current_town = random.choice(TOWNS)
        self.turns = 20  # Number of turns to play

    def show_status(self):
        print(Fore.CYAN + f"\nCurrent Gold: {self.gold} | Current Town: {self.current_town} | Turns Left: {self.turns}")
        print("Inventory:")
        for good, amount in self.inventory.items():
            print(Fore.YELLOW + f"{good}: {amount}")
        print(Style.RESET_ALL)

# Game Class
class Game:
    def __init__(self):
        self.prices = {town: {good: self.generate_initial_price(good) for good in GOODS} for town in TOWNS}
        self.event_occurred = False

    def generate_initial_price(self, good):
        if good == 'Spices':
            return random.randint(20, 50)
        elif good == 'Gems':
            return random.randint(70, 150)
        elif good == 'Food':
            return random.randint(5, 15)
        elif good == 'Textiles':
            return random.randint(10, 30)
        elif good == 'Metals':
            return random.randint(25, 60)
        else:
            return 50  # default price

    def update_economy(self):
        # Update prices for each good in each town
        for town in TOWNS:
            for good in GOODS:
                # Simulate price changes
                price_change = random.randint(-5, 5)
                self.prices[town][good] += price_change
                # Ensure prices stay within reasonable bounds
                if self.prices[town][good] < 1:
                    self.prices[town][good] = 1

    def get_prices(self, town):
        return self.prices[town]

    def random_event(self, player):
        event = random.choice(EVENTS)
        if event == 'Nothing Happens':
            print(Fore.GREEN + "\nNothing happened this turn.")
            self.event_occurred = False
        else:
            self.event_occurred = True
            print(Fore.RED + f"\nEvent Triggered: {event}!")
            if event == 'Thieves':
                loss = random.randint(10, 30)
                player.gold = max(0, player.gold - loss)
                print(Fore.RED + f"You lost {loss} gold to thieves!")
            elif event == 'Bad Weather':
                print(Fore.RED + "Traveling to the next town took extra time.")
                player.turns -= 1
            elif event == 'Bandits':
                loss = random.randint(1, 3)
                good = random.choice(GOODS)
                player.inventory[good] = max(0, player.inventory[good] - loss)
                print(Fore.RED + f"Bandits stole {loss} units of {good}!")
            elif event == 'Market Crash':
                print(Fore.RED + "The market is unstable! Prices fluctuate wildly.")
                # Drastically change the economy
                for town in TOWNS:
                    for good in GOODS:
                        self.prices[town][good] = max(1, self.prices[town][good] + random.randint(-20, 20))
            elif event == 'Steady Market':
                print(Fore.GREEN + "The market is steady. No major events.")
        print(Style.RESET_ALL)

# Market Class
class Market:
    def __init__(self, town, game):
        self.town = town
        self.prices = game.get_prices(town)

    def show_prices(self):
        print(Fore.GREEN + f"\nMarket Prices in {self.town}:")
        for good, price in self.prices.items():
            print(Fore.MAGENTA + f"{good}: {price} gold per unit")
        print(Style.RESET_ALL)

    def get_price(self, good):
        return self.prices[good]

# Game Functions
def clear_screen():
    # Do not clear the screen to preserve initial text
    pass  # Do nothing to prevent clearing the initial text

def slow_print(text, delay=0.05):
    for c in text:
        sys.stdout.write(c)
        sys.stdout.flush()
        time.sleep(delay)
    print()

def main():
    clear_screen()
    print(Fore.YELLOW + GAME_TITLE)
    time.sleep(1)
    print(Fore.CYAN + WELCOME_ART)
    time.sleep(2)

    player = Player()
    game = Game()

    while player.turns > 0:
        # Instead of clearing the screen, print a separator
        print("\n" + "=" * 60)
        player.show_status()
        market = Market(player.current_town, game)
        market.show_prices()

        # Buy or Sell Phase
        action = ''
        while action.lower() not in ['b', 's', 't', 'q']:
            print(Fore.GREEN + "\nWhat would you like to do?")
            print("B) Buy Goods")
            print("S) Sell Goods")
            print("T) Travel to Another Town")
            print("Q) Quit Game")
            action = input("Enter your choice: ").strip()

        if action.lower() == 'b':
            buy_goods(player, market)
        elif action.lower() == 's':
            sell_goods(player, market)
        elif action.lower() == 't':
            travel(player)
            player.turns -= 1
            game.update_economy()
            game.random_event(player)
            continue
        elif action.lower() == 'q':
            break

        # Post-action Events
        game.update_economy()
        game.random_event(player)
        time.sleep(2)

        input("\nPress Enter to continue...")
        player.turns -= 1

    # Game Over
    print(Fore.YELLOW + GOOD_LUCK)
    print(Fore.GREEN + f"\nGame Over! You ended with {player.gold} gold.")
    print("Thanks for playing!")
    print(Style.RESET_ALL)

def buy_goods(player, market):
    print(Fore.BLUE + "\nAvailable Goods to Buy:")
    for index, good in enumerate(GOODS, start=1):
        price = market.get_price(good)
        print(Fore.MAGENTA + f"{index}) {good} - {price} gold per unit")

    try:
        choice = int(input(Fore.GREEN + "\nEnter the number of the good you want to buy: ").strip())
        if 1 <= choice <= len(GOODS):
            good = GOODS[choice - 1]
            price = market.get_price(good)
            max_units = player.gold // price
            if max_units == 0:
                print(Fore.RED + "You don't have enough gold to buy any units of this good.")
                return
            print(Fore.YELLOW + f"You can buy up to {max_units} units of {good}.")
            quantity = int(input("Enter the quantity you want to buy: ").strip())
            if 0 < quantity <= max_units:
                total_cost = price * quantity
                player.gold -= total_cost
                player.inventory[good] += quantity
                print(Fore.GREEN + f"Purchased {quantity} units of {good} for {total_cost} gold.")
            else:
                print(Fore.RED + "Invalid quantity.")
        else:
            print(Fore.RED + "Invalid choice.")
    except ValueError:
        print(Fore.RED + "Please enter a valid number.")
    print(Style.RESET_ALL)

def sell_goods(player, market):
    print(Fore.BLUE + "\nYour Goods to Sell:")
    owned_goods = {good: qty for good, qty in player.inventory.items() if qty > 0}
    if not owned_goods:
        print(Fore.RED + "You have no goods to sell.")
        return

    for index, (good, qty) in enumerate(owned_goods.items(), start=1):
        price = market.get_price(good)
        print(Fore.MAGENTA + f"{index}) {good} - {qty} units available - {price} gold per unit")

    try:
        choice = int(input(Fore.GREEN + "\nEnter the number of the good you want to sell: ").strip())
        if 1 <= choice <= len(owned_goods):
            good = list(owned_goods.keys())[choice - 1]
            qty_owned = player.inventory[good]
            price = market.get_price(good)
            print(Fore.YELLOW + f"You have {qty_owned} units of {good}.")
            quantity = int(input("Enter the quantity you want to sell: ").strip())
            if 0 < quantity <= qty_owned:
                total_earnings = price * quantity
                player.gold += total_earnings
                player.inventory[good] -= quantity
                print(Fore.GREEN + f"Sold {quantity} units of {good} for {total_earnings} gold.")
            else:
                print(Fore.RED + "Invalid quantity.")
        else:
            print(Fore.RED + "Invalid choice.")
    except ValueError:
        print(Fore.RED + "Please enter a valid number.")
    print(Style.RESET_ALL)

def travel(player):
    print(Fore.BLUE + "\nAvailable Towns to Travel:")
    other_towns = [town for town in TOWNS if town != player.current_town]
    for index, town in enumerate(other_towns, start=1):
        print(Fore.MAGENTA + f"{index}) {town}")

    try:
        choice = int(input(Fore.GREEN + "\nEnter the number of the town you want to travel to: ").strip())
        if 1 <= choice <= len(other_towns):
            player.current_town = other_towns[choice - 1]
            print(Fore.GREEN + f"Traveled to {player.current_town}.")
        else:
            print(Fore.RED + "Invalid choice.")
    except ValueError:
        print(Fore.RED + "Please enter a valid number.")
    print(Style.RESET_ALL)

# Run the Game
if __name__ == "__main__":
    main()