Passing Pre-Interpolated Strings to Text()

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
Dyschology
Newbie
Posts: 4
Joined: Wed Dec 06, 2017 5:40 pm
Contact:

Passing Pre-Interpolated Strings to Text()

#1 Post by Dyschology »

Hello all,

I'm trying to set up a screen displayable that, when shown, will display text that is bound to the mouse cursor. I've created a custom displayable based on Apricotorange's flashlight tutorial (viewtopic.php?f=51&t=20872) that takes a displayable as an argument and (re)draws it at the mouse position whenever the mouse is moved. Since it needs a displayable and not just a string I am using the Text() function to convert it.

It works great when I pass it a normal text displayable. However I plan to use it to display info on an item when moused over in the inventory. This means I need it to display variables. The problem happens when I pass Text() a string with a variable included (using square brackets) that needs interpolation. I get the exception: KeyError: u'item'. The variable I am trying to interpolate is an Item object named item. I'm therefore assuming the problem is that interpolation doesn’t happen until inside the Text() function and it can no longer reference the object "item".

I have tried a bunch of different workarounds but nothing I do seems to fix the core problem of having to use Text(). Is there a way to force renpy to interpolate first and then pass the string? Or should I perhaps be taking a different approach for this? Thanks!

Screen code:

Code: Select all

screen tooltip(item=False):      
    if item:
        default txt = "[item[0].name]: [item[0].desc] (Value: [item[0].value])"
        default txt2 = "Test Test Test"
        hbox:
            xalign 0.5 yalign 1.0
            text "[item[0].name]: [item[0].desc] (Value: [item[0].value])"            
            add MouseSnap(Text(txt2))
            #add MouseSnap("[item[0].name]: [item[0].desc] (Value: [item[0].value])", item)
            #add Text(txt)
            #add MouseSnap(Text("[item[0].name]: [item[0].desc] (Value: [item[0].value])"))
All of the lines in the hbox attempt to do the same thing. The uncommented ones work, the commented ones throw an exception.
Edit: They try to do similar things, except for the text line that simply displays the correct text but does not bind it to the mouse.

Custom displayable code:

Code: Select all

    class MouseSnap(renpy.Displayable):
        def __init__(self, dis):
            super(MouseSnap, self).__init__()
            
            # Displayable to snap to mouse
            self.child = dis

            # Start outside game window
            self.pos = (-1, -1)

        def render(self, width, height, st, at):
            render = renpy.Render(config.screen_width, config.screen_height)
            
            # If we are outside the window render nothing
            if self.pos == (-1, -1):
                return render

            # Render the displayable
            child_render = renpy.render(self.child, width, height, st, at)

            # Draw the image centered on the cursor.
            x, y = self.pos
            x += 25
            y += 25
            render.blit(child_render, (x, y))
            return render

        def event(self, ev, x, y, st):
            # Re-render if the position changed.
            if self.pos != (x, y):
                renpy.redraw(self, 0)

            # Update stored position
            self.pos = (x, y)

        def visit(self):
            return [ self.child ]
Last edited by Dyschology on Wed Dec 06, 2017 6:57 pm, edited 1 time in total.

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Passing Pre-Interpolated Strings to Text()

#2 Post by PyTom »

Give text the substitute=False argument. That will turn off interpolation.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Dyschology
Newbie
Posts: 4
Joined: Wed Dec 06, 2017 5:40 pm
Contact:

Re: Passing Pre-Interpolated Strings to Text()

#3 Post by Dyschology »

Wow that was fast, thanks!

However my goal isn't to completely turn off interpolation, otherwise my item description would just be a bunch of variable names. I'm trying to figure out some way to be able to use interpolation while still ending up with a Text displayable I can pass to my custom displayable's render method.

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Passing Pre-Interpolated Strings to Text()

#4 Post by Remix »

I only scanned your opening post quickly, so ignore this if I am barking up the wrong tree...

txt = renpy.substitute( "[vars] blah blah [arg]" )
MouseThing( Text( txt ) )

From memory (so might need more sleuthing - maybe output txt first to check ... renpy.substitute *might* return interpolated text plus a flag)
Frameworks & Scriptlets:

philat
Eileen-Class Veteran
Posts: 1910
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Passing Pre-Interpolated Strings to Text()

#5 Post by philat »

Use .format or % interpolation instead of brackets.

Dyschology
Newbie
Posts: 4
Joined: Wed Dec 06, 2017 5:40 pm
Contact:

Re: Passing Pre-Interpolated Strings to Text()

#6 Post by Dyschology »

Aright, after trying a million things I finally figured it out.

Unfortunately using renpy.substitute gave me the same error.

Using normal % interpolation also didn't work, however using what the wiki called "faking it" and passing the arguments after the string in a tuple separated by a % did work.

For example:
Text("%(item[0].name)s: %(item[0].desc)s Value: %(item[0].value)d")
Did not work, but
Text("%s: %s Value: %d" % (item[0].name, item[0].desc, item[0].value))
Did work.

Thanks for everyone's help!

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Passing Pre-Interpolated Strings to Text()

#7 Post by Remix »

If that works, .format *should* do too and might offer more versatility (**dict from obj sort of thing ) and readability

Text( "{name}: {desc} Value: {value}".format( **item[0] ) )

or (if item[0] is not a dictionary object)
Text( "{name}: {desc} Value: {value}".format( **item[0].__dict__ ) )

A minor note: In python, the % based string interpolation is considered quite old school. Most programming these days uses the more modern {} format. Not that Ren'py minds which one you use :)
Frameworks & Scriptlets:

Post Reply

Who is online

Users browsing this forum: Google [Bot]