import random
from relatively_constant_variables import player_engagement_items, story_events, all_idea_lists, existing_game_inspirations, multiplayer_features, list_names
import json
import gradio as gr
import re
import os
def pick_random_items(items, n):
return random.sample(items, n)
def generate_timeline(events, label):
timeline = []
for event in events:
timeline.append((random.randint(1, 100), label, event))
return timeline
def create_story(timeline):
story = []
for entry in timeline:
if entry[1] == "Story":
story.append(f"The hero {entry[2].replace('engageBattle', 'engaged in a fierce battle').replace('solveRiddle', 'solved a complex riddle').replace('exploreLocation', 'explored a mysterious location')}.")
else:
story.append(f"The player interacted with {entry[2]}.")
return " ".join(story)
def generate_story_and_timeline(no_story_timeline_points=10, no_ui_timeline_points=10, num_lists=1, items_per_list=1, include_existing_games=False, include_multiplayer=False): # , no_media_timeline_points=5, include_media=True):
# Pick 10 random UI items
random_ui_items = pick_random_items(player_engagement_items, no_ui_timeline_points)
random_story_items = pick_random_items(story_events, no_story_timeline_points)
# Generate UI and story timelines
ui_timeline = generate_timeline(random_ui_items, "UI")
story_timeline = generate_timeline(random_story_items, "Story")
# Initialize merged timeline with UI and story timelines
merged_timeline = ui_timeline + story_timeline
#no_media_merged_timeline = ui_timeline + story_timeline
#print(merged_timeline)
#print(no_media_merged_timeline)
# Include media-related items if specified
# if include_media:
# media_files = generate_media_file_list(no_media_timeline_points)
# #rendered_media = render_media_with_dropdowns(media_files)
# media_timeline = generate_timeline(media_files, "Media")
# merged_timeline += media_timeline
# print(merged_timeline)
# Sort the merged timeline based on the random numbers
merged_timeline.sort(key=lambda x: x[0])
# no_media_merged_timeline.sort(key=lambda x: x[0])
# Create the story
story = create_story(merged_timeline)
# Format the timeline for display
formatted_timeline = "\n".join([f"{entry[0]}: {entry[1]} - {entry[2]}" for entry in merged_timeline])
# no_media_formatted_timeline = "\n".join([f"{entry[0]}: {entry[1]} - {entry[2]}" for entry in no_media_merged_timeline])
# game_structure_with_media = generate_game_structures(formatted_timeline) #, game_structure_without_media = generate_game_structures(formatted_timeline, no_media_formatted_timeline)
game_structure_with_media = convert_timeline_to_game_structure(formatted_timeline)
print("simulplay debug - good to here 4")
suggestions, selected_list_names = timeline_get_random_suggestions(num_lists, items_per_list, include_existing_games, include_multiplayer)
print("simulplay debug - good to here 4")
return formatted_timeline, story, json.dumps(game_structure_with_media, indent=2), suggestions, selected_list_names #no_media_formatted_timeline, json.dumps(game_structure_without_media, indent=2) #, game_structure_with_media
media_file_types = ["image", "video", "audio"]
def generate_media_file_list(n):
return [random.choice(media_file_types) for _ in range(n)]
def show_elements(text):
# Parse the input text
pattern = r'(\d+): (UI|Story|Media) - (.+)'
blocks = re.findall(pattern, text)
# Sort blocks by their timestamp
blocks.sort(key=lambda x: int(x[0]))
outputs = []
for timestamp, block_type, content in blocks:
if block_type == 'UI':
# Create HTML for UI elements
ui_html = f'
{content}
'
outputs.append(gr.HTML(ui_html))
elif block_type == 'Story':
# Display story elements as Markdown
outputs.append(gr.Markdown(f"**{content}**"))
elif block_type == 'Media':
if content.lower() == 'audio':
# Placeholder for audio element
outputs.append(gr.Audio(label=f"Audio at {timestamp} in the order"))
elif content.lower() == 'video':
# Placeholder for video element
outputs.append(gr.Video(label=f"Video at {timestamp} in the order"))
elif content.lower() == 'image':
# Placeholder for image element
outputs.append(gr.Image(label=f"Image at {timestamp} in the order"))
return outputs
def show_elements_json_input(json_input):
data = json.loads(json_input)
masterlocation1 = data['masterlocation1']
outputs = []
for location, details in masterlocation1.items():
if location == 'end':
continue
with gr.Accordion(f"Location: {location} - Previous description {details['description']}", open=False):
description = gr.Textbox(label="Description", value=details['description'], interactive=True)
outputs.append(description)
events = gr.Textbox(label="Events", value=json.dumps(details['events']), interactive=True)
outputs.append(events)
choices = gr.Textbox(label="Choices", value=json.dumps(details['choices']), interactive=True)
outputs.append(choices)
transitions = gr.Textbox(label="Transitions", value=json.dumps(details['transitions']), interactive=True)
outputs.append(transitions)
# New media field
media = gr.Textbox(label="Media", value=json.dumps(details['media']), interactive=True)
outputs.append(media)
# New developernotes field
developernotes = gr.Textbox(label="developernotes", value=json.dumps(details['developernotes']), interactive=True)
outputs.append(developernotes)
#adding/removing a field means incrementing/decreasing the i+n to match the fields
num_current_unique_fields = 6
def update_json(*current_values):
updated_data = {"masterlocation1": {}}
locations = [loc for loc in masterlocation1.keys() if loc != 'end']
for i, location in enumerate(locations):
updated_data["masterlocation1"][location] = {
"description": current_values[i*num_current_unique_fields],
"events": json.loads(current_values[i*num_current_unique_fields + 1]),
"choices": json.loads(current_values[i*num_current_unique_fields + 2]),
"transitions": json.loads(current_values[i*num_current_unique_fields + 3]),
"media": json.loads(current_values[i*num_current_unique_fields + 4]), # New media field
"developernotes": json.loads(current_values[i*num_current_unique_fields + 5])
}
updated_data["masterlocation1"]["end"] = masterlocation1["end"]
return json.dumps(updated_data, indent=2) #json.dumps(updated_data, default=lambda o: o.__dict__, indent=2)
update_button = gr.Button("Update JSON - Still need to copy to correct textbox to load")
json_output = gr.Textbox(label="Updated JSON - Still need to copy to correct textbox to load", lines=10)
#json_output = gr.Code(label="Updated JSON", lines=10) #Locks whole UI so use textbox
update_button.click(update_json, inputs=outputs, outputs=json_output)
return outputs + [update_button, json_output] #, json_output_code]
def show_elements_json_input_play_and_edit_version(json_input):
data = json.loads(json_input)
outputs = []
for location_name, location_data in data.items():
if location_name == "end":
continue
for sub_location, details in location_data.items():
with gr.Accordion(f"Location: {location_name} - {sub_location}", open=False):
description = gr.Textbox(label="Description", value=details.get('description', ''), interactive=True)
outputs.append(description)
choices = gr.Textbox(label="Choices", value=json.dumps(details.get('choices', [])), interactive=True)
outputs.append(choices)
transitions = gr.Textbox(label="Transitions", value=json.dumps(details.get('transitions', {})), interactive=True)
outputs.append(transitions)
consequences = gr.Textbox(label="Consequences", value=json.dumps(details.get('consequences', {})), interactive=True)
outputs.append(consequences)
media = gr.Textbox(label="Media", value=json.dumps(details.get('media', [])), interactive=True)
outputs.append(media)
# Add developernotes field if it exists in the config
if 'developernotes' in details:
developernotes = gr.Textbox(label="Developer Notes", value=details.get('developernotes', ''), interactive=True)
outputs.append(developernotes)
# Determine the number of fields dynamically
num_current_unique_fields = 5 if 'developernotes' not in next(iter(next(iter(data.values())).values())) else 6
def update_json(*current_values):
updated_data = {}
location_names = list(data.keys())
location_names.remove("end") if "end" in location_names else None
value_index = 0
for location_name in location_names:
updated_data[location_name] = {}
sub_locations = list(data[location_name].keys())
for sub_location in sub_locations:
updated_data[location_name][sub_location] = {
"description": current_values[value_index],
"choices": json.loads(current_values[value_index + 1]),
"transitions": json.loads(current_values[value_index + 2]),
"consequences": json.loads(current_values[value_index + 3]),
"media": json.loads(current_values[value_index + 4])
}
if num_current_unique_fields == 6:
updated_data[location_name][sub_location]["developernotes"] = current_values[value_index + 5]
value_index += num_current_unique_fields
if "end" in data:
updated_data["end"] = data["end"]
return json.dumps(updated_data, indent=2)
update_button = gr.Button("Update JSON")
json_output = gr.Textbox(label="Updated JSON", lines=10)
update_button.click(update_json, inputs=outputs, outputs=json_output)
return outputs + [update_button, json_output]
def create_media_component(file_path):
print(file_path)
_, extension = os.path.splitext(file_path)
extension = extension.lower()[1:] # Remove the dot and convert to lowercase
if extension in ['jpg', 'jpeg', 'png', 'gif', 'webp']:
return gr.Image(value=file_path, label="Image Input")
elif extension in ['mp4', 'avi', 'mov']:
return gr.Video(value=file_path, label="Video Input")
elif extension in ['mp3', 'wav', 'ogg']:
return gr.Audio(value=file_path, label="Audio Input")
else:
return gr.Textbox(value=file_path, label=f"File: {os.path.basename(file_path)}")
def convert_timeline_to_game_structure(timeline):
lines = timeline.split('\n')
game_structure = {}
current_location = 0
sub_location = 0
for i, line in enumerate(lines):
if line.strip() == "":
continue
if line[0].isdigit(): # New location starts
current_location += 1
sub_location = 0
location_key = f"location{current_location}"
game_structure[location_key] = {
"description": "",
"events": [],
"choices": ["continue"],
"transitions": {},
"media": [],
"developernotes": []
}
else: # Continue with sub-locations or media entries
sub_location += 1
location_key = f"location{current_location}_{sub_location}"
# Extract the event description
parts = line.split(': ', 1)
if len(parts) == 2:
prefix, rest = parts
event_parts = rest.split(' - ', 1)
if len(event_parts) == 2:
event_type, event_description = event_parts
else:
event_type, event_description = "Unknown", rest
else:
event_type, event_description = "Unknown", line
description = rest.strip() if event_type in ["Media", "UI"] else f"{event_type}: {event_description}"
if sub_location == 0:
game_structure[f"location{current_location}"]["description"] = description
else:
game_structure[f"location{current_location}"]["events"].append({
"description": description,
"type": event_type
})
# Set the transition to the next location or to the end
if i < len(lines) - 1:
next_line = lines[i + 1].strip()
if next_line and next_line[0].isdigit(): # New location starts
game_structure[f"location{current_location}"]["transitions"]["continue"] = f"masterlocation1_location{current_location + 1}"
else:
#game_structure[f"location{current_location}"]["transitions"]["continue"] = f"location_{current_location}_{sub_location + 1}"
game_structure[f"location{current_location}"]["transitions"]["continue"] = "end"
else:
game_structure[f"location{current_location}"]["transitions"]["continue"] = "end"
# Add an end location
game_structure["end"] = {
"description": "The adventure ends here.",
# "choices": [],
# "transitions": {}
"choices": ["restart"],
"transitions": {"restart": "location1"} # Assuming location_1 is the start
}
# Wrap the game structure in master_location1
wrapped_structure = {"masterlocation1": game_structure}
return wrapped_structure
# def generate_game_structures(timeline_with_media): #, timeline_without_media):
# game_structure_with_media = convert_timeline_to_game_structure(timeline_with_media)
# #game_structure_without_media = convert_timeline_to_game_structure(timeline_without_media)
# return game_structure_with_media #, game_structure_without_media
# def timeline_get_random_suggestions(num_lists, items_per_list):
# """
# Generate random suggestions from a specified number of lists.
# :param num_lists: Number of lists to consider
# :param items_per_list: Number of items to select from each list
# :return: A list of randomly selected suggestions
# """
# selected_lists = random.sample(all_idea_lists, min(num_lists, len(all_idea_lists)))
# suggestions = []
# for lst in selected_lists:
# suggestions.extend(random.sample(lst, min(items_per_list, len(lst))))
# return suggestions
def timeline_get_random_suggestions(num_lists, items_per_list, include_existing_games, include_multiplayer):
"""
Generate random suggestions from a specified number of lists.
:param num_lists: Number of lists to consider
:param items_per_list: Number of items to select from each list
:param include_existing_games: Whether to include existing game inspiration lists
:param include_multiplayer: Whether to include multiplayer features list
:return: A tuple containing the list of randomly selected suggestions and the names of selected lists
"""
available_lists = all_idea_lists.copy()
if not include_existing_games:
available_lists = [lst for lst in available_lists if lst not in existing_game_inspirations]
if not include_multiplayer:
available_lists = [lst for lst in available_lists if lst != multiplayer_features]
selected_lists = random.sample(available_lists, min(num_lists, len(available_lists)))
suggestions = []
selected_list_names = []
for lst in selected_lists:
suggestions.extend(random.sample(lst, min(items_per_list, len(lst))))
selected_list_names.append(list_names[all_idea_lists.index(lst)])
return suggestions, selected_list_names