3 Mods hinzugefügt, Fehlende Nahrungspunkteangaben im Inventar ergänzt, falsche Nahrungspunkte berichtigt
|
@ -102,7 +102,7 @@ local function register_egg(name, def)
|
|||
description = "Fried " .. def.description,
|
||||
inventory_image = def.inventory_image .. "_fried.png",
|
||||
on_use = minetest.item_eat(4),
|
||||
groups = {food_egg = 1, flammable = 2, food_egg_fried = 1},
|
||||
groups = {food_egg = 1, flammable = 2, food_egg_fried = 1, eatable = 4},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -180,14 +180,14 @@ minetest.register_craftitem("animalia:beef_raw", {
|
|||
description = "Raw Beef",
|
||||
inventory_image = "animalia_beef_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1, eatable = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:beef_cooked", {
|
||||
description = "Steak",
|
||||
inventory_image = "animalia_beef_cooked.png",
|
||||
on_use = minetest.item_eat(8),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, eatable = 8},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -200,14 +200,14 @@ minetest.register_craftitem("animalia:mutton_raw", {
|
|||
description = "Raw Mutton",
|
||||
inventory_image = "animalia_mutton_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1, eatable = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:mutton_cooked", {
|
||||
description = "Cooked Mutton",
|
||||
inventory_image = "animalia_mutton_cooked.png",
|
||||
on_use = minetest.item_eat(6),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, eatable = 6},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -220,14 +220,14 @@ minetest.register_craftitem("animalia:rat_raw", {
|
|||
description = "Raw Rat",
|
||||
inventory_image = "animalia_rat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1, eatable = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:rat_cooked", {
|
||||
description = "Cooked Rat",
|
||||
inventory_image = "animalia_rat_cooked.png",
|
||||
on_use = minetest.item_eat(2),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, eatable = 2},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -240,14 +240,14 @@ minetest.register_craftitem("animalia:porkchop_raw", {
|
|||
description = "Raw Porkchop",
|
||||
inventory_image = "animalia_porkchop_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1, food_pork_raw = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1, food_pork_raw = 1, eatable = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:porkchop_cooked", {
|
||||
description = "Cooked Porkchop",
|
||||
inventory_image = "animalia_porkchop_cooked.png",
|
||||
on_use = minetest.item_eat(7),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, eatable = 7},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -260,14 +260,14 @@ minetest.register_craftitem("animalia:poultry_raw", {
|
|||
description = "Raw Poultry",
|
||||
inventory_image = "animalia_poultry_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_chicken_raw = 1, food_meat_raw = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_chicken_raw = 1, food_meat_raw = 1, eatable = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:poultry_cooked", {
|
||||
description = "Cooked Poultry",
|
||||
inventory_image = "animalia_poultry_cooked.png",
|
||||
on_use = minetest.item_eat(6),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_chicken = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_chicken = 1, eatable = 6},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -290,14 +290,14 @@ minetest.register_craftitem("animalia:venison_raw", {
|
|||
description = "Raw Venison",
|
||||
inventory_image = "animalia_venison_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, food_meat_raw = 1, eatable = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:venison_cooked", {
|
||||
description = "Venison Steak",
|
||||
inventory_image = "animalia_venison_cooked.png",
|
||||
on_use = minetest.item_eat(10),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1, eatable = 10},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -333,7 +333,7 @@ minetest.register_craftitem("animalia:bucket_milk", {
|
|||
inventory_image = "animalia_milk_bucket.png",
|
||||
stack_max = 1,
|
||||
on_use = minetest.item_eat(8, "bucket:bucket_empty"),
|
||||
groups = {food_milk = 1, flammable = 3},
|
||||
groups = {food_milk = 1, flammable = 3, eatable = 8},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:bucket_guano", {
|
||||
|
|
503
mods/atl_server_statistics/License.txt
Normal file
|
@ -0,0 +1,503 @@
|
|||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 2024-2025 Atlante (AtlanteWork@gmail.com)
|
||||
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.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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 Moe Ghoul>, 1 April 1990
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
36
mods/atl_server_statistics/init.lua
Normal file
|
@ -0,0 +1,36 @@
|
|||
atl_server_statistics = {
|
||||
mod_storage = minetest.get_mod_storage(),
|
||||
modpath = minetest.get_modpath("atl_server_statistics"),
|
||||
statistics = {"Messages Count", "Deaths Count", "Kills Count", "Nodes Dug", "Nodes Placed", "Items Crafted", "PlayTime"},
|
||||
color_message = "",
|
||||
reset_color_message = "#bce712",
|
||||
time_before_end_request = 30,
|
||||
reset_requests = {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function atl_server_statistics.load_file(path)
|
||||
local status, err = pcall(dofile, path)
|
||||
if not status then
|
||||
minetest.log("error", "-!- Failed to load file: " .. path .. " - Error: " .. err)
|
||||
else
|
||||
minetest.log("action", "-!- Successfully loaded file: " .. path)
|
||||
end
|
||||
end
|
||||
|
||||
if atl_server_statistics.modpath then
|
||||
local files_to_load = {
|
||||
"script/storage.lua",
|
||||
"script/event.lua",
|
||||
"script/command.lua",
|
||||
"script/util.lua",
|
||||
"script/formspec.lua",
|
||||
}
|
||||
for _, file in ipairs(files_to_load) do
|
||||
atl_server_statistics.load_file(atl_server_statistics.modpath .. "/" .. file)
|
||||
end
|
||||
else
|
||||
minetest.log("error", "-!- Files in " .. atl_server_statistics.modpath .. " mod are not set or valid.")
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain:atl_server_statistics
|
||||
|
||||
-!- Reset request has expired.=-!- Die Rücksetzanforderung ist abgelaufen.
|
||||
-!- Your statistics have been reset.=-!- Ihre Statistiken wurden zurückgesetzt.
|
||||
-!- No statistics available for =-!- Keine Statistiken verfügbar für
|
||||
-!- To confirm the reset of your statistics, type /yes_reset within the next 30 seconds.=-!- Um das Zurücksetzen Ihrer Statistiken zu bestätigen, geben Sie innerhalb der nächsten 30 Sekunden /yes_reset ein.
|
||||
-!- Reset request has expired or does not exist.=-!- Die Rücksetzanforderung ist abgelaufen oder existiert nicht.
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain:atl_server_statistics
|
||||
|
||||
#-!- Reset request has expired.=
|
||||
#-!- Your statistics have been reset.=
|
||||
#-!- No statistics available for =
|
||||
#-!- To confirm the reset of your statistics, type /yes_reset within the next 30 seconds.=
|
||||
#-!- Reset request has expired or does not exist.=
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain:atl_server_statistics
|
||||
|
||||
-!- Reset request has expired.=-!- La solicitud de reinicio ha expirado.
|
||||
-!- Your statistics have been reset.=-!- Tus estadísticas han sido reiniciadas.
|
||||
-!- No statistics available for =-!- No hay estadísticas disponibles para
|
||||
-!- To confirm the reset of your statistics, type /yes_reset within the next 30 seconds.=-!- Para confirmar el reinicio de tus estadísticas, escribe /yes_reset dentro de los próximos 30 segundos.
|
||||
-!- Reset request has expired or does not exist.=-!- La solicitud de reinicio ha expirado o no existe.
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain:atl_server_statistics
|
||||
|
||||
-!- Reset request has expired.=-!- La demande de réinitialisation a expiré.
|
||||
-!- Your statistics have been reset.=-!- Vos statistiques ont été réinitialisées.
|
||||
-!- No statistics available for =-!- Aucune statistique disponible pour
|
||||
-!- To confirm the reset of your statistics, type /yes_reset within the next 30 seconds.=-!- Pour confirmer la réinitialisation de vos statistiques, tapez /yes_reset dans les 30 secondes.
|
||||
-!- Reset request has expired or does not exist.=-!- La demande de réinitialisation a expiré ou n'existe pas.
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain:atl_server_statistics
|
||||
|
||||
-!- Reset request has expired.=-!- La richiesta di reset è scaduta.
|
||||
-!- Your statistics have been reset.=-!- Le tue statistiche sono state reimpostate.
|
||||
-!- No statistics available for =-!- Nessuna statistica disponibile per
|
||||
-!- To confirm the reset of your statistics, type /yes_reset within the next 30 seconds.=-!- Per confermare il ripristino delle tue statistiche, digita /yes_reset entro i prossimi 30 secondi.
|
||||
-!- Reset request has expired or does not exist.=-!- La richiesta di reset è scaduta o non esiste.
|
|
@ -0,0 +1,7 @@
|
|||
# textdomain:atl_server_statistics
|
||||
|
||||
-!- Reset request has expired.=-!- Запрос на сброс истек.
|
||||
-!- Your statistics have been reset.=-!- Ваши статистические данные были сброшены.
|
||||
-!- No statistics available for =-!- Нет доступной статистики для
|
||||
-!- To confirm the reset of your statistics, type /yes_reset within the next 30 seconds.=-!- Чтобы подтвердить сброс ваших статистических данных, введите /yes_reset в течение следующих 30 секунд.
|
||||
-!- Reset request has expired or does not exist.=-!- Запрос на сброс истек или не существует.
|
7
mods/atl_server_statistics/mod.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
name = atl_server_statistics
|
||||
title = Server Statistics
|
||||
author = Atlante
|
||||
depends =
|
||||
optional_depends =
|
||||
description = Adds in-game statistics with the /stats (player_name) command Which displays game time, number of messages, kills, deaths [...]
|
||||
release = 27785
|
30
mods/atl_server_statistics/readme.conf.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
Players Statistics for Minetest
|
||||
|
||||
Displays player statistics in a ranked format, with metrics such as playtime, kills, messages, and more.
|
||||
|
||||
Statistics Plus for Minetest is a complete mod designed to track and display various player statistics in a competitive leaderboard format. This mod provides a detailed view of player performance, including:
|
||||
|
||||
Number of messages sent
|
||||
Kills
|
||||
Deaths
|
||||
Nodes dug and placed
|
||||
Items crafted
|
||||
Total playtime
|
||||
|
||||
Main Features:
|
||||
|
||||
Comprehensive Player Stats: Track key statistics like kills, deaths, playtime, and more.
|
||||
Leaderboard Interface: A sleek and organized interface that ranks players based on different categories of stats.
|
||||
Tabs for Easy Navigation: Easily switch between different stats (messages, deaths, kills, mined nodes, placed nodes, crafted items, playtime) using tabs.
|
||||
Real-Time Updates: The leaderboard updates in real time, keeping the competition alive.
|
||||
Customizable Color Scheme: Top players are highlighted with different colors to distinguish them.
|
||||
Player-Specific Stats: Check a specific player's stats through commands in the chat interface.
|
||||
|
||||
This mod is ideal for servers that want to encourage competition or simply provide players with detailed feedback on their activities. It enhances player engagement by allowing them to track and compare their performance with others in real time.
|
||||
Usage:
|
||||
|
||||
Open the leaderboard via a /leaderboard command or get your personal stats directly with the /stats command.
|
||||
Navigate the leaderboard using tabs to view rankings by different statistics.
|
||||
Use chat commands to directly check the stats of a specific player.
|
||||
|
BIN
mods/atl_server_statistics/screenshot.png
Normal file
After Width: | Height: | Size: 106 KiB |
63
mods/atl_server_statistics/script/command.lua
Normal file
|
@ -0,0 +1,63 @@
|
|||
local S = minetest.get_translator("atl_server_statistics")
|
||||
|
||||
minetest.register_chatcommand("stats", {
|
||||
description = S("Allows you to display your current statistics or those of a target player"),
|
||||
params = "<player_name>",
|
||||
func = function(player_name, param)
|
||||
local target_player_name = param ~= "" and param or player_name
|
||||
if not atl_server_statistics.player_has_stats(target_player_name) then
|
||||
return minetest.chat_send_player(player_name, minetest.colorize(atl_server_statistics.color_message, S("-!- No statistics available for ") .. target_player_name))
|
||||
end
|
||||
if atl_server_statistics.is_player_online(target_player_name) then
|
||||
atl_server_statistics.update_playtime_on_stats(target_player_name)
|
||||
end
|
||||
local stats_message = S("-!- Statistics of ") .. target_player_name .. " <> "
|
||||
for _, stat in ipairs(atl_server_statistics.statistics) do
|
||||
local value = atl_server_statistics.get_value(target_player_name, stat)
|
||||
if value > 0 then
|
||||
stats_message = stats_message .. string.format("%s %s | ", stat, (stat == "PlayTime" and atl_server_statistics.format_playtime(value)) or value)
|
||||
end
|
||||
end
|
||||
minetest.chat_send_player(player_name, minetest.colorize(atl_server_statistics.color_message, stats_message))
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("reset", {
|
||||
description = S("Allows you to reset your statistics with confirmation"),
|
||||
func = function(player_name)
|
||||
local current_time = os.time()
|
||||
if atl_server_statistics.reset_requests[player_name] then
|
||||
if current_time - atl_server_statistics.reset_requests[player_name] <= atl_server_statistics.time_before_end_request then
|
||||
atl_server_statistics.reset_player_stats(player_name)
|
||||
minetest.chat_send_player(player_name, minetest.colorize(atl_server_statistics.reset_color_message, S("-!- Your statistics have been reset.")))
|
||||
atl_server_statistics.reset_requests[player_name] = nil
|
||||
else
|
||||
atl_server_statistics.reset_requests[player_name] = current_time
|
||||
return minetest.chat_send_player(player_name, minetest.colorize(atl_server_statistics.reset_color_message, S("-!- Statistics reset request has expired. Please try again.")))
|
||||
end
|
||||
else
|
||||
atl_server_statistics.reset_requests[player_name] = current_time
|
||||
minetest.chat_send_player(player_name, minetest.colorize(atl_server_statistics.reset_color_message, S("-!- To confirm the reset of your statistics, type /reset again within the next ") .. atl_server_statistics.time_before_end_request .. S(" seconds.")))
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("leaderboard", {
|
||||
description = S("Displays the leaderboard with tabs for each statistics domain"),
|
||||
func = function(player_name)
|
||||
|
||||
local stats_list = atl_server_statistics.statistics
|
||||
local formspec = atl_server_statistics.create_base_formspec(stats_list, 1, player_name)
|
||||
formspec = formspec .. atl_server_statistics.generate_stats_table(stats_list[1], player_name)
|
||||
minetest.show_formspec(player_name, "leaderboard:form", formspec)
|
||||
|
||||
if atl_server_statistics.is_player_online(player_name) then
|
||||
atl_server_statistics.update_playtime_on_stats(player_name)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
if minetest.settings:get_bool("atl_server_statistics.simplified_command") ~= true then
|
||||
minetest.register_chatcommand("s", minetest.registered_chatcommands["stats"])
|
||||
minetest.register_chatcommand("ld", minetest.registered_chatcommands["leaderboard"])
|
||||
end
|
76
mods/atl_server_statistics/script/event.lua
Normal file
|
@ -0,0 +1,76 @@
|
|||
local function register_event(event_name, register_func, setting_key, default_value)
|
||||
if not minetest.settings:get_bool("atl_server_statistics." .. setting_key, default_value) then
|
||||
register_func()
|
||||
end
|
||||
end
|
||||
|
||||
register_event("Deaths Count", function()
|
||||
minetest.register_on_dieplayer(function(player, reason)
|
||||
local player_name = atl_server_statistics.get_player_name(player)
|
||||
atl_server_statistics.increment_event_stat(player_name, "Deaths Count", 1)
|
||||
if reason.type == "punch" and reason.object and reason.object:is_player() then
|
||||
atl_server_statistics.increment_event_stat(atl_server_statistics.get_player_name(reason.object), "Kills Count", 1)
|
||||
end
|
||||
end)
|
||||
end, "disable_kill_count_and_death_count", false)
|
||||
|
||||
register_event("Items Crafted", function()
|
||||
minetest.register_on_craft(function(itemstack, player)
|
||||
atl_server_statistics.increment_event_stat(atl_server_statistics.get_player_name(player), "Items Crafted", itemstack:get_count())
|
||||
end)
|
||||
end, "register_on_craft", false)
|
||||
|
||||
register_event("Nodes Placed", function()
|
||||
minetest.register_on_placenode(function(_, _, placer)
|
||||
atl_server_statistics.increment_event_stat(atl_server_statistics.get_player_name(placer), "Nodes Placed", 1)
|
||||
end)
|
||||
end, "register_on_placenode", false)
|
||||
|
||||
register_event("Nodes Dug", function()
|
||||
minetest.register_on_dignode(function(_, _, digger)
|
||||
atl_server_statistics.increment_event_stat(atl_server_statistics.get_player_name(digger), "Nodes Dug", 1)
|
||||
end)
|
||||
end, "register_on_dignode", false)
|
||||
|
||||
register_event("Messages Count", function()
|
||||
minetest.register_on_chat_message(function(player_name)
|
||||
atl_server_statistics.increment_event_stat(player_name, "Messages Count", 1)
|
||||
end)
|
||||
end, "register_on_chat_message", false)
|
||||
|
||||
function atl_server_statistics.on_player_join(player)
|
||||
local player_name = atl_server_statistics.get_player_name(player)
|
||||
atl_server_statistics.mod_storage:set_int(player_name .. "_connect_time", os.time())
|
||||
for _, stat in ipairs(atl_server_statistics.statistics) do
|
||||
local key = player_name .. "_" .. stat
|
||||
atl_server_statistics.mod_storage:set_int(key, atl_server_statistics.mod_storage:get_int(key) or 0)
|
||||
end
|
||||
end
|
||||
|
||||
function atl_server_statistics.on_player_leave(player)
|
||||
atl_server_statistics.update_playtime_on_stats(atl_server_statistics.get_player_name(player))
|
||||
end
|
||||
|
||||
function atl_server_statistics.on_shutdown()
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
atl_server_statistics.update_playtime_on_stats(atl_server_statistics.get_player_name(player))
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(atl_server_statistics.on_player_join)
|
||||
minetest.register_on_leaveplayer(atl_server_statistics.on_player_leave)
|
||||
minetest.register_on_shutdown(atl_server_statistics.on_shutdown)
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if fields.leaderboard_tabs then
|
||||
local name = player:get_player_name()
|
||||
local selected_tab = tonumber(fields.leaderboard_tabs)
|
||||
local stats_list = atl_server_statistics.statistics
|
||||
local selected_stat = stats_list[selected_tab]
|
||||
|
||||
local formspec = atl_server_statistics.create_base_formspec(stats_list, selected_tab, name)
|
||||
formspec = formspec .. atl_server_statistics.generate_stats_table(selected_stat, name)
|
||||
|
||||
minetest.show_formspec(name, "leaderboard:form", formspec)
|
||||
end
|
||||
end)
|
79
mods/atl_server_statistics/script/formspec.lua
Normal file
|
@ -0,0 +1,79 @@
|
|||
function atl_server_statistics.generate_stats_table(stats_name, player_name)
|
||||
local players_stats = {}
|
||||
local mod_storage = atl_server_statistics.mod_storage
|
||||
local all_keys = mod_storage:to_table().fields
|
||||
|
||||
for key, _ in pairs(all_keys) do
|
||||
if key:find("_" .. stats_name) then
|
||||
local name = key:sub(1, -(#stats_name + 2))
|
||||
local stat_value = mod_storage:get_int(key)
|
||||
table.insert(players_stats, {name = name, value = stat_value})
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(players_stats, function(a, b)
|
||||
return a.value > b.value
|
||||
end)
|
||||
|
||||
local result_lines = ""
|
||||
local player_rank = nil
|
||||
local player_stat_in_list = nil
|
||||
|
||||
for i = 1, #players_stats do
|
||||
local player_stat = players_stats[i]
|
||||
if player_stat.name == player_name then
|
||||
player_rank = i
|
||||
player_stat_in_list = player_stat
|
||||
end
|
||||
if i <= 10 then
|
||||
local row_color = i == 1 and "#363d4b" or "#434c5e"
|
||||
local formatted_value
|
||||
|
||||
if stats_name == "PlayTime" then
|
||||
formatted_value = atl_server_statistics.format_playtime(player_stat.value)
|
||||
else
|
||||
formatted_value = tostring(player_stat.value)
|
||||
end
|
||||
|
||||
result_lines = result_lines ..
|
||||
"box[0," .. (i - 0.1) * 0.65 .. ";5.75,0.5;" .. row_color .. "]" ..
|
||||
"box[4.25," .. (i - 0.1) * 0.65 .. ";1.5,0.5;#6dafb7]" ..
|
||||
"box[0," .. (i - 0.1) * 0.65 .. ";0.55,0.5;#4a606c]" ..
|
||||
"label[0.225," .. (i - 0.08) * 0.65 .. ";" .. i .. "]" ..
|
||||
"label[1.75," .. (i - 0.08) * 0.65 .. ";" .. player_stat.name .. "]" ..
|
||||
"label[4.45," .. (i - 0.08) * 0.65 .. ";" .. formatted_value .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
if player_stat_in_list then
|
||||
local row_color = "#434c5e"
|
||||
local formatted_value
|
||||
|
||||
if stats_name == "PlayTime" then
|
||||
formatted_value = atl_server_statistics.format_playtime(player_stat_in_list.value)
|
||||
else
|
||||
formatted_value = tostring(player_stat_in_list.value)
|
||||
end
|
||||
|
||||
result_lines = result_lines ..
|
||||
"box[4.25,7.75;1.5,0.5;#6dafb7]" ..
|
||||
"box[0,7.75;0.85,0.5;#4a606c]" ..
|
||||
"box[0,7.75;4.25,0.5;" .. row_color .. "]" ..
|
||||
"label[0.225,7.75;" .. player_rank .. "]" ..
|
||||
"label[1.75,7.75;" .. player_stat_in_list.name .. "]" ..
|
||||
"label[4.45,7.75;" .. formatted_value .. "]"
|
||||
end
|
||||
return result_lines
|
||||
end
|
||||
|
||||
function atl_server_statistics.create_base_formspec(stats_list, selected_tab, player_name)
|
||||
local formspec = "size[6,8]" ..
|
||||
"tabheader[0,0;leaderboard_tabs;Messages, Deaths, Kills, Mined, Placed, Craft, Playtime;" .. selected_tab .. ";true;false]" ..
|
||||
"label[0.25,0;Rank]" ..
|
||||
"label[1.75,0;Player Name]" ..
|
||||
"label[4.5,0;Stats]" ..
|
||||
"label[0,7.25;Your Rank]" ..
|
||||
"label[1.5,7.25;Your Player Name]" ..
|
||||
"label[4.25,7.25;Your Stats]"
|
||||
return formspec
|
||||
end
|
37
mods/atl_server_statistics/script/storage.lua
Normal file
|
@ -0,0 +1,37 @@
|
|||
function atl_server_statistics.get_value(player_name, key)
|
||||
return player_name and atl_server_statistics.mod_storage:get_int(player_name .. "_" .. key) or 0
|
||||
end
|
||||
|
||||
function atl_server_statistics.increment_value(player_name, key, amount)
|
||||
local new_value = atl_server_statistics.get_value(player_name, key) + (amount or 0)
|
||||
atl_server_statistics.mod_storage:set_int(player_name .. "_" .. key, new_value)
|
||||
return new_value
|
||||
end
|
||||
|
||||
function atl_server_statistics.player_has_stats(player_name)
|
||||
for _, stat in ipairs(atl_server_statistics.statistics) do
|
||||
if atl_server_statistics.mod_storage:contains(player_name .. "_" .. stat) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function atl_server_statistics.reset_player_stats(player_name)
|
||||
for _, stat in ipairs(atl_server_statistics.statistics) do
|
||||
atl_server_statistics.mod_storage:set_int(player_name .. "_" .. stat, 0)
|
||||
end
|
||||
atl_server_statistics.mod_storage:set_int(player_name .. "_connect_time", os.time())
|
||||
end
|
||||
|
||||
function atl_server_statistics.format_playtime(seconds)
|
||||
return string.format("%02d:%02d:%02d", math.floor(seconds / 3600), math.floor((seconds % 3600) / 60), seconds % 60)
|
||||
end
|
||||
|
||||
function atl_server_statistics.update_playtime_on_stats(player_name)
|
||||
local connect_time = atl_server_statistics.mod_storage:get_int(player_name .. "_connect_time")
|
||||
if connect_time > 0 then
|
||||
atl_server_statistics.increment_value(player_name, "PlayTime", os.time() - connect_time)
|
||||
atl_server_statistics.mod_storage:set_int(player_name .. "_connect_time", os.time())
|
||||
end
|
||||
end
|
18
mods/atl_server_statistics/script/util.lua
Normal file
|
@ -0,0 +1,18 @@
|
|||
function atl_server_statistics.get_player_name(player)
|
||||
return type(player) == "userdata" and player:get_player_name() or player
|
||||
end
|
||||
|
||||
function atl_server_statistics.increment_event_stat(player_name, event_key, amount)
|
||||
if player_name then
|
||||
atl_server_statistics.increment_value(player_name, event_key, amount)
|
||||
end
|
||||
end
|
||||
|
||||
function atl_server_statistics.is_player_online(player_name)
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
if player:get_player_name() == player_name then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
8
mods/atl_server_statistics/settingtypes.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
atl_server_statistics.disable_kill_count_and_death_count (Disables counting of deaths and murders) bool false
|
||||
atl_server_statistics.register_on_craft (Disables item crafting counting) bool false
|
||||
atl_server_statistics.register_on_placenode (Disables block placement counting) bool false
|
||||
atl_server_statistics.register_on_dignode (Disables block breaking counting) bool false
|
||||
atl_server_statistics.register_on_chat_message (Disables counting of sent messages) bool false
|
||||
atl_server_statistics.simplified_command (Disables command abbreviations) bool false
|
||||
|
||||
atl_server_statistics.time_before_end_reset_request (Farming Stage Length) float 30
|
|
@ -81,7 +81,7 @@ mt.register_node("cucina_vegana:" .. pname .. "_leaves", {
|
|||
mt.register_craftitem("cucina_vegana:" .. pname .. "_beans_raw", {
|
||||
description = S("Coffee Beans raw"),
|
||||
inventory_image = "cucina_vegana_" .. pname .. "_beans_raw.png",
|
||||
groups = {food = 1, food_coffee = 1},
|
||||
groups = {food = 1, food_coffee = 1, eatable = 3},
|
||||
on_use = mt.item_eat(3)
|
||||
|
||||
})
|
||||
|
|
|
@ -12,7 +12,7 @@ local S = cucina_vegana.get_translator
|
|||
minetest.register_craftitem("cucina_vegana:blueberry_puree", {
|
||||
description = S("Blueberry puree"),
|
||||
inventory_image = "cucina_vegana_blueberry_puree.png",
|
||||
groups = {food = 1, food_blueberry = 1, food_berry = 1},
|
||||
groups = {food = 1, food_blueberry = 1, food_berry = 1, eatable = 4},
|
||||
on_use = minetest.item_eat(4)
|
||||
})
|
||||
|
||||
|
@ -37,7 +37,7 @@ minetest.register_craftitem("cucina_vegana:ciabatta_dough", {
|
|||
minetest.register_craftitem("cucina_vegana:dandelion_honey", {
|
||||
description = S("Dandelion Honey"),
|
||||
inventory_image = "cucina_vegana_dandelion_honey.png",
|
||||
groups = {flammable = 1, food = 1, food_honey = 1, food_sugar = 1, eatable = 1},
|
||||
groups = {flammable = 1, food = 1, food_honey = 1, food_sugar = 1, eatable = 3},
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
|
@ -82,7 +82,7 @@ if not(minetest.get_modpath("x_farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:soy_milk", {
|
||||
description = S("Soy Milk"),
|
||||
inventory_image = "cucina_vegana_soy_milk.png",
|
||||
groups = {flammable = 1, food = 1, food_milk = 1, eatable = 1, food_vegan = 1, food_soy_milk = 1},
|
||||
groups = {flammable = 1, food = 1, food_milk = 1, eatable = 2, food_vegan = 1, food_soy_milk = 1},
|
||||
on_use = minetest.item_eat(2, "vessels:drinking_glass"),
|
||||
})
|
||||
|
||||
|
@ -92,7 +92,7 @@ if not(minetest.get_modpath("farming")) then
|
|||
|
||||
minetest.register_craftitem("cucina_vegana:sunflower_seeds_dough", {
|
||||
description = S("Sunflower Seeds Dough"),
|
||||
groups = {food = 1, food_vegan = 1, eatable = 1, bread_dough = 1},
|
||||
groups = {food = 1, food_vegan = 1, eatable = 2, bread_dough = 1},
|
||||
inventory_image = "cucina_vegana_sunflower_seeds_dough.png",
|
||||
on_use = minetest.item_eat(2),
|
||||
})
|
||||
|
@ -106,7 +106,7 @@ if not(minetest.get_modpath("farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:tofu", {
|
||||
description = S("Tofu (raw)"),
|
||||
inventory_image = "cucina_vegana_tofu.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_tofu_raw = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 2, food_vegan = 1, food_tofu_raw = 1},
|
||||
on_use = minetest.item_eat(2),
|
||||
})
|
||||
|
||||
|
@ -118,28 +118,28 @@ end
|
|||
|
||||
minetest.register_craftitem("cucina_vegana:imitation_butter", {
|
||||
description = S("Imitation Butter"),
|
||||
groups = {food = 1, food_butter = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {food = 1, food_butter = 1, food_vegan = 1, eatable = 2},
|
||||
inventory_image = "cucina_vegana_imitation_butter.png",
|
||||
on_use = minetest.item_eat(2),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:imitation_cheese", {
|
||||
description = S("Imitation Cheese"),
|
||||
groups = {food = 1, food_cheese = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {food = 1, food_cheese = 1, food_vegan = 1, eatable = 3},
|
||||
inventory_image = "cucina_vegana_imitation_cheese.png",
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:imitation_fish", {
|
||||
description = S("Imitation Fish"),
|
||||
groups = {food = 1, food_fish = 1, food_vegan = 1, eatable = 1, food_fish_raw = 1, fish = 1},
|
||||
groups = {food = 1, food_fish = 1, food_vegan = 1, eatable = 3, food_fish_raw = 1, fish = 1},
|
||||
inventory_image = "cucina_vegana_imitation_fish.png",
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:imitation_meat", {
|
||||
description = S("Imitation Meat"),
|
||||
groups = {food = 1, food_meat = 1, food_vegan = 1, eatable = 1, food_meat_raw = 1},
|
||||
groups = {food = 1, food_meat = 1, food_vegan = 1, eatable = 3, food_meat_raw = 1},
|
||||
inventory_image = "cucina_vegana_imitation_meat.png",
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
@ -157,7 +157,7 @@ minetest.register_craftitem("cucina_vegana:imitation_poultry", {
|
|||
minetest.register_craftitem("cucina_vegana:asparagus", {
|
||||
description = S("Asparagus"),
|
||||
inventory_image = "cucina_vegana_asparagus.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_asparagus = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 3, food_vegan = 1, food_asparagus = 1},
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
|
@ -166,7 +166,7 @@ if not(minetest.get_modpath("ethereal")) then
|
|||
minetest.register_craftitem("cucina_vegana:banana", {
|
||||
description = S("Banana"),
|
||||
inventory_image = "cucina_vegana_banana.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_banana = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 4, food_vegan = 1, food_banana = 1},
|
||||
on_use = minetest.item_eat(4),
|
||||
})
|
||||
|
||||
|
@ -191,7 +191,7 @@ if not(minetest.get_modpath("x_farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:coffee_beans_roasted", {
|
||||
description = S("Coffee Beans"),
|
||||
inventory_image = "cucina_vegana_coffee_beans_roasted.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_coffee = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = .5, food_vegan = 1, food_coffee = 1},
|
||||
on_use = minetest.item_eat(.5),
|
||||
})
|
||||
|
||||
|
@ -218,7 +218,7 @@ minetest.register_craftitem("cucina_vegana:flax_roasted", {
|
|||
minetest.register_craftitem("cucina_vegana:kohlrabi", {
|
||||
description = S("Kohlrabi"),
|
||||
inventory_image = "cucina_vegana_kohlrabi.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_kohlrabi = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 3, food_vegan = 1, food_kohlrabi = 1},
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
|
@ -227,7 +227,7 @@ if not(minetest.get_modpath("farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:lettuce", {
|
||||
description = S("Lettuce"),
|
||||
inventory_image = "cucina_vegana_lettuce.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_lettuce = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 2, food_vegan = 1, food_lettuce = 1},
|
||||
on_use = minetest.item_eat(2),
|
||||
})
|
||||
|
||||
|
@ -245,7 +245,7 @@ if not(minetest.get_modpath("sandwiches")) then
|
|||
minetest.register_craftitem("cucina_vegana:peanut", {
|
||||
description = S("Peanut"),
|
||||
inventory_image = "cucina_vegana_peanut.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_peanut = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 4, food_vegan = 1, food_peanut = 1},
|
||||
on_use = minetest.item_eat(4),
|
||||
})
|
||||
|
||||
|
@ -296,7 +296,7 @@ if not(minetest.get_modpath("farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:tomato", {
|
||||
description = S("Tomato"),
|
||||
inventory_image = "cucina_vegana_tomato.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_tomato = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 4, food_vegan = 1, food_tomato = 1},
|
||||
on_use = minetest.item_eat(4),
|
||||
})
|
||||
|
||||
|
@ -307,14 +307,14 @@ if not(minetest.get_modpath("x_farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:potato", {
|
||||
description = S("Potato"),
|
||||
inventory_image = "cucina_vegana_potato.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_potato = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 5, food_vegan = 1, food_potato = 1},
|
||||
on_use = minetest.item_eat(5),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:carrot", {
|
||||
description = S("Carrot"),
|
||||
inventory_image = "cucina_vegana_carrot.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_carrot = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 3, food_vegan = 1, food_carrot = 1},
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
|
@ -331,21 +331,21 @@ if not(minetest.get_modpath("farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:chili", {
|
||||
description = S("Chili"),
|
||||
inventory_image = "cucina_vegana_chili.png",
|
||||
groups = {flammable = 1, food = 1, food_vegan = 1, food_chili = 1},
|
||||
groups = {flammable = 1, food = 1, food_vegan = 1, food_chili = 1, eatable = 1},
|
||||
on_use = minetest.item_eat(1),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:onion", {
|
||||
description = S("Onion"),
|
||||
inventory_image = "cucina_vegana_onion.png",
|
||||
groups = {flammable = 1, food = 1, food_vegan = 1, food_onion = 1},
|
||||
groups = {flammable = 1, food = 1, food_vegan = 1, food_onion = 1, eatable = 3},
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:cucumber", {
|
||||
description = S("Cucumber"),
|
||||
inventory_image = "cucina_vegana_cucumber.png",
|
||||
groups = {flammable = 1, food = 1, food_vegan = 1, food_onion = 1},
|
||||
groups = {flammable = 1, food = 1, food_vegan = 1, food_onion = 1, eatable = 3},
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
|
@ -356,14 +356,14 @@ if not(minetest.get_modpath("x_farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:strawberry", {
|
||||
description = S("Strawberry"),
|
||||
inventory_image = "cucina_vegana_strawberry.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_strawberry = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 2, food_vegan = 1, food_strawberry = 1},
|
||||
on_use = minetest.item_eat(2),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:corn", {
|
||||
description = S("Corncob"),
|
||||
inventory_image = "cucina_vegana_corn.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_corn = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 2, food_vegan = 1, food_corn = 1},
|
||||
on_use = minetest.item_eat(2),
|
||||
})
|
||||
|
||||
|
@ -375,7 +375,7 @@ end
|
|||
|
||||
minetest.register_craftitem("cucina_vegana:kohlrabi_roasted", {
|
||||
description = S("Roasted Kohlrabi"),
|
||||
groups = {food = 1, eatable = 1},
|
||||
groups = {food = 1, eatable = 4},
|
||||
inventory_image = "cucina_vegana_kohlrabi_roasted.png",
|
||||
on_use = minetest.item_eat(4),
|
||||
})
|
||||
|
@ -384,14 +384,14 @@ if not(minetest.get_modpath("farming")) then
|
|||
|
||||
minetest.register_craftitem("cucina_vegana:sunflower_seeds_roasted", {
|
||||
description = S("Roasted Sunflower Seeds"),
|
||||
groups = {food = 1, eatable = 1},
|
||||
groups = {food = 1, eatable = 2},
|
||||
inventory_image = "cucina_vegana_sunflower_seeds_roasted.png",
|
||||
on_use = minetest.item_eat(2),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cucina_vegana:sunflower_seeds_bread", {
|
||||
description = S("Sunflower Seeds Bread"),
|
||||
groups = {food = 1, food_bread = 1, eatable = 1},
|
||||
groups = {food = 1, food_bread = 1, eatable = 4},
|
||||
inventory_image = "cucina_vegana_sunflower_seeds_bread.png",
|
||||
on_use = minetest.item_eat(4),
|
||||
})
|
||||
|
@ -399,7 +399,7 @@ if not(minetest.get_modpath("farming")) then
|
|||
minetest.register_craftitem("cucina_vegana:tofu_cooked", {
|
||||
description = S("Tofu"),
|
||||
inventory_image = "cucina_vegana_tofu_cooked.png",
|
||||
groups = {flammable = 1, food = 1, eatable = 1, food_vegan = 1, food_tofu = 1, food_meat = 1},
|
||||
groups = {flammable = 1, food = 1, eatable = 3, food_vegan = 1, food_tofu = 1, food_meat = 1},
|
||||
on_use = minetest.item_eat(3),
|
||||
})
|
||||
|
||||
|
@ -409,7 +409,7 @@ if not(minetest.get_modpath("x_farming")) then
|
|||
|
||||
minetest.register_craftitem("cucina_vegana:vegan_sushi", {
|
||||
description = S("Vegan Sushi"),
|
||||
groups = {food = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {food = 1, food_vegan = 1, eatable = 4},
|
||||
inventory_image = "cucina_vegana_vegan_sushi.png",
|
||||
on_use = minetest.item_eat(4),
|
||||
})
|
||||
|
@ -418,7 +418,7 @@ end
|
|||
|
||||
minetest.register_craftitem("cucina_vegana:vegan_strawberry_milk", {
|
||||
description = S("Vegan Strawberry Milk"),
|
||||
groups = {food = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {food = 1, food_vegan = 1, eatable = 3},
|
||||
inventory_image = "cucina_vegana_vegan_strawberry_milk.png",
|
||||
on_use = minetest.item_eat(3, "vessels:drinking_glass"),
|
||||
})
|
||||
|
|
|
@ -41,7 +41,7 @@ minetest.register_node("cucina_vegana:flax_seed_oil", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 2},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -72,7 +72,7 @@ minetest.register_node("cucina_vegana:peanut_oil", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -109,7 +109,7 @@ minetest.register_node("cucina_vegana:sunflower_seeds_oil", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 2},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -127,7 +127,7 @@ minetest.register_node("cucina_vegana:corn_oil", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_oil = 1, food_vegan = 1, eatable = 2},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -151,7 +151,7 @@ minetest.register_node("cucina_vegana:blueberry_jam", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, food_sweet = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, food_sweet = 1, eatable = 8},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:coffee_cup", {
|
||||
|
@ -168,7 +168,7 @@ minetest.register_node("cucina_vegana:coffee_cup", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 2},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:coffee_cup_hot", {
|
||||
|
@ -200,7 +200,7 @@ minetest.register_node("cucina_vegana:coffee_cup_hot", {
|
|||
return itemstack
|
||||
end,
|
||||
walkable = true,
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 2},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:cucumber_in_glass", {
|
||||
|
@ -217,7 +217,7 @@ minetest.register_node("cucina_vegana:cucumber_in_glass", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 5},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:ciabatta_bread", {
|
||||
|
@ -234,7 +234,7 @@ minetest.register_node("cucina_vegana:ciabatta_bread", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_bread = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_bread = 1, food_vegan = 1, eatable = 4},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:edamame", {
|
||||
|
@ -268,7 +268,7 @@ minetest.register_node("cucina_vegana:edamame_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 4},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -286,7 +286,7 @@ minetest.register_node("cucina_vegana:lettuce_oil", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_oil = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_oil = 1, food_vegan = 1, eatable = 2},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -304,7 +304,7 @@ minetest.register_node("cucina_vegana:peanut_butter", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, food_sweet = 1, food_butter = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, food_sweet = 1, food_butter = 1, eatable = 10},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:salad_bowl", {
|
||||
|
@ -321,7 +321,7 @@ minetest.register_node("cucina_vegana:salad_bowl", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 4},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -339,7 +339,7 @@ minetest.register_node("cucina_vegana:sauce_hollandaise", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_sauce = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, food = 1, food_sauce = 1, food_vegan = 1, eatable = 3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -357,7 +357,7 @@ minetest.register_node("cucina_vegana:sea_salad", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -378,7 +378,7 @@ if not(minetest.get_modpath("x_farming")) then
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -507,7 +507,7 @@ minetest.register_node("cucina_vegana:fryer", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 8},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:kohlrabi_soup", {
|
||||
|
@ -541,7 +541,7 @@ minetest.register_node("cucina_vegana:salad_hollandaise", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -576,7 +576,7 @@ minetest.register_node("cucina_vegana:tofu_chives_rosemary", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -598,7 +598,7 @@ minetest.register_node("cucina_vegana:asparagus_hollandaise_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -616,7 +616,7 @@ minetest.register_node("cucina_vegana:asparagus_rice_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 6},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -634,7 +634,7 @@ minetest.register_node("cucina_vegana:asparagus_soup_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -654,7 +654,7 @@ minetest.register_node("cucina_vegana:bowl_rice_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1, eatable = 4},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -674,7 +674,7 @@ minetest.register_node("cucina_vegana:fish_parsley_rosemary_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 6},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -692,7 +692,7 @@ minetest.register_node("cucina_vegana:kohlrabi_soup_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -726,7 +726,7 @@ minetest.register_node("cucina_vegana:pizza_vegana", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 6},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:pizza_funghi_raw", {
|
||||
|
@ -759,7 +759,7 @@ minetest.register_node("cucina_vegana:pizza_funghi", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, food_vegan = 1, eatable = 6},
|
||||
})
|
||||
|
||||
minetest.register_node("cucina_vegana:soy_soup_cooked", {
|
||||
|
@ -776,7 +776,7 @@ minetest.register_node("cucina_vegana:soy_soup_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 5},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
|
@ -794,6 +794,6 @@ minetest.register_node("cucina_vegana:tofu_chives_rosemary_cooked", {
|
|||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 1},
|
||||
groups = {dig_immediate = 3, attached_node = 1, eatable = 6},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
|
21
mods/death_coords/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Niden
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
18
mods/death_coords/README.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# DCM
|
||||
Show Death Coordinates
|
||||
|
||||
Installation:
|
||||
```Minetest/mods/death_coords```
|
||||
|
||||
Chat
|
||||
|
||||

|
||||
|
||||
|
||||
# Niden
|
||||
|
||||
Discord: Niden#7063
|
||||
|
||||
Licence: MIT Licence
|
||||
|
||||
https://github.com/Niden1
|
1
mods/death_coords/depends.txt
Normal file
|
@ -0,0 +1 @@
|
|||
default
|
66
mods/death_coords/init.lua
Normal file
|
@ -0,0 +1,66 @@
|
|||
activate = true
|
||||
|
||||
minetest.register_chatcommand(
|
||||
"death",
|
||||
{
|
||||
description = "Enable or disable death coordinates",
|
||||
params = "<true> | <false>",
|
||||
privs = {ban = true},
|
||||
func = function(name, param)
|
||||
if param == "true" then
|
||||
activate = true
|
||||
minetest.chat_send_all(minetest.colorize("#00FF00", "*** [Server]: Death coordinates are enabled!"))
|
||||
|
||||
music =
|
||||
minetest.sound_play(
|
||||
"notify",
|
||||
{
|
||||
loop = false,
|
||||
gain = 1.0
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
if param == "false" then
|
||||
activate = false
|
||||
|
||||
minetest.chat_send_all(minetest.colorize("#FF0000", "*** [Server]: Death coordinates are disabled!"))
|
||||
|
||||
music =
|
||||
minetest.sound_play(
|
||||
"notify",
|
||||
{
|
||||
loop = false,
|
||||
gain = 1.0
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_on_dieplayer(
|
||||
function(player)
|
||||
if activate == true then
|
||||
local pname = player:get_player_name()
|
||||
local pos = player:getpos()
|
||||
pos.x = math.floor(pos.x)
|
||||
pos.y = math.floor(pos.y)
|
||||
pos.z = math.floor(pos.z)
|
||||
minetest.chat_send_player(
|
||||
pname,
|
||||
core.get_color_escape_sequence("#FF0000") ..
|
||||
"*** [Server] - Last Dead At: " .. pos.x .. ", " .. pos.y .. ", " .. pos.z
|
||||
)
|
||||
|
||||
music =
|
||||
minetest.sound_play(
|
||||
"die",
|
||||
{
|
||||
loop = false,
|
||||
gain = 1.0
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
)
|
5
mods/death_coords/mod.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
name = death_coords
|
||||
author = Niden
|
||||
description = Shows a message with the coordinates of the last death.
|
||||
title = death_coords
|
||||
release = 14333
|
BIN
mods/death_coords/screenshot.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
mods/death_coords/sounds/die.ogg
Normal file
BIN
mods/death_coords/sounds/notify.ogg
Normal file
3
mods/glass_stained/depends.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
default
|
||||
xpanes
|
||||
dye
|
362
mods/glass_stained/init.lua
Normal file
|
@ -0,0 +1,362 @@
|
|||
local alias = {
|
||||
"one",
|
||||
"two",
|
||||
"three",
|
||||
"four",
|
||||
"five",
|
||||
"six",
|
||||
"seven",
|
||||
"eight",
|
||||
"nine",
|
||||
"ten",
|
||||
"eleven",
|
||||
"twelve"
|
||||
}
|
||||
|
||||
local crafting = {
|
||||
{"blue", "blue", "blue"},
|
||||
{"red", "blue", "white"},
|
||||
{"yellow", "blue", "blue"},
|
||||
{"yellow", "red", "red"},
|
||||
{"violet", "red", "blue"},
|
||||
{"violet", "blue", "blue"},
|
||||
{"red", "violet", "blue"},
|
||||
{"blue", "yellow", "dark_green"},
|
||||
{"blue", "red", "yellow"},
|
||||
{"dark_green", "cyan", "yellow"},
|
||||
{"blue", "dark_green", "dark_green"},
|
||||
{"yellow", "cyan", "cyan"},
|
||||
{"blue", "dark_green", "yellow"},
|
||||
{"dark_green", "blue", "white"},
|
||||
{"red", "red", "dark_green"},
|
||||
{"blue", "blue", "cyan"},
|
||||
{"red", "dark_green", "yellow"},
|
||||
{"violet", "yellow", "dark_green"},
|
||||
}
|
||||
|
||||
local nodeboxes = {
|
||||
single = {{-0.5, -0.5, 0, 0.5, 0.5, 0}},
|
||||
double = {{-0.5, -0.5, 0, 0.5, 1.5, 0}},
|
||||
triple = {{-0.5, -0.5, 0, 0.5, 1.5, 0}, {0.5, -0.5, 0, 1.5, 0.5, 0}},
|
||||
quadruple = {{-0.5, -0.5, 0, 1.5, 1.5, 0}},
|
||||
noncuple = {{-1.5, -1.5, 0, 1.5, 1.5, 0}},
|
||||
offset = {{-0.5, -0.5, 1, 0.5, 0.5, 1}}
|
||||
}
|
||||
|
||||
local thick_nodeboxes = {
|
||||
single = {{-0.5, -0.5, -0.03125, 0.5, 0.5, 0.03125}},
|
||||
double = {{-0.5, -0.5, -0.03125, 0.5, 1.5, 0.03125}},
|
||||
triple = {{-0.5, -0.5, -0.03125, 0.5, 1.5, 0.03125}, {-0.5, -0.5, -0.03125, 1.5, 0.5, 0.03125}},
|
||||
quadruple = {{-0.5, -0.5, -0.03125, 1.5, 1.5, 0.03125}},
|
||||
noncuple = {{-1.5, -1.5, -0.03125, 1.5, 1.5, 0.03125}},
|
||||
offset = {{-0.5, -0.5, 0.96875, 0.5, 0.5, 1.03125}}
|
||||
}
|
||||
|
||||
local selection_boxes = {
|
||||
single = {{-0.5, -0.5, -0.25, 0.5, 0.5, 0.25}},
|
||||
double = {{-0.5, -0.5, -0.25, 0.5, 1.5, 0.25}},
|
||||
triple = {{-0.5, -0.5, -0.25, 0.5, 1.5, 0.25}, {-0.5, -0.5, -0.25, 1.5, 0.5, 0.25}},
|
||||
quadruple = {{-0.5, -0.5, -0.25, 1.5, 1.5, 0.25}},
|
||||
noncuple = {{-1.5, -1.5, -0.25, 1.5, 1.5, 0.25}},
|
||||
offset = {{-0.5, -0.5, 0.75, 0.5, 0.5, 1.25}}
|
||||
}
|
||||
|
||||
local panes = {
|
||||
{
|
||||
"glass",
|
||||
"Glass Pane",
|
||||
"default_glass.png",
|
||||
"glass_stained_edge.png",
|
||||
default.node_sound_glass_defaults(),
|
||||
{
|
||||
{"xpanes:pane_flat", "xpanes:pane_flat"},
|
||||
{"xpanes:pane_flat", "xpanes:pane_flat"}
|
||||
},
|
||||
"4"
|
||||
},
|
||||
{
|
||||
"obsidian_glass",
|
||||
"Obsidian Glass Pane",
|
||||
"default_obsidian_glass.png",
|
||||
"xpanes_edge_obsidian.png",
|
||||
default.node_sound_glass_defaults(),
|
||||
{
|
||||
{"xpanes:obsidian_pane_flat", "xpanes:obsidian_pane_flat"},
|
||||
{"xpanes:obsidian_pane_flat", "xpanes:obsidian_pane_flat"}
|
||||
},
|
||||
"4"
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
"Steel Bars",
|
||||
"xpanes_bar.png",
|
||||
"xpanes_bar_top.png",
|
||||
default.node_sound_metal_defaults(),
|
||||
{
|
||||
{"xpanes:bar_flat", "xpanes:bar_flat"},
|
||||
{"xpanes:bar_flat", "xpanes:bar_flat"}
|
||||
},
|
||||
"4"
|
||||
},
|
||||
}
|
||||
|
||||
local function define_crafts(pane, main_craft, main_output)
|
||||
single_pane = pane.."_single"
|
||||
|
||||
minetest.register_craft({
|
||||
output = single_pane.." "..main_output,
|
||||
recipe = main_craft,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = pane.."_double",
|
||||
recipe = {
|
||||
{single_pane},
|
||||
{single_pane}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = single_pane.." 2",
|
||||
recipe = {
|
||||
{pane.."_double"}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = pane.."_triple",
|
||||
recipe = {
|
||||
{single_pane, ""},
|
||||
{single_pane, single_pane}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = single_pane.." 3",
|
||||
recipe = {
|
||||
{pane.."_triple"}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = pane.."_quadruple",
|
||||
recipe = {
|
||||
{single_pane, single_pane},
|
||||
{single_pane, single_pane}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = single_pane.." 4",
|
||||
recipe = {
|
||||
{pane.."_quadruple"}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = pane.."_noncuple",
|
||||
recipe = {
|
||||
{single_pane, single_pane, single_pane},
|
||||
{single_pane, single_pane, single_pane},
|
||||
{single_pane, single_pane, single_pane}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = single_pane.." 9",
|
||||
recipe = {
|
||||
{pane.."_noncuple"}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = pane.."_offset",
|
||||
recipe = {
|
||||
{single_pane}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = single_pane,
|
||||
recipe = {
|
||||
{pane.."_offset"}
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
for name, selection_box in pairs(selection_boxes) do
|
||||
for node = 1, 18 do
|
||||
minetest.register_node("glass_stained:glass_"..node.."_"..name, {
|
||||
description = "Stained Glass "..node.." ("..name:sub(1, 1):upper()..name:sub(2, -1)..")",
|
||||
drawtype = "nodebox",
|
||||
tiles = {"glass_stained_"..node..".png"},
|
||||
wield_image = "glass_stained_"..node..".png",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = nodeboxes[name],
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = selection_box,
|
||||
},
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||
use_texture_alpha = true,
|
||||
sounds = default.node_sound_glass_defaults()
|
||||
})
|
||||
|
||||
if name == "noncuple" then
|
||||
define_crafts("glass_stained:glass_"..node, {
|
||||
{"dye:"..crafting[node][1], "xpanes:pane_flat"},
|
||||
{"dye:"..crafting[node][2], "xpanes:pane_flat"},
|
||||
{"dye:"..crafting[node][3], "xpanes:pane_flat"}
|
||||
}, "3")
|
||||
end
|
||||
|
||||
if node <= 12 then
|
||||
minetest.register_alias("glass_stained:glass_number_"..alias[node], "glass_stained:glass_"..node.."single")
|
||||
minetest.register_alias("glass_stained:glass_number_"..alias[node].."top", "glass_stained:glass_"..node.."double")
|
||||
end
|
||||
end
|
||||
|
||||
for _, pane in ipairs(panes) do
|
||||
minetest.register_node("glass_stained:pane_"..pane[1].."_"..name, {
|
||||
description = pane[2].." ("..name:sub(1, 1):upper()..name:sub(2, -1)..")",
|
||||
drawtype = "nodebox",
|
||||
tiles = {pane[4], pane[4], pane[3]},
|
||||
wield_image = pane[3],
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = thick_nodeboxes[name],
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = selection_box,
|
||||
},
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||
sounds = pane[5]
|
||||
})
|
||||
|
||||
if name == "noncuple" then
|
||||
define_crafts("glass_stained:pane_"..pane[1], pane[6], pane[7])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_alias("glass_stained:glass_normal", "glass_stained:pane_glass_single")
|
||||
minetest.register_alias("glass_stained:glass_normal_top", "glass_stained:pane_glass_double")
|
||||
minetest.register_alias("glass_stained:obsidian_glass_normal", "glass_stained:pane_obsidian_glass_single")
|
||||
minetest.register_alias("glass_stained:obsidian_glass_normal_top", "glass_stained:pane_obsidian_glass_double")
|
||||
minetest.register_alias("glass_stained:steel_bars_normal", "glass_stained:pane_bar_single")
|
||||
minetest.register_alias("glass_stained:steel_bars_normal_top", "glass_stained:pane_bar_double")
|
||||
minetest.register_alias("glass_stained:steel_bars_fancy", "glass_stained:pane_bar_top_pane_single")
|
||||
|
||||
xpanes.register_pane("bar_top", {
|
||||
description = "Spiked Steel Railing",
|
||||
textures = {"glass_stained_bar_fancy.png", "xpanes_pane_half.png", "default_glass_detail.png"},
|
||||
inventory_image = "glass_stained_bar_fancy.png",
|
||||
wield_image = "glass_stained_bar_fancy.png",
|
||||
groups = {cracky = 2},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
recipe = {
|
||||
{"", "default:steel_ingot", ""},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
xpanes.register_pane("pane", {
|
||||
description = "Glass Pane",
|
||||
textures = {"default_glass.png","xpanes_pane_half.png","glass_stained_edge.png"},
|
||||
inventory_image = "default_glass.png",
|
||||
wield_image = "default_glass.png",
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
groups = {snappy = 2, cracky = 3, oddly_breakable_by_hand = 3},
|
||||
recipe = {
|
||||
{"default:glass", "default:glass", "default:glass"},
|
||||
{"default:glass", "default:glass", "default:glass"}
|
||||
}
|
||||
})
|
||||
|
||||
xpanes.register_pane("obsidian_pane", {
|
||||
description = "Obsidian Glass Pane",
|
||||
textures = {"default_obsidian_glass.png","xpanes_pane_half.png","xpanes_edge_obsidian.png"},
|
||||
inventory_image = "default_obsidian_glass.png",
|
||||
wield_image = "default_obsidian_glass.png",
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
groups = {snappy = 2, cracky = 3},
|
||||
recipe = {
|
||||
{"default:obsidian_glass", "default:obsidian_glass", "default:obsidian_glass"},
|
||||
{"default:obsidian_glass", "default:obsidian_glass", "default:obsidian_glass"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_node("glass_stained:pane_bar_top_pane_single", {
|
||||
description = "Spiked Steel Railing Pane (Single)",
|
||||
drawtype = "nodebox",
|
||||
tiles = {"blank.png", "blank.png", "glass_stained_bar_fancy.png"},
|
||||
wield_image = "glass_stained_bar_fancy.png",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = thick_nodeboxes["single"],
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = selection_boxes["single"],
|
||||
},
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("glass_stained:pane_bar_top_pane_offset", {
|
||||
description = "Spiked Steel Railing Pane (Offset)",
|
||||
drawtype = "nodebox",
|
||||
tiles = {"blank.png", "blank.png", "glass_stained_bar_fancy.png"},
|
||||
wield_image = "glass_stained_bar_fancy.png",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = thick_nodeboxes["offset"],
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = selection_boxes["offset"],
|
||||
},
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "glass_stained:pane_bar_top_pane_single",
|
||||
recipe = {
|
||||
{"xpanes:bar_top_flat"}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "glass_stained:pane_bar_top_pane_offset",
|
||||
recipe = {
|
||||
{"glass_stained:pane_bar_top_pane_single"}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "glass_stained:pane_bar_top_pane_single",
|
||||
recipe = {
|
||||
{"glass_stained:pane_bar_top_pane_offset"}
|
||||
},
|
||||
})
|
63
mods/glass_stained/licence.txt
Normal file
|
@ -0,0 +1,63 @@
|
|||
LICENSE FOR CODE:
|
||||
=================
|
||||
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
|
||||
|
||||
LICENSE FOR MEDIA:
|
||||
==================
|
||||
|
||||
|
||||
Licenses of media (textures, models and sounds)
|
||||
-----------------------------------------------
|
||||
|
||||
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||
|
||||
You are free to:
|
||||
Share — copy and redistribute the material in any medium or format.
|
||||
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
|
||||
The licensor cannot revoke these freedoms as long as you follow the license terms.
|
||||
|
||||
Under the following terms:
|
||||
|
||||
Attribution — You must give appropriate credit, provide a link to the license, and
|
||||
indicate if changes were made. You may do so in any reasonable manner, but not in any way
|
||||
that suggests the licensor endorses you or your use.
|
||||
|
||||
ShareAlike — If you remix, transform, or build upon the material, you must distribute
|
||||
your contributions under the same license as the original.
|
||||
|
||||
No additional restrictions — You may not apply legal terms or technological measures that
|
||||
legally restrict others from doing anything the license permits.
|
||||
|
||||
Notices:
|
||||
|
||||
You do not have to comply with the license for elements of the material in the public
|
||||
domain or where your use is permitted by an applicable exception or limitation.
|
||||
No warranties are given. The license may not give you all of the permissions necessary
|
||||
for your intended use. For example, other rights such as publicity, privacy, or moral
|
||||
rights may limit how you use the material.
|
||||
|
||||
For more details:
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
7
mods/glass_stained/mod.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
name=glass_stained
|
||||
description=A mod that adds fancy stained glass and spiked iron railing.
|
||||
depends=default,xpanes,dye
|
||||
|
||||
release = 6066
|
||||
author = v-rob
|
||||
title = Fancy Stained Glass
|
BIN
mods/glass_stained/screenshot.png
Normal file
After Width: | Height: | Size: 301 KiB |
BIN
mods/glass_stained/textures/glass_stained_1.png
Normal file
After Width: | Height: | Size: 253 B |
BIN
mods/glass_stained/textures/glass_stained_10.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
mods/glass_stained/textures/glass_stained_11.png
Normal file
After Width: | Height: | Size: 292 B |
BIN
mods/glass_stained/textures/glass_stained_12.png
Normal file
After Width: | Height: | Size: 289 B |
BIN
mods/glass_stained/textures/glass_stained_13.png
Normal file
After Width: | Height: | Size: 323 B |
BIN
mods/glass_stained/textures/glass_stained_14.png
Normal file
After Width: | Height: | Size: 311 B |
BIN
mods/glass_stained/textures/glass_stained_15.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
mods/glass_stained/textures/glass_stained_16.png
Normal file
After Width: | Height: | Size: 231 B |
BIN
mods/glass_stained/textures/glass_stained_17.png
Normal file
After Width: | Height: | Size: 232 B |
BIN
mods/glass_stained/textures/glass_stained_18.png
Normal file
After Width: | Height: | Size: 235 B |
BIN
mods/glass_stained/textures/glass_stained_2.png
Normal file
After Width: | Height: | Size: 277 B |
BIN
mods/glass_stained/textures/glass_stained_3.png
Normal file
After Width: | Height: | Size: 271 B |
BIN
mods/glass_stained/textures/glass_stained_4.png
Normal file
After Width: | Height: | Size: 267 B |
BIN
mods/glass_stained/textures/glass_stained_5.png
Normal file
After Width: | Height: | Size: 306 B |
BIN
mods/glass_stained/textures/glass_stained_6.png
Normal file
After Width: | Height: | Size: 283 B |
BIN
mods/glass_stained/textures/glass_stained_7.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
mods/glass_stained/textures/glass_stained_8.png
Normal file
After Width: | Height: | Size: 336 B |
BIN
mods/glass_stained/textures/glass_stained_9.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
mods/glass_stained/textures/glass_stained_bar_fancy.png
Normal file
After Width: | Height: | Size: 316 B |
BIN
mods/glass_stained/textures/glass_stained_edge.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
mods/glass_stained/textures/glass_stained_palette.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
mods/glass_stained/textures/xpanes_edge_obsidian.png
Normal file
After Width: | Height: | Size: 215 B |
152
mods/protector/README.md
Normal file
|
@ -0,0 +1,152 @@
|
|||
Protector Redo mod [protect]
|
||||
|
||||
Protector redo for minetest is a mod that protects a players builds by placing
|
||||
a block that stops other players from digging or placing blocks in that area.
|
||||
|
||||
based on glomie's mod, remade by Zeg9 and rewritten by TenPlus1.
|
||||
|
||||
https://forum.minetest.net/viewtopic.php?f=11&t=9376
|
||||
|
||||
Change log:
|
||||
|
||||
- 0.1 - Initial release
|
||||
- 0.2 - Texture update
|
||||
- 0.3 - Added Protection Logo to blend in with player builds
|
||||
- 0.4 - Code tweak for 0.4.10+
|
||||
- 0.5 - Added protector.radius variable in init.lua (default: 5)
|
||||
- 0.6 - Added Protected Doors (wood and steel) and Protected Chest
|
||||
- 0.7 - Protected Chests now have "To Chest" and "To Inventory" buttons to copy
|
||||
contents across, also chests can be named
|
||||
- 0.8 - Updated to work with Minetest 0.4.12, simplified textures
|
||||
- 0.9 - Tweaked code
|
||||
- 1.0 - Only owner can remove protector
|
||||
- 1.1 - Set 'protector_pvp = true' in minetest.conf to disable pvp in protected
|
||||
areas except your own, also setting protector_pvp_spawn higher than 0 will
|
||||
disable pvp around spawn area with the radius you entered
|
||||
- 1.2 - Shift and click support added with Minetest 0.4.13 to quickly copy stacks
|
||||
to and from protected chest
|
||||
- 1.3 - Moved protector on_place into node itself, protector zone display changed
|
||||
from 10 to 5 seconds, general code tidy
|
||||
- 1.4 - Changed protector recipes to give single item instead of 4, added + button
|
||||
to interface, tweaked and tidied code, added admin command /delprot to remove
|
||||
protectors in bulk from banned/old players
|
||||
- 1.5 - Added much requested protected trapdoor
|
||||
- 1.6 - Added protector_drop (true or false) and protector_hurt (hurt by this num)
|
||||
variables to minetest.conf settings to stop players breaking protected
|
||||
areas by dropping tools and hurting player.
|
||||
- 1.7 - Included an edited version of WTFPL doors mod since protected doors didn't
|
||||
work with the doors mod in the latest daily build... Now it's fine :)
|
||||
added support for "protection_bypass" privelage.
|
||||
- 1.8 - Added 'protector_flip' setting to stop players using lag to grief into
|
||||
another players house, it flips them around to stop them digging.
|
||||
- 1.9 - Renamed 'protector_pvp_spawn' setting to 'protector_spawn' which protects
|
||||
an area around static spawnpoint and disables pvp if active.
|
||||
(note: previous name can still be used)
|
||||
- 2.0 - Added protector placement tool (thanks to Shara) so that players can easily
|
||||
stand on a protector, face in a direction and it places a new one at a set
|
||||
distance to cover protection radius. Added /protector_show command (thanks agaran)
|
||||
Protectors and chest cannot be moved by mesecon pistons or machines.
|
||||
- 2.1 - Added 'protector_night_pvp' setting so night-time becomes a free for all and
|
||||
players can hurt one another even inside protected areas (not spawn protected)
|
||||
- 2.2 - Updated protector tool so that player only needs to stand nearby (2 block radius)
|
||||
It can also place vertically (up and down) as well. New protector recipe added.
|
||||
- 2.3 - Localise many of the protector functions and tidy code.
|
||||
- 2.4 - Update to newer functions, Minetest 0.4.16 needed to run now.
|
||||
- 2.5 - Added HUD text to show when player is inside a protected area (updates every 5 seconds)
|
||||
- 2.6 - Add protection against CSM tampering, updated Intllib support (thanks codexp), tweaked block textures
|
||||
- 2.7 - Remove protection field entity when protector has been dug
|
||||
- 2.8 - Added 'protector_show_interval' setting to minetest.conf [default is 5], make protection field glow in dark.
|
||||
- 2.9 - Added MineClone2 recipes for protection block but no official support as yet
|
||||
- 3.0 - Added PlayerFactions support, 'protector_hud_interval' setting and listing in advanced settings for mod values.
|
||||
- 3.1 - Ability to hide protection blocks using /protector_hide and /protector_show , italian local added (thanks Hamlet)
|
||||
- 3.2 - Defaults to Minetest translation if found, otherwise intllib fallback if loaded, locale files updated for both. Added 'protector_msg' setting for player text.
|
||||
- 3.3 - Added support for playerfactions new api (thanks louisroyer), added limiter to protection radius of 22.
|
||||
- 3.4 - Player flip and hurt functions moved to minetest.register_protection_violation function (thanks hlqkj), added 'protector_crafts' setting, changed wood doors n chests to immediate_dig for mineclone2 fix. Upped protector radius limit to 30.
|
||||
- 3.5 - Store settings in global, reduce screenshot, tweak door sounds, use node template, add name check to commands, add commands to add and remove member names, tweak & tidy code.
|
||||
|
||||
Lucky Blocks: 10
|
||||
|
||||
|
||||
Usage: (requires server privelage)
|
||||
|
||||
list names to remove
|
||||
|
||||
/protector_remove
|
||||
|
||||
remove specific user names
|
||||
|
||||
/protector_remove name1 name2
|
||||
|
||||
reset names on remove list
|
||||
|
||||
/protector_remove -
|
||||
|
||||
Whenever a player is near any protectors with name1 or name2 then it will be
|
||||
replaced by an air block.
|
||||
|
||||
|
||||
show owner name to replace
|
||||
|
||||
/protector_replace
|
||||
|
||||
replace owner with new name
|
||||
|
||||
/protector_replace owner new_owner
|
||||
|
||||
reset names on replace list
|
||||
|
||||
/protector_replace -
|
||||
|
||||
show protected areas of your nearby protectors (max of 5)
|
||||
|
||||
/protector_show_area
|
||||
|
||||
A players own protection blocks can be hidden and shown using the following:
|
||||
|
||||
/protector_hide
|
||||
/protector_show
|
||||
|
||||
Adding members to local protection can be done by using
|
||||
|
||||
/protector_add_member
|
||||
|
||||
Removing members from local protection can be done by using
|
||||
|
||||
/protector_del_member
|
||||
|
||||
|
||||
The following lines can be added to your minetest.conf file to configure specific features of the mod:
|
||||
|
||||
protector_radius = 5
|
||||
- Sets the area around each protection node so that other players cannot dig, place or enter through protected doors or chests.
|
||||
|
||||
protector_pvp = true
|
||||
- true or false this setting disabled pvp inside of protected areas for all players apart from those listed on the protector node.
|
||||
|
||||
protector_night_pvp = false
|
||||
- when true this setting enables pvp at night time only, even inside protected areas, requires protector_pvp to be active to work.
|
||||
|
||||
protector_spawn = 10
|
||||
- Sets an area 10 nodes around static spawnpoint that is protected.
|
||||
|
||||
protector_hurt = 2
|
||||
- When set to above 0, players digging in protected areas will be hurt by 2 health points (or whichever number it's set to)
|
||||
|
||||
protector_flip = true
|
||||
- When true players who dig inside a protected area will flipped around to stop them using lag to grief into someone else's build
|
||||
|
||||
protector_show_interval
|
||||
- Number of seconds the protection field is visible, defaults to 5 seconds.
|
||||
|
||||
protector_recipe = true
|
||||
- When true allows players to craft protection blocks
|
||||
|
||||
protector_msg = true
|
||||
- When true shows protection messages in players chat when trying to interact in someone else's area
|
||||
|
||||
|
||||
Protector Tool
|
||||
|
||||
Can be crafted with a protector surrounded by steel ingots and is used to place new protectors at a set distance of protector.radius in all directions including up and down simply by looking in a direction.
|
||||
|
||||
Use by standing near an existing protector, looking in a direction and using as a tool, hold sneak/shift to place new protector containing member list from inside nearest one.
|
249
mods/protector/admin.lua
Normal file
|
@ -0,0 +1,249 @@
|
|||
|
||||
-- translation and default name vars
|
||||
|
||||
local S = core.get_translator("protector")
|
||||
local removal_names = ""
|
||||
local replace_names = ""
|
||||
|
||||
-- remove protection command
|
||||
|
||||
core.register_chatcommand("protector_remove", {
|
||||
params = S("<names list>"),
|
||||
description = S("Remove Protectors around players (separate names with spaces)"),
|
||||
privs = {server = true},
|
||||
|
||||
func = function(name, param)
|
||||
|
||||
if param == "-" then
|
||||
|
||||
core.chat_send_player(name, S("Name List Reset"))
|
||||
|
||||
removal_names = "" ; return
|
||||
end
|
||||
|
||||
if param ~= "" then
|
||||
removal_names = param
|
||||
end
|
||||
|
||||
core.chat_send_player(name,
|
||||
S("Protector Names to remove: @1", removal_names))
|
||||
end
|
||||
})
|
||||
|
||||
-- replace protection command
|
||||
|
||||
core.register_chatcommand("protector_replace", {
|
||||
params = S("<owner name> <name to replace with>"),
|
||||
description = S("Replace Protector Owner with name provided"),
|
||||
privs = {server = true},
|
||||
|
||||
func = function(name, param)
|
||||
|
||||
-- reset list to empty
|
||||
if param == "-" then
|
||||
|
||||
core.chat_send_player(name, S("Name List Reset"))
|
||||
|
||||
replace_names = "" ; return
|
||||
end
|
||||
|
||||
-- check and set replacement name
|
||||
if param ~= "" then
|
||||
|
||||
local names = param:split(" ") ; if not names[2] then return end
|
||||
|
||||
if names[2] ~= string.match(names[2], "[%w_-]+") then
|
||||
core.chat_send_player(name, S("Invalid player name!")) ; return
|
||||
end
|
||||
|
||||
if names[2]:len() > 25 then
|
||||
core.chat_send_player(name, S("Player name too long")) ; return
|
||||
end
|
||||
|
||||
replace_names = param
|
||||
end
|
||||
|
||||
-- show name info
|
||||
if replace_names ~= "" then
|
||||
|
||||
local names = replace_names:split(" ")
|
||||
|
||||
core.chat_send_player(name, S("Replacing Protector name @1 with @2",
|
||||
names[1] or "", names[2] or ""))
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- Abm to remove or replace protectors within active player area
|
||||
|
||||
core.register_abm({
|
||||
nodenames = {"protector:protect", "protector:protect2", "protector:protect_hidden"},
|
||||
interval = 5,
|
||||
chance = 1,
|
||||
catch_up = false,
|
||||
|
||||
action = function(pos, node)
|
||||
|
||||
if removal_names == "" and replace_names == "" then return end
|
||||
|
||||
local meta = core.get_meta(pos) ; if not meta then return end
|
||||
local owner = meta:get_string("owner")
|
||||
|
||||
if removal_names ~= "" then
|
||||
|
||||
local names = removal_names:split(" ")
|
||||
|
||||
for _, n in pairs(names) do
|
||||
|
||||
if n == owner then
|
||||
core.set_node(pos, {name = "air"}) ; return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if replace_names ~= "" then
|
||||
|
||||
local names = replace_names:split(" ")
|
||||
|
||||
if names[1] and names[2] and owner == names[1] then
|
||||
|
||||
meta:set_string("owner", names[2])
|
||||
meta:set_string("infotext", S("Protection (owned by @1)", names[2]))
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- show protection areas of nearby protectors owned by you (thanks agaran)
|
||||
|
||||
local r = protector.radius
|
||||
|
||||
core.register_chatcommand("protector_show_area", {
|
||||
params = "",
|
||||
description = S("Show protected areas of your nearby protectors"),
|
||||
privs = {},
|
||||
|
||||
func = function(name, param)
|
||||
|
||||
local player = core.get_player_by_name(name)
|
||||
local pos = player:get_pos()
|
||||
|
||||
-- find the protector nodes
|
||||
local pos = core.find_nodes_in_area(
|
||||
{x = pos.x - r, y = pos.y - r, z = pos.z - r},
|
||||
{x = pos.x + r, y = pos.y + r, z = pos.z + r},
|
||||
{"protector:protect", "protector:protect2", "protector:protect_hidden"})
|
||||
|
||||
local meta, owner
|
||||
|
||||
-- show a maximum of 5 protected areas only
|
||||
for n = 1, math.min(#pos, 5) do
|
||||
|
||||
meta = core.get_meta(pos[n])
|
||||
owner = meta:get_string("owner") or ""
|
||||
|
||||
if owner == name
|
||||
or core.check_player_privs(name, {protection_bypass = true}) then
|
||||
core.add_entity(pos[n], "protector:display")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- ability to hide protection blocks (borrowed from doors mod :)
|
||||
|
||||
core.register_node("protector:protect_hidden", {
|
||||
description = "Hidden Protector",
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
-- has to be walkable for falling nodes to stop falling
|
||||
walkable = true,
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = false,
|
||||
floodable = false,
|
||||
drop = "",
|
||||
groups = {not_in_creative_inventory = 1, unbreakable = 1},
|
||||
is_ground_content = false,
|
||||
on_blast = function() end,
|
||||
-- 1px block to stop falling nodes replacing protector
|
||||
collision_box = {
|
||||
type = "fixed", fixed = {-15/32, 13/32, -15/32, -13/32, 1/2, -13/32}
|
||||
}
|
||||
})
|
||||
|
||||
-- make own protectors visible in area
|
||||
|
||||
core.register_chatcommand("protector_show", {
|
||||
params = "",
|
||||
description = S("Show your nearby protection blocks"),
|
||||
privs = {interact = true},
|
||||
|
||||
func = function(name, param)
|
||||
|
||||
local player = core.get_player_by_name(name)
|
||||
|
||||
if not player then
|
||||
return false, S("Player not found.")
|
||||
end
|
||||
|
||||
local pos = player:get_pos()
|
||||
|
||||
local a = core.find_nodes_in_area(
|
||||
{x = pos.x - r, y = pos.y - r, z = pos.z - r},
|
||||
{x = pos.x + r, y = pos.y + r, z = pos.z + r},
|
||||
{"protector:protect_hidden"})
|
||||
|
||||
local meta, owner
|
||||
|
||||
for _, row in pairs(a) do
|
||||
|
||||
meta = core.get_meta(row)
|
||||
owner = meta:get_string("owner") or ""
|
||||
|
||||
if owner == name
|
||||
or core.check_player_privs(name, {protection_bypass = true}) then
|
||||
core.swap_node(row, {name = "protector:protect"})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- make own protectors invisible in area
|
||||
|
||||
core.register_chatcommand("protector_hide", {
|
||||
params = "",
|
||||
description = S("Hide your nearby protection blocks"),
|
||||
privs = {interact = true},
|
||||
|
||||
func = function(name, param)
|
||||
|
||||
local player = core.get_player_by_name(name)
|
||||
|
||||
if not player then
|
||||
return false, S("Player not found.")
|
||||
end
|
||||
|
||||
local pos = player:get_pos()
|
||||
|
||||
local a = core.find_nodes_in_area(
|
||||
{x = pos.x - r, y = pos.y - r, z = pos.z - r},
|
||||
{x = pos.x + r, y = pos.y + r, z = pos.z + r},
|
||||
{"protector:protect", "protector:protect2"})
|
||||
|
||||
local meta, owner
|
||||
|
||||
for _, row in pairs(a) do
|
||||
|
||||
meta = core.get_meta(row)
|
||||
owner = meta:get_string("owner") or ""
|
||||
|
||||
if owner == name
|
||||
or core.check_player_privs(name, {protection_bypass = true}) then
|
||||
core.swap_node(row, {name = "protector:protect_hidden"})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
253
mods/protector/chest.lua
Normal file
|
@ -0,0 +1,253 @@
|
|||
|
||||
-- translation
|
||||
|
||||
local S = core.get_translator("protector")
|
||||
local F = core.formspec_escape
|
||||
|
||||
-- MineClone support
|
||||
|
||||
local mcl = core.get_modpath("mcl_core")
|
||||
local mcf = core.get_modpath("mcl_formspec")
|
||||
|
||||
-- Are crafts enabled?
|
||||
|
||||
local protector_crafts = core.settings:get_bool("protector_crafts") ~= false
|
||||
|
||||
-- Protected Chest
|
||||
|
||||
local chest_size = mcl and (9 * 3) or (8 * 4)
|
||||
|
||||
core.register_node("protector:chest", {
|
||||
description = S("Protected Chest"),
|
||||
tiles = {
|
||||
"default_chest_top.png", "default_chest_top.png",
|
||||
"default_chest_side.png", "default_chest_side.png",
|
||||
"default_chest_side.png", "default_chest_front.png^protector_logo.png"
|
||||
},
|
||||
paramtype2 = "facedir",
|
||||
groups = {dig_immediate = 2, unbreakable = 1},
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
|
||||
on_construct = function(pos)
|
||||
|
||||
local meta = core.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
meta:set_string("infotext", S("Protected Chest"))
|
||||
meta:set_string("name", S("Protected Chest"))
|
||||
inv:set_size("main", chest_size)
|
||||
end,
|
||||
|
||||
can_dig = function(pos,player)
|
||||
|
||||
local meta = core.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
if inv:is_empty("main") then
|
||||
|
||||
if not core.is_protected(pos, player:get_player_name()) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
|
||||
core.log("action", player:get_player_name()
|
||||
.. " moves stuff to protected chest at " .. core.pos_to_string(pos))
|
||||
end,
|
||||
|
||||
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
|
||||
core.log("action", player:get_player_name()
|
||||
.. " takes stuff from protected chest at " .. core.pos_to_string(pos))
|
||||
end,
|
||||
|
||||
on_metadata_inventory_move = function(
|
||||
pos, from_list, from_index, to_list, to_index, count, player)
|
||||
|
||||
core.log("action", player:get_player_name()
|
||||
.. " moves stuff inside protected chest at " .. core.pos_to_string(pos))
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
|
||||
if core.is_protected(pos, player:get_player_name()) then
|
||||
return 0
|
||||
end
|
||||
|
||||
return stack:get_count()
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
|
||||
if core.is_protected(pos, player:get_player_name()) then
|
||||
return 0
|
||||
end
|
||||
|
||||
return stack:get_count()
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_move = function(
|
||||
pos, from_list, from_index, to_list, to_index, count, player)
|
||||
|
||||
if core.is_protected(pos, player:get_player_name()) then
|
||||
return 0
|
||||
end
|
||||
|
||||
return count
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
|
||||
if core.is_protected(pos, clicker:get_player_name()) then return end
|
||||
|
||||
local meta = core.get_meta(pos) ; if not meta then return end
|
||||
|
||||
local spos = pos.x .. "," .. pos.y .. "," ..pos.z
|
||||
local formspec
|
||||
|
||||
-- mineclone support
|
||||
if mcl and mcf then
|
||||
|
||||
formspec = "size[9,8.75]"
|
||||
.. "label[0,0;" .. core.formspec_escape(
|
||||
core.colorize("#313131", "Protected Chest")) .. "]"
|
||||
.. "list[nodemeta:" .. spos .. ";main;0,0.5;9,3;]"
|
||||
.. mcl_formspec.get_itemslot_bg(0,0.5,9,3)
|
||||
.. "image_button[3.0,3.5;1.05,0.8;protector_up_icon.png;protect_up;]"
|
||||
.. "image_button[4.0,3.5;1.05,0.8;protector_down_icon.png;protect_down;]"
|
||||
.. "label[0,4.0;" .. core.formspec_escape(
|
||||
core.colorize("#313131", "Inventory")) .. "]"
|
||||
.. "list[current_player;main;0,4.5;9,3;9]"
|
||||
.. mcl_formspec.get_itemslot_bg(0,4.5,9,3)
|
||||
.. "list[current_player;main;0,7.74;9,1;]"
|
||||
.. mcl_formspec.get_itemslot_bg(0,7.74,9,1)
|
||||
.. "listring[nodemeta:" .. spos .. ";main]"
|
||||
.. "listring[current_player;main]"
|
||||
|
||||
else -- default formspec
|
||||
|
||||
formspec = "size[8,9]"
|
||||
.. "list[nodemeta:".. spos .. ";main;0,0.3;8,4;]"
|
||||
|
||||
.. "image_button[-0.01,4.26;1.05,0.8;protector_up_icon.png;protect_up;]"
|
||||
.. "image_button[0.98,4.26;1.05,0.8;protector_down_icon.png;protect_down;]"
|
||||
.. "tooltip[protect_up;" .. S("To Chest") .. "]"
|
||||
.. "tooltip[protect_down;" .. S("To Inventory") .. "]"
|
||||
|
||||
.. "field[2.3,4.8;4,0.25;protect_name;;"
|
||||
.. meta:get_string("name") .. "]"
|
||||
.. "button[5.99,4.5;2.05,0.25;protect_rename;" .. S("Rename") .. "]"
|
||||
|
||||
.. "list[current_player;main;0,5;8,1;]"
|
||||
.. "list[current_player;main;0,6.08;8,3;8]"
|
||||
.. "listring[nodemeta:" .. spos .. ";main]"
|
||||
.. "listring[current_player;main]"
|
||||
end
|
||||
|
||||
core.show_formspec(clicker:get_player_name(),
|
||||
"protector:chest_" .. core.pos_to_string(pos), formspec)
|
||||
end,
|
||||
|
||||
on_blast = function() end
|
||||
})
|
||||
|
||||
-- Container transfer helper
|
||||
|
||||
local function to_from(src, dst)
|
||||
|
||||
local stack, item, leftover
|
||||
local size = dst:get_size("main")
|
||||
|
||||
for i = 1, size do
|
||||
|
||||
stack = src:get_stack("main", i)
|
||||
item = stack:get_name()
|
||||
|
||||
if item ~= "" and dst:room_for_item("main", item) then
|
||||
|
||||
leftover = dst:add_item("main", stack)
|
||||
|
||||
if leftover and not leftover:is_empty() then
|
||||
src:set_stack("main", i, leftover)
|
||||
else
|
||||
src:set_stack("main", i, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Protected Chest formspec buttons
|
||||
|
||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
|
||||
if string.sub(formname, 0, 16) ~= "protector:chest_" then return end
|
||||
|
||||
local pos_s = string.sub(formname, 17)
|
||||
local pos = core.string_to_pos(pos_s)
|
||||
|
||||
if core.is_protected(pos, player:get_player_name()) then return end
|
||||
|
||||
local meta = core.get_meta(pos) ; if not meta then return end
|
||||
local chest_inv = meta:get_inventory() ; if not chest_inv then return end
|
||||
local player_inv = player:get_inventory()
|
||||
|
||||
-- copy contents of player inventory to chest
|
||||
if fields.protect_up then
|
||||
|
||||
to_from(player_inv, chest_inv)
|
||||
|
||||
-- copy contents of chest to player inventory
|
||||
elseif fields.protect_down then
|
||||
|
||||
to_from(chest_inv, player_inv)
|
||||
|
||||
elseif fields.protect_name or fields.protect_rename then
|
||||
|
||||
-- change chest infotext to display name
|
||||
if fields.protect_name ~= "" then
|
||||
|
||||
if fields.protect_name ~= string.match(fields.protect_name, "[%w%s_-]+")
|
||||
or fields.protect_name:len() > 35 then
|
||||
return
|
||||
end
|
||||
|
||||
meta:set_string("name", fields.protect_name)
|
||||
meta:set_string("infotext", fields.protect_name)
|
||||
else
|
||||
meta:set_string("name", S("Protected Chest"))
|
||||
meta:set_string("infotext", S("Protected Chest"))
|
||||
end
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
-- Protected Chest recipes
|
||||
|
||||
if protector_crafts then
|
||||
|
||||
if mcl then
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:chest",
|
||||
recipe = { {"mcl_chests:chest", "mcl_core:gold_ingot"} }
|
||||
})
|
||||
else
|
||||
core.register_craft({
|
||||
output = "protector:chest",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"group:wood", "default:copper_ingot", "group:wood"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:chest",
|
||||
recipe = { {"default:chest", "default:copper_ingot"} }
|
||||
})
|
||||
end
|
||||
end
|
521
mods/protector/doors.lua
Normal file
|
@ -0,0 +1,521 @@
|
|||
|
||||
-- doors code from an old client re-used
|
||||
|
||||
local S = core.get_translator("protector")
|
||||
|
||||
-- MineClone support
|
||||
|
||||
local mcl = core.get_modpath("mcl_core")
|
||||
|
||||
-- Are crafts enabled?
|
||||
|
||||
local protector_crafts = core.settings:get_bool("protector_crafts") ~= false
|
||||
|
||||
-- Registers a door
|
||||
|
||||
local function register_door(name, def)
|
||||
|
||||
def.groups.not_in_creative_inventory = 1
|
||||
def.groups.handy = 1
|
||||
def.groups.prot_door = 1
|
||||
|
||||
local box = {{-0.5, -0.5, -0.5, 0.5, 0.5, -0.5 + 1.5/16}}
|
||||
|
||||
def.node_box_bottom = box
|
||||
def.node_box_top = box
|
||||
def.selection_box_bottom = box
|
||||
def.selection_box_top = box
|
||||
|
||||
core.register_craftitem(name, {
|
||||
description = def.description,
|
||||
inventory_image = def.inventory_image,
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
|
||||
if pointed_thing.type ~= "node" then return itemstack end
|
||||
|
||||
local ptu = pointed_thing.under
|
||||
local nu = core.get_node(ptu)
|
||||
|
||||
if core.registered_nodes[nu.name]
|
||||
and core.registered_nodes[nu.name].on_rightclick then
|
||||
return core.registered_nodes[nu.name].on_rightclick(
|
||||
ptu, nu, placer, itemstack)
|
||||
end
|
||||
|
||||
local pt = pointed_thing.above
|
||||
local pt2 = {x = pt.x, y = pt.y, z = pt.z}
|
||||
|
||||
pt2.y = pt2.y + 1
|
||||
|
||||
if not core.registered_nodes[core.get_node(pt).name].buildable_to
|
||||
or not core.registered_nodes[core.get_node(pt2).name].buildable_to
|
||||
or not placer or not placer:is_player() then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
if core.is_protected(pt, placer:get_player_name())
|
||||
or core.is_protected(pt2, placer:get_player_name()) then
|
||||
core.record_protection_violation(pt, placer:get_player_name())
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local p2 = core.dir_to_facedir(placer:get_look_dir())
|
||||
local pt3 = {x = pt.x, y = pt.y, z = pt.z}
|
||||
|
||||
if p2 == 0 then pt3.x = pt3.x - 1
|
||||
elseif p2 == 1 then pt3.z = pt3.z + 1
|
||||
elseif p2 == 2 then pt3.x = pt3.x + 1
|
||||
elseif p2 == 3 then pt3.z = pt3.z - 1
|
||||
end
|
||||
|
||||
if core.get_item_group(core.get_node(pt3).name, "prot_door") == 0 then
|
||||
core.set_node(pt, {name = name .. "_b_1", param2 = p2})
|
||||
core.set_node(pt2, {name = name .. "_t_1", param2 = p2})
|
||||
else
|
||||
core.set_node(pt, {name = name .. "_b_2", param2 = p2})
|
||||
core.set_node(pt2, {name = name .. "_t_2", param2 = p2})
|
||||
|
||||
core.get_meta(pt):set_int("right", 1)
|
||||
core.get_meta(pt2):set_int("right", 1)
|
||||
end
|
||||
|
||||
if not core.settings:get_bool("creative_mode") then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
core.sound_play(def.sounds.place, {pos = pt2}, true)
|
||||
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
local tt = def.tiles_top
|
||||
local tb = def.tiles_bottom
|
||||
|
||||
local function after_dig_node(pos, name, digger)
|
||||
|
||||
local node = core.get_node(pos)
|
||||
|
||||
if node.name == name then
|
||||
core.node_dig(pos, node, digger)
|
||||
end
|
||||
end
|
||||
|
||||
local function on_rightclick(pos, dir, check_name, replace, replace_dir, params)
|
||||
|
||||
pos.y = pos.y + dir
|
||||
|
||||
if core.get_node(pos).name ~= check_name then return end
|
||||
|
||||
local p2 = core.get_node(pos).param2
|
||||
|
||||
p2 = params[p2 + 1]
|
||||
|
||||
core.swap_node(pos, {name = replace_dir, param2 = p2})
|
||||
|
||||
pos.y = pos.y - dir
|
||||
|
||||
core.swap_node(pos, {name = replace, param2=p2})
|
||||
|
||||
core.sound_play(def.open_sound,
|
||||
{pos = pos, gain = 0.3, max_hear_distance = 10}, true)
|
||||
end
|
||||
|
||||
local function on_rotate(pos, node, dir, user, check_name, mode, new_param2)
|
||||
|
||||
if mode ~= screwdriver.ROTATE_FACE then return false end
|
||||
|
||||
pos.y = pos.y + dir
|
||||
|
||||
if core.get_node(pos).name ~= check_name then return false end
|
||||
|
||||
if core.is_protected(pos, user:get_player_name()) then
|
||||
core.record_protection_violation(pos, user:get_player_name())
|
||||
return false
|
||||
end
|
||||
|
||||
local node2 = core.get_node(pos)
|
||||
|
||||
node2.param2 = (node2.param2 + 1) % 4
|
||||
|
||||
core.swap_node(pos, node2)
|
||||
|
||||
pos.y = pos.y - dir
|
||||
|
||||
node.param2 = (node.param2 + 1) % 4
|
||||
|
||||
core.swap_node(pos, node)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
core.register_node(name .. "_b_1", {
|
||||
tiles = {tb[2], tb[2], tb[2], tb[2], tb[1], tb[1] .. "^[transformfx"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
use_texture_alpha = "clip",
|
||||
is_ground_content = false,
|
||||
node_dig_prediction = "",
|
||||
drop = name,
|
||||
drawtype = "nodebox",
|
||||
node_box = {type = "fixed", fixed = def.node_box_bottom},
|
||||
selection_box = {type = "fixed", fixed = def.selection_box_bottom},
|
||||
groups = def.groups,
|
||||
_mcl_hardness = 0.8,
|
||||
_mcl_blast_resistance = 1,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
pos.y = pos.y + 1
|
||||
after_dig_node(pos, name.."_t_1", digger)
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
|
||||
if not core.is_protected(pos, clicker:get_player_name()) then
|
||||
on_rightclick(pos, 1, name .. "_t_1", name .. "_b_2",
|
||||
name .. "_t_2", {1,2,3,0})
|
||||
end
|
||||
end,
|
||||
|
||||
on_rotate = function(pos, node, user, mode, new_param2)
|
||||
return on_rotate(pos, node, 1, user, name .. "_t_1", mode)
|
||||
end,
|
||||
|
||||
sounds = def.sounds,
|
||||
sunlight_propagates = def.sunlight,
|
||||
on_blast = function() end
|
||||
})
|
||||
|
||||
core.register_node(name .. "_t_1", {
|
||||
tiles = {tt[2], tt[2], tt[2], tt[2], tt[1], tt[1] .. "^[transformfx"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
use_texture_alpha = "clip",
|
||||
is_ground_content = false,
|
||||
node_dig_prediction = "",
|
||||
drop = "",
|
||||
drawtype = "nodebox",
|
||||
node_box = {type = "fixed", fixed = def.node_box_top},
|
||||
selection_box = {type = "fixed", fixed = def.selection_box_top},
|
||||
groups = def.groups,
|
||||
_mcl_hardness = 0.8,
|
||||
_mcl_blast_resistance = 1,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
pos.y = pos.y - 1
|
||||
after_dig_node(pos, name .. "_b_1", digger)
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
if not core.is_protected(pos, clicker:get_player_name()) then
|
||||
on_rightclick(pos, -1, name .. "_b_1", name .. "_t_2",
|
||||
name .. "_b_2", {1,2,3,0})
|
||||
end
|
||||
end,
|
||||
|
||||
on_rotate = function(pos, node, user, mode, new_param2)
|
||||
return on_rotate(pos, node, -1, user, name .. "_b_1", mode)
|
||||
end,
|
||||
|
||||
sounds = def.sounds,
|
||||
sunlight_propagates = def.sunlight,
|
||||
on_blast = function() end
|
||||
})
|
||||
|
||||
core.register_node(name .. "_b_2", {
|
||||
tiles = {tb[2], tb[2], tb[2], tb[2], tb[1] .. "^[transformfx", tb[1]},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
use_texture_alpha = "clip",
|
||||
is_ground_content = false,
|
||||
node_dig_prediction = "",
|
||||
drop = name,
|
||||
drawtype = "nodebox",
|
||||
node_box = {type = "fixed", fixed = def.node_box_bottom},
|
||||
selection_box = {type = "fixed", fixed = def.selection_box_bottom},
|
||||
groups = def.groups,
|
||||
_mcl_hardness = 0.8,
|
||||
_mcl_blast_resistance = 1,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
pos.y = pos.y + 1
|
||||
after_dig_node(pos, name .. "_t_2", digger)
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
if not core.is_protected(pos, clicker:get_player_name()) then
|
||||
on_rightclick(pos, 1, name .. "_t_2", name .. "_b_1",
|
||||
name .. "_t_1", {3,0,1,2})
|
||||
end
|
||||
end,
|
||||
|
||||
on_rotate = function(pos, node, user, mode, new_param2)
|
||||
return on_rotate(pos, node, 1, user, name .. "_t_2", mode)
|
||||
end,
|
||||
|
||||
sounds = def.sounds,
|
||||
sunlight_propagates = def.sunlight,
|
||||
on_blast = function() end
|
||||
})
|
||||
|
||||
core.register_node(name .. "_t_2", {
|
||||
tiles = {tt[2], tt[2], tt[2], tt[2], tt[1] .. "^[transformfx", tt[1]},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
use_texture_alpha = "clip",
|
||||
is_ground_content = false,
|
||||
node_dig_prediction = "",
|
||||
drop = "",
|
||||
drawtype = "nodebox",
|
||||
node_box = {type = "fixed", fixed = def.node_box_top},
|
||||
selection_box = {type = "fixed", fixed = def.selection_box_top},
|
||||
groups = def.groups,
|
||||
_mcl_hardness = 0.8,
|
||||
_mcl_blast_resistance = 1,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
pos.y = pos.y - 1
|
||||
after_dig_node(pos, name .. "_b_2", digger)
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
if not core.is_protected(pos, clicker:get_player_name()) then
|
||||
on_rightclick(pos, -1, name .. "_b_2", name .. "_t_1",
|
||||
name .. "_b_1", {3,0,1,2})
|
||||
end
|
||||
end,
|
||||
|
||||
on_rotate = function(pos, node, user, mode, new_param2)
|
||||
return on_rotate(pos, node, -1, user, name .. "_b_2", mode)
|
||||
end,
|
||||
|
||||
sounds = def.sounds,
|
||||
sunlight_propagates = def.sunlight,
|
||||
on_blast = function() end
|
||||
})
|
||||
end
|
||||
|
||||
-- Protected Wooden Door
|
||||
|
||||
local name = "protector:door_wood"
|
||||
|
||||
register_door(name, {
|
||||
description = S("Protected Wooden Door"),
|
||||
inventory_image = "doors_wood.png^protector_logo.png",
|
||||
groups = {
|
||||
snappy = 1, choppy = 2, dig_immediate = 2, unbreakable = 1, axey = 1, handy = 1
|
||||
},
|
||||
tiles_bottom = {"doors_wood_b.png^protector_logo.png", "doors_brown.png"},
|
||||
tiles_top = {"doors_wood_a.png", "doors_brown.png"},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
open_sound = "default_dug_node",
|
||||
sunlight = false
|
||||
})
|
||||
|
||||
if protector_crafts then
|
||||
|
||||
if mcl then
|
||||
|
||||
core.register_craft({
|
||||
output = name,
|
||||
recipe = { {"mcl_doors:wooden_door", "mcl_core:gold_ingot"} }
|
||||
})
|
||||
else
|
||||
core.register_craft({
|
||||
output = name,
|
||||
recipe = {
|
||||
{"group:wood", "group:wood"},
|
||||
{"group:wood", "default:copper_ingot"},
|
||||
{"group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
core.register_craft({
|
||||
output = name,
|
||||
recipe = { {"doors:door_wood", "default:copper_ingot"} }
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Protected Steel Door
|
||||
|
||||
local name = "protector:door_steel"
|
||||
|
||||
register_door(name, {
|
||||
description = S("Protected Steel Door"),
|
||||
inventory_image = "doors_steel.png^protector_logo.png",
|
||||
groups = {
|
||||
snappy = 1, cracky = 1, handy = 1,
|
||||
level = (mcl and 0 or 2), pickaxey = 2, unbreakable = 1
|
||||
},
|
||||
tiles_bottom = {"doors_steel_b.png^protector_logo.png", "doors_grey.png"},
|
||||
tiles_top = {"doors_steel_a.png", "doors_grey.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
open_sound = "default_place_node_metal",
|
||||
sunlight = false,
|
||||
})
|
||||
|
||||
if protector_crafts then
|
||||
|
||||
if mcl then
|
||||
|
||||
core.register_craft({
|
||||
output = name,
|
||||
recipe = { {"mcl_doors:iron_door", "mcl_core:gold_ingot"} }
|
||||
})
|
||||
else
|
||||
core.register_craft({
|
||||
output = name,
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:copper_ingot"},
|
||||
{"default:steel_ingot", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
core.register_craft({
|
||||
output = name,
|
||||
recipe = { {"doors:door_steel", "default:copper_ingot"} }
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
----trapdoor----
|
||||
|
||||
local function register_trapdoor(name, def)
|
||||
|
||||
local name_closed = name
|
||||
local name_opened = name .. "_open"
|
||||
|
||||
def.on_rightclick = function (pos, node, clicker, itemstack, pointed_thing)
|
||||
|
||||
if core.is_protected(pos, clicker:get_player_name()) then return end
|
||||
|
||||
local newname = node.name == name_closed and name_opened or name_closed
|
||||
|
||||
core.sound_play(def.open_sound,
|
||||
{pos = pos, gain = 0.3, max_hear_distance = 10}, true)
|
||||
|
||||
core.swap_node(pos,
|
||||
{name = newname, param1 = node.param1, param2 = node.param2})
|
||||
end
|
||||
|
||||
-- Common trapdoor configuration
|
||||
def.drawtype = "nodebox"
|
||||
def.paramtype = "light"
|
||||
def.paramtype2 = "facedir"
|
||||
def.use_texture_alpha = "clip"
|
||||
def.is_ground_content = false
|
||||
def.node_dig_prediction = ""
|
||||
|
||||
local def_opened = table.copy(def)
|
||||
local def_closed = table.copy(def)
|
||||
|
||||
def_closed.node_box = {
|
||||
type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
|
||||
}
|
||||
def_closed.selection_box = {
|
||||
type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
|
||||
}
|
||||
def_closed.tiles = { def.tile_front, def.tile_front, def.tile_side, def.tile_side,
|
||||
def.tile_side, def.tile_side }
|
||||
|
||||
def_opened.node_box = {
|
||||
type = "fixed", fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
|
||||
}
|
||||
def_opened.selection_box = {
|
||||
type = "fixed", fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
|
||||
}
|
||||
def_opened.tiles = { def.tile_side, def.tile_side,
|
||||
def.tile_side .. "^[transform3",
|
||||
def.tile_side .. "^[transform1",
|
||||
def.tile_front, def.tile_front }
|
||||
|
||||
def_opened.drop = name_closed
|
||||
def_opened.groups.not_in_creative_inventory = 1
|
||||
|
||||
core.register_node(name_opened, def_opened)
|
||||
core.register_node(name_closed, def_closed)
|
||||
end
|
||||
|
||||
-- Protected Wooden Trapdoor
|
||||
|
||||
register_trapdoor("protector:trapdoor", {
|
||||
description = S("Protected Trapdoor"),
|
||||
inventory_image = "doors_trapdoor.png^protector_logo.png",
|
||||
wield_image = "doors_trapdoor.png^protector_logo.png",
|
||||
tile_front = "doors_trapdoor.png^protector_logo.png",
|
||||
tile_side = "doors_trapdoor_side.png",
|
||||
groups = {snappy = 1, choppy = 2, dig_immediate = 2, unbreakable = 1, axey = 1},
|
||||
_mcl_hardness = 0.8,
|
||||
_mcl_blast_resistance = 1,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
open_sound = "default_dug_node"
|
||||
})
|
||||
|
||||
if protector_crafts then
|
||||
|
||||
if mcl then
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:trapdoor",
|
||||
recipe = { {"mcl_doors:trapdoor", "mcl_core:gold_ingot"} }
|
||||
})
|
||||
else
|
||||
core.register_craft({
|
||||
output = "protector:trapdoor 2",
|
||||
recipe = {
|
||||
{"group:wood", "default:copper_ingot", "group:wood"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:trapdoor",
|
||||
recipe = { {"doors:trapdoor", "default:copper_ingot"} }
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Protected Steel Trapdoor
|
||||
|
||||
register_trapdoor("protector:trapdoor_steel", {
|
||||
description = S("Protected Steel Trapdoor"),
|
||||
inventory_image = "doors_trapdoor_steel.png^protector_logo.png",
|
||||
wield_image = "doors_trapdoor_steel.png^protector_logo.png",
|
||||
tile_front = "doors_trapdoor_steel.png^protector_logo.png",
|
||||
tile_side = "doors_trapdoor_steel_side.png",
|
||||
groups = {
|
||||
snappy = 1, bendy = 2, cracky = 1, level = (mcl and 0 or 2),
|
||||
unbreakable = 1, pickaxey = 2, handy = 1
|
||||
},
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 1,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
open_sound = "default_place_node_metal"
|
||||
})
|
||||
|
||||
if protector_crafts then
|
||||
|
||||
if mcl then
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:trapdoor_steel",
|
||||
recipe = { {"mcl_doors:iron_trapdoor", "mcl_core:gold_ingot"} }
|
||||
})
|
||||
else
|
||||
core.register_craft({
|
||||
output = "protector:trapdoor_steel",
|
||||
recipe = {
|
||||
{"default:copper_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:trapdoor_steel",
|
||||
recipe = { {"doors:trapdoor_steel", "default:copper_ingot"} }
|
||||
})
|
||||
end
|
||||
end
|
82
mods/protector/hud.lua
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
-- translation and protector radius
|
||||
|
||||
local S = core.get_translator("protector")
|
||||
local radius = protector.radius
|
||||
|
||||
-- hud settings
|
||||
|
||||
local hud = {}
|
||||
local hud_timer = 0
|
||||
local hud_interval = (tonumber(core.settings:get("protector_hud_interval")) or 4)
|
||||
local hud_style = core.has_feature("hud_def_type_field")
|
||||
|
||||
if hud_interval > 0 then
|
||||
|
||||
core.register_globalstep(function(dtime)
|
||||
|
||||
hud_timer = hud_timer + dtime
|
||||
|
||||
if hud_timer < hud_interval then return end
|
||||
|
||||
hud_timer = 0
|
||||
|
||||
for _, player in pairs(core.get_connected_players()) do
|
||||
|
||||
local name = player:get_player_name()
|
||||
local pos = vector.round(player:get_pos())
|
||||
local hud_text = ""
|
||||
|
||||
local protectors = core.find_nodes_in_area(
|
||||
{x = pos.x - radius , y = pos.y - radius , z = pos.z - radius},
|
||||
{x = pos.x + radius , y = pos.y + radius , z = pos.z + radius},
|
||||
{"protector:protect","protector:protect2", "protector:protect_hidden"})
|
||||
|
||||
if #protectors > 0 then
|
||||
|
||||
local npos = protectors[1]
|
||||
local meta = core.get_meta(npos)
|
||||
local nodeowner = meta:get_string("owner")
|
||||
local members = meta:get_string("members"):split(" ")
|
||||
|
||||
hud_text = S("Owner: @1", nodeowner)
|
||||
|
||||
if #members > 0 then
|
||||
hud_text = hud_text .. " [" .. #members .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
if not hud[name] then
|
||||
|
||||
hud[name] = {}
|
||||
|
||||
local hud_tab = {
|
||||
name = "Protector Area",
|
||||
number = 0xFFFF22,
|
||||
position = {x = 0, y = 0.95},
|
||||
offset = {x = 8, y = -8},
|
||||
text = hud_text,
|
||||
scale = {x = 200, y = 60},
|
||||
alignment = {x = 1, y = -1},
|
||||
}
|
||||
|
||||
if hud_style then
|
||||
hud_tab["type"] = "text"
|
||||
else
|
||||
hud_tab["hud_elem_type"] = "text"
|
||||
end
|
||||
|
||||
hud[name].id = player:hud_add(hud_tab)
|
||||
|
||||
return
|
||||
else
|
||||
player:hud_change(hud[name].id, "text", hud_text)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
core.register_on_leaveplayer(function(player)
|
||||
hud[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
end -- END hud_interval > 0
|
808
mods/protector/init.lua
Normal file
|
@ -0,0 +1,808 @@
|
|||
|
||||
-- default support (for use with MineClone2 and other [games]
|
||||
|
||||
if not core.global_exists("default") then
|
||||
|
||||
default = {
|
||||
node_sound_stone_defaults = function(table) return {} end,
|
||||
node_sound_wood_defaults = function(table) return {} end,
|
||||
node_sound_metal_defaults = function(table) return {} end,
|
||||
gui_bg = "", gui_bg_img = "", gui_slots = ""
|
||||
}
|
||||
end
|
||||
|
||||
if core.get_modpath("mcl_sounds") then
|
||||
default.node_sound_stone_defaults = mcl_sounds.node_sound_stone_defaults
|
||||
default.node_sound_wood_defaults = mcl_sounds.node_sound_wood_defaults
|
||||
default.node_sound_metal_defaults = mcl_sounds.node_sound_metal_defaults
|
||||
end
|
||||
|
||||
-- modpath, formspec helper and translator
|
||||
|
||||
local MP = core.get_modpath(core.get_current_modname())
|
||||
local F = core.formspec_escape
|
||||
local S = core.get_translator("protector")
|
||||
|
||||
-- global table
|
||||
|
||||
protector = {
|
||||
mod = "redo",
|
||||
max_shares = 12,
|
||||
radius = tonumber(core.settings:get("protector_radius")) or 5
|
||||
}
|
||||
|
||||
-- radius limiter (minetest cannot handle node volume of more than 4096000)
|
||||
|
||||
if protector.radius > 30 then protector.radius = 30 end
|
||||
|
||||
-- playerfactions check
|
||||
|
||||
local factions_available = core.global_exists("factions")
|
||||
|
||||
if factions_available then protector.max_shares = 8 end
|
||||
|
||||
-- localize math
|
||||
|
||||
local math_floor, math_pi = math.floor, math.pi
|
||||
|
||||
-- settings
|
||||
|
||||
local protector_flip = core.settings:get_bool("protector_flip") or false
|
||||
local protector_hurt = tonumber(core.settings:get("protector_hurt")) or 0
|
||||
local protector_spawn = tonumber(core.settings:get("protector_spawn")
|
||||
or core.settings:get("protector_pvp_spawn")) or 0
|
||||
local protector_show = tonumber(core.settings:get("protector_show_interval")) or 5
|
||||
local protector_recipe = core.settings:get_bool("protector_recipe") ~= false
|
||||
local protector_msg = core.settings:get_bool("protector_msg") ~= false
|
||||
|
||||
-- get static spawn position
|
||||
|
||||
local statspawn = core.string_to_pos(core.settings:get("static_spawnpoint"))
|
||||
or {x = 0, y = 2, z = 0}
|
||||
|
||||
-- return list of members as a table
|
||||
|
||||
local function get_member_list(meta)
|
||||
|
||||
return meta:get_string("members"):split(" ")
|
||||
end
|
||||
|
||||
-- write member list table in protector meta as string
|
||||
|
||||
local function set_member_list(meta, list)
|
||||
|
||||
meta:set_string("members", table.concat(list, " "))
|
||||
end
|
||||
|
||||
-- check for owner name
|
||||
|
||||
local function is_owner(meta, name)
|
||||
|
||||
return name == meta:get_string("owner")
|
||||
end
|
||||
|
||||
-- check for member name
|
||||
|
||||
local function is_member(meta, name)
|
||||
|
||||
if factions_available and meta:get_int("faction_members") == 1 then
|
||||
|
||||
if factions.version == nil then
|
||||
|
||||
-- backward compatibility
|
||||
if factions.get_player_faction(name) ~= nil
|
||||
and factions.get_player_faction(meta:get_string("owner")) ==
|
||||
factions.get_player_faction(name) then
|
||||
return true
|
||||
end
|
||||
else
|
||||
-- is member if player and owner share at least one faction
|
||||
local player_factions = factions.get_player_factions(name)
|
||||
local owner = meta:get_string("owner")
|
||||
|
||||
if player_factions ~= nil and player_factions ~= false then
|
||||
|
||||
for _, f in ipairs(player_factions) do
|
||||
|
||||
if factions.player_is_in_faction(f, owner) then return true end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, n in pairs(get_member_list(meta)) do
|
||||
|
||||
if n == name then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- add player name to table as member
|
||||
|
||||
local function add_member(meta, name)
|
||||
|
||||
-- Validate player name for MT compliance
|
||||
if name ~= string.match(name, "[%w_-]+") then return end
|
||||
|
||||
-- Constant (20) defined by player.h
|
||||
if name:len() > 25 then return end
|
||||
|
||||
-- does name already exist?
|
||||
if is_owner(meta, name) or is_member(meta, name) then return end
|
||||
|
||||
local list = get_member_list(meta)
|
||||
|
||||
if #list >= protector.max_shares then return end
|
||||
|
||||
table.insert(list, name)
|
||||
|
||||
set_member_list(meta, list)
|
||||
end
|
||||
|
||||
-- remove player name from table
|
||||
|
||||
local function del_member(meta, name)
|
||||
|
||||
local list = get_member_list(meta)
|
||||
|
||||
for i, n in pairs(list) do
|
||||
|
||||
if n == name then
|
||||
table.remove(list, i) ; break
|
||||
end
|
||||
end
|
||||
|
||||
set_member_list(meta, list)
|
||||
end
|
||||
|
||||
-- protector interface
|
||||
|
||||
local function protector_formspec(meta)
|
||||
|
||||
local formspec = "size[8,7]"
|
||||
.. default.gui_bg
|
||||
.. default.gui_bg_img
|
||||
.. "label[2.5,0;" .. F(S("-- Protector interface --")) .. "]"
|
||||
.. "label[0,1;" .. F(S("PUNCH node to show protected area")) .. "]"
|
||||
.. "label[0,2;" .. F(S("Members:")) .. "]"
|
||||
.. "button_exit[2.5,6.2;3,0.5;close_me;" .. F(S("Close")) .. "]"
|
||||
.. "field_close_on_enter[protector_add_member;false]"
|
||||
|
||||
local members = get_member_list(meta)
|
||||
local i = 0
|
||||
local checkbox_faction = false
|
||||
|
||||
-- Display the checkbox only if the owner is member of at least 1 faction
|
||||
if factions_available then
|
||||
|
||||
if factions.version == nil then
|
||||
|
||||
-- backward compatibility
|
||||
if factions.get_player_faction(meta:get_string("owner")) then
|
||||
checkbox_faction = true
|
||||
end
|
||||
else
|
||||
local player_factions = factions.get_player_factions(meta:get_string("owner"))
|
||||
|
||||
if player_factions ~= nil and type(player_factions) == "table"
|
||||
and #player_factions >= 1 then
|
||||
checkbox_faction = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if checkbox_faction then
|
||||
|
||||
formspec = formspec .. "checkbox[0,5;faction_members;"
|
||||
.. F(S("Allow faction access"))
|
||||
.. ";" .. (meta:get_int("faction_members") == 1 and
|
||||
"true" or "false") .. "]"
|
||||
end
|
||||
|
||||
for n = 1, #members do
|
||||
|
||||
if i < protector.max_shares then
|
||||
|
||||
-- show username
|
||||
formspec = formspec .. "button[" .. (i % 4 * 2)
|
||||
.. "," .. math_floor(i / 4 + 3)
|
||||
.. ";1.5,.5;protector_member;" .. F(members[n]) .. "]"
|
||||
|
||||
-- username remove button
|
||||
.. "button[" .. (i % 4 * 2 + 1.25) .. ","
|
||||
.. math_floor(i / 4 + 3)
|
||||
.. ";.75,.5;protector_del_member_" .. F(members[n]) .. ";X]"
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if i < protector.max_shares then
|
||||
|
||||
-- user name entry field
|
||||
formspec = formspec .. "field[" .. (i % 4 * 2 + 1 / 3) .. ","
|
||||
.. (math_floor(i / 4 + 3) + 1 / 3)
|
||||
.. ";1.433,.5;protector_add_member;;]"
|
||||
|
||||
-- username add button
|
||||
.."button[" .. (i % 4 * 2 + 1.25) .. ","
|
||||
.. math_floor(i / 4 + 3) .. ";.75,.5;protector_submit;+]"
|
||||
end
|
||||
|
||||
return formspec
|
||||
end
|
||||
|
||||
-- check if pos is inside a protected spawn area
|
||||
|
||||
local function inside_spawn(pos, radius)
|
||||
|
||||
if protector_spawn <= 0 then return false end
|
||||
|
||||
if pos.x < statspawn.x + radius and pos.x > statspawn.x - radius
|
||||
and pos.y < statspawn.y + radius and pos.y > statspawn.y - radius
|
||||
and pos.z < statspawn.z + radius and pos.z > statspawn.z - radius then
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- show protection message if enabled
|
||||
|
||||
local function show_msg(player_name, msg)
|
||||
|
||||
-- if messages disabled or no player name provided
|
||||
if protector_msg == false or not player_name or player_name == "" then return end
|
||||
|
||||
core.chat_send_player(player_name, msg)
|
||||
end
|
||||
|
||||
-- Infolevel:
|
||||
-- 0 for no info
|
||||
-- 1 for "This area is owned by <owner> !" if you can't dig
|
||||
-- 2 for "This area is owned by <owner>.
|
||||
-- 3 for checking protector overlaps
|
||||
|
||||
function protector.can_dig(r, pos, digger, onlyowner, infolevel)
|
||||
|
||||
if not digger or not pos then return false end
|
||||
|
||||
-- protector_bypass privileged users can override protection
|
||||
if infolevel == 1
|
||||
and core.check_player_privs(digger, {protection_bypass = true}) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- infolevel 3 is only used to bypass priv check, change to 1 now
|
||||
if infolevel == 3 then infolevel = 1 end
|
||||
|
||||
-- is spawn area protected ?
|
||||
if inside_spawn(pos, protector_spawn) then
|
||||
|
||||
show_msg(digger, S("Spawn @1 has been protected up to a @2 block radius.",
|
||||
core.pos_to_string(statspawn), protector_spawn))
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- find the protector nodes
|
||||
local pos = core.find_nodes_in_area(
|
||||
{x = pos.x - r, y = pos.y - r, z = pos.z - r},
|
||||
{x = pos.x + r, y = pos.y + r, z = pos.z + r},
|
||||
{"protector:protect", "protector:protect2", "protector:protect_hidden"})
|
||||
|
||||
local meta, owner, members
|
||||
|
||||
for n = 1, #pos do
|
||||
|
||||
meta = core.get_meta(pos[n])
|
||||
owner = meta:get_string("owner") or ""
|
||||
members = meta:get_string("members") or ""
|
||||
|
||||
-- node change and digger isn't owner
|
||||
if infolevel == 1 and owner ~= digger then
|
||||
|
||||
-- and you aren't on the member list
|
||||
if onlyowner or not is_member(meta, digger) then
|
||||
|
||||
show_msg(digger, S("This area is owned by @1", owner) .. "!")
|
||||
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- when using protector as tool, show protector information
|
||||
if infolevel == 2 then
|
||||
|
||||
core.chat_send_player(digger,
|
||||
S("This area is owned by @1", owner) .. ".")
|
||||
|
||||
core.chat_send_player(digger,
|
||||
S("Protection located at: @1", core.pos_to_string(pos[n])))
|
||||
|
||||
if members ~= "" then
|
||||
core.chat_send_player(digger, S("Members: @1.", members))
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- show when you can build on unprotected area
|
||||
if infolevel == 2 then
|
||||
|
||||
if #pos < 1 then
|
||||
core.chat_send_player(digger, S("This area is not protected."))
|
||||
end
|
||||
|
||||
core.chat_send_player(digger, S("You can build here."))
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- add protector hurt and flip to protection violation function
|
||||
|
||||
core.register_on_protection_violation(function(pos, name)
|
||||
|
||||
local player = core.get_player_by_name(name)
|
||||
|
||||
if player and player:is_player() then
|
||||
|
||||
-- hurt player if protection violated
|
||||
if protector_hurt > 0 and player:get_hp() > 0 then
|
||||
|
||||
-- This delay fixes item duplication bug (thanks luk3yx)
|
||||
core.after(0.1, function(player)
|
||||
player:set_hp(player:get_hp() - protector_hurt)
|
||||
end, player)
|
||||
end
|
||||
|
||||
-- flip player when protection violated
|
||||
if protector_flip then
|
||||
|
||||
-- yaw + 180°
|
||||
local yaw = player:get_look_horizontal() + math_pi
|
||||
|
||||
if yaw > 2 * math_pi then
|
||||
yaw = yaw - 2 * math_pi
|
||||
end
|
||||
|
||||
player:set_look_horizontal(yaw)
|
||||
|
||||
-- invert pitch
|
||||
player:set_look_vertical(-player:get_look_vertical())
|
||||
|
||||
-- if digging below player, move up to avoid falling through hole
|
||||
local pla_pos = player:get_pos()
|
||||
|
||||
if pos.y < pla_pos.y then
|
||||
player:set_pos({x = pla_pos.x, y = pla_pos.y + 0.8, z = pla_pos.z})
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- backup old is_protected function
|
||||
|
||||
local old_is_protected = core.is_protected
|
||||
|
||||
-- check for protected area, return true if protected and digger isn't on list
|
||||
|
||||
function core.is_protected(pos, digger)
|
||||
|
||||
digger = digger or "" -- nil check
|
||||
|
||||
-- is area protected against digger?
|
||||
if not protector.can_dig(protector.radius, pos, digger, false, 1) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- otherwise can dig or place
|
||||
return old_is_protected(pos, digger)
|
||||
end
|
||||
|
||||
-- make sure protection block doesn't overlap another protector's area
|
||||
|
||||
local function check_overlap(itemstack, placer, pointed_thing)
|
||||
|
||||
if pointed_thing.type ~= "node" then return itemstack end
|
||||
|
||||
local pos = pointed_thing.above
|
||||
local name = placer:get_player_name()
|
||||
|
||||
-- make sure protector doesn't overlap onto protected spawn area
|
||||
if inside_spawn(pos, protector_spawn + protector.radius) then
|
||||
|
||||
core.chat_send_player(name,
|
||||
S("Spawn @1 has been protected up to a @2 block radius.",
|
||||
core.pos_to_string(statspawn), protector_spawn))
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- make sure protector doesn't overlap any other player's area
|
||||
if not protector.can_dig(protector.radius * 2, pos, name, true, 3) then
|
||||
|
||||
core.chat_send_player(name,
|
||||
S("Overlaps into above players protected area"))
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
return core.item_place(itemstack, placer, pointed_thing)
|
||||
end
|
||||
|
||||
-- remove protector display entities
|
||||
|
||||
local function del_display(pos)
|
||||
|
||||
local objects = core.get_objects_inside_radius(pos, 0.5)
|
||||
|
||||
for _, v in ipairs(objects) do
|
||||
|
||||
if v and v:get_luaentity() and v:get_luaentity().name == "protector:display" then
|
||||
v:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- temporary position store
|
||||
|
||||
local player_pos = {}
|
||||
|
||||
-- stone texture
|
||||
|
||||
local stone_tex = "default_stone.png"
|
||||
|
||||
if core.get_modpath("nc_terrain") then
|
||||
stone_tex = "nc_terrain_stone.png"
|
||||
end
|
||||
|
||||
-- protector default
|
||||
|
||||
local def = {
|
||||
|
||||
description = S("Protection Block") .. " (" .. S("USE for area check") .. ")",
|
||||
tiles = {
|
||||
stone_tex .. "^protector_overlay.png",
|
||||
stone_tex .. "^protector_overlay.png",
|
||||
stone_tex .. "^protector_overlay.png^protector_logo.png"
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {type = "fixed", fixed = {{-0.499 ,-0.499, -0.499, 0.499, 0.499, 0.499}}},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
groups = {dig_immediate = 2, unbreakable = 1},
|
||||
is_ground_content = false,
|
||||
paramtype = "light",
|
||||
light_source = 4,
|
||||
walkable = true,
|
||||
|
||||
on_place = check_overlap,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
|
||||
local meta = core.get_meta(pos)
|
||||
|
||||
meta:set_string("owner", placer:get_player_name() or "")
|
||||
meta:set_string("members", "")
|
||||
meta:set_string("infotext",
|
||||
S("Protection (owned by @1)", meta:get_string("owner")))
|
||||
end,
|
||||
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
|
||||
if pointed_thing.type ~= "node" then return end
|
||||
|
||||
protector.can_dig(protector.radius, pointed_thing.under,
|
||||
user:get_player_name(), false, 2)
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker, itemstack)
|
||||
|
||||
local meta = core.get_meta(pos)
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
if meta and protector.can_dig(1, pos, name, true, 1) then
|
||||
|
||||
player_pos[name] = pos
|
||||
|
||||
core.show_formspec(name, "protector:node", protector_formspec(meta))
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = function(pos, node, puncher)
|
||||
|
||||
if core.is_protected(pos, puncher:get_player_name()) then return end
|
||||
|
||||
core.add_entity(pos, "protector:display")
|
||||
end,
|
||||
|
||||
can_dig = function(pos, player)
|
||||
|
||||
return player and protector.can_dig(1, pos, player:get_player_name(), true, 1)
|
||||
end,
|
||||
|
||||
on_blast = function() end,
|
||||
|
||||
after_destruct = del_display
|
||||
}
|
||||
|
||||
-- protection node
|
||||
|
||||
core.register_node("protector:protect", table.copy(def))
|
||||
|
||||
-- default recipe and alternative for MineClone2
|
||||
|
||||
if protector_recipe then
|
||||
|
||||
local item_gold = "default:gold_ingot"
|
||||
local item_stone = "default:stone"
|
||||
|
||||
if core.get_modpath("mcl_core") then
|
||||
item_gold = "mcl_core:gold_ingot"
|
||||
item_stone = "mcl_core:stone"
|
||||
end
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:protect",
|
||||
recipe = {
|
||||
{item_stone, item_stone, item_stone},
|
||||
{item_stone, item_gold, item_stone},
|
||||
{item_stone, item_stone, item_stone}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
-- protection logo
|
||||
|
||||
def.description = S("Protection Logo") .. " (" .. S("USE for area check") .. ")"
|
||||
def.tiles = {"protector_logo.png"}
|
||||
def.wield_image = "protector_logo.png"
|
||||
def.inventory_image = "protector_logo.png"
|
||||
def.use_texture_alpha = "clip"
|
||||
def.paramtype2 = "wallmounted"
|
||||
def.legacy_wallmounted = true
|
||||
def.sunlight_propagates = true
|
||||
def.node_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.375, 0.4375, -0.5, 0.375, 0.5, 0.5},
|
||||
wall_bottom = {-0.375, -0.5, -0.5, 0.375, -0.4375, 0.5},
|
||||
wall_side = {-0.5, -0.5, -0.375, -0.4375, 0.5, 0.375}
|
||||
}
|
||||
def.selection_box = {type = "wallmounted"}
|
||||
|
||||
core.register_node("protector:protect2", table.copy(def))
|
||||
|
||||
-- recipes to switch between protectors
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:protect", recipe = {{"protector:protect2"}}
|
||||
})
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:protect2", recipe = {{"protector:protect"}}
|
||||
})
|
||||
|
||||
-- check formspec buttons or when name entered
|
||||
|
||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
|
||||
if formname ~= "protector:node" then return end
|
||||
|
||||
local name = player:get_player_name()
|
||||
local pos = player_pos[name]
|
||||
|
||||
if not name or not pos then return end
|
||||
|
||||
local add_member_input = fields.protector_add_member
|
||||
|
||||
-- reset formspec until close button pressed
|
||||
if (fields.close_me or fields.quit)
|
||||
and (not add_member_input or add_member_input == "") then
|
||||
player_pos[name] = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- only owner can add names
|
||||
if not protector.can_dig(1, pos, player:get_player_name(), true, 1) then
|
||||
return
|
||||
end
|
||||
|
||||
-- are we adding member to a protection node ? (csm protection)
|
||||
local nod = core.get_node(pos).name
|
||||
|
||||
if nod ~= "protector:protect" and nod ~= "protector:protect2" then
|
||||
player_pos[name] = nil
|
||||
return
|
||||
end
|
||||
|
||||
local meta = core.get_meta(pos) ; if not meta then return end
|
||||
|
||||
-- add faction members
|
||||
if factions_available and fields.faction_members ~= nil then
|
||||
meta:set_int("faction_members", fields.faction_members == "true" and 1 or 0)
|
||||
end
|
||||
|
||||
-- add member [+]
|
||||
if add_member_input then
|
||||
|
||||
for _, i in pairs(add_member_input:split(" ")) do
|
||||
add_member(meta, i)
|
||||
end
|
||||
end
|
||||
|
||||
-- remove member [x]
|
||||
for field, value in pairs(fields) do
|
||||
|
||||
if string.sub(field, 0,
|
||||
string.len("protector_del_member_")) == "protector_del_member_" then
|
||||
|
||||
del_member(meta, string.sub(field,string.len("protector_del_member_") + 1))
|
||||
end
|
||||
end
|
||||
|
||||
core.show_formspec(name, formname, protector_formspec(meta))
|
||||
end)
|
||||
|
||||
-- display entity shown when protector node is punched
|
||||
|
||||
core.register_entity("protector:display", {
|
||||
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collisionbox = {0, 0, 0, 0, 0, 0},
|
||||
visual = "wielditem",
|
||||
-- wielditem seems to be scaled to 1.5 times original node size
|
||||
visual_size = {x = 0.67, y = 0.67},
|
||||
textures = {"protector:display_node"},
|
||||
glow = 10
|
||||
},
|
||||
|
||||
timer = 0,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
|
||||
self.timer = self.timer + dtime
|
||||
|
||||
-- remove after set number of seconds
|
||||
if self.timer > protector_show then self.object:remove() end
|
||||
end
|
||||
})
|
||||
|
||||
-- Display-zone node, Do NOT place the display as a node,
|
||||
-- it is made to be used as an entity (see above)
|
||||
|
||||
local r = protector.radius
|
||||
|
||||
core.register_node("protector:display_node", {
|
||||
tiles = {"protector_display.png"},
|
||||
use_texture_alpha = "clip",
|
||||
walkable = false,
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-(r+.55), -(r+.55), -(r+.55), -(r+.45), (r+.55), (r+.55)}, -- sides
|
||||
{-(r+.55), -(r+.55), (r+.45), (r+.55), (r+.55), (r+.55)},
|
||||
{(r+.45), -(r+.55), -(r+.55), (r+.55), (r+.55), (r+.55)},
|
||||
{-(r+.55), -(r+.55), -(r+.55), (r+.55), (r+.55), -(r+.45)},
|
||||
{-(r+.55), (r+.45), -(r+.55), (r+.55), (r+.55), (r+.55)}, -- top
|
||||
{-(r+.55), -(r+.55), -(r+.55), (r+.55), -(r+.45), (r+.55)}, -- bottom
|
||||
{-.55,-.55,-.55, .55,.55,.55} -- middle (surrounding protector)
|
||||
}
|
||||
},
|
||||
selection_box = {type = "regular"},
|
||||
paramtype = "light",
|
||||
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
||||
drop = "",
|
||||
on_blast = function() end
|
||||
})
|
||||
|
||||
-- load mod sections
|
||||
|
||||
dofile(MP .. "/doors.lua")
|
||||
dofile(MP .. "/chest.lua")
|
||||
dofile(MP .. "/pvp.lua")
|
||||
dofile(MP .. "/admin.lua")
|
||||
dofile(MP .. "/tool.lua")
|
||||
dofile(MP .. "/hud.lua")
|
||||
|
||||
if core.get_modpath("lucky_block") then
|
||||
dofile(MP .. "/lucky_block.lua")
|
||||
end
|
||||
|
||||
-- stop mesecon pistons from pushing protectors
|
||||
|
||||
if core.get_modpath("mesecons_mvps") then
|
||||
mesecon.register_mvps_stopper("protector:protect")
|
||||
mesecon.register_mvps_stopper("protector:protect2")
|
||||
mesecon.register_mvps_stopper("protector:protect_hidden")
|
||||
mesecon.register_mvps_stopper("protector:chest")
|
||||
end
|
||||
|
||||
-- player command to add member names to local protection
|
||||
|
||||
core.register_chatcommand("protector_add_member", {
|
||||
params = "",
|
||||
description = S("Add member names to local protection"),
|
||||
privs = {interact = true},
|
||||
|
||||
func = function(name, param)
|
||||
|
||||
if param == "" then return end
|
||||
|
||||
local to_add = param:split(" ")
|
||||
local player = core.get_player_by_name(name)
|
||||
local pos = player:get_pos()
|
||||
|
||||
-- find the protector nodes
|
||||
local pos = core.find_nodes_in_area(
|
||||
{x = pos.x - r, y = pos.y - r, z = pos.z - r},
|
||||
{x = pos.x + r, y = pos.y + r, z = pos.z + r},
|
||||
{"protector:protect", "protector:protect2", "protector:protect_hidden"})
|
||||
|
||||
local meta, owner
|
||||
|
||||
for n = 1, #pos do
|
||||
|
||||
meta = core.get_meta(pos[n])
|
||||
owner = meta:get_string("owner") or ""
|
||||
|
||||
if owner == name
|
||||
or core.check_player_privs(name, {protection_bypass = true}) then
|
||||
|
||||
for m = 1, #to_add do
|
||||
add_member(meta, to_add[m])
|
||||
end
|
||||
|
||||
core.add_entity(pos[n], "protector:display")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- player command to remove member names from local protection
|
||||
|
||||
core.register_chatcommand("protector_del_member", {
|
||||
params = "",
|
||||
description = S("Remove member names from local protection"),
|
||||
privs = {interact = true},
|
||||
|
||||
func = function(name, param)
|
||||
|
||||
if param == "" then return end
|
||||
|
||||
local to_del = param:split(" ")
|
||||
local player = core.get_player_by_name(name)
|
||||
local pos = player:get_pos()
|
||||
|
||||
-- find the protector nodes
|
||||
local pos = core.find_nodes_in_area(
|
||||
{x = pos.x - r, y = pos.y - r, z = pos.z - r},
|
||||
{x = pos.x + r, y = pos.y + r, z = pos.z + r},
|
||||
{"protector:protect", "protector:protect2", "protector:protect_hidden"})
|
||||
|
||||
local meta, owner
|
||||
|
||||
for n = 1, #pos do
|
||||
|
||||
meta = core.get_meta(pos[n])
|
||||
owner = meta:get_string("owner") or ""
|
||||
|
||||
if owner == name
|
||||
or core.check_player_privs(name, {protection_bypass = true}) then
|
||||
|
||||
for m = 1, #to_del do
|
||||
del_member(meta, to_del[m])
|
||||
end
|
||||
|
||||
core.add_entity(pos[n], "protector:display")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
print ("[MOD] Protector Redo loaded")
|
33
mods/protector/license.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2025 TenPlus1
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
Original doors mod code (WTFPL license)
|
||||
|
||||
Textures by TenPlus1 (CC0) unless mentioned below
|
||||
|
||||
Textures from original Minetest doors mod (CC-BY-SA 3.0)
|
||||
doors_*.png
|
||||
..default_chest*.png
|
||||
|
||||
Textures by Sirrobzeroone (CC0)
|
||||
protector_tool.png
|
57
mods/protector/locale/protector.de.tr
Normal file
|
@ -0,0 +1,57 @@
|
|||
# textdomain: protector
|
||||
# author: Xanthin and CodeXP
|
||||
# last update: 2020/Jul/12
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=Entferne Störschützer von bestimmten Namen in der Nähe von Spielern (trenne Namen durch Leerzeichen)
|
||||
<names list>=<Namensliste der Spieler>
|
||||
Replace Protector Owner with name provided=Ersetze Besitzer der Störschützer mit neuem Besitzer
|
||||
<owner name> <name to replace with>=<Name des Besitzers> <Name des neuen Besitzers>
|
||||
Replacing Protector name '@1' with '@2'=Ersetze Besitzer der Störschützer von '@1' mit '@2'
|
||||
Show protected areas of your nearby protectors=Zeige geschützte Bereiche der Störschützer in der Nähe
|
||||
Protector Names to remove: @1=Störschutznamen zum Entfernen: @1
|
||||
Name List Reset=Namensliste zurückgesetzt
|
||||
Invalid player name!=
|
||||
Player name too long=
|
||||
Player not found.=
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=Geschützte Holztür
|
||||
Protected Steel Door=Geschützte Stahltür
|
||||
Protected Trapdoor=Geschützte Falltür
|
||||
Protected Steel Trapdoor=Geschützte Stahlfalltür
|
||||
Protected Chest=Geschützte Truhe
|
||||
To Chest=Zur Truhe
|
||||
To Inventory=Zum Inventar
|
||||
Protected Chest (@1)=Geschützte Truhe (@1)
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=-- Störschutz-Interface --
|
||||
PUNCH node to show protected area=SCHLAGE Node, um geschützten Bereich anzuzeigen oder
|
||||
USE for area check=BENUTZE für Bereichsprüfung
|
||||
Members:=Mitglieder:
|
||||
Close=Schließen
|
||||
Protection located at: @1=Störschutz befindet sich bei: @1
|
||||
Members: @1.=Mitglieder: @1.
|
||||
Allow faction access=
|
||||
This area is not protected.=Dieser Bereich ist nicht geschützt.
|
||||
You can build here.=Du kannst hier bauen.
|
||||
Overlaps into above players protected area=Überlappung im geschützen Bereich eines Spielers
|
||||
Protection Block=Störschutzblock
|
||||
Protection (owned by @1)=Störschutz (gehört @1)
|
||||
Protection Logo=Störschutzlogo
|
||||
[MOD] Protector Redo loaded=[MOD] Protector Redo geladen
|
||||
Spawn @1 has been protected up to a @2 block radius.=Spawn @1 ist geschützt mit einem Radius von @2 Blöcke.
|
||||
This area is owned by @1=Dieser Bereich gehört @1
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=Besitzer: @1
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=Störschutz Platzier-Werkzeug (stehe neben Störschutz, schaue in die gewünschte Richtung und anwenden)
|
||||
Protector already in place!=Störschutz is bereits platziert!
|
||||
No protectors available to place!=Keine Störschützer mehr im Inventar!
|
||||
"Protector placed at @1"=Störschutz befindet sich bei: @1
|
||||
Out of bounds!=
|
||||
Cannot place protector, already protected at @1=
|
||||
Cannot place protector, container at @1=
|
57
mods/protector/locale/protector.es.tr
Normal file
|
@ -0,0 +1,57 @@
|
|||
# textdomain: protector
|
||||
# author: universales
|
||||
# last update: 2020-02-27
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=Eliminar protectores alrededor de los jugadores (nombres separados con espacios)
|
||||
<names list>=<Lista de nombres>
|
||||
Replace Protector Owner with name provided=Reemplace el propietario del protector con el nombre proporcionado
|
||||
<owner name> <name to replace with>=<Nombre del propietario> <Nombre del nuevo propietario>
|
||||
Replacing Protector name '@1' with '@2'=Reemplazando el nombre del protector '@1' a '@2'
|
||||
Show protected areas of your nearby protectors=Mostrar áreas protegidas de sus protectores cercanos
|
||||
Protector Names to remove: @1=Nombres de protectores para eliminar: @1
|
||||
Name List Reset=Restablecer lista de nombres
|
||||
Invalid player name!=
|
||||
Player name too long=
|
||||
Player not found.=
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=Puerta de madera protegida
|
||||
Protected Steel Door=Puerta de hierro protegida
|
||||
Protected Trapdoor=Trampilla Protegida
|
||||
Protected Steel Trapdoor=Trampilla de hierro protegida
|
||||
Protected Chest=Cofre protegido
|
||||
To Chest=Al cofre
|
||||
To Inventory=Al inventario
|
||||
Protected Chest (@1)=Cofre protegido (@1)
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=-- Interfaz del protector --
|
||||
PUNCH node to show protected area=nodo de perforación para mostrar el área protegida
|
||||
USE for area check=Usar para chequeo del área
|
||||
Members:=Miembros:
|
||||
Close=Cerrar
|
||||
Protection located at: @1=Protección ubicada en: @1
|
||||
Members: @1.=Miembros: @1.
|
||||
Allow faction access=
|
||||
This area is not protected.=Esta área no está protegida.
|
||||
You can build here.=Puedes construir aquí.
|
||||
Overlaps into above players protected area=Se superpone en el área protegida de los jugadores anteriores
|
||||
Protection Block=Bloque de protección
|
||||
Protection (owned by @1)=Protegido (Propiedad de @1)
|
||||
Protection Logo=Logotipo de la protección
|
||||
[MOD] Protector Redo loaded=[MOD] Protector recargado
|
||||
Spawn @1 has been protected up to a @2 block radius.=Spawn @1 ha sido protegido hasta un radio de bloque @2.
|
||||
This area is owned by @1=Esta área es propiedad de @1
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=Propietario: @1
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=Herramienta de colocación del protector (pararse cerca del protector, dirección de la cara y uso)
|
||||
Protector already in place!=¡El protector ya está en este lugar!
|
||||
No protectors available to place!=¡No hay protectores disponibles para colocar!
|
||||
Protector placed at @1=Protector colocado en @1
|
||||
Out of bounds!=
|
||||
Cannot place protector, already protected at @1=
|
||||
Cannot place protector, container at @1=
|
57
mods/protector/locale/protector.fr.tr
Normal file
|
@ -0,0 +1,57 @@
|
|||
# textdomain: protector
|
||||
# author: CodeXP and TenPlus1
|
||||
# last update: 2020/Jul/12
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=Retirer les protecteurs près des joueurs avec les noms fournis (noms séparés avec des espaces)
|
||||
<names list>=<liste de noms>
|
||||
Replace Protector Owner with name provided=Remplacer le propriétaire du protecteur par le nom fourni
|
||||
<owner name> <name to replace with>=<nom du propriétaire> <nom à remplacer>
|
||||
Replacing Protector name '@1' with '@2'=
|
||||
Show protected areas of your nearby protectors=Affichez les zones protégées de vos protecteurs à proximité
|
||||
Protector Names to remove: @1=Noms de protecteurs à supprimer: @1
|
||||
Name List Reset=Liste de noms réinitialiser
|
||||
Invalid player name!=
|
||||
Player name too long=
|
||||
Player not found.=
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=Porte en bois protégée
|
||||
Protected Steel Door=Porte en acier protégée
|
||||
Protected Trapdoor=Trappe protégé
|
||||
Protected Steel Trapdoor=Trap en acier protégé
|
||||
Protected Chest=Coffre protégé
|
||||
To Chest=Vers le coffre
|
||||
To Inventory=Vers l'inventaire
|
||||
Protected Chest (@1)=Coffre protégé (@1)
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=-- Interface Protector --
|
||||
PUNCH node to show protected area=TAPÉ le bloc pour afficher la zone protégée
|
||||
USE for area check=UTILISER pour vérifier la zone
|
||||
Members:=Membres:
|
||||
Close=Fermer
|
||||
Protection located at: @1=Protection située à: @1
|
||||
Members: @1.=Membres: @1.
|
||||
Allow faction access=
|
||||
This area is not protected.=msgstr "Cette zone n'est pas protégée.
|
||||
You can build here.=Vous pouvez construire ici.
|
||||
Overlaps into above players protected area=Vous chevauché une zone protégé.
|
||||
Protection Block=Bloc de protection
|
||||
Protection (owned by @1)=Protection (détenue par @1)
|
||||
Protection Logo=Logo de protection
|
||||
[MOD] Protector Redo loaded=[MOD] Protector Redo chargé
|
||||
Spawn @1 has been protected up to a @2 block radius.=
|
||||
This area is owned by @1=Cette zone appartient à @1!
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=Propriétaire: @1
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=Outil de placement du protecteur (se tenir près du protecteur, direction du visage et utilisation)
|
||||
Protector already in place!=Protecteur déjà en place!
|
||||
No protectors available to place!=Aucun protecteur disponible à placer!
|
||||
Protector placed at @1=Protection située à: @1
|
||||
Out of bounds!=
|
||||
Cannot place protector, already protected at @1=
|
||||
Cannot place protector, container at @1=
|
57
mods/protector/locale/protector.it.tr
Normal file
|
@ -0,0 +1,57 @@
|
|||
# textdomain: protector
|
||||
# author: Xanthin and CodeXP
|
||||
# last update: 2018/Jul/10
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=Elimina i protettori attorno ai giocatori (separa i nomi con gli spazi)
|
||||
<names list>=<elenco nomi>
|
||||
Replace Protector Owner with name provided=Sostituisci il proprietario del protettore col nome fornito
|
||||
<owner name> <name to replace with>=<nome proprietario> <nome con cui sostituirlo>
|
||||
Replacing Protector name '@1' with '@2'=Sostituzione del nome del protettore '@1' con '@2'
|
||||
Show protected areas of your nearby protectors=Mostra le aree protette dei protettori vicino a te
|
||||
Protector Names to remove: @1=Nomi dei protettori da eliminare: @1
|
||||
Name List Reset=Azzera l'elenco dei nomi
|
||||
Invalid player name!=
|
||||
Player name too long=
|
||||
Player not found.=
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=Porta di legno protetta
|
||||
Protected Steel Door=Porta d'acciaio protetta
|
||||
Protected Trapdoor=Botola protetta
|
||||
Protected Steel Trapdoor=Botola d'acciaio protetta
|
||||
Protected Chest=Baule protetto
|
||||
To Chest=Al baule
|
||||
To Inventory=All'inventario
|
||||
Protected Chest (@1)=Baule protetto (@1)
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=-- Interfaccia protettore --
|
||||
PUNCH node to show protected area=COLPISCI il nodo per mostrare l'area protetta
|
||||
USE for area check=USA per controllare l'area
|
||||
Members:=Membri:
|
||||
Close=Chiudi
|
||||
Protection located at: @1=Protezione collocata a: @1
|
||||
Members: @1.=Membri: @1.
|
||||
Allow faction access=
|
||||
This area is not protected.=Quest'area non è protetta.
|
||||
You can build here.=Qui puoi costruire.
|
||||
Overlaps into above players protected area=Si sovrappone ad un'area sovrastante protetta dai giocatori
|
||||
Protection Block=Blocco di protezione
|
||||
Protection (owned by @1)=Protezione (di proprietà di @1)
|
||||
Protection Logo=Logo di protezione
|
||||
[MOD] Protector Redo loaded=[MOD] Protector Redo caricato
|
||||
Spawn @1 has been protected up to a @2 block radius.=Lo spawn @1 è stato protetto fino a un raggio di @2 blocchi.
|
||||
This area is owned by @1=Quest'area è di proprietà di @1
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=Proprietario: @1
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=Strumento di posizionamento protettore (stai vicino al protettore, guarda la direzione e usa)
|
||||
Protector already in place!=Protettore già presente!
|
||||
No protectors available to place!=Nessun protettore disponibile da posizionare!
|
||||
Protector placed at @1=Protettore posizionato a @1
|
||||
Out of bounds!=
|
||||
Cannot place protector, already protected at @1=
|
||||
Cannot place protector, container at @1=
|
62
mods/protector/locale/protector.ru.tr
Normal file
|
@ -0,0 +1,62 @@
|
|||
# textdomain: protector
|
||||
# author: SkyBuilder1717
|
||||
# last update: 2025/Jan/27
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=Удалить Защитников вокруг игроков (отделяйте имена с помощью пробела)
|
||||
<names list>=<игроки>
|
||||
Replace Protector Owner with name provided=Заменить Владельца Защитника с доставленным именем
|
||||
<owner name> <name to replace with>=<владелец> <новый владелец>
|
||||
Replacing Protector name '@1' with '@2'=Замена Имени Защитника '@1' с '@2'
|
||||
Show protected areas of your nearby protectors=Показать защищённые зоны Защитниками с вами неподалёку
|
||||
Protector Names to remove: @1=Имена Защитников чтобы удалить: @1
|
||||
Name List Reset=Сброс Список Имён
|
||||
Invalid player name!=Неправильное имя игрока!
|
||||
Player name too long=Имя игрока слишком длинное
|
||||
Player not found.=Игрок не найден.
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=Защищённая Деревянная Дверь
|
||||
Protected Steel Door=Защищённая Стальная Дверь
|
||||
Protected Trapdoor=Защищённый Люк
|
||||
Protected Steel Trapdoor=Защищённый Стальной Люк
|
||||
Protected Chest=Защищённый Сундук
|
||||
To Chest=В Сундук
|
||||
To Inventory=В Инвентарь
|
||||
Protected Chest (@1)=Защищённый Сундук (@1)
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=-- Интерфейс Защитника --
|
||||
PUNCH node to show protected area=УДАРЬТЕ по блоку чтобы показать защищённую зону
|
||||
USE for area check=ИСПОЛЬЗУЙТЕ для проверки зоны
|
||||
Members:=Участники:
|
||||
Close=Закрыть
|
||||
Allow faction access=Разрешить частичный доступ
|
||||
Protection located at: @1=Защитник расположен на: @1
|
||||
Members: @1.=Участники: @1.
|
||||
This area is not protected.=Эта зона не защищена.
|
||||
You can build here.=Вы можете здесь строить.
|
||||
Overlaps into above players protected area=Перекрывает защищенную зону вышеперечисленных игроков
|
||||
Protection Block=Блок Защиты
|
||||
Protection (owned by @1)=Защита (владелец: @1)
|
||||
Protection Logo=Логотип Защиты
|
||||
[MOD] Protector Redo loaded=[MOD] Protector Redo загружен
|
||||
Spawn @1 has been protected up to a @2 block radius.=Спавн @1 был защищён радиусом в блоках @2.
|
||||
This area is owned by @1=Эта зона принадлежит @1.
|
||||
|
||||
### pvp.lua ###
|
||||
[Protector] on_punchplayer called with nil objects=on_punchplayer вызван на нулевом объекте
|
||||
[Protector] pvp_protect not active, update your version of Luanti=[Protector] pvp_protect не активен, обновите версию Luanti
|
||||
[Protector] pvp_protect is disabled=[Protector] pvp_protect выключен
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=Владелец: @1
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=Инструмент Размещения Защитника (встаньте рядом с Защитником, повернитесь к нему и используйте предмет)
|
||||
Protector already in place!=Защитник уже стоит на этом месте!
|
||||
No protectors available to place!=Нет доступных Защитников чтобы поставить!
|
||||
Out of bounds!=За пределами!
|
||||
Protector placed at @1=Защитник размещён на @1
|
||||
Cannot place protector, already protected at @1=Нельзя поставить Защитник, другой Защитник уже на @1
|
||||
Cannot place protector, container at @1=Нельзя поставить Защитник, контейнер на @1
|
57
mods/protector/locale/protector.tr.tr
Normal file
|
@ -0,0 +1,57 @@
|
|||
# textdomain: protector
|
||||
# author: CodeXP and TenPlus1
|
||||
# last update: 2020/Jul/12
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=Ismi verilen oyuncuların yanındaki korumaları kaldır. (İsimleri boşlukla ayır)
|
||||
<names list>=<isim listesi>
|
||||
Replace Protector Owner with name provided=Koruyucu Sahibini belirtilen adla değiştirin
|
||||
<owner name> <name to replace with>=<sahip adı> <değiştirilecek ad>
|
||||
Replacing Protector name '@1' with '@2'='@1' Koruyucu adını '@2' ile değiştirin
|
||||
Show protected areas of your nearby protectors=Yakındaki koruyucuların korunan alanlarını göster
|
||||
Protector Names to remove: @1=Silinecek korumaların isimleri: @1
|
||||
Name List Reset=İsim listesini sıfırla
|
||||
Invalid player name!=
|
||||
Player name too long=
|
||||
Player not found.=
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=Korumalı ahşap kapı
|
||||
Protected Steel Door=Korumalı çelik kapı
|
||||
Protected Trapdoor=Korumalı tuzak kapısı
|
||||
Protected Steel Trapdoor=Korumalı çelik tuzak kapısı
|
||||
Protected Chest=Korumalı sandık
|
||||
To Chest=Sandığa
|
||||
To Inventory=Envantere
|
||||
Protected Chest (@1)=Korumalı sandık (@1)
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=-- Koruyucu arayüz --
|
||||
PUNCH node to show protected area=Korunan alanı göstermek için yumruk
|
||||
USE for area check=Bölge kontrolü için kullan
|
||||
Members:=Üyeler
|
||||
Close=Kapat
|
||||
Protection located at: @1=Korumanın bulunduğu yer @1
|
||||
Members: @1.=Üyeler @1.
|
||||
Allow faction access=
|
||||
This area is not protected.=Bu alan korumalı değildir.
|
||||
You can build here.=Buraya inşaa edebilirsiniz.
|
||||
Overlaps into above players protected area=Yukarıdaki oyuncuların koruma alanı ile çakışıyor
|
||||
Protection Block=Koruma kutusu
|
||||
Protection (owned by @1)=Koruma (@1 sahibidir)
|
||||
Protection Logo=Koruma arması
|
||||
[MOD] Protector Redo loaded=[MOD] Protector Redo yüklendi
|
||||
Spawn @1 has been protected up to a @2 block radius.=Spawn @1, @2 blok yarıçapa kadar korunur.
|
||||
This area is owned by @1=Burasının sahibi @1!
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=Sahip: @1
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=Koruyucu Yerleştirme Aleti (koruyucunun yanında durun, yüz yönü ve kullanım)
|
||||
Protector already in place!=Koruyucu zaten yerinde!
|
||||
No protectors available to place!=Yerleştirilecek koruyucu yok!
|
||||
Protector placed at @1=Korumanın bulunduğu yer @1
|
||||
Out of bounds!=
|
||||
Cannot place protector, already protected at @1=
|
||||
Cannot place protector, container at @1=
|
56
mods/protector/locale/protector.uk.tr
Normal file
|
@ -0,0 +1,56 @@
|
|||
# textdomain: protector
|
||||
|
||||
Protector Redo=Захист
|
||||
Lets players craft special blocks to protect their builds or disable PVP in areas.=Дозволяє гравцям створювати спеціальні блоки для захисту їхніх споруд або вимкнення PVP на певних територіях.
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=Видалити захист поряд із гравцями (перечислити імена, розділяючи пробілами)
|
||||
<names list>=<список імен>
|
||||
Replace Protector Owner with name provided=Замінити власника захисту новим власником
|
||||
<owner name> <name to replace with>=<ім'я власника> <ім'я нового власника>
|
||||
Replacing Protector name '@1' with '@2'=Заміняється власник захисту із '@1' на '@2'
|
||||
Show protected areas of your nearby protectors=Показати найближчі захищені території
|
||||
Protector Names to remove: @1=Імена, які будуть видалені: @1
|
||||
Name List Reset=Очистити список імен
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=Захищені дерев'яні двері
|
||||
Protected Steel Door=Захищені сталеві двері
|
||||
Protected Trapdoor=Захищений дерев'яний люк
|
||||
Protected Steel Trapdoor=Захищений сталевий люк
|
||||
Protected Chest=Захищена скриня
|
||||
To Chest=В скриню
|
||||
To Inventory=В інвентар
|
||||
Protected Chest (@1)=Захищена скриня (@1)
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=-- Налаштування захисту --
|
||||
PUNCH node to show protected area=ВДАРИТИ блок для підсвітки захищеної території
|
||||
USE for area check=ЛКМ для перевірки захищеної території
|
||||
Members:=Учасники:
|
||||
Close=Закрити
|
||||
Protection located at: @1=Захист знаходиться на координатах: @1
|
||||
Members: @1.=Учасники: @1.
|
||||
This area is not protected.=Територія вільна.
|
||||
You can build here.=Тут можна будувати.
|
||||
Overlaps into above players protected area=Блок захисту не може бути встановлений тут, десь поруч є територія іншого гравця
|
||||
Protection Block=Блок захисту території
|
||||
Protection (owned by @1)=Захист території гравця @1
|
||||
Protection Logo=Захисний знак
|
||||
[MOD] Protector Redo loaded=[МОД] Protector Redo завантажено
|
||||
Spawn @1 has been protected up to a @2 block radius.=Спавн @1 захищений у радіусі @2 блока.
|
||||
This area is owned by @1=Ця територія належить гравцю @1
|
||||
|
||||
### pvp.lua ###
|
||||
[Protector] on_punchplayer called with nil objects=[Захист] on_punchplayer викликана із нульовими об'єктами
|
||||
[Protector] pvp_protect not active, update your version of Minetest=[Захист] pvp_protect неактивний, оновіть версію Luanti
|
||||
[Protector] pvp_protect is disabled=[Защита] pvp_protect вимкнений
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=Територія належить @1
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=Інструмент встановлення захисту (встаньте поруч із захистом, поверніться в потрібному напрямку і використайте)
|
||||
Protector already in place!=Захист уже встановлено!
|
||||
No protectors available to place!=У вас немає блоків захисту території в інвентарю!
|
||||
Protector placed at @1=Захист знаходиться на координатах @1
|
59
mods/protector/locale/template.txt
Normal file
|
@ -0,0 +1,59 @@
|
|||
# textdomain: protector
|
||||
# author: ?
|
||||
# last update: 2020/Jul/12
|
||||
|
||||
### admin.lua ###
|
||||
Remove Protectors around players (separate names with spaces)=
|
||||
<names list>=
|
||||
Replace Protector Owner with name provided=
|
||||
<owner name> <name to replace with>=
|
||||
Replacing Protector name '@1' with '@2'=
|
||||
Show protected areas of your nearby protectors=
|
||||
Protector Names to remove: @1=
|
||||
Name List Reset=
|
||||
Invalid player name!=
|
||||
Player name too long=
|
||||
Player not found.=
|
||||
|
||||
### doors_chest.lua ###
|
||||
Protected Wooden Door=
|
||||
Protected Steel Door=
|
||||
Protected Trapdoor=
|
||||
Protected Steel Trapdoor=
|
||||
Protected Chest=
|
||||
To Chest=
|
||||
To Inventory=
|
||||
Protected Chest (@1)=
|
||||
|
||||
### init.lua ###
|
||||
-- Protector interface --=
|
||||
PUNCH node to show protected area=
|
||||
USE for area check=
|
||||
Members:=
|
||||
Close=
|
||||
Protection located at: @1=
|
||||
Members: @1.=
|
||||
Allow faction access=
|
||||
This area is not protected.=
|
||||
You can build here.=
|
||||
Overlaps into above players protected area=
|
||||
Protection Block=
|
||||
Protection (owned by @1)=
|
||||
Protection Logo=
|
||||
[MOD] Protector Redo loaded=
|
||||
Spawn @1 has been protected up to a @2 block radius.=
|
||||
This area is owned by @1=
|
||||
Add member names to local protection
|
||||
Remove member names from local protection
|
||||
|
||||
### hud.lua ###
|
||||
Owner: @1=
|
||||
|
||||
### tool.lua ###
|
||||
Protector Placer Tool (stand near protector, face direction and use)=
|
||||
Protector already in place!=
|
||||
Out of bounds!=
|
||||
No protectors available to place!=
|
||||
Protector placed at @1=
|
||||
Cannot place protector, already protected at @1=
|
||||
Cannot place protector, container at @1=
|
15
mods/protector/lucky_block.lua
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
-- add lucky blocks
|
||||
|
||||
lucky_block:add_blocks({
|
||||
{"dro", {"protector:protect"}, 2},
|
||||
{"dro", {"protector:protect2"}, 2},
|
||||
{"dro", {"protector:door_wood"}, 2},
|
||||
{"dro", {"protector:door_steel"}, 2},
|
||||
{"exp", 5, true},
|
||||
{"dro", {"protector:trapdoor"}, 2},
|
||||
{"dro", {"protector:trapdoor_steel"}, 2},
|
||||
{"dro", {"protector:tool"}, 1},
|
||||
{"dro", {"protector:chest"}, 1},
|
||||
{"exp"}
|
||||
})
|
7
mods/protector/mod.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
name = protector
|
||||
description = Lets players craft special blocks to protect their builds or disable PVP in areas.
|
||||
optional_depends = default, lucky_block, mesecons_mvps, playerfactions, mcl_core, mcl_formspec, mcl_sounds
|
||||
min_minetest_version = 5.0
|
||||
release = 30961
|
||||
author = TenPlus1
|
||||
title = Protector Redo
|
70
mods/protector/pvp.lua
Normal file
|
@ -0,0 +1,70 @@
|
|||
|
||||
-- get static spawn position
|
||||
|
||||
local statspawn = core.string_to_pos(core.settings:get("static_spawnpoint"))
|
||||
or {x = 0, y = 2, z = 0}
|
||||
|
||||
-- is spawn protected
|
||||
|
||||
local protector_spawn = tonumber(core.settings:get("protector_spawn")
|
||||
or core.settings:get("protector_pvp_spawn")) or 0
|
||||
|
||||
-- is night-only pvp enabled
|
||||
|
||||
local protector_night_pvp = core.settings:get_bool("protector_night_pvp")
|
||||
|
||||
-- disables PVP in your own protected areas
|
||||
|
||||
if core.settings:get_bool("enable_pvp")
|
||||
and core.settings:get_bool("protector_pvp") then
|
||||
|
||||
if core.register_on_punchplayer then
|
||||
|
||||
core.register_on_punchplayer(function(player, hitter,
|
||||
time_from_last_punch, tool_capabilities, dir, damage)
|
||||
|
||||
if not player or not hitter then
|
||||
print("[MOD] Protector - on_punchplayer called with nil objects")
|
||||
return false
|
||||
end
|
||||
|
||||
if not hitter:is_player() then return false end
|
||||
|
||||
-- no pvp at spawn area
|
||||
local pos = player:get_pos()
|
||||
|
||||
if pos.x < statspawn.x + protector_spawn
|
||||
and pos.x > statspawn.x - protector_spawn
|
||||
and pos.y < statspawn.y + protector_spawn
|
||||
and pos.y > statspawn.y - protector_spawn
|
||||
and pos.z < statspawn.z + protector_spawn
|
||||
and pos.z > statspawn.z - protector_spawn then
|
||||
return true
|
||||
end
|
||||
|
||||
-- do we enable pvp at night time only ?
|
||||
if protector_night_pvp then
|
||||
|
||||
-- get time of day
|
||||
local tod = core.get_timeofday() or 0
|
||||
|
||||
if tod > 0.2 and tod < 0.8 then
|
||||
--
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- is player being punched inside a protected area ?
|
||||
if core.is_protected(pos, hitter:get_player_name()) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end)
|
||||
else
|
||||
print("[MOD] Protector - pvp_protect not active, update your version of Minetest")
|
||||
end
|
||||
else
|
||||
print("[MOD] Protector - pvp_protect is disabled")
|
||||
end
|
BIN
mods/protector/screenshot.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
35
mods/protector/settingtypes.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Size of protected area around protection node limiting player interaction
|
||||
protector_radius (Protector Radius [max 30]) int 5
|
||||
|
||||
# Flips player around when accessing protected area to stop lag griefing
|
||||
protector_flip (Protector Flip) bool false
|
||||
|
||||
# Hurts player by amount entered when accessing protected area, 0 to disable
|
||||
protector_hurt (Protector Hurt) int 0
|
||||
|
||||
# Sets a protected area around spawn by node radius given
|
||||
protector_spawn (Protector Spawn) int 0
|
||||
|
||||
# Enables PVP inside of protected areas
|
||||
protector_pvp (Protector PVP) bool false
|
||||
|
||||
# When true will allow PVP inside protected spawn area
|
||||
protector_pvp_spawn (Protector PVP Spawn) int 0
|
||||
|
||||
# When true will allow PVP inside all protected areas at night time only
|
||||
protector_night_pvp (Protector Night PVP) bool false
|
||||
|
||||
# Interval in seconds that protection field is shown
|
||||
protector_show_interval (Protector Show Interval) int 5
|
||||
|
||||
# Interval in seconds that HUD ownership text is updated, 0 to disable
|
||||
protector_hud_interval (Protector HUD Interval) int 5
|
||||
|
||||
# Enables craft recipe for protection block
|
||||
protector_recipe (Enable Protector recipe) bool true
|
||||
|
||||
# Enables craft recipes for protected doors and chest
|
||||
protector_crafts (Enable Protector door/chest recipes) bool true
|
||||
|
||||
# Enables protection messages in player chat
|
||||
protector_msg (Enable Protector Messages) bool true
|
BIN
mods/protector/textures/default_chest_front.png
Normal file
After Width: | Height: | Size: 421 B |
BIN
mods/protector/textures/default_chest_side.png
Normal file
After Width: | Height: | Size: 375 B |
BIN
mods/protector/textures/default_chest_top.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
mods/protector/textures/doors_brown.png
Normal file
After Width: | Height: | Size: 109 B |
BIN
mods/protector/textures/doors_grey.png
Normal file
After Width: | Height: | Size: 105 B |
BIN
mods/protector/textures/doors_steel.png
Normal file
After Width: | Height: | Size: 132 B |
BIN
mods/protector/textures/doors_steel_a.png
Normal file
After Width: | Height: | Size: 273 B |
BIN
mods/protector/textures/doors_steel_b.png
Normal file
After Width: | Height: | Size: 260 B |
BIN
mods/protector/textures/doors_trapdoor.png
Normal file
After Width: | Height: | Size: 257 B |
BIN
mods/protector/textures/doors_trapdoor_side.png
Normal file
After Width: | Height: | Size: 233 B |
BIN
mods/protector/textures/doors_trapdoor_steel.png
Normal file
After Width: | Height: | Size: 153 B |
BIN
mods/protector/textures/doors_trapdoor_steel_side.png
Normal file
After Width: | Height: | Size: 101 B |
BIN
mods/protector/textures/doors_wood.png
Normal file
After Width: | Height: | Size: 130 B |
BIN
mods/protector/textures/doors_wood_a.png
Normal file
After Width: | Height: | Size: 294 B |
BIN
mods/protector/textures/doors_wood_b.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
mods/protector/textures/johnsmith/protector_logo.png
Normal file
After Width: | Height: | Size: 862 B |
34
mods/protector/textures/license.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
following Textures created by Fernando Zapata (CC BY-SA 3.0):
|
||||
doors_wood.png
|
||||
doors_wood_a.png
|
||||
doors_wood_b.png
|
||||
doors_brown.png
|
||||
|
||||
following Textures created by BlockMen (WTFPL):
|
||||
doors_trapdoor.png
|
||||
|
||||
following textures created by celeron55 (CC BY-SA 3.0):
|
||||
doors_trapdoor_side.png
|
||||
|
||||
following textures created by PilzAdam (WTFPL):
|
||||
doors_steel.png
|
||||
doors_steel_a.png
|
||||
doors_steel_b.png
|
||||
doors_grey.png
|
||||
doors_trapdoor_steel.png
|
||||
doors_trapdoor_steel_side.png
|
||||
|
||||
following textures by Cisoun (WTFPL):
|
||||
default_chest_front.png
|
||||
default_chest_side.png
|
||||
default_chest_top.png
|
||||
|
||||
following textures by TenPlus1 (CC BY-SA 3.0):
|
||||
protector_logo.png
|
||||
protector_display.png
|
||||
protector_overlay.png
|
||||
|
||||
following textures by Kilbith (CC BY-SA 3.0):
|
||||
protector_up_icon.png
|
||||
protector_down_icon.png (both rotated)
|
BIN
mods/protector/textures/protector_display.png
Normal file
After Width: | Height: | Size: 96 B |
BIN
mods/protector/textures/protector_down_icon.png
Normal file
After Width: | Height: | Size: 481 B |
BIN
mods/protector/textures/protector_logo.png
Normal file
After Width: | Height: | Size: 138 B |
BIN
mods/protector/textures/protector_overlay.png
Normal file
After Width: | Height: | Size: 116 B |
BIN
mods/protector/textures/protector_tool.png
Normal file
After Width: | Height: | Size: 174 B |
BIN
mods/protector/textures/protector_up_icon.png
Normal file
After Width: | Height: | Size: 478 B |
164
mods/protector/tool.lua
Normal file
|
@ -0,0 +1,164 @@
|
|||
|
||||
-- protector placement tool (thanks to Shara for code and idea)
|
||||
|
||||
local S = core.get_translator("protector")
|
||||
|
||||
-- get protection radius
|
||||
|
||||
local r = protector.radius
|
||||
|
||||
-- protector placement tool
|
||||
|
||||
core.register_craftitem("protector:tool", {
|
||||
description = S("Protector Placer Tool (stand near protector, face direction and use)"),
|
||||
inventory_image = "protector_tool.png",
|
||||
stack_max = 1,
|
||||
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
|
||||
local name = user:get_player_name()
|
||||
|
||||
-- check for protector near player (2 block radius)
|
||||
local pos = user:get_pos()
|
||||
local pp = core.find_nodes_in_area(
|
||||
vector.subtract(pos, 2), vector.add(pos, 2),
|
||||
{"protector:protect", "protector:protect2", "protector:protect_hidden"})
|
||||
|
||||
if #pp == 0 then return end -- none found
|
||||
|
||||
pos = pp[1] -- take position of first protector found
|
||||
|
||||
-- get members on protector
|
||||
local meta = core.get_meta(pos)
|
||||
local members = meta:get_string("members") or ""
|
||||
|
||||
-- get direction player is facing
|
||||
local dir = core.dir_to_facedir( user:get_look_dir() )
|
||||
local vec = {x = 0, y = 0, z = 0}
|
||||
local gap = (r * 2) + 1
|
||||
local pit = user:get_look_vertical()
|
||||
|
||||
-- set placement coords
|
||||
if pit > 1.2 then vec.y = -gap -- up
|
||||
elseif pit < -1.2 then vec.y = gap -- down
|
||||
elseif dir == 0 then vec.z = gap -- north
|
||||
elseif dir == 1 then vec.x = gap -- east
|
||||
elseif dir == 2 then vec.z = -gap -- south
|
||||
elseif dir == 3 then vec.x = -gap -- west
|
||||
end
|
||||
|
||||
-- new position
|
||||
pos.x = pos.x + vec.x
|
||||
pos.y = pos.y + vec.y
|
||||
pos.z = pos.z + vec.z
|
||||
|
||||
-- does placing a protector overlap existing area
|
||||
if not protector.can_dig(r * 2, pos, user:get_player_name(), true, 3) then
|
||||
|
||||
core.chat_send_player(name,
|
||||
S("Overlaps into above players protected area"))
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- does a protector already exist ?
|
||||
if #core.find_nodes_in_area(vector.subtract(pos, 1), vector.add(pos, 1),
|
||||
{"protector:protect", "protector:protect2",
|
||||
"protector:protect_hidden"}) > 0 then
|
||||
|
||||
core.chat_send_player(name, S("Protector already in place!"))
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- do not place protector out of map bounds or replace bedrock
|
||||
if #core.find_nodes_in_area(pos, pos, {"ignore", "mcl_core:bedrock"}) > 0 then
|
||||
|
||||
core.chat_send_player(name, S("Out of bounds!"))
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- do we have protectors to use ?
|
||||
local nod
|
||||
local inv = user:get_inventory()
|
||||
|
||||
if not inv:contains_item("main", "protector:protect")
|
||||
and not inv:contains_item("main", "protector:protect2") then
|
||||
|
||||
core.chat_send_player(name,
|
||||
S("No protectors available to place!"))
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- take protector (block first then logo)
|
||||
if inv:contains_item("main", "protector:protect") then
|
||||
|
||||
inv:remove_item("main", "protector:protect")
|
||||
|
||||
nod = "protector:protect"
|
||||
|
||||
elseif inv:contains_item("main", "protector:protect2") then
|
||||
|
||||
inv:remove_item("main", "protector:protect2")
|
||||
|
||||
nod = "protector:protect2"
|
||||
end
|
||||
|
||||
-- do not replace containers with inventory space
|
||||
local inv = core.get_inventory({type = "node", pos = pos})
|
||||
|
||||
if inv then
|
||||
core.chat_send_player(name,
|
||||
S("Cannot place protector, container at @1",
|
||||
core.pos_to_string(pos)))
|
||||
return
|
||||
end
|
||||
|
||||
-- protection check for other mods like Areas
|
||||
if core.is_protected(pos, name) then
|
||||
|
||||
core.chat_send_player(name,
|
||||
S("Cannot place protector, already protected at @1",
|
||||
core.pos_to_string(pos)))
|
||||
return
|
||||
end
|
||||
|
||||
-- place protector
|
||||
core.set_node(pos, {name = nod, param2 = 1})
|
||||
|
||||
-- set protector metadata
|
||||
local meta = core.get_meta(pos)
|
||||
|
||||
meta:set_string("owner", name)
|
||||
meta:set_string("infotext", "Protection (owned by " .. name .. ")")
|
||||
|
||||
-- copy members across if holding sneak when using tool
|
||||
if user:get_player_control().sneak then
|
||||
meta:set_string("members", members)
|
||||
else
|
||||
meta:set_string("members", "")
|
||||
end
|
||||
|
||||
core.chat_send_player(name,
|
||||
S("Protector placed at @1", core.pos_to_string(pos)))
|
||||
end
|
||||
})
|
||||
|
||||
-- tool recipe
|
||||
|
||||
local df = "default:steel_ingot"
|
||||
|
||||
if core.get_modpath("mcl_core") then
|
||||
df = "mcl_core:iron_ingot"
|
||||
end
|
||||
|
||||
core.register_craft({
|
||||
output = "protector:tool",
|
||||
recipe = {
|
||||
{df, df, df},
|
||||
{df, "protector:protect", df},
|
||||
{df, df, df}
|
||||
}
|
||||
})
|