import streamlit as st import os import random import time from PIL import Image import json from datetime import datetime from pathlib import Path import base64 from io import BytesIO # Constants for game board GRID_WIDTH = 16 GRID_HEIGHT = 9 REFRESH_RATE = 5 # seconds # Fantasy name generator def generate_fantasy_name(): prefixes = ['Aer', 'Bal', 'Cal', 'Dor', 'El', 'Fae', 'Gor', 'Hel', 'Il', 'Jor', 'Kal', 'Lyr', 'Mel', 'Nym', 'Oro', 'Pyr', 'Qar', 'Ryn', 'Syl', 'Tyr'] suffixes = ['ian', 'or', 'ion', 'us', 'ix', 'ar', 'en', 'yr', 'el', 'an', 'is', 'ax', 'on', 'ir', 'ex', 'az', 'er', 'eth', 'ys', 'ix'] return random.choice(prefixes) + random.choice(suffixes) # Initialize session state if 'initialized' not in st.session_state: st.session_state.initialized = False st.session_state.game_state = { 'players': {}, 'chat_messages': [], 'last_sync': time.time() } st.session_state.player_name = None st.session_state.character_stats = None st.session_state.position = { 'x': random.randint(0, GRID_WIDTH - 1), 'y': random.randint(0, GRID_HEIGHT - 1) } st.session_state.last_move = time.time() def roll_stats(): return { 'STR': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), 'DEX': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), 'CON': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), 'INT': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), 'WIS': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), 'CHA': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), 'HP': random.randint(1, 20) * 2 + random.randint(1, 20), 'MAX_HP': 40, 'score': 0, 'created_at': time.time() } def save_character_sheet(player_name, stats): """Save character sheet as markdown""" filepath = f"characters/{player_name}.md" os.makedirs('characters', exist_ok=True) markdown = f"""# {player_name}'s Character Sheet ## Stats - **STR**: {stats['STR']} - **DEX**: {stats['DEX']} - **CON**: {stats['CON']} - **INT**: {stats['INT']} - **WIS**: {stats['WIS']} - **CHA**: {stats['CHA']} ## Health HP: {stats['HP']}/{stats['MAX_HP']} ## Score Current Score: {stats['score']} ## Position X: {st.session_state.position['x']}, Y: {st.session_state.position['y']} ## Session Info Created: {datetime.fromtimestamp(stats['created_at']).strftime('%Y-%m-%d %H:%M:%S')} Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} """ with open(filepath, 'w') as f: f.write(markdown) def load_character_sheet(player_name): """Load character sheet if it exists""" filepath = f"characters/{player_name}.md" if os.path.exists(filepath): with open(filepath, 'r') as f: return f.read() return None def update_position(direction): """Update player position with wrapping""" if direction == "up": st.session_state.position['y'] = (st.session_state.position['y'] - 1) % GRID_HEIGHT elif direction == "down": st.session_state.position['y'] = (st.session_state.position['y'] + 1) % GRID_HEIGHT elif direction == "left": st.session_state.position['x'] = (st.session_state.position['x'] - 1) % GRID_WIDTH elif direction == "right": st.session_state.position['x'] = (st.session_state.position['x'] + 1) % GRID_WIDTH st.session_state.last_move = time.time() if st.session_state.character_stats: save_character_sheet(st.session_state.player_name, st.session_state.character_stats) def create_game_board(): """Create and display the game board""" # Create placeholder images for tiles tile_image = Image.new('RGB', (50, 50), color='green') player_image = Image.new('RGB', (50, 50), color='blue') # Create columns for each row for y in range(GRID_HEIGHT): cols = st.columns(GRID_WIDTH) for x in range(GRID_WIDTH): # Display player or tile if (x == st.session_state.position['x'] and y == st.session_state.position['y']): cols[x].image(player_image, use_column_width=True) else: cols[x].image(tile_image, use_column_width=True) def main(): # Sidebar for player info and controls st.sidebar.title("Player Info") # Player name handling if st.session_state.player_name is None: default_name = generate_fantasy_name() player_name = st.sidebar.text_input("Enter your name or use generated name:", value=default_name) if st.sidebar.button("Start Playing"): st.session_state.player_name = player_name if st.session_state.character_stats is None: st.session_state.character_stats = roll_stats() save_character_sheet(player_name, st.session_state.character_stats) st.rerun() else: # Show current name and allow changes new_name = st.sidebar.text_input("Your name:", value=st.session_state.player_name) if new_name != st.session_state.player_name: old_name = st.session_state.player_name st.session_state.player_name = new_name os.rename(f"characters/{old_name}.md", f"characters/{new_name}.md") st.rerun() # Display character sheet character_sheet = load_character_sheet(st.session_state.player_name) if character_sheet: st.sidebar.markdown(character_sheet) # Movement controls st.sidebar.markdown("### Movement Controls") move_cols = st.sidebar.columns(3) if move_cols[1].button("⬆️", key="up"): update_position("up") st.rerun() cols = st.sidebar.columns(3) if cols[0].button("⬅️", key="left"): update_position("left") st.rerun() if cols[1].button("⬇️", key="down"): update_position("down") st.rerun() if cols[2].button("➡️", key="right"): update_position("right") st.rerun() # Main game area st.title("Multiplayer Tile Game") # Display game board create_game_board() # Auto-refresh logic if (time.time() - st.session_state.last_move) > REFRESH_RATE: st.session_state.last_move = time.time() st.rerun() if __name__ == "__main__": main()