class Fonction synthax in imagebutton action

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.
Post Reply
Message
Author
sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

class Fonction synthax in imagebutton action

#1 Post by sculpteur »

Hello,

I got an error because i think i write the wrong synthax in this line :

Code: Select all

 action [Play ("sound", "0 - sound_giveitem.mp3"), Function(Container.drop, item=item)]
It's in this code :

Code: Select all

screen container_trash:
    # modal True
    for item in container_trash.items:
        imagebutton:
            xpos 900 ypos 540
            idle "GUI_inv_container_button_drop_simple"
            hover "GUI_inv_container_button_drop_hovered"
            action [Play ("sound", "0 - sound_giveitem.mp3"), Function(Container.drop, item=item)]
And there is the code this line is refering too :

Code: Select all

    class Container(store.object):
        def __init__(self, allowed=[], allow_all=False, spaces = 4):
            self.items = []
            self.allowed = allowed
            self.allow_all = allow_all
            self.spaces = spaces

        def add(self, item):
            if self.allow_all or item in self.allowed:
                self.items.append(item)
                return True
            else:
                return False

        def drop(self, item):
            self.items.remove(item)
            return True

        def has_space(self):
            return len(self.items) < self.spaces

    class Item(store.object):
        def __init__(self, name, image="", droppable=True):
            self.name=name
            self.image=image
            self.droppable = droppable


So if someone know what are the two arguments i suppose to put in fonction in the first line : Function(Container.drop, item=item) it will be great !
Thanks guys
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: class Fonction synthax in imagebutton action

#2 Post by Remix »

In method drop() item is just an indexed parameter rather than a keyword... try:

def drop(self, item=None):

or address it as the first indexed argument in the call, Function(Container.drop, item)

Sub-note: Consider viewtopic.php?f=51&t=47911#p497160 as an idea if you are mixing your own flavour of inventory
Frameworks & Scriptlets:

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: class Fonction synthax in imagebutton action

#3 Post by sculpteur »

Hey, thank you for your answer.

I'am not sure too understand all of it but I still tried different combination with what you said and I can't manage to avoid the error.

And I am not even sure to understand the error message.

It tell me this strange thing :
File "renpy/common/00action_other.rpy", line 506, in __call__
rv = self.callable(*self.args, **self.kwargs)
TypeError: unbound method drop() must be called with Container instance as first argument (got Item instance instead)

Or this :
TypeError: unbound method drop() must be called with Container instance as first argument (got nothing instead)
So if you could explain me a little better what the synthax should look like or even give me a link to a good python tutorial who dea about function, it will be great.
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: class Fonction synthax in imagebutton action

#4 Post by sculpteur »

Any idea ?
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
Rastagong
Regular
Posts: 35
Joined: Sat Dec 02, 2017 3:28 pm
Completed: Sylvan Disappearance, Upon a Darkening Flood
Tumblr: rastagong-tearoom
itch: rastagong
Contact:

Re: class Fonction synthax in imagebutton action

#5 Post by Rastagong »

Yup, I believe the problem is that you call Container.drop!

Container with an uppercase C refers to the Container class, which is the template/blueprint from which you can create actual containers.
So when you call Container.drop, you're not referring to any specific container, and the drop method can't work: drop is designed to work at the level of a a real container instance, not at the level of the Container class.

I assume you've already created a specific container named container_trash somewhere in your code, right?
And the screen is supposed to drop items from this specific container, correct?
Therefore, you should call container_trash.drop: this correctly refers to the drop method of the specific container named container_trash.
Read Sylvan Disappearance, a folk horror epistolary mystery visual novel!

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: class Fonction synthax in imagebutton action

#6 Post by sculpteur »

Waw!

Yes it was this.
I'am so dumb!
With your explication everything make sens now!

Thank you really much !
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: class Fonction synthax in imagebutton action

#7 Post by sculpteur »

By the way, just a little extra, probably really simple for you.

Do you have any idea how to change this line :

Code: Select all

    for item in container_trash.items:

To have a condition instead ?

I'am looking for something like :
Either this :

Code: Select all

   if item in container_trash.items:

Code: Select all

   if item in container_trash.items > 0 :
Meaning, if there is at least, one item in the container.

Or this

Code: Select all

   if item in container_trash.items is droppable :
To be able to check the droppable condition.



But this is not working. Probably because of the way i am writing "item" I think.

This is the rest of the code this is coming from :

Code: Select all

init python:

    items = {
        "Tools": Item("Tools", image="gui/item_icon_tools.png"),
        "Ducktape": Item("Ducktape", image="gui/item_icon_ducktape.png"),
        "Teddybear": Item("Teddybear", image="gui/item_icon_teddybear.png"),
        "Towel": Item("Towel", image="gui/item_icon_towel.png"),
        "Soap": Item("Soap", image="gui/item_icon_soap.png"),
        "Sponge": Item("Sponge", image="gui/item_icon_sponge.png"),
        "Bassin": Item("Bassin", image="gui/item_icon_bassin.png"),
        "Manche": Item("Manche", image="gui/item_icon_manche.png"),
        "ClothesTop": Item("ClothesTop", image="gui/item_icon_clothes_top1.png"),
        "ClothesJean": Item("ClothesJean", image="gui/item_icon_clothes_jean1.png"),
        "Shampoo": Item("Shampoo", image="gui/item_icon_shampoo.png"),
        "Hairbleach": Item("Hairbleach", image="gui/item_icon_hairbleach.png"),
        "FoodFruit": Item("FoodFruit", image="gui/item_icon_foodfruit.png"),
        "FoodCan": Item("FoodCan", image="gui/item_icon_foodcan.png"),
        }

    inventory = Inventory()
    container = Container()
    container1 = Container([items["Ducktape"], items["Tools"]])
    container2 = Container([items["Teddybear"]])
    container3 = Container([items["Towel"], items["Sponge"], items["Bassin"], items["Soap"]])
    container4 = Container([items["Manche"]])
    container5 = Container([items["Manche"]])
    container_food = Container([items["FoodFruit"], items["FoodCan"]])
    container_found = Container("Container", allow_all=True)
    container_trash = Container("Container", allow_all=True)

    inventory.spaces = 4
    container_found.spaces = 13
    container_trash.spaces = 1

    items["Bassin"].droppable = False

    inv_button_sensitive = False
    inv_button_show = False
    inventory_show = False
    show_inventory = False
    show_inventory_addon = False
    desactivate_inventory_addon = False

Code: Select all

screen container_trash:
    # modal True
    for item in container_trash.items:
        imagebutton:
            xpos 900 ypos 540
            idle "GUI_inv_container_button_drop_simple"
            hover "GUI_inv_container_button_drop_hovered"
            action [Play ("sound", "0 - sound_giveitem.mp3"), Function(container_trash.drop, item=item)]

Code: Select all

    class Item(store.object):
        def __init__(self, name, image="", droppable=True):
            self.name=name
            self.image=image
            self.droppable = droppable
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
Rastagong
Regular
Posts: 35
Joined: Sat Dec 02, 2017 3:28 pm
Completed: Sylvan Disappearance, Upon a Darkening Flood
Tumblr: rastagong-tearoom
itch: rastagong
Contact:

Re: class Fonction synthax in imagebutton action

#8 Post by Rastagong »

Don't worry, it's not much!

So you'd like to check if there is at least one item in the container_trash, and if at least one item is droppable?

That's not too complicated!
That said, for the record, if container_trash contains 0 items (that is, if container_trash.items is an empty list), then the for item in container_trash.items loop will itself be empty: if there are no items in container_trash.items, then the loop will do nothing anyway.
In other words, no imagebutton will be displayed on the screen if there are no items to display in the first place.
Therefore, your condition is in part naturally fulfilled by the loop: it's just lacking the verification that at least one item is droppable.
To display only droppable items, you would have a few possibilities:


1) With the showif statement
The easiest way is to use the showif statement inside the loop, to check if each item is droppable.
The showif statement simply takes a condition to verify. It would be used this way:

Code: Select all

screen container_trash:
    for item in container_trash.items:
        showif item.droppable: #If the item is droppable, display the imagebutton
            imagebutton:
                # …


2)With a list comprehension
Alternatively, you could use a list comprehension to enforce the droppable condition on the list over which the loop iterates.
Instead of having the loop iterate over all items and check if each item is droppable, we would have the loop iterate only over the droppable items from the very beginning.

The list comprehension to use would be: [item for item in container_trash.items if item.droppable]
This is basically a new list, but which contains only droppable items.
Then instead of having the loop iterate over container_trash.items (all items), we would have the loop iterate over this list comprehension:

Code: Select all

screen container_trash:
    for item in [item for item in container_trash.items if item.droppable]:
        imagebutton:
            # …
In this way, we do not use showif at all: all the items in the loop are already droppable, they are filtered by the list comprehension.



3)Avoiding the loop if there isn't at least 1 droppable item
One last possibility is to avoid the loop entirely is there isn't at least 1 droppable item.
We would do so with a list comprehension again, but by storing it in a variable.

First, we use the default statement to define a screen variable: that variable must contain only droppable items.
The list comprehension we have already used allows us to do just that: [item for item in container_trash.items if item.droppable] is a list which contains only droppable items.
If there are no droppable items, or no items at all, that list will be empty.
Let's store it in a screen variable called onlyDroppableItems:

Code: Select all

screen container_trash:
    default onlyDroppableItems = [item for item in container_trash.items if item.droppable]
    
Since onlyDroppableItems contains only droppable items, we can use it as a condition to display the loop only if the list is not empty.
At the same time, we can have the loop iterate over this same list!

Code: Select all

screen container_trash:
    default onlyDroppableItems = [item for item in container_trash.items if item.droppable]
    if onlyDroppableItems: #If it's not empty, then there's at least one droppable item
        for item in onlyDroppableItems:
            imagebutton:
                # …


The index clause
One last thing! Whichever solution you end up using, consider adding an index clause to the for loop!
This is not a thing you normally see in Python code, it's exclusive to Ren'Py (and you need to have Ren'Py version 7.0 or higher to use it).

Basically, the index clause takes an expression that should be unique to each item found in the list. It can be useful to prevent weird side effects if you have animations or changes in the screen (I think you might need it since items can be dropped, but I'm not fully certain).

There are more details in the Ren'Py documentation on the for statement:
If given, the index clause should consist of an expression that returns a hashable and comparable value that is unique for each row in the list. Ren'Py uses this value to make sure that transforms and other state wind up associated with the correct iteration. If you're seeing weird behavior when elements are added to or removed from a list you're iterating over, you might want to use an index clause.
In your case, the name of the item (item.name) is clearly the value to use in the index clause.

It would be used like this: for item index item.name in onlyDroppableItems
Of course, you would need to adapt the part with the iterable (onlyDroppableItems) depending on which of 3 the solutions you chose to use!

If that last thing sounds too weird, don't worry about it.
But if you notice weird side effects in your screen someday (for instance an item turning into another item after dropping one), then consider adding this index clause, it might fix your problem!
Read Sylvan Disappearance, a folk horror epistolary mystery visual novel!

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: class Fonction synthax in imagebutton action

#9 Post by sculpteur »

Wow, that's amazing.

I've never seen a message like this : your answer is so comprehensive, understandable and pedagogic !

You have not only solved my problems but you also have advanced my knowledge without any difficulty of comprehension.

Thank you so much for your time !
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

Post Reply

Who is online

Users browsing this forum: No registered users