Inventory System with click-to-use-item feature

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
ourdecemberdreams
Regular
Posts: 58
Joined: Sat Apr 15, 2017 3:26 pm
Projects: The Last December
Tumblr: ourdecemberdreams
Deviantart: ourdecemberdreams
itch: ourdecemberdreams
Contact:

Inventory System with click-to-use-item feature

#1 Post by ourdecemberdreams »

Heyyy so I'm trying to make an inventory system but I got stuck pretty badly at implementing this function. I want to make it such that users can select an object from the inventory screen then decide what they would want to do with it, like drop it, or use it. If not they can simply select another object to look at the other object's details etc. I have this so far:

Code: Select all

init:
    $ inventory = [["images/inventory/gem_blue.png", "images/inventory/gem_blue.png", "images/inventory/gem_blue_selected.png", "Water", "A blue gem"], ["images/inventory/gem_red.png", "images/inventory/gem_red.png", "images/inventory/gem_red_selected.png", "Earth", "A red gem"], ["images/inventory/gem_green.png", "images/inventory/gem_green.png", "images/inventory/gem_green_selected.png", "Land", "A green gem"]]
    $ use_item = []

screen description:
    default item = 0
    vbox:
        text inventory[item][3]
        xpos 660
        ypos 530

screen inventory:
    tag menu

    imagemap:
        ground "gui/inventory_background.png"
        hover "gui/inventory_background.png"
        alpha False
        
        hotspot (1170, 0, 110, 140) action Return()


    grid 4 2:
        spacing 16
        xpos 652
        ypos 230

        for i in range(len(inventory)):
            imagebutton:
                xsize 73
                ysize 71
                
                idle inventory[i][0]
                hover inventory[i][1]
                selected_idle inventory[i][2]
                selected_hover inventory[i][2]
                hovered Show("description", item = i)
                unhovered Hide("description") action [ShowMenu("itemmenu"), SetVariable("use_item", inventory[i][3])]

        for i in range(8 - len(inventory)):
            null
            
screen itemmenu:
    default item = 0
    vbox:
        text inventory[item][4]
        xpos 660
        ypos 530
Problem is, when I select one of the object, all three of the object gets selected and the description will show the first object's even if I click on the other 2 objects. I'm not sure where I went wrong? Please help! Thanks!

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Inventory System with click-to-use-item feature

#2 Post by kivik »

A few things here:

1 - don't use for i in range(len(inventory)) when you're iterating over a list of items, use for item in inventory to directly reference items in a list. It shortens your code and makes it much easier to understand what's going on.
Your second iteration in the list by range(8 - len(inventory)) is fine however as you're just trying to create empty spaces.

2 - don't use a list of lists to store your items - you don't have a contextual reference to any of the items this way. If you don't want to use objects, then at least use a python dictionary to store them - that way you'll be reference their properties by item["name"], item["image"] instead of item[1] for name, item[2] for image etc.

For reference, a dictionary looks like this: {"name": "Water", "desc": "A blue gem", "image": etc. etc.}. So you can have a list of dicts: [{item 1 dictionary}, {item 2 dictionary}, etc.] and iterate through them.

3 - you're showing the description screen and passing item=i in, but your description screen doesn't take a parameter. So item = i is never used. You've added a default item = 0 line at the start of it, but that just creates a screen variable and set it to 0 after the screen is shown, and 0 is the first item.

Take a look at the parameter part of this page: https://www.renpy.org/doc/html/screens. ... -statement

See if you can work out what needs to change :)


You may have more questions after this, but get those bits fixed first, test it out, understand what's going on, and then see if you can work out the rest of what you want to do :)

ourdecemberdreams
Regular
Posts: 58
Joined: Sat Apr 15, 2017 3:26 pm
Projects: The Last December
Tumblr: ourdecemberdreams
Deviantart: ourdecemberdreams
itch: ourdecemberdreams
Contact:

Re: Inventory System with click-to-use-item feature

#3 Post by ourdecemberdreams »

kivik wrote: Mon May 28, 2018 10:20 am 2 - don't use a list of lists to store your items - you don't have a contextual reference to any of the items this way. If you don't want to use objects, then at least use a python dictionary to store them - that way you'll be reference their properties by item["name"], item["image"] instead of item[1] for name, item[2] for image etc.

For reference, a dictionary looks like this: {"name": "Water", "desc": "A blue gem", "image": etc. etc.}. So you can have a list of dicts: [{item 1 dictionary}, {item 2 dictionary}, etc.] and iterate through them.
hey thanks for pointing this out! I've edited my array into that format.

Code: Select all

init 1:
    default item = 0
    
    $ inventory = [
        {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
        {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"}, 
        {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"}
        ]
    $ use_item = []

---

kivik wrote: Mon May 28, 2018 10:20 am 3 - you're showing the description screen and passing item=i in, but your description screen doesn't take a parameter. So item = i is never used. You've added a default item = 0 line at the start of it, but that just creates a screen variable and set it to 0 after the screen is shown, and 0 is the first item.
I've actually managed to figure out how to get the selected items to only select one, seems like it was a problem with my "itemmenu" screen? If I remove that action, it works well, but I'm not sure why it's wrong?

Code: Select all

screen description:
    vbox:
        text inventory[item]["description"]
        xpos 660
        ypos 530

screen inventory:
    tag menu

    imagemap:
        ground "gui/inventory_background.png"
        hover "gui/inventory_background.png"
        selected_idle "gui/inventory_background.png"
        selected_hover "gui/inventory_background.png"
        alpha False
        
        hotspot (1170, 0, 110, 140) action [Return(), Hide("itemmenu")]
        #hotspot (982, 546, 115, 44) action inventory.remove(inventory[item])




    grid 4 2:
        spacing 16
        xpos 652
        ypos 230

        for item in inventory:
            imagebutton:
                xsize 73
                ysize 71
                
                idle inventory[item]["normal"]
                selected_idle inventory[item]["select"]
                selected_hover inventory[item]["select"]
                hovered Show("description", item = i)
                unhovered Hide("description")
                action SetVariable("use_item", inventory[item]["title"])

        for i in range(8 - len(inventory)):
            null
            
screen itemmenu:
    vbox:
        text inventory[item].title
        xpos 660
        ypos 530    

---

kivik wrote: Mon May 28, 2018 10:20 am 1 - don't use for i in range(len(inventory)) when you're iterating over a list of items, use for item in inventory to directly reference items in a list. It shortens your code and makes it much easier to understand what's going on.
Your second iteration in the list by range(8 - len(inventory)) is fine however as you're just trying to create empty spaces.
I've edited my code as per you advice, but I've got a new error code now...

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/screens.rpy", line 197, in execute
    ground "gui/inventory_background.png"
  File "game/screens.rpy", line 197, in execute
    ground "gui/inventory_background.png"
  File "game/screens.rpy", line 212, in execute
    
  File "game/screens.rpy", line 217, in execute
    
  File "game/screens.rpy", line 218, in execute
    idle inventory[i][0]
  File "game/screens.rpy", line 218, in keywords
    idle inventory[i][0]
TypeError: list indices must be integers, not RevertableDict

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ast.py", line 814, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/python.py", line 1719, in py_exec_bytecode
    exec bytecode in globals, locals
  File "renpy/common/_layout/screen_main_menu.rpym", line 30, in <module>
    ui.interact()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ui.py", line 285, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2538, in interact
    scene_lists.replace_transient()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 822, in replace_transient
    self.remove(layer, tag)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 1107, in remove
    self.hide_or_replace(layer, remove_index, "hide")
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 1031, in hide_or_replace
    d = oldsle.displayable._hide(now - st, now - at, prefix)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 443, in _hide
    self.update()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 578, in update
    self.screen.function(**self.scope)
  File "game/screens.rpy", line 197, in execute
    ground "gui/inventory_background.png"
  File "game/screens.rpy", line 197, in execute
    ground "gui/inventory_background.png"
  File "game/screens.rpy", line 212, in execute
    
  File "game/screens.rpy", line 217, in execute
    
  File "game/screens.rpy", line 218, in execute
    idle inventory[i][0]
  File "game/screens.rpy", line 218, in keywords
    idle inventory[i][0]
  File "<screen language>", line 222, in <module>
TypeError: list indices must be integers, not RevertableDict

Darwin-17.4.0-x86_64-i386-64bit
Ren'Py 6.99.12.4.2187

User avatar
Enchant00
Regular
Posts: 136
Joined: Tue Jan 12, 2016 1:17 am
Contact:

Re: Inventory System with click-to-use-item feature

#4 Post by Enchant00 »

The problem lies with the way you are iterating over your dictionary. When you use a for loop on a dictionary, it moves on each key inside your dictionary.

Code: Select all

for i in random_dic:
    random_dic = {key1: value1, key2: value 2}
So it moves from key1 to key2 and .etc

In your code you used this line

Code: Select all

for i in range(len(inventory)):
    ...extra code
Which means that it is iterating over a range of numbers rather than the dictionary itself. The difference between a dictionary and a list in terms of loops and iterations is that a list is acessed by it's indice or number value while a dictionary is acessed by its key value.

You code is that of an indice value rather than key value. So what is understood is that iterate from numbers: 0 - the length of your dictionary rather than iterate from the first key all the way to the last.

Your loop should be something like this. That was it will go through the keys or the elements rather than it's indice value which is usually for list and alike but not for dictionaries.

Code: Select all

for i in inventory:
    ...extra code

User avatar
Enchant00
Regular
Posts: 136
Joined: Tue Jan 12, 2016 1:17 am
Contact:

Re: Inventory System with click-to-use-item feature

#5 Post by Enchant00 »

Oh wait it seems the first problem was already tackled my bad :D Anyway, I think the problem is actually here in this part of your code

Code: Select all

 for item in inventory:
            imagebutton:
                xsize 73
                ysize 71
                
                idle inventory[item]["normal"]
                selected_idle inventory[item]["select"]
                selected_hover inventory[item]["select"]
I'm checking your inventory dictionary but I don't see any "normal" or "select"? Also, when you access a value from a key inside a dictionary you use the indice which should be declared something as such: dictionary_name[key][indice number] if you have multiple values.

Code: Select all

...
                idle inventory[item]["normal"]  # Your code fails at this part trying to acess normal which in turn should be an indice instead. 
                selected_idle inventory[item]["select"]
                selected_hover inventory[item]["select"]
Hmms it also seems that you placed your dictionary items inside a list []. This would return an error since iteration is that of a list rather than a dict and in your inventory[item]["normal"] you're trying to access a dictionary from a type list. Also, the lack of keys makes it difficult to access.

Also, I would recommend that your dictionary be constructed in this manner:

Code: Select all

$ inventory = {
    "Gem": {
        'Blue':  {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
        'Red' :    {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"},
        'Green' :  {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"}
        }
    }
So when you loop is would be something like this. I also think that they keys you are trying to access are the "idle" and "selected" keys so forgive me if I'm wrong but probably the code below should work with the proper keys instead.

Code: Select all

for item in inventory:
    for x in inventory[item]
            imagebutton:
                xsize 73
                ysize 71
                
                idle inventory[item][x]['idle']  # No normal key so I'm guessing you want to use the idle key
                selected_idle inventory[item][x]["selected"]
                selected_hover inventory[item][x]["selected"]

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Inventory System with click-to-use-item feature

#6 Post by kivik »

I'm not sure how enchant00's double loop works, since "item" is not an index when you do for item in inventory. This is what I was thinking about (going by OP's own list of dicts:

Code: Select all

$ inventory = [
        {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
        {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"}, 
        {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"}
        ]
I'd loop through it like this:

Code: Select all

        for item in inventory:
            imagebutton:
                xsize 73
                ysize 71
                
                idle item["idle"]
                selected_idle item["select"]
                selected_hover item["select"]
                hovered Show("description", item = item)
                unhovered Hide("description")
                action SetVariable("use_item", item["title"])
The idea of for item in list is that you directly use the item variable, and not have to worry about indices - you then use the key to access the contextual information you want, i.e. item["select"]

Also you still haven't setup a parameter for your screen:

Code: Select all

screen description(item):
    vbox:
        text item["description"]
        xpos 660
        ypos 530
This way you're passing the item directly into your description screen, and referencing it as item. Alternatively, you can just pass the description through:

Code: Select all

hover Show("description", desc=item["description"])

...

screen description(desc):
    vbox:
        text desc
        xpos 660
        ypos 530

ourdecemberdreams
Regular
Posts: 58
Joined: Sat Apr 15, 2017 3:26 pm
Projects: The Last December
Tumblr: ourdecemberdreams
Deviantart: ourdecemberdreams
itch: ourdecemberdreams
Contact:

Re: Inventory System with click-to-use-item feature

#7 Post by ourdecemberdreams »

kivik wrote: Mon May 28, 2018 4:12 pm I'd loop through it like this:

Code: Select all

        for item in inventory:
            imagebutton:
                xsize 73
                ysize 71
                
                idle item["idle"]
                selected_idle item["select"]
                selected_hover item["select"]
                hovered Show("description", item = item)
                unhovered Hide("description")
                action SetVariable("use_item", item["title"])
The idea of for item in list is that you directly use the item variable, and not have to worry about indices - you then use the key to access the contextual information you want, i.e. item["select"]

Also you still haven't setup a parameter for your screen:

Code: Select all

screen description(item):
    vbox:
        text item["description"]
        xpos 660
        ypos 530
This way you're passing the item directly into your description screen, and referencing it as item. Alternatively, you can just pass the description through:

Code: Select all

hover Show("description", desc=item["description"])

...

screen description(desc):
    vbox:
        text desc
        xpos 660
        ypos 530
Ahh sorry, it seems like I misunderstood the meaning of parameters. I've edited my parameters and loop according to yours, but the error's still there :(

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/screens.rpy", line 197, in execute
    screen inventory:
  File "game/screens.rpy", line 197, in execute
    screen inventory:
  File "game/screens.rpy", line 212, in execute
    grid 4 2:
  File "game/screens.rpy", line 217, in execute
    for item in inventory:
  File "game/screens.rpy", line 218, in execute
    imagebutton:
  File "game/screens.rpy", line 218, in keywords
    imagebutton:
TypeError: list indices must be integers, not RevertableDict

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ast.py", line 814, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/python.py", line 1719, in py_exec_bytecode
    exec bytecode in globals, locals
  File "renpy/common/_layout/screen_main_menu.rpym", line 30, in <module>
    ui.interact()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ui.py", line 285, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2538, in interact
    scene_lists.replace_transient()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 822, in replace_transient
    self.remove(layer, tag)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 1107, in remove
    self.hide_or_replace(layer, remove_index, "hide")
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 1031, in hide_or_replace
    d = oldsle.displayable._hide(now - st, now - at, prefix)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 443, in _hide
    self.update()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 578, in update
    self.screen.function(**self.scope)
  File "game/screens.rpy", line 197, in execute
    screen inventory:
  File "game/screens.rpy", line 197, in execute
    screen inventory:
  File "game/screens.rpy", line 212, in execute
    grid 4 2:
  File "game/screens.rpy", line 217, in execute
    for item in inventory:
  File "game/screens.rpy", line 218, in execute
    imagebutton:
  File "game/screens.rpy", line 218, in keywords
    imagebutton:
  File "<screen language>", line 224, in <module>
TypeError: list indices must be integers, not RevertableDict

Darwin-17.4.0-x86_64-i386-64bit
Ren'Py 6.99.12.4.2187
Here's my new code:

Code: Select all

init 1:
    default item = 0
    
    $ inventory = [
        {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
        {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"}, 
        {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"}
        ]
    $ use_item = []

screen description(desc):
    vbox:
        text desc
        xpos 660
        ypos 530

screen inventory:
    tag menu

    imagemap:
        ground "gui/inventory_background.png"
        hover "gui/inventory_background.png"
        selected_idle "gui/inventory_background.png"
        selected_hover "gui/inventory_background.png"
        alpha False
        
        hotspot (1170, 0, 110, 140) action [Return(), Hide("itemmenu")]
        #hotspot (982, 546, 115, 44) action inventory.remove(inventory[item])
        #hotspot (982, 586, 115, 44) action Return()


    grid 4 2:
        spacing 16
        xpos 652
        ypos 230

        for item in inventory:
            imagebutton:
                xsize 73
                ysize 71
                
                idle item["idle"]
                selected_idle item["selected"]
                selected_hover inventory[item]["selected"]
                hovered Show("description", desc=item["description"])
                unhovered Hide("description")
                action [ShowMenu("itemmenu"), SetVariable("use_item", item["title"])]

        for i in range(8 - len(inventory)):
            null
            
screen itemmenu(item):
    vbox:
        text item["title"]
        xpos 660
        ypos 530
        

ourdecemberdreams
Regular
Posts: 58
Joined: Sat Apr 15, 2017 3:26 pm
Projects: The Last December
Tumblr: ourdecemberdreams
Deviantart: ourdecemberdreams
itch: ourdecemberdreams
Contact:

Re: Inventory System with click-to-use-item feature

#8 Post by ourdecemberdreams »

Enchant00 wrote: Mon May 28, 2018 12:35 pm I'm checking your inventory dictionary but I don't see any "normal" or "select"? Also, when you access a value from a key inside a dictionary you use the indice which should be declared something as such: dictionary_name[key][indice number] if you have multiple values.

Code: Select all

...
                idle inventory[item]["normal"]  # Your code fails at this part trying to acess normal which in turn should be an indice instead. 
                selected_idle inventory[item]["select"]
                selected_hover inventory[item]["select"]
Hmms it also seems that you placed your dictionary items inside a list []. This would return an error since iteration is that of a list rather than a dict and in your inventory[item]["normal"] you're trying to access a dictionary from a type list. Also, the lack of keys makes it difficult to access.

Also, I would recommend that your dictionary be constructed in this manner:

Code: Select all

$ inventory = {
    "Gem": {
        'Blue':  {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
        'Red' :    {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"},
        'Green' :  {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"}
        }
    }
So when you loop is would be something like this. I also think that they keys you are trying to access are the "idle" and "selected" keys so forgive me if I'm wrong but probably the code below should work with the proper keys instead.

Code: Select all

for item in inventory:
    for x in inventory[item]
            imagebutton:
                xsize 73
                ysize 71
                
                idle inventory[item][x]['idle']  # No normal key so I'm guessing you want to use the idle key
                selected_idle inventory[item][x]["selected"]
                selected_hover inventory[item][x]["selected"]
Hahahaha sorry I forgot to change the "normal"s and "selected"s I copied and pasted here before changing it in my codes, but it's named correctly in my codes. I've tried defining my inventory and loop with your method:

Code: Select all

init 1:
    default item = 0
    
    $ inventory = {
        "Gem": {
            'Blue':  {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
            'Red' :    {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"},
            'Green' :  {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"}
        }
    }
    $ use_item = []

screen description(desc):
    vbox:
        text desc
        xpos 660
        ypos 530

screen inventory:
    tag menu

    imagemap:
        ground "gui/inventory_background.png"
        hover "gui/inventory_background.png"
        selected_idle "gui/inventory_background.png"
        selected_hover "gui/inventory_background.png"
        alpha False
        
        hotspot (1170, 0, 110, 140) action [Return(), Hide("itemmenu")]
        #hotspot (982, 546, 115, 44) action inventory.remove(inventory[item])
        #hotspot (982, 586, 115, 44) action Return()


    grid 4 2:
        spacing 16
        xpos 652
        ypos 230

        for item in inventory:
            for x in inventory[item]:
                imagebutton:
                    xsize 73
                    ysize 71
                    
                    idle inventory[item][x]["idle"]
                    selected_idle inventory[item][x]["selected"]
                    selected_hover inventory[item][x]["selected"]
                    hovered Show("description", desc=inventory[item][x]["description"])
                    unhovered Hide("description")
                    action SetVariable("use_item", inventory[item][x]["title"])

        for i in range(8 - len(inventory)):
            null
but now I've got a new error:

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
Exception: Grid overfull.

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ast.py", line 814, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/python.py", line 1719, in py_exec_bytecode
    exec bytecode in globals, locals
  File "renpy/common/_layout/screen_main_menu.rpym", line 30, in <module>
    ui.interact()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ui.py", line 285, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2526, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2883, in interact_core
    self.draw_screen(root_widget, fullscreen_video, (not fullscreen_video) or video_frame_drawn)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 1955, in draw_screen
    renpy.config.screen_height,
  File "renpy/display/render.pyx", line 427, in renpy.display.render.render_screen (gen/renpy.display.render.c:6806)
    rv = render(root, width, height, 0, 0)
  File "renpy/display/render.pyx", line 196, in renpy.display.render.render (gen/renpy.display.render.c:2978)
    rv = d.render(widtho, heighto, st, at)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 693, in render
    surf = render(child, width, height, cst, cat)
  File "renpy/display/render.pyx", line 110, in renpy.display.render.render (gen/renpy.display.render.c:3440)
    cpdef render(d, object widtho, object heighto, double st, double at):
  File "renpy/display/render.pyx", line 196, in renpy.display.render.render (gen/renpy.display.render.c:2978)
    rv = d.render(widtho, heighto, st, at)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 693, in render
    surf = render(child, width, height, cst, cat)
  File "renpy/display/render.pyx", line 110, in renpy.display.render.render (gen/renpy.display.render.c:3440)
    cpdef render(d, object widtho, object heighto, double st, double at):
  File "renpy/display/render.pyx", line 196, in renpy.display.render.render (gen/renpy.display.render.c:2978)
    rv = d.render(widtho, heighto, st, at)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 693, in render
    surf = render(child, width, height, cst, cat)
  File "renpy/display/render.pyx", line 110, in renpy.display.render.render (gen/renpy.display.render.c:3440)
    cpdef render(d, object widtho, object heighto, double st, double at):
  File "renpy/display/render.pyx", line 196, in renpy.display.render.render (gen/renpy.display.render.c:2978)
    rv = d.render(widtho, heighto, st, at)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 623, in render
    child = renpy.display.render.render(self.child, w, h, st, at)
  File "renpy/display/render.pyx", line 110, in renpy.display.render.render (gen/renpy.display.render.c:3440)
    cpdef render(d, object widtho, object heighto, double st, double at):
  File "renpy/display/render.pyx", line 196, in renpy.display.render.render (gen/renpy.display.render.c:2978)
    rv = d.render(widtho, heighto, st, at)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 693, in render
    surf = render(child, width, height, cst, cat)
  File "renpy/display/render.pyx", line 110, in renpy.display.render.render (gen/renpy.display.render.c:3440)
    cpdef render(d, object widtho, object heighto, double st, double at):
  File "renpy/display/render.pyx", line 196, in renpy.display.render.render (gen/renpy.display.render.c:2978)
    rv = d.render(widtho, heighto, st, at)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 409, in render
    raise Exception("Grid overfull.")
Exception: Grid overfull.

Darwin-17.4.0-x86_64-i386-64bit
Ren'Py 6.99.12.4.2187

User avatar
Enchant00
Regular
Posts: 136
Joined: Tue Jan 12, 2016 1:17 am
Contact:

Re: Inventory System with click-to-use-item feature

#9 Post by Enchant00 »

The problem usually arises when you try to add children to a grid that doesn't have enough rows or column.

Change this line of code:

Code: Select all

for i in range(8 - len(inventory)):
            null
To this:

Code: Select all

 for key  in inventory:
            for i in range(8 - len(inventory[key])):
                null
- Your original code with the new inventory dictionary would add 7 nulls to populate the grid and in addition to your 3 gems would be 10 cells which is greater than your (4,2) 8 cell grid

ourdecemberdreams
Regular
Posts: 58
Joined: Sat Apr 15, 2017 3:26 pm
Projects: The Last December
Tumblr: ourdecemberdreams
Deviantart: ourdecemberdreams
itch: ourdecemberdreams
Contact:

Re: Inventory System with click-to-use-item feature

#10 Post by ourdecemberdreams »

Enchant00 wrote: Tue May 29, 2018 2:58 am The problem usually arises when you try to add children to a grid that doesn't have enough rows or column.

Change this line of code:

Code: Select all

for i in range(8 - len(inventory)):
            null
To this:

Code: Select all

 for key  in inventory:
            for i in range(8 - len(inventory[key])):
                null
- Your original code with the new inventory dictionary would add 7 nulls to populate the grid and in addition to your 3 gems would be 10 cells which is greater than your (4,2) 8 cell grid
Hey thank you so much! I've changed that line of code and it works now! Thanks for providing the correct code AND explaining why mine was wrong in simple terms, it helps a lot. But now I've got some new questions.

I've added this line of code to make it such that users can select an item to decide whether or not to use it, but when I select one object, all objects get highlighted and shows the "selected image" instead of the "idle" one, although the correct selected item title is shown. Not exactly sure what's wrong...

Code: Select all

action [Show("itemmenu", title=inventory[item][x]["title"]), SetVariable("use_item", inventory[item][x]["title"])]
I've also tried to add a remove item action, it sort of kinda worked in my previous code (though it was buggy), but now it gives me an error. Couldn't find another way to remove the item though, would be nice if you can point me to the right way.

Code: Select all

hotspot (982, 546, 115, 44) action inventory.remove(inventory[item][X])


Below is my full inventory screen code, in case it might help provide a better full picture :)

Code: Select all

init 1:
    default item = 0
    
    $ inventory = {
        "Gem": {
            'Blue':  {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
            'Red' :    {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"},
            'Green' :  {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"}
        }
    }
    $ use_item = []

screen description(desc):
    vbox:
        text desc
        xpos 660
        ypos 530

screen inventory:
    tag menu

    imagemap:
        ground "gui/inventory_background.png"
        hover "gui/inventory_background.png"
        selected_idle "gui/inventory_background.png"
        selected_hover "gui/inventory_background.png"
        alpha False
        
        hotspot (1170, 0, 110, 140) action [Return(), Hide("itemmenu")]
        hotspot (982, 546, 115, 44) action inventory.remove(inventory[item][X]) #######ERROR SAYS "AttributeError: 'RevertableDict' object has no attribute 'remove'"


    grid 4 2:
        spacing 16
        xpos 652
        ypos 230

        for item in inventory:
            for x in inventory[item]:
                imagebutton:
                    xsize 73
                    ysize 71
                    
                    idle inventory[item][x]["idle"]
                    selected_idle inventory[item][x]["selected"]
                    selected_hover inventory[item][x]["selected"]
                    hovered Show("description", desc=inventory[item][x]["description"])
                    unhovered Hide("description")
                    action [Show("itemmenu", title=inventory[item][x]["title"]), SetVariable("use_item", inventory[item][x]["title"])] #######THE SELECTION CODE

        for key in inventory:
            for i in range(8 - len(inventory[key])):
                null
            
screen itemmenu(title):
    vbox:
        text title
        xpos 660
        ypos 530

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Inventory System with click-to-use-item feature

#11 Post by kivik »

Oh dear, I really think you need to learn about how lists and dictionaries work with python, as well as what your code is actually doing, otherwise there will be a lot of back and forth.

Meanwhile I think you have to either go with Enchant00's suggestion or mine, because we're suggesting completely different things. I personally don't understand Enchant00's suggestion with the dual layered dict. It just doesn't make sense to me - your inventory isn't actually a collection of items (which is what I think you need), instead it's a collection of a collection. Do you need your 3 gems wrapped up inside a dictionary called gem? Will you have different item types that aren't gems later that needs to go inside other dictionaries inside your inventory?

It just seems awfully complicated, and strangest of which, you're not using a direct handle on your items and still using indices in a way that I don't understand.

If gem needs to be a property of your items, just add a "type" or "property" key to your actual items, so your inventory will just be a collection of items, instead of a collection of a collection of items. It either be a list or a dict of items. If you want to follow my suggestion (but you still need to read up on and understand how lists and dicts work):

dict version:

Code: Select all

default inventory = {
    'Blue Gem': {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
    'Red Gem': {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"},
    'Green Gem':  {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"},
    }
Then you'd only need a single for loop:

Code: Select all

for key, item in inventory.items():
    # key is the key to the item: Blue Gem, Red Gem, Green Gem
    # item is the item itself
    # item["title"] will be Water, Earth and Land
    # item["description"] will be A blue gem, A red gem, A green gem
    # etc
No need for two loops and then inventory[item][x]["title"] and all that crazy stuff. The minor problem of this implementation is that the items will never be arranged in any particular order, dictionaries aren't ordered.

If you want to use this, read how to add and remove stuff from a dict with python.


List version:

Code: Select all

default inventory = [
    {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
    {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Earth", "description":"A red gem"},
    {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"},
    ]
Still use a for loop, but no keys this time:

Code: Select all

for item in inventory:
    # same as before, but no keys this time
This will be kept in the order you add and remove stuff. You use python's list's way of appending and removing things from the list if you use this approach.


With either approach, you need to rewrite your screen codes properly, i.e. item["title"] instead of inventory[item][x]["title"]. The whole point of using a for loop through a collection is that you use the item handle, and not indices anymore. Also you need to change your null values being added to your grid back to how it was before.


Now onto your problems:

1 - AttributeError

Code: Select all

        hotspot (982, 546, 115, 44) action inventory.remove(inventory[item][X]) #######ERROR SAYS "AttributeError: 'RevertableDict' object has no attribute 'remove'"
First of all, this is outside of your for loop, so item and x don't exist here. (Also, you used capital X here and lower x in the for loop, this does matter in programming, you have to use the same cases). However, your code crashed before that got evaluated because of:

Second issue: You're using .remove() on a dict, which doesn't work. To remove stuff from a dict, you need to use a different approach (as mentioned earlier in my reply). I'm going to hold off from telling you here, because I personally don't think you should be using a dict anyway, but you can google "python remove element from dict" to find how to do it easily.

To overcome both issues, you should have a screen variable in your inventory screen:

Code: Select all

screen inventory:
    default current_item = ""
This variable can now be referenced WITHIN the screen - that means not outside, not in your label, not anywhere else but within the screen block.

The way you'd use it is, instead of SetVariable("use_item" etc.), you do:

If you use dict:

Code: Select all

SetScreenVariable("current_item", key)
If you use list:

Code: Select all

SetScreenVariable("current_item", item)
Then to remove the item from your inventory, you'd remove it according to the dict / list methods that you'll look up. You already know the list method:

Code: Select all

remove(current_item)
2 - wrong thing being selected

I'm not actually sure how you're showing what's selected with your current code, so I can't help you here. How do you know which item is being selected?

User avatar
Enchant00
Regular
Posts: 136
Joined: Tue Jan 12, 2016 1:17 am
Contact:

Re: Inventory System with click-to-use-item feature

#12 Post by Enchant00 »

Your inventory is a dictionary compared to your original code which was a list. You use the .remove when you want to delete something from a list but when you want to delete from a dictionary you would use the .pop instead.

Code: Select all

hotspot (982, 546, 115, 44) action inventory.pop(inventory[item][X])
Now, I'm looking at this code but I predict that there would be an error mainly on the part on (inventory[item][X]). I'm not sure with the nature of hotspots and if there is none then that's good but if my guess is right you would get a define error or something like dictionary doesn't exist. The reason is because your for loop which contain the (item and X) iterations are defined after your imagemaps, specifically under grid, and since code is read from top to bottom the (item and x) doesn't exist yet.

How to fix that would really depend on how you want the item to be removed. So here are my questions:
1. Does the player select on the item first and then click the hotspot to remove the item?
2. Does the hotspot remove a specific item even if the player hasn't selected it?
- If no.2 is the case, then follow up question is how do you want the hotspot to determine which would be removed?

Now for the part on multiple buttons being selected I think it has something to do with how RENPY determines which button is selected when selected is not explicitly defined by you. I wasn't really sure what was wrong but after some trial and error it seems that all you have to do is define selected yourself which conveniently enough is a property of the imagebutton

Code: Select all

 imagebutton:
                    xsize 73
                    ysize 71
                    
                    idle inventory[item][x]["idle"]
                    selected use_item == inventory[item][x]["title"] # just add this line of code
                    selected_idle inventory[item][x]["selected"]
                    selected_hover inventory[item][x]["selected"]
                    hovered Show("description", desc=inventory[item][x]["description"])
                    unhovered Hide("description")
                    action [Show("itemmenu", title=inventory[item][x]["title"]), SetVariable("use_item", inventory[item][x]["title"])]
- Basically, what that line of code means is that the button is only selected if the use_item variable is equal to the inventory item title.

User avatar
Enchant00
Regular
Posts: 136
Joined: Tue Jan 12, 2016 1:17 am
Contact:

Re: Inventory System with click-to-use-item feature

#13 Post by Enchant00 »

kivik wrote: Tue May 29, 2018 11:45 am Oh dear, I really think you need to learn about how lists and dictionaries work with python, as well as what your code is actually doing, otherwise there will be a lot of back and forth.

Meanwhile I think you have to either go with Enchant00's suggestion or mine, because we're suggesting completely different things. I personally don't understand Enchant00's suggestion with the dual layered dict. It just doesn't make sense to me - your inventory isn't actually a collection of items (which is what I think you need), instead it's a collection of a collection. Do you need your 3 gems wrapped up inside a dictionary called gem? Will you have different item types that aren't gems later that needs to go inside other dictionaries inside your inventory?
Actually, to be completely honest kivik's way is a lot more simpler than mine :lol: The reason for my double dictionary construction is just preference on my part and to me it's just to organize my code. If you use kivik's list method, then you could simply just use list indice to navigate your items then acess the dictionary key directly. If you plan to use a single dictionary then you only need the key to acess the value. Reagardles both would only need a single loop.

My line of thinking is that when you have like 100+ items or so and all you have to go by is the list indice then you might get confused and it's a pain. If you use a single dictionary, then as long as you know the key you would be fine. The problem with both for me is that if you have lines and lines of item definitions it would take awhile to find the item you want.

So you could say my code is like grouping similar thing together so in the future if I need to look for something specific I could quickly access it.

Hence;
My dictionary

Code: Select all

Inventory::

    Gem::
        Blue Gem:
        Red Gem:       
        Yello Gem:
    
    Item2::
        Items under cetegory Item 2...
List or Single Dictionary

Code: Select all

Inventory::

    Blue Gem:
    Red Gem:       
    Yellow Gem:
    Item2
    Item3
    Item 4
List or Single Dictionary Organized Alternative

Code: Select all

Inventory::

    Blue Gem:
    Red Gem:       
    Yellow Gem:

    Pink Gem
    Green Gem

or

    [b][[/b]Item2
    Item3
    Item 4[b]][/b]

     [b][[/b]Item4
    Item5
    Item 6[b]][/b]
- In the end it's just a matter of preference. Although, my dictionary style organizes my code in a way I understand, it makes it more difficult to loop through it and apply things to the dictionary's elements. If you use kivik's method, loops and the coding process is much easier but you may have a long lists of item definitions. You can even organize the code better when using the list or single dictionary method by grouping liken items inside into a list or by simply spacing out items that are similar.

- If you still face problems, I'll try to simplify my code structure using kiviks suggestion that way life would be better for you.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Inventory System with click-to-use-item feature

#14 Post by kivik »

Ah Enchant00, I wondered if it was part of the requirements that I missed since there was a lot of code / text to read through!

I think it'd be better to separate categorisation, by either add a "category" key to the items, or have a separate dict that references the keys, e.g.:

Code: Select all

Inventory:
    Blue Gem:
        category: gem
    Red Gem:
        category: gem
etc.
Or ditch the category inside item and have:

Code: Select all

Inventory:
    Blue Gem:
    Red Gem:
etc.

Categories:
    gems:
        Blue Gem
        Red Gem
etc.
That way you can still reference it by keys and keep it simple with single for loops, and be able to grab the items by categories depending on which implementation used.

Ultimately all these would be a lot easier using classes and objects to manage!

ourdecemberdreams
Regular
Posts: 58
Joined: Sat Apr 15, 2017 3:26 pm
Projects: The Last December
Tumblr: ourdecemberdreams
Deviantart: ourdecemberdreams
itch: ourdecemberdreams
Contact:

Re: Inventory System with click-to-use-item feature

#15 Post by ourdecemberdreams »

Okays, so I've read through both your advices and this is what I have came to put together hahahah:

Code: Select all

init 1:
    default item = 0
    default use_item = 0
    
    default inventory = {
    'Blue Gem': {"idle":"images/inventory/gem_blue.png", "selected":"images/inventory/gem_blue_selected.png", "title":"Water", "description":"A blue gem"},
    'Red Gem': {"idle":"images/inventory/gem_red.png", "selected":"images/inventory/gem_red_selected.png", "title":"Fire", "description":"A red gem"},
    'Green Gem': {"idle":"images/inventory/gem_green.png", "selected":"images/inventory/gem_green_selected.png", "title":"Land", "description":"A green gem"},
    }

    $ use_item = []
    $ hp_integer = 100
    $ ma_integer = 100
    $ hp = "%d" % hp_integer
    $ ma = "%d" % ma_integer
    
    
init python:
    def use_item():
        if use_item["hp"]: #healing item
            hp_integer = hp_integer+use_item["hp"]
            if hp_integer > 100: # can't heal beyond max HP
                hp_integer = 100
            #inventory.drop(self) # consumable item - drop after use
        elif use_item["ma"]: #mp restore item
            ma_integer = ma_integer+use_item["ma"]
            if ma_integer > 100: # can't increase MP beyond max MP
                ma_integer = 100
            #inventory.drop(self) # consumable item - drop after use
        else:
            null

screen description(desc):
    vbox:
        text desc
        xpos 660
        ypos 530

screen inventory:
    tag menu

    imagemap:
        ground "gui/inventory_background.png"
        hover "gui/inventory_hover_background.png"
        selected_idle "gui/inventory_background.png"
        selected_hover "gui/inventory_hover_background.png"
        alpha False
        
        hotspot (1170, 0, 110, 140) action [Return(), Hide("itemmenu")]
        #hotspot (982, 546, 115, 44) action Function(use_item)
        #hotspot (982, 586, 115, 44) action inventory.pop(use_item)
        
    vbox:
        text hp
        xpos 660
        ypos 560
        
    vbox:
        text ma
        xpos 660
        ypos 590
        
    grid 4 2:
        spacing 16
        xpos 652
        ypos 230

        for key, item in inventory.items():
            imagebutton:
                xsize 73
                ysize 71
                
                idle item["idle"]
                selected use_item == item
                selected_idle item["selected"]
                selected_hover item["selected"]
                hovered Show("description", desc=item["description"])
                unhovered Hide("description")
                action [Show("itemmenu", title=item["title"]), SetVariable("use_item", key)]

        for i in range(8 - len(inventory)):
            null
        
screen itemmenu(title):
    vbox:
        text title
        xpos 660
        ypos 530
I would have been open to read through and better understand how lists and dictionaries work with python, but I'm kinda in a rush to get this out by a deadline I have. So I'll cut to the point of my questions:

1- currently the above code works just fine (no crashes), but the items' selected images are gone, it's still hoverable and clickable but it just displays the idle image, my guess is...

Code: Select all

selected use_item == item
is somehow overwriting

Code: Select all

selected_hover item["selected"]
and

Code: Select all

selected_idle item["selected"]
? I've tried placing the first line of code above and below the other 2, doesn't seem to make a difference.


---


2- what I would need to happen for the below code is have the user select an object, then if the "remove" button is pressed, the object will be removed from the inventory.

Code: Select all

#hotspot (982, 586, 115, 44) action inventory.pop(use_item)
but right now, if I use this code, the following error will appear:

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/screens.rpy", line 219, in execute
    screen inventory:
  File "game/screens.rpy", line 219, in execute
    screen inventory:
  File "game/screens.rpy", line 222, in execute
    imagemap:
  File "game/screens.rpy", line 231, in execute
    hotspot (982, 586, 115, 44) action inventory.pop(use_item)
  File "game/screens.rpy", line 231, in keywords
    hotspot (982, 586, 115, 44) action inventory.pop(use_item)
KeyError: 0

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ast.py", line 814, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/python.py", line 1719, in py_exec_bytecode
    exec bytecode in globals, locals
  File "renpy/common/_layout/screen_main_menu.rpym", line 30, in <module>
    ui.interact()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ui.py", line 285, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2526, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2793, in interact_core
    root_widget.visit_all(lambda i : i.per_interact())
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 495, in visit_all
    d.visit_all(callback)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 495, in visit_all
    d.visit_all(callback)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 495, in visit_all
    d.visit_all(callback)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 399, in visit_all
    callback(self)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2793, in <lambda>
    root_widget.visit_all(lambda i : i.per_interact())
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 409, in per_interact
    self.update()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 578, in update
    self.screen.function(**self.scope)
  File "game/screens.rpy", line 219, in execute
    screen inventory:
  File "game/screens.rpy", line 219, in execute
    screen inventory:
  File "game/screens.rpy", line 222, in execute
    imagemap:
  File "game/screens.rpy", line 231, in execute
    hotspot (982, 586, 115, 44) action inventory.pop(use_item)
  File "game/screens.rpy", line 231, in keywords
    hotspot (982, 586, 115, 44) action inventory.pop(use_item)
  File "<screen language>", line 231, in <module>
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/python.py", line 618, in do_mutation
    return method(self, *args, **kwargs)
KeyError: 0

Darwin-17.4.0-x86_64-i386-64bit
Ren'Py 6.99.12.4.2187

---


3- the below code should allow the user to "use" and item when the hotspot is pressed after selecting an item.

Code: Select all

#hotspot (982, 546, 115, 44) action Function(use_item)
so if the item is used, the code will check for the action required to be taken, say -50ma or +50hp.

Code: Select all

    def use_item():
        if use_item["hp"]:
            hp_integer = hp_integer+use_item["hp"]
            if hp_integer > 100:
                hp_integer = 100
        elif use_item["ma"]:
            ma_integer = ma_integer+use_item["ma"]
            if ma_integer > 100:
                ma_integer = 100
        else:
            null
but currently, if pressed, this error will appear:

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "renpy/common/00action_other.rpy", line 484, in __call__
    rv = self.callable(*self.args, **self.kwargs)
TypeError: 'unicode' object is not callable

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ast.py", line 814, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/python.py", line 1719, in py_exec_bytecode
    exec bytecode in globals, locals
  File "renpy/common/_layout/screen_main_menu.rpym", line 30, in <module>
    ui.interact()
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/ui.py", line 285, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 2526, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, **kwargs)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/core.py", line 3204, in interact_core
    rv = root_widget.event(ev, x, y, 0)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 960, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 960, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 960, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/screen.py", line 651, in event
    rv = self.child.event(ev, x, y, st)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 960, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 960, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/layout.py", line 960, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/behavior.py", line 889, in event
    return handle_click(self.clicked)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/behavior.py", line 824, in handle_click
    rv = run(action)
  File "/Volumes/OTHERS/VN/RenPy/renpy-6.99.11-sdk/renpy/display/behavior.py", line 306, in run
    return action(*args, **kwargs)
  File "renpy/common/00action_other.rpy", line 484, in __call__
    rv = self.callable(*self.args, **self.kwargs)
TypeError: 'unicode' object is not callable

Darwin-17.4.0-x86_64-i386-64bit
Ren'Py 6.99.12.4.2187

Post Reply

Who is online

Users browsing this forum: No registered users