Untitled

 avatar
unknown
plain_text
a month ago
12 kB
4
Indexable
import pygame
import sys
import random
import csv
import time

# ------------------------------
# Constants and Configuration
# ------------------------------
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
FPS = 60

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREY = (200, 200, 200)
CITY_COLOR = (150, 50, 50)
PLAYER_COLOR = (50, 150, 50)
MENU_BG_COLOR = (50, 50, 50)
MENU_TEXT_COLOR = (255, 255, 255)

# ------------------------------
# Helper Functions
# ------------------------------
def load_census_data(filename):
    """
    Loads census-like data from a CSV file.
    The CSV should have columns: city, population, x, y,
    where x and y are normalized coordinates (0.0 to 1.0).
    """
    cities = []
    try:
        with open(filename, mode='r', encoding='utf-8') as csvfile:
            reader = csv.DictReader(csvfile)
            for row in reader:
                try:
                    city = row['city']
                    population = int(row['population'])
                    x = float(row['x'])
                    y = float(row['y'])
                    cities.append({'name': city, 'population': population, 'x': x, 'y': y})
                except ValueError:
                    continue  # skip rows with invalid data
    except FileNotFoundError:
        print("Census file not found. Make sure 'census.csv' exists in the same directory.")
    return cities

# ------------------------------
# Game World Entities
# ------------------------------
class City:
    def __init__(self, name, population, x, y):
        self.name = name
        self.population = population
        self.x = int(x * SCREEN_WIDTH)
        self.y = int(y * SCREEN_HEIGHT)
        # Radius scaled to population (ensuring a minimum and maximum)
        self.radius = max(5, min(population // 50000, 30))
        self.crime_rate = random.uniform(0, 1)  # Scale 0 (low) to 1 (high)
        self.economy = random.uniform(0.5, 1.5)   # Economic multiplier
        self.businesses = []  # List of business opportunities

    def draw(self, surface):
        pygame.draw.circle(surface, CITY_COLOR, (self.x, self.y), self.radius)
        font = pygame.font.SysFont("arial", 14)
        text = font.render(self.name, True, BLACK)
        surface.blit(text, (self.x - self.radius, self.y - self.radius - 15))
    
    def simulate_day(self):
        # Random fluctuation in crime rate and economy
        self.crime_rate = max(0, min(self.crime_rate + random.uniform(-0.05, 0.05), 1))
        self.economy = max(0.1, self.economy + random.uniform(-0.05, 0.05))
        # Future expansion: simulate business growth, local events, etc.

class Player:
    def __init__(self, world):
        self.world = world
        # Start in the middle of the screen
        self.x = SCREEN_WIDTH // 2
        self.y = SCREEN_HEIGHT // 2
        self.size = 20
        self.speed = 4
        self.wealth = 10000  # Starting money
        self.reputation = 50  # Scale from 0 to 100
        self.current_city = None
        self.role = "Neutral"  # Options: "Neutral", "Billionaire", "Mafia Boss"
    
    def handle_input(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            self.x -= self.speed
        if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            self.x += self.speed
        if keys[pygame.K_UP] or keys[pygame.K_w]:
            self.y -= self.speed
        if keys[pygame.K_DOWN] or keys[pygame.K_s]:
            self.y += self.speed

        # Constrain player within screen boundaries
        self.x = max(0, min(self.x, SCREEN_WIDTH - self.size))
        self.y = max(0, min(self.y, SCREEN_HEIGHT - self.size))
    
    def draw(self, surface):
        pygame.draw.rect(surface, PLAYER_COLOR, (self.x, self.y, self.size, self.size))
    
    def interact(self):
        """
        Check if the player is near a city and return that city if so.
        """
        for city in self.world.cities:
            dx = city.x - self.x
            dy = city.y - self.y
            dist = (dx**2 + dy**2) ** 0.5
            if dist < city.radius + self.size:
                self.current_city = city
                return city
        self.current_city = None
        return None

class Faction:
    def __init__(self, name, influence, funds):
        self.name = name
        self.influence = influence  # 0 to 100 scale
        self.funds = funds

    def update_influence(self):
        # Factions fluctuate based on world events; simplistic update for now.
        self.influence = max(0, min(self.influence + random.uniform(-1, 1), 100))

class World:
    def __init__(self):
        self.cities = []
        census_data = load_census_data("census.csv")
        for data in census_data:
            self.cities.append(City(data['name'], data['population'], data['x'], data['y']))
        # Create factions representing divergent paths
        self.factions = {
            "Mafia": Faction("Underground Crime Syndicate", influence=50, funds=500000),
            "Corporation": Faction("Global Conglomerate", influence=50, funds=1000000)
        }
        self.day = 1
        self.event_log = ["Welcome to Modern America!"]

    def simulate_day(self):
        # Update each city's simulation and each faction's influence.
        for city in self.cities:
            city.simulate_day()
        for faction in self.factions.values():
            faction.update_influence()
        self.day += 1
        self.event_log.append(f"Day {self.day}: Global events shift the balance.")

# ------------------------------
# Game Class and Main Loop
# ------------------------------
class Game:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption("Open World Sandbox: Modern America")
        self.clock = pygame.time.Clock()
        self.running = True

        self.world = World()
        self.player = Player(self.world)
        self.last_day_update = time.time()
        self.font = pygame.font.SysFont("arial", 18)

        # Menu system variables for contextual actions
        self.menu_mode = False
        self.menu_text = ""
        self.menu_options = {}
    
    def draw_ui(self):
        # Display player's stats and global state at the top left.
        stats = [
            f"Wealth: ${self.player.wealth}",
            f"Reputation: {self.player.reputation}",
            f"Day: {self.world.day}",
            f"Role: {self.player.role}"
        ]
        y = 10
        for stat in stats:
            text = self.font.render(stat, True, BLACK)
            self.screen.blit(text, (10, y))
            y += 20

        # Display the last few events
        y_offset = 100
        for event in self.world.event_log[-3:]:
            event_text = self.font.render(event, True, BLACK)
            self.screen.blit(event_text, (10, y_offset))
            y_offset += 20

        if self.menu_mode:
            # Draw semi-transparent overlay for the menu
            overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
            overlay.set_alpha(200)
            overlay.fill(GREY)
            self.screen.blit(overlay, (0, 0))
            lines = self.menu_text.split('\n')
            y = SCREEN_HEIGHT // 2 - len(lines)*15
            for line in lines:
                menu_line = self.font.render(line, True, MENU_TEXT_COLOR)
                self.screen.blit(menu_line, (SCREEN_WIDTH//2 - 200, y))
                y += 30

    def process_menu_input(self, event):
        # Basic menu input processing: choose an option based on number keys.
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_1 and "1" in self.menu_options:
                self.menu_options["1"]()
            elif event.key == pygame.K_2 and "2" in self.menu_options:
                self.menu_options["2"]()
            elif event.key == pygame.K_3 and "3" in self.menu_options:
                self.menu_options["3"]()
            elif event.key == pygame.K_ESCAPE:
                self.menu_mode = False

    # ------------------------------
    # Player Career Choices
    # ------------------------------
    def choose_billionaire_path(self):
        self.player.role = "Billionaire"
        self.player.wealth += 1000000
        self.player.reputation += 10
        self.world.factions["Corporation"].funds += 500000
        self.world.event_log.append("Your investments soared! Welcome to the billionaire club.")
        self.menu_mode = False

    def choose_mafia_path(self):
        self.player.role = "Mafia Boss"
        self.player.wealth += 500000
        self.player.reputation -= 20  # Underground life comes at a cost
        self.world.factions["Mafia"].funds += 250000
        self.world.event_log.append("You now run an underground crime syndicate.")
        self.menu_mode = False

    def invest_in_city(self, city):
        # A sample economic action where investing can yield gains or losses.
        investment = random.randint(1000, 10000)
        result = random.choice(["gain", "loss"])
        if result == "gain":
            profit = int(investment * random.uniform(0.1, 0.5) * city.economy)
            self.player.wealth += profit
            self.world.event_log.append(f"Invested in {city.name}: +${profit}")
        else:
            loss = int(investment * random.uniform(0.1, 0.5))
            self.player.wealth = max(0, self.player.wealth - loss)
            self.world.event_log.append(f"Invested in {city.name}: -${loss}")
        self.menu_mode = False

    # ------------------------------
    # Game Loop Methods
    # ------------------------------
    def update(self):
        # Update the world simulation: every 10 seconds equals a new day.
        current_time = time.time()
        if current_time - self.last_day_update > 10:
            self.world.simulate_day()
            self.last_day_update = current_time

        # Process player movement
        self.player.handle_input()
        city = self.player.interact()
        # If near a city, open a contextual menu for choices.
        if city and not self.menu_mode:
            self.menu_mode = True
            self.menu_text = (
                f"You have arrived in {city.name}.\n"
                "Choose your action:\n"
                "1. Invest in local businesses (Billionaire path)\n"
                "2. Engage in underground operations (Mafia path)\n"
                "3. Explore the city further\n"
                "Press ESC to cancel."
            )
            # Map keys to functions. Option 3 just cancels the menu.
            self.menu_options = {
                "1": self.choose_billionaire_path,
                "2": self.choose_mafia_path,
                "3": lambda: setattr(self, 'menu_mode', False)
            }

    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
            if self.menu_mode:
                self.process_menu_input(event)

    def draw(self):
        self.screen.fill(WHITE)
        # Draw cities on the world map
        for city in self.world.cities:
            city.draw(self.screen)
        # Draw the player
        self.player.draw(self.screen)
        # Draw the UI overlay
        self.draw_ui()
        pygame.display.flip()

    def run(self):
        while self.running:
            self.clock.tick(FPS)
            self.handle_events()
            self.update()
            self.draw()
        pygame.quit()
        sys.exit()

# ------------------------------
# Entry Point
# ------------------------------
if __name__ == '__main__':
    game = Game()
    game.run()
Editor is loading...
Leave a Comment