help with inventory label[SOLVED]

exer059

New Member
Jul 16, 2017
9
1
Hi, i just wanted to make a simple inventory label and screen with a simple grid, I tried to reproduce some part from lemmasoft.renai.us examples but for some reason it takes me a lot of tries and it did not work.
If anyone could help me with this little project I would be very grateful.

Thanks in advance cheers"!

Python:
init python:

    # class
    class item():
        def __init__(self, name,  imag="", cost=0):
            self.name = name
            self.imag = imag
            self.cost = cost

    class Inventory():
        def __init__(self, money=10):
            self.money = money
            self.items = []
        def add(self, item):
            self.items.append(item)
        def drop(self, item):
            self.items.remove(item)
        def buy(self, item):
            if self.money >= item.cost:
                self.items.append(item)
                self.money -= item.cost
# screen
screen Invty:
    add "fondos/Invt.png"
    modal True
    hbox :
        grid 5 4:
            for item in Inventory:
                imagebutton auto "icons/Moc_ico_%s.png" action [Hide("Invty"), Return(None)]

# label
label Inventario:

    $ inventory = Inventory()
    python:
        obj1 = item("objeto1", imagen="icon/obj/icoTest.png", cost=0)
    call screen Invty
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,584
2,229
I'm going to guess here, because I only see 1 obvious error.
(You've typo'd imag as imagen in a couple of places).

Firstly, class and screen only create frameworks to be used later.

My guess is that your label Inventario: appears exactly as you've written it above. Somewhere at the top of your script and before label start:. Unless you have a jump Inventario as part of your active game code, it will never be executed.
I'm guessing the original author of the inventory code intended it more as a "this code goes in the main game script" rather than a literal label called "Inventario".

Similarly, $ inventory = Inventory() is something I'd normally only expect to be executed once. It is effectively create a variable inventory based upon class Inventory(). The line after it appears to be creating a new item, for the game to use later - I'd expect a lot of these "items" beyond just this one.

Then whilst I'd expect both the inventory setup and loading the items to only take place once - the call screen Invty() is something I'd expect to happen a lot more often, and definitely as part of the main code after label start:.

Before I reply what I think the answer might be... just a bit of background about variable creation.

define creates a variable that is not saved as part of the save game files. Their values are not expected to change while the game is running and the RenPy author has strongly suggested bad things can and will happen if you ignore this advice.

default creates a variable that is saved as part of the save game files. Loading a save file, will overwrite any values currently stored by the game with the values that are part of the save file.

define is therefore used for static variables and default is used for player variables.

Some older code (before default was added to RenPy) used to initialize variables during the init: processes. 99% of the time, it's just old code that has been copy/pasted by developers who didn't know any better.

In the case of your inventory and items, I would expect "items" to be static variables and "Inventory" to be a player controlled variable.
The only exception I can imagine, would be if you wanted to alter the cost of items while the game is running. It would create headaches, because it would require the item list to be saved too - and therefore loading old save files might effectively remove items from the game.

So based on that background... I think what you want is:

Python:
init python:

    # class
    class item():
        def __init__(self, name,  imag="", cost=0):
            self.name = name
            self.imag = imag
            self.cost = cost

    class Inventory():
        def __init__(self, money=10):
            self.money = money
            self.items = []
        def add(self, item):
            self.items.append(item)
        def drop(self, item):
            self.items.remove(item)
        def buy(self, item):
            if self.money >= item.cost:
                self.items.append(item)
                self.money -= item.cost

# screen
screen Invty:
    add "fondos/Invt.png"
    modal True
    hbox :
        grid 5 4:
            for item in Inventory:
                imagebutton auto "icons/Moc_ico_%s.png" action [Hide("Invty"), Return(None)]

default inventory = Inventory()

define obj1 = item("objeto1", imag="icon/obj/icoTest.png", cost=0)

define obj2 = item("objeto2", "icon/obj/icoTest.png", 0)  # technically you don't need the names,
                                                          # since the parameters are already in the correct order.
define obj3 = item("objeto3", "icon/obj/icoTest.png", 0)
define obj4 = item("objeto4", "icon/obj/icoTest.png", 0)
#etc

label start:

    scene black with fade
    "*** START ***"

    call screen Invty # just for testing purposes until it's used for "real" later. (Should currently be empty)

    $ inventory.add (obj1)
    $ inventory.add (obj2)

    call screen Invty # more testing... shows 2 items now.

    # the rest of the game...

I've not tested this code, and it's only a guess on my part that you've not got a jump Inventario anywhere.

As a side note, it's usual to only use Capitialization for class names and lowercase almost everywhere else. I've not changed anything here, because (a) it will still work and (b) I didn't want to introduce any new typos. But if you're still at the very early stages, it might be a bad habit you can break now rather than causing problems later. That's the screen names, labels, even image filenames.
 
Last edited:
  • Like
Reactions: exer059

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,298
[...] but for some reason it takes me a lot of tries and it did not work.
There's a "s" missing at "reason", and some of them are explained relatively explicitly by the error message.

  • Error 1:
    traceback said:
    File "game/script.rpy", line 447, in <module>
    obj1 = item("objeto1", imagen="icon/obj/icoTest.png", cost=0)
    TypeError: __init__() got an unexpected keyword argument 'imagen'
    This one is explicit. It tell you exactly where the error is (well, obviously not on line 447, its on my test file), and what is the error.
    Therefore, change:
    Code:
    obj1 = item("objeto1", imagen="icon/obj/icoTest.png", cost=0)
    into :
    Code:
    obj1 = item("objeto1", imag="icon/obj/icoTest.png", cost=0)
    Problem solved.

  • Error 2:
    traceback said:
    File "game/script.rpy", line 438, in execute
    grid 5 4:
    TypeError: 'type' object is not iterable
    This one is need more knowledge, because the error isn't on the line pointed, and the error message is obscure for who don't know Python ; you asked to iterate through a element that isn't iterable.
    It happen that you've a for loop (therefore an iteration) right after the line pointed by Ren'py. The error is here :
    Code:
    for item in Inventory:
    Inventory is your object (Note: I know, I'll come to it) you should have asked to iterate through the embedded list:
    Code:
    for item in Inventory.items:

  • Error 3:
    traceback said:
    File "game/script.rpy", line 439, in <module>
    for item in Inventory.items:
    AttributeError: type object 'Inventory' has no attribute 'items'
    This time you are perplex ; "but, I iterate through the list, and the list exist".
    No, the list do not exist, because you are using the class Inventory for you iteration, while your object is :
    Code:
    $ inventory = Inventory()
    wrote with a lowercase "i".
    Therefore, change again the line in the screen :
    Code:
    for item in inventory.items:

  • Error 4:
    traceback said:
    File "renpy/common/000statements.rpy", line 570, in execute_call_screen
    store._return = renpy.call_screen(name, *args, **kwargs)
    Exception: Grid not completely full.
    The documentation say it: "This must be given (columns * rows) children. Giving it a different number of children is an error."
    The grid is expecting 5x4 (20) entries, you are giving it only one. I'm pretty sure that there were more in the initial code, removing it wasn't at all a good idea.
    You need to put it back, or at least put back something that looks like what you removed :
    Code:
    grid 5 4:
    for item in inventory.items:
    imagebutton auto "icons/Moc_ico_%s.png" action [Hide("Invty"), Return(None)]
    for i in range( len( inventory.items ), 20 ):
    null

  • Error 5:
    Starting here there's no error thrown by Ren'py, because the screen is correct. Yet, yes, there's nothing shown on the screen. But there's a pretty good reason for that, the inventory is empty. A little change in the screen show it :
    Code:
    grid 5 4:
    for item in inventory.items:
    imagebutton auto "icons/Moc_ico_%s.png" action [Hide("Invty"), Return(None)]
    for i in range( len( inventory.items ), 20 ):
    add "icons/empty.png"
    Why is it empty ? Captain Obvious would say that it's because you put no object inside it, and he would be right :
    Code:
    obj1 = item("objeto1", imag="icon/obj/icoTest.png", cost=0)
    You just created an object, but never put it into the inventory. Do it:
    Code:
    obj1 = item("objeto1", imag="icon/obj/icoTest.png", cost=0)
    inventory.add( obj1 )

  • Error 6:
    This one is visual, the icons you get do not correspond to the object ; and if you've more than one object, they'll all looks the same.
    It's because you don't use the image defined for the object, but the same image for every single object:
    Code:
    imagebutton auto "icons/Moc_ico_%s.png" action [Hide("Invty"), Return(None)]
    You should use the image defined for the object:
    Code:
    imagebutton auto item.imag action [Hide("Invty"), Return(None)]

  • Error 7:
    We missed you, traceback
    traceback said:
    File "renpy/common/00defaults.rpy", line 139, in _imagemap_auto_function
    rv = auto_param % variant
    TypeError: not all arguments converted during string formatting
    This one need to know Ren'py to be understood. The image is defined as pure icon, while Ren'py expect an name :
    "This should be a string that contains %s in it. If it is, and one of the image properties is omitted, %s is replaced with the name of that property, and the value is used as the default for that property."

    I'll follow the easiest way, using a standard idle image. Replace:
    Code:
    imagebutton auto item.imag action [Hide("Invty"), Return(None)]
    by:
    Code:
    imagebutton idle item.imag action [Hide("Invty"), Return(None)]

  • Error 8:
    This one, I only assume that you have it, but I can be wrong.
    traceback said:
    File "renpy/common/000statements.rpy", line 570, in execute_call_screen
    store._return = renpy.call_screen(name, *args, **kwargs)
    IOError: Couldn't find file 'icon/obj/icoTest.png'.
    In your object, you used "icon" for the directory name, while in the original code, the imagebutton took its image from the "icons" directory.
    Therefore the last correction is to change:
    Code:
    obj1 = item("objeto1", imag="icon/obj/icoTest.png", cost=0)
    into:
    Code:
    obj1 = item("objeto1", imag="icons/obj/icoTest.png", cost=0)
Congratulation, now your code looks like this:
You don't have permission to view the spoiler content. Log in or register now.
and it works.



All this being said, there were two kinds of errors in your code.

The errors 2 and 4 were due to the fact that you changed the original code without knowing what you were doing. Never do that. Either you know, at least more or less, what you are doing, or you change nothing.

As for the 6 other errors, they were all due to a lack of attention. You are writing code, it's something really strict that ask a constant attention to the smallest detail ; like by example an uppercase where you should have used a lowercase.
Yet, be happy, Python don't ask you to end all your lines with ";".



Side note for those who know: And now, I'll go take some sleep
 

exer059

New Member
Jul 16, 2017
9
1
OMG, yes, thank you, thank you very much!!.
I created a jump before but since it didn't work the first 10 times I just deleted.

I was just trying, but I got really mad because it didn't work. So I startedto deleted several parts of the original code.

I really apreciated your help