Ren'Py [SOLVED]Solved Showing specific screen

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,917
So I'm making a gallery. The gallery will show the thumbs as imagebuttons. I want the image button to show a different screen, but these image buttons won't exactly show me the screen I want to.
Python:
init python:

    class Gallery:
        def __init__(self, name, images, thumb, character, locked="gallery_locked"):
            self.name = name
            self.images = images
            self.thumb = thumb
            self.character = [0,1,2,3,4]
            self.locked = locked
            self.refresh_lock()
            self.charactername()

        def num_images(self):
            return len(self.images)

        def refresh_lock(self):
            self.num_unlock = 0
            lockme = False
            for img in self.images:
                if not renpy.seen_image(img):
                    lockme = True
                else:
                    self.num_unlock += 1
            self.is_locked = lockme

        def charactername(self):
            return self.character[0]

    gallery_images = []
    gallery_images.append(Gallery("Charlotte", ["charlotte1"], "thumbcharlotte1", 0))
    gallery_images.append(Gallery("Julia", ["julia1"], "thumbjulia1", 1))
    gallery_images.append(Gallery("Valerie", ["valerie1"], "thumbvalerie1", 2))
    gallery_images.append(Gallery("Laura", ["laura1"], "thumblaura1", 3))
    gallery_images.append(Gallery("Eileen", ["eileen1"], "thumbeileen1", 4))
    gallery_images.append(Gallery("Harem", ["harem1"], "thumbharem1", 5))

screen gallery:
    tag menu

    add "black"

    $ start = gallery_page * maxperpage
    $ end = min(start + maxperpage - 1, len(gallery_images) - 1)

    #image grid
    grid maxnumx maxnumy:
        xfill True
        yfill True

        for i in range(start, end + 1):
            $ gallery_images[i].refresh_lock()
            if gallery_images[i].is_locked:
                null
            else:
                imagebutton idle gallery_images[i].thumb:
                    if gallery_images[i].character[0]:
                        action Show("gallerychar_charlotte", dissolve,)
                    elif gallery_images[i].character[1]:
                        action Show("gallerychar_julia", dissolve,)
                    elif gallery_images[i].character[2]:
                        action Show("gallerychar_valerie", dissolve,)
                    elif gallery_images[i].character[3]:
                        action Show("gallerychar_laura", dissolve,)
                    elif gallery_images[i].character[4]:
                        action Show("gallerychar_eileen", dissolve,)
                    elif gallery_images[i].character[5]:
                        action Show("gallerychar_harem", dissolve,)
                    xalign 0.5
                    yalign 0.5

        for i in range(end - start + 1, maxperpage):
            null

    #names
    grid maxnumx maxnumy:
        xfill True
        yfill True

        for i in range(start, end + 1):
            hbox:
                spacing maxthumby - 70
                xalign 0.5
                yalign 0.9
                $ total = gallery_images[i].num_images()
                $ partial = gallery_images[i].num_unlock
                if gallery_images[i].is_locked:
                    null
                else:
                    text gallery_images[i].name
                    text "[partial]/[total]"

        for i in range(end - start + 1, maxperpage):
            null

    #previous and next buttons
    if gallery_page > 0:
        textbutton "<":
            action SetVariable("gallery_page", gallery_page - 1)
            xalign 0.1
            yalign 1.0
    if (gallery_page + 1) * maxperpage < len(gallery_images):
        textbutton ">":
            action SetVariable("gallery_page", gallery_page + 1)
            xalign 0.9
            yalign 1.0
    #return button
    textbutton "Return":
        action Return()
        xalign 1.0
        yalign 0.01
How the hell do I fix this?
 

the66

beware, the germans are cumming
Modder
Donor
Respected User
Jan 27, 2017
7,655
23,746
  1. you define the attribute character of your Gallery class as list [0,1,2,3,4,5] and the class argument character is never used.
  2. when you want to check the value of the character attribute you have to use something like if gallery_images[i].character==0:
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,171
Python:
        def __init__(self, name, images, thumb, character, locked="gallery_locked"):
            [...]
            self.character = [0,1,2,3,4]
            [...]
            self.charactername()

        def charactername(self):
            return self.character[0]

    [...]
    gallery_images.append(Gallery("Charlotte", ["charlotte1"], "thumbcharlotte1", 0))
    [...]
                    if gallery_images[i].character[0]:
                        [...]
                    if gallery_images[i].character[1]:
                        [...]
Four things here.

Firstly, according to the way you fill the gallery_images list, and use the character attribute,
the code should be :
Python:
        def __init__(self, name, images, thumb, character, locked="gallery_locked"):
            [...]
            self.character = [False,False,False,False,False]
            self.character[character] = True
            [...]
What you wrote is just the creation of a list that will contain the value 0, 1, 2, 3 and 4, this for every character. So, when later you utilize it, it will never works.
if gallery_images[i].character[0]: will always be False, because the value is 0, will all the others will always be True, because the value is not 0.

Secondly, the call to the charname method, in the __init__ meta-method is useless. The only thing done by this method is to return an entry of the character list, and always the same entry. And you'll not even store this returned value.

Thirdly, the charname method is useless. Like you wrote your code It's a method that will always return 0. And even with the correction regarding the character list, it stay useless, since it will always return the value of the first entry of the list.

Fourthly, you already have an attribute storing the name of the character, name. You don't need another way to know what character it is.


Python:
        def __init__(self, name, images, thumb, character, locked="gallery_locked"):
            [...]
            self.locked = locked
            self.refresh_lock()
One thing here.

You define the locked attribute, but never use it and will never use it since there's a is_locked attribute, defined by the refresh_lock method, and that you only rely on it.



Therefore, the class become :
Python:
#       def __init__(self, name, images, thumb, character, locked="gallery_locked"):
        def __init__(self, name, images, thumb ):
            self.name = name
            self.images = images
            self.thumb = thumb
#            self.character = [0,1,2,3,4]
#            self.locked = locked
            self.refresh_lock()
#            self.charactername()

        def num_images(self):
            return len(self.images)

        def refresh_lock(self):
            self.num_unlock = 0
            lockme = False
            for img in self.images:
                if not renpy.seen_image(img):
                    lockme = True
                else:
                    self.num_unlock += 1
            self.is_locked = lockme

#        def charactername(self):
#            return self.character[0]
The creation of a new object become :
Code:
#    gallery_images.append(Gallery("Charlotte", ["charlotte1"], "thumbcharlotte1", 0))
    gallery_images.append(Gallery("Charlotte", ["charlotte1"], "thumbcharlotte1"))
And the screen become either :
Code:
                imagebutton idle gallery_images[i].thumb:
                    if gallery_images[i].name == "Charlotte":
                        action Show("gallerychar_charlotte", dissolve,)
                    elif gallery_images[i].name == "Julia":
                        action Show("gallerychar_julia", dissolve,)
                    elif gallery_images[i].name == "Valerie":
                        action Show("gallerychar_valerie", dissolve,)
                    elif gallery_images[i].name == "Laura":
                        action Show("gallerychar_laura", dissolve,)
                    elif gallery_images[i].name == "Eileen":
                        action Show("gallerychar_eileen", dissolve,)
                    elif gallery_images[i].name == "Harem":
                        action Show("gallerychar_harem", dissolve,)
Or, better but need a little change in the code of the class, it can become :
Code:
        def charactername(self):
            return self.name.lower()
[...]
                imagebutton idle gallery_images[i].thumb:
                    action Show("gallerychar_{}".format( gallery_images[i].charactername() ), dissolve,)



Then, there's this thing :
Python:
        def refresh_lock(self):
            self.num_unlock = 0
            lockme = False
            for img in self.images:
                if not renpy.seen_image(img):
                    lockme = True
                else:
                    self.num_unlock += 1
            self.is_locked = lockme

[...]
                $ total = gallery_images[i].num_images()
                $ partial = gallery_images[i].num_unlock
                if gallery_images[i].is_locked:
                    null
                else:
                    text gallery_images[i].name
                    text "[partial]/[total]"
The is_locked attribute is True unless all the images have been seen. Therefore, your if/else structurein the screen don't do what you probably expected. Actually, to see how many images have been unlocked, over how many images there's to unlock, you need to have them all unlocked ; which is pretty useless.


Depending of your intent, the code should be either :
Python:
        def refresh_lock(self):
            self.num_unlock = 0
            lockme = False
            for img in self.images:
                if renpy.seen_image(img):
                    self.num_unlock += 1
            # Will be unlocked if at least one image have been seen.
            self.is_locked = self.num_unlock == 0
or this :
Code:
                $ total = gallery_images[i].num_images()
                $ partial = gallery_images[i].num_unlock
                text gallery_images[i].name
                text "[partial]/[total]"
or that :
Code:
                $ total = gallery_images[i].num_images()
                $ partial = gallery_images[i].num_unlock
                if gallery_images[i].is_locked:
                    text gallery_images[i].name
                    text "[partial]/[total]"
There's few other things, but normally they don't interfere and shouldn't prevent the gallery to works.

Edit: Corrected an error in the code.
 
Last edited:
  • Like
Reactions: AmazonessKing

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,917
Holy... That's a better answer than I expected. Thank you so much, it is so simple. Just wanted to point out some things.
You define the locked attribute, but never use it and will never use it since there's a is_locked attribute, defined by the refresh_lock method, and that you only rely on it.
I atually do, not in the main gallery. See, this is a gallerychar:
Python:
screen gallerychar_charlotte:

    add "black"

    $ start = gallerychar_charlotte_page * maxpercharpage
    $ end = min(start + maxpercharpage - 1, len(gallery_charlotteimages) - 1)

    #image grid
    grid maxnumcharx maxnumchary:
        xfill True
        yfill True

        for i in range(start, end + 1):
            $ gallery_charlotteimages[i].refresh_lock()
            if gallery_charlotteimages[i].is_locked:
                add gallery_charlotteimages[i].locked:
                    xalign 0.5
                    yalign 0.5
            else:
                imagebutton idle gallery_charlotteimages[i].thumb:
                    action Show("gallery_closeup", dissolve, gallery_charlotteimages[i].images)
                    xalign 0.5
                    yalign 0.5

        for i in range(end - start + 1, maxpercharpage):
            null

    #names
    grid maxnumcharx maxnumchary:
        xfill True
        yfill True

        for i in range(start, end + 1):
            hbox:
                spacing maxthumbchary - 70
                xalign 0.5
                yalign 0.9
                $ total = gallery_charlotteimages[i].num_images()
                $ partial = gallery_charlotteimages[i].num_unlock
                if gallery_charlotteimages[i].is_locked:
                    null
                else:
                    text gallery_charlotteimages[i].name
                    text "[partial]/[total]"

        for i in range(end - start + 1, maxpercharpage):
            null

    #previous and next buttons
    if gallerychar_charlotte_page > 0:
        textbutton "<":
            action SetVariable("gallerychar_charlotte_page", gallerychar_charlotte_page - 1)
            xalign 0.1
            yalign 1.0
    if (gallerychar_charlotte_page + 1) * maxpercharpage < len(gallery_charlotteimages):
        textbutton ">":
            action SetVariable("gallerychar_charlotte_page", gallerychar_charlotte_page + 1)
            xalign 0.9
            yalign 1.0
    #return button
    textbutton "Return":
        action [SetVariable("gallerychar_charlotte_page", 0), Hide("gallerychar_charlotte", dissolve)]
        xalign 1.0
        yalign 0.01
As you can see, I use the locked in the character gallery. Because I want it to reflect how many images are there to unlock, unlike the main gallery page, because there are "secret characters" and routes to unlock, the later 3 routes, so I don't want that to be reflected in the main gallery page.

So when the main gallery look like this:
You don't have permission to view the spoiler content. Log in or register now.
The character image gallery would look like this:
You don't have permission to view the spoiler content. Log in or register now.

Of course this is really really rough, I still need to implement a more things like fixing the position, putting names inside the gallery of specific characters, implement a change to "replay" mode. Make everything more interactive and user friendly and fun to traverse.

There's few other things, but normally they don't interfere and shouldn't prevent the gallery to works.
If you do, please go ahead. I know the gallery image is convoluted, but I kinda wanted to do it from scratch so I could adapt it to my needs, and it have been kind of working. I also want the gallery button to only appear if I have more than 1 image unlocked, but I didn't manage. I tried something like.
Python:
screen navigation():

    vbox:
        style_prefix "navigation"

        xpos gui.navigation_xpos
        yalign 0.5

        spacing gui.navigation_spacing

        if main_menu:

            textbutton _("Start") action Start()

            showif gallery_images[i].num_unlock > 0:
                textbutton _("Gallery") action ShowMenu("gallery")
But it tells me that
Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/screens.rpy", line 355, in execute
    screen main_menu():
  File "game/screens.rpy", line 355, in execute
    screen main_menu():
  File "game/screens.rpy", line 370, in execute
    use navigation
  File "game/screens.rpy", line 292, in execute
    screen navigation():
  File "game/screens.rpy", line 292, in execute
    screen navigation():
  File "game/screens.rpy", line 294, in execute
    vbox:
  File "game/screens.rpy", line 302, in execute
    if main_menu:
  File "game/screens.rpy", line 306, in execute
    showif gallery_images[i].num_unlock > 0:
TypeError: list indices must be integers, not unicode
I'm not exactly sure why it asks me for it to be integers if the > 0 is integers. Or is it because of the list? If so, I can't see a way to reference the class just for this one variable. Maybe using "$"?
 

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,917
I kind of have a work around.
Python:
            if renpy.seen_image("charlotte1" or "julia1" or "valerie1"):
                textbutton _("Gallery") action ShowMenu("gallery")
or
Python:
            if renpy.seen_image("charlotte1" and "julia1" and "valerie1"):
                textbutton _("Gallery") action ShowMenu("gallery")
The problem is that I need to see ALL of them in order to unlock the gallery and I was wondering if there was a way for me to unlock the gallery if I see either of those.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,171
Holy... That's a better answer than I expected. Thank you so much, it is so simple.
You're welcome. As your answer proved, I can only guess what is your intent. Therefore, the best way to answer you was to explain why this or that, so you can adapt it if needed.


If you do, please go ahead.
There's really no need to. The other little things are more an aesthetic question than anything else. Correcting them would probably confuse you more than helping you. This because it will not make things works effectively better, while making them not fitting anymore the change you already have in mind to achieve the final result you want.

The only thing I effectively have to add is correcting an error I made and just seen ; writing directly on the forum isn't always good and you can miss obvious error :(
This will not works :
Code:
                    action Show("gallerychar_{}".format gallery_images[i].charactername(), dissolve,)
It should be wrote like that :
Code:
                    action Show("gallerychar_{}".format( gallery_images[i].charactername() ), dissolve,)
I forgot the parenthesis.


I also want the gallery button to only appear if I have more than 1 image unlocked, but I didn't manage.
Something like this should do it :
Code:
[...]
      imagebutton:
          idle gallery_images[i].thumb:
          if  gallery_images[i].num_unlock > 1:
               action Show( [...] )
It will always display the button, but if there's less than 2 images unlocked, it will have no action, which will make it none sensitive, and so none clickable.
I thing that it's a better approach than not showing it at all, since it will keep the constancy of the gallery ; it works the same with a textbutton.


File "game/screens.rpy", line 306, in execute
showif gallery_images.num_unlock > 0:
TypeError: list indices must be integers, not unicode
[/CODE]
I'm not exactly sure why it asks me for it to be integers if the > 0 is integers.


The error refer to i, which should be an integer. If you look at the code you gave, you don't assign a value to this i variable. Therefore, Ren'py look into the store if there's a variable named i and apparently find it. Except that this variable have a string as value, which lead to the error.
 
  • Like
Reactions: AmazonessKing

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,917
It will always display the button, but if there's less than 2 images unlocked, it will have no action, which will make it none sensitive, and so none clickable.
Still tells me that the list must be integers. I have to figure a way to fix this. Thanks anyway!
 

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,917
I found a way with my old code of
Python:
            if renpy.seen_image("charlotte1" or "julia1" or "valerie1"):
                textbutton _("Gallery") action ShowMenu("gallery")
As I thought it was going to work. The reason it wasn't working it's because of what the renpy documentation says about renpy.seen_image:
renpy.seen_image(name)
Returns True if the named image has been seen at least once on the user's system. An image has been seen if it's been displayed using the show statement, scene statement, or function. (Note that there are cases where the user won't actually see the image, like a show immediately followed by a hide.)
So since for testing one of the pics I had only showed itself for just a single line of text, renpy considered it as "not seen" yet, but it worked perfectly with the other scenes that lasted longer.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,171
Still tells me that the list must be integers. I have to figure a way to fix this. Thanks anyway!
The list indice, not the list itself. You don't use it in a loop defining i so it will not works. You have to use it inside one of your for i in range(start, end + 1): block.


Python:
            if renpy.seen_image("charlotte1" or "julia1" or "valerie1"):
Oops, missed this the first time. It absolutely don't do what you think. With this syntax, Ren'py will always test if the image named "charlotte1" have been seen, and never test the other. What you want is :
Python:
            if renpy.seen_image("charlotte1") or renpy.seen_image("julia1" ) or renpy.seen_image("valerie1"):
 
  • Like
Reactions: AmazonessKing