Suggestions wanted on how to generate a semi randomised menu

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
HaldaneBDoyle
Newbie
Posts: 4
Joined: Sun Oct 15, 2023 4:48 am
Contact:

Suggestions wanted on how to generate a semi randomised menu

#1 Post by HaldaneBDoyle »

I am looking for guidance on how to code the following menu in RenPy. The context is to create a semi-randomised way to connect a collection of storylets (to give the player a choice between sticking to the narrative flow, or veering off into other topics).

Each storylet will end with six possible menu options (call them A1/A2/B1/B2/C1/C2)

The program randomly choses one A, one B and one C to present to the player (A*/B*/C*) in a menu

Bonus points for an idea how to randomise the order that the three options are presented

More bonus points for an idea of how to exclude any storylets which have already been selected from being offered again.

I have managed to get this functionality working with a toy model in python. Just looking for advice on how to adapt it to RenPy. The python code for the toy model is below in case that is of any use.

*********

import pandas as pd
import random

# Load the CSV files
storylet_df = pd.read_csv('100StoryletToyModelDataset.csv')
conversations_df = pd.read_csv('generated_cyclic_conversations.csv')

def simulate_conversation(visited_storylets, previous_choice=None, previous_presented_links=None):
# If visited_storylets is empty, randomly select a storylet. Otherwise, use the previous choice to determine the next storylet.
if not visited_storylets:
selected_storylet_number = random.choice(storylet_df['Storylet Number'].tolist())
else:
selected_storylet_number = visited_storylets[-1] # Starting point to get the next storylet

# Get the link corresponding to the previous choice
user_choice_link = previous_presented_links[int(previous_choice) - 1]
selected_storylet_number = int(storylet_df[storylet_df['Storylet Number'] == selected_storylet_number][user_choice_link].values[0])

# Split possible links into separate lists for A, B, and C
a_links = ['A1 Link', 'A2 Link']
b_links = ['B1 Link', 'B2 Link']
c_links = ['C1 Link', 'C2 Link']

# Get the valid links for each group (A, B, C)
valid_a_links = [link for link in a_links if storylet_df[storylet_df['Storylet Number'] == selected_storylet_number][link].values[0] not in visited_storylets]
valid_b_links = [link for link in b_links if storylet_df[storylet_df['Storylet Number'] == selected_storylet_number][link].values[0] not in visited_storylets]
valid_c_links = [link for link in c_links if storylet_df[storylet_df['Storylet Number'] == selected_storylet_number][link].values[0] not in visited_storylets]

# Randomly choose one valid link from each group
selected_a_link = random.choice(valid_a_links) if valid_a_links else None
selected_b_link = random.choice(valid_b_links) if valid_b_links else None
selected_c_link = random.choice(valid_c_links) if valid_c_links else None

# Combine the selected links to form presented_links
presented_links = [link for link in [selected_a_link, selected_b_link, selected_c_link] if link]

# Check if there are no presented links
if not presented_links:
print("THE END")
return None, visited_storylets, None

# Adjusting the links to fetch the link text
presented_links_text = [link.replace(' Link', ' Link Text') for link in presented_links]

# Use the conversations_df to look up the text for the random selections
selected_row = conversations_df[conversations_df['Storylet Number'] == selected_storylet_number].iloc[0]
fragment = selected_row['Fragment']
link_texts = [selected_row[link_text] for link_text in presented_links_text]

# Display the current storylet number and path
print(f"Current Storylet Number: {selected_storylet_number}")
print(f"Current Path: {visited_storylets}\n")

# Display the conversation
print(fragment)
for i, link_text in enumerate(link_texts, start=1):
# Fetch the storylet number each link will take the user to
link_dest = storylet_df[storylet_df['Storylet Number'] == selected_storylet_number][presented_links[i-1]].values[0]
print(f"{i}) {link_text} (leads to Storylet {link_dest})")

# Prompt user for a choice
while True:
try:
user_choice = int(input("Enter your choice: "))
if 1 <= user_choice <= len(presented_links):
break
else:
print(f"Please enter a number between 1 and {len(presented_links)}.")
except ValueError:
print("Please enter a valid number.")

# Update the visited storylets
visited_storylets.append(selected_storylet_number)
return user_choice, visited_storylets, presented_links

def main_simulation(steps=100):
visited_storylets = []
user_choice = None
presented_links = None
for _ in range(steps):
user_choice, visited_storylets, presented_links = simulate_conversation(visited_storylets, user_choice, presented_links)
if user_choice is None:
break
print("\n" + "-"*50 + "\n") # Separate each conversation with a line

if __name__ == "__main__":
main_simulation()

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1012
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Suggestions wanted on how to generate a semi randomised menu

#2 Post by m_from_space »

So at the moment the keyword "menu" within the Renpy script language is actually a function. You can overwrite that function. For example if you want the menu to always be randomized, you can do this:

Code: Select all

init python:
    shuffle_menu = False
    # save the old menu function in a variable
    renpy_menu = menu
    # make our own menu function that allows shuffling
    def menu(items):
        items = list(items)
        if shuffle_menu:
            renpy.random.shuffle(items)
        return renpy_menu(items)
Usage:

Code: Select all

label start:
    $ shuffle_menu = True
    "The following menu will be shuffled."
    menu:
        "Entry 1":
            pass
        "Entry 2":
            pass
        "Entry 3":
            pass
I think you will be able to figure out the rest given that you already wrote the python code for it. :)

Counter Arts
Miko-Class Veteran
Posts: 649
Joined: Fri Dec 16, 2005 5:21 pm
Completed: Fading Hearts, Infinite Game Works
Projects: Don't Save the World
Organization: Sakura River
Location: Canada
Contact:

Re: Suggestions wanted on how to generate a semi randomised menu

#3 Post by Counter Arts »

Something like this might be more up your alley.

Code: Select all

# format is an array of tuples/array
# [ ("Displayed Choice string", "targetLabel"),  ("Displayed Choice string 2", "targetLabel2") ]
$ currentMenu = generateChoices() 
$ result = renpy.display_menu([ ("East", "eastTargetLabel"), ("West", "eastTargetLabel") ])
$ renpy.call(result)
Fading Hearts is RELEASED
http://www.sakurariver.ca

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot], Verum