Ren'Py Renpy Inventory Screen - Problem with showing Itemname while hovering

Vannyr

New Member
Aug 13, 2017
6
4
Hey there friends! :)

Long time lurker here. So I am currently developing a sandbox visual novel (first time) and it has been so much fun so far, but now I am in front of my dreaded inventory screen and I got it to work....ALMOST! But there is one thing I just cant wrap my head around, so maybe some of you kind people can help me before I rip all of my hair out. I've been at it for hours and hours and just... cant figure it out. Its driving me crazy haha.

So as some other games, I am using Milkymans Inventory System:

I am coding on Renpy 8, so this is Python 3.

I envision my game to have 3 different inventories: General / Gifts / Clothes
For now I am just coding the General tab. Thats why I named everything "genitem, genname" etc. I would just alter the code for the other inventories.

Here is the code for the inventory itself:
Python:
#default inventory for general
default genbackpack = GenContainer()

#default general inventory items
default generalgodofwaifu = GeneralItem('God Of Waifu', 'A good game', 'images/Items/itemgodofwaifu.png')
default generalsupersmashsisters = GeneralItem('Super Smash Sisters', 'A smashing game', 'images/Items/itemsupersmashsisters.png')

init python:
##### GENERAL ITEMS CODE #####
    class GeneralItem(object):
        def __init__(self, genname, gendescription, genimg):
            self.genname = genname
            self.gendescription = gendescription
            self.genimg = genimg

    class GeneralInvItem(object):
        def __init__(self, genitem, genamount):
            self.genitem = genitem
            self.genamount = genamount

    class GenContainer(object):
        def __init__(self):
            self.geninventory = []


        def add_genitem(self, genitem, genamount=1):
            if genitem in [a.genitem for a in self.geninventory]:
                self.geninventory[[a.genitem for a in self.geninventory].index(genitem)].genamount += genamount
            else:
                self.geninventory.append(GeneralInvItem(genitem,genamount))
                return
I don't have any other code there, just wanted to test it with adding first.

This is the command for adding items in the script:
Python:
    $ genbackpack.add_genitem(generalgodofwaifu)
    $ genbackpack.add_genitem(generalsupersmashsisters)

And this is my inventory screen on the General Tab:
Python:
default GeneralItemhov = "Unhovered"

screen inventoryuigeneral1:

## Some frames etc here that I am leaving out since it isnt important###

    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    hover a.genitem.genimg
                    action NullAction()
                    hovered SetVariable("GeneralItemhov", "Hovered")
                    unhovered SetVariable("GeneralItemhov", "Unhovered")
    showif GeneralItemhov == "Hovered":
        vbox:
            xpos 300
            ypos 800
            for a in genbackpack.geninventory:
                text a.genitem.genname            
                text a.genitem.gendescription
It displays the images of the items (genimg) themselves correctly side to side as programmed in the grid.
When I hover over one of the items, it shows me all the names of the items and descriptions in the General Inventory. I understand that its because I asked it to with "a." because it lists everything in that Container.
But for the life of me I cant figure out how to ONLY display the name and description of the item the player is currently hovering over. Every other code I tried so far gave me an error. I've searched everything up and down for an answer but came up short. Did I already make a mistake with displaying the images themselves?

And I dont even dare to ask how to program a function that opens a second inventory tab when the first 18 items of the first General Inventory Page are full. These two are the only things standing in my way of finally putting my troubles to rest.

I would be thrilled if some of you talented people could help me out! Other than this, coding as been a breeze and so much fun. Thank you so much in advance and much love from Germany!
Vannyr

Edit: Formatting, spelling etc
 
Last edited:

peterppp

Member
Mar 5, 2020
459
867
Hey there friends! :)

Long time lurker here. So I am currently developing a sandbox visual novel (first time) and it has been so much fun so far, but now I am in front of my dreaded inventory screen and I got it to work....ALMOST! But there is one thing I just cant wrap my head around, so maybe some of you kind people can help me before I rip all of my hair out. I've been at it for hours and hours and just... cant figure it out. Its driving me crazy haha.

So as some other games, I am using Milkymans Inventory System:

I am coding on Renpy 8, so this is Python 3.

I envision my game to have 3 different inventories: General / Gifts / Clothes
For now I am just coding the General tab. Thats why I named everything "genitem, genname" etc. I would just alter the code for the other inventories.

Here is the code for the inventory itself:
Python:
#default inventory for general
default genbackpack = GenContainer()

#default general inventory items
default generalgodofwaifu = GeneralItem('God Of Waifu', 'A good game', 'images/Items/itemgodofwaifu.png')
default generalsupersmashsisters = GeneralItem('Super Smash Sisters', 'A smashing game', 'images/Items/itemsupersmashsisters.png')

init python:
##### GENERAL ITEMS CODE #####
    class GeneralItem(object):
        def __init__(self, genname, gendescription, genimg):
            self.genname = genname
            self.gendescription = gendescription
            self.genimg = genimg

    class GeneralInvItem(object):
        def __init__(self, genitem, genamount):
            self.genitem = genitem
            self.genamount = genamount

    class GenContainer(object):
        def __init__(self):
            self.geninventory = []


        def add_genitem(self, genitem, genamount=1):
            if genitem in [a.genitem for a in self.geninventory]:
                self.geninventory[[a.genitem for a in self.geninventory].index(genitem)].genamount += genamount
            else:
                self.geninventory.append(GeneralInvItem(genitem,genamount))
                return
I don't have any other code there, just wanted to test it with adding first.

This is the command for adding items in the script:
Python:
    $ genbackpack.add_genitem(generalgodofwaifu)
    $ genbackpack.add_genitem(generalsupersmashsisters)

And this is my inventory screen on the General Tab:
Python:
default GeneralItemhov = "Unhovered"

screen inventoryuigeneral1:

## Some frames etc here that I am leaving out since it isnt important###

    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    hover a.genitem.genimg
                    action NullAction()
                    hovered SetVariable("GeneralItemhov", "Hovered")
                    unhovered SetVariable("GeneralItemhov", "Unhovered")
    showif GeneralItemhov == "Hovered":
        vbox:
            xpos 300
            ypos 800
            for a in genbackpack.geninventory:
                text a.genitem.genname
                text a.genitem.gendescription
It displays the images of the items (genimg) themselves correctly side to side as programmed in the grid.
When I hover over one of the items, it shows me all the names of the items and descriptions in the General Inventory. I understand that its because I asked it to with "a." because it lists everything in that Container.
But for the life of me I cant figure out how to ONLY display the name and description of the item the player is currently hovering over. Every other code I tried so far gave me an error. I've searched everything up and down for an answer but came up short. Did I already make a mistake with displaying the images themselves?

And I dont even dare to ask how to program a function that opens a second inventory tab when the first 18 items of the first General Inventory Page are full. These two are the only things standing in my way of finally putting my troubles to rest.

I would be thrilled if some of you talented people could help me out! Other than this, coding as been a breeze and so much fun. Thank you so much in advance and much love from Germany!
Vannyr

Edit: Formatting, spelling etc
there are probably better ways to do it, but for showing the text for the items, this is what i came up with.
Code:
    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    hover a.genitem.genimg
                    action NullAction()
                    hovered SetVariable("GeneralItemhov", [a.genitem.genname, a.genitem.gendescription])
                    unhovered SetVariable("GeneralItemhov", "Unhovered")
    showif GeneralItemhov != "Unhovered":
        vbox:
            xpos 300
            ypos 800
            text GeneralItemhov[0] 
            text GeneralItemhov[1]
i would have preferred to instead show a screen or something passing the "a" object and do the vbox in the screen using said "a" object, or something like that, but spending some 20 minutes on it, i couldn't figure out if that is even possible with hovered. and i'm sure no one here knows either*

* i read about this technique to get data from people in the internet. let's see if it works.
 
Last edited:
  • Like
Reactions: Vannyr

Vannyr

New Member
Aug 13, 2017
6
4
there are probably better ways to do it, but for showing the text for the items, this is what i came up with.
Code:
    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    hover a.genitem.genimg
                    action NullAction()
                    hovered SetVariable("GeneralItemhov", [a.genitem.genname, a.genitem.gendescription])
                    unhovered SetVariable("GeneralItemhov", "Unhovered")
    showif GeneralItemhov != "Unhovered":
        vbox:
            xpos 300
            ypos 800
            text GeneralItemhov[0]
            text GeneralItemhov[1]
Oh my GOD, I was already ready to go to sleep, but after reading your reply I jolted back up and had to test it. And now I am just sitting here, smiling, hovering over the items because it works! Thank you SO much!
Now a big weight has been lifted off my shoulders and the only thing I need to worry about is it switching to the second page of the inventory once the 6x3 grid is full, but that seems to be documented way better and is a thing I can tackle once I get there. Once again, thank you!

i would have preferred to instead show a screen or something passing the "a" object and do the vbox in the screen using said "a" object, or something like that, but spending some 20 minutes on it, i couldn't figure out if that is even possible with hovered. and i'm sure no one here knows either*

* i read about this technique to get data from people in the internet. let's see if it works.
You actually had me laughing there. I mean: If someone on here knows a better way to code it, I can't wait to read it and make notes to learn. Mine is pretty sloppy as is, but coding in a genuine coding language is definitely my weak spot haha.
 
  • Like
Reactions: peterppp

peterppp

Member
Mar 5, 2020
459
867
Oh my GOD, I was already ready to go to sleep, but after reading your reply I jolted back up and had to test it. And now I am just sitting here, smiling, hovering over the items because it works! Thank you SO much!
Now a big weight has been lifted off my shoulders and the only thing I need to worry about is it switching to the second page of the inventory once the 6x3 grid is full, but that seems to be documented way better and is a thing I can tackle once I get there. Once again, thank you!



You actually had me laughing there. I mean: If someone on here knows a better way to code it, I can't wait to read it and make notes to learn. Mine is pretty sloppy as is, but coding in a genuine coding language is definitely my weak spot haha.
i figured out how to do what i originally wanted
Code:
    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    hover a.genitem.genimg
                    action NullAction()
                    hovered SetVariable("GeneralItemhov", a)
                    unhovered SetVariable("GeneralItemhov", "Unhovered")
    showif GeneralItemhov != "Unhovered":
        vbox:
            xpos 300
            ypos 800
            if isinstance(GeneralItemhov, GeneralInvItem):
                text GeneralItemhov.genitem.genname
                text GeneralItemhov.genitem.gendescription
now everything you want to do with "a" can be decided after the showif which gives you flexibility to do different things. the thing i had to add to make it work is the isinstance check. not sure why, but it seems GeneralItemhov is not always an "a" object inside showif and it will cause error
 
Last edited:
  • Like
Reactions: Vannyr

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,130
14,809
Excuse-me guys, but why the fuck do you all use hovered and unhovered ?

Python:
screen inventoryuigeneral1():  # The '()' is not optional.

    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    #hover a.genitem.genimg   # This is useless since it's the same than /idle/
                    action NullAction()
                    tooltip ( a.genitem.genname, a.genitem.gendescription )          

    $ tt = GetTooltip()
    if tt:
        vbox:
            xpos 300
            ypos 800
            text tt[0]
            text tt[1]
 

peterppp

Member
Mar 5, 2020
459
867
Excuse-me guys, but why the fuck do you all use hovered and unhovered ?

Python:
screen inventoryuigeneral1():  # The '()' is not optional.

    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    #hover a.genitem.genimg   # This is useless since it's the same than /idle/
                    action NullAction()
                    tooltip ( a.genitem.genname, a.genitem.gendescription )        

    $ tt = GetTooltip()
    if tt:
        vbox:
            xpos 300
            ypos 800
            text tt[0]
            text tt[1]
better, but unless there's a good reason for passing selected values of "a"...
Python:
    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    #hover a.genitem.genimg   # This is useless since it's the same than /idle/
                    action NullAction()
                    tooltip (a)  
    $ tt = GetTooltip()
    if tt:
        vbox:
            xpos 300
            ypos 800
            text tt.genitem.genname      
            text tt.genitem.gendescription
 
  • Like
Reactions: Vannyr

Quintillian

Newbie
Apr 15, 2019
94
196
Excuse-me guys, but why the fuck do you all use hovered and unhovered ?

Python:
screen inventoryuigeneral1():  # The '()' is not optional.

    hbox:
        grid 6 3:
            xpos 300
            ypos 150
            spacing 21
            for a in genbackpack.geninventory:
                imagebutton:
                    idle a.genitem.genimg
                    #hover a.genitem.genimg   # This is useless since it's the same than /idle/
                    action NullAction()
                    tooltip ( a.genitem.genname, a.genitem.gendescription )      

    $ tt = GetTooltip()
    if tt:
        vbox:
            xpos 300
            ypos 800
            text tt[0]
            text tt[1]
Indeed are what you need, Vannyr.

Also to expand a little on this answer, screen declarations like screen inventoryuigeneral1(): should always have the () parenthesis at the end for even if they dont receive any parameters.

You can use action NullAction() to make the button .

And lastly, for:
Python:
class GenContainer(object):
        def __init__(self):
            self.geninventory = []


        def add_genitem(self, genitem, genamount=1):
            if genitem in [a.genitem for a in self.geninventory]:
                self.geninventory[[a.genitem for a in self.geninventory].index(genitem)].genamount += genamount
            else:
                self.geninventory.append(GeneralInvItem(genitem,genamount))
                return
I understand it is a coding style choice, and one of the biggest hurdles of programming is deciding how to name stuff(no joke), but adding gen to everything inside the GenContainer class seems redundant, makes the code harder to read, and if in the future you need to or want to refactor GenContainer to change its name, now you have more work changing all the other gens too. Just a thing to consider.

And speaking of things to consider. I can't see any reason in the code above why self.geninventory must be a list instead of a dictionary. If you dont know the difference between the two, is not the end of the world. Go read about it, and then consider this alternative version:

Python:
from collections import defaultdict
def default_inv_item():
    return GeneralInvItem(None, genamount=0)

class GenContainer(object):
    def __init__(self):
        self.geninventory = defaultdict(default_inv_item)
 
    def add_genitem(self, genitem, genamount = 1):
        inv_genitem = self.geninventory[genitem.genname]
        inv_genitem.genamount += genamount
        inv_genitem.genitem = genitem
Good luck with your game!
 
Last edited:
  • Like
Reactions: Vannyr

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,130
14,809
better, but unless there's a good reason for passing selected values of "a"...
There's no reason to pass directly the separate values, except remind to the readers that it's not limited to a single value like in the doc example. Or, more precisely, that a tuple (but also a list or a dict) count for one.

This being said, your tooltip (a) is incorrect ; not wrong, just incorrect. Like it's a single value, tooltip a is enough.
Normally Ren'Py shouldn't complain, and Python will not confuse it with a one entity tuple, but I don't guaranty the first at 100%, while the confusion can come from the reader.
 
  • Like
Reactions: Vannyr and peterppp

Vannyr

New Member
Aug 13, 2017
6
4
First of all:
Thank you all MASSIVELY for taking the time to help me out. This project is very close to my heart and I want to produce the best experience I possibly can. So I am very, very thankful for your help, I cant stress enough how much I was ripping my hair out trying to resolve this haha.

I'll try to reply to as much as I can:

Excuse-me guys, but why the fuck do you all use hovered and unhovered ?
As someone who only coded in renpy language so far, this was my first time using pure python coding. First I tried and looked up tutorials on yt, lemnasoft & here and tried a bunch of stuff until I got it to work mostly. This hovered/unhovered code was the one I found first and that was documented in a way I could understand it as a beginner. And thats my first goal: Don't just copy paste the code, Vannyr, understand it, learn from it.
Your code is way more elegant and now I know how to use the tooltip function! Thank you!

Indeed are what you need, Vannyr.

Also to expand a little on this answer, screen declarations like screen inventoryuigeneral1(): should always have the () parenthesis at the end for even if they dont receive any parameters.

You can use action NullAction() to make the button .
Thank you for these tips so far. It hadn't even crossed my mind that this would increase performance, but I will definitely implement it in all screens I'll be using. Also thank you for the hyperlinks, more stuff to study and learn from!

And lastly, for:
Python:
class GenContainer(object):
        def __init__(self):
            self.geninventory = []


        def add_genitem(self, genitem, genamount=1):
            if genitem in [a.genitem for a in self.geninventory]:
                self.geninventory[[a.genitem for a in self.geninventory].index(genitem)].genamount += genamount
            else:
                self.geninventory.append(GeneralInvItem(genitem,genamount))
                return
I understand it is a coding style choice, and one of the biggest hurdles of programming is deciding how to name stuff(no joke), but adding gen to everything inside the GenContainer class seems redundant, makes the code harder to read, and if in the future you need to or want to refactor GenContainer to change its name, now you have more work changing all the other gens too. Just a thing to consider.
Absolutely true, you're right. When I came up with the names, I was following Milkymans explanation to understand what I was doing, but I found nothing about having multiple inventories. I was afraid I would code myself in a corner when I use "amount" and "item" with the same name in different inventories, maybe leading to an error I couldn't foresee, so I tried to differenciate these aswell.

And speaking of things to consider. I can't see any reason in the code above why self.geninventory must be a list instead of a dictionary. If you dont know the difference between the two, is not the end of the world. Go read about it, and then consider this alternative version:

Python:
from collections import defaultdict
def default_inv_item():
    return GeneralInvItem(None, genamount=0)

class GenContainer(object):
    def __init__(self):
        self.geninventory = defaultdict(default_inv_item)

    def add_genitem(self, genitem, genamount = 1):
        inv_genitem = self.geninventory[genitem.genname]
        inv_genitem.genamount += genamount
        inv_genitem.genitem = genitem
I will definitely come back to this, I already set apart some time to dig through all of your tips and suggestions and try to learn from it. From my mindset a week ago, it was like this: I want the player to have the items in their inventory arranged in the order they picked them up in. I thought a dictionary would order them in order OF the dictionary and a list would be closer to my goal. Also, since I presume I might need more than 18 inventory spaces and with that another inventory page, I took a sneak peek at how to code that aswell and almost everything I found was with lists. I am sure you guys can make it work with dictionaries aswell, but I myself was too afraid of losing even more hair haha.

Good luck with your game!
Thank you so much! I hope I can share the 0.1 version that I envision as soon as possible.
 
Last edited:
  • Like
Reactions: Quintillian