Inventory Screen

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Message
Author
Roxie
Regular
Posts: 71
Joined: Sat Aug 13, 2011 9:07 pm
Projects: Assess K, Mizuchi
Organization: Aikasa Collective, Altabe Studio
itch: aikasacolle
Location: Southern California
Contact:

Re: Inventory Screen

#16 Post by Roxie »

Thanks Leon! A couple of issues came up. When items were selected, only the 2nd item was dropped during the combining, leaving the 1st item to remain in the inventory when it should also be dropped. Also it allows many items to be selected at once, instead of only the selected items matching the recipe for combining to work.
ImageImage
Assess K (VN Adventure Game) LSF Thread | Mizuchi (GxG VN) LSF Thread | Honest Critique
[Proofreader, Beta-Tester]
Razz Art Visual - Starlight Vega [Co-writer]
Roseverte - Cafe-0, Duplicity, East Tower, How to Take Off Your Mask; Bakufu - Love Sniper
Zeiva Inc. - Train of Afterlife, OASE, X-Note, Area-X, Voices from the Sea, Natural - Beyond Nature, Dragon Essence, Anicon - Cat

User avatar
leon
Miko-Class Veteran
Posts: 554
Joined: Sun Oct 09, 2011 11:15 pm
Completed: Visual Novel Tycoon, Night at the Hospital, Time Labyrinth, The Buried Moon, Left of Center, Super Otome Quest
Projects: Lemon Project, Porcelain Heart, Dream's Dénouement
Organization: Team ANARKY
Contact:

Re: Inventory Screen

#17 Post by leon »

Roxie wrote:Thanks Leon! A couple of issues came up. When items were selected, only the 2nd item was dropped during the combining, leaving the 1st item to remain in the inventory when it should also be dropped.
At the start under init -1 python add:

Code: Select all

import copy
Add the recipe class:

Code: Select all

    class Recipe(store.object):
        def __init__(self, items=[], item_created=None):
            self.items = items
            self.item_created = item_created
        def combine_check(self):
            too_many=False # too many items selected?
            correct_recipe_items = copy.copy(self.items) # make a copy of the list of recipe items
            for item in inventory.selected_items:
                if item.recipeItem: # and item in self.items:
                    if item in correct_recipe_items:
                        correct_recipe_items.remove(item) # remove the current item from the list of correct_recipe_items; if correct_recipe_items is empty at the end, we have created the recipe
                    if not (item in self.items): # current item is not in this recipe
                        too_many=True
            if len(correct_recipe_items) == 0 and not too_many: # correct_recipe_items is empty means we have selecte just the right items
                inventory.add(self.item_created) # add the newly created item
                for drop_item in self.items: # remove all the items in this recipe from inventory
                    inventory.drop(drop_item)
Change the combine_items function:

Code: Select all

init python:
    def combine_items():
        for recipe in recipes:
            recipe.combine_check()
        inventory.selected_items = []
        return
Finally define the recipes:

Code: Select all

recipes = [Recipe([chocolate, candy], diabetes), Recipe([banana, black_paint], fake_gun)]
Roxie wrote:Also it allows many items to be selected at once, instead of only the selected items matching the recipe for combining to work.
I think the best method to solve this is to group the items of the same type.
Change the use function like this:

Code: Select all

def use(self): #here we define what should happen when we use the item
    if self.recipeItem:
        if self in inventory.selected_items:
            inventory.selected_items.remove(self)
        else:
            inventory.selected_items.append(self)
Change the Inventory class constructor:

Code: Select all

class Inventory(store.object):
    def __init__(self):
        self.items = []
        self.selected_items = []

Then change the inventory screen to something like:

Code: Select all

screen inventory_screen:    
    add "gui/inventory.png" # the background
    modal True #prevent clicking on other stuff when inventory is shown
    hbox align (.95,.04) spacing 20:
        textbutton "Close Inventory" action [ Hide("inventory_screen"), Show("inventory_button"), Return(None)]
    $ x = 515 # coordinates of the top left item position
    $ y = 25
    $ i = 0
    $ sorted_items = sorted(inventory.items, key=attrgetter('name')) #sort by name
    $ 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
    $ tmp_inventory = []
    for item in sorted_items:
        $ tmp_inventory.append(item)
        if tmp_inventory.count(item) == 1:
            if i+1 <= (inv_page+1)*9 and i+1>inv_page*9:
                $ x += 190
                if i%3==0:
                    $ y += 170
                    $ x = 515
                $ pic = item.image
                $ my_tooltip = "tooltip_inventory_" + pic.replace("gui/inv_", "").replace(".png", "") # we use tooltips to describe what the item does.
                if item.recipeItem:
                    imagebutton idle pic hover pic xpos x ypos y action [Hide("gui_tooltip"), SetVariable("item", item), item_use] hovered [ Play ("sound", "sfx/click.wav"), Show("gui_tooltip", my_picture=my_tooltip, my_tt_ypos=693) ] unhovered [Hide("gui_tooltip")] at inv_eff
                else:
                    imagebutton idle pic hover pic xpos x ypos y action [Hide("gui_tooltip"), Show("inventory_button"), SetVariable("item", item), Hide("inventory_screen"), item_use] hovered [ Play ("sound", "sfx/click.wav"), Show("gui_tooltip", my_picture=my_tooltip, my_tt_ypos=693) ] unhovered [Hide("gui_tooltip")] at inv_eff
                if item in inventory.selected_items:
                    add "gui/selected.png" xpos x ypos y anchor(.5,.5)                        
                $ i += 1
            if sorted_items.count(item) > 1:
                text str(sorted_items.count(item)) xpos x+50 ypos y-50 anchor(.5,.5) color "#000" #align(.9,.1)
        if len(inventory.items)>9:
            textbutton _("Next Page") action [SetVariable('inv_page', next_inv_page), Show("inventory_screen")] xpos .475 ypos .83
    textbutton "Combine" action [Function(combine_items), Hide("inventory_screen"), Show("inventory_screen")] align (.80,.80)

Roxie
Regular
Posts: 71
Joined: Sat Aug 13, 2011 9:07 pm
Projects: Assess K, Mizuchi
Organization: Aikasa Collective, Altabe Studio
itch: aikasacolle
Location: Southern California
Contact:

Re: Inventory Screen

#18 Post by Roxie »

For some reason, when I click on the item, the selected png doesn't work, instead it maintains a hover glow instead. And then when I click another item, that previous item no longer glows, while the new one glows and is selected instead.
ImageImage
Assess K (VN Adventure Game) LSF Thread | Mizuchi (GxG VN) LSF Thread | Honest Critique
[Proofreader, Beta-Tester]
Razz Art Visual - Starlight Vega [Co-writer]
Roseverte - Cafe-0, Duplicity, East Tower, How to Take Off Your Mask; Bakufu - Love Sniper
Zeiva Inc. - Train of Afterlife, OASE, X-Note, Area-X, Voices from the Sea, Natural - Beyond Nature, Dragon Essence, Anicon - Cat

SecretGuitar1
Newbie
Posts: 6
Joined: Mon Jan 12, 2015 11:37 am
Projects: Tales of Yardora, Helen's Creek
Tumblr: Akiyo Kawaii
Deviantart: SecretGuitar1
Location: The Netherlands
Contact:

Re: Inventory Screen

#19 Post by SecretGuitar1 »

Your codes were great help, but I came across a problem.
When you choose to close the inventory screen, while being in a choice menu, it gives an errorcode.

I came across it in the game I implemented your code in, so i putted a choice menu in your "inventory game", and it did it again.

User avatar
leon
Miko-Class Veteran
Posts: 554
Joined: Sun Oct 09, 2011 11:15 pm
Completed: Visual Novel Tycoon, Night at the Hospital, Time Labyrinth, The Buried Moon, Left of Center, Super Otome Quest
Projects: Lemon Project, Porcelain Heart, Dream's Dénouement
Organization: Team ANARKY
Contact:

Re: Inventory Screen

#20 Post by leon »

@Roxie:
To fix the hover problem add selected_idle and selected_hover states to inv_eff transform like this:

Code: Select all

    transform inv_eff:
        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
        on selected_idle:
            linear 0.2 alpha 1.0
        on selected_hover:
            linear 0.2 alpha 2.5
I have no idea why the selected image wouldn't work. Double check all the lines that include inventory.selected_items for typos.

@SecretGuitar1:
Try changing the close button like this:

Code: Select all

screen inventory_button:
    textbutton "Show Inventory" action [ Show("inventory_screen"), Hide("inventory_button")] align (.95,.04)

SecretGuitar1
Newbie
Posts: 6
Joined: Mon Jan 12, 2015 11:37 am
Projects: Tales of Yardora, Helen's Creek
Tumblr: Akiyo Kawaii
Deviantart: SecretGuitar1
Location: The Netherlands
Contact:

Re: Inventory Screen

#21 Post by SecretGuitar1 »

@SecretGuitar1:
Try changing the close button like this:

Code: Select all

screen inventory_button:
    textbutton "Show Inventory" action [ Show("inventory_screen"), Hide("inventory_button")] align (.95,.04)
[/quote]

It is the exact same code that i was using before.

Maybe I could just inform people not to open and close the inventory screen, while being in a choicemenu, with a message in AVL mode

User avatar
leon
Miko-Class Veteran
Posts: 554
Joined: Sun Oct 09, 2011 11:15 pm
Completed: Visual Novel Tycoon, Night at the Hospital, Time Labyrinth, The Buried Moon, Left of Center, Super Otome Quest
Projects: Lemon Project, Porcelain Heart, Dream's Dénouement
Organization: Team ANARKY
Contact:

Re: Inventory Screen

#22 Post by leon »

Sorry I meant this part:

Code: Select all

    hbox align (.95,.04) spacing 20:
        textbutton "Close Inventory" action [ Hide("inventory_screen"), Show("inventory_button") ]
Return(None) there could be a problem...

If that doesn't work you could just hide the inventory_button while the menus are being shown.

nhguy03276
Regular
Posts: 41
Joined: Thu Jan 29, 2015 12:48 pm
Contact:

Re: Inventory Screen

#23 Post by nhguy03276 »

Thank you for sharing the code, integration into my code has begun, and it is starting to come together, however, I'm a silly noob, and am having problems moving the textbutton for the inventory from being on screen to a existing Vbox status bar. I think I've isolated the call line, but may be way off:
textbutton "Show Inventory" action [ Show("inventory_screen"), Hide("inventory_button")] align (.95,.04)


When I try to make it a ui.textbutton, I get a whole host of syntax errors. I'm sure this has got to be a simple fix, so I'm going keep working on it, and it is likely I'll find a solution before you respond, but in case I don't....


The next Question, I noticed that even in your demo version, clicking open/close inventory advances the story. Is there a way to stop that, say, I'm walking down the street, and I get the I'm hungry warning, I can stop and get and eat say an apple from inventory, without it causing me to skip parts of the story, or possibly selecting a choice on the main screen?

thank you.

User avatar
leon
Miko-Class Veteran
Posts: 554
Joined: Sun Oct 09, 2011 11:15 pm
Completed: Visual Novel Tycoon, Night at the Hospital, Time Labyrinth, The Buried Moon, Left of Center, Super Otome Quest
Projects: Lemon Project, Porcelain Heart, Dream's Dénouement
Organization: Team ANARKY
Contact:

Re: Inventory Screen

#24 Post by leon »

Maybe this will help - http://www.renpy.org/doc/html/screens.html#textbutton
You can also use imagebutton, button or imagemap statements.

See my previous post to prevent advancing the story.

nhguy03276
Regular
Posts: 41
Joined: Thu Jan 29, 2015 12:48 pm
Contact:

Re: Inventory Screen

#25 Post by nhguy03276 »

leon wrote: See my previous post to prevent advancing the story.
Reading comprehension for the win... I misread that as a different issue altogether. That did take care of my problem, thank you.

However, How would you go about adding a daily limit to consumables?

In my game hunger is tied to mood, and mood directs the dialogue. if mood is good, better interactions, bad mood, not so much. The hungrier you are, the worse you mood becomes. Some foods improve mood more than others. basically I want to limit how many apples or cookies one can eat in a day. (I don't want people walking around with 50 apples or 50 cookies to avoid low moods and paying for better meals.)

so basically I was thinking:

Apple = Item ("apple", hp=5, image=".png" dailylimit=3)
Cookie= Item ("cookie", mp=4, image=".png" dailylimit=2)

and once you reached you limit, it sends back a "As good as [apple]s are, you couldn't eat another [Apple] today"

I want to manually reset these limits when I start the new day. I thought I had a code worked out, but it started causing a double inventory drop which lead to all sorts of errors...
Last edited by nhguy03276 on Mon Feb 02, 2015 9:11 pm, edited 1 time in total.

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

Re: Inventory Screen

#26 Post by philat »

Eh, to use it like that looks like you'd have to rework a lot of the code. Depending on how many items you want to limit the use of, and whether you want to limit all restorative items collectively or individually, etc., the optimal approach would change, but. I suppose the simplest way conceptually would be something like.

Code: Select all

init python:
    hp_consumables = 0

    class Item(store.object):

        [skip a bunch of code here]

        def use(self): #here we define what should happen when we use the item
            global hp_consumables ## reference the global variable
            if self.hp>0: #healing item
                if hp_consumables < 3:
                    hp_consumables += 1  ## increase the counter
                    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
                else:
                    renpy.say(None, "I can't eat more food now.")
And so forth. Or I suppose you could bake the limits into some other object, like player or inventory, before comparing. Dunno what would be best for you.

nhguy03276
Regular
Posts: 41
Joined: Thu Jan 29, 2015 12:48 pm
Contact:

Re: Inventory Screen

#27 Post by nhguy03276 »

philat wrote:Eh, to use it like that looks like you'd have to rework a lot of the code. Depending on how many items you want to limit the use of, and whether you want to limit all restorative items collectively or individually, etc., the optimal approach would change, but. I suppose the simplest way conceptually would be something like.

Code: Select all

init python:
    hp_consumables = 0

    class Item(store.object):

        [skip a bunch of code here]

        def use(self): #here we define what should happen when we use the item
            global hp_consumables ## reference the global variable
            if self.hp>0: #healing item
                if hp_consumables < 3:
                    hp_consumables += 1  ## increase the counter
                    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
                else:
                    renpy.say(None, "I can't eat more food now.")
And so forth. Or I suppose you could bake the limits into some other object, like player or inventory, before comparing. Dunno what would be best for you.

I believe you are correct, the elegant solution isn't going to be easy. Luckily I only plan on 6 or 7 consumable restoratives that will go into inventory. Most restoratives will be consumed on acquire. (ie. you go out to the diner for breakfast, you eat at the diner, not bring it with you to work).

I considered point of sale limits, probably the easiest solution, but I don't like that. and yeah, I want each consumable to have it's own limit. What I'm thinking, is something like:

Code: Select all

*Snip*
  def use(self): 
 
             global d_limit_ + "name"     ####  whatever the proper syntax is to do this
             if self.dailylimit > 0 
                if  self.dailylimit >= d_limit_"name"
                     d_limit_"name" += 1  
                else : 
                     renpy.say "yadda yadda."
    *snip* back to the rest of the code. 
I think that would work, with the proper syntax, but I'm not sure. It would require being careful with the inventory "name". I've not had good luck with passing variables between script and screen. does this sound right?

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

Re: Inventory Screen

#28 Post by philat »

Hmm. At that point, perhaps just using a list of consumed items would be more convenient.

Code: Select all

init python:
    consumed_items = []

    def use(self): #here we define what should happen when we use the item
        global consumed_items
        if self.hp>0: #healing item
            if consumed_items.count(self.name) < self.dailylimit:
                consumed_items.append(self.name)
                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
            else:
                renpy.say(None, "I can't eat more another [self.name] now.")
Haven't tested it, mind you, but the concept should work.

nhguy03276
Regular
Posts: 41
Joined: Thu Jan 29, 2015 12:48 pm
Contact:

Re: Inventory Screen

#29 Post by nhguy03276 »

Sorry for not getting back to this sooner, I tend to work on 10 different things at the same time, and didn't actually work on the daily limits aspect again until today.

I just wanted to let you know the list code did indeed work, it functions as hoped.

I did however get an error code on the feedback:

Code: Select all

else:
            renpy.say(None, "I can't eat more another now.") 


returns a Exception: Cannot start an interaction in the middle of an interaction, without creating a new context.


As a temporary fix for now, I simply replaced it with a 'pass', until I can figure it out.

nhguy03276
Regular
Posts: 41
Joined: Thu Jan 29, 2015 12:48 pm
Contact:

Re: Inventory Screen

#30 Post by nhguy03276 »

Well, half the night later, and I figured it out. I'm sure someone else will clean up the code a bit, but at least it works the way I want.

Code: Select all

init python:
    consumed_items = []

    def use(self):
        global consumed_items
        global thisitem   

        if self.hp>0:
            if consumed_items.count(self.name) < self.dailylimit:
                consumed_items.append(self.name)
                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
            else:
                thisitem = self.name
                renpy.call_in_new_context ("oops")




label oops:
    n "As much as I like [thisitem]s, I couldn't eat another today."
    return

needed the new global for the item name, a label for the say, and a return to bring you back to the same point. However, I think this way, I can also create different oops messages for each limited item like "I'll get fat if I eat too many cookies", or "my mouth is already minty fresh, better not waste the mouthwash" but that's for another time.

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot]