Enabling Textbuttons to Add Duplicate Items to the Inventory

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
User avatar
screamingpenguin
Regular
Posts: 32
Joined: Mon Dec 11, 2017 5:11 am
Projects: Hollow Voices
Contact:

Enabling Textbuttons to Add Duplicate Items to the Inventory

#1 Post by screamingpenguin »

So, to summarise, I am in the process of setting up a shop screen in my game, but I've come across a problem that I am stuck on.

If a certain item is already in the inventory, the button will disable itself.
Eg. if I have an apple in the inventory, the button to purchase an apple will disable itself because I already have an apple.

I've scoured the documentation looking for something that will work around this, but I've found nothing. Any help would be appreciated!
This is my code:

Code: Select all

init python:
    class Item(renpy.store.object):
        def __init__(self, name, image, price=0.0):
            self.name = name
            self.image = image
            self.price = price

default shop_inventory = [apple,orange,pear]
default inventory = []
default money = 15

label start:
    define apple = Item("Apple","items/apple.png",5)
    define orange = Item("Orange","item/orange.png",5)
    define pear = Item("Pear","item/pear.png",5)
    call screen shop
    return

screen shop:
    modal True
    frame:
        xsize 400 ysize 400 ypadding 10 xpadding 10 xalign .5 yalign .5
        vbox:
            for i in shop_inventory:
                if money >= i.price:
                    textbutton i.name action [AddToSet("inventory",i),SetVariable("money",money-i.price)]
                else:
                    textbutton i.name action NullAction()

User avatar
hell_oh_world
Miko-Class Veteran
Posts: 777
Joined: Fri Jul 12, 2019 5:21 am
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#2 Post by hell_oh_world »

screamingpenguin wrote: Thu Aug 29, 2019 8:53 pm So, to summarise, I am in the process of setting up a shop screen in my game, but I've come across a problem that I am stuck on.

If a certain item is already in the inventory, the button will disable itself.
Eg. if I have an apple in the inventory, the button to purchase an apple will disable itself because I already have an apple.

I've scoured the documentation looking for something that will work around this, but I've found nothing. Any help would be appreciated!
This is my code:

Code: Select all

init python:
    class Item(renpy.store.object):
        def __init__(self, name, image, price=0.0):
            self.name = name
            self.image = image
            self.price = price

default shop_inventory = [apple,orange,pear]
default inventory = []
default money = 15

label start:
    define apple = Item("Apple","items/apple.png",5)
    define orange = Item("Orange","item/orange.png",5)
    define pear = Item("Pear","item/pear.png",5)
    call screen shop
    return

screen shop:
    modal True
    frame:
        xsize 400 ysize 400 ypadding 10 xpadding 10 xalign .5 yalign .5
        vbox:
            for i in shop_inventory:
                if money >= i.price:
                    textbutton i.name action [AddToSet("inventory",i),SetVariable("money",money-i.price)]
                else:
                    textbutton i.name action NullAction()
Just another condition will do maybe:

Code: Select all

if money >= i.price and (i not in inventory): ## Added another condition
        textbutton i.name action [AddToSet("inventory",i),SetVariable("money",money-i.price)]
 else:
        textbutton i.name action NullAction()

User avatar
screamingpenguin
Regular
Posts: 32
Joined: Mon Dec 11, 2017 5:11 am
Projects: Hollow Voices
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#3 Post by screamingpenguin »

Sorry! I don't think I was clear enough about my issue haha.
I want to be able to add multiple of the same item into the inventory, but the issue is that if a certain item is already in it, it won't allow me to add another.
So if I already have an apple in my inventory and I want to buy another apple, it won't allow me to do so because the button automatically disables itself because it knows there's an apple in there already? If that makes sense? I need a way to be able to add as many apples to the inventory as I want without the textbutton disabling itself. Sorry for not being clear haha.

User avatar
hell_oh_world
Miko-Class Veteran
Posts: 777
Joined: Fri Jul 12, 2019 5:21 am
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#4 Post by hell_oh_world »

screamingpenguin wrote: Fri Aug 30, 2019 12:10 am Sorry! I don't think I was clear enough about my issue haha.
I want to be able to add multiple of the same item into the inventory, but the issue is that if a certain item is already in it, it won't allow me to add another.
So if I already have an apple in my inventory and I want to buy another apple, it won't allow me to do so because the button automatically disables itself because it knows there's an apple in there already? If that makes sense? I need a way to be able to add as many apples to the inventory as I want without the textbutton disabling itself. Sorry for not being clear haha.
It's okay. I think I misunderstood it too. I don't know much about classes in python. Others might be able to help you. If only you were using methods, then this will be my approach on that kind of matter:

Code: Select all

default shop_inventory = {}
default inventory = {}
default money = 15

label start:
    $ shop_inventory.update({"Apple" : ("items/apple.png",5)})
    $ shop_inventory.update({"Orange" : ("items/orange.png",5)})
    $ shop_inventory.update({"Pear" : ("items/pear.png",5)})
    call screen shop
    return

screen shop:
    modal True
    frame:
        xsize 400 ysize 400 ypadding 10 xpadding 10 xalign .5 yalign .5
        vbox:
            for i in shop_inventory.keys():
                $ p = shop_inventory[i][1]
                if money >= p:
                    if i in inventory.keys():
                        textbutton i action [SetVariable("inventory['"+ i +"']", inventory[i] + 1), SetVariable("money", money-p)]
                    else:
                        textbutton i action [SetVariable("inventory['"+ i +"']", 1), SetVariable("money", money-p)]
                else:
                    textbutton i action NullAction()

## The inventory dictionary would look like this if you buy something:
inventory = {
    "Apple" : 1 ## 1 indicates the number of apples you have, it increments each time you buy an apple.
    ...
}

philat
Eileen-Class Veteran
Posts: 1912
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#5 Post by philat »

You should roll your own screen action instead of using AddToSet. It's not very difficult if you look at 00action_data.rpy in the common files. You'd only have to copy AddToSet and change a few names/lines.

User avatar
Kia
Eileen-Class Veteran
Posts: 1040
Joined: Fri Aug 01, 2014 7:49 am
Deviantart: KiaAzad
Discord: Kia#6810
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#6 Post by Kia »

the easy way would be defining a function:

Code: Select all

init python:
    def add_item_to_inventory(x):
        inventory.append(x)
then for your button action you can use:

Code: Select all

    action Function(add_item_to_inventory, i)
note: untested code but it should work

User avatar
xavimat
Eileen-Class Veteran
Posts: 1461
Joined: Sat Feb 25, 2012 8:45 pm
Completed: Yeshua, Jesus Life, Cops&Robbers
Projects: Fear&Love
Organization: Pilgrim Creations
Github: xavi-mat
itch: pilgrimcreations
Location: Spain
Discord: xavimat
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#7 Post by xavimat »

My approach is slightly different:
Instead of having two lists: inventory and shop_inventory, I have only one with all items in it.
Also I add an attribute to items: quantity = 0.
So, If you want to see/use your inventory, you can see/use only the items that have item.quantity > 0.
If you want to buy an item, you simply add 1 to quantity: item.quantity += 1 (after checking if you have the money, of course).
Instead of performing two operations in the screen action (add item and subtract money), I do a method in the class to do both (also, to double check if the money is enough).
Your code, with these variations, could be:

Code: Select all

init python:
    class Item:
        def __init__(self, name, image, price=0):
            self.name = name
            self.image = image
            self.price = price
            self.quantity = 0
        def buy(self):
            global money
            if money >= self.price:
                money -= self.price
                self.quantity += 1

define apple = Item("Apple","items/apple.png",5)
define orange = Item("Orange","item/orange.png",5)
define pear = Item("Pear","item/pear.png",5)

default inventory = [apple,orange,pear]
default money = 15

label start:
    call screen shop
    return

screen shop():
    frame:
        xsize 400 ysize 400 ypadding 10 xpadding 10 xalign .5 yalign .5
        vbox:
            for i in inventory:
                textbutton i.name action [SensitiveIf(money >= i.price), Function(i.buy)]
I have also changed the way the screen checks for money: instead of NullAction (apparently enabled but doing nothing), buttons are now disabled if there is not enough money.
You can define different shops with partial lists, but the main inventory list can have all items from the beginning.

Also:
1. Don't use float for money, it will cause problems (because 0.3 != 0.1+0.1+0.1).
2. Don't "define" things in labels, it will confuse you (or others) when reading your code; in any case, renpy executes all "defines" in init time.
3. Don't use renpy.store.object to define classes, it's not necessary and not recommended.
4. Remember the parenthesis, even empty, in the screen definition.
5. Usually, there is no need of "modal True" if you are calling the screen.
Comunidad Ren'Py en español: ¡Únete a nuestro Discord!
Rhaier Kingdom A Ren'Py Multiplayer Adventure Visual Novel.
Cops&Robbers A two-player experiment | Fear&Love Why can't we say I love you?
Honest Critique (Avatar made with Chibi Maker by ~gen8)

User avatar
screamingpenguin
Regular
Posts: 32
Joined: Mon Dec 11, 2017 5:11 am
Projects: Hollow Voices
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#8 Post by screamingpenguin »

xavimat wrote: Fri Aug 30, 2019 11:33 am My approach is slightly different:
Instead of having two lists: inventory and shop_inventory, I have only one with all items in it.
Also I add an attribute to items: quantity = 0.
So, If you want to see/use your inventory, you can see/use only the items that have item.quantity > 0.
If you want to buy an item, you simply add 1 to quantity: item.quantity += 1 (after checking if you have the money, of course).
Instead of performing two operations in the screen action (add item and subtract money), I do a method in the class to do both (also, to double check if the money is enough).
Your code, with these variations, could be:

Code: Select all

init python:
    class Item:
        def __init__(self, name, image, price=0):
            self.name = name
            self.image = image
            self.price = price
            self.quantity = 0
        def buy(self):
            global money
            if money >= self.price:
                money -= self.price
                self.quantity += 1

define apple = Item("Apple","items/apple.png",5)
define orange = Item("Orange","item/orange.png",5)
define pear = Item("Pear","item/pear.png",5)

default inventory = [apple,orange,pear]
default money = 15

label start:
    call screen shop
    return

screen shop():
    frame:
        xsize 400 ysize 400 ypadding 10 xpadding 10 xalign .5 yalign .5
        vbox:
            for i in inventory:
                textbutton i.name action [SensitiveIf(money >= i.price), Function(i.buy)]
I have also changed the way the screen checks for money: instead of NullAction (apparently enabled but doing nothing), buttons are now disabled if there is not enough money.
You can define different shops with partial lists, but the main inventory list can have all items from the beginning.

Also:
1. Don't use float for money, it will cause problems (because 0.3 != 0.1+0.1+0.1).
2. Don't "define" things in labels, it will confuse you (or others) when reading your code; in any case, renpy executes all "defines" in init time.
3. Don't use renpy.store.object to define classes, it's not necessary and not recommended.
4. Remember the parenthesis, even empty, in the screen definition.
5. Usually, there is no need of "modal True" if you are calling the screen.
Thank you so much for your help, I think I understand the concept somewhat better now. I've fixed my code and files (I defined items in the label because I used to get errors that items weren't defined, but I've only just recently learned that renpy loads files in alphabetical order, which is why I got those errors!) and by creating a test shop, it functions as I'd like.

I just need a little more help though, because I have several different shops in the game that sell different things (eg, food shop, toy shop, etc), which of course need separate 'inventories' for each one (and some items in the game cannot be purchased as they're earned through gameplay), so how would I use the Function to add the item from say 'food_inventory' to the normal 'inventory' upon purchase? Thanks again for your help :)

User avatar
Kia
Eileen-Class Veteran
Posts: 1040
Joined: Fri Aug 01, 2014 7:49 am
Deviantart: KiaAzad
Discord: Kia#6810
Contact:

Re: Enabling Textbuttons to Add Duplicate Items to the Inventory

#9 Post by Kia »

you can create a shop class and create different instances of it for each shop

Code: Select all

init python:
    class shops:
        def __init__(self, name, items):
            self.name = name
            self.items = items
and you can add sell, buy, money and every other attribute and function a shop can have to this class

Post Reply

Who is online

Users browsing this forum: Bing [Bot]