Add itemdropping unified_inventory and toolranks with modded nether support

This commit is contained in:
MistUnky 2021-04-26 23:52:52 -04:00
parent 0a3cab9719
commit 9be932d884
107 changed files with 5571 additions and 0 deletions

View File

@ -0,0 +1,19 @@
unused_args = false
allow_defined_top = true
max_line_length = 999
ignore = {
"name", "drops", "i",
}
globals = {
"minetest",
}
read_globals = {
string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn"}},
"vector", "ItemStack",
"dump",
}

View File

@ -0,0 +1,3 @@
- The `master` branch should be stable to end-users at all times. It should target latest Minetest point release.
- Put rewrites and new features in branches.
- Conform with setting defaults so that end-user upgrades doesn't change expected in-game behavior. Discuss default changes in an issue if one really need to change.

View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
(This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.)
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
{signature of Ty Coon}, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -0,0 +1,60 @@
# Item Drop [![](https://github.com/minetest-mods/item_drop/workflows/build/badge.svg)](https://github.com/minetest-mods/item_drop/actions) [![License](https://img.shields.io/badge/license-LGPLv2.1%2B-blue.svg)](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
A highly configurable mod providing item magnet and in-world node drops\
By [PilzAdam](https://github.com/PilzAdam),
[texmex](https://github.com/tacotexmex/), [hybriddog](https://github.com/hybriddog/).
## Licensing
LGPLv2.1/CC BY-SA 3.0. Particle code from WCILA mod by Aurailus, originally licensed MIT.
## Notes
`item_drop` can be played with Minetest 0.4.16 or above. It was originally
developed by [PilzAdam](https://github.com/PilzAdam/item_drop).
## List of features
* All settings may be configured from within the game itself.
(Settings tab > Advanced settings > Mods > item_drop)
* Drops nodes as in-world items on dig if `item_drop.enable_item_drop` is
`true` (true by default) It does nothing in creative mode.
* Puts dropped items to the player's inventory if `item_drop.enable_item_pickup`
is `true` (true by default)
* Multiple items are picked in a quick succession instead of all at once which
is indicated by the pickup sound.
* It uses a node radius set in `item_drop.pickup_radius` (default 0.75),
if items are within this radius around the player's belt, they're picked.
* If `item_drop.pickup_age` is something positive, items dropped by players
are ignored for this time to avoid instantly picking up when dropping.
* If `item_drop.pickup_age` is `-1`, items are only picked when they don't
move, it's another fix for instant item picking.
* If `item_drop.magnet_radius` is bigger than `item_drop.pickup_radius`,
items between these radii are flying to the player for
`item_drop.magnet_time` seconds, after this time, they're picked or stop
flying.
* Enable manual item pickups by mouse only if `item_drop.mouse_pickup` is
`true` (true by default)
* Plays a sound when the items are picked up with the gain level set to
`item_drop.pickup_sound_gain` (default 0.2)
* Requires a key to be pressed in order to pick items if
`item_drop.enable_pickup_key` is `true` (true by default)
* The keytypes to choose from by setting `item_pickup_keytype` are:
* Use key (`Use`)
* Sneak key (`Sneak`)
* Left and Right keys combined (`LeftAndRight`)
* Right mouse button (`RMB`)
* Sneak key and right mouse button combined (`SneakAndRMB`)
* If `item_drop.pickup_keyinvert` is `true`, items are
collected when the key is not pressed instead of when it's pressed.
* Displays a particle of the picked item above the player if
`item_drop.pickup_particle` is `true` (true by default)
## Known issues
## Bug reports and suggestions
You can report bugs or suggest ideas by
[filing an issue](http://github.com/minetest-mods/item_drop/issues/new).
## Links
* [Download ZIP](https://github.com/minetest-mods/item_drop/archive/master.zip)
* [Source](https://github.com/minetest-mods/item_drop/)
* [Forum thread](https://forum.minetest.net/viewtopic.php?t=16913)

View File

@ -0,0 +1 @@
A highly configurable mod providing item magnet and in-world node drops

View File

@ -0,0 +1,424 @@
local load_time_start = minetest.get_us_time()
-- Functions which can be overridden by mods
item_drop = {
-- This function is executed before picking up an item or making it fly to
-- the player. If it does not return true, the item is ignored.
-- It is also executed before collecting the item after it flew to
-- the player and did not reach him/her for magnet_time seconds.
can_pickup = function(entity, player)
if entity.item_drop_picked then
-- Ignore items where picking has already failed
return false
end
return true
end,
-- before_collect and after_collect are executed before and after an item
-- is collected by a player
before_collect = function(entity, pos, player)
end,
after_collect = function(entity, pos, player)
entity.item_drop_picked = true
end,
}
local function legacy_setting_getbool(name_new, name_old, default)
local v = minetest.settings:get_bool(name_new)
if v == nil then
v = minetest.settings:get_bool(name_new)
end
if default then
return v ~= false
end
return v
end
local function legacy_setting_getnumber(name_new, name_old, default)
return tonumber(minetest.settings:get(name_new))
or tonumber(minetest.settings:get(name_old))
or default
end
if legacy_setting_getbool("item_drop.enable_item_pickup",
"enable_item_pickup", true) then
local pickup_gain = legacy_setting_getnumber("item_drop.pickup_sound_gain",
"item_pickup_gain", 0.2)
local pickup_particle =
minetest.settings:get_bool("item_drop.pickup_particle", true)
local pickup_radius = legacy_setting_getnumber("item_drop.pickup_radius",
"item_pickup_radius", 0.75)
local magnet_radius = tonumber(
minetest.settings:get("item_drop.magnet_radius")) or -1
local magnet_time = tonumber(
minetest.settings:get("item_drop.magnet_time")) or 5.0
local pickup_age = tonumber(
minetest.settings:get("item_drop.pickup_age")) or 0.5
local key_triggered = legacy_setting_getbool("item_drop.enable_pickup_key",
"enable_item_pickup_key", true)
local key_invert = minetest.settings:get_bool(
"item_drop.pickup_keyinvert") ~= false
local keytype
if key_triggered then
keytype = minetest.settings:get("item_drop.pickup_keytype") or
minetest.settings:get("item_pickup_keytype") or "Use"
-- disable pickup age if picking is explicitly enabled by the player
if not key_invert then
pickup_age = math.min(pickup_age, 0)
end
end
local mouse_pickup = minetest.settings:get_bool(
"item_drop.mouse_pickup") ~= false
if not mouse_pickup then
minetest.registered_entities["__builtin:item"].pointable = false
end
local magnet_mode = magnet_radius > pickup_radius
local zero_velocity_mode = pickup_age == -1
if magnet_mode
and zero_velocity_mode then
error"zero velocity mode can't be used together with magnet mode"
end
-- tells whether an inventorycube should be shown as pickup_particle or not
-- for known drawtypes
local inventorycube_drawtypes = {
normal = true,
allfaces = true,
allfaces_optional = true,
glasslike = true,
glasslike_framed = true,
glasslike_framed_optional = true,
liquid = true,
flowingliquid = true,
}
-- adds the item to the inventory and removes the object
local function collect_item(ent, pos, player)
item_drop.before_collect(ent, pos, player)
minetest.sound_play("item_drop_pickup", {
pos = pos,
gain = pickup_gain,
})
if pickup_particle then
local item = minetest.registered_nodes[
ent.itemstring:gsub("(.*)%s.*$", "%1")]
local image
if item and item.tiles and item.tiles[1] then
if inventorycube_drawtypes[item.drawtype] then
local tiles = item.tiles
local top = tiles[1]
if type(top) == "table" then
top = top.name
end
local left = tiles[3] or top
if type(left) == "table" then
left = left.name
end
local right = tiles[5] or left
if type(right) == "table" then
right = right.name
end
image = minetest.inventorycube(top, left, right)
else
image = item.inventory_image or item.tiles[1]
end
minetest.add_particle({
pos = {x = pos.x, y = pos.y + 1.5, z = pos.z},
velocity = {x = 0, y = 1, z = 0},
acceleration = {x = 0, y = -4, z = 0},
expirationtime = 0.2,
size = 3,--math.random() + 0.5,
vertical = false,
texture = image,
})
end
end
ent:on_punch(player)
item_drop.after_collect(ent, pos, player)
end
-- opt_get_ent gets the object's luaentity if it can be collected
local opt_get_ent
if zero_velocity_mode then
function opt_get_ent(object)
if object:is_player()
or not vector.equals(object:get_velocity(), {x=0, y=0, z=0}) then
return
end
local ent = object:get_luaentity()
if not ent
or ent.name ~= "__builtin:item"
or ent.itemstring == "" then
return
end
return ent
end
else
function opt_get_ent(object)
if object:is_player() then
return
end
local ent = object:get_luaentity()
if not ent
or ent.name ~= "__builtin:item"
or (ent.dropped_by and ent.age < pickup_age)
or ent.itemstring == "" then
return
end
return ent
end
end
local afterflight
if magnet_mode then
-- take item or reset velocity after flying a second
function afterflight(object, inv, player)
-- TODO: test what happens if player left the game
local ent = opt_get_ent(object)
if not ent then
return
end
local item = ItemStack(ent.itemstring)
if inv
and inv:room_for_item("main", item)
and item_drop.can_pickup(ent, player) then
collect_item(ent, object:get_pos(), player)
else
-- the acceleration will be reset by the object's on_step
object:set_velocity({x=0,y=0,z=0})
ent.is_magnet_item = false
end
end
-- disable velocity and acceleration changes of items flying to players
minetest.after(0, function()
local ObjectRef
local blocked_methods = {"set_acceleration", "set_velocity",
"setacceleration", "setvelocity"}
local itemdef = minetest.registered_entities["__builtin:item"]
local old_on_step = itemdef.on_step
local function do_nothing() end
function itemdef.on_step(self, ...)
if not self.is_magnet_item then
return old_on_step(self, ...)
end
ObjectRef = ObjectRef or getmetatable(self.object)
local old_funcs = {}
for i = 1, #blocked_methods do
local method = blocked_methods[i]
old_funcs[method] = ObjectRef[method]
ObjectRef[method] = do_nothing
end
old_on_step(self, ...)
for i = 1, #blocked_methods do
local method = blocked_methods[i]
ObjectRef[method] = old_funcs[method]
end
end
end)
end
-- set keytype to the key name if possible
if keytype == "Use" then
keytype = "aux1"
elseif keytype == "Sneak" then
keytype = "sneak"
elseif keytype == "LeftAndRight" then -- LeftAndRight combination
keytype = 0
elseif keytype == "SneakAndRMB" then -- SneakAndRMB combination
keytype = 1
end
-- tests if the player has the keys pressed to enable item picking
local function has_keys_pressed(player)
if not key_triggered then
return true
end
local control = player:get_player_control()
local keys_pressed
if keytype == 0 then -- LeftAndRight combination
keys_pressed = control.left and control.right
elseif keytype == 1 then -- SneakAndRMB combination
keys_pressed = control.sneak and control.RMB
else
keys_pressed = control[keytype]
end
return keys_pressed ~= key_invert
end
local function is_inside_map(pos)
local bound = 31000
return -bound < pos.x and pos.x < bound
and -bound < pos.y and pos.y < bound
and -bound < pos.z and pos.z < bound
end
-- called for each player to possibly collect an item, returns true if so
local function pickupfunc(player)
if not has_keys_pressed(player)
or not minetest.get_player_privs(player:get_player_name()).interact
or player:get_hp() <= 0 then
return
end
local pos = player:get_pos()
if not is_inside_map(pos) then
-- get_objects_inside_radius crashes for too far positions
return
end
pos.y = pos.y+0.5
local inv = player:get_inventory()
local objectlist = minetest.get_objects_inside_radius(pos,
magnet_mode and magnet_radius or pickup_radius)
for i = 1,#objectlist do
local object = objectlist[i]
local ent = opt_get_ent(object)
if ent
and item_drop.can_pickup(ent, player) then
local item = ItemStack(ent.itemstring)
if inv:room_for_item("main", item) then
local flying_item
local pos2
if magnet_mode then
pos2 = object:get_pos()
flying_item = vector.distance(pos, pos2) > pickup_radius
end
if not flying_item then
-- The item is near enough to pick it
collect_item(ent, pos, player)
-- Collect one item at a time to avoid the loud pop
return true
end
-- The item is not too far a way but near enough to be
-- magnetised, make it fly to the player
local vel = vector.multiply(vector.subtract(pos, pos2), 3)
vel.y = vel.y + 0.6
object:set_velocity(vel)
if not ent.is_magnet_item then
ent.object:set_acceleration({x=0, y=0, z=0})
ent.is_magnet_item = true
minetest.after(magnet_time, afterflight,
object, inv, player)
end
end
end
end
end
local function pickup_step()
local got_item
local players = minetest.get_connected_players()
for i = 1,#players do
got_item = got_item or pickupfunc(players[i])
end
-- lower step if takeable item(s) were found
local time
if got_item then
time = 0.02
else
time = 0.2
end
minetest.after(time, pickup_step)
end
minetest.after(3.0, pickup_step)
end
if legacy_setting_getbool("item_drop.enable_item_drop", "enable_item_drop", true)
and not minetest.settings:get_bool("creative_mode") then
-- Workaround to test if an item metadata (ItemStackMetaRef) is empty
local function itemmeta_is_empty(meta)
local t = meta:to_table()
for k, v in pairs(t) do
if k ~= "fields" then
return false
end
assert(type(v) == "table")
if next(v) ~= nil then
return false
end
end
return true
end
-- Tests if the item has special information such as metadata
local function can_split_item(item)
return item:get_wear() == 0 and itemmeta_is_empty(item:get_meta())
end
local function spawn_items(pos, items_to_spawn)
for i = 1,#items_to_spawn do
local obj = minetest.add_item(pos, items_to_spawn[i])
if not obj then
error("Couldn't spawn item " .. name .. ", drops: "
.. dump(drops))
end
local vel = obj:get_velocity()
local x = math.random(-5, 4)
if x >= 0 then
x = x+1
end
vel.x = 1 / x
local z = math.random(-5, 4)
if z >= 0 then
z = z+1
end
vel.z = 1 / z
obj:set_velocity(vel)
end
end
local old_handle_node_drops = minetest.handle_node_drops
function minetest.handle_node_drops(pos, drops, player)
if not player or player.is_fake_player then
-- Node Breaker or similar machines should receive items in the
-- inventory
return old_handle_node_drops(pos, drops, player)
end
for i = 1,#drops do
local item = drops[i]
if type(item) == "string" then
-- The string is not necessarily only the item name,
-- so always convert it to ItemStack
item = ItemStack(item)
end
local count = item:get_count()
local name = item:get_name()
-- Sometimes nothing should be dropped
if name == ""
or not minetest.registered_items[name] then
count = 0
end
if count > 0 then
-- Split items if possible
local items_to_spawn = {item}
if can_split_item(item) then
for i = 1,count do
items_to_spawn[i] = name
end
end
spawn_items(pos, items_to_spawn)
end
end
end
end
local time = (minetest.get_us_time() - load_time_start) / 1000000
local msg = "[item_drop] loaded after ca. " .. time .. " seconds."
if time > 0.01 then
print(msg)
else
minetest.log("info", msg)
end

View File

@ -0,0 +1,2 @@
name = item_drop
description = A highly configurable mod providing item magnet and in-world node drops

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

View File

@ -0,0 +1,38 @@
#Pick up items automatically
item_drop.enable_item_pickup (Enable item pickups) bool true
#Drop items in-world on dig, does nothing in creative mode
item_drop.enable_item_drop (Enable item drops) bool true
#Use a key to pick up items
item_drop.enable_pickup_key (Use pickup key) bool true
#Collect items when the key is not pressed instead of when it is pressed
item_drop.pickup_keyinvert (Invert pickup key) bool true
#What keytype to use as pickup key
item_drop.pickup_keytype (Pickup keytype) enum Use Use,Sneak,LeftAndRight,RMB,SneakAndRMB
#The volume of the pickup sound
item_drop.pickup_sound_gain (Pickup sound gain) float 0.4
#Display a particle of the item picked up above the player
item_drop.pickup_particle (Pickup particle) bool true
#Player pickup radius, the maximum distance from which items can be collected
item_drop.pickup_radius (Pickup radius) float 0.75
#Magnet radius, items between pickup_radius and this begin flying to the player
#Set it to -1 (or something else smaller than pickup_radius) to disable item
#flying
item_drop.magnet_radius (Magnet radius) float -1
#Item flight duration, items flying for more than this time are added to the
#player's inventory
item_drop.magnet_time (Magnet time) float 5.0
#Time delay in seconds after autopicking an item if it's dropped by a player
item_drop.pickup_age (Pickup age) float 0.5
#Enable manual item pickups by mouse
item_drop.mouse_pickup (Mouse pickup) bool true

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@ -0,0 +1,20 @@
# minetest-toolranks
Minetest tool ranks mod
## Original mod by lisacvuk
https://github.com/lisacvuk/minetest-toolranks
Tool gains levels for digging nodes. Higher level tools take longer to
wear out.
## Are you a mod developer?
Does one of your mods add new tools?
If so, to support this mod, check if it is loaded with
```minetest.get_modpath("toolranks")```
and then replace all after_use definitions with toolranks.new_afteruse.
Optionaly, you can also replace tools description with
```toolranks.create_description("Tool Name", 0, 1)```
and then set original_description to your tools name.
### This is a fork
Yep, this is a simplified version of toolranks with lesser dependencies.

View File

@ -0,0 +1 @@
default

View File

@ -0,0 +1,141 @@
toolranks = {
colors = {
grey = minetest.get_color_escape_sequence("#9d9d9d"),
green = minetest.get_color_escape_sequence("#1eff00"),
gold = minetest.get_color_escape_sequence("#ffdf00"),
white = minetest.get_color_escape_sequence("#ffffff")
}
}
function toolranks.create_description(name, uses, level)
return toolranks.colors.green .. (name or "") .. "\n"
.. toolranks.colors.gold .. "Level: " .. (level or 1) .. "\n"
.. toolranks.colors.grey .. "Used: " .. (uses or 0) .. " times"
end
function toolranks.get_level(uses)
if uses >= 3200 then
return 6
elseif uses >= 2000 then
return 5
elseif uses >= 1000 then
return 4
elseif uses >= 400 then
return 3
elseif uses >= 200 then
return 2
else
return 1
end
end
function toolranks.new_afteruse(itemstack, user, node, digparams)
-- Get tool metadata and number of times used
local itemmeta = itemstack:get_meta()
local dugnodes = tonumber(itemmeta:get_string("dug")) or 0
-- Only count nodes that spend the tool
if digparams.wear > 0 then
dugnodes = dugnodes + 1
itemmeta:set_string("dug", dugnodes)
else
return
end
-- Get tool description and last level
local itemdef = itemstack:get_definition()
local itemdesc = itemdef.original_description or itemdef.description or "Tool"
local lastlevel = tonumber(itemmeta:get_string("lastlevel")) or 1
local name = user:get_player_name()
-- Warn player when tool is almost broken
if itemstack:get_wear() > 60100 then
minetest.chat_send_player(name,
toolranks.colors.gold .. "Your tool is almost broken!")
minetest.sound_play("default_tool_breaks", {
to_player = name,
gain = 1.0
})
end
local level = toolranks.get_level(dugnodes)
-- Alert player when tool has leveled up
if lastlevel < level then
minetest.chat_send_player(name, "Your "
.. toolranks.colors.green .. itemdesc
.. toolranks.colors.white .. " just leveled up!")
minetest.sound_play("toolranks_levelup", {
to_player = name,
gain = 1.0
})
itemmeta:set_string("lastlevel", level)
end
-- Set new meta
itemmeta:set_string("description",
toolranks.create_description(itemdesc, dugnodes, level))
local wear = digparams.wear
-- Set wear level
if level > 1 then
wear = digparams.wear * 4 / (4 + level)
end
itemstack:add_wear(wear)
return itemstack
end
-- Default tool list
local tools = {
"default:sword_wood", "default:sword_stone", "default:sword_steel",
"default:sword_bronze", "default:sword_mese", "default:sword_diamond",
"default:pick_wood", "default:pick_stone", "default:pick_steel",
"default:pick_bronze", "default:pick_mese", "default:pick_diamond",
"default:axe_wood", "default:axe_stone", "default:axe_steel",
"default:axe_bronze", "default:axe_mese", "default:axe_diamond",
"default:shovel_wood", "default:shovel_stone", "default:shovel_steel",
"default:shovel_bronze", "default:shovel_mese", "default:shovel_diamond",
--"nether:shovel_nether", "nether:axe_nether", "nether:sword_nether",
--"nether:pick_nether",
}
-- Loop through tool list and add new toolranks description
for n = 1, #tools do
local name = tools[n]
local def = minetest.registered_tools[name]
local desc = def and def.description
if desc then
minetest.override_item(name, {
original_description = desc,
description = toolranks.create_description(desc),
after_use = toolranks.new_afteruse
})
end
end

View File

@ -0,0 +1,2 @@
Code: LGPLv2.1+
Sounds: CC BY 3.0

View File

@ -0,0 +1,4 @@
name = toolranks
depends = default
optional_depends =
description = Add ability to level up tools to make them last longer.

Binary file not shown.

View File

@ -0,0 +1,20 @@
unused_args = false
allow_defined_top = true
max_line_length = 999
globals = {
"unified_inventory",
}
read_globals = {
string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn"}},
"minetest", "vector",
"ItemStack", "datastorage",
"hb",
}
files["callbacks.lua"].ignore = { "player", "draw_lite_mode" }
files["bags.lua"].ignore = { "player" }

View File

@ -0,0 +1,19 @@
Unified Inventory for Minetest
Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Contact information:
Examine a git patch to get the contributor's email address.

View File

@ -0,0 +1,99 @@
# Unified Inventory
[![](https://github.com/minetest-mods/unified_inventory/workflows/Check%20&%20Release/badge.svg)](https://github.com/minetest-mods/unified_inventory/actions)
![Screenshot](screenshot.png)
Unified Inventory replaces the default survival and creative inventory.
## Features
* Node, item and tool browser
* Crafting guide
* Can copy the recipe to the crafting grid
* Recipe search function by ingredients
* Up to four bags with up to 24 slots each
* Home function to teleport
* Trash slot
* Lite mode: reduces the item browser width
* `minetest.conf` setting `unified_inventory_lite = true`
* Mod API for modders: see [mod_api.txt](doc/mod_api.txt)
* Setting-determinated features: see [settingtypes.txt](settingtypes.txt)
## Requirements
* Minetest 5.4.0+
# Licenses
Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel)
Copyright (C) 2012-? Various minetest-mods contributors
## Code
GNU LGPLv2+, see [license notice](LICENSE.txt)
## Textures
VanessaE: (CC-BY-4.0)
* `ui_group.png`
Tango Project: (Public Domain, CC-BY-4.0)
* [`ui_reset_icon.png`](https://commons.wikimedia.org/wiki/File:Edit-clear.svg)
* [`ui_doubleleft_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-backward.svg)
* [`ui_doubleright_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-forward.svg)
* [`ui_left_icon.png` / `ui_right_icon.png`](http://commons.wikimedia.org/wiki/File:Media-playback-start.svg)
* [`ui_skip_backward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-backward.svg)
* [`ui_skip_forward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg)
From http://www.clker.com (Public Domain, CC-BY-4.0):
* [`bags_small.png`](http://www.clker.com/clipart-moneybag-empty.html)
* [`bags_medium.png`](http://www.clker.com/clipart-backpack-1.html)
* [`bags_large.png` / `ui_bags_icon.png`](http://www.clker.com/clipart-backpack-green-brown.html)
* `ui_trash_icon.png`: <http://www.clker.com/clipart-29090.html> and <http://www.clker.com/clipart-trash.html>
* [`ui_search_icon.png`](http://www.clker.com/clipart-24887.html)
* [`ui_off_icon.png` / `ui_on_icon.png`](http://www.clker.com/clipart-on-off-switches.html)
* [`ui_waypoints_icon.png`](http://www.clker.com/clipart-map-pin-red.html)
* [`ui_circular_arrows_icon.png`](http://www.clker.com/clipart-circular-arrow-pattern.html)
* [`ui_pencil_icon.pnc`](http://www.clker.com/clipart-2256.html)
* [`ui_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html)
Everaldo Coelho (YellowIcon) (LGPL v2.1+):
* [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png)
Gregory H. Revera: (CC-BY-SA 3.0)
* [`ui_moon_icon.png`](http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg)
Thomas Bresson: (CC-BY 3.0)
* [`ui_sun_icon.png`](http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg)
Fibonacci: (Public domain, CC-BY 4.0)
* [`ui_xyz_off_icon.png`](http://commons.wikimedia.org/wiki/File:No_sign.svg)
Gregory Maxwell: (Public domain, CC-BY 4.0)
* [`ui_ok_icon.png`](http://commons.wikimedia.org/wiki/File:Yes_check.svg)
Adrien Facélina: (LGPL v2.1+)
* [`inventory_plus_worldedit_gui.png`](http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg)
Other files from Wikimedia Commons:
* [`ui_gohome_icon.png` / `ui_home_icon.png` / `ui_sethome_icon.png`](http://commons.wikimedia.org/wiki/File:Home_256x256.png) (GPL v2+)
RealBadAngel: (CC-BY-4.0)
* Everything else.

View File

@ -0,0 +1,333 @@
local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape
local ui = unified_inventory
-- Create detached creative inventory after loading all mods
minetest.after(0.01, function()
local rev_aliases = {}
for source, target in pairs(minetest.registered_aliases) do
if not rev_aliases[target] then rev_aliases[target] = {} end
table.insert(rev_aliases[target], source)
end
ui.items_list = {}
for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or
def.groups.not_in_creative_inventory == 0) and
def.description and def.description ~= "" then
table.insert(ui.items_list, name)
local all_names = rev_aliases[name] or {}
table.insert(all_names, name)
for _, player_name in ipairs(all_names) do
local recipes = minetest.get_all_craft_recipes(player_name)
if recipes then
for _, recipe in ipairs(recipes) do
local unknowns
for _,chk in pairs(recipe.items) do
local groupchk = string.find(chk, "group:")
if (not groupchk and not minetest.registered_items[chk])
or (groupchk and not ui.get_group_item(string.gsub(chk, "group:", "")).item)
or minetest.get_item_group(chk, "not_in_craft_guide") ~= 0 then
unknowns = true
end
end
if not unknowns then
ui.register_craft(recipe)
end
end
end
end
end
end
table.sort(ui.items_list)
ui.items_list_size = #ui.items_list
print("Unified Inventory. inventory size: "..ui.items_list_size)
for _, name in ipairs(ui.items_list) do
local def = minetest.registered_items[name]
-- Simple drops
if type(def.drop) == "string" then
local dstack = ItemStack(def.drop)
if not dstack:is_empty() and dstack:get_name() ~= name then
ui.register_craft({
type = "digging",
items = {name},
output = def.drop,
width = 0,
})
end
-- Complex drops. Yes, it's really complex!
elseif type(def.drop) == "table" then
--[[ Extract single items from the table and save them into dedicated tables
to register them later, in order to avoid duplicates. These tables counts
the total number of guaranteed drops and drops by chance (maybes) for each item.
For maybes, the final count is the theoretical maximum number of items, not
neccessarily the actual drop count. ]]
local drop_guaranteed = {}
local drop_maybe = {}
-- This is for catching an obscure corner case: If the top items table has
-- only items with rarity = 1, but max_items is set, then only the first
-- max_items will be part of the drop, any later entries are logically
-- impossible, so this variable is for keeping track of this
local max_items_left = def.drop.max_items
-- For checking whether we still encountered only guaranteed only so far;
-- for the first “maybe” item it will become false which will cause ALL
-- later items to be considered “maybes”.
-- A common idiom is:
-- { max_items 1, { items = {
-- { items={"example:1"}, rarity = 5 },
-- { items={"example:2"}, rarity = 1 }, }}}
-- example:2 must be considered a “maybe” because max_items is set and it
-- appears after a “maybe”
local max_start = true
-- Let's iterate through the items madness!
-- Handle invalid drop entries gracefully.
local drop_items = def.drop.items or { }
for i=1,#drop_items do
if max_items_left ~= nil and max_items_left <= 0 then break end
local itit = drop_items[i]
for j=1,#itit.items do
local dstack = ItemStack(itit.items[j])
if not dstack:is_empty() and dstack:get_name() ~= name then
local dname = dstack:get_name()
local dcount = dstack:get_count()
-- Guaranteed drops AND we are not yet in “maybe mode”
if #itit.items == 1 and itit.rarity == 1 and max_start then
if drop_guaranteed[dname] == nil then
drop_guaranteed[dname] = 0
end
drop_guaranteed[dname] = drop_guaranteed[dname] + dcount
if max_items_left ~= nil then
max_items_left = max_items_left - 1
if max_items_left <= 0 then break end
end
-- Drop was a “maybe”
else
if max_items_left ~= nil then max_start = false end
if drop_maybe[dname] == nil then
drop_maybe[dname] = 0
end
drop_maybe[dname] = drop_maybe[dname] + dcount
end
end
end
end
for itemstring, count in pairs(drop_guaranteed) do
ui.register_craft({
type = "digging",
items = {name},
output = itemstring .. " " .. count,
width = 0,
})
end
for itemstring, count in pairs(drop_maybe) do
ui.register_craft({
type = "digging_chance",
items = {name},
output = itemstring .. " " .. count,
width = 0,
})
end
end
end
for _, recipes in pairs(ui.crafts_for.recipe) do
for _, recipe in ipairs(recipes) do
local ingredient_items = {}
for _, spec in pairs(recipe.items) do
local matches_spec = ui.canonical_item_spec_matcher(spec)
for _, name in ipairs(ui.items_list) do
if matches_spec(name) then
ingredient_items[name] = true
end
end
end
for name, _ in pairs(ingredient_items) do
if ui.crafts_for.usage[name] == nil then
ui.crafts_for.usage[name] = {}
end
table.insert(ui.crafts_for.usage[name], recipe)
end
end
end
end)
-- load_home
local function load_home()
local input = io.open(ui.home_filename, "r")
if not input then
ui.home_pos = {}
return
end
while true do
local x = input:read("*n")
if not x then break end
local y = input:read("*n")
local z = input:read("*n")
local name = input:read("*l")
ui.home_pos[name:sub(2)] = {x = x, y = y, z = z}
end
io.close(input)
end
load_home()
function ui.set_home(player, pos)
local player_name = player:get_player_name()
ui.home_pos[player_name] = vector.round(pos)
-- save the home data from the table to the file
local output = io.open(ui.home_filename, "w")
for k, v in pairs(ui.home_pos) do
output:write(v.x.." "..v.y.." "..v.z.." "..k.."\n")
end
io.close(output)
end
function ui.go_home(player)
local pos = ui.home_pos[player:get_player_name()]
if pos then
player:set_pos(pos)
return true
end
return false
end
-- register_craft
function ui.register_craft(options)
if not options.output then
return
end
local itemstack = ItemStack(options.output)
if itemstack:is_empty() then
return
end
if options.type == "normal" and options.width == 0 then
options = { type = "shapeless", items = options.items, output = options.output, width = 0 }
end
if not ui.crafts_for.recipe[itemstack:get_name()] then
ui.crafts_for.recipe[itemstack:get_name()] = {}
end
table.insert(ui.crafts_for.recipe[itemstack:get_name()],options)
end
local craft_type_defaults = {
width = 3,
height = 3,
uses_crafting_grid = false,
}
function ui.craft_type_defaults(name, options)
if not options.description then
options.description = name
end
setmetatable(options, {__index = craft_type_defaults})
return options
end
function ui.register_craft_type(name, options)
ui.registered_craft_types[name] =
ui.craft_type_defaults(name, options)
end
ui.register_craft_type("normal", {
description = F(S("Crafting")),
icon = "ui_craftgrid_icon.png",
width = 3,
height = 3,
get_shaped_craft_width = function (craft) return craft.width end,
dynamic_display_size = function (craft)
local w = craft.width
local h = math.ceil(table.maxn(craft.items) / craft.width)
local g = w < h and h or w
return { width = g, height = g }
end,
uses_crafting_grid = true,
})
ui.register_craft_type("shapeless", {
description = F(S("Mixing")),
icon = "ui_craftgrid_icon.png",
width = 3,
height = 3,
dynamic_display_size = function (craft)
local maxn = table.maxn(craft.items)
local g = 1
while g*g < maxn do g = g + 1 end
return { width = g, height = g }
end,
uses_crafting_grid = true,
})
ui.register_craft_type("cooking", {
description = F(S("Cooking")),
icon = "default_furnace_front.png",
width = 1,
height = 1,
})
ui.register_craft_type("digging", {
description = F(S("Digging")),
icon = "default_tool_steelpick.png",
width = 1,
height = 1,
})
ui.register_craft_type("digging_chance", {
description = "Digging (by chance)",
icon = "default_tool_steelpick.png^[transformFY.png",
width = 1,
height = 1,
})
function ui.register_page(name, def)
ui.pages[name] = def
end
function ui.register_button(name, def)
if not def.action then
def.action = function(player)
ui.set_inventory_formspec(player, name)
end
end
def.name = name
table.insert(ui.buttons, def)
end
function ui.is_creative(playername)
return minetest.check_player_privs(playername, {creative=true})
or minetest.settings:get_bool("creative_mode")
end
function ui.single_slot(xpos, ypos, bright)
return string.format("background9[%f,%f;%f,%f;ui_single_slot%s.png;false;16]",
xpos, ypos, ui.imgscale, ui.imgscale, (bright and "_bright" or "") )
end
function ui.make_trash_slot(xpos, ypos)
return
ui.single_slot(xpos, ypos)..
"image["..xpos..","..ypos..";1.25,1.25;ui_trash_slot_icon.png]"..
"list[detached:trash;main;"..(xpos + ui.list_img_offset)..","..(ypos + ui.list_img_offset)..";1,1;]"
end
function ui.make_inv_img_grid(xpos, ypos, width, height, bright)
local tiled = {}
local n=1
for y = 0, (height - 1) do
for x = 0, (width -1) do
tiled[n] = ui.single_slot(xpos + (ui.imgscale * x), ypos + (ui.imgscale * y), bright)
n = n + 1
end
end
return table.concat(tiled)
end

View File

@ -0,0 +1,280 @@
--[[
Bags for Minetest
Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com>
License: GPLv3
--]]
local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape
local ui = unified_inventory
ui.register_page("bags", {
get_formspec = function(player)
local player_name = player:get_player_name()
return { formspec = table.concat({
ui.style_full.standard_inv_bg,
ui.single_slot(0.925, 1.5),
ui.single_slot(3.425, 1.5),
ui.single_slot(5.925, 1.5),
ui.single_slot(8.425, 1.5),
"label["..ui.style_full.form_header_x..","..ui.style_full.form_header_y..";" .. F(S("Bags")) .. "]",
"button[0.6125,2.75;1.875,0.75;bag1;" .. F(S("Bag @1", 1)) .. "]",
"button[3.1125,2.75;1.875,0.75;bag2;" .. F(S("Bag @1", 2)) .. "]",
"button[5.6125,2.75;1.875,0.75;bag3;" .. F(S("Bag @1", 3)) .. "]",
"button[8.1125,2.75;1.875,0.75;bag4;" .. F(S("Bag @1", 4)) .. "]",
"listcolors[#00000000;#00000000]",
"list[detached:" .. F(player_name) .. "_bags;bag1;1.075,1.65;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag2;3.575,1.65;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag3;6.075,1.65;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag4;8.575,1.65;1,1;]"
}) }
end,
})
ui.register_button("bags", {
type = "image",
image = "ui_bags_icon.png",
tooltip = S("Bags"),
hide_lite=true
})
local function get_player_bag_stack(player, i)
return minetest.get_inventory({
type = "detached",
name = player:get_player_name() .. "_bags"
}):get_stack("bag" .. i, 1)
end
for bag_i = 1, 4 do
ui.register_page("bag" .. bag_i, {
get_formspec = function(player)
local stack = get_player_bag_stack(player, bag_i)
local image = stack:get_definition().inventory_image
local slots = stack:get_definition().groups.bagslots
local formspec = {
ui.style_full.standard_inv_bg,
ui.make_inv_img_grid(0.3, 1.5, 8, slots/8),
"image[9.2,0.4;1,1;" .. image .. "]",
"label[0.3,0.65;" .. F(S("Bag @1", bag_i)) .. "]",
"listcolors[#00000000;#00000000]",
"listring[current_player;main]",
string.format("list[current_player;bag%icontents;%f,%f;8,3;]",
bag_i, 0.3 + ui.list_img_offset, 1.5 + ui.list_img_offset),
"listring[current_name;bag" .. bag_i .. "contents]",
}
local n = #formspec + 1
local player_name = player:get_player_name() -- For if statement.
if ui.trash_enabled
or ui.is_creative(player_name)
or minetest.get_player_privs(player_name).give then
formspec[n] = ui.make_trash_slot(7.8, 0.25)
n = n + 1
end
local inv = player:get_inventory()
for i = 1, 4 do
local def = get_player_bag_stack(player, i):get_definition()
if def.groups.bagslots then
local list_name = "bag" .. i .. "contents"
local size = inv:get_size(list_name)
local used = 0
for si = 1, size do
local stk = inv:get_stack(list_name, si)
if not stk:is_empty() then
used = used + 1
end
end
local img = def.inventory_image
local label = F(S("Bag @1", i)) .. "\n" .. used .. "/" .. size
formspec[n] = string.format("image_button[%f,0.4;1,1;%s;bag%i;%s]",
(i + 1.35)*1.25, img, i, label)
n = n + 1
end
end
return { formspec = table.concat(formspec) }
end,
})
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then
return
end
for i = 1, 4 do
if fields["bag" .. i] then
local stack = get_player_bag_stack(player, i)
if not stack:get_definition().groups.bagslots then
return
end
ui.set_inventory_formspec(player, "bag" .. i)
return
end
end
end)
local function save_bags_metadata(player, bags_inv)
local is_empty = true
local bags = {}
for i = 1, 4 do
local bag = "bag" .. i
if not bags_inv:is_empty(bag) then
-- Stack limit is 1, otherwise use stack:to_string()
bags[i] = bags_inv:get_stack(bag, 1):get_name()
is_empty = false
end
end
local meta = player:get_meta()
if is_empty then
meta:set_string("unified_inventory:bags", nil)
else
meta:set_string("unified_inventory:bags",
minetest.serialize(bags))
end
end
local function load_bags_metadata(player, bags_inv)
local player_inv = player:get_inventory()
local meta = player:get_meta()
local bags_meta = meta:get("unified_inventory:bags")
local bags = bags_meta and minetest.deserialize(bags_meta) or {}
local dirty_meta = false
if not bags_meta then
-- Backwards compatiblity
for i = 1, 4 do
local bag = "bag" .. i
if not player_inv:is_empty(bag) then
-- Stack limit is 1, otherwise use stack:to_string()
bags[i] = player_inv:get_stack(bag, 1):get_name()
dirty_meta = true
end
end
end
-- Fill detached slots
for i = 1, 4 do
local bag = "bag" .. i
bags_inv:set_size(bag, 1)
bags_inv:set_stack(bag, 1, bags[i] or "")
end
if dirty_meta then
-- Requires detached inventory to be set up
save_bags_metadata(player, bags_inv)
end
-- Clean up deprecated garbage after saving
for i = 1, 4 do
local bag = "bag" .. i
player_inv:set_size(bag, 0)
end
end
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
local bags_inv = minetest.create_detached_inventory(player_name .. "_bags",{
on_put = function(inv, listname, index, stack, player)
player:get_inventory():set_size(listname .. "contents",
stack:get_definition().groups.bagslots)
save_bags_metadata(player, inv)
end,
allow_put = function(inv, listname, index, stack, player)
local new_slots = stack:get_definition().groups.bagslots
if not new_slots then
return 0
end
local player_inv = player:get_inventory()
local old_slots = player_inv:get_size(listname .. "contents")
if new_slots >= old_slots then
return 1
end
-- using a smaller bag, make sure it fits
local old_list = player_inv:get_list(listname .. "contents")
local new_list = {}
local slots_used = 0
local use_new_list = false
for i, v in ipairs(old_list) do
if v and not v:is_empty() then
slots_used = slots_used + 1
use_new_list = i > new_slots
new_list[slots_used] = v
end
end
if new_slots >= slots_used then
if use_new_list then
player_inv:set_list(listname .. "contents", new_list)
end
return 1
end
-- New bag is smaller: Disallow inserting
return 0
end,
allow_take = function(inv, listname, index, stack, player)
if player:get_inventory():is_empty(listname .. "contents") then
return stack:get_count()
end
return 0
end,
on_take = function(inv, listname, index, stack, player)
player:get_inventory():set_size(listname .. "contents", 0)
save_bags_metadata(player, inv)
end,
allow_move = function()
return 0
end,
}, player_name)
load_bags_metadata(player, bags_inv)
end)
-- register bag tools
minetest.register_tool("unified_inventory:bag_small", {
description = S("Small Bag"),
inventory_image = "bags_small.png",
groups = {bagslots=8},
})
minetest.register_tool("unified_inventory:bag_medium", {
description = S("Medium Bag"),
inventory_image = "bags_medium.png",
groups = {bagslots=16},
})
minetest.register_tool("unified_inventory:bag_large", {
description = S("Large Bag"),
inventory_image = "bags_large.png",
groups = {bagslots=24},
})
-- register bag crafts
if minetest.get_modpath("farming") ~= nil then
minetest.register_craft({
output = "unified_inventory:bag_small",
recipe = {
{"", "farming:string", ""},
{"group:wool", "group:wool", "group:wool"},
{"group:wool", "group:wool", "group:wool"},
},
})
minetest.register_craft({
output = "unified_inventory:bag_medium",
recipe = {
{"", "", ""},
{"farming:string", "unified_inventory:bag_small", "farming:string"},
{"farming:string", "unified_inventory:bag_small", "farming:string"},
},
})
minetest.register_craft({
output = "unified_inventory:bag_large",
recipe = {
{"", "", ""},
{"farming:string", "unified_inventory:bag_medium", "farming:string"},
{"farming:string", "unified_inventory:bag_medium", "farming:string"},
},
})
end

View File

@ -0,0 +1,214 @@
local function default_refill(stack)
stack:set_count(stack:get_stack_max())
local itemdef = minetest.registered_items[stack:get_name()]
if itemdef
and (itemdef.wear_represents or "mechanical_wear") == "mechanical_wear"
and stack:get_wear() ~= 0 then
stack:set_wear(0)
end
return stack
end
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
unified_inventory.players[player_name] = {}
unified_inventory.current_index[player_name] = 1
unified_inventory.filtered_items_list[player_name] =
unified_inventory.items_list
unified_inventory.activefilter[player_name] = ""
unified_inventory.active_search_direction[player_name] = "nochange"
unified_inventory.apply_filter(player, "", "nochange")
unified_inventory.current_searchbox[player_name] = ""
unified_inventory.alternate[player_name] = 1
unified_inventory.current_item[player_name] = nil
unified_inventory.current_craft_direction[player_name] = "recipe"
unified_inventory.set_inventory_formspec(player,
unified_inventory.default)
-- Refill slot
local refill = minetest.create_detached_inventory(player_name.."refill", {
allow_put = function(inv, listname, index, stack, player)
if unified_inventory.is_creative(player_name) then
return stack:get_count()
else
return 0
end
end,
on_put = function(inv, listname, index, stack, player)
local handle_refill = (minetest.registered_items[stack:get_name()] or {}).on_refill or default_refill
stack = handle_refill(stack)
inv:set_stack(listname, index, stack)
minetest.sound_play("electricity",
{to_player=player_name, gain = 1.0})
end,
}, player_name)
refill:set_size("main", 1)
end)
local function apply_new_filter(player, search_text, new_dir)
local player_name = player:get_player_name()
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
unified_inventory.apply_filter(player, search_text, new_dir)
unified_inventory.current_searchbox[player_name] = search_text
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local player_name = player:get_player_name()
local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name)
if formname ~= "" then
return
end
-- always take new search text, even if not searching on it yet
if fields.searchbox
and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then
unified_inventory.current_searchbox[player_name] = fields.searchbox
end
for i, def in pairs(unified_inventory.buttons) do
if fields[def.name] then
def.action(player)
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
return
end
end
-- Inventory page controls
local start = math.floor(
unified_inventory.current_index[player_name] / ui_peruser.items_per_page + 1)
local start_i = start
local pagemax = math.floor(
(#unified_inventory.filtered_items_list[player_name] - 1)
/ (ui_peruser.items_per_page) + 1)
if fields.start_list then
start_i = 1
end
if fields.rewind1 then
start_i = start_i - 1
end
if fields.forward1 then
start_i = start_i + 1
end
if fields.rewind3 then
start_i = start_i - 3
end
if fields.forward3 then
start_i = start_i + 3
end
if fields.end_list then
start_i = pagemax
end
if start_i < 1 then
start_i = 1
end
if start_i > pagemax then
start_i = pagemax
end
if start_i ~= start then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
unified_inventory.current_index[player_name] = (start_i - 1) * ui_peruser.items_per_page + 1
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
-- Check clicked item image button
local clicked_item
for name, value in pairs(fields) do
local new_dir, mangled_item = string.match(name, "^item_button_([a-z]+)_(.*)$")
if new_dir and mangled_item then
clicked_item = unified_inventory.demangle_for_formspec(mangled_item)
if string.sub(clicked_item, 1, 6) == "group:" then
-- Change search filter to this group
apply_new_filter(player, clicked_item, new_dir)
return
end
if new_dir == "recipe" or new_dir == "usage" then
unified_inventory.current_craft_direction[player_name] = new_dir
end
break
end
end
if clicked_item then
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
local page = unified_inventory.current_page[player_name]
local player_creative = unified_inventory.is_creative(player_name)
if not player_creative then
page = "craftguide"
end
if page == "craftguide" then
unified_inventory.current_item[player_name] = clicked_item
unified_inventory.alternate[player_name] = 1
unified_inventory.set_inventory_formspec(player, "craftguide")
elseif player_creative then
-- Creative page: Add entire stack to inventory
local inv = player:get_inventory()
local stack = ItemStack(clicked_item)
stack:set_count(stack:get_stack_max())
if inv:room_for_item("main", stack) then
inv:add_item("main", stack)
end
end
end
if fields.searchbutton
or fields.key_enter_field == "searchbox" then
unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name], "nochange")
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
minetest.sound_play("paperflip2",
{to_player=player_name, gain = 1.0})
elseif fields.searchresetbutton then
apply_new_filter(player, "", "nochange")
end
-- alternate buttons
if not (fields.alternate or fields.alternate_prev) then
return
end
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
local item_name = unified_inventory.current_item[player_name]
if not item_name then
return
end
local crafts = unified_inventory.crafts_for[unified_inventory.current_craft_direction[player_name]][item_name]
if not crafts then
return
end
local alternates = #crafts
if alternates <= 1 then
return
end
local alternate
if fields.alternate then
alternate = unified_inventory.alternate[player_name] + 1
if alternate > alternates then
alternate = 1
end
elseif fields.alternate_prev then
alternate = unified_inventory.alternate[player_name] - 1
if alternate < 1 then
alternate = alternates
end
end
unified_inventory.alternate[player_name] = alternate
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end)
if minetest.delete_detached_inventory then
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
minetest.delete_detached_inventory(player_name.."_bags")
minetest.delete_detached_inventory(player_name.."craftrecipe")
minetest.delete_detached_inventory(player_name.."refill")
end)
end

View File

@ -0,0 +1,103 @@
unified_inventory API
=====================
This file provides information about the API of unified_inventory.
API revisions within unified_inventory can be checked using:
(unified_inventory.version or 1)
**Revision history**
* Version `1`: Classic formspec layout (no real_coordinates)
* Version `2`: Force formspec version 4 (includes real_coordinates)
Misc functions
--------------
Grouped by use-case, afterwards sorted alphabetically.
* `unified_inventory.is_creative(name)`
* Checks whether creative is enabled or the player has `creative`
Pages
-----
Register a new page: The callback inside this function is called on user input.
unified_inventory.register_page("pagename", {
get_formspec = function(player)
-- ^ `player` is an `ObjectRef`
-- Compute the formspec string here
return {
formspec = "button[2,2;2,1;mybutton;Press me]",
-- ^ Final form of the formspec to display
draw_inventory = false, -- default `true`
-- ^ Optional. Hides the player's `main` inventory list
draw_item_list = false, -- default `true`
-- ^ Optional. Hides the item list on the right side
formspec_prepend = false, -- default `false`
-- ^ Optional. When `false`: Disables the formspec prepend
}
end,
})
Buttons
-------
Register a new button for the bottom row:
unified_inventory.register_button("skins", {
type = "image",
image = "skins_skin_button.png",
tooltip = "Skins",
hide_lite = true
-- ^ Button is hidden when following two conditions are met:
-- Configuration line `unified_inventory_lite = true`
-- Player does not have the privilege `ui_full`
})
Crafting
--------
The code blocks below document each possible parameter using exemplary values.
Provide information to display custom craft types:
unified_inventory.register_craft_type("mytype", {
-- ^ Unique identifier for `register_craft`
description = "Sample Craft",
-- ^ Text shown below the crafting arrow
icon = "dummy.png",
-- ^ Image shown above the crafting arrow
width = 3,
height = 3,
-- ^ Maximal input dimensions of the recipes
dynamic_display_size = function(craft)
-- ^ `craft` is the definition from `register_craft`
return {
width = 2,
height = 3
}
end,
-- ^ Optional callback to change the displayed recipe size
uses_crafting_grid = true,
})
Register a non-standard craft recipe:
unified_inventory.register_craft({
output = "default:foobar",
type = "mytype",
-- ^ Standard craft type or custom (see `register_craft_type`)
items = {
{ "default:foo" },
{ "default:bar" }
},
width = 3,
-- ^ Same as `minetest.register_recipe`
})

View File

@ -0,0 +1,127 @@
local S = minetest.get_translator("unified_inventory")
function unified_inventory.canonical_item_spec_matcher(spec)
local specname = ItemStack(spec):get_name()
if specname:sub(1, 6) ~= "group:" then
return function (itemname)
return itemname == specname
end
end
local group_names = specname:sub(7):split(",")
return function (itemname)
local itemdef = minetest.registered_items[itemname]
for _, group_name in ipairs(group_names) do
if (itemdef.groups[group_name] or 0) == 0 then
return false
end
end
return true
end
end
function unified_inventory.item_matches_spec(item, spec)
local itemname = ItemStack(item):get_name()
return unified_inventory.canonical_item_spec_matcher(spec)(itemname)
end
function unified_inventory.extract_groupnames(groupname)
local specname = ItemStack(groupname):get_name()
if specname:sub(1, 6) ~= "group:" then
return nil, 0
end
local group_names = specname:sub(7):split(",")
return table.concat(group_names, S(" and ")), #group_names
end
unified_inventory.registered_group_items = {
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
stone = "default:cobble",
wood = "default:wood",
book = "default:book",
sand = "default:sand",
leaves = "default:leaves",
tree = "default:tree",
vessel = "vessels:glass_bottle",
wool = "wool:white",
}
function unified_inventory.register_group_item(groupname, itemname)
unified_inventory.registered_group_items[groupname] = itemname
end
-- This is used when displaying craft recipes, where an ingredient is
-- specified by group rather than as a specific item. A single-item group
-- is represented by that item, with the single-item status signalled
-- in the "sole" field. If the group contains no items at all, the item
-- field will be nil.
--
-- Within a multiple-item group, we prefer to use an item that has the
-- same specific name as the group, and if there are more than one of
-- those items we prefer the one registered for the group by a mod.
-- Among equally-preferred items, we just pick the one with the
-- lexicographically earliest name.
--
-- The parameter to this function isn't just a single group name.
-- It may be a comma-separated list of group names. This is really a
-- "group:..." ingredient specification, minus the "group:" prefix.
local function compute_group_item(group_name_list)
local group_names = group_name_list:split(",")
local candidate_items = {}
for itemname, itemdef in pairs(minetest.registered_items) do
if (itemdef.groups.not_in_creative_inventory or 0) == 0 then
local all = true
for _, group_name in ipairs(group_names) do
if (itemdef.groups[group_name] or 0) == 0 then
all = false
end
end
if all then table.insert(candidate_items, itemname) end
end
end
local num_candidates = #candidate_items
if num_candidates == 0 then
return {sole = true}
elseif num_candidates == 1 then
return {item = candidate_items[1], sole = true}
end
local is_group = {}
local registered_rep = {}
for _, group_name in ipairs(group_names) do
is_group[group_name] = true
local rep = unified_inventory.registered_group_items[group_name]
if rep then registered_rep[rep] = true end
end
local bestitem = ""
local bestpref = 0
for _, item in ipairs(candidate_items) do
local pref
if registered_rep[item] then
pref = 4
elseif string.sub(item, 1, 8) == "default:" and is_group[string.sub(item, 9)] then
pref = 3
elseif is_group[item:gsub("^[^:]*:", "")] then
pref = 2
else
pref = 1
end
if pref > bestpref or (pref == bestpref and item < bestitem) then
bestitem = item
bestpref = pref
end
end
return {item = bestitem, sole = false}
end
local group_item_cache = {}
function unified_inventory.get_group_item(group_name)
if not group_item_cache[group_name] then
group_item_cache[group_name] = compute_group_item(group_name)
end
return group_item_cache[group_name]
end

View File

@ -0,0 +1,69 @@
bags_small.png:
http://www.clker.com/clipart-moneybag-empty.html
bags_medium.png:
http://www.clker.com/clipart-backpack-1.html
bags_large.png / ui_bags_icon.png:
http://www.clker.com/clipart-backpack-green-brown.html
ui_craftguide_icon.png / ui_craft_icon.png
http://commons.wikimedia.org/wiki/File:Advancedsettings.png
ui_doubleleft_icon.png
http://commons.wikimedia.org/wiki/File:Media-seek-backward.svg
ui_doubleright_icon.png
http://commons.wikimedia.org/wiki/File:Media-seek-forward.svg
ui_left_icon.png / ui_right_icon.png
http://commons.wikimedia.org/wiki/File:Media-playback-start.svg
ui_skip_backward_icon.png
http://commons.wikimedia.org/wiki/File:Media-skip-backward.svg
ui_skip_forward_icon.png
http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg
ui_reset_icon.png
https://commons.wikimedia.org/wiki/File:Edit-clear.svg
ui_gohome_icon.png / ui_home_icon.png / ui_sethome_icon.png
http://commons.wikimedia.org/wiki/File:Home_256x256.png
ui_moon_icon.png
http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg
ui_sun_icon.png
http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg
ui_trash_icon.png
http://www.clker.com/clipart-29090.html
http://www.clker.com/clipart-trash.html
ui_search_icon.png
http://www.clker.com/clipart-24887.html
ui_off_icon.png / ui_on_icon.png
http://www.clker.com/clipart-on-off-switches.html
ui_waypoints_icon.png
http://www.clker.com/clipart-map-pin-red.html
ui_circular_arrows_icon.png
http://www.clker.com/clipart-circular-arrow-pattern.html
ui_pencil_icon.pnc
http://www.clker.com/clipart-2256.html
ui_waypoint_set_icon.png
http://www.clker.com/clipart-larger-flag.html
ui_xyz_off_icon.png
http://commons.wikimedia.org/wiki/File:No_sign.svg
ui_ok_icon.png
http://commons.wikimedia.org/wiki/File:Yes_check.svg
inventory_plus_worldedit_gui.png
http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg

View File

@ -0,0 +1,161 @@
-- Unified Inventory for Minetest >= 0.4.16
local modpath = minetest.get_modpath(minetest.get_current_modname())
local worldpath = minetest.get_worldpath()
-- Data tables definitions
unified_inventory = {
activefilter = {},
active_search_direction = {},
alternate = {},
current_page = {},
current_searchbox = {},
current_index = {},
current_item = {},
current_craft_direction = {},
registered_craft_types = {},
crafts_for = {usage = {}, recipe = {} },
players = {},
items_list_size = 0,
items_list = {},
filtered_items_list_size = {},
filtered_items_list = {},
pages = {},
buttons = {},
-- Homepos stuff
home_pos = {},
home_filename = worldpath.."/unified_inventory_home.home",
-- Default inventory page
default = "craft",
-- "Lite" mode
lite_mode = minetest.settings:get_bool("unified_inventory_lite"),
-- Trash enabled
trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false),
imgscale = 1.25,
list_img_offset = 0.13,
standard_background = "background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]",
version = 2
}
local ui = unified_inventory
-- These tables establish position and layout for the two UI styles.
-- UI doesn't use formspec_[xy] anymore, but other mods may need them.
ui.style_full = {
formspec_x = 1,
formspec_y = 1,
pagecols = 8,
pagerows = 10,
page_x = 10.75,
page_y = 1.45,
craft_x = 2.8,
craft_y = 1.15,
craftresult_x = 7.8,
craft_arrow_x = 6.55,
craft_guide_x = 3.3,
craft_guide_y = 1.15,
craft_guide_arrow_x = 7.05,
craft_guide_result_x = 8.3,
craft_guide_resultstr_x = 0.3,
craft_guide_resultstr_y = 0.6,
give_btn_x = 0.25,
main_button_x = 0.4,
main_button_y = 11.0,
page_buttons_x = 11.60,
page_buttons_y = 10.15,
searchwidth = 3.4,
form_header_x = 0.4,
form_header_y = 0.4,
btn_spc = 0.85,
btn_size = 0.75,
std_inv_x = 0.3,
std_inv_y = 5.75,
}
ui.style_lite = {
formspec_x = 0.6,
formspec_y = 0.6,
pagecols = 4,
pagerows = 6,
page_x = 10.5,
page_y = 1.25,
craft_x = 2.6,
craft_y = 0.75,
craftresult_x = 5.75,
craft_arrow_x = 6.35,
craft_guide_x = 3.1,
craft_guide_y = 0.75,
craft_guide_arrow_x = 7.05,
craft_guide_result_x = 8.3,
craft_guide_resultstr_x = 0.15,
craft_guide_resultstr_y = 0.35,
give_btn_x = 0.15,
main_button_x = 10.5,
main_button_y = 7.9,
page_buttons_x = 10.5,
page_buttons_y = 6.3,
searchwidth = 1.6,
form_header_x = 0.2,
form_header_y = 0.2,
btn_spc = 0.8,
btn_size = 0.7,
std_inv_x = 0.1,
std_inv_y = 4.6,
}
dofile(modpath.."/api.lua")
for _, style in ipairs({ui.style_full, ui.style_lite}) do
style.items_per_page = style.pagecols * style.pagerows
style.standard_inv = string.format("list[current_player;main;%f,%f;8,4;]",
style.std_inv_x + ui.list_img_offset, style.std_inv_y + ui.list_img_offset)
style.standard_inv_bg = ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y, 8, 1, true)..
ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y + ui.imgscale, 8, 3)
style.craft_grid = table.concat({
ui.make_inv_img_grid(style.craft_x, style.craft_y, 3, 3),
ui.single_slot(style.craft_x + ui.imgscale*4, style.craft_y), -- the craft result slot
string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]",
style.craft_arrow_x, style.craft_y, ui.imgscale, ui.imgscale),
string.format("list[current_player;craft;%f,%f;3,3;]",
style.craft_x + ui.list_img_offset, style.craft_y + ui.list_img_offset),
string.format("list[current_player;craftpreview;%f,%f;1,1;]",
style.craftresult_x + ui.list_img_offset, style.craft_y + ui.list_img_offset)
})
end
-- Disable default creative inventory
local creative = rawget(_G, "creative") or rawget(_G, "creative_inventory")
if creative then
function creative.set_creative_formspec(player, start_i, pagenum)
return
end
end
-- Disable sfinv inventory
local sfinv = rawget(_G, "sfinv")
if sfinv then
sfinv.enabled = false
end
dofile(modpath.."/group.lua")
dofile(modpath.."/internal.lua")
dofile(modpath.."/callbacks.lua")
dofile(modpath.."/match_craft.lua")
dofile(modpath.."/register.lua")
if minetest.settings:get_bool("unified_inventory_bags") ~= false then
dofile(modpath.."/bags.lua")
end
dofile(modpath.."/item_names.lua")
if minetest.get_modpath("datastorage") then
dofile(modpath.."/waypoints.lua")
end

View File

@ -0,0 +1,335 @@
local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape
local ui = unified_inventory
-- This pair of encoding functions is used where variable text must go in
-- button names, where the text might contain formspec metacharacters.
-- We can escape button names for the formspec, to avoid screwing up
-- form structure overall, but they then don't get de-escaped, and so
-- the input we get back from the button contains the formspec escaping.
-- This is a game engine bug, and in the anticipation that it might be
-- fixed some day we don't want to rely on it. So for safety we apply
-- an encoding that avoids all formspec metacharacters.
function ui.mangle_for_formspec(str)
return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end)
end
function ui.demangle_for_formspec(str)
return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end)
end
function ui.get_per_player_formspec(player_name)
local draw_lite_mode = ui.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true})
return table.copy(draw_lite_mode and ui.style_lite or ui.style_full), draw_lite_mode
end
function ui.get_formspec(player, page)
if not player then
return ""
end
local player_name = player:get_player_name()
local ui_peruser,draw_lite_mode = ui.get_per_player_formspec(player_name)
ui.current_page[player_name] = page
local pagedef = ui.pages[page]
if not pagedef then
return "" -- Invalid page name
end
local formspec = {
"formspec_version[4]size[17.75,12.25]",
pagedef.formspec_prepend and "" or "no_prepend[]",
ui.standard_background -- Background
}
local n = 4
if draw_lite_mode then
formspec[1] = "formspec_version[4]size[14,9.75]"
formspec[3] = ui.standard_background
end
local perplayer_formspec = ui.get_per_player_formspec(player_name)
local fsdata = pagedef.get_formspec(player, perplayer_formspec)
formspec[n] = fsdata.formspec
n = n+1
local button_row = 0
local button_col = 0
-- Main buttons
local filtered_inv_buttons = {}
for i, def in pairs(ui.buttons) do
if not (draw_lite_mode and def.hide_lite) then
table.insert(filtered_inv_buttons, def)
end
end
for i, def in pairs(filtered_inv_buttons) do
if draw_lite_mode and i > 4 then
button_row = 1
button_col = 1
end
if def.type == "image" then
if (def.condition == nil or def.condition(player) == true) then
formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s;]",
ui_peruser.main_button_x + ui_peruser.btn_spc * (i - 1) - button_col * ui_peruser.btn_spc * 4,
ui_peruser.main_button_y + button_row * ui_peruser.btn_spc,
ui_peruser.btn_size,ui_peruser.btn_size,
F(def.image),
F(def.name))
formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]"
n = n+2
else
formspec[n] = string.format("image[%f,%f;%f,%f;%s^[colorize:#808080:alpha]",
ui_peruser.main_button_x + ui_peruser.btn_spc * (i - 1) - button_col * ui_peruser.btn_spc * 4,
ui_peruser.main_button_y + button_row * ui_peruser.btn_spc,
ui_peruser.btn_size,ui_peruser.btn_size,def.image)
n = n+1
end
end
end
if fsdata.draw_inventory ~= false then
-- Player inventory
formspec[n] = "listcolors[#00000000;#00000000]"
formspec[n+1] = ui_peruser.standard_inv
n = n+2
end
if fsdata.draw_item_list == false then
return table.concat(formspec, "")
end
-- Search box
formspec[n] = "field_close_on_enter[searchbox;false]"
formspec[n+1] = string.format("field[%f,%f;%f,%f;searchbox;;%s]",
ui_peruser.page_buttons_x, ui_peruser.page_buttons_y,
ui_peruser.searchwidth - 0.1, ui_peruser.btn_size,
F(ui.current_searchbox[player_name]))
formspec[n+2] = string.format("image_button[%f,%f;%f,%f;ui_search_icon.png;searchbutton;]",
ui_peruser.page_buttons_x + ui_peruser.searchwidth, ui_peruser.page_buttons_y,
ui_peruser.btn_size,ui_peruser.btn_size)
formspec[n+3] = "tooltip[searchbutton;" ..F(S("Search")) .. "]"
formspec[n+4] = string.format("image_button[%f,%f;%f,%f;ui_reset_icon.png;searchresetbutton;]",
ui_peruser.page_buttons_x + ui_peruser.searchwidth + ui_peruser.btn_spc,
ui_peruser.page_buttons_y,
ui_peruser.btn_size, ui_peruser.btn_size)
formspec[n+5] = "tooltip[searchresetbutton;"..F(S("Reset search and display everything")).."]"
n = n + 6
-- Controls to flip items pages
local btnlist = {
{ "ui_skip_backward_icon.png", "start_list", S("First page") },
{ "ui_doubleleft_icon.png", "rewind3", S("Back three pages") },
{ "ui_left_icon.png", "rewind1", S("Back one page") },
{ "ui_right_icon.png", "forward1", S("Forward one page") },
{ "ui_doubleright_icon.png", "forward3", S("Forward three pages") },
{ "ui_skip_forward_icon.png", "end_list", S("Last page") },
}
if draw_lite_mode then
btnlist[5] = nil
btnlist[2] = nil
end
local bn = 0
for _, b in pairs(btnlist) do
formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s;]",
ui_peruser.page_buttons_x + ui_peruser.btn_spc*bn,
ui_peruser.page_buttons_y + ui_peruser.btn_spc,
ui_peruser.btn_size, ui_peruser.btn_size,
b[1],b[2])
formspec[n+1] = "tooltip["..b[2]..";"..F(b[3]).."]"
bn = bn + 1
n = n + 2
end
local no_matches = S("No matching items")
if draw_lite_mode then
no_matches = S("No matches.")
end
-- Items list
if #ui.filtered_items_list[player_name] == 0 then
formspec[n] = "label["..ui_peruser.page_x..","..(ui_peruser.page_y+0.15)..";" .. F(no_matches) .. "]"
else
local dir = ui.active_search_direction[player_name]
local list_index = ui.current_index[player_name]
local page2 = math.floor(list_index / (ui_peruser.items_per_page) + 1)
local pagemax = math.floor(
(#ui.filtered_items_list[player_name] - 1)
/ (ui_peruser.items_per_page) + 1)
for y = 0, ui_peruser.pagerows - 1 do
for x = 0, ui_peruser.pagecols - 1 do
local name = ui.filtered_items_list[player_name][list_index]
local item = minetest.registered_items[name]
if item then
-- Clicked on current item: Flip crafting direction
if name == ui.current_item[player_name] then
local cdir = ui.current_craft_direction[player_name]
if cdir == "recipe" then
dir = "usage"
elseif cdir == "usage" then
dir = "recipe"
end
else
-- Default: use active search direction by default
dir = ui.active_search_direction[player_name]
end
local button_name = "item_button_" .. dir .. "_"
.. ui.mangle_for_formspec(name)
formspec[n] = ("item_image_button[%f,%f;%f,%f;%s;%s;]"):format(
ui_peruser.page_x + x * ui_peruser.btn_spc,
ui_peruser.page_y + y * ui_peruser.btn_spc,
ui_peruser.btn_size, ui_peruser.btn_size,
name, button_name
)
formspec[n + 1] = ("tooltip[%s;%s \\[%s\\]]"):format(
button_name, minetest.formspec_escape(item.description),
item.mod_origin or "??"
)
n = n + 2
list_index = list_index + 1
end
end
end
formspec[n] = string.format("label[%f,%f;%s: %s]",
ui_peruser.page_x, ui_peruser.form_header_y,
F(S("Page")), S("@1 of @2",page2,pagemax))
end
n= n+1
if ui.activefilter[player_name] ~= "" then
formspec[n] = string.format("label[%f,%f;%s:]",
ui_peruser.page_x, ui_peruser.page_y - 0.65, F(S("Filter")))
formspec[n+1] = string.format("label[%f,%f;%s]",
ui_peruser.page_x, ui_peruser.page_y - 0.25, F(ui.activefilter[player_name]))
end
return table.concat(formspec, "")
end
function ui.set_inventory_formspec(player, page)
if player then
player:set_inventory_formspec(ui.get_formspec(player, page))
end
end
--apply filter to the inventory list (create filtered copy of full one)
function ui.apply_filter(player, filter, search_dir)
if not player then
return false
end
local player_name = player:get_player_name()
local lfilter = string.lower(filter)
local ffilter
if lfilter:sub(1, 6) == "group:" then
local groups = lfilter:sub(7):split(",")
ffilter = function(name, def)
for _, group in ipairs(groups) do
if not def.groups[group]
or def.groups[group] <= 0 then
return false
end
end
return true
end
else
local lang = minetest.get_player_information(player_name).lang_code
ffilter = function(name, def)
local lname = string.lower(name)
local ldesc = string.lower(def.description)
local llocaldesc = minetest.get_translated_string
and string.lower(minetest.get_translated_string(lang, def.description))
return string.find(lname, lfilter, 1, true) or string.find(ldesc, lfilter, 1, true)
or llocaldesc and string.find(llocaldesc, lfilter, 1, true)
end
end
ui.filtered_items_list[player_name]={}
for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0)
and def.description
and def.description ~= ""
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
end
end
table.sort(ui.filtered_items_list[player_name])
ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name]
ui.current_index[player_name] = 1
ui.activefilter[player_name] = filter
ui.active_search_direction[player_name] = search_dir
ui.set_inventory_formspec(player,
ui.current_page[player_name])
end
function ui.items_in_group(groups)
local items = {}
for name, item in pairs(minetest.registered_items) do
for _, group in pairs(groups:split(',')) do
if item.groups[group] then
table.insert(items, name)
end
end
end
return items
end
function ui.sort_inventory(inv)
local inlist = inv:get_list("main")
local typecnt = {}
local typekeys = {}
for _, st in ipairs(inlist) do
if not st:is_empty() then
local n = st:get_name()
local w = st:get_wear()
local m = st:get_metadata()
local k = string.format("%s %05d %s", n, w, m)
if not typecnt[k] then
typecnt[k] = {
name = n,
wear = w,
metadata = m,
stack_max = st:get_stack_max(),
count = 0,
}
table.insert(typekeys, k)
end
typecnt[k].count = typecnt[k].count + st:get_count()
end
end
table.sort(typekeys)
local outlist = {}
for _, k in ipairs(typekeys) do
local tc = typecnt[k]
while tc.count > 0 do
local c = math.min(tc.count, tc.stack_max)
table.insert(outlist, ItemStack({
name = tc.name,
wear = tc.wear,
metadata = tc.metadata,
count = c,
}))
tc.count = tc.count - c
end
end
if #outlist > #inlist then return end
while #outlist < #inlist do
table.insert(outlist, ItemStack(nil))
end
inv:set_list("main", outlist)
end

View File

@ -0,0 +1,76 @@
-- Based on 4itemnames mod by 4aiman
local item_names = {} -- [player_name] = { hud, dtime, itemname }
local dlimit = 3 -- HUD element will be hidden after this many seconds
local hudbars_mod = minetest.get_modpath("hudbars")
local function set_hud(player)
local player_name = player:get_player_name()
local off = {x=0, y=-65}
if hudbars_mod then
-- Assume no alignment (2 per line)
off.y = off.y - math.ceil(hb.hudbars_count / 2) * 25
else
off.y = off.y - 25
end
item_names[player_name] = {
hud = player:hud_add({
hud_elem_type = "text",
position = {x=0.5, y=1},
offset = off,
alignment = {x=0, y=-1},
number = 0xFFFFFF,
text = "",
}),
dtime = dlimit,
index = 1,
itemname = ""
}
end
minetest.register_on_joinplayer(function(player)
minetest.after(0, set_hud, player)
end)
minetest.register_on_leaveplayer(function(player)
item_names[player:get_player_name()] = nil
end)
minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
local data = item_names[player:get_player_name()]
if not data or not data.hud then
data = {} -- Update on next step
set_hud(player)
end
local index = player:get_wield_index()
local stack = player:get_wielded_item()
local itemname = stack:get_name()
if data.hud and data.dtime < dlimit then
data.dtime = data.dtime + dtime
if data.dtime > dlimit then
player:hud_change(data.hud, 'text', "")
end
end
if data.hud and (itemname ~= data.itemname or index ~= data.index) then
data.itemname = itemname
data.index = index
data.dtime = 0
local desc = stack.get_meta
and stack:get_meta():get_string("description")
if not desc or desc == "" then
-- Try to use default description when none is set in the meta
local def = minetest.registered_items[itemname]
desc = def and def.description or ""
end
player:hud_change(data.hud, 'text', desc)
end
end
end)

View File

@ -0,0 +1,358 @@
# LANGUAGE translation for the unified_inventory mod.
# Copyright (C) 2018 Maciej Kasatkin (RealBadAngel)
# This file is distributed under the same license as the unified_inventory package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: unified_inventory\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-02 03:34+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: api.lua register.lua
msgid "Crafting"
msgstr ""
#: api.lua
msgid "Mixing"
msgstr ""
#: api.lua
msgid "Cooking"
msgstr ""
#: api.lua
msgid "Digging"
msgstr ""
#: bags.lua
msgid "Bags"
msgstr ""
#: bags.lua
msgid "Bag @1"
msgstr ""
#: bags.lua
msgid "Small Bag"
msgstr ""
#: bags.lua
msgid "Medium Bag"
msgstr ""
#: bags.lua
msgid "Large Bag"
msgstr ""
#: group.lua
msgid " and "
msgstr ""
#: internal.lua
msgid "First page"
msgstr ""
#: internal.lua
msgid "Back three pages"
msgstr ""
#: internal.lua
msgid "Back one page"
msgstr ""
#: internal.lua
msgid "Forward one page"
msgstr ""
#: internal.lua
msgid "Forward three pages"
msgstr ""
#: internal.lua
msgid "Last page"
msgstr ""
#: internal.lua
msgid "Search"
msgstr ""
#: internal.lua
msgid "Reset search and display everything"
msgstr ""
#: internal.lua
msgid "No matching items"
msgstr ""
#: internal.lua
msgid "No matches."
msgstr ""
#: internal.lua
msgid "Page"
msgstr ""
#: internal.lua
#, lua-format
msgid "%s of %s"
msgstr ""
#: internal.lua
msgid "Filter"
msgstr ""
#: register.lua
msgid "Can use the creative inventory"
msgstr ""
#: register.lua
msgid ""
"Forces Unified Inventory to be displayed in Full mode if Lite mode is "
"configured globally"
msgstr ""
#: register.lua
msgid "Crafting Grid"
msgstr ""
#: register.lua
msgid "Crafting Guide"
msgstr ""
#: register.lua
msgid "Set home position"
msgstr ""
#: register.lua
#, lua-format
msgid "Home position set to: %s"
msgstr ""
#: register.lua
msgid "You don't have the \"home\" privilege!"
msgstr ""
#: register.lua
msgid "Go home"
msgstr ""
#: register.lua
msgid "Set time to day"
msgstr ""
#: register.lua
msgid "Time of day set to 6am"
msgstr ""
#: register.lua
msgid "You don't have the settime privilege!"
msgstr ""
#: register.lua
msgid "Set time to night"
msgstr ""
#: register.lua
msgid "Time of day set to 9pm"
msgstr ""
#: register.lua
msgid "Clear inventory"
msgstr ""
#: register.lua
msgid ""
"This button has been disabled outside of creative mode to prevent accidental "
"inventory trashing.\n"
"Use the trash slot instead."
msgstr ""
#: register.lua
msgid "Inventory cleared!"
msgstr ""
#: register.lua
msgid "Trash:"
msgstr ""
#: register.lua
msgid "Refill:"
msgstr ""
#: register.lua
#, lua-format
msgid "Any item belonging to the %s group"
msgstr ""
#: register.lua
#, lua-format
msgid "Any item belonging to the groups %s"
msgstr ""
#: register.lua
#, lua-format
msgid "Recipe %d of %d"
msgstr ""
#: register.lua
#, lua-format
msgid "Usage %d of %d"
msgstr ""
#: register.lua
msgid "No recipes"
msgstr ""
#: register.lua
msgid "No usages"
msgstr ""
#: register.lua
msgid "Result"
msgstr ""
#: register.lua
msgid "Ingredient"
msgstr ""
#: register.lua
msgid "Show next recipe"
msgstr ""
#: register.lua
msgid "Show next usage"
msgstr ""
#: register.lua
msgid "Show previous recipe"
msgstr ""
#: register.lua
msgid "Show previous usage"
msgstr ""
#: register.lua
#, lua-format
msgid "%s (%s)"
msgstr ""
#: register.lua
msgid "Give me:"
msgstr ""
#: register.lua
msgid ""
"This recipe is too\n"
"large to be displayed."
msgstr ""
#: register.lua
msgid "To craft grid:"
msgstr ""
#: register.lua
msgid "All"
msgstr ""
#: waypoints.lua
msgid "White"
msgstr ""
#: waypoints.lua
msgid "Yellow"
msgstr ""
#: waypoints.lua
msgid "Red"
msgstr ""
#: waypoints.lua
msgid "Green"
msgstr ""
#: waypoints.lua
msgid "Blue"
msgstr ""
#: waypoints.lua
msgid "Waypoints"
msgstr ""
#: waypoints.lua
#, lua-format
msgid "Select Waypoint #%d"
msgstr ""
#: waypoints.lua
#, lua-format
msgid "Waypoint %d"
msgstr ""
#: waypoints.lua
msgid "Set waypoint to current location"
msgstr ""
#: waypoints.lua
msgid "invisible"
msgstr ""
#: waypoints.lua
msgid "visible"
msgstr ""
#: waypoints.lua
msgid "Make waypoint @1"
msgstr ""
#: waypoints.lua
msgid "Disable"
msgstr ""
#: waypoints.lua
msgid "Enable"
msgstr ""
#: waypoints.lua
msgid "@1 display of waypoint coordinates"
msgstr ""
#: waypoints.lua
msgid "Change color of waypoint display"
msgstr ""
#: waypoints.lua
msgid "Edit waypoint name"
msgstr ""
#: waypoints.lua
msgid "Waypoint active"
msgstr ""
#: waypoints.lua
msgid "Waypoint inactive"
msgstr ""
#: waypoints.lua
msgid "Finish editing"
msgstr ""
#: waypoints.lua
msgid "World position"
msgstr ""
#: waypoints.lua
msgid "Name"
msgstr ""
#: waypoints.lua
msgid "HUD text color"
msgstr ""

View File

@ -0,0 +1,79 @@
# textdomain: unified_inventory
Crafting=Fertigung
Mixing=Mischen
Cooking=Kochen
Digging=Graben
Bags=Taschen
Bag @1=Tasche @1
Small Bag=Kleine Tasche
Medium Bag=Mittelgroße Tasche
Large Bag=Große Tasche
and = und
First page=Erste Seite
Back three pages=3 Seiten zurückblättern
Back one page=1 Seite zurückblättern
Forward one page=1 Seite vorblättern
Forward three pages=3 Seiten vorblättern
Last page=Letzte Seite
Search=Suchen
Reset search and display everything=Suche zurücksetzen und alles anzeigen
No matching items=Keine passenden Gegenstände
No matches.=Keine Treffer
Page=Seite
@1 of @2=@1 von @2
Filter=Filter
Can use the creative inventory=Kann das Kreativinventar nutzen
Crafting Grid=Fertigungsraster
Crafting Guide=Fertigungsführer
Set home position=Heimatposition setzen
Home position set to: @1=Heimatposition nach @1 gesetzt
You don't have the "home" privilege!=Du hast das „home“-Privileg nicht!
Go home=Nach Hause gehen
Set time to day=Zur Tageszeit wechseln
Time of day set to 6am=Tageszeit auf 6 Uhr gesetzt
You don't have the settime privilege!=Du hast das „settime“-Privileg nicht!
Set time to night=Zur Nachtzeit wechseln
Time of day set to 9pm=Tageszeit auf 21 Uhr gesetzt
Clear inventory=Inventar leeren
Inventory cleared!=Inventar geleert!
Trash:=Müll:
Refill:=Nachfüllen:
Any item belonging to the @1 group=Irgendein Gegenstand, der zur Gruppe @1 gehört
Any item belonging to the groups @1=Irgendein Gegenstand, der zu den Gruppen @1 gehört
Recipe @1 of @2=Rezept @1 von @2
Usage @1 of @2=Verwendung @1 von @2
No recipes=Keine Rezepte
No usages=Keine Verwendungen
Result=Ergebnis
Ingredient=Zutat
Show next recipe=Nächstes Rezept zeigen
Show next usage=Nächste Verwendung zeigen
Show previous recipe=Vorheriges Rezept zeigen
Show previous usage=Vorherige Verwendung zeigen
Give me:=Gib mir:
To craft grid:=Ins Fertigungsraster:
All=Alles
White=Weiß
Yellow=Gelb
Red=Rot
Green=Grün
Blue=Blau
Waypoints=Wegpunkte
Select Waypoint #@1=Wegpunkt Nr. @1 auswählen
Waypoint @1=Wegpunkt Nr. @1
Set waypoint to current location=Setze Wegpunkt zur derzeitigen Position
invisible=unsichtbar
visible=sichtbar
Make waypoint @1=Wegpunkt @1 machen
Disable=ausschalten
Enable=einschalten
@1 display of waypoint coordinates=Anzeige der Wegpunktkoordinaten @1
Change color of waypoint display=Farbe der Darstellung der Wegpunkte ändern
Edit waypoint name=Name des Wegpunkts ändern
Waypoint active=Wegpunkt aktiv
Waypoint inactive=Wegpunkt inaktiv
Finish editing=Bearbeitung abschließen
World position=Weltposition
Name=Name
HUD text color=HUD-Textfarbe
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Zwingt Unified Inventory, im Vollmodus angezeigt zu werden, wenn der Minimalmodus global eingestellt ist

View File

@ -0,0 +1,100 @@
# textdomain: unified_inventory
# waypoints.lua
White=Blanco
Yellow=Amarillo
Red=Rojo
Green=Verde
Blue=Azul
Waypoints=Puntos
Select Waypoint #@1=Seleccionar Punto #@1
Waypoint @1=Punto @1
Set waypoint to current location=Establecer el punto a la ubicación actual
Make waypoint @1=Hacer punto @1
invisible=invisible
visible=visible
@1 display of waypoint coordinates=Visualizar coordenadas del punto @1
Disable=Deshabilitado
Enable=Habilitado
Change color of waypoint display=Cambiar el color del punto
Edit waypoint name=Editar nombre del punto
Waypoint active=Punto activo
Waypoint inactive=Punto inactivo
Finish editing=Terminar edición
World position=Posición en el mundo
Name=Nombre
HUD text color=Color del texto de la Interfaz
# group.lua
and = y
# register.lua
Can use the creative inventory=Puede usar el inventario creativo
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Obliga al Inventario Unificado a mostrarse en modo Completo si el modo Simple está configurado globalmente
Crafting Grid=Cuadricula de Elaboración
Crafting Guide=Guía de Elaboración
Set home position=Establecer posición de la casa
Home position set to: @1=Posición de la casa cambiada a: @1
You don't have the \"home\" privilege!=¡No tienes el privilegio \"home\"!
Go home=Ir a casa
Set time to day=Cambiar a dia
Set time to night=Cambiar a noche
Time of day set to 6am=Hora del día cambiada a 6 AM
Time of day set to 9pm=Hora del día cambiada a 9 PM
You don't have the settime privilege!=¡No tienes el privilegio "settime"!
Clear inventory=Limpiar inventario
Inventory cleared!=¡Inventario limpio!
This button has been disabled outside=Este botón ha sido deshabilitado
Crafting=Elaboración
Trash:=Basura:
Refill:=Rellenar:
Any item belonging to the @1 group=Cualquier elemento que pertenezca al grupo @1
Any item belonging to the groups @1=Cualquier elemento perteneciente a los grupos @1
Recipe @1 of @2=Receta @1 de @2
Usage @1 of @2=Uso @1 de @2
No recipes=No tiene receta
No usages=No tiene uso
Result=Resultado
Ingredient=Ingrediente
Show next recipe=Mostrar la siguiente receta
Show next usage=Mostrar el siguiente uso
Show previous recipe=Mostrar la receta anterior
Show previous usage=Mostrar el uso anterior
@1 (@2)=@1 (@2)
Give me:=Dame:
This recipe is too@nlarge to be displayed.=Esta receta es demasiado@ngrande para ser mostrada.
To craft grid:=Construir:
All=Todos
# api.lua
Mixing=Mezclar
Cooking=Hornear
Digging=Recoger
# internal.lua
First page=Primera página
Back three pages=Volver tres páginas
Back one page=Volver una página
Forward one page=Avanzar una página
Forward three pages=Avanzar tres páginas
Last page=Ultima Pagina
Search=Buscar
Reset search and display everything=Limpiar la busqueda y mostrar todo
No matching items=No se encontraron elementos
No matches.=No hay resultados.
Page=Página
@1 of @2=@1 de @2
Filter=Filtro
# bags.lua
Bags=Bolsos
Bag @1=Bolso @1
Small Bag=Bolso Pequeño
Medium Bag=Bolso Mediano
Large Bag=Bolso Grande

View File

@ -0,0 +1,57 @@
# textdomain: unified_inventory
Crafting=Création
Cooking=Cuisson
Digging=Creuser
Bags=Sacs
Bag @1=Sac @1
Small Bag=Petit sac
Medium Bag=Sac moyen
Large Bag=Grand sac
and = et
First page=1ère page
Back three pages=3 pages en arrière
Back one page=Page précédente
Forward one page=Page suivante
Forward three pages=3 pages en avant
Last page=Dernière page
Search=Rechercher
No matching items=Aucun élément correspondant
No matches.=Aucun match
Page=Page
@1 of @2=@1 de @2
Filter=Filtre
Can use the creative inventory=Vous pouvez utiliser l'inventaire créatif
Crafting Grid=Grille de création
Crafting Guide=Guide de création
Set home position=Position dans le monde
Home position set to: @1=Position de votre base fixée à: @1
You don't have the "home" privilege!=Vous n'avez pas le privilège "home"!
Time of day set to 6am=Heure fixée à 6h
You don't have the settime privilege!=Vous n'avez pas le privilège "settime"!
Time of day set to 9pm=Heure fixée à 21h
Inventory cleared!=Inventaire vidé !
Trash:=Poubelle :
Refill:=Remplir :
Recipe @1 of @2=Recette @1 de @2
Result=Résultat
To craft grid:=Sur de création:
All=Tout
White=Blanc
Yellow=Jaune
Red=Rouge
Green=Vert
Blue=Bleu
Waypoints=Point de passage
Select Waypoint #@1=Choisir un point de passage #@1
Waypoint @1=Point de passage @1
Set waypoint to current location=Marquer un point de passage à la position actuelle
Make waypoint @1=Rendre @1 le point de passage
@1 display of waypoint coordinates=@1 montrer les coordonnées des points de passages
Change color of waypoint display=Changer la couleur du point de passage
Edit waypoint name=Editer le nom du point de passage
Waypoint active=Point de passage actif
Waypoint inactive=Point de passage inactif
Finish editing=Terminer l'édition
World position=Position dans le monde
Name=Nom
HUD text color=Couleur de texte du HUD

View File

@ -0,0 +1,79 @@
# textdomain: unified_inventory
Crafting=Assemblaggio
Mixing=Unione
Cooking=Cottura
Digging=Scavo
Bags=Borse
Bag @1=Borsa @1
Small Bag=Borsa piccola
Medium Bag=Borsa media
Large Bag=Borsa grande
and = e
First page=Prima pagina
Back three pages=Indietro di tre pagine
Back one page=Indietro di una pagina
Forward one page=Avanti di una pagina
Forward three pages=Avanti di tre pagine
Last page=Ultima pagina
Search=Cerca
Reset search and display everything=Azzera la ricerca e mostra tutto
No matching items=Nessun oggetto corrispondente
No matches.=Nessuna corrispondenza.
Page=Pagina
@1 of @2=@1 di @2
Filter=Filtro
Can use the creative inventory=Può usare l'inventario creativo
Crafting Grid=Griglia di assemblaggio
Crafting Guide=Guida di assemblaggio
Set home position=Imposta la residenza
Home position set to: @1=Residenza impostata su: @1
You don't have the "home" privilege!=Non hai il privilegio "home"!
Go home=Torna a casa
Set time to day=Imposta l'orario sul giorno
Time of day set to 6am=Orario impostato sulle 6am
You don't have the settime privilege!=Non hai il privilegio "time"!
Set time to night=Imposta l'orario sulla notte
Time of day set to 9pm=Orario impostato sulle 9am
Clear inventory=Ripulisci l'inventario
Inventory cleared!=Inventario ripulito!
Trash:=Butta:
Refill:=Riempi:
Any item belonging to the @1 group=Qualunque oggetto appartenente al gruppo @1
Any item belonging to the groups @1=Qualunque oggetto appartenente ai gruppi @1
Recipe @1 of @2=Ricetta @1 di @2
Usage @1 of @2=Uso @1 di @2
No recipes=Nessuna ricetta
No usages=Nessun utilizzo
Result=Risultato
Ingredient=Ingrediente
Show next recipe=Mostra la prossima ricetta
Show next usage=Mostra il prossimo utilizzo
Show previous recipe=Mostra la ricetta precedente
Show previous usage=Mostra l'utilizzo precedente
Give me:=Dammi:
To craft grid:=Alla griglia di assemblaggio:
All=Tutto
White=Bianco
Yellow=Giallo
Red=Rosso
Green=Verde
Blue=Blu
Waypoints=Tappe
Select Waypoint #@1=Seleziona tappa n°@1
Waypoint @1=Tappa @1
Set waypoint to current location=Imposta tappa alla posizione attuale
invisible=invisibile
visible=visibile
Make waypoint @1=Crea tappa @1
Disable=Disabilita
Enable=Abilita
@1 display of waypoint coordinates=@1 la visualizzazione delle coordinate della tappa
Change color of waypoint display=Modifica il colore della visualizzazione della tappa
Edit waypoint name=Modifica il nome della tappa
Waypoint active=Tappa attiva
Waypoint inactive=Tappa inattiva
Finish editing=Termina la modifica
World position=Posizione del mondo
Name=Nome
HUD text color=Colore del testo del visore
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Forza la visualizzazione di Unified Inventory in modalità completa se è configurata globalmente la visualizzazione semplice

View File

@ -0,0 +1,78 @@
# textdomain: unified_inventory
Crafting=Pertukangan
Mixing=Pencampuran
Cooking=Pemasakan
Digging=Penggalian
Bags=Beg
Bag @1=Beg @1
Small Bag=Beg Kecil
Medium Bag=Beg Sederhana
Large Bag=Beg Besar
and = dan
First page=Halaman pertama
Back three pages=Tiga halaman sebelumnya
Back one page=Halaman sebelumnya
Forward one page=Halaman seterusnya
Forward three pages=Tiga halaman seterusnya
Last page=Halaman terakhir
Search=Cari
Reset search and display everything=Set semula carian dan tunjukkan semua benda
No matching items=Tiada item sepadan
No matches.=Tiada padanan.
Page=Halaman
@1 of @2=@1 drpd @2
Filter=Tapis
Can use the creative inventory=Boleh guna inventori kreatif
Crafting Grid=Grid Pertukangan
Crafting Guide=Panduan Pertukangan
Set home position=Tetapkan kedudukan rumah
Home position set to: @1=Kedudukan rumah ditetapkan ke: @1
You don't have the "home" privilege!=Anda tidak ada keistimewaan "home"!
Go home=Balik rumah
Set time to day=Tetapkan masa jadi siang
Time of day set to 6am=Masa ditetapkan ke 6 pagi
You don't have the settime privilege!=Anda tidak ada keistimewaan settime!
Set time to night=Tetapkan masa jadi malam
Time of day set to 9pm=Masa ditetapkan ke 9 malam
Clear inventory=Kosongkan inventori
Inventory cleared!=Inventori dikosongkan!
Trash:=Buang:
Refill:=Isi balik:
Any item belonging to the @1 group=Sebarang item dari kumpulan @1
Any item belonging to the groups @1=Sebarang item dari kumpulan @1
Recipe @1 of @2=Resipi @1 drpd @2
Usage @1 of @2=Kegunaan @1 drpd @2
No recipes=Tiada resipi
No usages=Tiada kegunaan
Result=Hasil
Ingredient=Bahan
Show next recipe=Tunjuk resipi seterusnya
Show next usage=Tunjuk kegunaan seterusnya
Show previous recipe=Tunjuk resipi sebelumnya
Show previous usage=Tunjuk kegunaan sebelumnya
@1 (@2)=@1 (@2)
Give me:=Beri saya:
To craft grid:=Ke grid pertukangan:
White=Putih
Yellow=Kuning
Red=Merah
Green=Hijau
Blue=Biru
Waypoints=Titik Arah
Select Waypoint #@1=Pilih Titik Arah #@1
Waypoint @1=Titik Arah @1
Set waypoint to current location=Tetapkan titik arah ke lokasi semasa
invisible=Sembunyikan
visible=Paparkan
Make waypoint @1=@1 titik arah
Disable=Sembunyikan
Enable=Paparkan
@1 display of waypoint coordinates=@1 koordinat untuk titik arah
Change color of waypoint display=Tukar warna paparan titik arah
Edit waypoint name=Edit nama titik arah
Waypoint active=Titik arah aktif
Waypoint inactive=Titik arah tidak aktif
Finish editing=Selesai edit
World position=Kedudukan dunia
Name=Nama
HUD text color=Warna tulisan HUD

View File

@ -0,0 +1,61 @@
# textdomain: unified_inventory
Bags=Plecaki
Bag @1=Plecak @1
Small Bag=Maly plecak
Medium Bag=Sredni plecak
Large Bag=Duzy plecak
and = i
First page=Pierwsza strona
Back three pages=3 strony w tyl
Back one page=1 strona w tyl
Forward one page=1 strona do przodu
Forward three pages=3 strony do przodu
Last page=Ostatnia strona
Search=Szukaj
No matching items=Brak pasujacych przedmiotow
No matches.=Brak wyników
Page=Strona
@1 of @2=@1 z @2
Filter=Filtr
Set home position=Ustaw pozycję wyjściową
Home position set to: @1=Pozycja domowa ustawiona na: @1
You don't have the "home" privilege!=Nie masz uprawnien do zmiany czasu "home"!
Go home=Idź do domu
Set time to day=Ustaw czas na dzień
Time of day set to 6am=Czas ustawiony na 6:00
You don't have the settime privilege!=Nie masz uprawnien do zmiany czasu "settime"!
Set time to night=Ustaw czas na noc
Time of day set to 9pm=Czas ustawiony na 21:00
Clear inventory=Wyczyść zapasy
Inventory cleared!=Zapasy zostały wyczyszczone!
Trash:=Smietnik:
Refill:=Uzupelnianie:
Recipe @1 of @2=Recepta @1 z @2
Usage @1 of @2=Użycie @1 z @2
No recipes=Brak recepty
No usages=Bez użycia
Result=Wynik
Ingredient=Składnik
Give me:=Daj mi:
All=Wszystko
White=Bialy
Yellow=Zolty
Red=Czerwony
Green=Zielony
Blue=Niebieski
Waypoints=Punkty orientacyjne
Select Waypoint #@1=Wybierz punkt #@1
Waypoint @1=Punkty orientacyjne @1
Set waypoint to current location=Ustaw punkt orientacyjny na biezacej pozycji
invisible=niewidzialny
visible=widomy
Make waypoint @1=Robić punkt @1
@1 display of waypoint coordinates=@1 koordynatow punktu
Change color of waypoint display=Zmien kolor punktu
Edit waypoint name=Edytuj nazwe punktu
Waypoint active=Punkt wlaczony
Waypoint inactive=Punkt wylaczony
Finish editing=Zakoncz edycje
World position=Pozycja
Name=Nazwa
HUD text color=Kolor tekstu HUD

View File

@ -0,0 +1,76 @@
# textdomain: unified_inventory
Crafting=Artesanato
Mixing=Muistura
Cooking=Cozimento
Digging=Escavação
Bags=Bolsas
Bag @1=Bolsa @1
Small Bag=Bolsa Pequena
Medium Bag=Bolsa Média
Large Bag=Bolsa Grande
and = e
First page=Primeira Página
Back three pages=Voltar 3 Páginas
Back one page=Voltar 1 Página
Forward one page=Avançar 1 Página
Forward three pages=Avançar 3 Páginas
Last page=Ultima Página
Search=Pesquisar
Reset search and display everything=Redefinir pesquisa e exibir tudo
No matching items=Nenhum item correspondente
No matches.=Sem correspondências
Page=Página
@1 of @2=@1 de @2
Filter=Filtro
Can use the creative inventory=Pode usar o inventário do criativo
Crafting Grid=Grade de Artesanato
Crafting Guide=Guia de Artesanato
Set home position=Definir posição de casa
Home position set to: @1=Posição inicial definida para: @1
You don't have the "home" privilege!=Você não tem o privilégio de "home"!
Go home=Transportar para Casa
Set time to day=Definir turno para dia
Time of day set to 6am=Hora do dia definida para 06h
You don't have the settime privilege!=Você não tem o privilégio de "settime"!
Set time to night=Definir turno para noite
Time of day set to 9pm=Hora do dia ajustada para 21h
Clear inventory=Limpar Inventário
Inventory cleared!=Inventário Apagado!
Trash:=Lixo:
Refill:=Recarga:
Any item belonging to the @1 group=Qualquer item pertencente ao grupo '@1'.
Any item belonging to the groups @1=Qualquer item pertencente aos grupos '@1'.
Recipe @1 of @2=Receita @1 de @2
Usage @1 of @2=Utilização @1 de @2
No recipes=Sem Receita
No usages=Sem Utilização
Result=Resultado
Ingredient=Ingrediente
Show next recipe=Exibir Próxima Receita
Show next usage=Mostrar Próxima Utilização
Show previous recipe=Exibir Receita Anterior
Show previous usage=Exibir Utilização Anterior
Give me:=Gerado:
To craft grid:=Para Grade de Artesanato
All=MAX
White=Branco
Yellow=Amarelo
Red=Vermelho
Green=Verde
Blue=Azul
Waypoints=Apontador de Direção
Select Waypoint #@1=Seleção de Apontador de Direção #@1
Waypoint @1=Apontador de Direção @1
Set waypoint to current location=Configurar localização atual do Apontador de Direção
invisible=invisível
visible=visível
Make waypoint @1=Fazer Apontador de Direção @1
@1 display of waypoint coordinates=@1 exibição de coordenadas de Fazer Apontador de Direção
Change color of waypoint display=Mudar cor exibida do Apontador de Direção
Edit waypoint name=Editar Nome de Apontador de Direção
Waypoint active=Apontador de Direção Ativo
Waypoint inactive=Apontador de Direção Inativo
Finish editing=Edição Finalizada
World position=Posição Mundial
Name=Nome
HUD text color=Cor de HUD

View File

@ -0,0 +1,78 @@
# textdomain: unified_inventory
Crafting=Крафт
Mixing=Мешать
Cooking=Варить
Digging=Копать
Bags=Сумки
Bag @1=Сумка @1
Small Bag=Малая сумка
Medium Bag=Средняя сумка
Large Bag=Большая сумка
and = и
First page=Первая страница
Back three pages=3 страницы назад
Back one page=1 страницу назад
Forward one page=1 страницу вперёд
Forward three pages=3 страницы вперёд
Last page=Последняя страница
Search=Поиск
Reset search and display everything=Сброс поиска, показать всё
No matching items=Нет подходящих элементов
No matches.=Ничего не найдено
Page=Страница
@1 of @2=@1 из @2
Filter=Фильтр
Can use the creative inventory=Можно использовать инвентарь творческого режима
Crafting Grid=Решетка крафта
Crafting Guide=Книга рецептов
Set home position=Установить позицию дома
Home position set to: @1=Дом теперь расположен по коодинатам: @1
You don't have the "home" privilege!=У вас нет привилегии "home"!
Go home=Отправиться домой
Set time to day=День
Time of day set to 6am=Установлено время 6 утра
You don't have the settime privilege!=Вам не разрешено устанавливать время! (нет привилегии "settime")
Set time to night=Ночь
Time of day set to 9pm=Установлено время 9 вечера
Clear inventory=Очистить инвентарь
Inventory cleared!=Инвентарь очищен!
Trash:=Мусор:
Refill:=Наполнить:
Any item belonging to the @1 group=Любой элемент из группы: @1
Any item belonging to the groups @1=Любой элемент из группы: @1
Recipe @1 of @2=Рецепт @1 из @2
Usage @1 of @2=Вариант @1 of @2
No recipes=Рецептов нет
No usages=Не используется
Result=Результат
Ingredient=Состав
Show next recipe=Следующий рецепт
Show next usage=Следующее использование
Show previous recipe=Прошлый рецепт
Show previous usage=Прошлая страница
Give me:=Дай мне:
To craft grid:=На решeтку крафта:
All=Все
White=Белый
Yellow=Желтый
Red=Красный
Green=Зелёный
Blue=Синий
Waypoints=Путевые точки
Select Waypoint #@1=Выбрать путевую точку №@1
Waypoint @1=Путевая точка @1
Set waypoint to current location=Установить путевую точку по текущей позиции
invisible=невидимой
visible=видимой
Make waypoint @1=Сделать путевую точку @1
Disable=Выключить
Enable=Включить
@1 display of waypoint coordinates=@1 показ координат путевых точек
Change color of waypoint display=Поменять цвет путевой точки
Edit waypoint name=Переименовать путевую точку
Waypoint active=Путевая точка включена
Waypoint inactive=Путевая точка выключена
Finish editing=Закончить редакцию
World position=Позиция мира
Name=Имя
HUD text color=Цвет текста HUDа

View File

@ -0,0 +1,100 @@
# textdomain: unified_inventory
# waypoints.lua
White=
Yellow=
Red=
Green=
Blue=
Waypoints=
Select Waypoint #@1=
Waypoint @1=
Set waypoint to current location=
Make waypoint @1=
invisible=
visible=
@1 display of waypoint coordinates=
Disable=
Enable=
Change color of waypoint display=
Edit waypoint name=
Waypoint active=
Waypoint inactive=
Finish editing=
World position=
Name=
HUD text color=
# group.lua
and =
# register.lua
Can use the creative inventory=
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=
Crafting Guide=
Set home position=
Home position set to: @1=
You don't have the \"home\" privilege!=
Go home=
Set time to day=
Set time to night=
Time of day set to 6am=
Time of day set to 9pm=
You don't have the settime privilege!=
Clear inventory=
Inventory cleared!=
This button has been disabled outside=
Crafting=
Trash:=
Refill:=
Any item belonging to the @1 group=
Any item belonging to the groups @1=
Recipe @1 of @2=
Usage @1 of @2=
No recipes=
No usages=
Result=
Ingredient=
Show next recipe=
Show next usage=
Show previous recipe=
Show previous usage=
@1 (@2)=
Give me:=
This recipe is too@nlarge to be displayed.=
To craft grid:=
All=
# api.lua
Mixing=
Cooking=
Digging=
# internal.lua
First page=
Back three pages=
Back one page=
Forward one page=
Forward three pages=
Last page=
Search=
Reset search and display everything=
No matching items=
No matches.=
Page=
@1 of @2=
Filter=
# bags.lua
Bags=
Bag @1=
Small Bag=
Medium Bag=
Large Bag=

View File

@ -0,0 +1,69 @@
# textdomain: unified_inventory
Crafting=Üretim
Mixing=Karıştırma
Cooking=Pişirme
Digging=Kazma
Bags=Çantalarım
Bag @1=@1. Çanta
Small Bag=Küçük Çanta
Medium Bag=Çanta
Large Bag=Büyük Çanta
and = ve
First page=İlk Sayfa
Back three pages=3 Sayfa Gerile
Back one page=Geri
Forward one page=İleri
Forward three pages=3 Sayfa İlerile
Last page=Son Sayfa
Search=Ara
No matching items=Eşleşme yok
No matches.=Eşleşme yok
Page=Sayfa
@1 of @2=@1 dan @2
Filter=Süzgeç
Can use the creative inventory=Yaratıcı envanteri kullanabilir
Crafting Grid=Üretim tablosu
Crafting Guide=Kılavuz
Set home position=Set ev pozisyon
Home position set to: @1=Yeni eviniz: @1
You don't have the "home" privilege!="home" yetkiniz yok!
Go home=Eve git
Set time to day=Güne zaman ayarla
Time of day set to 6am=Saat 06:00 olarak ayarlandı
You don't have the settime privilege!="settime" yetkiniz yok!
Set time to night=Geceye zaman ayarla
Time of day set to 9pm=Saat 19:00 olarak ayarlandı
msgid ""=Yaratıcı modu dışında iken bu tuş kullanılamaz.
Inventory cleared!=Envanter temizlendi!
Trash:=Çöp
Refill:=Doldur
Recipe @1 of @2=@1 dan @2 tarifi
Usage @1 of @2=Kullanım @1/@2
No recipes=Tarifi yok
No usages=Kullanım yok
Result=Çıktı
Ingredient=Bileşen
Give me:=Ver bana:
To craft grid:=Üretim tablosuna kopyala
All=Tümü
White=Beyaz
Yellow=Sarı
Red=Kırmızı
Green=Yeşil
Blue=Mavi
Waypoints=Konum Noktaları
Select Waypoint #@1=#@1 konum noktası seç
Waypoint @1=@1 Konum Noktaları
Set waypoint to current location=Bulunduğun noktayı işaretle
invisible=görünmez
visible=görünür
Make waypoint @1=Yol noktası @1
@1 display of waypoint coordinates=Yol noktası koordinatlarının görüntülenmesini @1
Change color of waypoint display=Konum Gösterge Rengi
Edit waypoint name=Konum Noktasını Düzenle
Waypoint active=Konum Etkin
Waypoint inactive=Konum Devredışı
Finish editing=Düzenleme bitti
World position=Dünya konumu
Name=İsim
HUD text color=Metin rengi

View File

@ -0,0 +1,79 @@
# textdomain: unified_inventory
# traslation by: IFRFSX(BingFengFSX)
#Email: IFRFSX@Protonmail.com
Crafting=合成
Mixing=混合
Cooking=烹饪
Digging=挖出
Bags=背包
Bag @1=背包@1
Small Bag=小背包
Medium Bag=中背包
Large Bag=大背包
and = 和
First page=第一页
Back three pages=后退三页
Back one page=后退一页
Forward one page=前进一页
Forward three pages=前进三页
Last page=最后一页
Search=搜索
No matching items=没有匹配物品
No matches.=没有匹配
Page=页面
@1 of @2=第@1页共@2页
Filter=过滤器
Can use the creative inventory=可以使用创造背包
Crafting Grid=合成表
Crafting Guide=合成指南
Set home position=设置家的位置
Home position set to: @1=家的位置设置到: @1
You don't have the "home" privilege!=你没有“home”权限
Go home=回家
Set time to day=设置时间到白天
Time of day set to 6am=时间设置到早晨6点
You don't have the settime privilege!=你没有“settime”权限
Set time to night=设置时间到晚上
Time of day set to 9pm=时间设置到晚上9点
Inventory cleared!=清空背包
Clear inventory=清空背包
Trash:=丢弃:
Refill:=填满:
Recipe @1 of @2=第@1配方共@2个
Usage @1 of @2=第@1用法共@2个
No recipes=没有配方
No usages=没有用法
Result=结果
Ingredient=原料
Give me:=给予:
To craft grid:=填充物品到合成表
All=全部
White=白
Yellow=黄
Red=红
Green=绿
Blue=蓝
Waypoints=航路点
Select Waypoint #@1=查询航路点 #@1
Waypoint @1=航路点 @1
Set waypoint to current location=将航路点设置到当前位置
invisible=不可见的
visible=可见的
Make waypoint @1=设置航路点 @1
@1 display of waypoint coordinates=显示航路点@1坐标
Change color of waypoint display=改变航路点显示的颜色
Edit waypoint name=编辑航路点名称
Waypoint active=航路点已激活
Waypoint inactive=航路点未激活
Finish editing=完成编辑
World position=世界位置
Name=名称
HUD text color=HUD文本颜色
Reset search and display everything=重置搜索并显示所有物品
Any item belonging to the @1 group=属于@1组的任何项目
Any item belonging to the groups @1=属于组@1的任何项目

View File

@ -0,0 +1,79 @@
# textdomain: unified_inventory
# traslation by: IFRFSX(BingFengFSX)
#Email: IFRFSX@Protonmail.com
Crafting=合成
Mixing=混合
Cooking=烹飪
Digging=挖出
Bags=揹包
Bag @1=揹包@1
Small Bag=小揹包
Medium Bag=中揹包
Large Bag=大揹包
and = 和
First page=第一頁
Back three pages=後退三頁
Back one page=後退一頁
Forward one page=前進一頁
Forward three pages=前進三頁
Last page=最後一頁
Search=搜索
No matching items=沒有匹配物品
No matches.=沒有匹配
Page=頁面
@1 of @2=第@1頁共@2頁
Filter=過濾器
Can use the creative inventory=可以使用創造揹包
Crafting Grid=合成表
Crafting Guide=合成指南
Set home position=設置家的位置
Home position set to: @1=家的位置設置到: @1
You don't have the "home" privilege!=你沒有“home”權限
Go home=回家
Set time to day=設置時間到白天
Time of day set to 6am=時間設置到早晨6點
You don't have the settime privilege!=你沒有“settime”權限
Set time to night=設置時間到晚上
Time of day set to 9pm=時間設置到晚上9點
Inventory cleared!=清空揹包
Clear inventory=清空揹包
Trash:=丟棄:
Refill:=填滿:
Recipe @1 of @2=第@1配方共@2個
Usage @1 of @2=第@1用法共@2個
No recipes=沒有配方
No usages=沒有用法
Result=結果
Ingredient=原料
Give me:=給予:
To craft grid:=填充物品到合成表
All=全部
White=白
Yellow=黃
Red=紅
Green=綠
Blue=藍
Waypoints=航路點
Select Waypoint #@1=查詢航路點 #@1
Waypoint @1=航路點 @1
Set waypoint to current location=將航路點設置到當前位置
invisible=不可見的
visible=可見的
Make waypoint @1=設置航路點 @1
@1 display of waypoint coordinates=顯示航路點@1座標
Change color of waypoint display=改變航路點顯示的顏色
Edit waypoint name=編輯航路點名稱
Waypoint active=航路點已激活
Waypoint inactive=航路點未激活
Finish editing=完成編輯
World position=世界位置
Name=名稱
HUD text color=HUD文本顏色
Reset search and display everything=重置搜索並顯示所有物品
Any item belonging to the @1 group=屬於@1組的任何項目
Any item belonging to the groups @1=屬於組@1的任何項目

View File

@ -0,0 +1,409 @@
-- match_craft.lua
-- Find and automatically move inventory items to the crafting grid
-- according to the recipe.
--[[
Retrieve items from inventory lists and calculate their total count.
Return a table of "item name" - "total count" pairs.
Arguments:
inv: minetest inventory reference
lists: names of inventory lists to use
Example usage:
-- Count items in "main" and "craft" lists of player inventory
unified_inventory.count_items(player_inv_ref, {"main", "craft"})
Example output:
{
["default:pine_wood"] = 2,
["default:acacia_wood"] = 4,
["default:chest"] = 3,
["default:axe_diamond"] = 2, -- unstackable item are counted too
["wool:white"] = 6
}
]]--
function unified_inventory.count_items(inv, lists)
local counts = {}
for i = 1, #lists do
local name = lists[i]
local size = inv:get_size(name)
local list = inv:get_list(name)
for j = 1, size do
local stack = list[j]
if not stack:is_empty() then
local item = stack:get_name()
local count = stack:get_count()
counts[item] = (counts[item] or 0) + count
end
end
end
return counts
end
--[[
Retrieve craft recipe items and their positions in the crafting grid.
Return a table of "craft item name" - "set of positions" pairs.
Note that if craft width is not 3 then positions are recalculated as
if items were placed on a 3x3 grid. Also note that craft can contain
groups of items with "group:" prefix.
Arguments:
craft: minetest craft recipe
Example output:
-- Bed recipe
{
["wool:white"] = {[1] = true, [2] = true, [3] = true}
["group:wood"] = {[4] = true, [5] = true, [6] = true}
}
--]]
function unified_inventory.count_craft_positions(craft)
local positions = {}
local craft_items = craft.items
local craft_type = unified_inventory.registered_craft_types[craft.type]
or unified_inventory.craft_type_defaults(craft.type, {})
local display_width = craft_type.dynamic_display_size
and craft_type.dynamic_display_size(craft).width
or craft_type.width
local craft_width = craft_type.get_shaped_craft_width
and craft_type.get_shaped_craft_width(craft)
or display_width
local i = 0
for y = 1, 3 do
for x = 1, craft_width do
i = i + 1
local item = craft_items[i]
if item ~= nil then
local pos = 3 * (y - 1) + x
local set = positions[item]
if set ~= nil then
set[pos] = true
else
positions[item] = {[pos] = true}
end
end
end
end
return positions
end
--[[
For every craft item find all matching inventory items.
- If craft item is a group then find all inventory items that matches
this group.
- If craft item is not a group (regular item) then find only this item.
If inventory doesn't contain needed item then found set is empty for
this item.
Return a table of "craft item name" - "set of matching inventory items"
pairs.
Arguments:
inv_items: table with items names as keys
craft_items: table with items names or groups as keys
Example output:
{
["group:wood"] = {
["default:pine_wood"] = true,
["default:acacia_wood"] = true
},
["wool:white"] = {
["wool:white"] = true
}
}
--]]
function unified_inventory.find_usable_items(inv_items, craft_items)
local get_group = minetest.get_item_group
local result = {}
for craft_item in pairs(craft_items) do
local group = craft_item:match("^group:(.+)")
local found = {}
if group ~= nil then
for inv_item in pairs(inv_items) do
if get_group(inv_item, group) > 0 then
found[inv_item] = true
end
end
else
if inv_items[craft_item] ~= nil then
found[craft_item] = true
end
end
result[craft_item] = found
end
return result
end
--[[
Match inventory items with craft grid positions.
For every position select the matching inventory item with maximum
(total_count / (times_matched + 1)) value.
If for some position matching item cannot be found or match count is 0
then return nil.
Return a table of "matched item name" - "set of craft positions" pairs
and overall match count.
Arguments:
inv_counts: table of inventory items counts from "count_items"
craft_positions: table of craft positions from "count_craft_positions"
Example output:
match_table = {
["wool:white"] = {[1] = true, [2] = true, [3] = true}
["default:acacia_wood"] = {[4] = true, [6] = true}
["default:pine_wood"] = {[5] = true}
}
match_count = 2
--]]
function unified_inventory.match_items(inv_counts, craft_positions)
local usable = unified_inventory.find_usable_items(inv_counts, craft_positions)
local match_table = {}
local match_count
local matches = {}
for craft_item, pos_set in pairs(craft_positions) do
local use_set = usable[craft_item]
for pos in pairs(pos_set) do
local pos_item
local pos_count
for use_item in pairs(use_set) do
local count = inv_counts[use_item]
local times_matched = matches[use_item] or 0
local new_pos_count = math.floor(count / (times_matched + 1))
if pos_count == nil or pos_count < new_pos_count then
pos_item = use_item
pos_count = new_pos_count
end
end
if pos_item == nil or pos_count == 0 then
return nil
end
local set = match_table[pos_item]
if set ~= nil then
set[pos] = true
else
match_table[pos_item] = {[pos] = true}
end
matches[pos_item] = (matches[pos_item] or 0) + 1
end
end
for match_item, times_matched in pairs(matches) do
local count = inv_counts[match_item]
local item_count = math.floor(count / times_matched)
if match_count == nil or item_count < match_count then
match_count = item_count
end
end
return match_table, match_count
end
--[[
Remove item from inventory lists.
Return stack of actually removed items.
This function replicates the inv:remove_item function but can accept
multiple lists.
Arguments:
inv: minetest inventory reference
lists: names of inventory lists
stack: minetest item stack
--]]
function unified_inventory.remove_item(inv, lists, stack)
local removed = ItemStack(nil)
local leftover = ItemStack(stack)
for i = 1, #lists do
if leftover:is_empty() then
break
end
local cur_removed = inv:remove_item(lists[i], leftover)
removed:add_item(cur_removed)
leftover:take_item(cur_removed:get_count())
end
return removed
end
--[[
Add item to inventory lists.
Return leftover stack.
This function replicates the inv:add_item function but can accept
multiple lists.
Arguments:
inv: minetest inventory reference
lists: names of inventory lists
stack: minetest item stack
--]]
function unified_inventory.add_item(inv, lists, stack)
local leftover = ItemStack(stack)
for i = 1, #lists do
if leftover:is_empty() then
break
end
leftover = inv:add_item(lists[i], leftover)
end
return leftover
end
--[[
Move items from source list to destination list if possible.
Skip positions specified in exclude set.
Arguments:
inv: minetest inventory reference
src_list: name of source list
dst_list: name of destination list
exclude: set of positions to skip
--]]
function unified_inventory.swap_items(inv, src_list, dst_list, exclude)
local size = inv:get_size(src_list)
local empty = ItemStack(nil)
for i = 1, size do
if exclude == nil or exclude[i] == nil then
local stack = inv:get_stack(src_list, i)
if not stack:is_empty() then
inv:set_stack(src_list, i, empty)
local leftover = inv:add_item(dst_list, stack)
if not leftover:is_empty() then
inv:set_stack(src_list, i, leftover)
end
end
end
end
end
--[[
Move matched items to the destination list.
If destination list position is already occupied with some other item
then function tries to (in that order):
1. Move it to the source list
2. Move it to some other unused position in destination list itself
3. Drop it to the ground if nothing else is possible.
Arguments:
player: minetest player object
src_list: name of source list
dst_list: name of destination list
match_table: table of matched items
amount: amount of items per every position
--]]
function unified_inventory.move_match(player, src_list, dst_list, match_table, amount)
local inv = player:get_inventory()
local item_drop = minetest.item_drop
local src_dst_list = {src_list, dst_list}
local dst_src_list = {dst_list, src_list}
local needed = {}
local moved = {}
-- Remove stacks needed for craft
for item, pos_set in pairs(match_table) do
local stack = ItemStack(item)
local stack_max = stack:get_stack_max()
local bounded_amount = math.min(stack_max, amount)
stack:set_count(bounded_amount)
for pos in pairs(pos_set) do
needed[pos] = unified_inventory.remove_item(inv, dst_src_list, stack)
end
end
-- Add already removed stacks
for pos, stack in pairs(needed) do
local occupied = inv:get_stack(dst_list, pos)
inv:set_stack(dst_list, pos, stack)
if not occupied:is_empty() then
local leftover = unified_inventory.add_item(inv, src_dst_list, occupied)
if not leftover:is_empty() then
inv:set_stack(dst_list, pos, leftover)
local oversize = unified_inventory.add_item(inv, src_dst_list, stack)
if not oversize:is_empty() then
item_drop(oversize, player, player:get_pos())
end
end
end
moved[pos] = true
end
-- Swap items from unused positions to src (moved positions excluded)
unified_inventory.swap_items(inv, dst_list, src_list, moved)
end
--[[
Find craft match and move matched items to the destination list.
If match cannot be found or match count is smaller than the desired
amount then do nothing.
If amount passed is -1 then amount is defined by match count itself.
This is used to indicate "craft All" case.
Arguments:
player: minetest player object
src_list: name of source list
dst_list: name of destination list
craft: minetest craft recipe
amount: desired amount of output items
--]]
function unified_inventory.craftguide_match_craft(player, src_list, dst_list, craft, amount)
local inv = player:get_inventory()
local src_dst_list = {src_list, dst_list}
local counts = unified_inventory.count_items(inv, src_dst_list)
local positions = unified_inventory.count_craft_positions(craft)
local match_table, match_count = unified_inventory.match_items(counts, positions)
if match_table == nil or match_count < amount then
return
end
if amount == -1 then
amount = match_count
end
unified_inventory.move_match(player, src_list, dst_list, match_table, amount)
end

View File

@ -0,0 +1,11 @@
name = unified_inventory
depends = default
optional_depends = creative, sfinv, datastorage, farming
description = """
Unified Inventory replaces the default survival and creative inventory.
It adds a nicer interface and a number of features, such as a crafting guide.
"""
min_minetest_version = 5.4.0
release = 7187
author = RealBadAngel
title = Unified Inventory

View File

@ -0,0 +1,518 @@
local S = minetest.get_translator("unified_inventory")
local NS = function(s) return s end
local F = minetest.formspec_escape
local ui = unified_inventory
minetest.register_privilege("creative", {
description = S("Can use the creative inventory"),
give_to_singleplayer = false,
})
minetest.register_privilege("ui_full", {
description = S("Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally"),
give_to_singleplayer = false,
})
local trash = minetest.create_detached_inventory("trash", {
--allow_put = function(inv, listname, index, stack, player)
-- if ui.is_creative(player:get_player_name()) then
-- return stack:get_count()
-- else
-- return 0
-- end
--end,
on_put = function(inv, listname, index, stack, player)
inv:set_stack(listname, index, nil)
local player_name = player:get_player_name()
minetest.sound_play("trash", {to_player=player_name, gain = 1.0})
end,
})
trash:set_size("main", 1)
ui.register_button("craft", {
type = "image",
image = "ui_craft_icon.png",
tooltip = S("Crafting Grid")
})
ui.register_button("craftguide", {
type = "image",
image = "ui_craftguide_icon.png",
tooltip = S("Crafting Guide")
})
ui.register_button("home_gui_set", {
type = "image",
image = "ui_sethome_icon.png",
tooltip = S("Set home position"),
hide_lite=true,
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {home=true}) then
ui.set_home(player, player:get_pos())
local home = ui.home_pos[player_name]
if home ~= nil then
minetest.sound_play("dingdong",
{to_player=player_name, gain = 1.0})
minetest.chat_send_player(player_name,
S("Home position set to: @1", minetest.pos_to_string(home)))
end
else
minetest.chat_send_player(player_name,
S("You don't have the \"home\" privilege!"))
ui.set_inventory_formspec(player, ui.current_page[player_name])
end
end,
condition = function(player)
return minetest.check_player_privs(player:get_player_name(), {home=true})
end,
})
ui.register_button("home_gui_go", {
type = "image",
image = "ui_gohome_icon.png",
tooltip = S("Go home"),
hide_lite=true,
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {home=true}) then
if ui.go_home(player) then
minetest.sound_play("teleport", {to_player = player_name})
end
else
minetest.chat_send_player(player_name,
S("You don't have the \"home\" privilege!"))
ui.set_inventory_formspec(player, ui.current_page[player_name])
end
end,
condition = function(player)
return minetest.check_player_privs(player:get_player_name(), {home=true})
end,
})
ui.register_button("misc_set_day", {
type = "image",
image = "ui_sun_icon.png",
tooltip = S("Set time to day"),
hide_lite=true,
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {settime=true}) then
minetest.sound_play("birds",
{to_player=player_name, gain = 1.0})
minetest.set_timeofday((6000 % 24000) / 24000)
minetest.chat_send_player(player_name,
S("Time of day set to 6am"))
else
minetest.chat_send_player(player_name,
S("You don't have the settime privilege!"))
ui.set_inventory_formspec(player, ui.current_page[player_name])
end
end,
condition = function(player)
return minetest.check_player_privs(player:get_player_name(), {settime=true})
end,
})
ui.register_button("misc_set_night", {
type = "image",
image = "ui_moon_icon.png",
tooltip = S("Set time to night"),
hide_lite=true,
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {settime=true}) then
minetest.sound_play("owl",
{to_player=player_name, gain = 1.0})
minetest.set_timeofday((21000 % 24000) / 24000)
minetest.chat_send_player(player_name,
S("Time of day set to 9pm"))
else
minetest.chat_send_player(player_name,
S("You don't have the settime privilege!"))
ui.set_inventory_formspec(player, ui.current_page[player_name])
end
end,
condition = function(player)
return minetest.check_player_privs(player:get_player_name(), {settime=true})
end,
})
ui.register_button("clear_inv", {
type = "image",
image = "ui_trash_icon.png",
tooltip = S("Clear inventory"),
action = function(player)
local player_name = player:get_player_name()
if not ui.is_creative(player_name) then
minetest.chat_send_player(player_name,
S("This button has been disabled outside"
.." of creative mode to prevent"
.." accidental inventory trashing."
.."\nUse the trash slot instead."))
ui.set_inventory_formspec(player, ui.current_page[player_name])
return
end
player:get_inventory():set_list("main", {})
minetest.chat_send_player(player_name, S('Inventory cleared!'))
minetest.sound_play("trash_all",
{to_player=player_name, gain = 1.0})
end,
condition = function(player)
return ui.is_creative(player:get_player_name())
end,
})
ui.register_page("craft", {
get_formspec = function(player, perplayer_formspec)
local formheaderx = perplayer_formspec.form_header_x
local formheadery = perplayer_formspec.form_header_y
local craftx = perplayer_formspec.craft_x
local crafty = perplayer_formspec.craft_y
local player_name = player:get_player_name()
local formspec = {
perplayer_formspec.standard_inv_bg,
perplayer_formspec.craft_grid,
"label["..formheaderx..","..formheadery..";" ..F(S("Crafting")).."]",
"listcolors[#00000000;#00000000]",
"listring[current_name;craft]",
"listring[current_player;main]"
}
local n=#formspec+1
if ui.trash_enabled or ui.is_creative(player_name) or minetest.get_player_privs(player_name).give then
formspec[n] = string.format("label[%f,%f;%s]", craftx + 6.45, crafty + 2.4, F(S("Trash:")))
formspec[n+1] = ui.make_trash_slot(craftx + 6.25, crafty + 2.5)
n=n + 2
end
if ui.is_creative(player_name) then
formspec[n] = ui.single_slot(craftx - 2.5, crafty + 2.5)
formspec[n+1] = string.format("label[%f,%f;%s]", craftx - 2.3, crafty + 2.4,F(S("Refill:")))
formspec[n+2] = string.format("list[detached:%srefill;main;%f,%f;1,1;]",
F(player_name), craftx - 2.5 + ui.list_img_offset, crafty + 2.5 + ui.list_img_offset)
end
return {formspec=table.concat(formspec)}
end,
})
-- stack_image_button(): generate a form button displaying a stack of items
--
-- The specified item may be a group. In that case, the group will be
-- represented by some item in the group, along with a flag indicating
-- that it's a group. If the group contains only one item, it will be
-- treated as if that item had been specified directly.
local function stack_image_button(x, y, w, h, buttonname_prefix, item)
local name = item:get_name()
local count = item:get_count()
local show_is_group = false
local displayitem = name.." "..count
local selectitem = name
if name:sub(1, 6) == "group:" then
local group_name = name:sub(7)
local group_item = ui.get_group_item(group_name)
show_is_group = not group_item.sole
displayitem = group_item.item or "unknown"
selectitem = group_item.sole and displayitem or name
end
local label = show_is_group and "G" or ""
local buttonname = F(buttonname_prefix..ui.mangle_for_formspec(selectitem))
local button = string.format("item_image_button[%f,%f;%f,%f;%s;%s;%s]",
x, y, w, h,
F(displayitem), buttonname, label)
if show_is_group then
local groupstring, andcount = ui.extract_groupnames(name)
local grouptip
if andcount == 1 then
grouptip = S("Any item belonging to the @1 group", groupstring)
elseif andcount > 1 then
grouptip = S("Any item belonging to the groups @1", groupstring)
end
grouptip = F(grouptip)
if andcount >= 1 then
button = button .. string.format("tooltip[%s;%s]", buttonname, grouptip)
end
end
return button
end
local recipe_text = {
recipe = NS("Recipe @1 of @2"),
usage = NS("Usage @1 of @2"),
}
local no_recipe_text = {
recipe = S("No recipes"),
usage = S("No usages"),
}
local role_text = {
recipe = S("Result"),
usage = S("Ingredient"),
}
local next_alt_text = {
recipe = S("Show next recipe"),
usage = S("Show next usage"),
}
local prev_alt_text = {
recipe = S("Show previous recipe"),
usage = S("Show previous usage"),
}
local other_dir = {
recipe = "usage",
usage = "recipe",
}
ui.register_page("craftguide", {
get_formspec = function(player, perplayer_formspec)
local craftguidex = perplayer_formspec.craft_guide_x
local craftguidey = perplayer_formspec.craft_guide_y
local craftguidearrowx = perplayer_formspec.craft_guide_arrow_x
local craftguideresultx = perplayer_formspec.craft_guide_result_x
local formheaderx = perplayer_formspec.form_header_x
local formheadery = perplayer_formspec.form_header_y
local give_x = perplayer_formspec.give_btn_x
local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name)
local formspec = {
perplayer_formspec.standard_inv_bg,
"label["..formheaderx..","..formheadery..";" .. F(S("Crafting Guide")) .. "]",
"listcolors[#00000000;#00000000]"
}
local item_name = ui.current_item[player_name]
if not item_name then
return { formspec = table.concat(formspec) }
end
local n = 4
local item_name_shown
if minetest.registered_items[item_name]
and minetest.registered_items[item_name].description then
item_name_shown = S("@1 (@2)",
minetest.registered_items[item_name].description, item_name)
else
item_name_shown = item_name
end
local dir = ui.current_craft_direction[player_name]
local rdir = dir == "recipe" and "usage" or "recipe"
local crafts = ui.crafts_for[dir][item_name]
local alternate = ui.alternate[player_name]
local alternates, craft
if crafts and #crafts > 0 then
alternates = #crafts
craft = crafts[alternate]
end
local has_give = player_privs.give or ui.is_creative(player_name)
formspec[n] = string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]",
craftguidearrowx, craftguidey, ui.imgscale, ui.imgscale)
formspec[n+1] = string.format("textarea[%f,%f;10,1;;%s: %s;]",
perplayer_formspec.craft_guide_resultstr_x, perplayer_formspec.craft_guide_resultstr_y,
F(role_text[dir]), item_name_shown)
n = n + 2
local giveme_form = table.concat({
"label[".. (give_x+0.1)..",".. (craftguidey + 2.7) .. ";" .. F(S("Give me:")) .. "]",
"button["..(give_x)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_1;1]",
"button["..(give_x+0.8)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_10;10]",
"button["..(give_x+1.6)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_99;99]"
})
if not craft then
-- No craft recipes available for this item.
formspec[n] = string.format("label[%f,%f;%s]", craftguidex+2.5, craftguidey+1.5, F(no_recipe_text[dir]))
local no_pos = dir == "recipe" and (craftguidex+2.5) or craftguideresultx
local item_pos = dir == "recipe" and craftguideresultx or (craftguidex+2.5)
formspec[n+1] = "image["..no_pos..","..craftguidey..";1.2,1.2;ui_no.png]"
formspec[n+2] = stack_image_button(item_pos, craftguidey, 1.2, 1.2,
"item_button_" .. other_dir[dir] .. "_", ItemStack(item_name))
if has_give then
formspec[n+3] = giveme_form
end
return { formspec = table.concat(formspec) }
else
formspec[n] = stack_image_button(craftguideresultx, craftguidey, 1.2, 1.2,
"item_button_" .. rdir .. "_", ItemStack(craft.output))
n = n + 1
end
local craft_type = ui.registered_craft_types[craft.type] or
ui.craft_type_defaults(craft.type, {})
if craft_type.icon then
formspec[n] = string.format("image[%f,%f;%f,%f;%s]",
craftguidearrowx+0.35, craftguidey, 0.5, 0.5, craft_type.icon)
n = n + 1
end
formspec[n] = string.format("label[%f,%f;%s]", craftguidearrowx + 0.15, craftguidey + 1.4, F(craft_type.description))
n = n + 1
local display_size = craft_type.dynamic_display_size
and craft_type.dynamic_display_size(craft)
or { width = craft_type.width, height = craft_type.height }
local craft_width = craft_type.get_shaped_craft_width
and craft_type.get_shaped_craft_width(craft)
or display_size.width
-- This keeps recipes aligned to the right,
-- so that they're close to the arrow.
local xoffset = craftguidex+3.75
local bspc = 1.25
-- Offset factor for crafting grids with side length > 4
local of = (3/math.max(3, math.max(display_size.width, display_size.height)))
local od = 0
-- Minimum grid size at which size optimization measures kick in
local mini_craft_size = 6
if display_size.width >= mini_craft_size then
od = math.max(1, display_size.width - 2)
xoffset = xoffset - 0.1
end
-- Size modifier factor
local sf = math.min(1, of * (1.05 + 0.05*od))
-- Button size
local bsize = 1.2 * sf
if display_size.width >= mini_craft_size then -- it's not a normal 3x3 grid
bsize = 0.8 * sf
end
if (bsize > 0.35 and display_size.width) then
for y = 1, display_size.height do
for x = 1, display_size.width do
local item
if craft and x <= craft_width then
item = craft.items[(y-1) * craft_width + x]
end
-- Flipped x, used to build formspec buttons from right to left
local fx = display_size.width - (x-1)
-- x offset, y offset
local xof = ((fx-1) * of + of) * bspc
local yof = ((y-1) * of + 1) * bspc
if item then
formspec[n] = stack_image_button(
xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize,
"item_button_recipe_",
ItemStack(item))
else
-- Fake buttons just to make grid
formspec[n] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]",
xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize)
end
n = n + 1
end
end
else
-- Error
formspec[n] = string.format("label[2,%f;%s]",
craftguidey, F(S("This recipe is too@nlarge to be displayed.")))
n = n + 1
end
if craft_type.uses_crafting_grid and display_size.width <= 3 then
formspec[n] = "label["..(give_x+0.1)..",".. (craftguidey + 1.7) .. ";" .. F(S("To craft grid:")) .. "]"
formspec[n+1] = "button[".. (give_x)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_1;1]"
formspec[n+2] = "button[".. (give_x+0.8)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_10;10]"
formspec[n+3] = "button[".. (give_x+1.6)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_max;" .. F(S("All")) .. "]"
n = n + 4
end
if has_give then
formspec[n] = giveme_form
n = n + 1
end
if alternates and alternates > 1 then
formspec[n] = string.format("label[%f,%f;%s]",
craftguidex+4, craftguidey + 2.3, F(S(recipe_text[dir], alternate, alternates)))
formspec[n+1] = string.format("image_button[%f,%f;1.1,1.1;ui_left_icon.png;alternate_prev;]",
craftguidearrowx+0.2, craftguidey + 2.6)
formspec[n+2] = string.format("image_button[%f,%f;1.1,1.1;ui_right_icon.png;alternate;]",
craftguidearrowx+1.35, craftguidey + 2.6)
formspec[n+3] = "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]"
formspec[n+4] = "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]"
end
return { formspec = table.concat(formspec) }
end,
})
local function craftguide_giveme(player, formname, fields)
local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name)
if not player_privs.give and
not ui.is_creative(player_name) then
minetest.log("action", "[unified_inventory] Denied give action to player " ..
player_name)
return
end
local amount
for k, v in pairs(fields) do
amount = k:match("craftguide_giveme_(.*)")
if amount then break end
end
amount = tonumber(amount) or 0
if amount == 0 then return end
local output = ui.current_item[player_name]
if (not output) or (output == "") then return end
local player_inv = player:get_inventory()
player_inv:add_item("main", {name = output, count = amount})
end
local function craftguide_craft(player, formname, fields)
local amount
for k, v in pairs(fields) do
amount = k:match("craftguide_craft_(.*)")
if amount then break end
end
if not amount then return end
amount = tonumber(amount) or -1 -- fallback for "all"
if amount == 0 or amount < -1 or amount > 99 then return end
local player_name = player:get_player_name()
local output = ui.current_item[player_name] or ""
if output == "" then return end
local crafts = ui.crafts_for[
ui.current_craft_direction[player_name]][output] or {}
if #crafts == 0 then return end
local alternate = ui.alternate[player_name]
local craft = crafts[alternate]
if craft.width > 3 then return end
ui.craftguide_match_craft(player, "main", "craft", craft, amount)
ui.set_inventory_formspec(player, "craft")
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then
return
end
for k, v in pairs(fields) do
if k:match("craftguide_craft_") then
craftguide_craft(player, formname, fields)
return
end
if k:match("craftguide_giveme_") then
craftguide_giveme(player, formname, fields)
return
end
end
end)

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -0,0 +1,11 @@
#Enabling lite mode enables a smaller and simpler version of the Unified
#Inventory, optimized for small displays.
unified_inventory_lite (Lite mode) bool false
#If enabled, bags will be made available which can be used to extend
#inventory storage size.
unified_inventory_bags (Enable bags) bool true
#If enabled, the trash slot can be used by those without both creative
#and the give privilege.
unified_inventory_trash (Enable trash) bool true

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Some files were not shown because too many files have changed in this diff Show More