[Solved] Dynamically define a long list of displayables.

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.
Message
Author
User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

[Solved] Dynamically define a long list of displayables.

#1 Post by Zealotus »

Solved!
See Nyaatrap's response for code: *clicky*
ありがとう ございます Nyaatrap-san! ^_^

Note! This is not my game originally!
Some clever people can probably figure out which game it is despite the fact that I've changes some variables around... I humbly ask you keep it to yourselves. Thank you!
I'm modifying it with no intentions on releasing it!
The main reason I'm doing this is to learn more about Ren'Py and Python.

That said, here's the code I have at the moment:

Code: Select all

        for o in outfit_list:
            for e in expression_list:
                renpy.image("chris {}".format(e), ConditionSwitch(
                            "player.image=='{}' and player.cos==1".format(o.image),im.Composite((1045,1536),(0,0),"sprites/{}/base1.png".format(o.image),(0,0),"sprites/chris/{}.png".format(e)),
                            "player.image=='{}' and player.cos==2".format(o.image),im.Composite((1045,1536),(0,0),"sprites/{}/base2.png".format(o.image),(0,0),"sprites/chris/{}.png".format(e)),
                            "player.image=='{}' and player.cos==3".format(o.image),im.Composite((1045,1536),(0,0),"sprites/{}/base3.png".format(o.image),(0,0),"sprites/chris/{}.png".format(e))))
outfit_list is a store object with all the information for each outfit. The 'image' property also being used in the file-path.
expression_list is just a plain list of words: smile, laugh, angry, etc.
The 'chris' folder contains a base sprite and all the expressions.

The error I'm getting is 'Exception: Switch could not choose a displayable.'

I've checked (in-game) that o.image returns the correct string.
Is it not possible to have a for loop within a for loop or what am I doing wrong?
Last edited by Zealotus on Tue Aug 19, 2014 1:13 pm, edited 3 times in total.

User avatar
fluxus
Regular
Posts: 133
Joined: Thu Jun 19, 2014 8:06 am
Projects: Animal Anaesthesia (a teaching game)
Contact:

Re: Trying to dynamically define a long list of displayables

#2 Post by fluxus »

Well, first off, you can have as many for loops inside each other as you feel like. Loops inside loops inside loops inside.. etc.

It's not so easy to see what exactly is happening inside that loop however, you might want to rewrite it to display or output a text with the output instead, so that you can see what is going on.

My first guess is that somehow none of the conditions provided for ConditionSwitch is true - if all turns out false, it has no displayable to select. If I'm right, testing ConditionSwitch with false conditions will return the same exception message.

Old doc:
http://www.renpy.org/wiki/renpy/doc/ref ... tionSwitch

New doc (but also shorter in content):
http://www.renpy.org/doc/html/displayables.html

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#3 Post by Zealotus »

Hmm...

Well I added a menu option that would print out every possible combination but...

Code: Select all

                    for o in outfit_list:
                        for e in expression_list:
                            for i in range(1,3):
                                say("chris {}".format(e),"sprites/{}/base{}.png sprites/chris/{}.png".format(o.image).format(i).format(e))
While i would expect the results to be:

Code: Select all

o = outfit_list[0] = chris
    e = expression_list[0] = think
        i = 1
            say("chris <think>","sprites/<chris>/base<1>.png sprites/chris/<think>.png"
(Without the < >, they're just there for readability.)
This returns 'IndexError: tuple index out of range' ... o_O;;

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Trying to dynamically define a long list of displayables

#4 Post by xela »

Zealotus wrote: This returns 'IndexError: tuple index out of range' ... o_O;;
How is this a surprise?

Try:

Code: Select all

"sprites/{}/base{}.png sprites/chris/{}.png".format(o.image, i, e))
Like what we're doing? Support us at:
Image

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#5 Post by Zealotus »

Ugh, I feel dumb... >.>;;

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#6 Post by Zealotus »

Found a way that works WAY better!

Code: Select all

init 990:
    $ expression="smile"
    image chris:
        LiveComposite((1045,1536),
        (0,0),"sprites/%s/base%s.png"%(player.image,player.cos),
        (0,0),"sprites/chris/%s.png"%(expression),)
    image small chris:
        LiveComposite((697,1024),
        (0,0),"small/%s/base%s.png"%(player.image,player.cos),
        (0,0),"small/chris/%s.png"%(expression),)
Although this requires some rewrite in the rest of the code...
Have to set '$ expression="<expression>" before every show statement, but eh...
That's not something that a few regexp replaces can't handle ; )

I'm sure there is a way to preserve the previous functionality, I just haven't found it yet.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Trying to dynamically define a long list of displayables

#7 Post by xela »

I can't see what's wrong with previous functionality. Before calling:

show chris ...

do you set:

player.image= ...
player.cos = ...

accordingly so the conditioning returns True?
Like what we're doing? Support us at:
Image

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#8 Post by Zealotus »

They're set when equiping an outfit. And an outfit is set at startup so there's always something in those variables.
Ptoblem is... I have to emulate all the possible values at boot becuase, as everyone knows, once the init has run you can't define more displayables.
And, correct me if I'm wrong, ConditionSwitch doesn't seem to handle variables when checking for True or False.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Trying to dynamically define a long list of displayables

#9 Post by xela »

Zealotus wrote:They're set when equiping an outfit. And an outfit is set at startup so there's always something in those variables.
I see...
Zealotus wrote:Ptoblem is... I have to emulate all the possible values at boot becuase, as everyone knows, once the init has run you can't define more displayables.
Who's this "everyone", we should find him and kick his ass! :)

*You can't define renpy image references outside of init. Displayable you can define on the fly just fine.
Zealotus wrote:And, correct me if I'm wrong, ConditionSwitch doesn't seem to handle variables when checking for True or False.
I don't understand what you're stating here, but you're prolly are. I expect it's just Python's eval() builtin.
Like what we're doing? Support us at:
Image

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#10 Post by Zealotus »

xela wrote:*You can't define renpy image references outside of init. Displayable you can define on the fly just fine.
Sooo, as long as I just define all the file locations i should be fine, or am I missing something?

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Trying to dynamically define a long list of displayables

#11 Post by xela »

???

You have some form of class that instantiates to player variable, do you not? Add a method to it to call images:

Code: Select all

def show(self, costume, expression):
    return LiveComposite((1045, 1536), (0, 0), "sprites/{}/base1.png".format(costume), (0, 0), "sprites/chris/{}.png".format(expression))
But I doubt you even have to pass arguments to it... if your class equipment method is working:

Code: Select all

def show(self):
    return LiveComposite((1045, 1536), (0, 0), "sprites/{}/base1.png".format(self.cos), (0, 0), "sprites/chris/{}.png".format(self.image))
You need to fix this to work with the game as the path is just guesswork based on your code in the first post. I am suggesting LiveComposite as I recall PyTom mentioning that it's preferred in modern Ren'Py. Your im.Composite should work as well.
Like what we're doing? Support us at:
Image

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#12 Post by Zealotus »

Nevermind my last post. It was late and I was very tired...

The class I've got is a general one for all the characters and outfits in the game.
They are global variables that is copied to the player variable upon equip.
So technically I could "equip" an enemy or NPC but that would break things later since
those don't have the same expressions (if any) and they're certainly not in chris' folder.

Anyway... I tried your above example, with correct paths ofc, but it didn't work.
Didn't break anything but Chris' images were not defined.

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: Trying to dynamically define a long list of displayables

#13 Post by nyaatrap »

FYI, Python is limited to 256 arguments, therefore ConditionSwitch is limited to 256 combination.
One way is splitting it (it's how I did), but it wasn't a cleaver way. The better way is something like this (the following code was implemented on a postponed RPG):

Code: Select all

    def MyConditionSwitch(folder, char, size, number, face):
        listvalue=[]
        for i in xrange(number):
            listvalue.append("{}.dress=={}".format(char,i))
            listvalue.append(LiveComposite(size,(0,0),"{}/{}/{}.png".format(folder,char,i),(0,0),"{}/{}/{}.png".format(folder,char,face)))
        return ConditionSwitch(*listvalue)

    for i in face_list:
        renpy.image("{} {}".format(char, i),  MyConditionSwitch(folder_name, char, (width,height),loop_count, i)))
The difference about im.Composite and LiveComposite:
im.Composite makes one layer from layers and cache it, then shows it. it's slower on first loading.
LiveComposite just shows layers with no extra caching. it's faster on first loading, but there's a side effect:
for example, if layers are shown 50% alpha, then each layer has 50% alpha. therefore, overwrap area of layers can't be 50% (like 75%) and looks awkward.

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#14 Post by Zealotus »

Oh my! The very creator himself! O_O
nyaatrap wrote:FYI, Python is limited to 256 arguments, therefore ConditionSwitch is limited to 256 combination.
One way is splitting it (it's how I did), but it wasn't a cleaver way.
Yeah, that would explain what's going on in defines...
nyaatrap wrote:The better way is something like this (the following code was implemented on a postponed RPG [ Zealotus: Aw, I sad! :( ] ):

Code: Select all

    def MyConditionSwitch(folder, char, size, number, face):
        listvalue=[]
        for i in xrange(number):
            listvalue.append("{}.dress=={}".format(char,i))
            listvalue.append(LiveComposite(size,(0,0),"{}/{}/{}.png".format(folder,char,i),(0,0),"{}/{}/{}.png".format(folder,char,face)))
        return ConditionSwitch(*listvalue)

    for i in face_list:
        renpy.image("{} {}".format(char, i),  MyConditionSwitch(folder_name, char, (width,height),loop_count, i)))
This! Why didn't I think of this!?
I'll see if I can adapt this for use in my modded version.
nyaatrap wrote:The difference about im.Composite and LiveComposite:
im.Composite makes one layer from layers and cache it, then shows it. it's slower on first loading.
LiveComposite just shows layers with no extra caching. it's faster on first loading, but there's a side effect:
for example, if layers are shown 50% alpha, then each layer has 50% alpha. therefore, overwrap area of layers can't be 50% (like 75%) and looks awkward.
Hmm, there are a few fades but they're only half a second or less so the awkward transparency isn't that much of an issue.

User avatar
Zealotus
Newbie
Posts: 10
Joined: Mon Aug 18, 2014 8:40 am
Location: Sweden
Contact:

Re: Trying to dynamically define a long list of displayables

#15 Post by Zealotus »

After some slight modifications this is what I ended up with:

Code: Select all

        def ChrisSwitch(folder,expression):
            listvalue=[]
            if folder == "sprites":
                size=(1045,1536)
            else:
                size=(697,1024)
            for o in outfit_list:
                for i in xrange(3):
                    listvalue.append("player.image=='{}' and player.cos=={}".format(o.image,i))
                    listvalue.append(im.Composite(size,(0,0),"{}/{}/base{}.png".format(folder,o.image,i),(0,0),"{}/chris/{}.png".format(folder,expression)))
            return ConditionSwitch(*listvalue)

        for e in expression_list:
                renpy.image("chris {}".format(e), ChrisSwitch("sprites",e))
                renpy.image("small chris {}".format(e), ChrisSwitch("small",e))
This function is a bit pre-formated since I'm only using it to define Chris.

And I noticed another side effect of LiveComposite... it's actually extremely slow! Why was this recommended again?

Updated first post to indicate that the problem is solved.
ありがとう ございます Nyaatrap-san! ^_^

Post Reply

Who is online

Users browsing this forum: Dark79