Compare commits

..

12 Commits

Author SHA1 Message Date
JoseDouglas26 35de4a4974 Textures fixes for doors 2024-02-22 11:25:23 -03:00
JoseDouglas26 787ef17925 Fix door param2 change when scrapping or waxing 2024-02-20 10:42:36 -03:00
JoseDouglas26 ff23d46125 Door duplication bug solved and more oxidation 2024-02-16 15:32:25 -03:00
JoseDouglas26 f83d1b18cd Oxidation, scrapping and waxing for copper doors 2024-02-16 12:35:43 -03:00
JoseDouglas26 802137f355 New copper doors items and open trapdoor oxidation 2024-02-14 17:34:39 -03:00
JoseDouglas26 5f9da709f6 Bug fixes and new functions.lua 2024-02-14 09:13:19 -03:00
JoseDouglas26 20888dfe32 Copper door textures and other improvements 2024-02-11 18:53:49 -03:00
JoseDouglas26 b704c1e773 Merge branch 'mcl_copper-and_new-blocks' of https://git.minetest.land/JoseDouglas26/MineClone2 into mcl_copper-and_new-blocks 2024-02-08 10:24:47 -03:00
JoseDouglas26 480b30ceab Copper bulb textures 2024-02-08 10:20:35 -03:00
JoseDouglas26 73a053615e More copper blocks and crafting "api" 2024-02-08 10:18:34 -03:00
JoseDouglas26 797b527d2d New mcl_copper and new 1.21 MC blocks 2024-02-05 15:20:36 +00:00
JoseDouglas26 e6c0ab0572 New mcl_copper and new 1.21 MC blocks 2024-02-05 11:58:46 -03:00
215 changed files with 1680 additions and 4971 deletions

View File

@ -4,7 +4,7 @@ root = true
end_of_line = lf
[*.lua]
charset = utf-8
charset = utf8
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

View File

@ -36,8 +36,6 @@ mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16)
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
-- Central chunk is offset from 0,0,0 coordinates by 32 nodes (2 blocks)
-- See more in https://git.minetest.land/MineClone2/MineClone2/wiki/World-structure%3A-positions%2C-boundaries%2C-blocks%2C-chunks%2C-dimensions%2C-barriers-and-the-void
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE

View File

@ -6,7 +6,16 @@ minetest.register_abm({
action = function(pos, node)
local def = minetest.registered_nodes[node.name]
if def and def._mcl_oxidized_variant then
minetest.set_node(pos, { name = def._mcl_oxidized_variant, param2 = node.param2 })
if def.groups.door == 1 then
if node.name:find("_b_") then
local top_pos = { x = pos.x, y = pos.y + 1, z = pos.z }
minetest.swap_node(top_pos, { name = def._mcl_oxidized_variant:gsub("_b_", "_t_"), param2 = node.param2 })
elseif node.name:find("_t_") then
local bot_pos = { x = pos.x, y = pos.y - 1, z = pos.z }
minetest.swap_node(bot_pos, { name = def._mcl_oxidized_variant:gsub("_t_", "_b_"), param2 = node.param2 })
end
end
minetest.swap_node(pos, { name = def._mcl_oxidized_variant, param2 = node.param2 })
end
end,
})

View File

@ -257,21 +257,12 @@ end
---@param dst_inventory InvRef Destination inventory to push to
---@param dst_list string Name of destination inventory list to push to
---@param condition? fun(stack: ItemStack) Condition which items are allowed to be transfered.
---@param count? integer Number of items to try to transfer at once
---@return integer Item stack number to be transfered
function mcl_util.select_stack(src_inventory, src_list, dst_inventory, dst_list, condition, count)
function mcl_util.select_stack(src_inventory, src_list, dst_inventory, dst_list, condition)
local src_size = src_inventory:get_size(src_list)
local stack
for i = 1, src_size do
stack = src_inventory:get_stack(src_list, i)
-- Allow for partial stack movement
if count and stack:get_count() >= count then
local new_stack = ItemStack(stack)
new_stack:set_count(count)
stack = new_stack
end
if not stack:is_empty() and dst_inventory:room_for_item(dst_list, stack) and ((condition == nil or condition(stack))) then
return i
end
@ -289,22 +280,21 @@ end
-- Returns true on success and false on failure
-- Possible failures: No item in source slot, destination inventory full
function mcl_util.move_item(source_inventory, source_list, source_stack_id, destination_inventory, destination_list)
-- Can't move items we don't have
if source_inventory:is_empty(source_list) then return false end
-- Can't move from an empty stack
local stack = source_inventory:get_stack(source_list, source_stack_id)
if stack:is_empty() then return false end
local new_stack = ItemStack(stack)
new_stack:set_count(1)
if not destination_inventory:room_for_item(destination_list, new_stack) then
return false
if not source_inventory:is_empty(source_list) then
local stack = source_inventory:get_stack(source_list, source_stack_id)
if not stack:is_empty() then
local new_stack = ItemStack(stack)
new_stack:set_count(1)
if not destination_inventory:room_for_item(destination_list, new_stack) then
return false
end
stack:take_item()
source_inventory:set_stack(source_list, source_stack_id, stack)
destination_inventory:add_item(destination_list, new_stack)
return true
end
end
stack:take_item()
source_inventory:set_stack(source_list, source_stack_id, stack)
destination_inventory:add_item(destination_list, new_stack)
return true
return false
end
--- Try pushing item from hopper inventory to destination inventory
@ -324,23 +314,25 @@ function mcl_util.hopper_push(pos, dst_pos)
local dst_list = 'main'
local dst_inv, stack_id
-- Find a inventory stack in the destination
if dst_def._mcl_hoppers_on_try_push then
dst_inv, dst_list, stack_id = dst_def._mcl_hoppers_on_try_push(dst_pos, pos, hop_inv, hop_list)
else
local dst_meta = minetest.get_meta(dst_pos)
dst_inv = dst_meta:get_inventory()
stack_id = mcl_util.select_stack(hop_inv, hop_list, dst_inv, dst_list, nil, 1)
end
if not stack_id then return false end
-- Move the item
local ok = mcl_util.move_item(hop_inv, hop_list, stack_id, dst_inv, dst_list)
if dst_def._mcl_hoppers_on_after_push then
dst_def._mcl_hoppers_on_after_push(dst_pos)
stack_id = mcl_util.select_stack(hop_inv, hop_list, dst_inv, dst_list)
end
return ok
if stack_id ~= nil then
local ok = mcl_util.move_item(hop_inv, hop_list, stack_id, dst_inv, dst_list)
if dst_def._mcl_hoppers_on_after_push then
dst_def._mcl_hoppers_on_after_push(dst_pos)
end
if ok then
return true
end
end
return false
end
-- Try pulling from source inventory to hopper inventory
@ -365,7 +357,7 @@ function mcl_util.hopper_pull(pos, src_pos)
else
local src_meta = minetest.get_meta(src_pos)
src_inv = src_meta:get_inventory()
stack_id = mcl_util.select_stack(src_inv, src_list, hop_inv, hop_list, nil, 1)
stack_id = mcl_util.select_stack(src_inv, src_list, hop_inv, hop_list)
end
if stack_id ~= nil then

View File

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state 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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,87 +1,4 @@
# tga_encoder
A TGA Encoder written in Lua without the use of external Libraries.
Created by fleckenstein for MineClone2, then improved by erlehmann.
May be used as a Minetest mod.
See `examples.lua` for example code and usage hints.
## Use Cases for `tga_encoder`
### Encoding Textures for Editing
TGA images of types 1/2/3 consist of header data followed by a pixel array.
This makes it trivial to parse TGA files and even edit pixels in-place.
No checksums need to be updated on any kind of in-place texture editing.
**Tip**: When storing an editable image in item meta, use zlib compression.
### Legacy Minetest Texture Encoding
Minetest 5.4 did not include `minetest.encode_png()` (or any equvivalent).
Since `tga_encoder` is written in pure Lua, it does not need engine support.
**Tip:** Look at `examples.lua` and the Minetest mod `mcl_maps` for guidance.
### Advanced Texture Format Control
The function `minetest.encode_png()` always encodes images as 32bpp RGBA.
`tga_encoder` allows saving images as grayscale, 16bpp RGBA and 24bpp RGB.
For generating maps from terrain, color-mapped formats can be more useful.
### Encoding Very Small Textures
Images of size 8×8 or below are often smaller than an equivalent PNG file.
Note that on many filesystems files use at least 4096 bytes (i.e. 64×64).
Therefore, saving bytes on files up to a few 100 bytes is often useless.
### Encoding Reference Textures
TGA is a simple format, which makes it easy to create reference textures.
Using a hex editor, one can trivially see how all the pixels are stored.
## Supported Image Types
For all types, images are encoded in a fast single pass (i.e. append-only).
### Color-Mapped Images (Type 1)
These images contain a palette, followed by pixel data.
* `A1R5G5B5` (8bpp RGB)
* `B8G8R8` (8bpp RGB)
* `B8G8R8A8` (8bpp RGBA)
### True-Color Images (Type 2)
These images contain uncompressed RGB(A) pixel data.
* `A1R5G5B5` (16bpp RGBA)
* `B8G8R8` (24bpp RGB)
* `B8G8R8A8` (32bpp RGBA)
### Grayscale Images (Type 3)
* `Y8` (8bpp grayscale)
### Run-Length Encoded (RLE), True-Color Images (Type 10)
These images contain compressed RGB(A) pixel data.
* `A1R5G5B5` (16bpp RGBA)
* `B8G8R8` (24bpp RGB)
* `B8G8R8A8` (32bpp RGBA)
## TODO
* Actually support `R8G8B8A8` input for `A1R5G5B5` output
* Add both zoomable and explorable maps to `mcl_maps`.

View File

@ -1,32 +0,0 @@
dofile("init.lua")
-- This generates images necessary to colorize 16 Minetest nodes in 4096 colors.
-- It serves as a demonstration of what you can achieve using colormapped nodes.
-- It is be useful for grass or beam or glass nodes that need to blend smoothly.
-- Sample depth rescaling is done according to the algorithm presented in:
-- <https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling>
local max_sample_in = math.pow(2, 4) - 1
local max_sample_out = math.pow(2, 8) - 1
for r = 0,15 do
local pixels = {}
for g = 0,15 do
if nil == pixels[g + 1] then
pixels[g + 1] = {}
end
for b = 0,15 do
local color = {
math.floor((r * max_sample_out / max_sample_in) + 0.5),
math.floor((g * max_sample_out / max_sample_in) + 0.5),
math.floor((b * max_sample_out / max_sample_in) + 0.5),
}
pixels[g + 1][b + 1] = color
end
end
local filename = "colormap_" .. tostring(r) .. ".tga"
tga_encoder.image(pixels):save(
filename,
{ color_format="A1R5G5B5" } -- waste less bits
)
end

View File

@ -1,105 +0,0 @@
#!/usr/bin/env lua5.1
-- -*- coding: utf-8 -*-
-- 3D “donut” shape rendering using floating-point math
-- see <https://www.a1k0n.net/2011/07/20/donut-math.html>
-- cargo-culted by erle 2023-09-18
local theta_spacing = 0.01 -- 0.07
local phi_spacing = 0.002 -- 0.02
local R1 = 1
local R2 = 2
local K2 = 5
local screen_height = 256
local screen_width = 256
local K1 = screen_width * K2 * 3 / ( 8 * ( R1 + R2 ) )
local output = {}
local zbuffer = {}
local grey = { 120, 120, 120 }
local gray = { 136, 136, 136 }
for y = 1,screen_height,1 do
output[y] = {}
zbuffer[y] = {}
for x = 1,screen_width,1 do
local hori = math.floor( ( (y - 1) / 32 ) % 2 )
local vert = math.floor( ( (x - 1) / 32 ) % 2 )
output[y][x] = hori ~= vert and grey or gray
zbuffer[y][x] = 0
end
end
function render_frame(A, B)
-- precompute sines and cosines of A and B
local cosA = math.cos(A)
local sinA = math.sin(A)
local cosB = math.cos(B)
local sinB = math.sin(B)
-- theta goas around the cross-sectional circle of a torus
local theta = 0
while theta <= 2*math.pi do
if ( theta < 2*math.pi * 1/8 ) or ( theta > 2*math.pi * 7/8 ) then
theta = theta + (theta_spacing * 16)
else
theta = theta + theta_spacing
end
-- precompute sines and cosines of theta
local costheta = math.cos(theta)
local sintheta = math.sin(theta)
-- phi goes around the center of revolution of a torus
local phi = 0
while phi <= 2*math.pi do
if ( phi > 2*math.pi * 3/8 ) and ( phi < 2*math.pi * 5/8 ) then
phi = phi + (phi_spacing * 128)
else
phi = phi + phi_spacing
end
-- precompute sines and cosines of phi
local cosphi = math.cos(phi)
local sinphi = math.sin(phi)
-- 2D (x, y) coordinates of the circle, before revolving
local circlex = R2 + R1*costheta
local circley = R1*sintheta
-- 3D (x, y, z) coordinates after rotation
local x = circlex*(cosB*cosphi + sinA*sinB*sinphi) - circley*cosA*sinB
local y = circlex*(sinB*cosphi - sinA*cosB*sinphi) + circley*cosA*cosB
local z = K2 + cosA*circlex*sinphi + circley*sinA
local ooz = 1/z
-- x and y projection
local xp = math.floor(screen_width/2 + K1*ooz*x)
local yp = math.floor(screen_height/2 + K1*ooz*y)
-- calculate luminance
local L = cosphi*costheta*sinB - cosA*costheta*sinphi - sinA*sintheta + cosB*( cosA*sintheta - costheta*sinA*sinphi )
-- if (L > 0) then
if (true) then
if (ooz > zbuffer[yp][xp]) then
zbuffer[yp][xp] = ooz
local luminance = math.max( math.ceil( L * 180 ), 0 )
-- luminance is now in the range 0 to 255
r = math.ceil( (luminance + xp) / 2 )
g = math.ceil( (luminance + yp) / 2 )
b = math.ceil( (luminance + xp + yp) / 3 )
output[yp][xp] = { r, g, b }
end
end
end
end
end
dofile('init.lua')
render_frame(-0.7, 0.7)
tga_encoder.image(output):save("donut.tga")

View File

@ -1,181 +0,0 @@
dofile("init.lua")
-- encode a bitmap
local _ = { 0, 0, 0 }
local R = { 255, 127, 127 }
local pixels = {
{ _, _, _, _, _, _, _ },
{ _, _, _, R, _, _, _ },
{ _, _, R, R, R, _, _ },
{ _, R, R, R, R, R, _ },
{ _, R, R, R, R, R, _ },
{ _, _, R, _, R, _, _ },
{ _, _, _, _, _, _, _ },
}
tga_encoder.image(pixels):save("bitmap_small.tga")
-- test that image can be encoded
local bitmap_small_0 = tga_encoder.image(pixels)
bitmap_small_0:encode()
assert(191 == #bitmap_small_0.data)
-- test that imbage can be encoded with parameters
local bitmap_small_1 = tga_encoder.image(pixels)
bitmap_small_1:encode(
{
colormap = {},
color_format = "B8G8R8",
compression = "RAW",
}
)
assert(191 == #bitmap_small_1.data)
-- change a single pixel, then rescale the bitmap
local pixels_orig = pixels
pixels_orig[4][4] = { 255, 255, 255 }
local pixels = {}
for x = 1,56,1 do
local x_orig = math.ceil(x/8)
for z = 1,56,1 do
local z_orig = math.ceil(z/8)
local color = pixels_orig[z_orig][x_orig]
pixels[z] = pixels[z] or {}
pixels[z][x] = color
end
end
tga_encoder.image(pixels):save("bitmap_large.tga")
-- note that the uncompressed grayscale TGA file written in this
-- example is 80 bytes but an optimized PNG file is 81 bytes …
local pixels = {}
for x = 1,6,1 do -- left to right
for z = 1,6,1 do -- bottom to top
local color = { math.min(x * z * 4 - 1, 255) }
pixels[z] = pixels[z] or {}
pixels[z][x] = color
end
end
tga_encoder.image(pixels):save("gradient_8bpp_raw.tga", {color_format="Y8", compression="RAW"})
local pixels = {}
for x = 1,16,1 do -- left to right
for z = 1,16,1 do -- bottom to top
local r = math.min(x * 32 - 1, 255)
local g = math.min(z * 32 - 1, 255)
local b = 0
-- blue rectangle in top right corner
if x > 8 and z > 8 then
r = 0
g = 0
b = math.min(z * 16 - 1, 255)
end
local color = { r, g, b }
pixels[z] = pixels[z] or {}
pixels[z][x] = color
end
end
local gradients = tga_encoder.image(pixels)
gradients:save("gradients_8bpp_raw.tga", {color_format="Y8", compression="RAW"})
gradients:save("gradients_16bpp_raw.tga", {color_format="A1R5G5B5", compression="RAW"})
gradients:save("gradients_16bpp_rle.tga", {color_format="A1R5G5B5", compression="RLE"})
gradients:save("gradients_24bpp_raw.tga", {color_format="B8G8R8", compression="RAW"})
gradients:save("gradients_24bpp_rle.tga", {color_format="B8G8R8", compression="RLE"})
for x = 1,16,1 do -- left to right
for z = 1,16,1 do -- bottom to top
local color = pixels[z][x]
color[#color+1] = ((x * x) + (z * z)) % 256
pixels[z][x] = color
end
end
gradients:save("gradients_32bpp_raw.tga", {color_format="B8G8R8A8", compression="RAW"})
-- the RLE-compressed file is larger than just dumping pixels because
-- the gradients in this picture can not be compressed well using RLE
gradients:save("gradients_32bpp_rle.tga", {color_format="B8G8R8A8", compression="RLE"})
local pixels = {}
for x = 1,512,1 do -- left to right
for z = 1,512,1 do -- bottom to top
local oz = (z - 256) / 256 + 0.75
local ox = (x - 256) / 256
local px, pz, i = 0, 0, 0
while (px * px) + (pz * pz) <= 4 and i < 128 do
px = (px * px) - (pz * pz) + oz
pz = (2 * px * pz) + ox
i = i + 1
end
local color = {
math.max(0, math.min(255, math.floor(px * 64))),
math.max(0, math.min(255, math.floor(pz * 64))),
math.max(0, math.min(255, math.floor(i))),
}
pixels[z] = pixels[z] or {}
pixels[z][x] = color
end
end
tga_encoder.image(pixels):save("fractal_8bpp.tga", {color_format="Y8"})
tga_encoder.image(pixels):save("fractal_16bpp.tga", {color_format="A1R5G5B5"})
tga_encoder.image(pixels):save("fractal_24bpp.tga", {color_format="B8G8R8"})
-- encode a colormapped bitmap
local K = { 0 }
local B = { 1 }
local R = { 2 }
local G = { 3 }
local W = { 4 }
local colormap = {
{ 1, 2, 3 }, -- K
{ 0, 0, 255 }, -- B
{ 255, 0, 0 }, -- R
{ 0, 255, 0 }, -- G
{ 253, 254, 255 }, -- W
}
local pixels = {
{ W, K, W, K, W, K, W },
{ R, G, B, R, G, B, K },
{ K, W, K, W, K, W, K },
{ G, B, R, G, B, R, W },
{ W, W, W, K, K, K, W },
{ B, R, G, B, R, G, K },
{ B, R, G, B, R, G, W },
}
-- note that the uncompressed colormapped TGA file written in this
-- example is 108 bytes but an optimized PNG file is 121 bytes …
tga_encoder.image(pixels):save("colormapped_B8G8R8.tga", {colormap=colormap})
-- encoding as A1R5G5B5 saves 1 byte per palette entry → 103 bytes
tga_encoder.image(pixels):save("colormapped_A1R5G5B5.tga", {colormap=colormap, color_format="A1R5G5B5"})
-- encode a colormapped bitmap with transparency
local _ = { 0 }
local K = { 1 }
local W = { 2 }
local colormap = {
{ 0, 0, 0, 0 },
{ 0, 0, 0, 255 },
{ 255, 255, 255, 255 },
}
local pixels = {
{ _, K, K, K, K, K, _ },
{ _, K, W, W, W, K, _ },
{ K, K, W, W, W, K, K },
{ K, W, W, W, W, W, K },
{ _, K, W, W, W, K, _ },
{ _, _, K, W, K, _, _ },
{ _, _, _, K, _, _, _ },
}
tga_encoder.image(pixels):save("colormapped_B8G8R8A8.tga", {colormap=colormap})
-- encoding a colormapped image with illegal colormap indexes should error out
local colormap = {
{ 0, 0, 0, 0 },
{ 0, 0, 0, 255 },
}
local status, message = pcall(
function ()
tga_encoder.image(pixels):encode({colormap=colormap})
end
)
assert(
false == status and
"init.lua:36: colormap index 2 not in colormap of size 2" == message
)

View File

@ -9,566 +9,60 @@ local image = setmetatable({}, {
})
function image:constructor(pixels)
self.data = ""
self.pixels = pixels
self.width = #pixels[1]
self.height = #pixels
self:encode()
end
local pixel_depth_by_color_format = {
["Y8"] = 8,
["A1R5G5B5"] = 16,
["B8G8R8"] = 24,
["B8G8R8A8"] = 32,
}
function image:encode_colormap_spec(properties)
local colormap = properties.colormap
local colormap_pixel_depth = 0
if 0 ~= #colormap then
colormap_pixel_depth = pixel_depth_by_color_format[
properties.color_format
]
-- ensure that each pixel references a legal colormap entry
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
local colormap_index = pixel[1]
if colormap_index >= #colormap then
error(
"colormap index " .. colormap_index ..
" not in colormap of size " .. #colormap
)
end
end
end
end
local colormap_spec =
string.char(0, 0) .. -- first entry index
string.char(#colormap % 256, math.floor(#colormap / 256)) .. -- number of entries
string.char(colormap_pixel_depth) -- bits per pixel
self.data = self.data .. colormap_spec
function image:encode_colormap_spec()
self.data = self.data
.. string.char(0, 0) -- first entry index
.. string.char(0, 0) -- number of entries
.. string.char(0) -- bits per pixel
end
function image:encode_image_spec(properties)
local color_format = properties.color_format
assert(
"Y8" == color_format or -- (8 bit grayscale = 1 byte = 8 bits)
"A1R5G5B5" == color_format or -- (A1R5G5B5 = 2 bytes = 16 bits)
"B8G8R8" == color_format or -- (B8G8R8 = 3 bytes = 24 bits)
"B8G8R8A8" == color_format -- (B8G8R8A8 = 4 bytes = 32 bits)
)
local scanline_order = properties.scanline_order
assert (
"bottom-top" == scanline_order or
"top-bottom" == scanline_order
)
local pixel_depth
if 0 ~= #properties.colormap then
pixel_depth = self.pixel_depth
else
pixel_depth = pixel_depth_by_color_format[color_format]
end
assert( nil ~= pixel_depth)
-- the origin is the bottom left corner of the image (always)
local x_origin_lo = 0
local x_origin_hi = 0
local y_origin_lo = 0
local y_origin_hi = 0
local image_descriptor = 0 -- equal to bottom-top scanline order
local width_lo = self.width % 256
local width_hi = math.floor(self.width / 256)
local height_lo = self.height % 256
local height_hi = math.floor(self.height / 256)
if "top-bottom" == scanline_order then
image_descriptor = 32
y_origin_lo = height_lo
y_origin_hi = height_hi
end
self.data = self.data .. string.char (
x_origin_lo, x_origin_hi,
y_origin_lo, y_origin_hi,
width_lo, width_hi,
height_lo, height_hi,
pixel_depth,
image_descriptor
)
function image:encode_image_spec()
self.data = self.data
.. string.char(0, 0) -- X-origin
.. string.char(0, 0) -- Y-origin
.. string.char(self.width % 256, math.floor(self.width / 256)) -- width
.. string.char(self.height % 256, math.floor(self.height / 256)) -- height
.. string.char(24) -- pixel depth (RGB = 3 bytes = 24 bits)
.. string.char(0) -- image descriptor
end
function image:encode_colormap(properties)
local colormap = properties.colormap
if 0 == #colormap then
return
end
local color_format = properties.color_format
assert (
"A1R5G5B5" == color_format or
"B8G8R8" == color_format or
"B8G8R8A8" == color_format
)
local colors = {}
if "A1R5G5B5" == color_format then
-- Sample depth rescaling is done according to the algorithm presented in:
-- <https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling>
local max_sample_in = math.pow(2, 8) - 1
local max_sample_out = math.pow(2, 5) - 1
for i = 1,#colormap,1 do
local color = colormap[i]
local colorword = 32768 +
((math.floor((color[1] * max_sample_out / max_sample_in) + 0.5)) * 1024) +
((math.floor((color[2] * max_sample_out / max_sample_in) + 0.5)) * 32) +
((math.floor((color[3] * max_sample_out / max_sample_in) + 0.5)) * 1)
local color_bytes = string.char(
colorword % 256,
math.floor(colorword / 256)
)
colors[#colors + 1] = color_bytes
end
elseif "B8G8R8" == color_format then
for i = 1,#colormap,1 do
local color = colormap[i]
local color_bytes = string.char(
color[3], -- B
color[2], -- G
color[1] -- R
)
colors[#colors + 1] = color_bytes
end
elseif "B8G8R8A8" == color_format then
for i = 1,#colormap,1 do
local color = colormap[i]
local color_bytes = string.char(
color[3], -- B
color[2], -- G
color[1], -- R
color[4] -- A
)
colors[#colors + 1] = color_bytes
end
end
assert( 0 ~= #colors )
self.data = self.data .. table.concat(colors)
end
function image:encode_header(properties)
local color_format = properties.color_format
local colormap = properties.colormap
local compression = properties.compression
local colormap_type
local image_type
if "Y8" == color_format and "RAW" == compression then
colormap_type = 0
image_type = 3 -- grayscale
elseif (
"A1R5G5B5" == color_format or
"B8G8R8" == color_format or
"B8G8R8A8" == color_format
) then
if "RAW" == compression then
if 0 ~= #colormap then
colormap_type = 1
image_type = 1 -- colormapped RGB(A)
else
colormap_type = 0
image_type = 2 -- RAW RGB(A)
end
elseif "RLE" == compression then
colormap_type = 0
image_type = 10 -- RLE RGB
end
end
assert( nil ~= colormap_type )
assert( nil ~= image_type )
function image:encode_header()
self.data = self.data
.. string.char(0) -- image id
.. string.char(colormap_type)
.. string.char(image_type)
self:encode_colormap_spec(properties) -- color map specification
self:encode_image_spec(properties) -- image specification
self:encode_colormap(properties)
.. string.char(0) -- color map type
.. string.char(10) -- image type (RLE RGB = 10)
self:encode_colormap_spec() -- color map specification
self:encode_image_spec() -- image specification
end
function image:encode_data(properties)
local color_format = properties.color_format
local colormap = properties.colormap
local compression = properties.compression
local data_length_before = #self.data
if "Y8" == color_format and "RAW" == compression then
if 8 == self.pixel_depth then
self:encode_data_Y8_as_Y8_raw()
elseif 24 == self.pixel_depth then
self:encode_data_R8G8B8_as_Y8_raw()
end
elseif "A1R5G5B5" == color_format then
if 0 ~= #colormap then
if "RAW" == compression then
if 8 == self.pixel_depth then
self:encode_data_Y8_as_Y8_raw()
end
end
else
if "RAW" == compression then
self:encode_data_R8G8B8_as_A1R5G5B5_raw()
elseif "RLE" == compression then
self:encode_data_R8G8B8_as_A1R5G5B5_rle()
end
end
elseif "B8G8R8" == color_format then
if 0 ~= #colormap then
if "RAW" == compression then
if 8 == self.pixel_depth then
self:encode_data_Y8_as_Y8_raw()
end
end
else
if "RAW" == compression then
self:encode_data_R8G8B8_as_B8G8R8_raw()
elseif "RLE" == compression then
self:encode_data_R8G8B8_as_B8G8R8_rle()
end
end
elseif "B8G8R8A8" == color_format then
if 0 ~= #colormap then
if "RAW" == compression then
if 8 == self.pixel_depth then
self:encode_data_Y8_as_Y8_raw()
end
end
else
if "RAW" == compression then
self:encode_data_R8G8B8A8_as_B8G8R8A8_raw()
elseif "RLE" == compression then
self:encode_data_R8G8B8A8_as_B8G8R8A8_rle()
end
end
end
local data_length_after = #self.data
assert(
data_length_after ~= data_length_before,
"No data encoded for color format: " .. color_format
)
end
function image:encode_data_Y8_as_Y8_raw()
assert(8 == self.pixel_depth)
local raw_pixels = {}
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
local raw_pixel = string.char(pixel[1])
raw_pixels[#raw_pixels + 1] = raw_pixel
end
end
self.data = self.data .. table.concat(raw_pixels)
end
function image:encode_data_R8G8B8_as_Y8_raw()
assert(24 == self.pixel_depth)
local raw_pixels = {}
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
-- the HSP RGB to brightness formula is
-- sqrt( 0.299 r² + .587 g² + .114 b² )
-- see <https://alienryderflex.com/hsp.html>
local gray = math.floor(
math.sqrt(
0.299 * pixel[1]^2 +
0.587 * pixel[2]^2 +
0.114 * pixel[3]^2
) + 0.5
)
local raw_pixel = string.char(gray)
raw_pixels[#raw_pixels + 1] = raw_pixel
end
end
self.data = self.data .. table.concat(raw_pixels)
end
function image:encode_data_R8G8B8_as_A1R5G5B5_raw()
assert(24 == self.pixel_depth)
local raw_pixels = {}
-- Sample depth rescaling is done according to the algorithm presented in:
-- <https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling>
local max_sample_in = math.pow(2, 8) - 1
local max_sample_out = math.pow(2, 5) - 1
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
local colorword = 32768 +
((math.floor((pixel[1] * max_sample_out / max_sample_in) + 0.5)) * 1024) +
((math.floor((pixel[2] * max_sample_out / max_sample_in) + 0.5)) * 32) +
((math.floor((pixel[3] * max_sample_out / max_sample_in) + 0.5)) * 1)
local raw_pixel = string.char(colorword % 256, math.floor(colorword / 256))
raw_pixels[#raw_pixels + 1] = raw_pixel
end
end
self.data = self.data .. table.concat(raw_pixels)
end
function image:encode_data_R8G8B8_as_A1R5G5B5_rle()
assert(24 == self.pixel_depth)
local colorword = nil
local previous_r = nil
local previous_g = nil
local previous_b = nil
local raw_pixel = ''
local raw_pixels = {}
function image:encode_data()
local current_pixel = ''
local previous_pixel = ''
local count = 1
local packets = {}
local raw_packet = ''
local rle_packet = ''
-- Sample depth rescaling is done according to the algorithm presented in:
-- <https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling>
local max_sample_in = math.pow(2, 8) - 1
local max_sample_out = math.pow(2, 5) - 1
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
if pixel[1] ~= previous_r or pixel[2] ~= previous_g or pixel[3] ~= previous_b or count == 128 then
if nil ~= previous_r then
colorword = 32768 +
((math.floor((previous_r * max_sample_out / max_sample_in) + 0.5)) * 1024) +
((math.floor((previous_g * max_sample_out / max_sample_in) + 0.5)) * 32) +
((math.floor((previous_b * max_sample_out / max_sample_in) + 0.5)) * 1)
if 1 == count then
-- remember pixel verbatim for raw encoding
raw_pixel = string.char(colorword % 256, math.floor(colorword / 256))
raw_pixels[#raw_pixels + 1] = raw_pixel
if 128 == #raw_pixels then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
else
-- encode raw pixels, if any
if #raw_pixels > 0 then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
-- RLE encoding
rle_packet = string.char(128 + count - 1, colorword % 256, math.floor(colorword / 256))
packets[#packets +1] = rle_packet
end
end
count = 1
previous_r = pixel[1]
previous_g = pixel[2]
previous_b = pixel[3]
else
count = count + 1
end
end
end
colorword = 32768 +
((math.floor((previous_r * max_sample_out / max_sample_in) + 0.5)) * 1024) +
((math.floor((previous_g * max_sample_out / max_sample_in) + 0.5)) * 32) +
((math.floor((previous_b * max_sample_out / max_sample_in) + 0.5)) * 1)
if 1 == count then
raw_pixel = string.char(colorword % 256, math.floor(colorword / 256))
raw_pixels[#raw_pixels + 1] = raw_pixel
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
else
-- encode raw pixels, if any
if #raw_pixels > 0 then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
-- RLE encoding
rle_packet = string.char(128 + count - 1, colorword % 256, math.floor(colorword / 256))
packets[#packets +1] = rle_packet
end
self.data = self.data .. table.concat(packets)
end
function image:encode_data_R8G8B8_as_B8G8R8_raw()
assert(24 == self.pixel_depth)
local raw_pixels = {}
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
local raw_pixel = string.char(pixel[3], pixel[2], pixel[1])
raw_pixels[#raw_pixels + 1] = raw_pixel
end
end
self.data = self.data .. table.concat(raw_pixels)
end
function image:encode_data_R8G8B8_as_B8G8R8_rle()
assert(24 == self.pixel_depth)
local previous_r = nil
local previous_g = nil
local previous_b = nil
local raw_pixel = ''
local raw_pixels = {}
local count = 1
local packets = {}
local raw_packet = ''
local rle_packet = ''
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
if pixel[1] ~= previous_r or pixel[2] ~= previous_g or pixel[3] ~= previous_b or count == 128 then
if nil ~= previous_r then
if 1 == count then
-- remember pixel verbatim for raw encoding
raw_pixel = string.char(previous_b, previous_g, previous_r)
raw_pixels[#raw_pixels + 1] = raw_pixel
if 128 == #raw_pixels then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
else
-- encode raw pixels, if any
if #raw_pixels > 0 then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
-- RLE encoding
rle_packet = string.char(128 + count - 1, previous_b, previous_g, previous_r)
packets[#packets +1] = rle_packet
end
end
current_pixel = string.char(pixel[3], pixel[2], pixel[1])
if current_pixel ~= previous_pixel or count == 128 then
packets[#packets +1] = rle_packet
count = 1
previous_r = pixel[1]
previous_g = pixel[2]
previous_b = pixel[3]
previous_pixel = current_pixel
else
count = count + 1
end
rle_packet = string.char(128 + count - 1) .. current_pixel
end
end
if 1 == count then
raw_pixel = string.char(previous_b, previous_g, previous_r)
raw_pixels[#raw_pixels + 1] = raw_pixel
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
else
-- encode raw pixels, if any
if #raw_pixels > 0 then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
-- RLE encoding
rle_packet = string.char(128 + count - 1, previous_b, previous_g, previous_r)
packets[#packets +1] = rle_packet
end
self.data = self.data .. table.concat(packets)
end
function image:encode_data_R8G8B8A8_as_B8G8R8A8_raw()
assert(32 == self.pixel_depth)
local raw_pixels = {}
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
local raw_pixel = string.char(pixel[3], pixel[2], pixel[1], pixel[4])
raw_pixels[#raw_pixels + 1] = raw_pixel
end
end
self.data = self.data .. table.concat(raw_pixels)
end
function image:encode_data_R8G8B8A8_as_B8G8R8A8_rle()
assert(32 == self.pixel_depth)
local previous_r = nil
local previous_g = nil
local previous_b = nil
local previous_a = nil
local raw_pixel = ''
local raw_pixels = {}
local count = 1
local packets = {}
local raw_packet = ''
local rle_packet = ''
for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do
if pixel[1] ~= previous_r or pixel[2] ~= previous_g or pixel[3] ~= previous_b or pixel[4] ~= previous_a or count == 128 then
if nil ~= previous_r then
if 1 == count then
-- remember pixel verbatim for raw encoding
raw_pixel = string.char(previous_b, previous_g, previous_r, previous_a)
raw_pixels[#raw_pixels + 1] = raw_pixel
if 128 == #raw_pixels then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
else
-- encode raw pixels, if any
if #raw_pixels > 0 then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
-- RLE encoding
rle_packet = string.char(128 + count - 1, previous_b, previous_g, previous_r, previous_a)
packets[#packets +1] = rle_packet
end
end
count = 1
previous_r = pixel[1]
previous_g = pixel[2]
previous_b = pixel[3]
previous_a = pixel[4]
else
count = count + 1
end
end
end
if 1 == count then
raw_pixel = string.char(previous_b, previous_g, previous_r, previous_a)
raw_pixels[#raw_pixels + 1] = raw_pixel
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
else
-- encode raw pixels, if any
if #raw_pixels > 0 then
raw_packet = string.char(#raw_pixels - 1)
packets[#packets + 1] = raw_packet
for i=1, #raw_pixels do
packets[#packets +1] = raw_pixels[i]
end
raw_pixels = {}
end
-- RLE encoding
rle_packet = string.char(128 + count - 1, previous_b, previous_g, previous_r, previous_a)
packets[#packets +1] = rle_packet
end
packets[#packets +1] = rle_packet
self.data = self.data .. table.concat(packets)
end
@ -581,45 +75,15 @@ function image:encode_footer()
.. string.char(0)
end
function image:encode(properties)
local properties = properties or {}
properties.colormap = properties.colormap or {}
properties.compression = properties.compression or "RAW"
properties.scanline_order = properties.scanline_order or "bottom-top"
self.pixel_depth = #self.pixels[1][1] * 8
local color_format_defaults_by_pixel_depth = {
[8] = "Y8",
[24] = "B8G8R8",
[32] = "B8G8R8A8",
}
if nil == properties.color_format then
if 0 ~= #properties.colormap then
properties.color_format =
color_format_defaults_by_pixel_depth[
#properties.colormap[1] * 8
]
else
properties.color_format =
color_format_defaults_by_pixel_depth[
self.pixel_depth
]
end
end
assert( nil ~= properties.color_format )
self.data = ""
self:encode_header(properties) -- header
function image:encode()
self:encode_header() -- header
-- no color map and image id data
self:encode_data(properties) -- encode data
self:encode_data() -- encode data
-- no extension or developer area
self:encode_footer() -- footer
end
function image:save(filename, properties)
self:encode(properties)
function image:save(filename)
local f = assert(io.open(filename, "wb"))
f:write(self.data)
f:close()

View File

@ -1,51 +0,0 @@
dofile("init.lua")
local colormap = {
{ 0, 0, 0 }, -- black
{ 255, 255, 255 }, -- white
{ 255, 0, 0 }, -- red
{ 0, 255, 0 }, -- green
{ 0, 0, 255 }, -- blue
}
local _ = { 0 }
local W = { 1 }
local R = { 2 }
local G = { 3 }
local B = { 4 }
local pixels_tiny = {
{ W, W, W, W, W, W, W, W, W, W, W, W, },
{ W, _, _, _, _, _, _, _, _, _, _, W, },
{ W, _, _, _, _, _, _, B, _, B, _, W, },
{ W, _, _, _, _, _, _, B, B, B, _, W, },
{ W, _, _, _, G, G, G, B, _, B, _, W, },
{ W, _, _, _, G, _, G, B, B, B, _, W, },
{ W, _, _, R, G, _, _, _, _, _, _, W, },
{ W, _, _, R, G, G, G, _, _, _, _, W, },
{ W, _, _, R, _, _, _, _, _, _, _, W, },
{ W, _, R, R, R, _, _, _, _, _, _, W, },
{ W, _, _, _, _, _, _, _, _, _, _, W, },
{ W, W, W, W, W, W, W, W, W, W, W, W, },
}
local pixels_huge = {}
local size_tiny = #pixels_tiny
local size_huge = 1200
local scale = size_huge / size_tiny
for x_huge = 1,size_huge,1 do
local x_tiny = math.ceil( x_huge / scale )
for z_huge = 1,size_huge,1 do
local z_tiny = math.ceil( z_huge / scale )
if nil == pixels_huge[z_huge] then
pixels_huge[z_huge] = {}
end
pixels_huge[z_huge][x_huge] = pixels_tiny[z_tiny][x_tiny]
end
end
tga_encoder.image(pixels_tiny):save("logo_tiny.tga", {colormap=colormap})
tga_encoder.image(pixels_huge):save("logo_huge.tga", {colormap=colormap})

View File

@ -1,2 +1,3 @@
name = tga_encoder
author = Fleckenstein
description = A TGA Encoder written in Lua without the use of external Libraries.

View File

@ -1,180 +0,0 @@
#!/usr/bin/env lua5.1
dofile("../init.lua")
local _ = { 0 }
local R = { 1 }
local G = { 2 }
local B = { 3 }
local pixels_colormapped_bt = {
{ _, _, _, _, _, B, _, B, },
{ _, _, _, _, _, B, B, B, },
{ _, _, G, G, G, B, _, B, },
{ _, _, G, _, G, B, B, B, },
{ _, R, G, _, _, _, _, _, },
{ _, R, G, G, G, _, _, _, },
{ _, R, _, _, _, _, _, _, },
{ R, R, R, _, _, _, _, _, },
}
local pixels_colormapped_tb = {
{ R, R, R, _, _, _, _, _, },
{ _, R, _, _, _, _, _, _, },
{ _, R, G, G, G, _, _, _, },
{ _, R, G, _, _, _, _, _, },
{ _, _, G, _, G, B, B, B, },
{ _, _, G, G, G, B, _, B, },
{ _, _, _, _, _, B, B, B, },
{ _, _, _, _, _, B, _, B, },
}
image_colormapped_bt = tga_encoder.image(pixels_colormapped_bt)
image_colormapped_tb = tga_encoder.image(pixels_colormapped_tb)
colormap_32bpp = {
{ 0, 0, 0, 128 },
{ 255, 0, 0, 255 },
{ 0, 255, 0, 255 },
{ 0, 0, 255, 255 },
}
image_colormapped_bt:save(
"type1_32bpp_bt.tga",
{ colormap = colormap_32bpp, color_format = "B8G8R8A8", scanline_order = "bottom-top" }
)
image_colormapped_tb:save(
"type1_32bpp_tb.tga",
{ colormap = colormap_32bpp, color_format = "B8G8R8A8", scanline_order = "top-bottom" }
)
image_colormapped_bt:save(
"type1_16bpp_bt.tga",
{ colormap = colormap_32bpp, color_format = "A1R5G5B5", scanline_order = "bottom-top" }
)
image_colormapped_tb:save(
"type1_16bpp_tb.tga",
{ colormap = colormap_32bpp, color_format = "A1R5G5B5", scanline_order = "top-bottom" }
)
colormap_24bpp = {
{ 0, 0, 0 },
{ 255, 0, 0 },
{ 0, 255, 0 },
{ 0, 0, 255 },
}
image_colormapped_bt:save(
"type1_24bpp_bt.tga",
{ colormap = colormap_32bpp, color_format = "B8G8R8", scanline_order = "bottom-top" }
)
image_colormapped_tb:save(
"type1_24bpp_tb.tga",
{ colormap = colormap_32bpp, color_format = "B8G8R8", scanline_order = "top-bottom" }
)
local _ = { 0, 0, 0, 128 }
local R = { 255, 0, 0, 255 }
local G = { 0, 255, 0, 255 }
local B = { 0, 0, 255, 255 }
local pixels_rgba_bt = {
{ _, _, _, _, _, B, _, B, },
{ _, _, _, _, _, B, B, B, },
{ _, _, G, G, G, B, _, B, },
{ _, _, G, _, G, B, B, B, },
{ _, R, G, _, _, _, _, _, },
{ _, R, G, G, G, _, _, _, },
{ _, R, _, _, _, _, _, _, },
{ R, R, R, _, _, _, _, _, },
}
local pixels_rgba_tb = {
{ R, R, R, _, _, _, _, _, },
{ _, R, _, _, _, _, _, _, },
{ _, R, G, G, G, _, _, _, },
{ _, R, G, _, _, _, _, _, },
{ _, _, G, _, G, B, B, B, },
{ _, _, G, G, G, B, _, B, },
{ _, _, _, _, _, B, B, B, },
{ _, _, _, _, _, B, _, B, },
}
image_rgba_bt = tga_encoder.image(pixels_rgba_bt)
image_rgba_tb = tga_encoder.image(pixels_rgba_tb)
image_rgba_bt:save(
"type2_32bpp_bt.tga",
{ color_format="B8G8R8A8", compression="RAW", scanline_order = "bottom-top" }
)
image_rgba_tb:save(
"type2_32bpp_tb.tga",
{ color_format="B8G8R8A8", compression="RAW", scanline_order = "top-bottom" }
)
image_rgba_bt:save(
"type10_32bpp_bt.tga",
{ color_format="B8G8R8A8", compression="RLE", scanline_order = "bottom-top" }
)
image_rgba_tb:save(
"type10_32bpp_tb.tga",
{ color_format="B8G8R8A8", compression="RLE", scanline_order = "top-bottom" }
)
local _ = { 0, 0, 0 }
local R = { 255, 0, 0 }
local G = { 0, 255, 0 }
local B = { 0, 0, 255 }
local pixels_rgb_bt = {
{ _, _, _, _, _, B, _, B, },
{ _, _, _, _, _, B, B, B, },
{ _, _, G, G, G, B, _, B, },
{ _, _, G, _, G, B, B, B, },
{ _, R, G, _, _, _, _, _, },
{ _, R, G, G, G, _, _, _, },
{ _, R, _, _, _, _, _, _, },
{ R, R, R, _, _, _, _, _, },
}
local pixels_rgb_tb = {
{ R, R, R, _, _, _, _, _, },
{ _, R, _, _, _, _, _, _, },
{ _, R, G, G, G, _, _, _, },
{ _, R, G, _, _, _, _, _, },
{ _, _, G, _, G, B, B, B, },
{ _, _, G, G, G, B, _, B, },
{ _, _, _, _, _, B, B, B, },
{ _, _, _, _, _, B, _, B, },
}
image_rgb_bt = tga_encoder.image(pixels_rgb_bt)
image_rgb_tb = tga_encoder.image(pixels_rgb_tb)
image_rgb_bt:save(
"type2_24bpp_bt.tga",
{ color_format="B8G8R8", compression="RAW", scanline_order = "bottom-top" }
)
image_rgb_tb:save(
"type2_24bpp_tb.tga",
{ color_format="B8G8R8", compression="RAW", scanline_order = "top-bottom" }
)
image_rgb_bt:save(
"type10_24bpp_bt.tga",
{ color_format="B8G8R8", compression="RLE", scanline_order = "bottom-top" }
)
image_rgb_tb:save(
"type10_24bpp_tb.tga",
{ color_format="B8G8R8", compression="RLE", scanline_order = "top-bottom" }
)
image_rgb_bt:save(
"type2_16bpp_bt.tga",
{ color_format="A1R5G5B5", compression="RAW", scanline_order = "bottom-top" }
)
image_rgb_tb:save(
"type2_16bpp_tb.tga",
{ color_format="A1R5G5B5", compression="RAW", scanline_order = "top-bottom" }
)
image_rgb_bt:save(
"type10_16bpp_bt.tga",
{ color_format="A1R5G5B5", compression="RLE", scanline_order = "bottom-top" }
)
image_rgb_tb:save(
"type10_16bpp_tb.tga",
{ color_format="A1R5G5B5", compression="RLE", scanline_order = "top-bottom" }
)

View File

@ -168,7 +168,7 @@ end
function boat.on_activate(self, staticdata, dtime_s)
self.object:set_armor_groups({fleshy = 125})
self.object:set_armor_groups({fleshy = 100})
local data = minetest.deserialize(staticdata)
if type(data) == "table" then
self._v = data.v

View File

@ -6,6 +6,9 @@ local pool = {}
local tick = false
minetest.register_on_joinplayer(function(player)
pool[player:get_player_name()] = 0
end)
@ -110,55 +113,6 @@ local function disable_physics(object, luaentity, ignore_check, reset_movement)
end
end
local function try_object_pickup(player, inv, object, checkpos)
if not inv then return end
local le = object:get_luaentity()
-- Check magnet timer
if not (le._magnet_timer >= 0) then return end
if not (le._magnet_timer < item_drop_settings.magnet_time) then return end
-- Don't try to collect again
if le._removed then return end
-- Ignore if itemstring is not set yet
if le.itemstring == "" then return end
-- Add what we can to the inventory
local itemstack = ItemStack(le.itemstring)
local leftovers = inv:add_item("main", itemstack )
check_pickup_achievements(object, player)
if leftovers:is_empty() then
-- Destroy entity
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
le.target = checkpos
le._removed = true
-- Stop the object
object:set_velocity(vector.zero())
object:set_acceleration(vector.zero())
object:move_to(checkpos)
-- Update sound pool
local name = player:get_player_name()
pool[name] = ( pool[name] or 0 ) + 1
-- Make sure the object gets removed
minetest.after(0.25, function()
--safety check
if object and object:get_luaentity() then
object:remove()
end
end)
else
-- Update entity itemstring
le.itemstring = leftovers:to_string()
end
end
minetest.register_globalstep(function(_)
tick = not tick
@ -169,17 +123,17 @@ minetest.register_globalstep(function(_)
local pos = player:get_pos()
if tick == true and (pool[name] or 0) > 0 then
if tick == true and pool[name] > 0 then
minetest.sound_play("item_drop_pickup", {
pos = pos,
gain = 0.3,
max_hear_distance = 16,
pitch = math.random(70, 110) / 100
})
if (pool[name] or 0) > 6 then
if pool[name] > 6 then
pool[name] = 6
else
pool[name] = (pool[name] or 1) - 1
pool[name] = pool[name] - 1
end
end
@ -193,7 +147,40 @@ minetest.register_globalstep(function(_)
object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer
and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
try_object_pickup( player, inv, object, checkpos )
if object:get_luaentity()._magnet_timer >= 0 and
object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and
inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
-- Collection
if not object:get_luaentity()._removed then
-- Ignore if itemstring is not set yet
if object:get_luaentity().itemstring ~= "" then
inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
check_pickup_achievements(object, player)
-- Destroy entity
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
object:get_luaentity().target = checkpos
object:get_luaentity()._removed = true
object:set_velocity(vector.zero())
object:set_acceleration(vector.zero())
object:move_to(checkpos)
pool[name] = pool[name] + 1
minetest.after(0.25, function()
--safety check
if object and object:get_luaentity() then
object:remove()
end
end)
end
end
end
elseif not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "mcl_experience:orb" then
local entity = object:get_luaentity()
entity.collector = player:get_player_name()

View File

@ -134,34 +134,4 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
end
end
return {x=0, y=0, z=0}
end
local plane_adjacents = {
vector.new(-1,0,0),
vector.new(1,0,0),
vector.new(0,0,-1),
vector.new(0,0,1),
}
function mcl_minecarts:get_start_direction(pos)
local dir
local i = 0
while (not dir and i < #plane_adjacents) do
i = i+1
local node = minetest.get_node_or_nil(vector.add(pos, plane_adjacents[i]))
if node ~= nil
and minetest.get_item_group(node.name, "rail") == 0
and minetest.get_item_group(node.name, "solid") == 1
and minetest.get_item_group(node.name, "opaque") == 1
then
dir = mcl_minecarts:check_front_up_down(pos, vector.multiply(plane_adjacents[i], -1), true)
end
end
return dir
end
function mcl_minecarts:set_velocity(obj, dir, factor)
obj._velocity = vector.multiply(dir, factor or 3)
obj._old_pos = nil
obj._punched = true
end
end

View File

@ -241,7 +241,9 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
if vector.equals(cart_dir, {x=0, y=0, z=0}) then
return
end
mcl_minecarts:set_velocity(self, cart_dir)
self._velocity = vector.multiply(cart_dir, 3)
self._old_pos = nil
self._punched = true
return
end
@ -298,7 +300,9 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
time_from_last_punch = math.min(time_from_last_punch, tool_capabilities.full_punch_interval)
local f = 3 * (time_from_last_punch / tool_capabilities.full_punch_interval)
mcl_minecarts:set_velocity(self, cart_dir, f)
self._velocity = vector.multiply(cart_dir, f)
self._old_pos = nil
self._punched = true
end
cart.on_activate_by_rail = on_activate_by_rail
@ -466,7 +470,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
return
end
local dir, last_switch, restart_pos = nil, nil, nil
local dir, last_switch = nil, nil
if not pos then
pos = self.object:get_pos()
end
@ -493,9 +497,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
minetest.swap_node(rou_pos, newnode)
mesecon.receptor_on(rou_pos)
end
if node.name == "mcl_minecarts:golden_rail_on" then
restart_pos = rou_pos
end
if node_old.name == "mcl_minecarts:detector_rail_on" then
local newnode = {name="mcl_minecarts:detector_rail", param2 = node_old.param2}
minetest.swap_node(rou_old, newnode)
@ -646,14 +647,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
if update.pos then
self.object:set_pos(pos)
end
-- stopped on "mcl_minecarts:golden_rail_on"
if vector.equals(vel, {x=0, y=0, z=0}) and restart_pos then
local dir = mcl_minecarts:get_start_direction(restart_pos)
if dir then
mcl_minecarts:set_velocity(self, dir)
end
end
end
function cart:get_staticdata()
@ -694,15 +687,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
if le then
le._railtype = railtype
end
local cart_dir
if node.name == "mcl_minecarts:golden_rail_on" then
cart_dir = mcl_minecarts:get_start_direction(railpos)
end
if cart_dir then
mcl_minecarts:set_velocity(le, cart_dir)
else
cart_dir = mcl_minecarts:get_rail_direction(railpos, {x=1, y=0, z=0}, nil, nil, railtype)
end
local cart_dir = mcl_minecarts:get_rail_direction(railpos, {x=1, y=0, z=0}, nil, nil, railtype)
cart:set_yaw(minetest.dir_to_yaw(cart_dir))
local pname = ""

View File

@ -112,22 +112,6 @@ register_rail("mcl_minecarts:golden_rail_on",
onstate = "mcl_minecarts:golden_rail_on",
rules = rail_rules_long,
},
effector = {
action_on = function(pos, node)
local dir = mcl_minecarts:get_start_direction(pos)
if not dir then return end
local objs = minetest.get_objects_inside_radius(pos, 1)
for _, o in pairs(objs) do
local l = o:get_luaentity()
local v = o:get_velocity()
if l and string.sub(l.name, 1, 14) == "mcl_minecarts:"
and v and vector.equals(v, vector.zero())
then
mcl_minecarts:set_velocity(l, dir)
end
end
end,
},
},
drop = "mcl_minecarts:golden_rail",
},

View File

@ -322,7 +322,7 @@ function mob_class:toggle_sit(clicker,p)
particle = "mobs_mc_wolf_icon_roam.png"
self.order = "roam"
self.state = "stand"
self.walk_chance = 50
self.walk_chance = default_walk_chance
self.jump = true
self:set_animation("stand")
-- TODO: Add sitting model

View File

@ -325,19 +325,12 @@ function mcl_mobs.register_mob(name, def)
_spawner = def._spawner,
}
minetest.register_entity(name, setmetatable(final_def,mcl_mobs.mob_class_meta))
if minetest.get_modpath("doc_identifier") ~= nil then
doc.sub.identifier.register_object(name, "basics", "mobs")
if def.unused ~= true then
doc.add_entry("mobs", name, {
name = def.description or name,
data = final_def,
})
end
end
minetest.register_entity(name, setmetatable(final_def,mcl_mobs.mob_class_meta))
end -- END mcl_mobs.register_mob function
@ -374,7 +367,7 @@ function mcl_mobs.register_arrow(name, def)
rotate = def.rotate,
on_punch = def.on_punch or function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
local vel = self.object:get_velocity():length()
self.object:set_velocity(dir * vel)
self.object:set_velocity({x=dir.x * vel, y=dir.y * vel, z=dir.z * vel})
self._puncher = puncher
end,
collisionbox = def.collisionbox or {0, 0, 0, 0, 0, 0},

View File

@ -87,8 +87,7 @@ function mob_class:check_item_pickup()
end
if self.pick_up then
for k,v in pairs(self.pick_up) do
local itemstack = ItemStack(l.itemstring)
if not player_near(p) and self.on_pick_up and itemstack:get_name():find(v) then
if not player_near(p) and self.on_pick_up and l.itemstring:find(v) then
local r = self.on_pick_up(self,l)
if r and r.is_empty and not r:is_empty() then
l.itemstring = r:to_string()

View File

@ -13,7 +13,7 @@ local get_node = minetest.get_node
local get_item_group = minetest.get_item_group
local get_node_light = minetest.get_node_light
local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
local mt_get_biome_name = minetest.get_biome_name
local get_biome_name = minetest.get_biome_name
local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_connected_players = minetest.get_connected_players
@ -664,29 +664,7 @@ local function has_room(self,pos)
return true
end
mcl_mobs.custom_biomecheck = nil
function mcl_mobs.register_custom_biomecheck(custom_biomecheck)
mcl_mobs.custom_biomecheck = custom_biomecheck
end
local function get_biome_name(pos)
if mcl_mobs.custom_biomecheck then
return mcl_mobs.custom_biomecheck (pos)
else
local gotten_biome = minetest.get_biome_data(pos)
if not gotten_biome then
return
end
gotten_biome = mt_get_biome_name(gotten_biome.biome)
--minetest.log ("biome: " .. dump(gotten_biome))
return gotten_biome
end
end
local function spawn_check(pos, spawn_def)
if not spawn_def or not pos then return end
@ -696,10 +674,11 @@ local function spawn_check(pos, spawn_def)
local mob_def = minetest.registered_entities[spawn_def.name]
local mob_type = mob_def.type
local gotten_node = get_node(pos).name
if not gotten_node then return end
local gotten_biome = minetest.get_biome_data(pos)
local biome_name = get_biome_name(pos)
if not biome_name then return end
if not gotten_node or not gotten_biome then return end
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
local is_ground = minetest.get_item_group(gotten_node,"solid") ~= 0
if not is_ground then
@ -717,9 +696,8 @@ local function spawn_check(pos, spawn_def)
if pos.y >= spawn_def.min_height
and pos.y <= spawn_def.max_height
and spawn_def.dimension == dimension
and biome_check(spawn_def.biomes, biome_name) then
and biome_check(spawn_def.biomes, gotten_biome) then
mcl_log("Spawn level 1 check - Passed")
if (is_ground or spawn_def.type_of_spawning ~= "ground")
and (spawn_def.type_of_spawning ~= "ground" or not is_leaf)
and (not is_farm_animal(spawn_def.name) or is_grass)
@ -729,7 +707,6 @@ local function spawn_check(pos, spawn_def)
and (spawn_def.check_position and spawn_def.check_position(pos) or spawn_def.check_position == nil)
and ( not spawn_protected or not minetest.is_protected(pos, "") ) then
mcl_log("Spawn level 2 check - Passed")
local gotten_light = get_node_light(pos)
if modern_lighting then

View File

@ -1,7 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname())
local axolotl = {
description = S("Axolotl"),
type = "animal",
spawn_class = "axolotl",
can_despawn = true,

View File

@ -30,7 +30,6 @@ local S = minetest.get_translator(minetest.get_current_modname())
--###################
local cod = {
description = S("Cod"),
type = "animal",
spawn_class = "water_ambient",
can_despawn = true,

View File

@ -136,7 +136,7 @@ mcl_mobs.register_mob("mobs_mc:creeper", {
})
mcl_mobs.register_mob("mobs_mc:creeper_charged", {
description = S("Charged Creeper"),
description = S("Creeper"),
type = "monster",
spawn_class = "hostile",
hp_min = 20,

View File

@ -30,7 +30,6 @@ local S = minetest.get_translator(minetest.get_current_modname())
--###################
local dolphin = {
description = S("Dolphin"),
type = "animal",
spawn_class = "water",
can_despawn = true,

View File

@ -126,14 +126,13 @@ mcl_mobs.register_arrow("mobs_mc:fireball", {
end,
hit_mob = function(self, mob)
local name = mob:get_luaentity().name
mob:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 6},
}, nil)
mcl_mobs.mob_class.boom(self,self.object:get_pos(), 1, true)
local ent = mob:get_luaentity()
if (not ent or ent.health <= 0) and self._puncher and name == "mobs_mc:ghast" then
if not ent or ent.health <= 0 then
awards.unlock(self._puncher:get_player_name(), "mcl:fireball_redir_serv")
end
end,

View File

@ -30,7 +30,6 @@ for i=1,4 do
end
mcl_mobs.register_mob("mobs_mc:glow_squid", {
description = S("Glow Squid"),
type = "animal",
spawn_class = "water_underground",
can_despawn = true,

View File

@ -122,10 +122,10 @@ local horse = {
stand_speed = 25,
stand_start = 0,
stand_end = 0,
walk_speed = 100,
walk_speed = 25,
walk_start = 0,
walk_end = 40,
run_speed = 200,
run_speed = 60,
run_start = 0,
run_end = 40,
},
@ -543,6 +543,11 @@ donkey.description = S("Donkey")
donkey.textures = {{"blank.png", "mobs_mc_donkey.png", "blank.png"}}
donkey.spawn_in_group = 3
donkey.spawn_in_group_min = 1
donkey.animation = {
speed_normal = 25,
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40,
}
donkey.sounds = {
random = "mobs_mc_donkey_random",
damage = "mobs_mc_donkey_hurt",

View File

@ -16,13 +16,6 @@ local trading_items = {
{ itemstring = "mcl_throwing:ender_pearl", amount_min = 2, amount_max = 6 },
{ itemstring = "mcl_potions:fire_resistance", amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_potions:fire_resistance_splash", amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_enchanting:book_enchanted", amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_armor:boots_iron_enchanted", amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_blackstone:blackstone", amount_min = 8, amount_max = 16 },
{ itemstring = "mcl_bows:arrow", amount_min = 6, amount_max = 12 },
{ itemstring = "mcl_core:crying_obsidian", amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_fire:fire_charge", amount_min = 1, amount_max = 1 },
--{ itemstring = "FIXME:spectral_arrow", amount_min = 6, amount_max = 12 },
}
local S = minetest.get_translator("mobs_mc")
@ -149,18 +142,14 @@ local piglin = {
local c_pos = self.object:get_pos()
if c_pos then
self.what_traded = trading_items[math.random(#trading_items)]
local stack = ItemStack(self.what_traded.itemstring)
stack:set_count(math.random(self.what_traded.amount_min, self.what_traded.amount_max))
if mcl_enchanting.is_enchanted(self.what_traded.itemstring) then
local enchantment = "soul_speed"
mcl_enchanting.enchant(stack, enchantment, mcl_enchanting.random(nil, 1, mcl_enchanting.enchantments[enchantment].max_level))
for x = 1, math.random(self.what_traded.amount_min, self.what_traded.amount_max) do
local p = c_pos
local nn=minetest.find_nodes_in_area_under_air(vector.offset(c_pos,-1,-1,-1),vector.offset(c_pos,1,1,1),{"group:solid"})
if nn and #nn > 0 then
p = vector.offset(nn[math.random(#nn)],0,1,0)
end
minetest.add_item(p, self.what_traded.itemstring)
end
local p = c_pos
local nn=minetest.find_nodes_in_area_under_air(vector.offset(c_pos,-1,-1,-1),vector.offset(c_pos,1,1,1),{"group:solid"})
if nn and #nn > 0 then
p = vector.offset(nn[math.random(#nn)],0,1,0)
end
minetest.add_item(p, stack)
end
end)
end
@ -343,13 +332,8 @@ mcl_mobs.register_mob("mobs_mc:baby_zombified_piglin", baby_zombified_piglin)
-- Compatibility code. These were removed, and now are called zombie piglins. They don't spawn.
-- This is only to catch old cases. Maybe could be an alias?
local pigman_unused = table.copy(zombified_piglin)
pigman_unused.unused = true
local baby_pigman_unused = table.copy(baby_zombified_piglin)
baby_pigman_unused.unused = true
mcl_mobs.register_mob("mobs_mc:pigman", pigman_unused)
mcl_mobs.register_mob("mobs_mc:baby_pigman", baby_pigman_unused)
mcl_mobs.register_mob("mobs_mc:pigman", zombified_piglin)
mcl_mobs.register_mob("mobs_mc:baby_pigman", baby_zombified_piglin)
-- Piglin Brute --

View File

@ -10,7 +10,6 @@ local S = minetest.get_translator(minetest.get_current_modname())
--###################
local salmon = {
description = S("Salmon"),
type = "animal",
spawn_class = "water_ambient",
can_despawn = true,

View File

@ -44,13 +44,6 @@ local skeleton = {
"mcl_bows_bow_0.png", -- wielded_item
}
},
-- TODO: change random to new api when min minetest version is 5.8
sounds = {
random = "mobs_mc_skeleton_random.2",
death = "mobs_mc_skeleton_death",
damage = "mobs_mc_skeleton_hurt",
distance = 16,
},
walk_velocity = 1.2,
run_velocity = 2.0,
damage = 2,

View File

@ -37,7 +37,7 @@ mcl_mobs.register_mob("mobs_mc:witherskeleton", {
visual_size = {x=1.2, y=1.2},
makes_footstep_sound = true,
sounds = {
random = "mobs_mc_skeleton_random.1",
random = "mobs_mc_skeleton_random",
death = "mobs_mc_skeleton_death",
damage = "mobs_mc_skeleton_hurt",
distance = 16,

View File

@ -176,7 +176,7 @@ end
-- Slime
local slime_big = {
description = S("Slime - big"),
description = S("Slime"),
type = "monster",
spawn_class = "hostile",
group_attack = { "mobs_mc:slime_big", "mobs_mc:slime_small", "mobs_mc:slime_tiny" },
@ -231,7 +231,6 @@ local slime_big = {
mcl_mobs.register_mob("mobs_mc:slime_big", slime_big)
local slime_small = table.copy(slime_big)
slime_small.description = S("Slime - small")
slime_small.sounds.base_pitch = 1.15
slime_small.hp_min = 4
slime_small.hp_max = 4
@ -249,7 +248,6 @@ slime_small.on_die = spawn_children_on_die("mobs_mc:slime_tiny", 0.6, 1.0)
mcl_mobs.register_mob("mobs_mc:slime_small", slime_small)
local slime_tiny = table.copy(slime_big)
slime_tiny.description = S("Slime - tiny")
slime_tiny.sounds.base_pitch = 1.3
slime_tiny.hp_min = 1
slime_tiny.hp_max = 1
@ -399,7 +397,7 @@ swamp_max)
-- Magma cube
local magma_cube_big = {
description = S("Magma Cube - big"),
description = S("Magma Cube"),
type = "monster",
spawn_class = "hostile",
hp_min = 16,
@ -460,7 +458,6 @@ local magma_cube_big = {
mcl_mobs.register_mob("mobs_mc:magma_cube_big", magma_cube_big)
local magma_cube_small = table.copy(magma_cube_big)
magma_cube_small.description = S("Magma Cube - small")
magma_cube_small.sounds.jump = "mobs_mc_magma_cube_small"
magma_cube_small.sounds.death = "mobs_mc_magma_cube_small"
magma_cube_small.hp_min = 4
@ -482,7 +479,6 @@ magma_cube_small.on_die = spawn_children_on_die("mobs_mc:magma_cube_tiny", 0.6,
mcl_mobs.register_mob("mobs_mc:magma_cube_small", magma_cube_small)
local magma_cube_tiny = table.copy(magma_cube_big)
magma_cube_tiny.description = S("Magma Cube - tiny")
magma_cube_tiny.sounds.jump = "mobs_mc_magma_cube_small"
magma_cube_tiny.sounds.death = "mobs_mc_magma_cube_small"
magma_cube_tiny.sounds.base_pitch = 1.25

View File

@ -11,7 +11,6 @@ local S = minetest.get_translator("mobs_mc")
local strider = {
description = S("Strider"),
type = "animal",
passive = true,
spawn_class = "passive",
@ -31,8 +30,6 @@ local strider = {
} },
visual_size = {x=3, y=3},
sounds = {
eat = "mobs_mc_animal_eat_generic",
distance = 16,
},
jump = true,
makes_footstep_sound = true,
@ -54,7 +51,6 @@ local strider = {
walk_start = 1,
walk_end = 20,
},
follow = { "mcl_crimson:warped_fungus" },
lava_damage = 0,
fire_damage = 0,
light_damage = 0,
@ -71,13 +67,8 @@ local strider = {
do_custom = function(self, dtime)
if minetest.find_node_near(self.object:get_pos(), 2, {"mcl_core:lava_source","mcl_core:lava_flowing","mcl_nether:nether_lava_source","mcl_nether:nether_lava_flowing"}) then
if self.driver then
self.walk_velocity = 4
self.run_velocity = 8
else
self.walk_velocity = 2
self.run_velocity = 4
end
self.walk_velocity = 2
self.run_velocity = 4
self.base_texture[1] = "extra_mobs_strider.png"
self.shaking = false
else
@ -131,7 +122,7 @@ local strider = {
local wielditem = clicker:get_wielded_item()
if wielditem:get_name() == "mcl_crimson:warped_fungus" then
if wielditem:get_name() ~= "mcl_crimson:warped_fungus" then
if self:feed_tame(clicker, 1, true, true) then return end
end
@ -206,7 +197,6 @@ mcl_mobs.register_mob("mobs_mc:strider", strider)
-- Baby strider.
local baby_strider = table.copy(strider)
baby_strider.description = S("Baby Strider")
baby_strider.collisionbox = {-.3, -0.01, -.3, .3, 0.94, .3}
baby_strider.xp_min = 13
baby_strider.xp_max = 13
@ -216,7 +206,7 @@ textures = { {
} }
baby_strider.walk_velocity = 1.2
baby_strider.run_velocity = 2.4
baby_strider.child = true
baby_strider.child = 1
mcl_mobs.register_mob("mobs_mc:baby_strider", baby_strider)

View File

@ -58,7 +58,6 @@ local function set_textures(self)
end
local tropical_fish = {
description = S("Tropical Fish"),
type = "animal",
spawn_class = "water_ambient",
can_despawn = true,

View File

@ -1989,17 +1989,6 @@ local trade_inventory = {
-- Otherwise, 20% chance to unlock if used freshly reset trade
unlock_stuff = true
end
-- calculate xp based on the price
local emeralds = 0
if wanted1:get_name() == "mcl_core:emerald" then
emeralds = wanted1:get_count()
elseif wanted2:get_name() == "mcl_core:emerald" then
emeralds = wanted2:get_count()
else
local offered = inv:get_stack("offered", 1)
emeralds = offered:get_name() == "mcl_core:emerald" and offered:get_count() or 0
end
local xp = 2 + math.ceil(emeralds / (64/4)) -- 1..64 emeralds = 3..6 xp
local update_formspec = false
if unlock_stuff then
-- First-time trade unlock all trades and unlock next trade tier
@ -2011,7 +2000,6 @@ local trade_inventory = {
set_textures(trader)
update_max_tradenum(trader)
update_formspec = true
xp = xp + 5
end
for t=1, #trades do
trades[t].locked = false
@ -2022,7 +2010,6 @@ local trade_inventory = {
-- TODO: Replace by Regeneration I
trader.health = math.min(trader.hp_max, trader.health + 4)
end
mcl_experience.add_xp(player, xp)
trade.trade_counter = trade.trade_counter + 1
mcl_log("Trade counter is: ".. trade.trade_counter)
-- Semi-randomly lock trade for repeated trade (not if there's only 1 trade)
@ -2060,7 +2047,6 @@ local trade_inventory = {
if update_formspec then
show_trade_formspec(name, trader, tradenum)
end
else
minetest.log("error", "[mobs_mc] Player took item from trader output but player_trading_with or player_tradenum is nil!")
end

View File

@ -135,7 +135,6 @@ end
-- Tamed wolf (aka “dog”)
local dog = table.copy(wolf)
dog.description = S("Dog")
dog.can_despawn = false
dog.passive = true
dog.hp_min = 20

View File

@ -53,7 +53,7 @@ doc.data = {}
doc.data.categories = {}
doc.data.aliases = {}
-- Default order (includes categories of other mods from the Docuentation System modpack)
doc.data.category_order = {"basics", "nodes", "tools", "craftitems", "advanced", "mobs"}
doc.data.category_order = {"basics", "nodes", "tools", "craftitems", "advanced"}
doc.data.category_count = 0
doc.data.players = {}

View File

@ -116,11 +116,7 @@ function doc_identifier.identify(itemstack, user, pointed_thing)
end
-- A known registered object
elseif ro then
if doc.entry_exists("mobs", le.name) then
doc.show_entry(username, "mobs", le.name, true)
else
doc.show_entry(username, ro.category, ro.entry, true)
end
doc.show_entry(username, ro.category, ro.entry, true)
-- Undefined object (error)
elseif minetest.registered_entities[le.name] == nil then
show_message(username, "error_unknown", le.name)

View File

@ -1136,86 +1136,6 @@ doc.add_category("craftitems", {
end
})
doc.add_category("mobs", {
name = S("Mobs"),
description = S("different mobs"),
build_formspec = function(data, playername)
if data then
local datastring = ""
if data.description then
datastring = datastring .. S("Description: @1", data.description)
datastring = newline2(datastring)
end
if data.type then
datastring = datastring .. S("Type: @1", data.type)
datastring = newline2(datastring)
end
if data.spawn_class then
datastring = datastring .. S("spawn class: @1", data.spawn_class)
datastring = newline2(datastring)
end
if data.jump then
datastring = datastring .. S("Can Jump")
datastring = newline2(datastring)
end
if data.fly then
datastring = datastring .. S("Can Fly")
datastring = newline2(datastring)
end
if data.drops then
count = 0
for _,item in ipairs(data.drops) do
count = count + 1
end
if count > 0 then
datastring = datastring .. S("drops: ")
datastring = newline(datastring)
for _,item in ipairs(data.drops) do
local itemDescription = ItemStack(item.name):get_short_description()
datastring = datastring .. itemDescription
datastring = newline(datastring)
end
datastring = newline2(datastring)
end
end
if data.follow then
datastring = datastring .. S("follows player when these items are held:")
datastring = newline(datastring)
if type(data.follow) == "string" then
datastring = datastring .. data.follow
datastring = newline(datastring)
else
for i=1, #data.follow do
local itemstring = data.follow[i]
local itemDescription = ItemStack(itemstring):get_short_description()
datastring = datastring .. itemDescription
datastring = newline(datastring)
end
end
datastring = newline2(datastring)
end
local formstring = doc.widgets.text(datastring, nil, nil, doc.FORMSPEC.ENTRY_WIDTH - 1.2)
return formstring
else
return "label[0,1;NO DATA AVALIABLE!]"
end
end
})
-- Register group definition stuff
-- More (user-)friendly group names to replace the rather technical names
-- for better understanding

View File

@ -106,31 +106,6 @@ local item_lists = {
"craftpreview",
}
local function init_data(name)
player_data[name] = {
filter = "",
pagenum = 1,
iX = sfinv_only and 8 or DEFAULT_SIZE,
items = init_items,
items_raw = init_items,
lang_code = M.get_player_information(name).lang_code or 'en',
}
end
local function get_player_data(name)
-- If the data alrady exists, use it
local data = player_data[name]
if data then return data end
-- Initialize player data if it doesn't exist
init_data(name)
local player = minetest.get_player_by_name(name)
local meta = player:get_meta()
local data = player_data[name]
data.inv_items = deserialize(meta:get_string("inv_items")) or {}
return data
end
local function table_merge(t, t2)
t, t2 = t or {}, t2 or {}
local c = #t
@ -649,7 +624,7 @@ local function get_recipe_fs(data, iY)
end
local function make_formspec(name)
local data = get_player_data(name)
local data = player_data[name]
local iY = sfinv_only and 4 or data.iX - 5
local ipp = data.iX * iY
@ -856,6 +831,17 @@ local function get_inv_items(player)
return inv_items
end
local function init_data(name)
player_data[name] = {
filter = "",
pagenum = 1,
iX = sfinv_only and 8 or DEFAULT_SIZE,
items = init_items,
items_raw = init_items,
lang_code = M.get_player_information(name).lang_code or 'en',
}
end
local function reset_data(data)
data.filter = ""
data.pagenum = 1
@ -891,7 +877,7 @@ end
local function on_receive_fields(player, fields)
local name = player:get_player_name()
local data = get_player_data(name)
local data = player_data[name]
for elem_name, def in pairs(formspec_elements) do
if fields[elem_name] and def.action then
@ -995,7 +981,7 @@ if sfinv_only then
on_enter = function(self, player, context)
if next(recipe_filters) then
local name = player:get_player_name()
local data = get_player_data(name)
local data = player_data[name]
data.items_raw = get_filtered_items(player)
search(data)
@ -1019,7 +1005,7 @@ else
local name = user:get_player_name()
if next(recipe_filters) then
local data = get_player_data(name)
local data = player_data[name]
data.items_raw = get_filtered_items(user)
search(data)
end
@ -1065,7 +1051,7 @@ if progressive_mode then
local function progressive_filter(recipes, player)
local name = player:get_player_name()
local data = get_player_data(name)
local data = player_data[name]
if #data.inv_items == 0 then
return {}
@ -1090,7 +1076,7 @@ if progressive_mode then
for i = 1, #players do
local player = players[i]
local name = player:get_player_name()
local data = get_player_data(name)
local data = player_data[name]
local inv_items = get_inv_items(player)
local diff = table_diff(inv_items, data.inv_items)
@ -1109,7 +1095,12 @@ if progressive_mode then
mcl_craftguide.add_recipe_filter("Default progressive filter", progressive_filter)
M.register_on_joinplayer(function(player)
get_player_data(player:get_player_name())
local name = player:get_player_name()
init_data(name)
local meta = player:get_meta()
local data = player_data[name]
data.inv_items = deserialize(meta:get_string("inv_items")) or {}
end)
local function save_meta(player)
@ -1154,7 +1145,7 @@ end
function mcl_craftguide.show(name)
local player = get_player_by_name(name)
if next(recipe_filters) then
local data = get_player_data(name)
local data = player_data[name]
data.items_raw = get_filtered_items(player)
search(data)
end

View File

@ -447,8 +447,8 @@ The values for X, Y and Z work like this:=Les valeurs pour X, Y et Z fonctionnen
You can view your current position in the debug screen (open with [F5]).=Vous pouvez afficher votre position actuelle dans l'écran de débogage (ouvrir avec [F5]).
# MCL2 extensions
Creative Mode=Mode créatif
Enabling Creative Mode in MineClone 2 applies the following changes:=L'activation du mode créatif dans MineClone 2 applique les modifications suivantes :
Creative Mode=Mode Creatif
Enabling Creative Mode in MineClone 2 applies the following changes:=L'activation du mode créatif dans MineClone 2 applique les modifications suivantes:
• You keep the things you've placed=• Vous gardez les choses que vous avez placées
• Creative inventory is available to obtain most items easily=• Un inventaire créatif est disponible pour obtenir facilement la plupart des objets
• Hand breaks all default blocks instantly=• La main brise instantanément tous les blocs par défaut

View File

@ -76,7 +76,6 @@ function tt.reload_itemstack_description(itemstack)
orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name"))
end
local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack)
if desc == def.description and meta:get_string("description") == "" then return end
meta:set_string("description", desc)
end
end

View File

@ -15,7 +15,7 @@ Eat a cooked porkchop.=Mangez du porc cuit.
Eat a cooked rabbit.=Mangez du lapin cuit.
Get really desperate and eat rotten flesh.=Soyez vraiment désespéré et mangez de la chair pourrie.
Getting Wood=Obtenir du bois
Getting an Upgrade=Obtenir une amélioration
Getting an Upgrade=Obtenir une augmentation de niveau
Hit a skeleton, wither skeleton or stray by bow and arrow from a distance of at least 20 meters.=Frappez un squelette, wither squelette ou stray à l'arc et à la flèche à une distance d'au moins 20 mètres.
Hot Topic=Sujet brûlant
Into Fire=Dans le feu

View File

@ -177,6 +177,7 @@ minetest.register_entity("mcl_experience:orb", {
delete_timer = 0,
radius = 4,
on_activate = function(self, staticdata, dtime_s)
self.object:set_velocity(vector.new(
math.random(-2,2)*math.random(),
@ -186,14 +187,10 @@ minetest.register_entity("mcl_experience:orb", {
self.object:set_armor_groups({immortal = 1})
self.object:set_velocity({x = 0, y = 2, z = 0})
self.object:set_acceleration(gravity)
-- Assign 0 xp in case the entity was persisted even though it should not have been (static_save = false)
-- This was a minetest bug for a while: https://github.com/minetest/minetest/issues/14420
local xp = tonumber(staticdata) or 0
local xp = tonumber(staticdata)
self._xp = xp
size = xp_to_size(xp)
self.object:set_properties({
size = xp_to_size(xp)
self.object:set_properties({
visual_size = {x = size, y = size},
glow = 14,
})

View File

@ -204,8 +204,7 @@ local function init(player)
local playername = player:get_player_name()
minetest.create_detached_inventory("creative_" .. playername, {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
if minetest.is_creative_enabled(playername) and
from_list ~= to_list then
if minetest.is_creative_enabled(playername) then
return count
else
return 0
@ -542,6 +541,7 @@ function mcl_inventory.set_creative_formspec(player)
"style[" .. this_tab .. ";border=false;bgimg=;bgimg_pressed=;noclip=true]",
"image[" .. offset[this_tab] .. ";1.5,1.44;" .. bg_img .. "]",
"item_image_button[" .. boffset[this_tab] .. ";1,1;" .. tab_icon[this_tab] .. ";" .. this_tab .. ";]",
"tooltip[blocks;" .. F(filtername[this_tab]) .. "]"
})
end
@ -570,33 +570,20 @@ function mcl_inventory.set_creative_formspec(player)
listrings,
tab(name, "blocks") ..
"tooltip[blocks;"..F(filtername["blocks"]).."]"..
tab(name, "deco") ..
"tooltip[deco;"..F(filtername["deco"]).."]"..
tab(name, "redstone") ..
"tooltip[redstone;"..F(filtername["redstone"]).."]"..
tab(name, "rail") ..
"tooltip[rail;"..F(filtername["rail"]).."]"..
tab(name, "misc") ..
"tooltip[misc;"..F(filtername["misc"]).."]"..
tab(name, "nix") ..
"tooltip[nix;"..F(filtername["nix"]).."]"..
tab(name, "blocks"),
tab(name, "deco"),
tab(name, "redstone"),
tab(name, "rail"),
tab(name, "misc"),
tab(name, "nix"),
tab(name, "food") ..
"tooltip[food;"..F(filtername["food"]).."]"..
tab(name, "tools") ..
"tooltip[tools;"..F(filtername["tools"]).."]"..
tab(name, "combat") ..
"tooltip[combat;"..F(filtername["combat"]).."]"..
tab(name, "mobs") ..
"tooltip[mobs;"..F(filtername["mobs"]).."]"..
tab(name, "brew") ..
"tooltip[brew;"..F(filtername["brew"]).."]"..
tab(name, "matr") ..
"tooltip[matr;"..F(filtername["matr"]).."]"..
tab(name, "inv") ..
"tooltip[inv;"..F(filtername["inv"]).."]"
tab(name, "food"),
tab(name, "tools"),
tab(name, "combat"),
tab(name, "mobs"),
tab(name, "brew"),
tab(name, "matr"),
tab(name, "inv"),
})
if name == "nix" then
@ -607,7 +594,6 @@ function mcl_inventory.set_creative_formspec(player)
formspec = formspec .. table.concat({
"field[5.325,0.15;6.1,0.6;search;;" .. minetest.formspec_escape(filter) .. "]",
"field_close_on_enter[search;false]",
"field_enter_after_edit[search;true]",
"set_focus[search;true]",
})
end

View File

@ -36,14 +36,9 @@ function mcl_inventory.register_survival_inventory_tab(def)
end
local player_current_tab = {}
function get_player_tab(player)
local tab = player_current_tab[player] or "main"
player_current_tab[player] = tab
return tab
end
minetest.register_on_joinplayer(function(player, last_login)
get_player_tab(player)
player_current_tab[player] = "main"
end)
minetest.register_on_leaveplayer(function(player, timed_out)
@ -189,7 +184,7 @@ function mcl_inventory.build_survival_formspec(player)
inv:set_width("craft", 2)
inv:set_size("craft", 4)
local tab = get_player_tab(player)
local tab = player_current_tab[player]
local tab_def = nil
@ -218,7 +213,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
for _, d in ipairs(mcl_inventory.registered_survival_inventory_tabs) do
if get_player_tab(player) == d.id and d.access(player) then
if player_current_tab[player] == d.id and d.access(player) then
d.handle(player, fields)
return
end

View File

@ -16,31 +16,19 @@ local function offhand_get_count(player)
return mcl_offhand.get_offhand(player):get_count()
end
local function get_offhand(player)
-- Get offhand data if it already exists
local offhand = mcl_offhand[player]
if offhand then return offhand end
-- Otherwise initialize it
offhand = {
minetest.register_on_joinplayer(function(player, last_login)
mcl_offhand[player] = {
hud = {},
last_wear = offhand_get_wear(player),
last_count = offhand_get_count(player),
}
mcl_offhand[player] = offhand
return offhand
end
minetest.register_on_joinplayer(function(player, last_login)
get_offhand(player)
end)
local function remove_hud(player, hud)
local offhand = get_offhand(player)
local offhand_hud = offhand.hud[hud]
local offhand_hud = mcl_offhand[player].hud[hud]
if offhand_hud then
player:hud_remove(offhand_hud)
offhand.hud[hud] = nil
mcl_offhand[player].hud[hud] = nil
end
end
@ -60,8 +48,7 @@ local function update_wear_bar(player, itemstack)
else
color = {255, 511 - wear_i, 0}
end
local offhand = get_offhand(player)
local wear_bar = offhand.hud.wear_bar
local wear_bar = mcl_offhand[player].hud.wear_bar
player:hud_change(wear_bar, "text", "mcl_wear_bar.png^[colorize:#" .. rgb_to_hex(color[1], color[2], color[3]))
player:hud_change(wear_bar, "scale", {x = 40 * wear_bar_percent, y = 3})
player:hud_change(wear_bar, "offset", {x = -320 - (20 - player:hud_get(wear_bar).scale.x / 2), y = -13})
@ -71,8 +58,7 @@ minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
local itemstack = mcl_offhand.get_offhand(player)
local offhand_item = itemstack:get_name()
local offhand = get_offhand(player)
local offhand_hud = offhand.hud
local offhand_hud = mcl_offhand[player].hud
local item = minetest.registered_items[offhand_item]
if offhand_item ~= "" and item then
local item_texture = item.inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px
@ -159,8 +145,7 @@ minetest.register_globalstep(function(dtime)
end
elseif offhand_hud.slot then
local offhand = get_offhand(player)
for index, _ in pairs(offhand.hud) do
for index, _ in pairs(mcl_offhand[player].hud) do
remove_hud(player, index)
end
end

View File

@ -77,31 +77,16 @@ local function rotate(pos, node, user, mode, new_param2)
end
local creative_dig = {}
local function destruct_bed(pos, oldnode)
local node = oldnode or minetest_get_node_or_nil(pos)
if not node then return end
local pos2, node2, bottom = get_bed_next_node(pos, oldnode)
-- Check creative dig flags and don't drop an item if the bed was dug by a player in
-- creative mode
local pos_hash = minetest.hash_node_position(pos)
local pos2_hash = minetest.hash_node_position(pos2)
local creative_mode = creative_dig[pos_hash] or creative_dig[pos2_hash]
if bottom then
if node2 and string.sub(node2.name, -4) == "_top" then
minetest_remove_node(pos2)
end
-- Drop the bed only when removing the top to prevent duplication and only if
-- it wasn't dug by a player in creative mode
local bed_node_def = minetest.registered_nodes[node.name]
if bed_node_def and bed_node_def._mcl_beds_drop and not creative_mode then
local stack = ItemStack(bed_node_def._mcl_beds_drop)
minetest.add_item(pos2, stack)
end
else
if node2 and string.sub(node2.name, -7) == "_bottom" then
minetest_remove_node(pos2)
@ -109,29 +94,6 @@ local function destruct_bed(pos, oldnode)
end
end
local function dig_bed(pos, node, digger)
local pos_hash = minetest.hash_node_position(pos)
if digger then
local name = digger:get_player_name()
if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name)
return
end
-- Set creative dig flags to stop dropping items
if minetest.is_creative_enabled(name) then
creative_dig[pos_hash] = true
end
end
-- Trigger the destruct_bed function
minetest.remove_node(pos)
-- Clean up creative dig flag
creative_dig[pos_hash] = nil
end
local function kick_player_after_destruct(destruct_pos)
for name, player_bed_pos in pairs(mcl_beds.bed_pos) do
if vector.distance(destruct_pos, player_bed_pos) < 0.1 then
@ -164,26 +126,6 @@ if minetest.get_modpath("mcl_sounds") then
})
end
local function place_bed(name, placer, pos, dir)
local botpos = vector_add(pos, minetest_facedir_to_dir(dir))
if minetest.is_protected(botpos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(botpos, placer:get_player_name())
return false
end
local botdef = minetest.registered_nodes[minetest_get_node(botpos).name]
if not botdef or not botdef.buildable_to then
return false
end
minetest.set_node(pos, {name = name .. "_bottom", param2 = dir})
minetest.set_node(botpos, {name = name .. "_top", param2 = dir})
return true
end
function mcl_beds.register_bed(name, def)
local common_box = {
type = "fixed",
@ -214,8 +156,7 @@ function mcl_beds.register_bed(name, def)
sounds = def.sounds or default_sounds,
selection_box = common_box,
collision_box = common_box,
_mcl_beds_drop = def.recipe and name or "",
drop = "",
drop = def.recipe and name or "",
node_placement_prediction = "",
on_place = function(itemstack, placer, pointed_thing)
@ -248,23 +189,30 @@ function mcl_beds.register_bed(name, def)
return itemstack
end
-- Try to place in three directions: inline with the view and rotated to
-- the right and left
local dir = minetest.dir_to_facedir(placer:get_look_dir())
if place_bed(name, placer, pos, dir) or
place_bed(name, placer, pos, (dir+1)%4) or
place_bed(name, placer, pos, (dir+3)%4) or
place_bed(name, placer, pos, (dir+2)%4) then
-- Bed was places
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
local botpos = vector_add(pos, minetest_facedir_to_dir(dir))
if minetest.is_protected(botpos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(botpos, placer:get_player_name())
return itemstack
end
local botdef = minetest.registered_nodes[minetest_get_node(botpos).name]
if not botdef or not botdef.buildable_to then
return itemstack
end
minetest.set_node(pos, {name = name .. "_bottom", param2 = dir})
minetest.set_node(botpos, {name = name .. "_top", param2 = dir})
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end,
after_destruct = destruct_bed,
on_dig = dig_bed,
on_destruct = kick_player_after_destruct,
@ -291,7 +239,7 @@ function mcl_beds.register_bed(name, def)
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
sounds = def.sounds or default_sounds,
drop = "",
drop = def.recipe and name or "",
selection_box = common_box,
collision_box = common_box,
@ -302,7 +250,6 @@ function mcl_beds.register_bed(name, def)
on_rotate = rotate,
after_destruct = destruct_bed,
on_dig = dig_bed,
})
minetest.register_alias(name, name .. "_bottom")

View File

@ -8,7 +8,7 @@ local is_sp = minetest.is_singleplayer()
local weather_mod = minetest.get_modpath("mcl_weather")
local explosions_mod = minetest.get_modpath("mcl_explosions")
local spawn_mod = minetest.get_modpath("mcl_spawn")
local pos_to_dim = minetest.get_modpath("mcl_worlds") and mcl_worlds.pos_to_dimension or function(pos) return "overworld" end
local worlds_mod = minetest.get_modpath("mcl_worlds")
local function mcl_log (message)
mcl_util.mcl_log (message, "[Beds]")
@ -38,16 +38,6 @@ local function is_night_skip_enabled()
return players_in_bed_setting() <= 100
end
local function players_in_overworld(players)
local count = 0
for _, player in pairs(players) do
if player and pos_to_dim(player:get_pos()) == "overworld" then
count = count +1
end
end
return count
end
local function check_in_beds(players)
if not players then
players = minetest.get_connected_players()
@ -55,7 +45,7 @@ local function check_in_beds(players)
if player_in_bed <= 0 then
return false
end
return players_in_bed_setting() <= (player_in_bed * 100) / players_in_overworld(players)
return players_in_bed_setting() <= (player_in_bed * 100) / #players
end
-- These monsters do not prevent sleep
@ -216,10 +206,10 @@ local function lay_down(player, pos, bed_pos, state, skip)
return true
end
local function update_formspecs(finished, players)
local ges = players_in_overworld(players or minetest.get_connected_players())
local function update_formspecs(finished, ges)
local ges = ges or #minetest.get_connected_players()
local form_n = "size[12,5;true]"
local all_in_bed = ges and players_in_bed_setting() <= (player_in_bed * 100) / ges or 0
local all_in_bed = players_in_bed_setting() <= (player_in_bed * 100) / ges
local night_skip = is_night_skip_enabled()
local button_leave = "button_exit[4,3;4,0.75;leave;"..F(S("Leave bed")).."]"
local button_abort = "button_exit[4,3;4,0.75;leave;"..F(S("Abort sleep")).."]"
@ -359,36 +349,25 @@ function mcl_beds.get_bed_bottom (pos)
return bed_bottom
end
local function recheck_in_beds()
if check_in_beds() then
update_formspecs(is_night_skip_enabled())
mcl_beds.sleep()
end
-- check again (a player can change the dimension)
if player_in_bed > 0 then
update_formspecs(false)
minetest.after(5, recheck_in_beds)
end
end
function mcl_beds.on_rightclick(pos, player, is_top)
-- Anti-Inception: Don't allow to sleep while you're sleeping
if player:get_meta():get_string("mcl_beds:sleeping") == "true" then
return
end
local dim = pos_to_dim(pos)
if dim == "nether" or dim == "end" then
-- Bed goes BOOM in the Nether or End.
local node = minetest.get_node(pos)
local dir = minetest.facedir_to_dir(node.param2)
if worlds_mod then
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" or dim == "end" then
-- Bed goes BOOM in the Nether or End.
local node = minetest.get_node(pos)
local dir = minetest.facedir_to_dir(node.param2)
minetest.remove_node(pos)
minetest.remove_node(string.sub(node.name, -4) == "_top" and vector.subtract(pos, dir) or vector.add(pos, dir))
if explosions_mod then
mcl_explosions.explode(pos, 5, {drop_chance = 1.0, fire = true})
minetest.remove_node(pos)
minetest.remove_node(string.sub(node.name, -4) == "_top" and vector.subtract(pos, dir) or vector.add(pos, dir))
if explosions_mod then
mcl_explosions.explode(pos, 5, {drop_chance = 1.0, fire = true})
end
return
end
return
end
local name = player:get_player_name()
local ppos = player:get_pos()
@ -406,13 +385,10 @@ function mcl_beds.on_rightclick(pos, player, is_top)
mcl_title.set(player, "actionbar", {text=message, color="white", stay=60})
else -- someone just successfully entered a bed
local connected_players = minetest.get_connected_players()
local ges = players_in_overworld(connected_players)
local sleep_hud_message = S("@1/@2 players currently in bed.", player_in_bed, math.ceil(players_in_bed_setting() * ges / 100))
local sleep_hud_message = S("@1/@2 players currently in bed.", player_in_bed, math.ceil(players_in_bed_setting() * #connected_players / 100))
for _, player in pairs(connected_players) do
-- only send message to players not sleeping and in the "overworld"
if not mcl_beds.player[player:get_player_name()] and pos_to_dim(player:get_pos()) == "overworld" then
-- clear, old message is still being displayed
if mcl_title.params_get(player) then mcl_title.clear(player) end
if not mcl_beds.player[player:get_player_name()] then -- only send message to players not sleeping.
if mcl_title.params_get(player) then mcl_title.clear(player) end -- clear, old message is still being displayed
mcl_title.set(player, "actionbar", {text=sleep_hud_message, color="white", stay=60})
end
end
@ -424,8 +400,13 @@ function mcl_beds.on_rightclick(pos, player, is_top)
update_formspecs(false)
-- skip the night and let all players stand up
if player_in_bed > 0 then
minetest.after(5, recheck_in_beds)
if check_in_beds() then
minetest.after(5, function()
if check_in_beds() then
update_formspecs(is_night_skip_enabled())
mcl_beds.sleep()
end
end)
end
end
@ -452,10 +433,15 @@ minetest.register_on_leaveplayer(function(player)
break
end
end
if player_in_bed > 0 then
minetest.after(5, recheck_in_beds)
if check_in_beds(players) then
minetest.after(5, function()
if check_in_beds() then
update_formspecs(is_night_skip_enabled())
mcl_beds.sleep()
end
end)
end
update_formspecs(false, players)
update_formspecs(false, #players)
end)
local message_rate_limit = tonumber(minetest.settings:get("chat_message_limit_per_10sec")) or 8 --NEVER change this! if this was java, i would've declared it as final

View File

@ -8,60 +8,36 @@ local S = minetest.get_translator(minetest.get_current_modname())
-- Function to allow harvesting honey and honeycomb from the beehive and bee nest.
local honey_harvest = function(pos, node, player, itemstack, pointed_thing)
local inv = player:get_inventory()
local item = player:get_wielded_item()
local shears = minetest.get_item_group(player:get_wielded_item():get_name(), "shears") > 0
local bottle = player:get_wielded_item():get_name() == "mcl_potions:glass_bottle"
local beehive = "mcl_beehives:beehive"
local is_creative = minetest.is_creative_enabled(player:get_player_name())
-- Determine the node name to replace the beehive with if harvest is successful
local beehive = "mcl_beehives:beehive"
if node.name == "mcl_beehives:beehive_5" then
beehive = "mcl_beehives:beehive"
elseif node.name == "mcl_beehives:bee_nest_5" then
beehive = "mcl_beehives:bee_nest"
end
-- Check for a campfire within 5 blocks below the beehive
local campfire_area = vector.offset(pos, 0, -5, 0)
local campfire = minetest.find_nodes_in_area(pos, campfire_area, "group:lit_campfire")
-- Player used a bottle
if item:get_name() == "mcl_potions:glass_bottle" then
if bottle then
local honey = "mcl_honey:honey_bottle"
if inv:room_for_item("main", honey) then
-- Replace the beehive with the version without honey or comb
node.name = beehive
minetest.set_node(pos, node)
-- Give honey bottle and take the empty bottle if survival mode
inv:add_item("main", "mcl_honey:honey_bottle")
if not is_creative then
itemstack:take_item()
end
-- Hurt the player if there was no campfire, or give award if there was
if not campfire[1] then
mcl_util.deal_damage(player, 10)
else
awards.unlock(player:get_player_name(), "mcl:bee_our_guest")
end
if not campfire[1] then mcl_util.deal_damage(player, 10) else awards.unlock(player:get_player_name(), "mcl:bee_our_guest") end
end
-- Player used shears
elseif minetest.get_item_group(item:get_name(), "shears") > 0 then
-- Give honeycomb
elseif shears then
minetest.add_item(pos, "mcl_honey:honeycomb 3")
-- Replace the beehive with the version without honey or comb
node.name = beehive
minetest.set_node(pos, node)
-- Hurt the player if there was no campfire
if not campfire[1] then mcl_util.deal_damage(player, 10) end
-- Add wear to the shears
if not is_creative then
mcl_util.use_item_durability(item, 1)
return item
end
end
end
@ -215,18 +191,6 @@ minetest.register_craft({
},
})
minetest.register_craft({
type = "fuel",
recipe = "group:bee_nest",
burntime = 15,
})
minetest.register_craft({
type = "fuel",
recipe = "group:beehive",
burntime = 15,
})
-- Temporary ABM to update honey levels
minetest.register_abm({
label = "Update Beehive Honey Levels",

View File

@ -475,11 +475,8 @@ minetest.register_node("mcl_books:bookshelf", {
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local function filter(stack)
return minetest.get_item_group(stack:get_name(), "book") == 1 or
stack:get_name() == "mcl_enchanting:book_enchanted"
end
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", filter, 1)
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main",
function(stack) return minetest.get_item_group(stack:get_name(), "book") == 1 or stack:get_name() == "mcl_enchanting:book_enchanted" end)
end,
})

View File

@ -27,11 +27,11 @@ local function damage_explosion(self, damagemulitplier)
for _,obj in pairs(objects) do
if obj:is_player() then
mcl_util.deal_damage(obj, damagemulitplier - vector.distance(p, obj:get_pos()), {type = "explosion"})
elseif obj:get_luaentity() and obj:get_luaentity().is_mob then
elseif obj:get_luaentity().is_mob then
obj:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=damagemulitplier - vector.distance(p, obj:get_pos())},
}, self.object:get_velocity()) -- TODO possibly change the punch dir to be outwards instead of rocket velocity
}, self.object:get_velocity())
end
end
end

View File

@ -379,27 +379,16 @@ end
local function hoppers_on_try_push(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z)
then
local function filter(stack)
return minetest.get_item_group(stack:get_name(), "brewitem") == 1 and
minetest.get_item_group(stack:get_name(), "bottle") == 0
end
return inv, "input", mcl_util.select_stack(hop_inv, hop_list, inv, "input", filter, 1)
if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z) then
return inv, "input", mcl_util.select_stack(hop_inv, hop_list, inv, "input",
function(stack) return minetest.get_item_group(stack:get_name(), "brewitem") == 1 and minetest.get_item_group(stack:get_name(), "bottle") == 0 end)
else
local filter = function(stack)
return stack:get_name() == "mcl_mobitems:blaze_powder"
end
local stack = mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", filter, 1 )
local stack = mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", function(stack) return stack:get_name() == "mcl_mobitems:blaze_powder" end)
if stack then
return inv, "fuel", stack
else
local function filter(stack)
return minetest.get_item_group(stack:get_name(), "bottle") == 1
end
return inv, "stand", mcl_util.select_stack(hop_inv, hop_list, inv, "stand", filter, 1)
return inv, "stand", mcl_util.select_stack(hop_inv, hop_list, inv, "stand",
function(stack) return minetest.get_item_group(stack:get_name(), "bottle") == 1 end)
end
end
end

View File

@ -26,9 +26,3 @@ minetest.register_craft({
{ "group:wood", "group:wood", "" },
}
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_cartography_table:cartography_table",
burntime = 15,
})

View File

@ -2,8 +2,6 @@
local planks = "mcl_cherry_blossom:cherrywood"
local logs = "mcl_cherry_blossom:cherrytree"
local stripped_logs = "mcl_cherry_blossom:stripped_cherrytree"
local wood = "mcl_cherry_blossom:cherrytree_bark"
local stripped_wood = "mcl_cherry_blossom:stripped_cherrytree_bark"
minetest.register_craft({
output = "mcl_cherry_blossom:cherrytree_bark 3",
@ -28,27 +26,6 @@ minetest.register_craft({
}
})
minetest.register_craft({
output = "mcl_cherry_blossom:cherrywood 4",
recipe = {
{ wood },
}
})
minetest.register_craft({
output = "mcl_cherry_blossom:cherrywood 4",
recipe = {
{ stripped_logs },
}
})
minetest.register_craft({
output = "mcl_cherry_blossom:cherrywood 4",
recipe = {
{ stripped_wood },
}
})
minetest.register_craft({
output = "mcl_cherry_blossom:cherry_door 3",
recipe = {

View File

@ -760,7 +760,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main", nil, 1)
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main")
if stack_id ~= nil then
return inv, "main", stack_id
end
@ -768,7 +768,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
local meta_other = minetest.get_meta(pos_other)
local inv_other = meta_other:get_inventory()
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main", nil, 1)
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main")
return inv_other, "main", stack_id
end,
})
@ -955,13 +955,13 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
local meta_other = minetest.get_meta(pos_other)
local inv_other = meta_other:get_inventory()
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main", nil, 1)
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main")
if stack_id ~= nil then
return inv_other, "main", stack_id
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main", nil, 1)
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main")
return inv, "main", stack_id
end,
})
@ -1522,7 +1522,7 @@ for color, desc in pairs(boxtypes) do
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", mcl_chests.is_not_shulker_box, 1)
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", mcl_chests.is_not_shulker_box)
end,
})

View File

@ -61,9 +61,9 @@ for _, row in ipairs(block.dyes) do
local sdesc_gtp = row[4]
local sdesc_cp = row[5]
local sdesc_c = row[6]
local ldesc_hc, ldesc_gt, ldesc_cp, ldesc_c, ldesc_gtp
local ldesc_hc, ldesc_gt, ldesc_cp, ldesc_c
local create_entry
local ename_hc, ename_gt, ename_cp, ename_c, ename_gtp
local ename_hc, ename_gt, ename_cp, ename_c
local ltt_cp = cp_tt
if is_canonical then
ldesc_hc = hc_desc

View File

@ -238,7 +238,7 @@ minetest.register_node("mcl_composters:composter", {
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition, 1)
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition)
end,
_mcl_hoppers_on_after_push = function(pos)
local meta = minetest.get_meta(pos)
@ -293,7 +293,7 @@ local function register_filled_composter(level)
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition, 1)
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition)
end,
_mcl_hoppers_on_after_push = function(pos)
local meta = minetest.get_meta(pos)

View File

@ -16,39 +16,130 @@ minetest.register_craft({
},
})
minetest.register_craft({
output = "mcl_copper:block_cut 4",
recipe = {
{ "mcl_copper:block", "mcl_copper:block" },
{ "mcl_copper:block", "mcl_copper:block" },
},
})
local function get_shape(name, material)
if name == "cut" then
return {
{material, material},
{material, material}
}
elseif name == "grate" then
return {
{"", material, ""},
{material, "", material},
{"", material, ""}
}
elseif name == "chiseled" then
return {
{material},
{material},
}
elseif name == "door" then
return {
{material, material},
{material, material},
{material, material}
}
elseif name == "trapdoor" then
return {
{material, material, material},
{material, material, material}
}
elseif name == "bulb_off" then
return {
{"", material, ""},
{material, "mcl_mobitems:blaze_rod", material},
{"", "mesecons:redstone", ""}
}
else
return {}
end
end
minetest.register_craft({
output = "mcl_copper:block_exposed_cut 4",
recipe = {
{ "mcl_copper:block_exposed", "mcl_copper:block_exposed" },
{ "mcl_copper:block_exposed", "mcl_copper:block_exposed" },
},
})
function mcl_copper.register_variants_recipes(name, material, amount)
local names
local materials = {}
if name ~= "cut" then
names = {
name, "waxed_"..name,
name.."_exposed", "waxed_"..name.."_exposed",
name.."_weathered", "waxed_"..name.."_weathered",
name.."_oxidized", "waxed_"..name.."_oxidized"
}
else
names = {
"block_"..name, "waxed_block_"..name,
"block_exposed_"..name, "waxed_block_exposed_"..name,
"block_weathered_"..name, "waxed_block_weathered_"..name,
"block_oxidized_"..name, "waxed_block_oxidized_"..name
}
end
minetest.register_craft({
output = "mcl_copper:block_oxidized_cut 4",
recipe = {
{ "mcl_copper:block_oxidized", "mcl_copper:block_oxidized" },
{ "mcl_copper:block_oxidized", "mcl_copper:block_oxidized" },
},
})
if type(material) == "string" then
materials = {
"mcl_copper:"..material, "mcl_copper:waxed_"..material,
"mcl_copper:"..material.."_exposed", "mcl_copper:waxed_"..material.."_exposed",
"mcl_copper:"..material.."_weathered", "mcl_copper:waxed_"..material.."_weathered",
"mcl_copper:"..material.."_oxidized", "mcl_copper:waxed_"..material.."_oxidized"
}
elseif type(material) == "table" then
if #material == 8 then
materials = material
else
return
end
else
return
end
minetest.register_craft({
output = "mcl_copper:block_weathered_cut 4",
recipe = {
{ "mcl_copper:block_weathered", "mcl_copper:block_weathered" },
{ "mcl_copper:block_weathered", "mcl_copper:block_weathered" },
},
})
for i = 1, 8 do
minetest.register_craft({
output = "mcl_copper:"..names[i].." "..tostring(amount),
recipe = get_shape(name, materials[i])
})
end
end
local waxable_blocks = { "block", "block_cut", "block_exposed", "block_exposed_cut", "block_weathered", "block_weathered_cut", "block_oxidized", "block_oxidized_cut" }
mcl_copper.register_variants_recipes("cut", "block", 4)
mcl_copper.register_variants_recipes("grate", "block", 4)
mcl_copper.register_variants_recipes("door", "block", 3)
mcl_copper.register_variants_recipes("trapdoor", "block", 2)
mcl_copper.register_variants_recipes("bulb_off", "block", 4)
local chiseled_materials = {
"mcl_stairs:slab_copper_cut",
"mcl_stairs:slab_waxed_copper_cut",
"mcl_stairs:slab_copper_exposed_cut",
"mcl_stairs:slab_waxed_copper_exposed_cut",
"mcl_stairs:slab_copper_weathered_cut",
"mcl_stairs:slab_waxed_copper_weathered_cut",
"mcl_stairs:slab_copper_oxidized_cut",
"mcl_stairs:slab_waxed_copper_oxidized_cut"
}
mcl_copper.register_variants_recipes("chiseled", chiseled_materials, 1)
local waxable_blocks = {
"block",
"block_cut",
"grate",
"chiseled",
"bulb_off",
"block_exposed",
"block_exposed_cut",
"grate_exposed",
"chiseled_exposed",
"bulb_off_exposed",
"block_weathered",
"block_weathered_cut",
"grate_weathered",
"chiseled_weathered",
"bulb_off_weathered",
"block_oxidized",
"block_oxidized_cut",
"grate_oxidized",
"chiseled_oxidized",
"bulb_off_oxidized"
}
for _, w in ipairs(waxable_blocks) do
minetest.register_craft({
@ -59,10 +150,22 @@ for _, w in ipairs(waxable_blocks) do
})
end
local cuttable_blocks = { "block", "waxed_block", "block_exposed", "waxed_block_exposed", "block_weathered", "waxed_block_weathered", "block_oxidized", "waxed_block_oxidized" }
local cuttable_blocks = {
"block",
"waxed_block",
"block_exposed",
"waxed_block_exposed",
"block_weathered",
"waxed_block_weathered",
"block_oxidized",
"waxed_block_oxidized"
}
for _, c in ipairs(cuttable_blocks) do
mcl_stonecutter.register_recipe("mcl_copper:"..c, "mcl_copper:"..c.."_cut", 4)
mcl_stonecutter.register_recipe("mcl_copper:"..c, "mcl_copper:"..c:gsub("block", "grate"), 4)
mcl_stonecutter.register_recipe("mcl_copper:"..c, "mcl_copper:"..c:gsub("block", "chiseled"), 4)
mcl_stonecutter.register_recipe("mcl_copper:"..c.."_cut", "mcl_copper:"..c:gsub("block", "chiseled"))
end
minetest.register_craft({

View File

@ -0,0 +1,152 @@
local lit_desc = "(Lit)"
local pow_desc = "(Powered)"
local mix_desc = "(Lit and Powered)"
mcl_copper.copper_descs = {
["block"] = {
"Block of Copper", "Waxed Block of Copper",
"Exposed Copper", "Waxed Exposed Copper",
"Weathered Copper", "Waxed Weathered Copper",
"Oxidized Copper", "Waxed Oxidized Copper"
},
["cut"] = {
"Cut Copper", "Waxed Cut Copper",
"Exposed Cut Copper", "Waxed Exposed Cut Copper",
"Weathered Cut Copper", "Waxed Weathered Cut Copper",
"Oxidized Cut Copper", "Waxed Oxidized Cut Copper"
},
["grate"] = {
"Copper Grate", "Waxed Copper Grate",
"Exposed Copper Grate", "Waxed Exposed Copper Grate",
"Weathered Copper Grate", "Waxed Weathered Copper Grate",
"Oxidized Copper Grate", "Waxed Oxidized Copper Grate"
},
["chiseled"] = {
"Chiseled Copper", "Waxed Chiseled Copper",
"Exposed Chiseled Copper", "Waxed Exposed Chiseled Copper",
"Weathered Chiseled Copper", "Waxed Weathered Chiseled Copper",
"Oxidized Chiseled Copper", "Waxed Oxidized Chiseled Copper"
},
["bulb_off"] = {
"Copper Bulb", "Waxed Copper Bulb",
"Exposed Copper Bulb", "Waxed Exposed Copper Bulb",
"Weathered Copper Bulb", "Waxed Weathered Copper Bulb",
"Oxidized Copper Bulb", "Waxed Oxidized Copper Bulb"
},
["bulb_on"] = {
{"Copper Bulb", lit_desc}, {"Waxed Copper Bulb", lit_desc},
{"Exposed Copper Bulb", lit_desc}, {"Waxed Exposed Copper Bulb", lit_desc},
{"Weathered Copper Bulb", lit_desc}, {"Waxed Weathered Copper Bulb", lit_desc},
{"Oxidized Copper Bulb", lit_desc}, {"Waxed Oxidized Copper Bulb", lit_desc}
},
["bulb_powered_off"] = {
{"Copper Bulb", pow_desc}, {"Waxed Copper Bulb", pow_desc},
{"Exposed Copper Bulb", pow_desc}, {"Waxed Exposed Copper Bulb", pow_desc},
{"Weathered Copper Bulb", pow_desc}, {"Waxed Weathered Copper Bulb", pow_desc},
{"Oxidized Copper Bulb", pow_desc}, {"Waxed Oxidized Copper Bulb", pow_desc}
},
["bulb_powered_on"] = {
{"Copper Bulb", mix_desc}, {"Waxed Copper Bulb", mix_desc},
{"Exposed Copper Bulb", mix_desc}, {"Waxed Exposed Copper Bulb", mix_desc},
{"Weathered Copper Bulb", mix_desc}, {"Waxed Weathered Copper Bulb", mix_desc},
{"Oxidized Copper Bulb", mix_desc}, {"Waxed Oxidized Copper Bulb", mix_desc}
}
}
mcl_copper.copper_longdescs = {
["block"] = {
"A block of copper is mostly a decorative block.",
"Exposed copper is a decorative block.",
"Weathered copper is a decorative block.",
"Oxidized copper is a decorative block."
},
["cut"] = {
"Cut copper is a decorative block.",
"Exposed cut copper is a decorative block.",
"Weathered cut copper is a decorative block.",
"Oxidized cut copper is a decorative block."
},
["grate"] = {
"Copper grate is a decorative block.",
"Exposed copper grate is a decorative block.",
"Weathered copper grate is a decorative block.",
"Oxidized copper grate is a decorative block."
},
["chiseled"] = {
"Chiseled copper is a decorative block.",
"Exposed chiseled copper is a decorative block.",
"Weathered chiseled copper is a decorative block.",
"Oxidized chiseled copper is a decorative block."
},
["bulb_off"] = {
"Copper bulb is a decorative block and a light source when lited.",
"Exposed copper bulb is a decorative block and a light source when lited.",
"Weathered copper bulb is a decorative block and a light source when lited.",
"Oxidized copper bulb is a decorative block and a light source when lited."
},
["bulb_on"] = {
"Copper bulb is a decorative block and a light source.",
"Exposed copper bulb is a decorative block and a light source.",
"Weathered copper bulb is a decorative block and a light source.",
"Oxidized copper bulb is a decorative block and a light source."
},
["bulb_powered_off"] = {
"Copper bulb is a decorative block and a light source when lited.",
"Exposed copper bulb is a decorative block and a light source when lited.",
"Weathered copper bulb is a decorative block and a light source when lited.",
"Oxidized copper bulb is a decorative block and a light source when lited."
},
["bulb_powered_on"] = {
"Copper bulb is a decorative block and a light source.",
"Exposed copper bulb is a decorative block and a light source.",
"Weathered copper bulb is a decorative block and a light source.",
"Oxidized copper bulb is a decorative block and a light source."
}
}
mcl_copper.stairs_subnames = {
["cut"] = {
"copper_cut", "waxed_copper_cut",
"copper_exposed_cut", "waxed_copper_exposed_cut",
"copper_weathered_cut", "waxed_copper_weathered_cut",
"copper_oxidized_cut", "waxed_copper_oxidized_cut"
}
}
mcl_copper.stairs_descs = {
["copper_cut"] = {
"Slab of Cut Copper", "Double Slab of Cut Copper", "Stairs of Cut Copper",
},
["waxed_copper_cut"] = {
"Waxed Slab of Cut Copper", "Waxed Double Slab of Cut Copper", "Waxed Stairs of Cut Copper",
},
["copper_exposed_cut"] = {
"Slab of Exposed Cut Copper", "Double Slab of Exposed Cut Copper", "Stairs of Exposed Cut Copper"
},
["waxed_copper_exposed_cut"] = {
"Waxed Slab of Exposed Cut Copper", "Waxed Double Slab of Exposed Cut Copper", "Waxed Stairs of Exposed Cut Copper"
},
["copper_weathered_cut"] = {
"Slab of Weathered Cut Copper", "Double Slab of Weathered Cut Copper", "Stairs of Weathered Cut Copper"
},
["waxed_copper_weathered_cut"] = {
"Waxed Slab of Weathered Cut Copper", "Waxed Double Slab of Weathered Cut Copper", "Waxed Stairs of Weathered Cut Copper"
},
["copper_oxidized_cut"] = {
"Slab of Oxidized Cut Copper", "Double Slab of Oxidized Cut Copper", "Stairs of Oxidized Cut Copper"
},
["waxed_copper_oxidized_cut"] = {
"Waxed Slab of Oxidized Cut Copper", "Waxed Double Slab of Oxidized Cut Copper", "Waxed Stairs of Oxidized Cut Copper"
}
}
mcl_copper.doors_descs = {
{"Copper Door", "Copper Trapdoor"},
{"Waxed Copper Door", "Waxed Copper Trapdoor"},
{"Exposed Copper Door", "Exposed Copper Trapdoor"},
{"Waxed Exposed Copper Door", "Waxed Exposed Copper Trapdoor"},
{"Weathered Copper Door", "Weathered Copper Trapdoor"},
{"Waxed Weathered Copper Door", "Waxed Weathered Copper Trapdoor"},
{"Oxidized Copper Door", "Oxidized Copper Trapdoor"},
{"Waxed Oxidized Copper Door", "Waxed Oxidized Copper Trapdoor"}
}

View File

@ -1,132 +1,115 @@
local stair_oxidization = {
{ "cut", "exposed_cut" },
{ "cut_inner", "exposed_cut_inner" },
{ "cut_outer", "exposed_cut_outer" },
{ "exposed_cut", "weathered_cut" },
{ "exposed_cut_inner", "weathered_cut_inner" },
{ "exposed_cut_outer", "weathered_cut_outer" },
{ "weathered_cut", "oxidized_cut" },
{ "weathered_cut_inner", "oxidized_cut_inner" },
{ "weathered_cut_outer", "oxidized_cut_outer" }
}
function mcl_copper.register_oxidation_and_scraping(mod_name, subname, decay_chain)
local item, oxidized_item
local slab_oxidization = {
{ "cut", "exposed_cut" },
{ "cut_top", "exposed_cut_top" },
{ "cut_double", "exposed_cut_double" },
{ "exposed_cut", "weathered_cut" },
{ "exposed_cut_top", "weathered_cut_top" },
{ "exposed_cut_double", "weathered_cut_double" },
{ "weathered_cut", "oxidized_cut" },
{ "weathered_cut_top", "oxidized_cut_top" },
{ "weathered_cut_double", "oxidized_cut_double" },
}
for i = 1, #decay_chain - 1 do
item = mod_name..":"..subname..decay_chain[i]
oxidized_item = mod_name..":"..subname..decay_chain[i + 1]
local def
local def_variant_oxidized
local def_variant_waxed
local def_variant_scraped
minetest.override_item(item, {_mcl_oxidized_variant = oxidized_item})
minetest.override_item(oxidized_item, {_mcl_stripped_variant = item})
-- set up oxidized and waxed variants.
for i = 1, #stair_oxidization do
-- stairs
def = "mcl_stairs:stair_copper_" .. stair_oxidization[i][1]
def_variant_oxidized = "mcl_stairs:stair_copper_" .. stair_oxidization[i][2]
minetest.override_item(def, { _mcl_oxidized_variant = def_variant_oxidized })
if subname:find("stair") then
minetest.override_item(item.."_inner", {_mcl_oxidized_variant = oxidized_item.."_inner"})
minetest.override_item(item.."_outer", {_mcl_oxidized_variant = oxidized_item.."_outer"})
minetest.override_item(oxidized_item.."_inner", {_mcl_stripped_variant = item.."_inner"})
minetest.override_item(oxidized_item.."_outer", {_mcl_stripped_variant = item.."_outer"})
elseif subname:find("slab") then
minetest.override_item(item.."_double", {_mcl_oxidized_variant = oxidized_item.."_double"})
minetest.override_item(item.."_top", {_mcl_oxidized_variant = oxidized_item.."_top"})
minetest.override_item(oxidized_item.."_double", {_mcl_stripped_variant = item.."_double"})
minetest.override_item(oxidized_item.."_top", {_mcl_stripped_variant = item.."_top"})
elseif subname:find("trapdoor") then
minetest.override_item(item.."_open", {_mcl_oxidized_variant = oxidized_item.."_open"})
minetest.override_item(oxidized_item.."_open", {_mcl_stripped_variant = item.."_open"})
elseif subname == "door" then
minetest.override_item(item.."_b_1", {_mcl_oxidized_variant = oxidized_item.."_b_1"})
minetest.override_item(oxidized_item.."_b_1", {_mcl_stripped_variant = item.."_b_1"})
minetest.override_item(item.."_t_1", {_mcl_oxidized_variant = oxidized_item.."_t_1"})
minetest.override_item(oxidized_item.."_t_1", {_mcl_stripped_variant = item.."_t_1"})
def_variant_waxed = "mcl_stairs:stair_waxed_copper_" .. stair_oxidization[i][1]
minetest.override_item(def, { _mcl_waxed_variant = def_variant_waxed })
minetest.override_item(item.."_b_2", {_mcl_oxidized_variant = oxidized_item.."_b_2"})
minetest.override_item(oxidized_item.."_b_2", {_mcl_stripped_variant = item.."_b_2"})
minetest.override_item(item.."_t_2", {_mcl_oxidized_variant = oxidized_item.."_t_2"})
minetest.override_item(oxidized_item.."_t_2", {_mcl_stripped_variant = item.."_t_2"})
-- slabs
def = "mcl_stairs:slab_copper_" .. slab_oxidization[i][1]
def_variant_oxidized = "mcl_stairs:slab_copper_" .. slab_oxidization[i][2]
minetest.override_item(def, { _mcl_oxidized_variant = def_variant_oxidized })
minetest.override_item(item.."_b_3", {_mcl_oxidized_variant = oxidized_item.."_b_3"})
minetest.override_item(oxidized_item.."_b_3", {_mcl_stripped_variant = item.."_b_3"})
minetest.override_item(item.."_t_3", {_mcl_oxidized_variant = oxidized_item.."_t_3"})
minetest.override_item(oxidized_item.."_t_3", {_mcl_stripped_variant = item.."_t_3"})
def_variant_waxed = "mcl_stairs:slab_waxed_copper_" .. slab_oxidization[i][1]
minetest.override_item(def, { _mcl_waxed_variant = def_variant_waxed })
end
-- Set up scraped variants.
for i = 1, #stair_oxidization do
-- does both stairs and slabs.
if i > 3 then
def = "mcl_stairs:stair_copper_" .. stair_oxidization[i][1]
def_variant_scraped = "mcl_stairs:stair_copper_" .. stair_oxidization[i - 3][1]
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
def = "mcl_stairs:slab_copper_" .. slab_oxidization[i][1]
def_variant_scraped = "mcl_stairs:slab_copper_" .. slab_oxidization[i - 3][1]
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
end
if i > 6 then
def = "mcl_stairs:stair_copper_" .. stair_oxidization[i][2]
def_variant_scraped = "mcl_stairs:stair_copper_" .. stair_oxidization[i][1]
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
def = "mcl_stairs:slab_copper_" .. slab_oxidization[i][2]
def_variant_scraped = "mcl_stairs:slab_copper_" .. slab_oxidization[i][1]
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
minetest.override_item(item.."_b_4", {_mcl_oxidized_variant = oxidized_item.."_b_4"})
minetest.override_item(oxidized_item.."_b_4", {_mcl_stripped_variant = item.."_b_4"})
minetest.override_item(item.."_t_4", {_mcl_oxidized_variant = oxidized_item.."_t_4"})
minetest.override_item(oxidized_item.."_t_4", {_mcl_stripped_variant = item.."_t_4"})
end
end
end
-- Set up scraped variants for waxed stairs.
local waxed_variants = {
{ "waxed_copper_cut", "copper_cut" },
{ "waxed_copper_exposed_cut", "copper_exposed_cut" },
{ "waxed_copper_weathered_cut", "copper_weathered_cut" },
{ "waxed_copper_oxidized_cut", "copper_oxidized_cut" },
}
function mcl_copper.register_waxing_and_scraping(mod_name, subname, decay_chain)
local waxed_item, unwaxed_item
for i = 1, #waxed_variants do
-- stairs
def = "mcl_stairs:stair_" .. waxed_variants[i][1]
def_variant_scraped = "mcl_stairs:stair_" .. waxed_variants[i][2]
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
for i = 1, #decay_chain do
waxed_item = mod_name..":"..subname..decay_chain[i]
unwaxed_item = mod_name..":"..subname:gsub("waxed_", "")..decay_chain[i]
def = "mcl_stairs:stair_" .. waxed_variants[i][1] .. "_inner"
def_variant_scraped = "mcl_stairs:stair_" .. waxed_variants[i][2] .. "_inner"
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
minetest.override_item(waxed_item, {_mcl_stripped_variant = unwaxed_item})
minetest.override_item(unwaxed_item, {_mcl_waxed_variant = waxed_item})
def = "mcl_stairs:stair_" .. waxed_variants[i][1] .. "_outer"
def_variant_scraped = "mcl_stairs:stair_" .. waxed_variants[i][2] .. "_outer"
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
if subname:find("stair") then
minetest.override_item(waxed_item.."_inner", {_mcl_stripped_variant = unwaxed_item.."_inner"})
minetest.override_item(waxed_item.."_outer", {_mcl_stripped_variant = unwaxed_item.."_outer"})
minetest.override_item(unwaxed_item.."_inner", {_mcl_waxed_variant = waxed_item.."_inner"})
minetest.override_item(unwaxed_item.."_outer", {_mcl_waxed_variant = waxed_item.."_outer"})
elseif subname:find("slab") then
minetest.override_item(waxed_item.."_double", {_mcl_stripped_variant = unwaxed_item.."_double"})
minetest.override_item(waxed_item.."_top", {_mcl_stripped_variant = unwaxed_item.."_top"})
minetest.override_item(unwaxed_item.."_double", {_mcl_waxed_variant = waxed_item.."_double"})
minetest.override_item(unwaxed_item.."_top", {_mcl_waxed_variant = waxed_item.."_top"})
elseif subname:find("trapdoor") then
minetest.override_item(waxed_item.."_open", {_mcl_stripped_variant = unwaxed_item.."_open"})
minetest.override_item(unwaxed_item.."_open", {_mcl_waxed_variant = waxed_item.."_open"})
elseif subname == "waxed_door" then
minetest.override_item(waxed_item.."_b_1", {_mcl_stripped_variant = unwaxed_item.."_b_1"})
minetest.override_item(unwaxed_item.."_b_1", {_mcl_waxed_variant = waxed_item.."_b_1"})
minetest.override_item(waxed_item.."_t_1", {_mcl_stripped_variant = unwaxed_item.."_t_1"})
minetest.override_item(unwaxed_item.."_t_1", {_mcl_waxed_variant = waxed_item.."_t_1"})
-- slab
def = "mcl_stairs:slab_" .. waxed_variants[i][1]
def_variant_scraped = "mcl_stairs:slab_" .. waxed_variants[i][2]
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
minetest.override_item(waxed_item.."_b_2", {_mcl_stripped_variant = unwaxed_item.."_b_2"})
minetest.override_item(unwaxed_item.."_b_2", {_mcl_waxed_variant = waxed_item.."_b_2"})
minetest.override_item(waxed_item.."_t_2", {_mcl_stripped_variant = unwaxed_item.."_t_2"})
minetest.override_item(unwaxed_item.."_t_2", {_mcl_waxed_variant = waxed_item.."_t_2"})
def = "mcl_stairs:slab_" .. waxed_variants[i][1] .. "_top"
def_variant_scraped = "mcl_stairs:slab_" .. waxed_variants[i][2] .. "_top"
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
def = "mcl_stairs:slab_" .. waxed_variants[i][1] .. "_double"
def_variant_scraped = "mcl_stairs:slab_" .. waxed_variants[i][2] .. "_double"
minetest.override_item(def, { _mcl_stripped_variant = def_variant_scraped })
minetest.override_item(waxed_item.."_b_3", {_mcl_stripped_variant = unwaxed_item.."_b_3"})
minetest.override_item(unwaxed_item.."_b_3", {_mcl_waxed_variant = waxed_item.."_b_3"})
minetest.override_item(waxed_item.."_t_3", {_mcl_stripped_variant = unwaxed_item.."_t_3"})
minetest.override_item(unwaxed_item.."_t_3", {_mcl_waxed_variant = waxed_item.."_t_3"})
minetest.override_item(waxed_item.."_b_4", {_mcl_stripped_variant = unwaxed_item.."_b_4"})
minetest.override_item(unwaxed_item.."_b_4", {_mcl_waxed_variant = waxed_item.."_b_4"})
minetest.override_item(waxed_item.."_t_4", {_mcl_stripped_variant = unwaxed_item.."_t_4"})
minetest.override_item(unwaxed_item.."_t_4", {_mcl_waxed_variant = waxed_item.."_t_4"})
end
end
end
-- Waxed Oxidized Slabs and Stairs
local oxidized_slabs = {
"oxidized_cut",
"oxidized_cut_double",
"oxidized_cut_top"
local cut_decay_chain = {
"_cut",
"_exposed_cut",
"_weathered_cut",
"_oxidized_cut"
}
local doors_decay_chain = {
"",
"_exposed",
"_weathered",
"_oxidized"
}
for i = 1, #oxidized_slabs do
def = "mcl_stairs:slab_copper_" .. oxidized_slabs[i]
def_variant_waxed = "mcl_stairs:slab_waxed_copper_" .. oxidized_slabs[i]
minetest.override_item(def, { _mcl_waxed_variant = def_variant_waxed })
end
local oxidized_stairs = {
"oxidized_cut",
"oxidized_cut_inner",
"oxidized_cut_outer"
}
for i = 1, #oxidized_stairs do
def = "mcl_stairs:stair_copper_" .. oxidized_stairs[i]
def_variant_waxed = "mcl_stairs:stair_waxed_copper_" .. oxidized_stairs[i]
minetest.override_item(def, { _mcl_waxed_variant = def_variant_waxed })
end
mcl_copper.register_oxidation_and_scraping("mcl_stairs", "stair_copper", cut_decay_chain)
mcl_copper.register_oxidation_and_scraping("mcl_stairs", "slab_copper", cut_decay_chain)
mcl_copper.register_oxidation_and_scraping("mcl_copper", "trapdoor", doors_decay_chain)
mcl_copper.register_oxidation_and_scraping("mcl_copper", "door", doors_decay_chain)
mcl_copper.register_waxing_and_scraping("mcl_stairs", "stair_waxed_copper", cut_decay_chain)
mcl_copper.register_waxing_and_scraping("mcl_stairs", "slab_waxed_copper", cut_decay_chain)
mcl_copper.register_waxing_and_scraping("mcl_copper", "waxed_trapdoor", doors_decay_chain)
mcl_copper.register_waxing_and_scraping("mcl_copper", "waxed_door", doors_decay_chain)

View File

@ -2,6 +2,7 @@ local path = minetest.get_modpath("mcl_copper")
mcl_copper = {} -- initialize global variable.
dofile(path .. "/descriptions.lua")
dofile(path .. "/nodes.lua")
dofile(path .. "/items.lua")
dofile(path .. "/crafting.lua")

View File

@ -55,3 +55,62 @@ Waxed Weathered Copper=Cobre Desgastado Encerado
Weathered cut copper is a decorative block.=Cobre lapidado desgastado é um bloco decorativo.
Weathered Cut Copper=Cobre Lapidado Desgastado
Waxed Weathered Cut Copper=Cobre Lapidado Desgastado Encerado
Copper Grate=Grade de Cobre
Waxed Copper Grate=Grade de Cobre Encerada
Copper grate is a decorative block.=Grade de cobre é um bloco decorativo.
Exposed Copper Grate=Grade de Cobre Exposto
Waxed Exposed Copper Grate=Grade de Cobre Exposto Encerada
Exposed copper grate is a decorative block.=Grade de cobre exposto é um bloco decorativo.
Weathered Copper Grate=Grade de Cobre Desgastado
Waxed Weathered Copper Grate=Grade de Cobre Desgastado Encerada
Weathered opper grate is a decorative block.=Grade de cobre de desgastado é um bloco decorativo.
Oxidized Copper Grate=Grade de Cobre Oxidado
Waxed Oxidized Copper Grate=Grade de Cobre Oxidado Encerada
Oxidized copper grate is a decorative block.=Grade de cobre oxidado é um bloco decorativo.
Chiseled Copper=Cobre Talhado
Waxed Chiseled Copper=Cobre Talhado Encerado
Chiseled copper is a decorative block.=Cobre talhado é um bloco decorativo.
Exposed Chiseled Copper=Cobre Talhado Exposto
Waxed Exposed Chiseled Copper=Cobre Talhado Exposto Encerado
Exposed chiseled copper is a decorative block.=Cobre talhado exposto é um bloco decorativo.
Weathered Chiseled Copper=Cobre Talhado Desgastado
Waxed Weathered Chiseled Copper=Cobre Talhado Desgastado Encerado
Weathered chiseled copper is a decorative block.=Cobre talhado desgastado é um bloco decorativo.
Oxidized Chiseled Copper=Cobre Talhado Oxidado
Waxed Oxidized Chiseled Copper=Cobre Talhado Oxidado Encerado
Oxidized chiseled copper is a decorative block.=Cobre talhado oxidado é um bloco decorativo.
Copper Bulb=Bulbo de Cobre
Waxed Copper Bulb=Bulbo de Cobre Encerado
Copper bulb is a decorative block and a light source.=Bulbo de cobre é um bloco decorativo e uma fonte de luz.
Copper bulb is a decorative block and a light source when lited.=Bulbo de cobre é um bloco decorativo e uma fonte de luz quando aceso.
Exposed Copper Bulb=Bulbo de Cobre Exposto
Waxed Exposed Copper Bulb=Bulbo de Cobre Exposto Encerado
Exposed copper bulb is a decorative block and a light source.=Bulbo de cobre exposto é um bloco decorativo e uma fonte de luz.
Exposed copper bulb is a decorative block and a light source when lited.=Bulbo de cobre exposto é um bloco decorativo e uma fonte de luz quando aceso.
Weathered Copper Bulb=Bulbo de Cobre Desgastado
Waxed Weathered Copper Bulb=Bulbo de Cobre Desgastado Encerado
Weathered copper bulb is a decorative block and a light source.=Bulbo de cobre desgastado é um bloco decorativo e uma fonte de luz.
Weathered copper bulb is a decorative block and a light source when lited.=Bulbo de cobre desgastado é um bloco decorativo e uma fonte de luz quando aceso.
Oxidized Copper Bulb=Bulbo de Cobre Oxidado
Waxed Oxidized Copper Bulb=Bulbo de Cobre Oxidado Encerado
Oxidized copper bulb is a decorative block and a light source.=Bulbo de cobre oxidado é um bloco decorativo e uma fonte de luz.
Oxidized copper bulb is a decorative block and a light source when lited.=Bulbo de cobre oxidado é um bloco decorativo e uma fonte de luz quando aceso.
Copper Door=Porta de Cobre
Waxed Copper Door=Porta de Cobre Encerada
Exposed Copper Door=Porta de Cobre Exposto
Waxed Exposed Copper Door=Porta de Cobre Exposto Encerada
Weathered Copper Door=Porta de Cobre Desgastado
Waxed Weathered Copper Door=Porta de Cobre Desgastado Encerada
Oxidized Copper Door=Porta de Cobre Oxidado
Waxed Oxidized Copper Door=Porta de Cobre Oxidado Encerada
Copper Trapdoor=Alçapão de Cobre
Waxed Copper Trapdoor=Alçapão de Cobre Encerado
Exposed Copper Trapdoor=Alçapão de Cobre Exposto
Waxed Exposed Copper Trapdoor=Alçapão de Cobre Exposto Encerado
Weathered Copper Trapdoor=Alçapão de Cobre Desgastado
Waxed Weathered Copper Trapdoor=Alçapão de Cobre Desgastado Encerado
Oxidized Copper Trapdoor=Alçapão de Cobre Oxidado
Waxed Oxidized Copper Trapdoor=Alçapão de Cobre Oxidado Encerado
@1 (Lit)=@1 (Aceso)
@1 (Powered)=@1 (Energizado)
@1 (Lit and Powered)=@1 (Aceso e Energizado)

View File

@ -55,3 +55,62 @@ Waxed Weathered Copper=
Weathered cut copper is a decorative block.=
Weathered Cut Copper=
Waxed Weathered Cut Copper=
Copper Grate=
Waxed Copper Grate=
Copper grate is a decorative block.=
Exposed Copper Grate=
Waxed Exposed Copper Grate=
Exposed copper grate is a decorative block.=
Weathered Copper Grate=
Waxed Weathered Copper Grate=
Weathered copper grate is a decorative block.=
Oxidized Copper Grate=
Waxed Oxidized Copper Grate=
Oxidized copper grate is a decorative block.=
Chiseled Copper=
Waxed Chiseled Copper=
Chiseled copper is a decorative block.=
Exposed Chiseled Copper=
Waxed Exposed Chiseled Copper=
Exposed chiseled copper is a decorative block.=
Weathered Chiseled Copper=
Waxed Weathered Chiseled Copper=
Weathered chiseled copper is a decorative block.=
Oxidized Chiseled Copper=
Waxed Oxidized Chiseled Copper=
Oxidized chiseled copper is a decorative block.=
Copper Bulb=
Waxed Copper Bulb=
Copper bulb is a decorative block and a light source.=
Copper bulb is a decorative block and a light source when lited.=
Exposed Copper Bulb=
Waxed Exposed Copper Bulb=
Exposed copper bulb is a decorative block and a light source.=
Exposed copper bulb is a decorative block and a light source when lited.=
Weathered Copper Bulb=
Waxed Weathered Copper Bulb=
Weathered copper bulb is a decorative block and a light source.=
Weathered copper bulb is a decorative block and a light source when lited.=
Oxidized Copper Bulb=
Waxed Oxidized Copper Bulb=
Oxidized copper bulb is a decorative block and a light source.=
Oxidized copper bulb is a decorative block and a light source when lited.=
Copper Door=
Waxed Copper Door=
Exposed Copper Door=
Waxed Exposed Copper Door=
Weathered Copper Door=
Waxed Weathered Copper Door=
Oxidized Copper Door=
Waxed Oxidized Copper Door=
Copper Trapdoor=
Waxed Copper Trapdoor=
Exposed Copper Trapdoor=
Waxed Exposed Copper Trapdoor=
Weathered Copper Trapdoor=
Waxed Weathered Copper Trapdoor=
Oxidized Copper Trapdoor=
Waxed Oxidized Copper Trapdoor=
@1 (Lit)=
@1 (Powered)=
@1 (Lit and Powered)=

View File

@ -1,5 +1,191 @@
local S = minetest.get_translator("mcl_copper")
local function set_description(descs, s_index, n_index)
local description
if type(descs[s_index][n_index]) == "string" then
description = S(descs[s_index][n_index])
elseif type(descs[s_index][n_index]) == "table" then
description = S("@1 "..descs[s_index][n_index][2], S(descs[s_index][n_index][1]))
else
return nil
end
return description
end
local function set_drop(drop, old_name, index_name)
if drop and old_name and index_name then
drop = "mcl_copper:"..old_name:gsub(index_name, drop)
end
return drop
end
local function set_groups(name, groups)
local groups = table.copy(groups)
if name and groups then
if name:find("waxed") then
groups.waxed = 1
elseif not name:find("oxidized") then
groups.oxidizable = 1
end
if name:find("door") then
groups.building_block = 0
groups.mesecon_effector_on = 1
end
else
return nil
end
return groups
end
local function set_light_level(light_source, index)
local ceil, floor_5, floor_7 = math.ceil(index / 2), math.floor(index / 5), math.floor(index / 7)
if light_source then
light_source = light_source - 3 * (ceil - 1) - floor_5 - floor_7
end
return light_source
end
local function set_tiles(tiles, index)
if not tiles or not index then
return
end
return tiles[math.ceil(index / 2)]
end
function mcl_copper.register_copper_variants(name, definitions)
local names, oxidized_variant, stripped_variant, waxed_variant
if name ~= "cut" then
names = {
name, "waxed_"..name,
name.."_exposed", "waxed_"..name.."_exposed",
name.."_weathered", "waxed_"..name.."_weathered",
name.."_oxidized", "waxed_"..name.."_oxidized"
}
else
names = {
"block_"..name, "waxed_block_"..name,
"block_exposed_"..name, "waxed_block_exposed_"..name,
"block_weathered_"..name, "waxed_block_weathered_"..name,
"block_oxidized_"..name, "waxed_block_oxidized_"..name
}
end
local tiles = {
"mcl_copper_"..name..".png",
"mcl_copper_"..name.."_exposed.png",
"mcl_copper_"..name.."_weathered.png",
"mcl_copper_"..name.."_oxidized.png"
}
for i = 1, #names do
if names[i]:find("waxed") then
stripped_variant = "mcl_copper:"..names[i-1]
else
if not names[i]:find("oxidized") then
oxidized_variant = "mcl_copper:"..names[i+2]
end
if i ~= 1 then
stripped_variant = "mcl_copper:"..names[i-2]
end
waxed_variant = "mcl_copper:"..names[i+1]
end
minetest.register_node("mcl_copper:"..names[i], {
description = set_description(mcl_copper.copper_descs, name, i),
drawtype = definitions.drawtype or "normal",
drop = set_drop(definitions.drop, names[i], name),
groups = set_groups(names[i], definitions.groups),
is_ground_content = false,
light_source = set_light_level(definitions.light_source, i),
mesecons = definitions.mesecons,
paramtype = definitions.paramtype or "none",
paramtype2 = definitions.paramtype2 or "none",
sounds = mcl_sounds.node_sound_metal_defaults(),
sunlight_propagates = definitions.sunlight_propagates or false,
tiles = {set_tiles(tiles, i)},
_doc_items_longdesc = S(mcl_copper.copper_longdescs[name][math.ceil(i/2)]),
_mcl_blast_resistance = 6,
_mcl_hardness = 3,
_mcl_oxidized_variant = oxidized_variant,
_mcl_stripped_variant = stripped_variant,
_mcl_waxed_variant = waxed_variant,
})
if definitions._mcl_stairs then
local subname = mcl_copper.stairs_subnames[name][i]
mcl_stairs.register_slab(subname, "mcl_copper:"..names[i], set_groups(subname, definitions.groups),
{set_tiles(tiles, i), set_tiles(tiles, i), set_tiles(tiles, i)},
set_description(mcl_copper.stairs_descs, subname, 1), nil, nil, nil,
set_description(mcl_copper.stairs_descs, subname, 2)
)
mcl_stairs.register_stair(subname, "mcl_copper:"..names[i], set_groups(subname, definitions.groups),
{set_tiles(tiles, i), set_tiles(tiles, i), set_tiles(tiles, i),
set_tiles(tiles, i), set_tiles(tiles, i), set_tiles(tiles, i)},
set_description(mcl_copper.stairs_descs, subname, 3), nil, nil, nil, "woodlike"
)
end
if definitions._mcl_doors then
local itemimg, lowertext, uppertext, frontimg, sideimg
local door_groups = set_groups(names[i]:gsub(name, "door"), definitions.groups)
local trapdoor_groups = set_groups(names[i]:gsub(name, "trapdoor"), definitions.groups)
if i % 2 == 1 then
itemimg = "mcl_copper_item_"..names[i]:gsub(name, "door")..".png"
lowertext = "mcl_copper_"..names[i]:gsub(name, "door").."_lower.png"
uppertext = "mcl_copper_"..names[i]:gsub(name, "door").."_upper.png"
frontimg = "mcl_copper_"..names[i]:gsub(name, "trapdoor")..".png"
sideimg = "mcl_copper_"..names[i]:gsub(name, "trapdoor").."_side.png"
else
itemimg = "mcl_copper_item_"..names[i-1]:gsub(name, "door")..".png"
lowertext = "mcl_copper_"..names[i-1]:gsub(name, "door").."_lower.png"
uppertext = "mcl_copper_"..names[i-1]:gsub(name, "door").."_upper.png"
frontimg = "mcl_copper_"..names[i-1]:gsub(name, "trapdoor")..".png"
sideimg = "mcl_copper_"..names[i-1]:gsub(name, "trapdoor").."_side.png"
end
mcl_doors:register_door("mcl_copper:"..names[i]:gsub(name, "door"), {
description = S(mcl_copper.doors_descs[i][1]),
groups = door_groups,
inventory_image = itemimg,
only_redstone_can_open = false,
sounds = mcl_sounds.node_sound_metal_defaults(),
sound_close = "doors_steel_door_close",
sound_open = "doors_steel_door_open",
tiles_bottom = lowertext,
tiles_top = uppertext,
_mcl_blast_resistance = 3,
_mcl_hardness = 3
})
mcl_doors:register_trapdoor("mcl_copper:"..names[i]:gsub(name, "trapdoor"), {
description = S(mcl_copper.doors_descs[i][2]),
groups = trapdoor_groups,
only_redstone_can_open = false,
sounds = mcl_sounds.node_sound_metal_defaults(),
sound_close = "doors_steel_door_close",
sound_open = "doors_steel_door_open",
tile_front = frontimg,
tile_side = sideimg,
wield_image = frontimg,
_mcl_blast_resistance = 3,
_mcl_hardness = 3
})
end
end
end
minetest.register_node("mcl_copper:stone_with_copper", {
description = S("Copper Ore"),
_doc_items_longdesc = S("Some copper contained in stone, it is pretty common and can be found below sea level."),
@ -17,326 +203,81 @@ minetest.register_node("mcl_copper:stone_with_copper", {
minetest.register_node("mcl_copper:block_raw", {
description = S("Block of Raw Copper"),
_doc_items_longdesc = S("A block used for compact raw copper storage."),
tiles = {"mcl_copper_block_raw.png"},
tiles = {"mcl_copper_raw_block.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, blast_furnace_smeltable = 1 },
groups = {pickaxey = 2, building_block = 1, blast_furnace_smeltable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
})
minetest.register_node("mcl_copper:block", {
description = S("Block of Copper"),
_doc_items_longdesc = S("A block of copper is mostly a decorative block."),
tiles = {"mcl_copper_block.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 3,
_mcl_oxidized_variant = "mcl_copper:block_exposed",
_mcl_waxed_variant = "mcl_copper:waxed_block",
})
minetest.register_node("mcl_copper:waxed_block", {
description = S("Waxed Block of Copper"),
_doc_items_longdesc = S("A block of copper is mostly a decorative block."),
tiles = {"mcl_copper_block.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block",
})
minetest.register_node("mcl_copper:block_exposed", {
description = S("Exposed Copper"),
_doc_items_longdesc = S("Exposed copper is a decorative block."),
tiles = {"mcl_copper_exposed.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_oxidized_variant = "mcl_copper:block_weathered",
_mcl_waxed_variant = "mcl_copper:waxed_block_exposed",
_mcl_stripped_variant = "mcl_copper:block",
})
minetest.register_node("mcl_copper:waxed_block_exposed", {
description = S("Waxed Exposed Copper"),
_doc_items_longdesc = S("Exposed copper is a decorative block."),
tiles = {"mcl_copper_exposed.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_exposed",
})
minetest.register_node("mcl_copper:block_weathered", {
description = S("Weathered Copper"),
_doc_items_longdesc = S("Weathered copper is a decorative block."),
tiles = {"mcl_copper_weathered.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_oxidized_variant = "mcl_copper:block_oxidized",
_mcl_waxed_variant = "mcl_copper:waxed_block_weathered",
_mcl_stripped_variant = "mcl_copper:block_exposed",
})
minetest.register_node("mcl_copper:waxed_block_weathered", {
description = S("Waxed Weathered Copper"),
_doc_items_longdesc = S("Weathered copper is a decorative block."),
tiles = {"mcl_copper_weathered.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_weathered",
})
minetest.register_node("mcl_copper:block_oxidized", {
description = S("Oxidized Copper"),
_doc_items_longdesc = S("Oxidized copper is a decorative block."),
tiles = {"mcl_copper_oxidized.png"},
is_ground_content = false,
mcl_copper.register_copper_variants("block", {
groups = {pickaxey = 2, building_block = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_waxed_variant = "mcl_copper:waxed_block_oxidized",
_mcl_stripped_variant = "mcl_copper:block_weathered",
_mcl_doors = true,
})
minetest.register_node("mcl_copper:waxed_block_oxidized", {
description = S("Waxed Oxidized Copper"),
_doc_items_longdesc = S("Oxidized copper is a decorative block."),
tiles = {"mcl_copper_oxidized.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_oxidized",
})
minetest.register_node("mcl_copper:block_cut", {
description = S("Cut Copper"),
_doc_items_longdesc = S("Cut copper is a decorative block."),
tiles = {"mcl_copper_block_cut.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_oxidized_variant = "mcl_copper:block_exposed_cut",
_mcl_waxed_variant = "mcl_copper:waxed_block_cut",
})
minetest.register_node("mcl_copper:waxed_block_cut", {
description = S("Waxed Cut Copper"),
_doc_items_longdesc = S("Cut copper is a decorative block."),
tiles = {"mcl_copper_block_cut.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_cut",
})
minetest.register_node("mcl_copper:block_exposed_cut", {
description = S("Exposed Cut Copper"),
_doc_items_longdesc = S("Exposed cut copper is a decorative block."),
tiles = {"mcl_copper_exposed_cut.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_waxed_variant = "mcl_copper:waxed_block_exposed_cut",
_mcl_oxidized_variant = "mcl_copper:block_weathered_cut",
_mcl_stripped_variant = "mcl_copper:block_cut",
})
minetest.register_node("mcl_copper:waxed_block_exposed_cut", {
description = S("Waxed Exposed Cut Copper"),
_doc_items_longdesc = S("Exposed cut copper is a decorative block."),
tiles = {"mcl_copper_exposed_cut.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_exposed_cut",
})
minetest.register_node("mcl_copper:block_weathered_cut", {
description = S("Weathered Cut Copper"),
_doc_items_longdesc = S("Weathered cut copper is a decorative block."),
tiles = {"mcl_copper_weathered_cut.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_exposed_cut",
_mcl_oxidized_variant = "mcl_copper:block_oxidized_cut",
_mcl_waxed_variant = "mcl_copper:waxed_block_weathered_cut",
})
minetest.register_node("mcl_copper:waxed_block_weathered_cut", {
description = S("Waxed Weathered Cut Copper"),
_doc_items_longdesc = S("Weathered cut copper is a decorative block."),
tiles = {"mcl_copper_weathered_cut.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_weathered_cut",
})
minetest.register_node("mcl_copper:block_oxidized_cut", {
description = S("Oxidized Cut Copper"),
_doc_items_longdesc = S("Oxidized cut copper is a decorative block."),
tiles = {"mcl_copper_oxidized_cut.png"},
is_ground_content = false,
mcl_copper.register_copper_variants("cut", {
groups = {pickaxey = 2, building_block = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_weathered_cut",
_mcl_waxed_variant = "mcl_copper:waxed_block_oxidized_cut",
_mcl_stairs = true,
})
minetest.register_node("mcl_copper:waxed_block_oxidized_cut", {
description = S("Waxed Oxidized Cut Copper"),
_doc_items_longdesc = S("Oxidized cut copper is a decorative block."),
tiles = {"mcl_copper_oxidized_cut.png"},
is_ground_content = false,
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_stripped_variant = "mcl_copper:block_oxidized_cut",
mcl_copper.register_copper_variants("grate", {
drawtype = "allfaces",
groups = {pickaxey = 2, building_block = 1, disable_suffocation = 1},
sunlight_propagates = true,
})
mcl_stairs.register_slab("copper_cut", "mcl_copper:block_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png"},
S("Slab of Cut Copper"),
nil, nil, nil,
S("Double Slab of Cut Copper"))
mcl_copper.register_copper_variants("chiseled", {
groups = {pickaxey = 2, building_block = 1}
})
mcl_stairs.register_slab("waxed_copper_cut", "mcl_copper:waxed_block_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png"},
S("Waxed Slab of Cut Copper"),
nil, nil, nil,
S("Waxed Double Slab of Cut Copper"))
mcl_copper.register_copper_variants("bulb_off", {
groups = {pickaxey = 2, building_block = 1},
mesecons = {
effector = {
action_on = function (pos, node)
minetest.swap_node(pos, {name = node.name:gsub("bulb_off", "bulb_powered_on")})
end
},
},
})
mcl_stairs.register_slab("copper_exposed_cut", "mcl_copper:block_exposed_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png"},
S("Slab of Exposed Cut Copper"),
nil, nil, nil,
S("Double Slab of Exposed Cut Copper"))
mcl_copper.register_copper_variants("bulb_on", {
drop = "bulb_off",
groups = {pickaxey = 2, building_block = 1, not_in_creative_inventory = 1},
light_source = 14,
mesecons = {
effector = {
action_on = function (pos, node)
minetest.swap_node(pos, {name = node.name:gsub("bulb_on", "bulb_powered_off")})
end
},
},
paramtype = "light"
})
mcl_stairs.register_slab("waxed_copper_exposed_cut", "mcl_copper:waxed_block_exposed_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png"},
S("Waxed Slab of Exposed Cut Copper"),
nil, nil, nil,
S("Waxed Double Slab of Exposed Cut Copper"))
mcl_copper.register_copper_variants("bulb_powered_off", {
drop = "bulb_off",
groups = {pickaxey = 2, building_block = 1, not_in_creative_inventory = 1},
mesecons = {
effector = {
action_off = function (pos, node)
minetest.swap_node(pos, {name = node.name:gsub("bulb_powered_off", "bulb_off")})
end
}
}
})
mcl_stairs.register_slab("copper_weathered_cut", "mcl_copper:block_weathered_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png"},
S("Slab of Weathered Cut Copper"),
nil, nil, nil,
S("Double Slab of Weathered Cut Copper"))
mcl_stairs.register_slab("waxed_copper_weathered_cut", "mcl_copper:waxed_block_weathered_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png"},
S("Waxed Slab of Weathered Cut Copper"),
nil, nil, nil,
S("Waxed Double Slab of Weathered Cut Copper"))
mcl_stairs.register_slab("copper_oxidized_cut", "mcl_copper:block_oxidized_cut",
{pickaxey = 2},
{"mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png"},
S("Slab of Oxidized Cut Copper"),
nil, nil, nil,
S("Double Slab of Oxidized Cut Copper"))
mcl_stairs.register_slab("waxed_copper_oxidized_cut", "mcl_copper:waxed_block_oxidized_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png"},
S("Waxed Slab of Oxidized Cut Copper"),
nil, nil, nil,
S("Waxed Double Slab of Oxidized Cut Copper"))
mcl_stairs.register_stair("copper_cut", "mcl_copper:block_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png"},
S("Stairs of Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_cut", "mcl_copper:waxed_block_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png"},
S("Waxed Stairs of Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_stairs.register_stair("copper_exposed_cut", "mcl_copper:block_exposed_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png"},
S("Stairs of Exposed Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_exposed_cut", "mcl_copper:waxed_block_exposed_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png"},
S("Waxed Stairs of Exposed Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_stairs.register_stair("copper_weathered_cut", "mcl_copper:block_weathered_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png"},
S("Stairs of Weathered Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_weathered_cut", "mcl_copper:waxed_block_weathered_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png"},
S("Waxed Stairs of Weathered Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_stairs.register_stair("copper_oxidized_cut", "mcl_copper:block_oxidized_cut",
{pickaxey = 2},
{"mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png"},
S("Stairs of Oxidized Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_oxidized_cut", "mcl_copper:waxed_block_oxidized_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png"},
S("Waxed Stairs of Oxidized Cut Copper"),
nil, 6, nil,
"woodlike")
mcl_copper.register_copper_variants("bulb_powered_on", {
drop = "bulb_off",
groups = {pickaxey = 2, building_block = 1, not_in_creative_inventory = 1},
light_source = 14,
mesecons = {
effector = {
action_off = function (pos, node)
minetest.swap_node(pos, {name = node.name:gsub("bulb_powered_on", "bulb_on")})
end
}
},
paramtype = "light"
})

View File

@ -164,12 +164,6 @@ minetest.register_node("mcl_core:deadbush", {
_mcl_hardness = 0,
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_core:deadbush",
burntime = 5,
})
minetest.register_node("mcl_core:barrier", {
description = S("Barrier"),
_doc_items_longdesc = S("Barriers are invisible walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block."),

View File

@ -1,6 +1,6 @@
# textdomain: mcl_crafting_table
Crafting Table=Etabli
A crafting table is a block which grants you access to a 3×3 crafting grid which allows you to perform advanced crafts.=Un établi est un bloc qui vous donne accès à une grille d'établi 3×3 qui vous permet de fabriquer des objets avancés.
A crafting table is a block which grants you access to a 3×3 crafting grid which allows you to perform advanced crafts.=Un établi est un bloc qui vous donne accès à une grille d'établi 3×3 qui vous permet d'effectuer des objets avancés.
Rightclick the crafting table to access the 3×3 crafting grid.=Faites un clic droit sur l'établi pour accéder à la grille d'établi 3x3.
Recipe book=Livre de Recette
Crafting=Fabriquer

View File

@ -5,8 +5,8 @@ local modpath = minetest.get_modpath(modname)
-- by debiankaios
-- adapted for mcl2 by cora
local wood_slab_groups = {handy = 1, axey = 1, material_wood = 1, wood_slab = 1}
local wood_stair_groups = {handy = 1, axey = 1, material_wood = 1, wood_stairs = 1}
local wood_slab_groups = {handy = 1, axey = 1, flammable = 3, material_wood = 1, fire_encouragement = 5, fire_flammability = 20, wood_slab = 1}
local wood_stair_groups = {handy = 1, axey = 1, flammable = 3, material_wood = 1, fire_encouragement = 5, fire_flammability = 20, wood_stairs = 1}
local function generate_warped_tree(pos)
minetest.place_schematic(pos,modpath.."/schematics/warped_fungus_1.mts","random",nil,false,"place_center_x,place_center_z")
@ -463,7 +463,7 @@ minetest.register_craft({
minetest.register_node("mcl_crimson:warped_hyphae_wood", {
description = S("Warped Hyphae Wood"),
tiles = {"mcl_crimson_warped_hyphae_wood.png"},
groups = {handy = 5,axey = 1, wood=1,building_block = 1, material_wood = 1},
groups = {handy = 5,axey = 1, flammable = 3, wood=1,building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20},
sounds = mcl_sounds.node_sound_wood_defaults(),
_mcl_hardness = 2,
})
@ -478,27 +478,6 @@ minetest.register_craft({
},
})
minetest.register_craft({
output = "mcl_crimson:warped_hyphae_wood 4",
recipe = {
{"mcl_crimson:warped_hyphae_bark"},
},
})
minetest.register_craft({
output = "mcl_crimson:warped_hyphae_wood 4",
recipe = {
{"mcl_crimson:stripped_warped_hyphae"},
},
})
minetest.register_craft({
output = "mcl_crimson:warped_hyphae_wood 4",
recipe = {
{"mcl_crimson:stripped_warped_hyphae_bark"},
},
})
minetest.register_craft({
output = "mcl_crimson:warped_nylium 2",
recipe = {
@ -691,27 +670,6 @@ minetest.register_craft({
},
})
minetest.register_craft({
output = "mcl_crimson:crimson_hyphae_wood 4",
recipe = {
{"mcl_crimson:crimson_hyphae_bark"},
},
})
minetest.register_craft({
output = "mcl_crimson:crimson_hyphae_wood 4",
recipe = {
{"mcl_crimson:stripped_crimson_hyphae"},
},
})
minetest.register_craft({
output = "mcl_crimson:crimson_hyphae_wood 4",
recipe = {
{"mcl_crimson:stripped_crimson_hyphae_bark"},
},
})
minetest.register_craft({
output = "mcl_crimson:crimson_nylium 2",
recipe = {
@ -757,7 +715,7 @@ mcl_doors:register_door("mcl_crimson:crimson_door", {
_doc_items_longdesc = S("Wooden doors are 2-block high barriers which can be opened or closed by hand and by a redstone signal."),
_doc_items_usagehelp = S("To open or close a wooden door, rightclick it or supply its lower half with a redstone signal."),
inventory_image = "mcl_crimson_crimson_door.png",
groups = {handy=1,axey=1, material_wood=1},
groups = {handy=1,axey=1, material_wood=1, flammable=-1},
_mcl_hardness = 3,
_mcl_blast_resistance = 3,
tiles_bottom = "mcl_crimson_crimson_door_bottom.png",
@ -772,7 +730,7 @@ mcl_doors:register_trapdoor("mcl_crimson:crimson_trapdoor", {
tile_front = "mcl_crimson_crimson_trapdoor.png",
tile_side = "mcl_crimson_crimson_trapdoor_side.png",
wield_image = "mcl_crimson_crimson_trapdoor.png",
groups = {handy=1,axey=1, mesecon_effector_on=1, material_wood=1},
groups = {handy=1,axey=1, mesecon_effector_on=1, material_wood=1, flammable=-1},
_mcl_hardness = 3,
_mcl_blast_resistance = 3,
sounds = mcl_sounds.node_sound_wood_defaults(),
@ -783,7 +741,7 @@ mcl_fences.register_fence_and_fence_gate(
S("Crimson Fence"),
S("Crimson Fence Gate"),
"mcl_crimson_crimson_fence.png",
{handy=1,axey=1,fence_wood=1},
{handy=1,axey=1, flammable=2,fence_wood=1, fire_encouragement=5, fire_flammability=20},
minetest.registered_nodes["mcl_crimson:crimson_hyphae"]._mcl_hardness,
minetest.registered_nodes["mcl_crimson:crimson_hyphae"]._mcl_blast_resistance,
{"group:fence_wood"},
@ -795,7 +753,7 @@ mcl_doors:register_door("mcl_crimson:warped_door", {
_doc_items_longdesc = S("Wooden doors are 2-block high barriers which can be opened or closed by hand and by a redstone signal."),
_doc_items_usagehelp = S("To open or close a wooden door, rightclick it or supply its lower half with a redstone signal."),
inventory_image = "mcl_crimson_warped_door.png",
groups = {handy=1,axey=1, material_wood=1},
groups = {handy=1,axey=1, material_wood=1, flammable=-1},
_mcl_hardness = 3,
_mcl_blast_resistance = 3,
tiles_bottom = "mcl_crimson_warped_door_bottom.png",
@ -810,7 +768,7 @@ mcl_doors:register_trapdoor("mcl_crimson:warped_trapdoor", {
tile_front = "mcl_crimson_warped_trapdoor.png",
tile_side = "mcl_crimson_warped_trapdoor_side.png",
wield_image = "mcl_crimson_warped_trapdoor.png",
groups = {handy=1,axey=1, mesecon_effector_on=1, material_wood=1},
groups = {handy=1,axey=1, mesecon_effector_on=1, material_wood=1, flammable=-1},
_mcl_hardness = 3,
_mcl_blast_resistance = 3,
sounds = mcl_sounds.node_sound_wood_defaults(),
@ -821,7 +779,7 @@ mcl_fences.register_fence_and_fence_gate(
S("Warped Fence"),
S("Warped Fence Gate"),
"mcl_crimson_warped_fence.png",
{handy=1,axey=1,fence_wood=1},
{handy=1,axey=1, flammable=2,fence_wood=1, fire_encouragement=5, fire_flammability=20},
minetest.registered_nodes["mcl_crimson:warped_hyphae"]._mcl_hardness,
minetest.registered_nodes["mcl_crimson:warped_hyphae"]._mcl_blast_resistance,
{"group:fence_wood"},

View File

@ -182,10 +182,6 @@ local function apply_bone_meal(pointed_thing, user)
local n = minetest.get_node(pos)
if n.name == "" then return false end
if mcl_util.check_area_protection(pos, pointed_thing.above, user) then
return false
end
for _, func in pairs(mcl_dye.bone_meal_callbacks) do
if func(pointed_thing, user) then
return true

View File

@ -60,21 +60,32 @@ minetest.register_node("mcl_end:purpur_pillar", {
})
local end_rod_name = "mcl_end:end_rod"
local end_rod_side_tex = "mcl_end_end_rod_side.png"
local end_rod_def = {
description = S("End Rod"),
_doc_items_longdesc = S("End rods are decorative light sources."),
tiles = {
"mcl_end_end_rod.png",
"mcl_end_end_rod_top.png",
"mcl_end_end_rod_bottom.png",
end_rod_side_tex,
end_rod_side_tex,
end_rod_side_tex,
end_rod_side_tex,
},
drawtype = "mesh",
mesh = "mcl_end_rod.obj",
drawtype = "nodebox",
is_ground_content = false,
paramtype = "light",
paramtype2 = "facedir",
light_source = minetest.LIGHT_MAX,
sunlight_propagates = true,
groups = { dig_immediate=3, deco_block=1, destroy_by_lava_flow=1, end_rod=1 },
use_texture_alpha = "clip",
node_box = {
type = "fixed",
fixed = {
{-0.125, -0.5, -0.125, 0.125, -0.4375, 0.125}, -- Base
{-0.0625, -0.4375, -0.0625, 0.0625, 0.5, 0.0625}, -- Rod
},
},
selection_box = {
type = "fixed",
fixed = {
@ -145,7 +156,8 @@ local colored_end_rods = {
{"lime", S("Lime End Rod"), "green"},
{"lightblue", S("Light Blue End Rod"), "lightblue"},
}
local end_rod_mask = "^[mask:mcl_end_end_rod_mask.png"
local top_mask = "^[mask:mobs_mc_empty.png\\^[fill\\:2x2\\:7,7\\:white"
local side_mask = "^[mask:mobs_mc_empty.png\\^[fill\\:16x15\\:0,0\\:white"
for num, row in ipairs(colored_end_rods) do
local name = row[1]
local desc = row[2]
@ -154,15 +166,18 @@ for num, row in ipairs(colored_end_rods) do
def.description = desc
def._doc_items_longdesc = nil
def._doc_items_create_entry = false
def.use_texture_alpha = "clip"
local side_tex
if name == "pink" then
def.tiles[1] = def.tiles[1] .. "^(" .. def.tiles[1] .. end_rod_mask .. "^[multiply:" .. name .. "^[hsl:0:300)"
def.tiles[1] = def.tiles[1] .. "^(" .. def.tiles[1] .. top_mask .. "^[multiply:" .. name .. "^[hsl:0:300)"
side_tex = end_rod_side_tex .. "^(" .. end_rod_side_tex .. side_mask .. "^[multiply:" .. name .. "^[hsl:0:300)"
elseif num > 4 then
def.tiles[1] = def.tiles[1] .. "^(" .. def.tiles[1] .. end_rod_mask .. "^[multiply:" .. name .. "^[hsl:0:300^[opacity:120)"
def.tiles[1] = def.tiles[1] .. "^(" .. def.tiles[1] .. top_mask .. "^[multiply:" .. name .. "^[hsl:0:300^[opacity:120)"
side_tex = end_rod_side_tex .. "^(" .. end_rod_side_tex .. side_mask .. "^[multiply:" .. name .. "^[hsl:0:300^[opacity:120)"
else
def.tiles[1] = def.tiles[1] .. "^(" .. def.tiles[1] .. end_rod_mask .. "^[multiply:" .. name .. "^[hsl:0:-100^[opacity:170)"
def.tiles[1] = def.tiles[1] .. "^(" .. def.tiles[1] .. top_mask .. "^[multiply:" .. name .. "^[hsl:0:-100^[opacity:170)"
side_tex = end_rod_side_tex .. "^(" .. end_rod_side_tex .. side_mask .. "^[multiply:" .. name .. "^[hsl:0:-100^[opacity:170)"
end
for i=3, 6 do def.tiles[i] = side_tex end
minetest.register_node(end_rod_name.."_"..name, def)
minetest.register_craft({
type = "shapeless",

View File

@ -17,7 +17,7 @@ A chorus plant stem is the part of a chorus plant which holds the whole plant to
Chorus Fruit=Fruit de chorus
A chorus fruit is an edible fruit from the chorus plant which is home to the End. Eating it teleports you to the top of a random solid block nearby, provided you won't end up inside a liquid, solid or harmful blocks. Teleportation might fail if there are very few or no places to teleport to.=Un fruit de chorus est un fruit comestible de l'usine de chorus qui abrite la fin. Le manger vous téléporte au sommet d'un bloc solide aléatoire à proximité, à condition de ne pas vous retrouver dans un bloc liquide, solide ou nuisible. La téléportation peut échouer s'il y a très peu ou pas d'endroits où se téléporter.
Popped Chorus Fruit=Chorus éclaté
Eye of Ender=Oeil de l'Ender
Eye of Ender=Œil de l'Ender
This item is used to locate End portal shrines in the Overworld and to activate End portals.=Cet objet est utilisé pour localiser les sanctuaires du portail de l'End dans l'Overworld et pour activer les portails de l'End.
Use the attack key to release the eye of ender. It will rise and fly in the horizontal direction of the closest end portal shrine. If you're very close, the eye of ender will take the direct path to the End portal shrine instead. After a few seconds, it stops. It may drop as an item, but there's a 20% chance it shatters.=Utilisez la touche d'attaque pour libérer l'œil d'Ender. Il s'élèvera et volera dans la direction horizontale du sanctuaire portail de l'End le plus proche. Si vous êtes très proche, l'œil d'Ender empruntera le chemin direct vers le sanctuaire du portail de l'End. Après quelques secondes, il s'arrête. Il peut tomber en tant qu'objet, mais il y a 20% de chances qu'il se brise.
To activate an End portal, eyes of ender need to be placed into each block of an intact End portal frame.=Pour activer un portail de l'End, les yeux d'ender doivent être placés dans chaque bloc d'un cadre de portail de l'End intact.

View File

@ -1,67 +0,0 @@
# Blender 3.6.7
# www.blender.org
o Cube
v 0.125000 -0.437500 -0.125000
v 0.125000 -0.500000 -0.125000
v 0.125000 -0.437500 0.125000
v 0.125000 -0.500000 0.125000
v -0.125000 -0.437500 -0.125000
v -0.125000 -0.500000 -0.125000
v -0.125000 -0.437500 0.125000
v -0.125000 -0.500000 0.125000
v -0.062500 -0.437500 0.062500
v -0.062500 0.500000 0.062500
v -0.062500 -0.437500 -0.062500
v -0.062500 0.500000 -0.062500
v 0.062500 -0.437500 0.062500
v 0.062500 0.500000 0.062500
v 0.062500 -0.437500 -0.062500
v 0.062500 0.500000 -0.062500
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vt 0.250000 1.000000
vt -0.000000 1.000000
vt -0.000000 0.750000
vt 0.250000 0.750000
vt 0.250000 0.000000
vt 0.250000 0.062500
vt 0.000000 0.062500
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 0.062500
vt 0.750000 0.062500
vt 0.750000 0.000000
vt 0.000000 0.437500
vt 0.250000 0.437500
vt 0.250000 0.687500
vt 0.000000 0.687500
vt 0.500000 0.000000
vt 0.500000 0.062500
vt 1.000000 1.000000
vt 0.875000 1.000000
vt 0.875000 0.062500
vt 0.750000 1.000000
vt 0.625000 1.000000
vt 0.625000 0.062500
vt 0.500000 1.000000
vt 0.187500 0.812500
vt 0.187500 0.937500
vt 0.062500 0.937500
vt 0.062500 0.812500
s 0
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/6/2 7/7/2 8/8/2
f 8/9/3 7/10/3 5/11/3 6/12/3
f 6/13/4 2/14/4 4/15/4 8/16/4
f 2/17/5 1/18/5 3/6/5 4/5/5
f 6/12/6 5/11/6 1/18/6 2/17/6
f 9/10/3 10/19/3 12/20/3 11/21/3
f 11/21/6 12/20/6 16/22/6 15/11/6
f 15/11/5 16/22/5 14/23/5 13/24/5
f 13/24/2 14/23/2 10/25/2 9/18/2
f 11/26/4 15/27/4 13/28/4 9/29/4
f 16/27/1 12/28/1 10/29/1 14/26/1

View File

@ -96,7 +96,7 @@ Hay bales are decorative blocks made from wheat.=Les balles de foin sont des blo
To carve a face into the pumpkin, use the shears on the side you want to carve.=Pour sculpter un visage dans la citrouille, utilisez les cisailles du côté que vous souhaitez sculpter.
Use the “Place” key on an animal to try to feed it wheat.=Utilisez la touche "Placer" sur un animal pour essayer de le nourrir de blé.
Grows on farmland=Pousse sur les terres agricoles
Turns block into farmland=Transforme un bloc en terre agricole
Turns block into farmland=Transforme un bloc en terres agricoles
60% chance of poisoning=60% de chances d'empoisonnement
Surface for crops=Surface pour les cultures
Can become wet=Peut devenir humide

View File

@ -2,7 +2,7 @@
Fishing Rod=Canne à pêche
Fishing rods can be used to catch fish.=Les cannes à pêche peuvent être utilisées pour attraper du poisson.
Rightclick to launch the bobber. When it sinks right-click again to reel in an item. Who knows what you're going to catch?=Clic droit pour lancer le bouchon. Lorsqu'il s'enfonce, cliquez de nouveau avec le bouton droit pour rembobiner. Qui sait ce que tu vas attraper?
Raw Fish=Poisson cru
Raw Fish=Poisson Cru
Raw fish is obtained by fishing and is a food item which can be eaten safely. Cooking it improves its nutritional value.=Le poisson cru est obtenu par la pêche et est un aliment qui peut être mangé en toute sécurité. La cuisson améliore sa valeur nutritive.
Cooked Fish=Poisson cuit
Mmh, fish! This is a healthy food item.=Mmh, poisson! Il s'agit d'un aliment sain.
@ -10,9 +10,9 @@ Raw Salmon=Saumon cru
Raw salmon is obtained by fishing and is a food item which can be eaten safely. Cooking it improves its nutritional value.=Le saumon cru est obtenu par la pêche et est un aliment qui peut être consommé en toute sécurité. La cuisson améliore sa valeur nutritive.
Cooked Salmon=Saumon cuit
This is a healthy food item which can be eaten.=Il s'agit d'un aliment sain qui peut être consommé.
Clownfish=Poisson-clown
Clownfish=Poisson-Clown
Clownfish may be obtained by fishing (and luck) and is a food item which can be eaten safely.=Le poisson-clown peut être obtenu par la pêche (et la chance) et est un aliment qui peut être mangé en toute sécurité.
Pufferfish=Poisson-globe
Pufferfish=Poisson-Globe
Pufferfish are a common species of fish and can be obtained by fishing. They can technically be eaten, but they are very bad for humans. Eating a pufferfish only restores 1 hunger point and will poison you very badly (which drains your health non-fatally) and causes serious food poisoning (which increases your hunger).=Le poisson-globe est une espèce de poisson commune et peut être obtenu par la pêche. Ils peuvent techniquement être mangés, mais ils sont très mauvais pour les humains. Manger un poisson-globe ne restaure que 1 point de faim et vous empoisonnera fortement (ce qui draine votre santé de manière non fatale) et provoque une grave intoxication alimentaire (qui augmente votre faim).
Catches fish in water=Attrape les poissons dans l'eau
Very poisonous=Très toxique

View File

@ -23,10 +23,4 @@ minetest.register_craft({
{ "group:wood", "group:wood", "" },
{ "group:wood", "group:wood", "" },
}
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_fletching_table:fletching_table",
burntime = 15,
})
})

View File

@ -183,38 +183,6 @@ def_fern.groups.compostability = 65
minetest.register_node("mcl_flowers:fern", def_fern)
--- Clover ---
-- Similar deal as fern, we can copy a lot from tall grass
local def_clover = table.copy(def_tallgrass)
def_clover.description = S("Clover")
def_clover._doc_items_longdesc = S("Clovers are small plants which occur naturally in plains and other temperate biomes. They can be picked up and planted again.")
def_clover.drawtype = "mesh"
def_clover.mesh = "mcl_clover_3leaf.obj"
def_clover.tiles = { "mcl_flowers_clover.png" }
def_clover.inventory_image = "mcl_flowers_clover_inv.png"
def_clover.wield_image = "mcl_flowers_clover_inv.png"
def_clover.drop = nil
def_clover.use_texture_alpha = "clip"
def_clover.selection_box = {
type = "fixed",
fixed = { -4/16, -0.5, -4/16, 4/16, 0, 4/16 },
}
def_clover.groups.compostability = 30
minetest.register_node("mcl_flowers:clover", def_clover)
local def_4l_clover = table.copy(def_clover)
def_4l_clover.description = S("Four-leaf Clover")
def_4l_clover._doc_items_longdesc = S("Clovers are small plants which occur naturally in plains and other temperate biomes. They can be picked up and planted again.")
def_4l_clover.mesh = "mcl_clover_4leaf.obj"
def_4l_clover.tiles = { "mcl_flowers_fourleaf_clover.png" }
def_4l_clover.inventory_image = "mcl_flowers_fourleaf_clover_inv.png"
def_4l_clover.wield_image = "mcl_flowers_fourleaf_clover_inv.png"
def_4l_clover.use_texture_alpha = "clip"
minetest.register_node("mcl_flowers:fourleaf_clover", def_4l_clover)
if has_mcl_flowerpots then
mcl_flowerpots.register_potted_flower("mcl_flowers:fern", {
name = "fern",
@ -270,7 +238,6 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im
end
-- Sunflower mesh and tiles
local top_drawtype, bottom_drawtype
local alpha = nil
local bottom_tiles = {}
if not mesh then
top_drawtype = "plantlike"
@ -280,7 +247,6 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im
top_drawtype = "airlike"
bottom_drawtype = "mesh"
bottom_tiles = bottom_img
alpha = "clip"
end
-- Bottom
minetest.register_node("mcl_flowers:"..name, {
@ -302,7 +268,6 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im
_mcl_shears_drop = shears_drop,
_mcl_fortune_drop = fortune_drop,
node_placement_prediction = "",
use_texture_alpha = alpha,
selection_box = {
type = "fixed",
fixed = { -selbox_radius, -0.5, -selbox_radius, selbox_radius, 0.5, selbox_radius },
@ -402,7 +367,6 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im
palette = palette,
walkable = false,
buildable_to = false,
use_texture_alpha = alpha,
selection_box = {
type = "fixed",
fixed = { -selbox_radius, -0.5, -selbox_radius, selbox_radius, selbox_top_height, selbox_radius },

View File

@ -1,38 +0,0 @@
# Blender 3.6.7
# www.blender.org
mtllib mcl_clover_3leaf.mtl
o Plane
v 0.000000 -0.280000 0.000000
v 0.000000 -0.280000 0.000000
v -0.250000 -0.280000 -0.250000
v 0.250000 -0.280000 -0.250000
v 0.035355 -0.500000 0.035355
v 0.035355 -0.300000 0.035355
v -0.035355 -0.500000 -0.035355
v -0.035355 -0.300000 -0.035355
v 0.035355 -0.500000 -0.035355
v 0.035355 -0.300000 -0.035355
v -0.035355 -0.500000 0.035355
v -0.035355 -0.300000 0.035355
v -0.091506 -0.280000 0.341506
v -0.341506 -0.280000 -0.091506
v 0.000000 -0.280000 0.000000
v 0.341506 -0.280000 -0.091506
v 0.091506 -0.280000 0.341506
vn -0.0000 1.0000 -0.0000
vn -0.7071 -0.0000 0.7071
vn 0.7071 -0.0000 0.7071
vt 0.500000 0.437500
vt 1.000000 0.937500
vt 0.000000 0.937500
vt 0.437500 0.062500
vt 0.562500 0.062500
vt 0.562500 0.437500
vt 0.437500 0.437500
s 0
usemtl Material.001
f 2/1/1 4/2/1 3/3/1
f 5/4/2 6/5/2 8/6/2 7/7/2
f 9/4/3 10/5/3 12/6/3 11/7/3
f 1/1/1 14/2/1 13/3/1
f 15/1/1 17/2/1 16/3/1

View File

@ -1,32 +0,0 @@
# Blender 3.6.7
# www.blender.org
mtllib mcl_clover_4leaf.mtl
o Plane
v -0.250000 -0.280000 0.250000
v 0.250000 -0.280000 0.250000
v -0.250000 -0.280000 -0.250000
v 0.250000 -0.280000 -0.250000
v 0.035355 -0.500000 0.035355
v 0.035355 -0.300000 0.035355
v -0.035355 -0.500000 -0.035355
v -0.035355 -0.300000 -0.035355
v 0.035355 -0.500000 -0.035355
v 0.035355 -0.300000 -0.035355
v -0.035355 -0.500000 0.035355
v -0.035355 -0.300000 0.035355
vn -0.0000 1.0000 -0.0000
vn -0.7071 -0.0000 0.7071
vn 0.7071 -0.0000 0.7071
vt 0.000000 0.125000
vt 0.875000 0.125000
vt 0.875000 1.000000
vt 0.000000 1.000000
vt 0.875000 0.000000
vt 1.000000 0.000000
vt 1.000000 0.375000
vt 0.875000 0.375000
s 0
usemtl Material.001
f 1/1/1 2/2/1 4/3/1 3/4/1
f 5/5/2 6/6/2 8/7/2 7/8/2
f 9/5/3 10/6/3 12/7/3 11/8/3

View File

@ -466,9 +466,9 @@ function mcl_furnaces.hoppers_on_try_push(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z) then
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", nil, 1)
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src")
else
return inv, "fuel", mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", mcl_util.is_fuel, 1)
return inv, "fuel", mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", mcl_util.is_fuel)
end
end

View File

@ -8,22 +8,35 @@ local S = minetest.get_translator(minetest.get_current_modname())
local alldirs = { { x = 0, y = 0, z = 1 }, { x = 1, y = 0, z = 0 }, { x = 0, y = 0, z = -1 }, { x = -1, y = 0, z = 0 }, { x = 0, y = -1, z = 0 }, { x = 0, y = 1, z = 0 } }
-- Waxing Function
function mcl_honey.wax_block(pos, node, player, itemstack)
function mcl_honey.wax_block(pos, node, player, itemstack, pointed_thing)
-- prevent modification of protected nodes.
if mcl_util.check_position_protection(pos, player) then
return
end
local def = minetest.registered_nodes[node.name]
if def and def._mcl_waxed_variant then
node.name = def._mcl_waxed_variant
if player:get_player_control().sneak then
if def and def._mcl_waxed_variant then
if def.groups.door == 1 then
if node.name:find("_b_") then
local top_pos = { x = pos.x, y = pos.y + 1, z = pos.z }
minetest.swap_node(top_pos, { name = def._mcl_waxed_variant:gsub("_b_", "_t_"), param2 = node.param2 })
elseif node.name:find("_t_") then
local bot_pos = { x = pos.x, y = pos.y - 1, z = pos.z }
minetest.swap_node(bot_pos, { name = def._mcl_waxed_variant:gsub("_t_", "_b_"), param2 = node.param2 })
end
end
else
return
end
else
return
if def and def.on_rightclick then
return def.on_rightclick(pos, node, player, itemstack, pointed_thing)
end
end
node.name = def._mcl_waxed_variant
minetest.set_node(pos, node)
minetest.swap_node(pos, node)
awards.unlock(player:get_player_name(), "mcl:wax_on")
if not minetest.is_creative_enabled(player:get_player_name()) then
itemstack:take_item()
@ -46,7 +59,7 @@ minetest.register_craftitem("mcl_honey:honeycomb", {
local pos = pointed_thing.under
-- wax the block. This is the only viable usage of honeycomb's on_place. If it "fails" to wax, then nothing is changed.
return mcl_honey.wax_block(pos, node, placer, itemstack)
return mcl_honey.wax_block(pos, node, placer, itemstack, pointed_thing)
end,
})

View File

@ -32,68 +32,6 @@ local mcl_hoppers_formspec = table.concat({
"listring[current_player;main]",
})
local function straight_hopper_act(pos, node, active_object_count, active_count_wider)
local timer = minetest.get_node_timer(pos)
if timer:is_started() then
--Pause if already recived item this tick
return
end
timer:start(1.0)
-- Move from internal inventory to dst first
local dst_pos = vector.offset(pos, 0, -1, 0)
local dst_node = minetest.get_node(dst_pos)
local dst_name = dst_node.name
local dst_def = minetest.registered_nodes[dst_name]
if dst_def and dst_def._mcl_hopper_act then
dst_def._mcl_hopper_act( dst_pos, dst_node, active_object_count, active_count_wider )
end
mcl_util.hopper_push(pos, dst_pos)
local src_pos = vector.offset(pos, 0, 1, 0)
mcl_util.hopper_pull(pos, src_pos)
end
local function bent_hopper_act(pos, node, active_object_count, active_object_count_wider)
local timer = minetest.get_node_timer(pos)
if timer:is_started() then
--Pause if already recived item this tick
return
end
timer:start(1.0)
-- Check if we are empty
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local empty = inv:is_empty("main")
-- Determine to which side the hopper is facing, get nodes
local face = minetest.get_node(pos).param2
local dst_pos = {}
if face == 0 then
dst_pos = vector.offset(pos, -1, 0, 0)
elseif face == 1 then
dst_pos = vector.offset(pos, 0, 0, 1)
elseif face == 2 then
dst_pos = vector.offset(pos, 1, 0, 0)
elseif face == 3 then
dst_pos = vector.offset(pos, 0, 0, -1)
end
local dst_node = minetest.get_node(dst_pos)
local dst_name = dst_node.name
local dst_def = minetest.registered_nodes[dst_name]
if dst_def and dst_def._mcl_hopper_act then
dst_def._mcl_hopper_act( dst_pos, dst_node, active_object_count, active_object_count_wider )
end
if not empty then
mcl_util.hopper_push(pos, dst_pos)
end
local src_pos = vector.offset(pos, 0, 1, 0)
mcl_util.hopper_pull(pos, src_pos)
end
-- Downwards hopper (base definition)
---@type node_definition
@ -268,7 +206,6 @@ def_hopper_enabled.mesecons = {
end,
},
}
def_hopper_enabled._mcl_hopper_act = straight_hopper_act
minetest.register_node("mcl_hoppers:hopper", def_hopper_enabled)
@ -418,7 +355,6 @@ def_hopper_side_enabled.mesecons = {
end,
},
}
def_hopper_side_enabled._mcl_hopper_act = bent_hopper_act
minetest.register_node("mcl_hoppers:hopper_side", def_hopper_side_enabled)
---@type node_definition
@ -623,7 +559,24 @@ minetest.register_abm({
neighbors = { "group:container" },
interval = 1.0,
chance = 1,
action = straight_hopper_act,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.get_node_timer(pos):is_started() then
return
end
-- Move from internal inventory to dst first
local dst_pos = vector.offset(pos, 0, -1, 0)
local pushed = mcl_util.hopper_push(pos, dst_pos)
local src_pos = vector.offset(pos, 0, 1, 0)
mcl_util.hopper_pull(pos, src_pos)
local dst_node = minetest.get_node(dst_pos)
if pushed and (dst_node.name == "mcl_hoppers:hopper" or dst_node.name == "mcl_hoppers:hopper_side") then
--Pause destination hopper
minetest.get_node_timer(dst_pos):start(1.0)
end
end,
})
-- Register push/pull for "bent" hopper
@ -633,7 +586,35 @@ minetest.register_abm({
neighbors = { "group:container" },
interval = 1.0,
chance = 1,
action = bent_hopper_act,
action = function(pos, node, active_object_count, active_object_count_wider)
if minetest.get_node_timer(pos):is_started() then
--Pause if already recived item this tick
return
end
-- Determine to which side the hopper is facing, get nodes
local face = minetest.get_node(pos).param2
local dst_pos = {}
if face == 0 then
dst_pos = vector.offset(pos, -1, 0, 0)
elseif face == 1 then
dst_pos = vector.offset(pos, 0, 0, 1)
elseif face == 2 then
dst_pos = vector.offset(pos, 1, 0, 0)
elseif face == 3 then
dst_pos = vector.offset(pos, 0, 0, -1)
end
local pushed = mcl_util.hopper_push(pos, dst_pos)
local src_pos = vector.offset(pos, 0, 1, 0)
mcl_util.hopper_pull(pos, src_pos)
local dst_node = minetest.get_node(dst_pos)
if pushed and (dst_node.name == "mcl_hoppers:hopper" or dst_node.name == "mcl_hoppers:hopper_side") then
--Pause destination hopper
minetest.get_node_timer(dst_pos):start(1.0)
end
end,
})
minetest.register_craft({

View File

@ -638,7 +638,7 @@ function mcl_itemframes.create_base_definitions()
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
groups = { dig_immediate = 3, deco_block = 1, dig_by_piston = 1, container = 1, attached_node_facedir = 1 },
groups = { dig_immediate = 3, deco_block = 1, dig_by_piston = 1, container = 1, }, -- attached_node_facedir = 1 }, -- allows for more placement options.
sounds = mcl_sounds.node_sound_defaults(),
node_placement_prediction = "",

View File

@ -76,7 +76,8 @@ local lectern_def = {
if wdir == 0 then
return itemstack
-- IE., no Hanging Lecterns for you!
else
end
if wdir == 1 then
-- (only make standing nodes...)
-- Determine the rotation based on player's yaw
local yaw = pi * 2 - placer:get_look_horizontal()
@ -135,11 +136,5 @@ minetest.register_craft({
}
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_lectern:lectern",
burntime = 15,
})
-- Base Aliases.
minetest.register_alias("lectern", "mcl_lectern:lectern")

View File

@ -26,9 +26,3 @@ minetest.register_craft({
{ "group:wood", "group:wood", "" },
}
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_loom:loom",
burntime = 15,
})

View File

@ -399,39 +399,12 @@ minetest.register_craft({
}
})
minetest.register_craft({
output = "mcl_mangrove:mangrove_wood 4",
recipe = {
{"mcl_mangrove:mangrove_tree_bark"},
}
})
minetest.register_craft({
output = "mcl_mangrove:mangrove_wood 4",
recipe = {
{"mcl_mangrove:mangrove_stripped"},
}
})
minetest.register_craft({
output = "mcl_mangrove:mangrove_wood 4",
recipe = {
{"mcl_mangrove:mangrove_stripped_bark"},
}
})
minetest.register_craft({
type = "fuel",
recipe = "group:fence_wood",
burntime = 15,
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_mangrove:mangrove_roots",
burntime = 15,
})
local adjacents = {
vector.new(1,0,0),
vector.new(-1,0,0),

View File

@ -2,7 +2,7 @@
Rotten Flesh=Chair putréfiée
80% chance of food poisoning=80% de chances d'intoxication alimentaire
Yuck! This piece of flesh clearly has seen better days. If you're really desperate, you can eat it to restore a few hunger points, but there's a 80% chance it causes food poisoning, which increases your hunger for a while.=Beurk ! Ce morceau de chair a clairement connu des jours meilleurs. Si vous êtes vraiment désespéré, vous pouvez le manger pour restaurer quelques points de faim, mais il y a 80% de chances qu'il provoque une intoxication alimentaire, ce qui augmente votre faim pendant un certain temps.
Yuck! This piece of flesh clearly has seen better days. If you're really desperate, you can eat it to restore a few hunger points, but there's a 80% chance it causes food poisoning, which increases your hunger for a while.=Beurk! Ce morceau de chair a clairement connu des jours meilleurs. Si vous êtes vraiment désespéré, vous pouvez le manger pour restaurer quelques points de faim, mais il y a 80% de chances qu'il provoque une intoxication alimentaire, ce qui augmente votre faim pendant un certain temps.
Raw Mutton=Mouton cru
@ -10,7 +10,7 @@ Raw mutton is the flesh from a sheep and can be eaten safely. Cooking it will gr
Cooked Mutton=Mouton cuit
Cooked mutton is the cooked flesh from a sheep and is used as food.=Le mouton cuit est la chair cuite d'un mouton et est utilisé comme nourriture.
Raw Beef=Boeuf cru
Raw Beef=Boeuf Cru
Raw beef is the flesh from cows and can be eaten safely. Cooking it will greatly increase its nutritional value.=Le boeuf cru est la chair des vaches et peut être mangé en toute sécurité. La cuisson augmentera considérablement sa valeur nutritive.
@ -23,25 +23,25 @@ Raw chicken is a food item which is not safe to consume. You can eat it to resto
Cooked Chicken=Poulet cuit
A cooked chicken is a healthy food item which can be eaten.=Un poulet cuit est un aliment sain qui peut être mangé.
Raw Porkchop=Porc cru
Raw Porkchop=Porc Cru
A raw porkchop is the flesh from a pig and can be eaten safely. Cooking it will greatly increase its nutritional value.=Un porc cru est la chair d'un porc et peut être mangée en toute sécurité. La cuisson augmentera considérablement sa valeur nutritive.
Cooked Porkchop=Porc cuit
Cooked porkchop is the cooked flesh of a pig and is used as food.=Le porc cuit est la chair cuite d'un porc et est utilisé comme aliment.
Raw Rabbit=Lapin cru
Raw Rabbit=Lapin Cru
Raw rabbit is a food item from a dead rabbit. It can be eaten safely. Cooking it will increase its nutritional value.=Le lapin cru est un aliment provenant d'un lapin mort. Il peut être mangé en toute sécurité. La cuisson augmentera sa valeur nutritive.
Cooked Rabbit=Lapin cuit
This is a food item which can be eaten.=Il s'agit d'un aliment qui peut être mangé.
Milk=Lait
Removes all status effects=Supprime tous les effets de statut !
Removes all status effects=Supprime tous les effets de statut!
Milk is very refreshing and can be obtained by using a bucket on a cow. Drinking it will remove all status effects, but restores no hunger points.=Le lait est très rafraîchissant et peut être obtenu en utilisant un seau sur une vache. Le boire supprimera tous les effets de statut, mais ne restaure aucun point de faim.
Use the placement key to drink the milk.=Utilisez la touche de placement pour boire le lait.
Spider Eye=Oeil d'araignée
Spider Eye=Œil d'araignée
Poisonous=Toxique
Spider eyes are used mainly in crafting. If you're really desperate, you can eat a spider eye, but it will poison you briefly.=Les yeux d'araignée sont utilisés principalement dans l'artisanat. Si vous êtes vraiment désespéré, vous pouvez manger un œil d'araignée, mais cela vous empoisonnera brièvement.

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ Missing effect parameter!=Paramètre d'effet manquant!
Missing or invalid duration parameter!=Paramètre durée manquant ou invalide!
Invalid factor parameter!=Paramètre facteur invalide!
@1 is not an available status effect.=@1 n'est pas un effet disponible.
Fermented Spider Eye=Oeil d'araignée fermenté
Fermented Spider Eye=Œil d'araignée fermenté
Glass Bottle=Bouteille en verre
Liquid container=Récipient de liquide

View File

@ -251,15 +251,6 @@ local function remove_shield_entity(player, i)
end
end
local function is_node_stack(itemstack)
return itemstack:get_definition().drawtype -- only node's definition table contains element "drawtype"
end
local function is_rmb_conflicting_node(nodename)
local nodedef = minetest.registered_nodes[nodename]
return nodedef.on_rightclick
end
local function handle_blocking(player)
local player_shield = mcl_shields.players[player]
local rmb = player:get_player_control().RMB
@ -275,7 +266,7 @@ local function handle_blocking(player)
local pos = player:get_pos()
if shield_in_hand then
if not_blocking then
minetest.after(0.05, function()
minetest.after(0.25, function()
if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then
player_shield.blocking = 2
set_shield(player, true, 2)
@ -286,16 +277,11 @@ local function handle_blocking(player)
end
elseif shield_in_offhand then
local pointed_thing = mcl_util.get_pointed_thing(player, true)
local wielded_stack = player:get_wielded_item()
local offhand_can_block = (minetest.get_item_group(wielded_item(player), "bow") ~= 1
and minetest.get_item_group(wielded_item(player), "crossbow") ~= 1)
local offhand_can_block = (wielded_item(player) == "" or not pointed_thing)
and (minetest.get_item_group(wielded_item(player), "bow") ~= 1 and minetest.get_item_group(wielded_item(player), "crossbow") ~= 1)
if pointed_thing and pointed_thing.type == "node" then
local pointed_node = minetest.get_node(pointed_thing.under)
if minetest.get_item_group(pointed_node.name, "container") > 1
or is_rmb_conflicting_node(pointed_node.name)
or is_node_stack(wielded_stack)
then
if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "container") > 1 then
return
end
end
@ -304,7 +290,7 @@ local function handle_blocking(player)
return
end
if not_blocking then
minetest.after(0.05, function()
minetest.after(0.25, function()
if (not_blocking or not shield_in_hand) and shield_in_offhand and rmb and offhand_can_block then
player_shield.blocking = 1
set_shield(player, true, 1)

View File

@ -4,7 +4,10 @@
--- DateTime: 10/14/22 4:05 PM
---
--local logging = minetest.settings:get_bool("mcl_logging_mcl_signs",true)
local DEBUG = minetest.settings:get_bool("mcl_logging_mcl_signs", false) -- special debug setting.
if DEBUG then
minetest.log("action", "[mcl_signs] Signs API Loading")
end
@ -112,6 +115,9 @@ mcl_signs.registered_signs = {}
mcl_signs.registered_signs.wall_signs = {}
mcl_signs.registered_signs.standing_signs = {}
mcl_signs.registered_signs.hanging_signs = {} -- unused. prepping for future use.
-- DEFINE SIGN BASE TYPES
mcl_signs.wall_standard = {} -- initialize
mcl_signs.standing_standard = {} -- initialize
function mcl_signs.build_signs_info()
local n = 23 / 56 - 1 / 128 -- some required magic number from the original code.
@ -135,110 +141,37 @@ function mcl_signs.build_signs_info()
end
-- DEFINE SIGN BASE TYPES
local common_definition = {
_mcl_hardness = 1,
_mcl_blast_resistance = 1,
stack_max = 16,
sounds = node_sounds,
groups = mcl_signs.sign_groups,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
drawtype = "mesh",
paramtype = "light",
tiles = { "mcl_signs_sign.png" },
sunlight_propagates = true,
-- wall signs' & hanging signs' base (definition)
mcl_signs.wall_standard = {
description = S("Sign"),
_tt_help = S("Can be written"),
_doc_items_longdesc = S("Signs can be written and come in two variants: Wall sign and sign on a sign post. Signs can be placed on the top and the sides of other blocks, but not below them."),
_doc_items_usagehelp = S("After placing the sign, you can write something on it. You have 4 lines of text with up to 15 characters for each line; anything beyond these limits is lost. Not all characters are supported. The text can not be changed once it has been written; you have to break and place the sign again. Can be colored and made to glow."),
inventory_image = "mcl_signs_default_sign.png",
walkable = false,
is_ground_content = false,
wield_image = "mcl_signs_default_sign.png",
node_placement_prediction = "",
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "wallmounted",
drawtype = "mesh",
mesh = "mcl_signs_signonwallmount.obj",
selection_box = { type = "wallmounted", wall_side = { -0.5, -7 / 28, -0.5, -23 / 56, 7 / 28, 0.5 } },
tiles = { "mcl_signs_sign.png" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
groups = mcl_signs.sign_groups,
stack_max = 16,
sounds = node_sounds,
on_rightclick = function (pos, node, clicker, itemstack, pointed_thing)
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Right Click event.")
end
-- make sure player is clicking
if not clicker or not clicker:is_player() then
return
end
local item = clicker:get_wielded_item()
local iname = item:get_name()
local protected = mcl_util.check_position_protection(pos, clicker)
if node and not protected then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Right Click event on valid node.")
end
-- handle glow from glow_ink_sac *first*
if (iname == "mcl_mobitems:glow_ink_sac") then
clicker:set_wielded_item(item)
local success = mcl_signs:glow_sign(pos)
if success then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Glow Success.")
end
itemstack:take_item()
end
return
end
-- check the wielded item to make sure that it is a dye.
local txt_color = mcl_signs:get_color_for_sign(iname)
if txt_color ~= "false" then
clicker:set_wielded_item(item)
local success = mcl_signs:color_sign(pos, txt_color)
-- "mcl_dye:black" is a special case: it makes the sign's lettering black AND removes glow.
if (iname == "mcl_dye:black") then
success = mcl_signs:glow_sign(pos, true)
if success and DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Glow removal Success.")
end
end
if success then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Color Success.")
end
itemstack:take_item()
end
return
end
-- No modifier item in hand, open the sign for edition
local old_text = minetest.get_meta(pos):get_string("text")
mcl_signs:show_formspec(clicker, pos, old_text)
end
end,
on_destruct = function(pos)
mcl_signs:destruct_sign(pos)
end,
-- Not Useless Code. this force updates the sign.
on_punch = function(pos, node, puncher)
mcl_signs:update_sign(pos)
end,
}
-- wall signs' & hanging signs' base (definition)
mcl_signs.wall_standard = table.copy(common_definition)
mcl_signs.wall_standard.description = S("Sign")
mcl_signs.wall_standard._tt_help = S("Can be written")
mcl_signs.wall_standard._doc_items_longdesc = S("Signs can be written and come in two variants: Wall sign and sign on a sign post. Signs can be placed on the top and the sides of other blocks, but not below them.")
mcl_signs.wall_standard._doc_items_usagehelp = S("After placing the sign, you can write something on it. You have 4 lines of text with up to 15 characters for each line; anything beyond these limits is lost. Not all characters are supported. The text can not be changed once it has been written; you have to break and place the sign again. Can be colored and made to glow.")
mcl_signs.wall_standard.inventory_image = "mcl_signs_default_sign.png"
mcl_signs.wall_standard.wield_image = "mcl_signs_default_sign.png"
mcl_signs.wall_standard.node_placement_prediction = ""
mcl_signs.wall_standard.paramtype2 = "wallmounted"
mcl_signs.wall_standard.mesh = "mcl_signs_signonwallmount.obj"
mcl_signs.wall_standard.selection_box = { type = "wallmounted", wall_side = { -0.5, -7 / 28, -0.5, -23 / 56, 7 / 28, 0.5 } }
mcl_signs.wall_standard.on_timer = function(pos)
on_timer = function(pos)
-- fix for /ClearObjects
mcl_signs:update_sign(pos)
-- note: update_sign decides to keep the timer running based on if there is text.
-- This prevents every sign from having a timer, when not needed.
end
mcl_signs.wall_standard.on_place = function(itemstack, placer, pointed_thing)
end,
on_place = function(itemstack, placer, pointed_thing)
local above = pointed_thing.above
local under = pointed_thing.under
@ -259,6 +192,9 @@ mcl_signs.wall_standard.on_place = function(itemstack, placer, pointed_thing)
end
local wdir = minetest.dir_to_wallmounted(dir)
--local placer_pos = placer:get_pos()
local fdir = minetest.dir_to_facedir(dir)
local sign_info
@ -336,10 +272,18 @@ mcl_signs.wall_standard.on_place = function(itemstack, placer, pointed_thing)
minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true)
mcl_signs:show_formspec(placer, place_pos, "")
mcl_signs:show_formspec(placer, place_pos)
return itemstack
end
mcl_signs.wall_standard.on_rotate = function(pos, node, user, mode)
end,
on_destruct = function(pos)
mcl_signs:destruct_sign(pos)
end,
-- Not Useless Code. force updates the sign.
on_punch = function(pos, node, puncher)
mcl_signs:update_sign(pos)
end,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then
local r = screwdriver.rotate.wallmounted(pos, node, mode)
node.param2 = r
@ -349,21 +293,105 @@ mcl_signs.wall_standard.on_rotate = function(pos, node, user, mode)
else
return false
end
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if DEBUG then
minetest.log("verbose", "[mcl_signs] Wall_Sign Right Click event.")
end
-- make sure player is clicking
if not clicker or not clicker:is_player() then
return
end
local item = clicker:get_wielded_item()
local iname = item:get_name()
local protected = mcl_util.check_position_protection(pos, clicker)
if node and not protected then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Wall_Sign Right Click event on valid node.")
end
-- handle glow from glow_ink_sac *first*
if (iname == "mcl_mobitems:glow_ink_sac") then
clicker:set_wielded_item(item)
local success = mcl_signs:glow_sign(pos)
if success then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Glow Success.")
end
itemstack:take_item()
end
return
end
-- "mcl_dye:black" is a special case: it makes the sign's lettering black AND removes glow.
if (iname == "mcl_dye:black") then
clicker:set_wielded_item(item)
local success = mcl_signs:glow_sign(pos, true)
mcl_signs:color_sign(pos, mcl_colors.BLACK)
if success then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Glow removal Success.")
end
itemstack:take_item()
end
return
end
-- check the wielded item to make sure that it is a dye.
local txt_color = mcl_signs:get_color_for_sign(iname)
if txt_color ~= "false" then
clicker:set_wielded_item(item)
local success = mcl_signs:color_sign(pos, txt_color)
if success then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Color Success.")
end
itemstack:take_item()
end
end
end
end,
_mcl_hardness = 1,
_mcl_blast_resistance = 1,
}
-- standing sign base (definition)
mcl_signs.standing_standard = table.copy(common_definition)
mcl_signs.standing_standard.paramtype2 = "facedir"
mcl_signs.standing_standard.mesh = "mcl_signs_sign.obj"
mcl_signs.standing_standard.selection_box = { type = "fixed", fixed = { -0.2, -0.5, -0.2, 0.2, 0.5, 0.2 } }
mcl_signs.standing_standard.drop = "mcl_signs:wall_sign"
mcl_signs.standing_standard.on_timer = function(pos)
mcl_signs.standing_standard = {
paramtype = "light",
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
sunlight_propagates = true,
walkable = false,
is_ground_content = false,
paramtype2 = "facedir",
drawtype = "mesh",
mesh = "mcl_signs_sign.obj",
selection_box = { type = "fixed", fixed = { -0.2, -0.5, -0.2, 0.2, 0.5, 0.2 } },
tiles = { "mcl_signs_sign.png" },
groups = mcl_signs.sign_groups,
drop = "mcl_signs:wall_sign",
stack_max = 16,
sounds = node_sounds,
on_destruct = function(pos)
mcl_signs:destruct_sign(pos)
end,
on_timer = function(pos)
-- fix for /ClearObjects
mcl_signs:update_sign(pos)
minetest.get_node_timer(pos):start(40.0)
end
mcl_signs.standing_standard.on_rotate = function(pos, node, user, mode)
end,
-- Not Useless Code. this force updates the sign.
on_punch = function(pos, node, puncher)
mcl_signs:update_sign(pos)
end,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then
node.name = "mcl_signs:standing_sign22_5"
minetest.swap_node(pos, node)
@ -372,7 +400,60 @@ mcl_signs.standing_standard.on_rotate = function(pos, node, user, mode)
end
mcl_signs:update_sign(pos, nil, nil, true)
return true
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if DEBUG then
minetest.log("verbose", "[mcl_signs] Standing_Sign Right Click event.")
end
-- make sure player is clicking
if not clicker or not clicker:is_player() then
return
end
local item = clicker:get_wielded_item()
local iname = item:get_name()
local protected = mcl_util.check_position_protection(pos, clicker)
if node and not protected then
-- handle glow from glow_ink_sac *first*
if DEBUG then
minetest.log("verbose", "[mcl_signs] Standing_Sign Right Click event on valid node.")
end
if (iname == "mcl_mobitems:glow_ink_sac") then
clicker:set_wielded_item(item)
local success = mcl_signs:glow_sign(pos)
if success then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Glow Success.")
end
itemstack:take_item()
end
return
end
-- check the wielded item to make sure that it is a dye.
local txt_color = mcl_signs:get_color_for_sign(iname)
if txt_color ~= "false" then
clicker:set_wielded_item(item)
local success = mcl_signs:color_sign(pos, txt_color)
if success then
if DEBUG then
minetest.log("verbose", "[mcl_signs] Sign Color Success.")
end
itemstack:take_item()
end
end
end
end,
_mcl_hardness = 1,
_mcl_blast_resistance = 1,
}
-- HELPER FUNCTIONS' VARIABLES
local sign_glow = 6
@ -582,7 +663,7 @@ function mcl_signs.register_sign (modname, color, _name, ttsign)
minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true)
mcl_signs:show_formspec(placer, place_pos, "")
mcl_signs:show_formspec(placer, place_pos)
return itemstack
end
@ -835,7 +916,7 @@ function mcl_signs.register_sign_custom (modname, _name, tiles, color, inventory
minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true)
mcl_signs:show_formspec(placer, place_pos, "")
mcl_signs:show_formspec(placer, place_pos)
return itemstack
end
minetest.register_node(":mcl_signs:wall_sign" .. _name, new_sign)
@ -1071,7 +1152,7 @@ function mcl_signs.reregister_sign (modname, color, _name, ttsign)
minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true)
mcl_signs:show_formspec(placer, place_pos, "")
mcl_signs:show_formspec(placer, place_pos)
return itemstack
end
@ -1320,7 +1401,7 @@ function mcl_signs.reregister_sign_custom (modname, _name, tiles, color, invento
minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true)
mcl_signs:show_formspec(placer, place_pos, "")
mcl_signs:show_formspec(placer, place_pos)
return itemstack
end
minetest.override_item("mcl_signs:wall_sign" .. _name, new_sign)
@ -1802,7 +1883,7 @@ function mcl_signs:update_sign(pos, fields, sender, force_remove, text_color)
return false
end
local text = meta:get_string("text", "")
if fields and fields.text then
if fields and (text == "" and fields.text) then
meta:set_string("text", fields.text)
text = fields.text
end
@ -1959,13 +2040,11 @@ function mcl_signs:update_sign(pos, fields, sender, force_remove, text_color)
end
function mcl_signs:show_formspec(player, pos, old_text)
function mcl_signs:show_formspec(player, pos)
minetest.show_formspec(
player:get_player_name(),
"mcl_signs:set_text_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z,
"size[6,3]textarea[0.25,0.25;6,1.5;text;" .. F(S("Enter sign text:")) .. ";".. F(old_text) .. "]" ..
"label[0,1.5;" .. F(S("Maximum line length: 15")) ..
"\n" .. F(S("Maximum lines: 4")) .. "]button_exit[0,2.5;6,1;submit;" .. F(S("Done")) .. "]"
"size[6,3]textarea[0.25,0.25;6,1.5;text;" .. F(S("Enter sign text:")) .. ";]label[0,1.5;" .. F(S("Maximum line length: 15")) .. "\n" .. F(S("Maximum lines: 4")) .. "]button_exit[0,2.5;6,1;submit;" .. F(S("Done")) .. "]"
)
end

View File

@ -257,12 +257,6 @@ minetest.register_craft({
},
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_smithing_table:table",
burntime = 15,
})
-- this is the exact same as mcl_smithing_table.upgrade_item_netherite , in case something relies on the old function
function mcl_smithing_table.upgrade_item(itemstack)
return mcl_smithing_table.upgrade_item_netherite(itemstack)

View File

@ -410,6 +410,16 @@ local function make_stripped_trunk(itemstack, placer, pointed_thing)
if noddef._mcl_stripped_variant == nil then
return itemstack
else
if noddef.groups.door == 1 then
local pt_under = pointed_thing.under
if node_name:find("_b_") then
local top_pos = {x = pt_under.x, y = pt_under.y + 1, z = pt_under.z}
minetest.swap_node(top_pos, {name=noddef._mcl_stripped_variant:gsub("_b_", "_t_"), param2=node.param2})
elseif node_name:find("_t_") then
local bot_pos = {x = pt_under.x, y = pt_under.y - 1, z = pt_under.z}
minetest.swap_node(bot_pos, {name=noddef._mcl_stripped_variant:gsub("_t_", "_b_"), param2=node.param2})
end
end
minetest.swap_node(pointed_thing.under, {name=noddef._mcl_stripped_variant, param2=node.param2})
if minetest.get_item_group(node_name, "waxed") ~= 0 then
awards.unlock(placer:get_player_name(), "mcl:wax_off")

View File

@ -1,28 +0,0 @@
# ```vl_hollow_logs```
This mod registers hollow logs derived from normal logs.
Hollow logs mostly have a decorative function, but some of them can be used in recipes. Changes may appear soon.
## Functions:
### ```vl_hollow_logs.register_hollow_log(defs)```
This is the function that registers the hollow trunk.
For a hollow log to be registered, the <span style="color:firebrick"> defs </span> parameter must be a table that contains up to 5 values, which are, in this order, the <span style="color:firebrick"> itemstring </span> of the hollow log, the <span style="color:firebrick"> itemstring </span> of the stripped hollow log, the <span style="color:firebrick"> description </span> of the hollow log, the <span style="color:firebrick"> description </span> of the stripped hollow log and, optionally, a <span style="color:turquoise"> boolean </span> to inform whether this trunk is NOT flammable. If the hollow log is defined as flammable, it becomes part of the <span style="color:springgreen"> hollow_log_flammable </span> group, which allows the log to be used as fuel for furnaces and also allows it to be an ingredient for chacoal.
Examples:
```lua
-- Flammable
{"tree", "stripped_oak", "Hollow Oak Log", "Stripped Hollow Oak Log"}
-- Not flammable
{"crimson_hyphae", "stripped_crimson_hyphae", "Hollow Crimson Stem", "Stripped Hollow Crimson Stem", true}
```
### ```vl_hollow_logs.register_craft(material, result)```
This function records the crafting recipe for a hollow log based on its non-hollow variant.
This function also defines a recipe for the stonecutter. The <span style="color:firebrick"> material </span> and <span style="color:firebrick"> result </span> parameters must be, respectively, the <span style="color:firebrick"> complete itemstring </span> of the source material and the (partial) <span style="color:firebrick"> itemstring </span> of the result. See the following examples:
```lua
vl_hollow_logs.register_craft("mcl_core:tree", "tree")
vl_hollow_logs.register_craft("mcl_crimson:stripped_crimson_hyphae", "stripped_crimson_hyphae")
```

View File

@ -1,112 +0,0 @@
local modpath = minetest.get_modpath(minetest.get_current_modname())
local S = minetest.get_translator(minetest.get_current_modname())
vl_hollow_logs = {}
--- Function to register a hollow log. See API.md to learn how to use this function.
---@param defs table {name:string, stripped_name>string, desc:string, stripped_desc:string, not_flammable:boolean|nil}
function vl_hollow_logs.register_hollow_log(defs)
if not defs or #defs < 4 then
error("Incomplete definition provided")
end
for i = 1, 4 do
if type(defs[i]) ~= "string" then
error("defs["..i.."] must be a string")
end
end
if defs[5] and type(defs[5]) ~= "boolean" then
error("defs[5] must be a boolean if present")
end
local modname = minetest.get_current_modname()
if #defs > 5 then
minetest.log("warning", "[vl_hollow_logs] unused vars passed, dumping the table")
minetest.log("warning", "from mod " .. modname .. ": " .. dump(defs))
end
local name = defs[1]
local stripped_name = defs[2]
local desc = defs[3]
local stripped_desc = defs[4]
local collisionbox = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, -0.375},
{-0.5, -0.5, -0.5, -0.375, 0.5, 0.5},
{0.375, -0.5, -0.5, 0.5, 0.5, 0.5},
{-0.5, -0.5, 0.375, 0.5, 0.5, 0.5},
}
}
local groups = {axey = 1, building_block = 1, handy = 1, hollow_log = 1}
if not defs[5] then
groups = table.insert(groups, {fire_encouragement = 5, fire_flammability = 5, flammable = 2, hollow_log_burnable = 1})
end
minetest.register_node(modname .. ":"..name.."_hollow", {
collision_box = collisionbox,
description = S(desc),
drawtype = "mesh",
groups = groups,
mesh = "vl_hollow_logs_log.obj",
on_place = mcl_util.rotate_axis,
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
sounds = mcl_sounds.node_sound_wood_defaults(),
sunlight_propagates = true,
tiles = {modname .. "_"..name..".png"},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_stripped_variant = modname .. ":stripped_"..name.."_hollow"
})
minetest.register_node(modname .. ":"..stripped_name.."_hollow", {
collision_box = collisionbox,
description = S(stripped_desc),
drawtype = "mesh",
groups = groups,
mesh = "vl_hollow_logs_log.obj",
on_place = mcl_util.rotate_axis,
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
sounds = mcl_sounds.node_sound_wood_defaults(),
sunlight_propagates = true,
tiles = {modname .. "_stripped_"..name..".png"},
_mcl_blast_resistance = 2,
_mcl_hardness = 2
})
end
vl_hollow_logs.logs = {
{"acaciatree", "stripped_acacia", "Hollow Acacia Log", "Stripped Hollow Acacia Log"},
{"birchtree", "stripped_birch", "Hollow Birch Log", "Stripped Hollow Birch Log"},
{"darktree", "stripped_dark_oak", "Hollow Dark Oak Log", "Stripped Hollow Dark Oak Log"},
{"jungletree", "stripped_jungle", "Hollow Jungle Log", "Stripped Hollow Jungle Log"},
{"sprucetree", "stripped_spruce", "Hollow Spruce Log", "Stripped Hollow Spruce Log"},
{"tree", "stripped_oak", "Hollow Oak Log", "Stripped Hollow Oak Log"}
}
if minetest.get_modpath("mcl_cherry_blossom") then
table.insert(vl_hollow_logs.logs, {"cherrytree", "stripped_cherrytree", "Hollow Cherry Log", "Stripped Hollow Cherry Log"})
end
if minetest.get_modpath("mcl_mangrove") then
table.insert(vl_hollow_logs.logs, {"mangrove_tree", "mangrove_stripped", "Hollow Mangrove Log", "Stripped Hollow Mangrove Log"})
end
if minetest.get_modpath("mcl_crimson") then
table.insert(vl_hollow_logs.logs, {"crimson_hyphae", "stripped_crimson_hyphae", "Hollow Crimson Stem", "Stripped Hollow Crimson Stem", true})
table.insert(vl_hollow_logs.logs, {"warped_hyphae", "stripped_warped_hyphae", "Hollow Warped Stem", "Stripped Hollow Warped Stem", true})
end
for _, defs in pairs(vl_hollow_logs.logs) do
vl_hollow_logs.register_hollow_log(defs)
end
dofile(modpath.."/recipes.lua")

View File

@ -1,21 +0,0 @@
# textdomain: mcl_hollow_logs
Hollow Acacia Log=
Hollow Birch Log=
Hollow Cherry Log=
Hollow Dark Oak Log=
Hollow Jungle Log=
Hollow Mangrove Log=
Hollow Oak Log=
Hollow Spruce Log=
Hollow Crimson Stem=
Hollow Warped Stem=
Stripped Hollow Acacia Log=
Stripped Hollow Birch Log=
Stripped Hollow Cherry Log=
Stripped Hollow Dark Oak Log=
Stripped Hollow Jungle Log=
Stripped Hollow Mangrove Log=
Stripped Hollow Oak Log=
Stripped Hollow Spruce Log=
Stripped Hollow Crimson Stem=
Stripped Hollow Warped Stem=

View File

@ -1,21 +0,0 @@
# textdomain: mcl_hollow_logs
Hollow Acacia Log=Tronco Oco de Acácia
Hollow Birch Log=Tronco Oco de Bétula
Hollow Cherry Log=Tronco Oco de Cerejeira
Hollow Dark Oak Log=Tronco Oco de Carvalho Escuro
Hollow Jungle Log=Tronco Oco da Selva
Hollow Mangrove Log=Tronco Oco de Mangue
Hollow Oak Log=Tronco Oco de Carvalho
Hollow Spruce Log=Tronco Oco de Pinheiro
Hollow Crimson Stem=Caule Oco Carmesim
Hollow Warped Stem=Caule Oco Distorcido
Stripped Hollow Acacia Log=Tronco Oco Descascado de Acácia
Stripped Hollow Birch Log=Tronco Oco Descascado de Bétula
Stripped Hollow Cherry Log=Tronco Oco Descascado de Cerejeira
Stripped Hollow Dark Oak Log=Tronco Oco Descascado de Carvalho Escuro
Stripped Hollow Jungle Log=Tronco Oco Descascado da Selva
Stripped Hollow Mangrove Log=Tronco Oco Descascado de Mangue
Stripped Hollow Oak Log=Tronco Oco Descascado de Carvalho
Stripped Hollow Spruce Log=Tronco Oco Descascado de Pinheiro
Stripped Hollow Crimson Stem=Caule Oco Descascado Carmesim
Stripped Hollow Warped Stem=Caule Oco Descascado Distorcido

View File

@ -1,4 +0,0 @@
name = vl_hollow_logs
depends = mcl_core, mcl_sounds, mcl_util
optional_depends = mcl_cherry_blossom, mcl_crimson, mcl_mangrove
author = JoseDouglas26

View File

@ -1,54 +0,0 @@
# Blender 3.6.7
# www.blender.org
o hollow_log
v -0.312500 -0.500000 0.312500
v -0.312500 0.500000 0.312500
v -0.312500 -0.500000 -0.312500
v -0.312500 0.500000 -0.312500
v 0.312500 -0.500000 0.312500
v 0.312500 0.500000 0.312500
v 0.312500 -0.500000 -0.312500
v 0.312500 0.500000 -0.312500
v -0.500000 -0.500000 -0.500000
v -0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v 0.500000 -0.500000 0.500000
v 0.500000 0.500000 0.500000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.380952 0.000000
vt 0.380952 1.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 0.619048 0.000000
vt 0.619048 1.000000
vt 0.928571 0.187500
vt 0.928571 0.812500
vt 1.000000 1.000000
vt 1.000000 -0.000000
vt 0.690476 0.187500
vt 0.690476 0.812500
s 0
f 10/1/1 11/2/1 12/3/1 9/4/1
f 9/1/2 12/2/2 14/3/2 13/4/2
f 13/1/3 14/2/3 16/3/3 15/4/3
f 15/1/4 16/2/4 11/3/4 10/4/4
f 7/5/4 8/6/4 4/2/4 3/1/4
f 5/5/1 6/6/1 8/2/1 7/1/1
f 3/7/5 1/8/5 10/9/5 9/10/5
f 2/8/6 4/7/6 12/10/6 11/9/6
f 7/11/5 3/7/5 9/10/5 13/5/5
f 4/7/6 8/11/6 14/5/6 12/10/6
f 5/12/5 7/11/5 13/5/5 15/6/5
f 8/11/6 6/12/6 16/6/6 14/5/6
f 1/8/5 5/12/5 15/6/5 10/9/5
f 6/12/6 2/8/6 11/9/6 16/6/6
f 3/5/3 4/6/3 2/2/3 1/1/3
f 1/5/2 2/6/2 6/2/2 5/1/2

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