Page 1 of 1

Inventory RPG-style

Posted: Thu Jun 01, 2023 8:37 am
by jeffster
v1.6. Added import from typing to work with 8.2+.
(Ren'Py 8.2 could give errors with v1.5, because of some Python type hints. Use v1.6 please).
Now it's more like a usable framework than just a sketch.

Here is yet another inventory, RPG-style:
  • Equip/unequip with dragging or clicking.
  • Backpack grid and custom equipment slots.
  • When an item is hovered or dragged, highlight suitable equipment slots.
  • "Filtering": highlight backpack slots with different colors according to their item type.
  • Calculating stats bonuses depending on the equipped items' properties.
  • Tooltips.
  • v1.1: Stackables & consumables. Stats bars (mana, energy, health).
  • v1.3: Crafting. The code was reworked for that.
  • v1.4-1.5: More documentation with some improvements.
It's not a framework, rather a simple code that you can modify and use as a starting point for your own system.

v1.0 is a simple (291 lines not counting comments) how-to drag-n-drop or click to rearrange and move draggables between drop areas.

The last version is a more complex program, with crafting etc.

Code: Select all

The program has "items" and "slots".

TL;DR: Use functions like

  addItem("egg", 5)             Add 5 eggs to the inventory.
  addItems("sword", "shield")   Add sword & shield to backpack.
  equip("sword", "hand_r")      Equip sword in right hand.
  Sack.push("sword")            Move sword from hand to backpack.
  consume("egg")                Eat 1 egg and feel the effects.
  minusOne("egg")               Remove 1 egg from inventory.
                                Works for non-stackables as well.
  mixPotion()                   Create 1 potion. Works only when there
                                are at least 2 suitable ingredients
                                in any of the slots "p1"-"p4".


Every item in the universe has an entry in the dictionary `items`.

When a new kind of item is crafted, it should be added to `items` dict.

When an item is placed in the inventory, its reference in `items`
receives `place` (the name of the slot where that item goes).


  items["shield"]["place"] = "hand_l"

means item "shield" goes to the left hand (= slot named "hand_l").

Likewise, when a stackable item appears in the inventory,
its reference in `items` receives "amount" value.


  items["egg"]["amount"] = 3

Each item (single or stack) in the inventory has a corresponding
`drag` element in the `inventory` screen.


There are several inventory screens:

  * `manslots` shows equipment slots on the character figure.
  * `potions` is a crafting screen with slots for alchemy ingredients.
  * `smithy` is another crafting screen (under development).

Unique slots of every screen have entries in corresponding dictionaries:
"manslots", "potions", "smithy".

These entries contain positions (x, y) in pixels of the slot on screen;
slot size (px) and field "item". If there's an item in that slot,
the name of an item is recorded there. E.g.:

  potions["p1"]["item"] = "egg"

Every name of an item is a unique identifier, there's only 1 item
(single or stack) with that name.

If another item of that kind would be necessary, it would get another
name and entry in `items` (like "egg000123").

Slot names should be unique too. Even in different screens there must
be no slots with the same name. Slot names should not start with "bk_",
because such names are recognized as backpack cells.


`backpack` is a common element of all inventory screens.

Its slots (cells) have always the same positions, calculated as a grid;
so there is no need to store their (x, y). Therefore data collection
`backpack` is just a list with 8*8=64 elements.

It contains names of items in those cells. E.g.:

  backpack[0] = "sword"

means that the left-top cell of the backpack contains sword.

Backpack cells as drag areas have drag_name's like "bk_0", "bk_1" etc.


  `items`     {} all the items in the game

Drop areas:
  `backpack` [] names of items in the backpack
  `manslots` {} character equipment slots (params + names of items there)
  `potions`  {} crafting potions slots (params + names of items there)
  `smithy`   {} crafting smithy slots (params + names of items there)

Screen `inventory`

It is switchable between variants: "manslots", "potions", "smithy".

Dict `drops` references current drop areas for the screen variant. So:

  default drops = manslots

means that the initial screen variant is character slots.

Then switching to screen "potions" looks like:

    SetVariable("screenType", "potions"),
    SetVariable("drops", potions)

In action

Moving between backpack and other screen slots can be done by clicking
or drag-n-dropping.

Dragging or hovering an item makes its suitable slots highlighted.

`manslots` has slot "eat", to be used with consumables.

`backpack` cells can be highlighted with colored background, according
to the type of item there.

`potions` slots are used to put there ingredients and create a potion.

Moving an item from one slot to another involves updating data
both for those slots and for the item. For example, to move
item "egg" in "potions" drop areas from slot "p1" to "p2":

  potions["p1"]["item"] = None       # or use `unequip("egg")`
  potions["p2"]["item"] = "egg"
  items["egg"]["place"] = "p2"

Moving the egg to a backpack cell #5 for example would be similar,

  backpack[5] = "egg"
  items["egg"]["place"] = "bk_5"

Also to clean the data for the previous slot of the egg, do first

  oldSlot = items["egg"]["place"]
  drops[oldSlot] = None

provided that `drops` dict is the reference to currently active
screen slots. For example,

  drops = potions

In practice, to put items in the backpack, just use `Sack.push()`:

  Sack.push("egg", cell="bk_5")

or to put the item in whatever empty backpack cell:


In these examples, if there is a stack of several eggs, then
the item "egg" is treated as the whole stack.

E.g. if player drops eggs onto slot "eat", it consumes 1 egg,
and internally it's:

  items["egg"]["amount"] -= 1

The remaining stack falls back in its backpack cell, or
disappears if there was only 1 egg in the stack.

Removing the item from inventory is done by cleaning its slot
and setting

  items[name]["place"] = None

where name is "egg" for example. And if the item was a stackable,

  items[name]["amount"] = 0

(removing "amount" key from items[name] works too).

In practice it's more convenient to use functions

  equip(itemName, slotName)  to equip in a slot

  minusOne(itemName)         to remove an item from inventory,
                             or remove 1 piece if it's a stack
  addItem(name [, amount])   to add item (or stack) to inventory
  addItems(*items)           to add different items in one go

  Sack.push(name [, amount, cell])  to move item to the backpack

  consume(item)              remove 1 item and run its effects

  mixPotion()                create 1 potion, spending 1 ingredient
                             from each slot "p1", "p2", "p3", "p4"

No copyright, public domain.

The demo is made and should be run with Ren'Py SDK at least 8.1. Earlier Ren'Py 8 versions would give errors (complaining about unknown variable config.check_conflicting_properties). If you want to use this with Ren'Py 7, you would need to rework the code a bit, as it uses some Python 3 magic.

Version 1.6:
(1.28 MiB) Downloaded 6 times
First version:
(537.52 KiB) Downloaded 46 times

Re: Inventory RPG-style

Posted: Sat Jun 03, 2023 11:58 pm
by Andredron

Re: Inventory RPG-style

Posted: Fri Jun 16, 2023 4:03 pm
by jeffster
Andredron wrote: Sat Jun 03, 2023 11:58 pm 👍👍👍
Updated to v1.1

Re: Inventory RPG-style

Posted: Mon Jun 19, 2023 8:19 am
by jeffster
Andredron wrote: Sat Jun 03, 2023 11:58 pm 👍👍👍
Updated to 1.3. Crafting etc.

Re: Inventory RPG-style

Posted: Tue Jun 20, 2023 7:46 am
by jeffster
v1.4. Some improvements. More explanations/documentation.

Re: Inventory RPG-style

Posted: Wed Jun 21, 2023 6:50 am
by jeffster
v1.5. More documentation. Some algorithms were reworked to be user-friendlier.
Now it's more like a usable framework than just a sketch.