GameConfigIdea / my_text_game_engine_attempt.py
kwabs22
Some changes and flie splitting
a69d738
import gradio as gr
import json
import os
import tempfile
import shutil
import zipfile
from relatively_constant_variables import finished_product_demo, all_states
class Player:
def __init__(self):
self.inventory = []
self.money = 20
self.knowledge = {}
def add_item(self, item):
self.inventory.append(item)
def has_item(self, item):
return item in self.inventory
def update_knowledge(self, topic):
self.knowledge[topic] = True
class GameSession:
def __init__(self, starting_location='village', starting_state='start'):
self.player = Player()
self.current_location = starting_location
self.current_state = starting_state
self.game_log = []
def make_choice(self, choice_index):
state = all_states[self.current_location][self.current_state]
if 0 <= choice_index < len(state['choices']):
choice = state['choices'][choice_index]
next_state = state['transitions'][choice]
self.game_log.append(f"You chose: {choice}")
self.game_log.append(state['description'])
if 'consequences' in state and choice in state['consequences']:
if state['consequences'][choice]:
state['consequences'][choice](self.player)
else:
# Handle empty consequence, e.g., log a message or provide a default action
print(f"No consequence for choice: {choice}")
# You can add any default action here if needed
if '_' in next_state:
self.current_location, self.current_state = next_state.split('_')
else:
self.current_state = next_state
return self.get_current_state_info()
else:
return "Invalid choice. Please try again."
def get_current_state_info(self):
state = all_states[self.current_location][self.current_state]
choices = [f"{idx + 1}. {choice}" for idx, choice in enumerate(state['choices'])]
return state['description'], choices, "\n".join(self.game_log)
def get_current_state_media(self):
media = all_states[self.current_location][self.current_state]['media']
return media
def start_game(starting_location='village', starting_state='start', new_states=all_states):
global all_states
game_session = GameSession(starting_location, starting_state)
description, choices, game_log = game_session.get_current_state_info()
all_states = new_states
return description, choices, game_log, game_session
def make_choice(choice, game_session, with_media=False): #Calls the nested make choice function in the game session class
if not choice:
description, choices, game_log = game_session.get_current_state_info()
return description, choices, "Please select a choice before proceeding.", game_session
choice_index = int(choice.split('.')[0]) - 1
result = game_session.make_choice(choice_index)
if with_media:
media = game_session.get_current_state_media()
return result[0], gr.update(choices=result[1]), result[2], game_session, media
else:
return result[0], gr.update(choices=result[1]), result[2], game_session
def validate_transitions(all_states):
errors = []
for location, states in all_states.items():
for state_key, state in states.items():
for transition_key, transition_state in state['transitions'].items():
# Check if the transition is to another location
if transition_state in all_states:
trans_location, trans_state = transition_state, 'start' # Assuming 'start' state for new locations
elif '_' in transition_state:
trans_location, trans_state = transition_state.split('_')
else:
trans_location, trans_state = location, transition_state
# Validate the transition state
if trans_location not in all_states or trans_state not in all_states[trans_location]:
errors.append(f"Invalid transition from {location}.{state_key} to {trans_location}.{trans_state}")
return errors
path_errors = validate_transitions(all_states)
if path_errors:
for error in path_errors:
print(error)
else:
print("All transitions are valid.")
def load_game(custom_config=None, with_media=False):
global all_states
if not custom_config:
return gr.update(value="No custom configuration provided."), None, None, None, None, None, None
try:
new_config = json.loads(custom_config)
all_states = new_config
# Determine the starting location and state
starting_location = next(iter(all_states.keys()))
starting_state = next(iter(all_states[starting_location].keys()))
print(f"Starting location: {starting_location}, Starting state: {starting_state}")
game_session = GameSession(starting_location, starting_state)
description, choices, game_log = game_session.get_current_state_info()
new_path_errors = validate_transitions(all_states)
output_media = []
if with_media:
media_list = all_states[starting_location][starting_state].get('media', [])
print(f"Media list: {media_list}")
if media_list:
for media_path in media_list:
#media_component = create_media_component(media_path)
output_media.append(media_path)
print(f"Created {len(output_media)} media components")
success_message = f"Custom configuration loaded successfully!\n{new_path_errors}"
return (
gr.update(value=success_message),
game_log,
description,
gr.update(choices=choices),
gr.update(value=custom_config),
game_session,
output_media if with_media else None
)
except json.JSONDecodeError as e:
error_message = format_json_error(custom_config, e)
return gr.update(value=error_message), None, None, None, gr.update(value=custom_config), None, None
except Exception as e:
error_message = f"Error loading custom configuration: {str(e)}"
return gr.update(value=error_message), None, None, None, gr.update(value=custom_config), None, None
def load_game_edit_version(custom_config=None, with_media=False, custom_starting_location=None, custom_starting_state=None):
global all_states
if not custom_config:
return gr.update(value="No custom configuration provided."), None, None, None, None, None, None
try:
new_config = json.loads(custom_config)
all_states = new_config
# Determine the starting location and state
if custom_starting_location and custom_starting_state:
if custom_starting_location not in all_states or custom_starting_state not in all_states[custom_starting_location]:
raise ValueError(f"Invalid custom starting point: {custom_starting_location}, {custom_starting_state}")
starting_location = custom_starting_location
starting_state = custom_starting_state
else:
starting_location = next(iter(all_states.keys()))
starting_state = next(iter(all_states[starting_location].keys()))
print(f"Starting location: {starting_location}, Starting state: {starting_state}")
game_session = GameSession(starting_location, starting_state)
description, choices, game_log = game_session.get_current_state_info()
new_path_errors = validate_transitions(all_states)
output_media = []
if with_media:
media_list = all_states[starting_location][starting_state].get('media', [])
print(f"Media list: {media_list}")
if media_list:
for media_path in media_list:
output_media.append(media_path)
print(f"Created {len(output_media)} media components")
success_message = f"Custom configuration loaded successfully!\n{new_path_errors}"
return (
gr.update(value=success_message),
game_log,
description,
gr.update(choices=choices),
gr.update(value=custom_config),
game_session,
output_media if with_media else None
)
except json.JSONDecodeError as e:
error_message = format_json_error(custom_config, e)
return gr.update(value=error_message), None, None, None, gr.update(value=custom_config), None, None
except Exception as e:
error_message = f"Error loading custom configuration: {str(e)}"
return gr.update(value=error_message), None, None, None, gr.update(value=custom_config), None, None
media_folder = os.path.abspath("saved_media") #make sure same as SAVE_DIR below
def export_config_with_media(config_json):
global media_folder
"""
Export the config JSON and zip it along with any files referenced in the media fields.
:param config_json: JSON string containing the config
:param media_folder: Path to the folder containing media files
:return: Path to the created zip file
"""
# Parse the JSON
config = json.loads(config_json)
# Create a temporary directory to store files for zipping
with tempfile.TemporaryDirectory() as temp_dir:
# Save the config JSON to the temp directory
config_path = os.path.join(temp_dir, 'config.json')
with open(config_path, 'w') as f:
json.dump(config, f, indent=2)
# Collect all media files
media_files = set()
for location in config.values():
if isinstance(location, dict):
for sublocation in location.values():
if isinstance(sublocation, dict) and 'media' in sublocation:
media_files.update(sublocation['media'])
# Copy media files to the temp directory
for media_file in media_files:
src_path = os.path.join(media_folder, media_file)
if os.path.exists(src_path):
dst_path = os.path.join(temp_dir, media_file)
shutil.copy2(src_path, dst_path)
else:
print(f"Warning: Media file not found: {media_file}")
# Create a zip file
zip_path = os.path.join(os.path.dirname(media_folder), 'config_with_media.zip')
with zipfile.ZipFile(zip_path, 'w') as zipf:
for root, _, files in os.walk(temp_dir):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, temp_dir)
zipf.write(file_path, arcname)
return zip_path
def format_json_error(config, error):
lineno, colno = error.lineno, error.colno
lines = config.split('\n')
error_line = lines[lineno - 1] if lineno <= len(lines) else ""
pointer = ' ' * (colno - 1) + '^'
return f"""Invalid JSON format in custom configuration:
Error at line {lineno}, column {colno}:
{error_line}
{pointer}
Error details: {str(error)}"""
def display_website(link):
html = f"<iframe src='{link}' width='100%' height='1000px'></iframe>"
gr.Info("If 404 then the space/page has probably been disabled - normally due to a better alternative")
return html
initgameinfo = start_game()
fpeinitgameinfo = start_game(new_states=finished_product_demo)