Random selection custom text tag for procedural text

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Post Reply
Message
Author
User avatar
Phanes
Newbie
Posts: 4
Joined: Mon Feb 28, 2022 9:41 pm
Projects: Ruin Me
itch: phanes
Contact:

Random selection custom text tag for procedural text

#1 Post by Phanes »

Inspired by the excellent Tracery, I wrote a custom text tag that lets you specify a series of options inline in dialogue or narration that will be randomly chosen when they're displayed. Random choices can be nested or even included in substitutions, letting you do some pretty complicated stuff including rudimentary L-systems.

I don't do any special processing for unusual tags, so this probably won't work with stuff like {nw} or other tags mentioned on the custom tags page.

Note that there's currently an issue with self-voicing where Ren'Py's automatic TTS won't run custom tags. This will be fixed soon, but even with that change you may see that text-to-speech will show a different randomly-generated quip than is displayed on screen. To fix both these issues, I made a pretty hacky monkey-patch that will make self-voicing consistently read the same thing as is displayed on-screen. No guarantees that this works for all situations.

The Code

Code: Select all

def randtext_tag(tag, argument, contents):
    randtext_depth = 0

    options = []

    curr_option = []

    for content in contents:
        if content[0] == renpy.TEXT_TAG:
            if content[1] == "randtext":
                randtext_depth += 1
            elif content[1] == "/randtext":
                randtext_depth -= 1
            curr_option.append(content)
        elif content[0] == renpy.TEXT_TEXT:
            if randtext_depth == 0:
                if '|' in content[1]:
                    splits = content[1].split('|')

                    for index, split in enumerate(splits):
                        if len(split) > 0:
                            curr_option.append((renpy.TEXT_TEXT, split))
                        else:
                            curr_option.append((renpy.TEXT_TEXT, "⁠"))

                        if index == 0 or index < len(splits) - 1:
                            options.append(curr_option)
                            curr_option = []
                else:
                    curr_option.append(content)
            else:
                curr_option.append(content)

    if len(curr_option) > 0:
        options.append(curr_option)

    choice = renpy.random.choice(options)

    return choice

config.custom_text_tags["randtext"] = randtext_tag

def monkey_tts_decorator(method):
    def monkey_tts(self):
        real_text = self.text

        fake_text = ""

        for t_type, t_text in self.tokens:
            if t_type == renpy.text.textsupport.TEXT:
                fake_text += t_text
            elif t_type == renpy.text.textsupport.TAG:
                fake_text += "{" + t_text + "}"
            elif t_text == renpy.text.textsupport.PARAGRAPH:
                fake_text += "\n"

        self.text = [fake_text]

        ret = method(self)

        self.text = real_text

        return ret
    return monkey_tts

renpy.text.text.Text._tts = monkey_tts_decorator(renpy.text.text.Text._tts)
How to Use and Examples

Put the {randtext} around a group of options separated by pipe (|) symbols, like so: The dress is {randtext}blue|white|yellow|black{/randtext}.

You can include empty options, or make an option more common by repeating it: I think therefore I am{randtext}hungry|hungry||am not{/randtext}.

You can nest random text: This episode is brought to you by {randtext}the letter {randtext}A|B|C{/randtext}|the number {randtext}1|2|3{/randtext}|viewers like you{/randtext}.

Randtext can include substitutions, which can in turn include random text and substitutions of their own. If you want to use nested substitution, make sure you're on a recent version of Ren'Py and apply the !i flag to substitutions.

A simple example for some eerie ambience, generating text like "A haunting song drifts, muffled, from a nearby building.":
"A {randtext}haunting|strange|familiar|catchy|charming|cheery{/randtext} {randtext}melody|song|chant|rhythm|hymn|tune{/randtext} {randtext}echoes from somewhere in the distance|drifts on the wind|plays from a nearby window|catches your ear from somewhere nearby|is barely audible|drifts, muffled, from a nearby building{/randtext}."
A more complicated random breakfast, generating text like "You arrive downstairs and discover blueberry muffins set out. Theresa enters shortly.":
define random_breakfast_food = "{randtext}spiced rice pudding|thick slabs of toast with {randtext}butter and jam|marmalade|scrambled eggs|cured fish|soft cheese{/randtext}|eggs over fish and onions|{randtext}bacon|sausage|mushrooms{/randtext} and eggs|fruit salad and cottage cheese|a {randtext}cheese|ham and cheese|mushroom and cheese|spinach and cheese{/randtext} omelet|{randtext}fruit-studded|blueberry|bran|nut-filled{/randtext} muffins|crepes with {randtext}fresh fruit|fruit preserves|hazelnut spread{/randtext}|a hash of potatoes and {randtext}corned beef|sausage|chipped beef|shredded pork{/randtext}|eggs {randtext}Benedict|Florentine|Cochon|Mornay|Royale{/randtext}|a mess of meats, eggs, tomatoes, baked beans, mushrooms, and toast|{randtext}thoroughly-dressed|lightly-seasoned|nut-topped|fruit-topped{/randtext} oatmeal|{randtext}pancakes|waffles|hotcakes{/randtext} with {randtext}syrup|honey|whipped cream|chocolate sauce|fruit compote{/randtext}|muesli with {randtext}berries|almonds|walnuts|tinned peaches{/randtext}{/randtext}"

"Theresa {randtext}is already in the dining room|is right behind you|enters with you{/randtext}. You {randtext}greet her before you|give her a nod and|exchange pleasantries and|push in her seat before you{/randtext} {randtext}sit at a table set with|prepare to eat your|are served{/randtext} [random_breakfast_food]."
Creator of queer erotic horror VN Ruin Me (NSFW).

Post Reply

Who is online

Users browsing this forum: No registered users