diff --git a/mods/extra_mp/item_drop/.luacheckrc b/mods/extra_mp/item_drop/.luacheckrc new file mode 100644 index 0000000..a9c034e --- /dev/null +++ b/mods/extra_mp/item_drop/.luacheckrc @@ -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", +} diff --git a/mods/extra_mp/item_drop/CONTRIBUTING.md b/mods/extra_mp/item_drop/CONTRIBUTING.md new file mode 100644 index 0000000..16a26e3 --- /dev/null +++ b/mods/extra_mp/item_drop/CONTRIBUTING.md @@ -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. diff --git a/mods/extra_mp/item_drop/LICENSE b/mods/extra_mp/item_drop/LICENSE new file mode 100644 index 0000000..19e3071 --- /dev/null +++ b/mods/extra_mp/item_drop/LICENSE @@ -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! diff --git a/mods/extra_mp/item_drop/README.md b/mods/extra_mp/item_drop/README.md new file mode 100644 index 0000000..771e82d --- /dev/null +++ b/mods/extra_mp/item_drop/README.md @@ -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) diff --git a/mods/extra_mp/item_drop/description.txt b/mods/extra_mp/item_drop/description.txt new file mode 100644 index 0000000..ef32f14 --- /dev/null +++ b/mods/extra_mp/item_drop/description.txt @@ -0,0 +1 @@ +A highly configurable mod providing item magnet and in-world node drops diff --git a/mods/extra_mp/item_drop/init.lua b/mods/extra_mp/item_drop/init.lua new file mode 100644 index 0000000..64ceed2 --- /dev/null +++ b/mods/extra_mp/item_drop/init.lua @@ -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 diff --git a/mods/extra_mp/item_drop/mod.conf b/mods/extra_mp/item_drop/mod.conf new file mode 100644 index 0000000..8966913 --- /dev/null +++ b/mods/extra_mp/item_drop/mod.conf @@ -0,0 +1,2 @@ +name = item_drop +description = A highly configurable mod providing item magnet and in-world node drops diff --git a/mods/extra_mp/item_drop/screenshot.png b/mods/extra_mp/item_drop/screenshot.png new file mode 100644 index 0000000..1313e40 Binary files /dev/null and b/mods/extra_mp/item_drop/screenshot.png differ diff --git a/mods/extra_mp/item_drop/settingtypes.txt b/mods/extra_mp/item_drop/settingtypes.txt new file mode 100644 index 0000000..14df02c --- /dev/null +++ b/mods/extra_mp/item_drop/settingtypes.txt @@ -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 diff --git a/mods/extra_mp/item_drop/sounds/item_drop_pickup.1.ogg b/mods/extra_mp/item_drop/sounds/item_drop_pickup.1.ogg new file mode 100644 index 0000000..2ae432d Binary files /dev/null and b/mods/extra_mp/item_drop/sounds/item_drop_pickup.1.ogg differ diff --git a/mods/extra_mp/item_drop/sounds/item_drop_pickup.2.ogg b/mods/extra_mp/item_drop/sounds/item_drop_pickup.2.ogg new file mode 100644 index 0000000..f58bf08 Binary files /dev/null and b/mods/extra_mp/item_drop/sounds/item_drop_pickup.2.ogg differ diff --git a/mods/extra_mp/item_drop/sounds/item_drop_pickup.3.ogg b/mods/extra_mp/item_drop/sounds/item_drop_pickup.3.ogg new file mode 100644 index 0000000..cf57c94 Binary files /dev/null and b/mods/extra_mp/item_drop/sounds/item_drop_pickup.3.ogg differ diff --git a/mods/extra_mp/item_drop/sounds/item_drop_pickup.4.ogg b/mods/extra_mp/item_drop/sounds/item_drop_pickup.4.ogg new file mode 100644 index 0000000..bfe99d9 Binary files /dev/null and b/mods/extra_mp/item_drop/sounds/item_drop_pickup.4.ogg differ diff --git a/mods/extra_mp/modpack.txt b/mods/extra_mp/modpack.txt new file mode 100644 index 0000000..e69de29 diff --git a/mods/extra_mp/toolranks/README.md b/mods/extra_mp/toolranks/README.md new file mode 100644 index 0000000..43516ec --- /dev/null +++ b/mods/extra_mp/toolranks/README.md @@ -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. diff --git a/mods/extra_mp/toolranks/depends.txt b/mods/extra_mp/toolranks/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/mods/extra_mp/toolranks/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/extra_mp/toolranks/init.lua b/mods/extra_mp/toolranks/init.lua new file mode 100644 index 0000000..4a75297 --- /dev/null +++ b/mods/extra_mp/toolranks/init.lua @@ -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 diff --git a/mods/extra_mp/toolranks/license.txt b/mods/extra_mp/toolranks/license.txt new file mode 100644 index 0000000..1eff911 --- /dev/null +++ b/mods/extra_mp/toolranks/license.txt @@ -0,0 +1,2 @@ +Code: LGPLv2.1+ +Sounds: CC BY 3.0 diff --git a/mods/extra_mp/toolranks/mod.conf b/mods/extra_mp/toolranks/mod.conf new file mode 100644 index 0000000..5cc00b0 --- /dev/null +++ b/mods/extra_mp/toolranks/mod.conf @@ -0,0 +1,4 @@ +name = toolranks +depends = default +optional_depends = +description = Add ability to level up tools to make them last longer. diff --git a/mods/extra_mp/toolranks/sounds/toolranks_levelup.ogg b/mods/extra_mp/toolranks/sounds/toolranks_levelup.ogg new file mode 100644 index 0000000..03b5b17 Binary files /dev/null and b/mods/extra_mp/toolranks/sounds/toolranks_levelup.ogg differ diff --git a/mods/extra_mp/unified_inventory/.luacheckrc b/mods/extra_mp/unified_inventory/.luacheckrc new file mode 100644 index 0000000..9fb6a7c --- /dev/null +++ b/mods/extra_mp/unified_inventory/.luacheckrc @@ -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" } diff --git a/mods/extra_mp/unified_inventory/LICENSE.txt b/mods/extra_mp/unified_inventory/LICENSE.txt new file mode 100644 index 0000000..32492e4 --- /dev/null +++ b/mods/extra_mp/unified_inventory/LICENSE.txt @@ -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. diff --git a/mods/extra_mp/unified_inventory/README.md b/mods/extra_mp/unified_inventory/README.md new file mode 100644 index 0000000..d159c02 --- /dev/null +++ b/mods/extra_mp/unified_inventory/README.md @@ -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`: and + * [`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. diff --git a/mods/extra_mp/unified_inventory/api.lua b/mods/extra_mp/unified_inventory/api.lua new file mode 100644 index 0000000..05a34ee --- /dev/null +++ b/mods/extra_mp/unified_inventory/api.lua @@ -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 diff --git a/mods/extra_mp/unified_inventory/bags.lua b/mods/extra_mp/unified_inventory/bags.lua new file mode 100644 index 0000000..14ac875 --- /dev/null +++ b/mods/extra_mp/unified_inventory/bags.lua @@ -0,0 +1,280 @@ +--[[ +Bags for Minetest + +Copyright (c) 2012 cornernote, Brett O'Donnell +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 diff --git a/mods/extra_mp/unified_inventory/callbacks.lua b/mods/extra_mp/unified_inventory/callbacks.lua new file mode 100644 index 0000000..bc90237 --- /dev/null +++ b/mods/extra_mp/unified_inventory/callbacks.lua @@ -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 diff --git a/mods/extra_mp/unified_inventory/doc/mod_api.txt b/mods/extra_mp/unified_inventory/doc/mod_api.txt new file mode 100644 index 0000000..0d100a0 --- /dev/null +++ b/mods/extra_mp/unified_inventory/doc/mod_api.txt @@ -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` + }) + diff --git a/mods/extra_mp/unified_inventory/group.lua b/mods/extra_mp/unified_inventory/group.lua new file mode 100644 index 0000000..3864267 --- /dev/null +++ b/mods/extra_mp/unified_inventory/group.lua @@ -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 + diff --git a/mods/extra_mp/unified_inventory/image_credits.txt b/mods/extra_mp/unified_inventory/image_credits.txt new file mode 100644 index 0000000..12fbc65 --- /dev/null +++ b/mods/extra_mp/unified_inventory/image_credits.txt @@ -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 diff --git a/mods/extra_mp/unified_inventory/init.lua b/mods/extra_mp/unified_inventory/init.lua new file mode 100644 index 0000000..231da9e --- /dev/null +++ b/mods/extra_mp/unified_inventory/init.lua @@ -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 diff --git a/mods/extra_mp/unified_inventory/internal.lua b/mods/extra_mp/unified_inventory/internal.lua new file mode 100644 index 0000000..d92b932 --- /dev/null +++ b/mods/extra_mp/unified_inventory/internal.lua @@ -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 diff --git a/mods/extra_mp/unified_inventory/item_names.lua b/mods/extra_mp/unified_inventory/item_names.lua new file mode 100644 index 0000000..a1368f8 --- /dev/null +++ b/mods/extra_mp/unified_inventory/item_names.lua @@ -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) + diff --git a/mods/extra_mp/unified_inventory/locale/template.pot b/mods/extra_mp/unified_inventory/locale/template.pot new file mode 100644 index 0000000..105fd64 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/template.pot @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "" diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.de.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.de.tr new file mode 100644 index 0000000..e2a05be --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.de.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.es.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.es.tr new file mode 100644 index 0000000..18b6c77 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.es.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.fr.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.fr.tr new file mode 100644 index 0000000..5367ddb --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.fr.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.it.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.it.tr new file mode 100644 index 0000000..1bf7660 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.it.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.ms.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.ms.tr new file mode 100644 index 0000000..25fc853 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.ms.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.pl.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.pl.tr new file mode 100644 index 0000000..19121d8 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.pl.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.pt.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.pt.tr new file mode 100644 index 0000000..3b0b902 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.pt.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.ru.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.ru.tr new file mode 100644 index 0000000..f2a2300 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.ru.tr @@ -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а diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.template.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.template.tr new file mode 100644 index 0000000..2ea4fca --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.template.tr @@ -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= diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.tr.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.tr.tr new file mode 100644 index 0000000..93246cc --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.tr.tr @@ -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 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.zh_CN.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.zh_CN.tr new file mode 100644 index 0000000..30e15e3 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.zh_CN.tr @@ -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的任何项目 diff --git a/mods/extra_mp/unified_inventory/locale/unified_inventory.zh_TW.tr b/mods/extra_mp/unified_inventory/locale/unified_inventory.zh_TW.tr new file mode 100644 index 0000000..3e8d1a1 --- /dev/null +++ b/mods/extra_mp/unified_inventory/locale/unified_inventory.zh_TW.tr @@ -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的任何項目 diff --git a/mods/extra_mp/unified_inventory/match_craft.lua b/mods/extra_mp/unified_inventory/match_craft.lua new file mode 100644 index 0000000..2dd40b0 --- /dev/null +++ b/mods/extra_mp/unified_inventory/match_craft.lua @@ -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 diff --git a/mods/extra_mp/unified_inventory/mod.conf b/mods/extra_mp/unified_inventory/mod.conf new file mode 100644 index 0000000..90ca5a7 --- /dev/null +++ b/mods/extra_mp/unified_inventory/mod.conf @@ -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 diff --git a/mods/extra_mp/unified_inventory/register.lua b/mods/extra_mp/unified_inventory/register.lua new file mode 100644 index 0000000..3cb5f59 --- /dev/null +++ b/mods/extra_mp/unified_inventory/register.lua @@ -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) diff --git a/mods/extra_mp/unified_inventory/screenshot.png b/mods/extra_mp/unified_inventory/screenshot.png new file mode 100644 index 0000000..972cbb4 Binary files /dev/null and b/mods/extra_mp/unified_inventory/screenshot.png differ diff --git a/mods/extra_mp/unified_inventory/settingtypes.txt b/mods/extra_mp/unified_inventory/settingtypes.txt new file mode 100644 index 0000000..910989f --- /dev/null +++ b/mods/extra_mp/unified_inventory/settingtypes.txt @@ -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 diff --git a/mods/extra_mp/unified_inventory/sounds/birds.ogg b/mods/extra_mp/unified_inventory/sounds/birds.ogg new file mode 100644 index 0000000..4a93395 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/birds.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/click.ogg b/mods/extra_mp/unified_inventory/sounds/click.ogg new file mode 100644 index 0000000..3db63a0 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/click.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/dingdong.ogg b/mods/extra_mp/unified_inventory/sounds/dingdong.ogg new file mode 100644 index 0000000..2c9d7ef Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/dingdong.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/electricity.ogg b/mods/extra_mp/unified_inventory/sounds/electricity.ogg new file mode 100644 index 0000000..4cd7c84 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/electricity.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/owl.ogg b/mods/extra_mp/unified_inventory/sounds/owl.ogg new file mode 100644 index 0000000..f30d0b3 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/owl.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/paperflip1.ogg b/mods/extra_mp/unified_inventory/sounds/paperflip1.ogg new file mode 100644 index 0000000..eaed13f Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/paperflip1.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/paperflip2.ogg b/mods/extra_mp/unified_inventory/sounds/paperflip2.ogg new file mode 100644 index 0000000..321bc48 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/paperflip2.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/teleport.ogg b/mods/extra_mp/unified_inventory/sounds/teleport.ogg new file mode 100644 index 0000000..ca32f74 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/teleport.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/trash.ogg b/mods/extra_mp/unified_inventory/sounds/trash.ogg new file mode 100644 index 0000000..51e4f24 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/trash.ogg differ diff --git a/mods/extra_mp/unified_inventory/sounds/trash_all.ogg b/mods/extra_mp/unified_inventory/sounds/trash_all.ogg new file mode 100644 index 0000000..85c3f66 Binary files /dev/null and b/mods/extra_mp/unified_inventory/sounds/trash_all.ogg differ diff --git a/mods/extra_mp/unified_inventory/textures/bags_large.png b/mods/extra_mp/unified_inventory/textures/bags_large.png new file mode 100644 index 0000000..187021c Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/bags_large.png differ diff --git a/mods/extra_mp/unified_inventory/textures/bags_medium.png b/mods/extra_mp/unified_inventory/textures/bags_medium.png new file mode 100644 index 0000000..d908883 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/bags_medium.png differ diff --git a/mods/extra_mp/unified_inventory/textures/bags_small.png b/mods/extra_mp/unified_inventory/textures/bags_small.png new file mode 100644 index 0000000..9e4f4f6 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/bags_small.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_1_icon.png b/mods/extra_mp/unified_inventory/textures/ui_1_icon.png new file mode 100644 index 0000000..ed4ceb9 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_1_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_2_icon.png b/mods/extra_mp/unified_inventory/textures/ui_2_icon.png new file mode 100644 index 0000000..f4566d8 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_2_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_3_icon.png b/mods/extra_mp/unified_inventory/textures/ui_3_icon.png new file mode 100644 index 0000000..ff6ebbb Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_3_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_4_icon.png b/mods/extra_mp/unified_inventory/textures/ui_4_icon.png new file mode 100644 index 0000000..3a12bfd Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_4_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_5_icon.png b/mods/extra_mp/unified_inventory/textures/ui_5_icon.png new file mode 100644 index 0000000..c389152 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_5_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_bags_icon.png b/mods/extra_mp/unified_inventory/textures/ui_bags_icon.png new file mode 100644 index 0000000..2882a23 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_bags_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_blank_image.png b/mods/extra_mp/unified_inventory/textures/ui_blank_image.png new file mode 100644 index 0000000..83d9d1a Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_blank_image.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_blue_icon_background.png b/mods/extra_mp/unified_inventory/textures/ui_blue_icon_background.png new file mode 100644 index 0000000..2f872a4 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_blue_icon_background.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_circular_arrows_icon.png b/mods/extra_mp/unified_inventory/textures/ui_circular_arrows_icon.png new file mode 100644 index 0000000..c6846e6 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_circular_arrows_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_craft_icon.png b/mods/extra_mp/unified_inventory/textures/ui_craft_icon.png new file mode 100644 index 0000000..a2283e3 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_craft_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_craftgrid_icon.png b/mods/extra_mp/unified_inventory/textures/ui_craftgrid_icon.png new file mode 100644 index 0000000..5111f1e Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_craftgrid_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_craftguide_icon.png b/mods/extra_mp/unified_inventory/textures/ui_craftguide_icon.png new file mode 100644 index 0000000..d6c89e6 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_craftguide_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_crafting_arrow.png b/mods/extra_mp/unified_inventory/textures/ui_crafting_arrow.png new file mode 100644 index 0000000..6901c58 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_crafting_arrow.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_doubleleft_icon.png b/mods/extra_mp/unified_inventory/textures/ui_doubleleft_icon.png new file mode 100644 index 0000000..64d50c0 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_doubleleft_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_doubleright_icon.png b/mods/extra_mp/unified_inventory/textures/ui_doubleright_icon.png new file mode 100644 index 0000000..af20930 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_doubleright_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_formbg_9_sliced.png b/mods/extra_mp/unified_inventory/textures/ui_formbg_9_sliced.png new file mode 100644 index 0000000..0b8463c Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_formbg_9_sliced.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_gohome_icon.png b/mods/extra_mp/unified_inventory/textures/ui_gohome_icon.png new file mode 100644 index 0000000..c5126ae Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_gohome_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_green_icon_background.png b/mods/extra_mp/unified_inventory/textures/ui_green_icon_background.png new file mode 100644 index 0000000..ea28c82 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_green_icon_background.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_group.png b/mods/extra_mp/unified_inventory/textures/ui_group.png new file mode 100644 index 0000000..b6b8d28 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_group.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_home_icon.png b/mods/extra_mp/unified_inventory/textures/ui_home_icon.png new file mode 100644 index 0000000..b9ce4f3 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_home_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_left_icon.png b/mods/extra_mp/unified_inventory/textures/ui_left_icon.png new file mode 100644 index 0000000..373b71e Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_left_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_moon_icon.png b/mods/extra_mp/unified_inventory/textures/ui_moon_icon.png new file mode 100644 index 0000000..cec7009 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_moon_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_no.png b/mods/extra_mp/unified_inventory/textures/ui_no.png new file mode 100644 index 0000000..aa98ed6 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_no.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_off_icon.png b/mods/extra_mp/unified_inventory/textures/ui_off_icon.png new file mode 100644 index 0000000..187e59a Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_off_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_ok_icon.png b/mods/extra_mp/unified_inventory/textures/ui_ok_icon.png new file mode 100644 index 0000000..4073899 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_ok_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_on_icon.png b/mods/extra_mp/unified_inventory/textures/ui_on_icon.png new file mode 100644 index 0000000..0f5c48f Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_on_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_pencil_icon.png b/mods/extra_mp/unified_inventory/textures/ui_pencil_icon.png new file mode 100644 index 0000000..dfcc19b Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_pencil_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_red_icon_background.png b/mods/extra_mp/unified_inventory/textures/ui_red_icon_background.png new file mode 100644 index 0000000..8d4d807 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_red_icon_background.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_reset_icon.png b/mods/extra_mp/unified_inventory/textures/ui_reset_icon.png new file mode 100644 index 0000000..e966685 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_reset_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_right_icon.png b/mods/extra_mp/unified_inventory/textures/ui_right_icon.png new file mode 100644 index 0000000..cbdab76 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_right_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_search_icon.png b/mods/extra_mp/unified_inventory/textures/ui_search_icon.png new file mode 100644 index 0000000..2934bdc Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_search_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_sethome_icon.png b/mods/extra_mp/unified_inventory/textures/ui_sethome_icon.png new file mode 100644 index 0000000..4c0f6e5 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_sethome_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_single_slot.png b/mods/extra_mp/unified_inventory/textures/ui_single_slot.png new file mode 100644 index 0000000..2451623 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_single_slot.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_single_slot_bright.png b/mods/extra_mp/unified_inventory/textures/ui_single_slot_bright.png new file mode 100644 index 0000000..c66365c Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_single_slot_bright.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_skip_backward_icon.png b/mods/extra_mp/unified_inventory/textures/ui_skip_backward_icon.png new file mode 100644 index 0000000..eac6e4c Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_skip_backward_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_skip_forward_icon.png b/mods/extra_mp/unified_inventory/textures/ui_skip_forward_icon.png new file mode 100644 index 0000000..3f85a9f Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_skip_forward_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_sun_icon.png b/mods/extra_mp/unified_inventory/textures/ui_sun_icon.png new file mode 100644 index 0000000..11c7eef Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_sun_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_trash_icon.png b/mods/extra_mp/unified_inventory/textures/ui_trash_icon.png new file mode 100644 index 0000000..c5ac97c Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_trash_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_trash_slot_icon.png b/mods/extra_mp/unified_inventory/textures/ui_trash_slot_icon.png new file mode 100644 index 0000000..5fc4de1 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_trash_slot_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_waypoint_set_icon.png b/mods/extra_mp/unified_inventory/textures/ui_waypoint_set_icon.png new file mode 100644 index 0000000..4649a4d Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_waypoint_set_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_waypoints_icon.png b/mods/extra_mp/unified_inventory/textures/ui_waypoints_icon.png new file mode 100644 index 0000000..91d6e3b Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_waypoints_icon.png differ diff --git a/mods/extra_mp/unified_inventory/textures/ui_xyz_icon.png b/mods/extra_mp/unified_inventory/textures/ui_xyz_icon.png new file mode 100644 index 0000000..003ea63 Binary files /dev/null and b/mods/extra_mp/unified_inventory/textures/ui_xyz_icon.png differ diff --git a/mods/extra_mp/unified_inventory/waypoints.lua b/mods/extra_mp/unified_inventory/waypoints.lua new file mode 100644 index 0000000..2a8ead4 --- /dev/null +++ b/mods/extra_mp/unified_inventory/waypoints.lua @@ -0,0 +1,244 @@ +local S = minetest.get_translator("unified_inventory") +local F = minetest.formspec_escape +local ui = unified_inventory + +local hud_colors = { + {"#FFFFFF", 0xFFFFFF, S("White")}, + {"#DBBB00", 0xf1d32c, S("Yellow")}, + {"#DD0000", 0xDD0000, S("Red")}, + {"#2cf136", 0x2cf136, S("Green")}, + {"#2c4df1", 0x2c4df1, S("Blue")}, +} + +local hud_colors_max = #hud_colors + +-- Stores temporary player data (persists until player leaves) +local waypoints_temp = {} + +ui.register_page("waypoints", { + get_formspec = function(player) + local player_name = player:get_player_name() + local wp_info_x = ui.style_full.form_header_x + 1.25 + local wp_info_y = ui.style_full.form_header_y + 0.5 + local wp_bottom_row = ui.style_full.std_inv_y - 1 + local wp_buttons_rj = ui.style_full.std_inv_x + 10.1 - ui.style_full.btn_spc + local wp_edit_w = ui.style_full.btn_spc * 4 - 0.1 + + -- build a "fake" temp entry if the server took too long + -- during sign-on and returned an empty entry + if not waypoints_temp[player_name] then waypoints_temp[player_name] = {hud = 1} end + + local waypoints = datastorage.get(player_name, "waypoints") + local formspec = { ui.style_full.standard_inv_bg, + string.format("label[%f,%f;%s]", + ui.style_full.form_header_x, ui.style_full.form_header_y, + F(S("Waypoints"))), + "image["..wp_info_x..","..wp_info_y..";1,1;ui_waypoints_icon.png]" + } + local n=4 + + -- Tabs buttons: + for i = 1, 5 do + local sw="select_waypoint"..i + formspec[n] = string.format("image_button[%f,%f;%f,%f;%sui_%i_icon.png;%s;]", + ui.style_full.main_button_x, wp_bottom_row - (5-i) * ui.style_full.btn_spc, + ui.style_full.btn_size, ui.style_full.btn_size, + (i == waypoints.selected) and "ui_blue_icon_background.png^" or "", + i, sw) + formspec[n+1] = "tooltip["..sw..";"..S("Select Waypoint #@1", i).."]" + n = n + 2 + end + + local i = waypoints.selected or 1 + local waypoint = waypoints[i] or {} + local temp = waypoints_temp[player_name][i] or {} + local default_name = S("Waypoint @1", i) + + -- Main buttons: + local btnlist = { + { "ui_waypoint_set_icon.png", "set_waypoint", S("Set waypoint to current location") }, + { waypoint.active and "ui_on_icon.png" or "ui_off_icon.png", "toggle_waypoint", S("Make waypoint @1", waypoint.active and "invisible" or "visible") }, + { waypoint.display_pos and "ui_green_icon_background.png^ui_xyz_icon.png" or "ui_red_icon_background.png^ui_xyz_icon.png^(ui_no.png^[transformR90)", "toggle_display_pos", S("@1 display of waypoint coordinates", waypoint.display_pos and "Disable" or "Enable") }, + { "ui_circular_arrows_icon.png", "toggle_color", S("Change color of waypoint display") }, + { "ui_pencil_icon.png", "rename_waypoint", S("Edit waypoint name") } + } + + local x = 4 + for _, b in pairs(btnlist) do + formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s%i;]", + wp_buttons_rj - ui.style_full.btn_spc * x, wp_bottom_row, + ui.style_full.btn_size, ui.style_full.btn_size, + b[1], b[2], i) + formspec[n+1] = "tooltip["..b[2]..i..";"..F(b[3]).."]" + x = x - 1 + n = n + 2 + end + + -- Waypoint's info: + formspec[n] = "label["..wp_info_x..","..(wp_info_y+1.1)..";" + if waypoint.active then + formspec[n+1] = F(S("Waypoint active")).."]" + else + formspec[n+1] = F(S("Waypoint inactive")).."]" + end + n = n + 2 + + if temp.edit then + formspec[n] = string.format("field[%f,%f;%f,%f;rename_box%i;;%s]", + wp_buttons_rj - wp_edit_w - 0.1, wp_bottom_row - ui.style_full.btn_spc, + wp_edit_w, ui.style_full.btn_size, i, (waypoint.name or default_name)) + formspec[n+1] = string.format("image_button[%f,%f;%f,%f;ui_ok_icon.png;confirm_rename%i;]", + wp_buttons_rj, wp_bottom_row - ui.style_full.btn_spc, + ui.style_full.btn_size, ui.style_full.btn_size, i) + formspec[n+2] = "tooltip[confirm_rename"..i..";"..F(S("Finish editing")).."]" + n = n + 3 + end + + formspec[n] = string.format("label[%f,%f;%s: %s]", + wp_info_x, wp_info_y+1.6, F(S("World position")), + minetest.pos_to_string(waypoint.world_pos or vector.new())) + formspec[n+1] = string.format("label[%f,%f;%s: %s]", + wp_info_x, wp_info_y+2.10, F(S("Name")), (waypoint.name or default_name)) + formspec[n+2] = string.format("label[%f,%f;%s: %s]", + wp_info_x, wp_info_y+2.60, F(S("HUD text color")), hud_colors[waypoint.color or 1][3]) + + return {formspec=table.concat(formspec)} + end, +}) + +ui.register_button("waypoints", { + type = "image", + image = "ui_waypoints_icon.png", + tooltip = S("Waypoints"), + hide_lite=true +}) + +local function update_hud(player, waypoints, temp, i) + local waypoint = waypoints[i] + if not waypoint then return end + temp[i] = temp[i] or {} + temp = temp[i] + local pos = waypoint.world_pos or vector.new() + local name + if waypoint.display_pos then + name = minetest.pos_to_string(pos) + if waypoint.name then + name = name..", "..waypoint.name + end + else + name = waypoint.name or "Waypoint "..i + end + if temp.hud then + player:hud_remove(temp.hud) + end + if waypoint.active then + temp.hud = player:hud_add({ + hud_elem_type = "waypoint", + number = hud_colors[waypoint.color or 1][2] , + name = name, + text = "m", + world_pos = pos + }) + else + temp.hud = nil + end +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "" then return end + + local player_name = player:get_player_name() + local update_formspec = false + local need_update_hud = false + local hit = false + + local waypoints = datastorage.get(player_name, "waypoints") + local temp = waypoints_temp[player_name] + for i = 1, 5, 1 do + if fields["select_waypoint"..i] then + hit = true + waypoints.selected = i + update_formspec = true + end + + if fields["toggle_waypoint"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + waypoints[i].active = not (waypoints[i].active) + need_update_hud = true + update_formspec = true + end + + if fields["set_waypoint"..i] then + hit = true + local pos = player:get_pos() + pos.x = math.floor(pos.x) + pos.y = math.floor(pos.y) + pos.z = math.floor(pos.z) + waypoints[i] = waypoints[i] or {} + waypoints[i].world_pos = pos + need_update_hud = true + update_formspec = true + end + + if fields["rename_waypoint"..i] then + hit = true + temp[i] = temp[i] or {} + temp[i].edit = true + update_formspec = true + end + + if fields["toggle_display_pos"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + waypoints[i].display_pos = not waypoints[i].display_pos + need_update_hud = true + update_formspec = true + end + + if fields["toggle_color"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + local color = waypoints[i].color or 1 + color = color + 1 + if color > hud_colors_max then + color = 1 + end + waypoints[i].color = color + need_update_hud = true + update_formspec = true + end + + if fields["confirm_rename"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + temp[i].edit = false + waypoints[i].name = fields["rename_box"..i] + need_update_hud = true + update_formspec = true + end + if need_update_hud then + update_hud(player, waypoints, temp, i) + end + if update_formspec then + ui.set_inventory_formspec(player, "waypoints") + end + if hit then return end + end +end) + + +minetest.register_on_joinplayer(function(player) + local player_name = player:get_player_name() + local waypoints = datastorage.get(player_name, "waypoints") + local temp = {} + waypoints_temp[player_name] = temp + for i = 1, 5 do + update_hud(player, waypoints, temp, i) + end +end) + +minetest.register_on_leaveplayer(function(player) + waypoints_temp[player:get_player_name()] = nil +end) + diff --git a/mods/nethermp/nether/items.lua b/mods/nethermp/nether/items.lua index cc67ae9..8e92b7d 100644 --- a/mods/nethermp/nether/items.lua +++ b/mods/nethermp/nether/items.lua @@ -1008,6 +1008,36 @@ minetest.register_tool("nether:sword_white", { }, }) +if minetest.get_modpath("toolranks") then + + -- Helper function + local function add_tool(name, desc, afteruse) + + minetest.override_item(name, { + original_description = desc, + description = toolranks.create_description(desc, 0, 1), + after_use = afteruse and toolranks.new_afteruse + }) + end + + add_tool("nether:pick_mushroom", "Nether Mushroom Pickaxe", true) + add_tool("nether:pick_wood", "Nether Wood Pickaxe", true) + add_tool("nether:pick_netherrack", "Netherrack Pickaxe", true) + add_tool("nether:pick_netherrack_blue", "Blue Netherrack Pickaxe", true) + add_tool("nether:pick_white", "Siwtonic Pickaxe", true) + + add_tool("nether:sword_netherrack", "Netherrack Sword", true) + add_tool("nether:sword_netherrack_blue", "Blue Netherrack Sword", true) + add_tool("nether:sword_white", "Siwtonic Sword", true) + + add_tool("nether:shovel_netherrack", "Netherrack Shovel", true) + add_tool("nether:shovel_netherrack_blue", "Blue Netherrack Shovel", true) + add_tool("nether:shovel_white", "Siwtonic Shovel", true) + + add_tool("nether:axe_netherrack", "Netherrack Axe", true) + add_tool("nether:axe_netherrack_blue", "Blue Netherrack Axe", true) + add_tool("nether:axe_white", "Siwtonic Axe", true) +end -- override creative hand if minetest.settings:get_bool("creative_mode") then