Issue with Inventory system after reload save

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
GoldenGob
Newbie
Posts: 5
Joined: Sat Dec 25, 2021 9:39 pm
itch: goldengob
Contact:

Issue with Inventory system after reload save

#1 Post by GoldenGob »

Hello all! I've been developing a visual novel for some time and have run into an issue regarding my inventory system, this code is based of another's so I haven't fully understood it. It has worked well but has one glaring flaw whenever I reload a save, being that whatever items are there are not registered, but the image is. So if I type "$ inventory.drop(AphroChilli)" for instance, it will result in an error.

I had a similar issue regarding the money system, I had to rectify it by having default values. Not sure how I can do that with the inventory though.


This is the inventory code.

Code: Select all

init -1 python:

    import renpy.store as store
    import renpy.exports as renpy # we need this so Ren'Py properly handles rollback with classes
    from operator import attrgetter # we need this for sorting items

    inv_page = 0 # initial page of teh inventory screen
    #item = None

    class Player(renpy.store.object):
        def __init__(self, name, max_hp=0, max_mp=0, element=None):
            self.name=name
            self.max_hp=max_hp
            self.hp=max_hp
            self.max_mp=max_mp
            self.mp=max_mp
            self.element=element
    player = Player("[player_name]", 100, 50)

    class Item(store.object):
        def __init__(self, name, player=None, hp=0, mp=0, element="", image="", cost=0):
            self.name = name
            self.player=player # which character can use this item?
            self.hp = hp # does this item restore hp?
            self.mp = mp # does this item restore mp?
            self.element=element # does this item change elemental damage?
            self.image=image # image file to use for this item
            self.cost=cost # how much does it cost in shops?
        def use(self): #here we define what should happen when we use the item
            if self.hp>0: #healing item
                player.hp = player.hp+self.hp
                if player.hp > player.max_hp: # can't heal beyond max HP
                    player.hp = player.max_hp
                inventory.drop(self) # consumable item - drop after use
            elif self.mp>0: #mp restore item
                player.mp = player.mp+self.mp
                if player.mp > player.max_mp: # can't increase MP beyond max MP
                    player.mp = player.max_mp
                inventory.drop(self) # consumable item - drop after use
            else:
                player.element=self.element #item to change elemental damage; we don't drop it, since it's not a consumable item

    class Inventory(store.object):
        def __init__(self, money=0):
            self.money = money
            self.items = []
        def add(self, item): # a simple method that adds an item; we could also add conditions here (like check if there is space in the inventory)
            self.items.append(item)

        def earn(self, amount):
            self.money += amount
        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

    #class ClothesInventory(store.object):
    #    def __init__(self):
    #        self.money = money
    #        self.items = []
    #    def add(self, item): # a simple method that adds an item; we could also add conditions here (like check if there is space in the inventory)
    #        self.items.append(item)

    #    def earn(self, amount):
    #        self.money += amount
    #    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

        #@property
        #def moneyz(self):
        #    self.money = money

    def item_use():
        item.use()



    #Tooltips:
    style.tips_top = Style(style.default)
    #style.title.font="gui/arial.ttf"
    style.tips_top.size=14
    style.tips_top.color="fff"
    style.tips_top.outlines=[(3, "6b7eef", 0,0)]
    style.tips_top.kerning = 5

    style.tips_bottom = Style(style.tips_top)
    style.tips_top.size=20
    style.tips_bottom.outlines=[(0, "6b7eef", 1, 1), (0, "6b7eef", 2, 2)]
    style.tips_bottom.kerning = 2

    style.button.background=Frame("gui/frame.png",25,25)
    style.button.yminimum=52
    style.button.xminimum=52
    style.button_text.color="000"




    showitems = True


    player = Player("derp", 100, 50)
    player.hp = 50
    player.mp = 10
    chocolate = Item("Chocolate", hp=40, image="gui/inv_chocolate.png")
    banana = Item("Banana", mp=20, image = "gui/inv_banana.png")
    IceCream = Item("Ice Cream", mp=20, image = "images/Objects/inv_IceCream.webp")
    WineBottle = Item("Wine", mp=20, image = "images/Objects/inv_WineBottle.webp")
    BeachBikini = Item("Beach Bikini", mp=20, image = "images/Objects/inv_bikiniicon.webp")
    gun = Item("Gun", element="bullets", image = "gui/inv_gun.png", cost=7)
    laser = Item("Laser Gun", element="laser", image = "gui/inv_laser.png")
    PirateCostume = Item("Pirate Costume", mp=20, image = "images/Objects/inv_PirateCostume.webp")
    AphroChilli = Item("Aphrodisiac", mp=20, image = "images/Objects/inv_AphroChilli.webp")
    HallEgg = Item("Ostrich Egg", mp=20, image = "images/Objects/inv_HallEgg.webp")
    HallChickEye = Item("Chicken Eye", mp=20, image = "images/Objects/inv_HallChickenEye.webp")
    HallCrowFeetOBJ = Item("Crow Feet", mp=20, image = "images/Objects/inv_HallCrowFeet.webp")



screen inventory_screen():
    zorder 2
    add "InventoryBG" xalign 0.5 yalign 0.3 # the background


    modal True #prevent clicking on other stuff when inventory is shown
    #use battle_frame(char=player, position=(.97,.20)) # we show characters stats (mp, hp) on the inv. screen
    #use battle_frame(char=dog, position=(.97,.50))
    #default current_money = inventory.money

    #style_group "Text_button"
    hbox align (1.0,.14) spacing 200:
        textbutton "Close Inventory" action [ Hide("inventory_screen"), Show("inventory_button"), Return(None)] xpos -350 ypos 20 style "Text_button"
            #xpos -200

        imagebutton:
            idle "icons/InventoryIconIdle.webp"
            hover "icons/InventoryIconHover.webp" focus_mask True action [ Hide("inventory_screen"), Show("inventory_button"), Return(None)]
            at InventoryZoom

    $ x = 150 # coordinates of the top left item position
    $ y = 100
    $ i = 0
    $ sorted_items = sorted(inventory.items, key=attrgetter('element'), reverse=True) # we sort the items, so non-consumable items that change elemental damage (guns) are listed first
    $ next_inv_page = inv_page + 1
    if next_inv_page > int(len(inventory.items)/9):
        $ next_inv_page = 0
    for item in sorted_items:
        if i+1 <= (inv_page+1)*9 and i+1>inv_page*9:
            $ x += 190
            if i%3==0:
                $ y += 170
                $ x = 790

            $ pic = item.image
            $ my_tooltip = "tooltip_inventory_" + pic.replace("images/Objects/inv_", "").replace(".webp", "") # we use tooltips to describe what the item does.
            #imagebutton idle pic hover pic xpos x ypos y action [Hide("gui_tooltip"), Show("inventory_button"), SetVariable("item", item), Hide("inventory_screen")] hovered [ Play ("sound", "sfx/click.wav"), Show("gui_tooltip", my_picture=my_tooltip, my_tt_ypos=693) ] unhovered [Hide("gui_tooltip")] at inv_eff
            imagebutton idle pic hover pic xpos x ypos y action [SetVariable("item", item)] hovered [ Play ("sound", "sfx/click.wav"), Show("gui_tooltip", my_picture=my_tooltip, my_tt_ypos=679) ] unhovered [Hide("gui_tooltip")] at inv_eff
            #if player.element and (player.element==item.element): #indicate the selected gun
            #    add "gui/selected.png" xpos x ypos y anchor(.5,.5)
        $ i += 1
        if len(inventory.items)>9:
            textbutton _("Next Page") action [SetVariable('inv_page', next_inv_page), Show("inventory_screen")] xpos .475 ypos .12

screen gui_tooltip (my_picture="", my_tt_xpos=700, my_tt_ypos=707):
    zorder 3
    add my_picture xpos my_tt_xpos ypos my_tt_ypos

init -1:
    transform inv_eff: # too lazy to make another version of each item, we just use ATL to make hovered items super bright
        zoom 0.5 xanchor 0.5 yanchor 0.5
        on idle:
            linear 0.2 alpha 1.0
        on hover:
            linear 0.2 alpha 2.5

    image information = Text("INFORMATION", style="tips_top")
    #Tooltips-inventory:
    #image tooltip_inventory_chocolate=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("Generic chocolate to heal\n40 points of health.", style="tips_bottom"))
    image tooltip_inventory_banana=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("A healthy banana full of potassium! You can also use it as ammo for your guns! O.O Recharges 20 bullets.", style="tips_bottom"))
    image tooltip_inventory_gun=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("An gun that looks like something a cop would\ncarry around. Most effective on humans.", style="tips_bottom"))
    image tooltip_inventory_laser=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("An energy gun that shoots photon beams.\nMost effective on aliens.", style="tips_bottom"))
    image tooltip_inventory_IceCream=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("Delicious Ice Cream", style="tips_bottom"))
    image tooltip_inventory_WineBottle=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("A bottle of fine wine", style="tips_bottom"))
    image tooltip_inventory_bikiniicon=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("Striped Bikini. XXL.", style="tips_bottom"))
    image tooltip_inventory_PirateCostume=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("An ill fitting costume, but you can make it work.", style="tips_bottom"))
    image tooltip_inventory_AphroChilli=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("Chilli: said to to arouse an uncontrollable urge, supposedly", style="tips_bottom"))
    image tooltip_inventory_HallEgg=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("The Egg of the king", style="tips_bottom"))
    image tooltip_inventory_HallCrowFeet=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("The claw of the winged omen", style="tips_bottom"))
    image tooltip_inventory_HallChickenEye=LiveComposite((665, 73), (3,0), ImageReference("information"), (3,30), Text("The Eye of vengeful prey", style="tips_bottom"))





The error:

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/script.rpy", line 607, in script call
    $ renpy.pause(hard=True)
  File "game/MenuChoices.rpy", line 942, in script call
    call Call_Story_Variables_Jumper from _call_Call_Story_Variables_Jumper_2
  File "game/script.rpy", line 864, in script call
    $ renpy.pause(hard=True)
  File "game/script.rpy", line 637, in script call
    $ renpy.pause(hard=True)
  File "game/script.rpy", line 882, in script call
    $ renpy.pause(hard=True)
  File "game/script.rpy", line 796, in script call
    $ renpy.pause(hard=True)
  File "game/MenuChoices.rpy", line 942, in script call
    call Call_Story_Variables_Jumper from _call_Call_Story_Variables_Jumper_2
  File "game/script.rpy", line 607, in script call
    $ renpy.pause(hard=True)
  File "game/Characters/Holidays/Halloween/Kate.rpy", line 225, in script
    $ inventory.drop(IceCream)
  File "game/Characters/Holidays/Halloween/Kate.rpy", line 225, in <module>
    $ inventory.drop(IceCream)
  File "game/Inventory.rpy", line 72, in drop
    self.items.remove(item)
ValueError: list.remove(x): x not in list

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

Full traceback:
  File "game/script.rpy", line 607, in script call
    $ renpy.pause(hard=True)
  File "game/MenuChoices.rpy", line 942, in script call
    call Call_Story_Variables_Jumper from _call_Call_Story_Variables_Jumper_2
  File "game/script.rpy", line 864, in script call
    $ renpy.pause(hard=True)
  File "game/script.rpy", line 637, in script call
    $ renpy.pause(hard=True)
  File "game/script.rpy", line 882, in script call
    $ renpy.pause(hard=True)
  File "game/script.rpy", line 796, in script call
    $ renpy.pause(hard=True)
  File "game/MenuChoices.rpy", line 942, in script call
    call Call_Story_Variables_Jumper from _call_Call_Story_Variables_Jumper_2
  File "game/script.rpy", line 607, in script call
    $ renpy.pause(hard=True)
  File "game/Characters/Holidays/Halloween/Kate.rpy", line 225, in script
    $ inventory.drop(IceCream)
  File "renpy/ast.py", line 1111, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "renpy/python.py", line 1048, in py_exec_bytecode
    exec(bytecode, globals, locals)
  File "game/Characters/Holidays/Halloween/Kate.rpy", line 225, in <module>
    $ inventory.drop(IceCream)
  File "game/Inventory.rpy", line 72, in drop
    self.items.remove(item)
  File "renpy/revertable.py", line 97, in do_mutation
    return method(self, *args, **kwargs)
ValueError: list.remove(x): x not in list

Windows-10-10.0.19041
Ren'Py 7.5.0.22052902
 0.141
Sun Nov 27 21:03:55 2022
Thank you for any help!

User avatar
GoldenGob
Newbie
Posts: 5
Joined: Sat Dec 25, 2021 9:39 pm
itch: goldengob
Contact:

Re: Issue with Inventory system after reload save

#2 Post by GoldenGob »

Would really appreciate any input!

User avatar
Alex
Lemma-Class Veteran
Posts: 3093
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Issue with Inventory system after reload save

#3 Post by Alex »

GoldenGob wrote: Fri Dec 02, 2022 11:08 am ...
What's the code for 'inventory' declaration?

User avatar
GoldenGob
Newbie
Posts: 5
Joined: Sat Dec 25, 2021 9:39 pm
itch: goldengob
Contact:

Re: Issue with Inventory system after reload save

#4 Post by GoldenGob »

Alex wrote: Sat Dec 03, 2022 6:11 pm
GoldenGob wrote: Fri Dec 02, 2022 11:08 am ...
What's the code for 'inventory' declaration?
The first code segment posted above contains everything regarding the inventory, but I used:

Code: Select all

$ inventory.drop(BeachBikini)
To remove an object, which led to a crash after I reloaded the save. I'm not exactly sure what you mean by declaration.

Code: Select all

class Inventory(store.object):
        def __init__(self, money=0):
            self.money = money
            self.items = []
        def add(self, item): # a simple method that adds an item; we could also add conditions here (like check if there is space in the inventory)
            self.items.append(item)

        def earn(self, amount):
            self.money += amount
        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

User avatar
GoldenGob
Newbie
Posts: 5
Joined: Sat Dec 25, 2021 9:39 pm
itch: goldengob
Contact:

Re: Issue with Inventory system after reload save

#5 Post by GoldenGob »

I fixed it. I had to default the items themselves.

Code: Select all

chocolate = Item("Chocolate", hp=40, image="gui/inv_chocolate.png")
    banana = Item("Banana", mp=20, image = "gui/inv_banana.png")
    IceCream = Item("Ice Cream", mp=20, image = "images/Objects/inv_IceCream.webp")
    WineBottle = Item("Wine", mp=20, image = "images/Objects/inv_WineBottle.webp")
    BeachBikini = Item("Beach Bikini", mp=20, image = "images/Objects/inv_bikiniicon.webp")
    gun = Item("Gun", element="bullets", image = "gui/inv_gun.png", cost=7)
    laser = Item("Laser Gun", element="laser", image = "gui/inv_laser.png")
    PirateCostume = Item("Pirate Costume", mp=20, image = "images/Objects/inv_PirateCostume.webp")
    AphroChilli = Item("Aphrodisiac", mp=20, image = "images/Objects/inv_AphroChilli.webp")
    HallEgg = Item("Ostrich Egg", mp=20, image = "images/Objects/inv_HallEgg.webp")
    HallChickEye = Item("Chicken Eye", mp=20, image = "images/Objects/inv_HallChickenEye.webp")
    HallCrowFeetOBJ = Item("Crow Feet", mp=20, image = "images/Objects/inv_HallCrowFeet.webp")


and add default before each. I placed it in a weird place before.

User avatar
Alex
Lemma-Class Veteran
Posts: 3093
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Issue with Inventory system after reload save

#6 Post by Alex »

GoldenGob wrote: Mon Dec 05, 2022 9:51 pm I fixed it. I had to default the items themselves.

Code: Select all

chocolate = Item("Chocolate", hp=40, image="gui/inv_chocolate.png")
    banana = Item("Banana", mp=20, image = "gui/inv_banana.png")
    IceCream = Item("Ice Cream", mp=20, image = "images/Objects/inv_IceCream.webp")
    WineBottle = Item("Wine", mp=20, image = "images/Objects/inv_WineBottle.webp")
    BeachBikini = Item("Beach Bikini", mp=20, image = "images/Objects/inv_bikiniicon.webp")
    gun = Item("Gun", element="bullets", image = "gui/inv_gun.png", cost=7)
    laser = Item("Laser Gun", element="laser", image = "gui/inv_laser.png")
    PirateCostume = Item("Pirate Costume", mp=20, image = "images/Objects/inv_PirateCostume.webp")
    AphroChilli = Item("Aphrodisiac", mp=20, image = "images/Objects/inv_AphroChilli.webp")
    HallEgg = Item("Ostrich Egg", mp=20, image = "images/Objects/inv_HallEgg.webp")
    HallChickEye = Item("Chicken Eye", mp=20, image = "images/Objects/inv_HallChickenEye.webp")
    HallCrowFeetOBJ = Item("Crow Feet", mp=20, image = "images/Objects/inv_HallCrowFeet.webp")


and add default before each. I placed it in a weird place before.
And also, do you have

Code: Select all

default inventory = Inventory()
?

User avatar
GoldenGob
Newbie
Posts: 5
Joined: Sat Dec 25, 2021 9:39 pm
itch: goldengob
Contact:

Re: Issue with Inventory system after reload save

#7 Post by GoldenGob »

Alex wrote: Tue Dec 06, 2022 3:20 pm

And also, do you have

Code: Select all

default inventory = Inventory()
?
Yes. It's in my variables initiated by init:

User avatar
Alex
Lemma-Class Veteran
Posts: 3093
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Issue with Inventory system after reload save

#8 Post by Alex »

GoldenGob wrote: Sat Dec 10, 2022 2:07 am Yes. It's in my variables initiated by init:
Well, line with 'default' statement doesn't need to be placed inside an init block or have any indentation. It is used for variables that will be changed during the game and that are needed to be stored.
Check the differences between 'init', 'define' and 'default' (if haven't yet) - https://www.renpy.org/doc/html/python.h ... -statement

Post Reply

Who is online

Users browsing this forum: Google [Bot], Majestic-12 [Bot]