347 lines
10 KiB
Markdown
347 lines
10 KiB
Markdown
|
---
|
||
|
title: ItemStacks und Inventare
|
||
|
layout: default
|
||
|
root: ../..
|
||
|
idx: 2.4
|
||
|
description: Manipuliere InvRefs und ItemStacks
|
||
|
redirect_from:
|
||
|
- /de/chapters/inventories.html
|
||
|
- /de/chapters/itemstacks.html
|
||
|
- /de/inventories/inventories.html
|
||
|
- /de/inventories/itemstacks.html
|
||
|
---
|
||
|
|
||
|
## Einleitung <!-- omit in toc -->
|
||
|
|
||
|
In diesem Kapitel werden Sie lernen, wie man Inventare verwendet und manipuliert, egal ob
|
||
|
ob es sich um ein Spielerinventar, ein Knoteninventar oder ein freistehendes Inventar handelt.
|
||
|
|
||
|
- [Was sind ItemStacks und Inventare?](#was-sind-itemstacks-und-inventare)
|
||
|
- [ItemStacks](#itemstacks)
|
||
|
- [Inventarstandorte](#inventarstandorte)
|
||
|
- [Lists](#lists)
|
||
|
- [Size and Width](#size-and-width)
|
||
|
- [Checking Contents](#checking-contents)
|
||
|
- [Modifying Inventories and ItemStacks](#modifying-inventories-and-itemstacks)
|
||
|
- [Adding to a List](#adding-to-a-list)
|
||
|
- [Taking Items](#taking-items)
|
||
|
- [Manipulating Stacks](#manipulating-stacks)
|
||
|
- [Wear](#wear)
|
||
|
- [Lua Tables](#lua-tables)
|
||
|
|
||
|
## Was sind ItemStacks und Inventare?
|
||
|
|
||
|
Ein ItemStack sind die Daten hinter einer einzelnen Zelle in einem Inventar.
|
||
|
|
||
|
Ein *Inventar* ist eine Sammlung von *Inventarlisten*, von denen jede
|
||
|
ein 2D-Gitter aus ItemStacks ist.
|
||
|
Inventarlisten werden im Kontext von Inventaren einfach *Listen* genannt.
|
||
|
Der Sinn eines Inventars ist es, mehrere Raster zu ermöglichen, wenn Spieler
|
||
|
und Blöcke nur maximal ein Inventar haben.
|
||
|
|
||
|
## ItemStacks
|
||
|
|
||
|
ItemStacks haben vier Komponenten: name, count, wear und metadata.
|
||
|
|
||
|
Der Itemname kann der Itemname eines registrierten Items, ein Alias oder ein
|
||
|
unbekannter Itemname sein.
|
||
|
Unbekannte Items treten häufig auf, wenn Benutzer Mods deinstallieren oder wenn Mods
|
||
|
Items ohne Vorsichtsmaßnahmen entfernen, z. B. durch die Registrierung von Aliasen.
|
||
|
|
||
|
```lua
|
||
|
print(stack:get_name())
|
||
|
stack:set_name("default:dirt")
|
||
|
|
||
|
if not stack:is_known() then
|
||
|
print("Ist ein unbekanntes Item!")
|
||
|
end
|
||
|
```
|
||
|
|
||
|
Der Anzahl wird immer 0 oder größer sein.
|
||
|
Bei normalem Spielverlauf sollte die Anzahl nicht größer sein als die maximale
|
||
|
Stackgröße des Gegenstands - `stack_max`.
|
||
|
Allerdings können Admin-Befehle und fehlerhafte Mods dazu führen, dass Stacks die maximale Größe überschreiten.
|
||
|
|
||
|
```lua
|
||
|
print(stack:get_stack_max())
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Ein ItemStack kann leer sein, in diesem Fall ist die Anzahl 0.
|
||
|
|
||
|
```lua
|
||
|
print(stack:get_count())
|
||
|
stack:set_count(10)
|
||
|
```
|
||
|
|
||
|
ItemStacks können auf verschiedene Weise mit der Funktion ItemStack konstruiert werden.
|
||
|
|
||
|
|
||
|
```lua
|
||
|
ItemStack() -- name="", count=0
|
||
|
ItemStack("default:pick_stone") -- count=1
|
||
|
ItemStack("default:stone 30")
|
||
|
ItemStack({ name = "default:wood", count = 10 })
|
||
|
```
|
||
|
|
||
|
Item-Metadaten sind ein unbegrenzter Schlüssel-Wert-Speicher für Daten über das Item.
|
||
|
Schlüssel-Wert bedeutet, dass Sie einen Namen (den sogenannten key) verwenden, um auf die Daten (den sogenannten value) zuzugreifen.
|
||
|
Einige Schlüssel haben eine besondere Bedeutung, wie z. B. `Beschreibung`, die verwendet wird, um eine pro Stack
|
||
|
Beschreibung.
|
||
|
Dies wird im Kapitel über Metadaten und Speicherung ausführlicher behandelt.
|
||
|
|
||
|
## Inventarstandorte
|
||
|
|
||
|
Ein Inventarstandort ist der Ort und die Art und Weise, wie das Inventar gespeichert wird.
|
||
|
Es gibt drei Arten von Inventarstandorten: Spieler, Blöcke und freistehend.
|
||
|
Ein Inventar ist direkt an einen und nur einen Ort gebunden - eine Aktualisierung des
|
||
|
Inventars wird es sofort aktualisieren.
|
||
|
|
||
|
Blockinventare beziehen sich auf die Position eines bestimmten Blockes, z. B. einer Truhe.
|
||
|
Der Block muss geladen werden, da er in den [Block-Metadaten](../map/storage.html#metadata) gespeichert ist.
|
||
|
|
||
|
```lua
|
||
|
local inv = minetest.get_inventory({ type="node", pos={x=1, y=2, z=3} })
|
||
|
```
|
||
|
|
||
|
Auf diese Weise erhält man eine *Inventar-Referenz*, allgemein als *InvRef* bezeichnet.
|
||
|
Inventar-Referenzen werden verwendet, um ein Inventar zu manipulieren.
|
||
|
*Referenz* bedeutet, dass die Daten nicht tatsächlich in diesem Objekt gespeichert sind,
|
||
|
sondern das Objekt aktualisiert die Daten direkt an Ort und Stelle.
|
||
|
|
||
|
Der Standort eines Inventarverweises kann wie folgt ermittelt werden:
|
||
|
|
||
|
```lua
|
||
|
local location = inv:get_location()
|
||
|
```
|
||
|
|
||
|
Spielerinventare können auf ähnliche Weise oder über eine Spielerreferenz abgerufen werden.
|
||
|
Der Spieler muss online sein, um auf sein Inventar zugreifen zu können.
|
||
|
|
||
|
```lua
|
||
|
local inv = minetest.get_inventory({ type="player", name="spieler1" })
|
||
|
-- oder
|
||
|
local inv = player:get_inventory()
|
||
|
```
|
||
|
|
||
|
Ein freistehendes Inventar ist ein Inventar, das unabhängig von Spielern oder Blöcken ist.
|
||
|
Freistehende Inventare werden auch nicht bei einem Neustart gespeichert.
|
||
|
|
||
|
```lua
|
||
|
local inv = minetest.get_inventory({
|
||
|
type="detached", name="inventar_name" })
|
||
|
```
|
||
|
|
||
|
Im Gegensatz zu den anderen Inventararten müssen Sie zunächst ein freistehendes Inventar erstellen
|
||
|
erstellen, bevor Sie darauf zugreifen:
|
||
|
```lua
|
||
|
minetest.create_detached_inventory("inventar_name")
|
||
|
```
|
||
|
|
||
|
Die Funktion create_detached_inventory akzeptiert 3 Argumente, wobei nur das erste -
|
||
|
der Inventarname - erforderlich ist.
|
||
|
Das zweite Argument nimmt eine Tabelle von Callbacks entgegen, die verwendet werden können,
|
||
|
um zu steuern, wie Spieler mit dem Inventar interagieren:
|
||
|
|
||
|
```lua
|
||
|
-- Eingabe nur freistehendes Inventar
|
||
|
minetest.create_detached_inventory("inventar_name", {
|
||
|
allow_move = function(inv, von_liste, von_index, zu_liste, zu_index, anzahl, player)
|
||
|
return anzahl -- erlaubt bewegen
|
||
|
end,
|
||
|
|
||
|
allow_put = function(inv, listenname, index, stack, spieler)
|
||
|
return stack:get_count() -- erlaubt setzen
|
||
|
end,
|
||
|
|
||
|
allow_take = function(inv, listenname, index, stack, spieler)
|
||
|
return 0 -- erlaubt es nicht zu nehmen
|
||
|
end,
|
||
|
|
||
|
on_put = function(inv, listenname, index, stack, spieler)
|
||
|
minetest.chat_send_all(spieler:get_player_name() ..
|
||
|
" gab " .. stack:to_string() ..
|
||
|
" zu der Spendenkiste von " .. minetest.pos_to_string(spieler:get_pos()))
|
||
|
end,
|
||
|
})
|
||
|
```
|
||
|
|
||
|
Berechtigungsaufrufe - d.h. diejenigen, die mit `allow_` beginnen - geben die Anzahl
|
||
|
der zu übertragenden Items zurück, wobei 0 verwendet wird, um die Übertragung vollständig zu verhindern.
|
||
|
|
||
|
Im Gegensatz dazu haben Aktionsrückrufe - beginnend mit `on_` - keinen Rückgabewert.
|
||
|
|
||
|
## Lists
|
||
|
|
||
|
Inventory Lists are a concept used to allow multiple grids to be stored inside a single location.
|
||
|
This is especially useful for the player as there are a number of common lists
|
||
|
which all games have, such as the *main* inventory and *craft* slots.
|
||
|
|
||
|
### Size and Width
|
||
|
|
||
|
Lists have a size, which is the total number of cells in the grid, and a width,
|
||
|
which is only used within the engine.
|
||
|
The width of the list is not used when drawing the inventory in a window,
|
||
|
because the code behind the window determines the width to use.
|
||
|
|
||
|
```lua
|
||
|
if inv:set_size("main", 32) then
|
||
|
inv:set_width("main", 8)
|
||
|
print("size: " .. inv:get_size("main"))
|
||
|
print("width: " .. inv:get_width("main"))
|
||
|
else
|
||
|
print("Error! Invalid itemname or size to set_size()")
|
||
|
end
|
||
|
```
|
||
|
|
||
|
`set_size` will fail and return false if the listname or size is invalid.
|
||
|
For example, the new size may be too small to fit all the current items
|
||
|
in the inventory.
|
||
|
|
||
|
### Checking Contents
|
||
|
|
||
|
`is_empty` can be used to see if a list contains any items:
|
||
|
|
||
|
```lua
|
||
|
if inv:is_empty("main") then
|
||
|
print("The list is empty!")
|
||
|
end
|
||
|
```
|
||
|
|
||
|
`contains_item` can be used to see if a list contains a specific item:
|
||
|
|
||
|
```lua
|
||
|
if inv:contains_item("main", "default:stone") then
|
||
|
print("I've found some stone!")
|
||
|
end
|
||
|
```
|
||
|
|
||
|
## Modifying Inventories and ItemStacks
|
||
|
|
||
|
### Adding to a List
|
||
|
|
||
|
`add_item` adds items to a list (in this case `"main"`). In the example below,
|
||
|
the maximum stack size is also respected:
|
||
|
|
||
|
```lua
|
||
|
local stack = ItemStack("default:stone 99")
|
||
|
local leftover = inv:add_item("main", stack)
|
||
|
if leftover:get_count() > 0 then
|
||
|
print("Inventory is full! " ..
|
||
|
leftover:get_count() .. " items weren't added")
|
||
|
end
|
||
|
```
|
||
|
|
||
|
### Taking Items
|
||
|
|
||
|
To remove items from a list:
|
||
|
|
||
|
```lua
|
||
|
local taken = inv:remove_item("main", stack)
|
||
|
print("Took " .. taken:get_count())
|
||
|
```
|
||
|
|
||
|
### Manipulating Stacks
|
||
|
|
||
|
You can modify individual stacks by first getting them:
|
||
|
|
||
|
```lua
|
||
|
local stack = inv:get_stack(listname, 0)
|
||
|
```
|
||
|
|
||
|
Then modifying them by setting properties or by using the methods which
|
||
|
respect `stack_size`:
|
||
|
|
||
|
|
||
|
```lua
|
||
|
local stack = ItemStack("default:stone 50")
|
||
|
local to_add = ItemStack("default:stone 100")
|
||
|
local leftover = stack:add_item(to_add)
|
||
|
local taken = stack:take_item(19)
|
||
|
|
||
|
print("Could not add" .. leftover:get_count() .. " of the items.")
|
||
|
-- ^ will be 51
|
||
|
|
||
|
print("Have " .. stack:get_count() .. " items")
|
||
|
-- ^ will be 80
|
||
|
-- min(50+100, stack_max) - 19 = 80
|
||
|
-- where stack_max = 99
|
||
|
```
|
||
|
|
||
|
`add_item` will add items to an ItemStack and return any that could not be added.
|
||
|
`take_item` will take up to the number of items but may take less, and returns the stack taken.
|
||
|
|
||
|
Finally, set the item stack:
|
||
|
|
||
|
```lua
|
||
|
inv:set_stack(listname, 0, stack)
|
||
|
```
|
||
|
|
||
|
## Wear
|
||
|
|
||
|
Tools can have wear; wear shows a progress bar and makes the tool break when completely worn.
|
||
|
Wear is a number out of 65535; the higher it is, the more worn the tool is.
|
||
|
|
||
|
Wear can be manipulated using `add_wear()`, `get_wear()`, and `set_wear(wear)`.
|
||
|
|
||
|
```lua
|
||
|
local stack = ItemStack("default:pick_mese")
|
||
|
local max_uses = 10
|
||
|
|
||
|
-- This is done automatically when you use a tool that digs things
|
||
|
-- It increases the wear of an item by one use.
|
||
|
stack:add_wear(65535 / (max_uses - 1))
|
||
|
```
|
||
|
|
||
|
When digging a node, the amount of wear a tool gets may depend on the node
|
||
|
being dug. So max_uses varies depending on what is being dug.
|
||
|
|
||
|
## Lua Tables
|
||
|
|
||
|
ItemStacks and Inventories can be converted to and from tables.
|
||
|
This is useful for copying and bulk operations.
|
||
|
|
||
|
```lua
|
||
|
-- Entire inventory
|
||
|
local data = inv1:get_lists()
|
||
|
inv2:set_lists(data)
|
||
|
|
||
|
-- One list
|
||
|
local listdata = inv1:get_list("main")
|
||
|
inv2:set_list("main", listdata)
|
||
|
```
|
||
|
|
||
|
The table of lists returned by `get_lists()` will be in this form:
|
||
|
|
||
|
```lua
|
||
|
{
|
||
|
list_one = {
|
||
|
ItemStack,
|
||
|
ItemStack,
|
||
|
ItemStack,
|
||
|
ItemStack,
|
||
|
-- inv:get_size("list_one") elements
|
||
|
},
|
||
|
list_two = {
|
||
|
ItemStack,
|
||
|
ItemStack,
|
||
|
ItemStack,
|
||
|
ItemStack,
|
||
|
-- inv:get_size("list_two") elements
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
`get_list()` will return a single list as just a list of ItemStacks.
|
||
|
|
||
|
One important thing to note is that the set methods above don't change the size
|
||
|
of the lists.
|
||
|
This means that you can clear a list by setting it to an empty table and it won't
|
||
|
decrease in size:
|
||
|
|
||
|
```lua
|
||
|
inv:set_list("main", {})
|
||
|
```
|