I do hope you're having a great day
I know you've read this a lot, but I'm a newbie whith Renpy
I started to make a RPG-like Visual Novel a month ago and even if I have resolved a lot of my issues thanks to your posts, there's still one problem I can not seem to be able to bypass ^^'
So I created some classes : Player, Item and Inventory to start my Inventory system, and I coded a screen (highly inspired by Leon's one ! Thanks a lot Leon !!) to display the inventory.
First of all, let me show you how I built my classes, so you'd be able to understand the following code !
Here's the declaration of my Player class:
Code: Select all
class Player(renpy.store.object):
def __init__(self, name, gender="m", level=1, max_hp=10, max_mp=5):
self.name = name
self.gender = gender
self.level = level
self.max_hp = max_hp
self.hp = max_hp
self.max_mp = max_mp
self.mp = max_mp
self.inventory = Inventory(25) #25 represents the amount of gold the player posses at the label start
Now, here's the declaration of my Item class:
Code: Select all
class Item(store.object):
def __init__(self, name, hp=0, mp=0, image="", cost=0, type="divers", consommable=True, essential=False):
self.name = name
self.hp = hp # How much hp gain ?
self.mp = mp # cHow much mp gain ?
self.image=image # path to the image without the extension "idle"/"hover"/"insensitive"
self.cost=cost # How much does it cost ?
self.type=type # How it will be sorted ?
self.consommable = consommable # Can the player use the item on himself ?
self.essential=essential #Can the player drop it ?
And finally, here's I made my Inventory class:
Code: Select all
class InventoryObject(object):
def __init__(self, item, amount):
self.item = item
self.amount = amount
class Inventory(store.object):
def __init__(self, gold=15):
self.gold = gold
self.items = []
def finditem(self, item): #return the element searched in the inventory
return(self.items[[i.item for i in self.items].index(item)])
def add(self, item, amount=1): # add a contener with the item et its amount in the inventory
if item in [i.item for i in self.items]:
self.finditem(item).amount += amount
else:
self.items.append(ObjetdInventaire(item, amount))
return('success')
There, you can see that my Inventory is not only made of a list of items.
It uses an instance of InventoryObject which is an object that contain the item but also contain the amount of it in the inventory.
So, in one way, it's a container.
To make it clearer, you can see it like this. "->"means that it contains the following:
Player -> Inventory -> items -> InventoryObject -> Item
-> amount
I created the screen to display my player.inventory that I call with a button in a side menu.
From now on, I will simplify my code to the strict essential so it does't have a frightening size (more than it has )
Here's the side menu button :
Code: Select all
imagebutton idle "gui/Inventaire_idle.png" action ToggleScreen("inventaire", dissolve) tooltip "Inventaire"
And then, here is the declaration of the screen that display my inventory:
Code: Select all
screen inventory:
modal True
#The whole inventory screen (Big thanks to Leon :D )
frame:
background "gui/Inventaire/inventaire_menu.png"
hbox:
frame:
style "frame_inventaire_items"
xalign 0.4 yalign 0.2
$ x = 0 # coordinates of the top left item position
$ y = 6
$ i = 0
$ next_inv_page = inv_page + 1
if next_inv_page > int(len(player.inventory.items)/25):
$ next_inv_page = 0
for it in player.inventory.items:
$ path = "{0}".format(it.item.image)
$ itidle = "{0}_idle.png".format(path)
if i+1 <= (inv_page+1)*25 and i+1>inv_page*25 and(it.item.type == tri_inventaire or tri_inventaire=="all"):
$ x += 80
if i%5==0:
if i%25!=0:
$ y += 75
$ x = 0
frame:
background "gui/Inventaire_petit/fond_icone_inventaire2.png"
xpos x ypos y
vbox:
xalign 0.5 yalign 0.5
imagebutton idle itidle action ToggleScreen("interaction_object", None, it.item, renpy.get_mouse_pos())
text "[it.amount]" xalign 1.0 yalign 0.0 size 10
$ i += 1
if len(player.inventory.items)>25:
textbutton _("Page précédente") action [SetVariable('inv_page', next_inv_page), Show("inventory")]
### Player stats box ( simplfied)
frame:
style "frame_inventaire_statistiques"
vbox:
vbox:
text "[player.name]"
text "Niveau [player.level]"
vbox:
hbox :
text "Hp"
text "[player.hp]/[player.max_hp]"
bar value AnimatedValue(player.hp, player.max_hp) style "greenbar"
vbox:
hbox :
text "Mp"
text "[player.mp]/[player.max_mp]"
bar value AnimatedValue(player.mp, player.max_mp) style "bluebar"
You can also take a look at my interaction_object screen that display the item menu:
Code: Select all
screen interaction_object( objet, position):
zorder 100
$ mouseposx = position[0]
$ mouseposy = position[1]
frame:
xpos mouseposx ypos mouseposy
xsize 400 ysize 250
vbox:
hbox:
textbutton "x" xalign 1.0 yalign 0.0 action ToggleScreen("interaction_object")
text "What do you want to do of [objet.name] ?" xalign 0.0
vbox:
xalign 0.5
hbox:
textbutton "use it on yourself" action [SensitiveIf(objet.consommable == True),Hide("interaction_object"), Function(player.inventory.remove_item, objet, 1)]
# textbutton "l'utiliser" tooltip "L'utiliser sur quelqu'un ou quelque chose" ###
#hbox: ###
# textbutton "le jeter" ### Havn't coded these three yet
# textbutton "Observer" ###
Now that you have the code that is concerned by my issue, I'm finally going to explain what's happening ^^'
So, when I do start the game and I show the inventory screen with the button, I have all my items in my inventory as shown on screen n1 with their amount.
Screen n1
Then, I click on an item. On screen n2 I clicked the strawberries, and the interaction_object screen showed up !
Screen n2
When I clicked the button to use the object on the player, the interaction_object screen disappeared, but instead of showing me only the inventory screen, the "say" screen showed on top, with the next say statement.
We can also see that one item of strawberries has been used, so I do know that my function has been executed correctly.
I'd like to understand what I may have done the wrong way to have the "say" statement rollforward...
I suspected that when the interaction of the second screen had finished (the interaction_object one, on an item), then the first screen (the inventory modal) sees its task as finished too and automatically execute a Return(). So it is supposed to close the modal, and rollforward the say statement.
As to know why the inventory screen do not disappear, I think it may be because of the way I had called it...
Does anyone know if I am right ?
I was wondering if someone here had had the same issue, or knows how to prevent the modal to use Return() while we do not ask for it.
I tried a lot of code to bypass this : I put the screen with the loop that display each item in another screen, I tried to rewrite the keymap to prevent the rollforward with any key, I attempted to use ui.interact() but with no success...
Maybe I have not used it well, so if you do know a way to solve my problem, I'd be more than happy!
I was looking forward to post this question here, because I've been working on this issue for some days now and I do know that many of you are a lot more experienced than I am !
Even if you don't have an answer to my question, you can answer the topic if you see any mistakes in my code ! I will also gladly take any advice you have to give
I'm sorry for any mistakes I may have made in english ^^' I hope it was still understandable.