Change techage to submodule

This commit is contained in:
Andrey Stepanov 2024-12-07 23:25:41 +05:00
parent 5f7d19dd5c
commit 5aca2ba20f
Signed by: Koldun
GPG Key ID: 53DE683337F5D25F
1014 changed files with 4 additions and 88661 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "techage"]
path = techage
url = https://git.luanti.ru/MTSR/techage

1
techage Submodule

@ -0,0 +1 @@
Subproject commit ce8b08d2d7937a46e643da1eb745a8ac6bf4598f

View File

@ -1,112 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
GPL v3
See LICENSE.txt for more information
Demo for a electrical power consuming node
]]--
-- for lazy programmers
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local S = techage.S
local PWR_NEEDED = 5
local CYCLE_TIME = 2
local Cable = techage.ElectricCable
--local Cable = techage.Axle
local power = networks.power
local function swap_node(pos, name)
local node = techage.get_node_lvm(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function on_rightclick(pos, node, clicker)
local nvm = techage.get_nvm(pos)
if not nvm.running and power.power_available(pos, Cable) then
nvm.running = true
swap_node(pos, "techage:sink_on")
M(pos):set_string("infotext", "on")
minetest.get_node_timer(pos):start(CYCLE_TIME)
else
nvm.running = false
swap_node(pos, "techage:sink")
M(pos):set_string("infotext", "off")
minetest.get_node_timer(pos):stop()
end
end
local function after_place_node(pos)
local nvm = techage.get_nvm(pos)
M(pos):set_string("infotext", "off")
Cable:after_place_node(pos)
end
local function after_dig_node(pos, oldnode)
Cable:after_dig_node(pos)
techage.del_mem(pos)
end
minetest.register_node("techage:sink", {
description = "Sink",
tiles = {'techage_electric_button.png^[colorize:#000000:50'},
on_timer = function(pos, elapsed)
local consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
if consumed == PWR_NEEDED then
swap_node(pos, "techage:sink_on")
M(pos):set_string("infotext", "on")
end
return true
end,
on_rightclick = on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype = "light",
light_source = 0,
paramtype2 = "facedir",
groups = {choppy = 2, cracky = 2, crumbly = 2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:sink_on", {
description = "Sink",
tiles = {'techage_electric_button.png'},
on_timer = function(pos, elapsed)
local consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
if consumed < PWR_NEEDED then
swap_node(pos, "techage:sink")
M(pos):set_string("infotext", "off")
end
return true
end,
on_rightclick = on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype = "light",
light_source = minetest.LIGHT_MAX,
paramtype2 = "facedir",
diggable = false,
drop = "",
groups = {not_in_creative_inventory = 1},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
power.register_nodes({"techage:sink", "techage:sink_on"}, Cable, "con")

View File

@ -1,43 +0,0 @@
local M = minetest.get_meta
minetest.register_node("techage:testblock", {
description = "Testblock",
tiles = {
"techage_top_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
after_place_node = function(pos, placer)
local nvm = techage.get_nvm(pos)
nvm.test_val = 1
M(pos):set_int("test_val", 1)
M(pos):set_string("infotext", "Value = " .. 1)
end,
})
minetest.register_lbm({
label = "Update testblock",
name = "techage:update_testblock",
nodenames = {
"techage:testblock",
},
run_at_every_load = true,
action = function(pos, node)
local nvm = techage.get_nvm(pos)
if M(pos):get_int("test_val") == nvm.test_val then
nvm.test_val = nvm.test_val + 1
M(pos):set_int("test_val", nvm.test_val)
M(pos):set_string("infotext", "Value = " .. nvm.test_val)
else
minetest.log("error", "[techage] Memory error at " .. minetest.pos_to_string(pos))
M(pos):set_string("infotext", "Error")
end
end,
})

View File

@ -1,662 +0,0 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 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 Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are 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.
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.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
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 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 work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero 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 Affero 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 Affero 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 Affero 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.
TechAge, a mod to go through 5 tech ages in search of wealth and power.
Copyright (C) 2019-2023 Joachim Stolberg
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero 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 your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
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 AGPL, see
<https://www.gnu.org/licenses/>.

View File

@ -1,408 +0,0 @@
# Tech Age [techage] (Minetest 5.4+)
Tech Age, a mod to go through 5 tech ages in search of wealth and power.
![screenshot](https://github.com/joe7575/techage/blob/master/screenshot.png)
Important facts:
- techage is not backwards compatible and cannot be installed on a server together with TechPack
- techage is significantly more extensive, since additional mods are integrated
- techage represents 5 technological ages:
- Iron Age (TA1) - simple tools like coal pile, coal burner, gravel sieve, hammer for getting ores and making goods
- Steam Age (TA2) - Simple machines that are powered by steam engines and drive axles
- Oil Age (TA3) - More modern machines that are powered by electricity.
- Present (TA4) - Electricity from renewable energy sources such as sun and wind.
- Future (TA5) - Machines to overcome space and time, new sources of energy and other achievements.
- Since the levels build on each other, all ages have to be run through one after the other
In contrast to TechPack, the resources are more limited and it is much more difficult to pass all levels.
(no endless ore generation by means of cobble generators)
**Techage blocks store information outside of the block. This is for performance reasons.
If you move, place, or remove blocks with any tool, at best, only the information is lost.
In the worst case, the server crashes.**
[Manuals](https://github.com/joe7575/techage/wiki)
### License
Copyright (C) 2019-2023 Joachim Stolberg
Code: Licensed under the GNU AGPL version 3 or later. See LICENSE.txt
Textures: CC BY-SA 3.0
The TA1 mill sound is from https://freesound.org/people/JustinBW/sounds/70200/
The TA1 watermill sound is from https://freesound.org/people/bmoreno/sounds/164182/
Many thanks to Thomas-S, niklp09, and others for their contributions
### Dependencies
Required: default, doors, bucket, stairs, screwdriver, basic_materials, tubelib2, networks, minecart, lcdlib, safer_lua, doclib
Recommended: signs_bot, hyperloop, compost, techpack_stairway, autobahn
Optional: unified_inventory, wielded_light, unifieddyes, lua-mashal, lsqlite3, moreores, ethereal, mesecon
The mods `default`, `doors`, `bucket`, `stairs`, and `screwdriver` are part of Minetest Game.
`basic_materials` will be found here: https://content.minetest.net/
The following mods in the newest version have to be downloaded directly from GitHub:
* [tubelib2](https://github.com/joe7575/tubelib2)
* [networks](https://github.com/joe7575/networks)
* [minecart](https://github.com/joe7575/minecart)
* [lcdlib](https://github.com/joe7575/lcdlib)
* [safer_lua](https://github.com/joe7575/safer_lua)
* [doclib](https://github.com/joe7575/doclib)
It is highly recommended that you install the following mods, too:
* [signs_bot](https://github.com/joe7575/signs_bot): For many automation tasks in TA3/TA4 like farming, mining, and item transportation
* [hyperloop](https://github.com/joe7575/Minetest-Hyperloop): Used as passenger transportation system in TA4
* [compost](https://github.com/joe7575/compost): The garden soil is needed for the TA4 LED Grow Light based flower bed
* [techpack_stairway](https://github.com/joe7575/techpack_stairway): Ladders, stairways, and bridges for your machines
* [autobahn](https://github.com/joe7575/autobahn): Street blocks and slopes with stripes for faster traveling
* [ta4_jetpack](https://github.com/joe7575/ta4_jetpack): A Jetpack with hydrogen as fuel and TA4 recipe
More recommended Techage related mods by other authors:
* [ta4_addons](https://github.com/Thomas--S/ta4_addons) from Thomas--S: A Touchscreen for the Lua controller
* [ts_vehicles](https://github.com/Thomas--S/ts_vehicles) from Thomas--S: A mod to provide cars and other vehicles for Minetest.
* [ta_apiary](https://gitlab.com/lesya_minetest_mods/ta_apiary) from Olesya Sibidanova: TechAge Machines for beekeeping
For large servers with many players, the following packages are recommended:
* lua-mashal for faster serialization/deserialization of data
* lsqlite3 for storing node and network data
The packages have to be installed via [luarocks](https://luarocks.org/):
luarocks --lua-version 5.1 install lsqlite3
luarocks --lua-version 5.1 install lua-marshal
To enable these `unsafe` packages, add 'techage' and 'lua-marshal'
to the list of trusted mods in `minetest.conf`:
secure.trusted_mods = techage,lua-marshal
and add the following line to your `world.mt` or `minetest.conf`:
techage_use_sqlite = true
Available worlds will be converted to 'lsqlite3', but there is no way back, so:
**Never disable 'lsqlite3' for a world that has already been used!**
### History
**2023-11-05 V1.18**
- Add TA2 clutch
- TA5 Generator: Add generator menu
- TA4 Injector: Allow rotation with a screwdriver
- Escape equal sign in german translation (Niklp09)
- Autocrafter: Add Beduino command interface
- Autocrafter: Add flush command
- Fix converter stores mesecon signals (Niklp09)
- TA1 Gravel Sieve: Use proper player creative check (Niklp09)
- TA4 Chest: Add storesize command
- Improve Assembly Tool
- Furnace: Fix burn time issue
- Allow further types of cobblestone for the coalburner
- Fix water mill river water bug (alwayshopeless)
- Improve manual
- Further improvements
**2023-08-25 V1.17**
- Add support for doclib / remove techage internal doc support
**The mod doclib is a new hard depenency !**
- Fix LICENCSE file bug
- Add beduino support for TA3 repeater (realmicu)
- Add inv_name_prefix to `techage.register_consumer` (debiankaios)
- Add generator menu to TA5 generator (fusion reactor)
- Adapt mod to the new lcdlib mod
- Fix some bugs
**2023-06-30 V1.16**
- Add TA4 node detector
- Add wrench menu to TA3 button
- Add arrows to the pump bottom and allow to turn the pump with the Techage Screwdriver
- Fix bug with configurred TA4 chest and TA5 teleport tubes
- Add gaze sensor
- Many bugfixes and improvements
**2023-05-05 V1.15**
- Allow energy storage with up to 13x13x13 concrete blocks
- Allow registration of other buckets
- Add hyperloop chest only if the hyperloop mod is available
- Add missing 'minetest.formspec_escape' #131
- Fix bug "Trouble with flycontroller #130"
- Add optional dependency on farming mod (orwell96)
- Fix forceload formspec receiver (Niklp09)
**2023-04-16 V1.14**
- Add file "api.md"
- Add API function `register_ore_for_gravelsieve`
- Add support for the game Asuna
- Merge pull request #124 from Niklp09/drops
- Fix keep node number issue
- Fix manual issue #123
**2023-04-10 V1.13**
- Add "Teleport mode" to the ta5 fly controller
**2023-04-01 V1.12**
- Improve Transformer:
- add wrench menu for 'max. power passed through'
- Increase max. power passed through from 100 to 300 ku
- Improve Electricmeter:
- add wrench menu for 'max. power passed through' and 'power countdown' 2458
- add commands to read the countdown value (Lua and Beduino controller)
- Improve TA3 Mesecons Converter:
- fix overload bug
- fix missing dominant 'on' issue
- Add version command to TA3/TA4 Terminal
- TA5 Hyperloop Chest: Disable inventory access on client side due to minetest core issues
**2023-03-05 V1.11**
- Reduce the number of necessary exp points for TA5 Hyperloop Chest,
TA5 Hyperloop Tank, and TA5 AI Chip II
- Fix possible kernel crashes with TA5 Hyperloop Chest and autocrafter
- Rework doorcontroller (menu changed)
- Increase tank cart storage size to 200 units
- Fix several paramtype/use_texture_alpha issues
- Add command 'load' to the TA4 power terminal
- Add beduino tank commands
- Fix power consumption bug for a stopped collider
- Fix electrolyzer formspec bug
- Add Rack and pinion node
- Expand ta4 sequencer wrench menu
- Accept mincart carts for the move controller
- movecontroller: Allow to move objects 'without' a move block
- Add empty_spool as fab output
- Fix doser goes blocked bug
**2023-02-04 V1.10**
- Improve flycontroller
- Remove handover for movecontroller
- Rename "techage:signal_lamp" to "techage:color_lamp"
- Rename "techage:signal_lamp2" to "techage:color_lamp2"
- Add countdown mode to TA4 Detector
- Adapt to new beduino and minecart versions
- Improve manuals
- flycontroller/movecontroller: Allow moving blocks through unloaded areas
- playerdetector: Add wrench menu to configure search radius
- Default furnace: Don't use items filled from the top as fuel
- Many further improvements and bug fixes from joe7575 and Niklp09
**2022-09-03 V1.09**
- Change the way items are pushed
- Add "Flow Limiter" mode to TA4 pump and TA4 pusher
**2022-06-06 V1.08**
- Native support for the mod Beduino added
**2022-01-22 V1.07**
- TA5 fusion reactor added
**2022-01-03 V1.06**
- TA5 teleport blocks added
- Many improvements
**2021-12-25 V1.05**
- Support for the mod i3 added (thanks to ghaydn)
- TA5 enabled
- Many improvements
**2021-12-12 V1.04**
- TA4 Collider added (experimental)
- move, turn, sound, and fly blocks added
- TA5 (future) introduced (TA4 is now the "present")
**2021-10-24 V1.03**
- Add TA4 Sequencer for time controlled command sequences
- Add TA4 Move Controller for moving blocks
- Add techage command counting function to be able to limit the amount of commands/min.
- Pull request #67: Add switch mode for 4x Button (by realmicu)
- Pull request #69: Add option to keep assignment for TA4 Tank (by Thomas-S)
**2021-09-18 V1.02**
- TA4 Chest: Fix items disappearing (PR #64 by Thomas--S)
- Add support for colored cables (PR #63 by Thomas--S)
**2021-08-16 V1.01**
- Allow singleplayer to place lava on y>0.
- Logic block: allow to use output numbers for the expression
- Pull request #60: Allow to pause the sequencer with a TechAge command (by Thomas-S)
- Pull request #61: Allow sharing the button based on protection (by Thomas-S)
- Pull request #62: Allow picking TA3 Tiny Generator with fuel (by realmicu)
- Add TA1 watermill
- Fix TA4 LED Grow Light bug
- Fix grinder recipe bu
**2021-07-23 V1.00**
- Change the way, power distribution works
- Add TA2 storage system
- Add TA4 Isolation Transformer
- Add TA4 Electric Meter
- Add new power terminal
- Many improvements on power producing/consuming nodes
- See Construction Board for some hints on moving to v1
**2021-05-14 V0.26**
- Add concentrator tubes
- Add ta4 cable wall entry
- Pull request #57: Distributor improvements (from Thomas-S)
- Add new power terminal commands
- Add new door controller
- Add laser beam nodes for energy transfer
- Add TA4 recycle machine
- Many improvements and bug fixes
**2020-11-01 V0.25**
- Pull request #37: Trowel: Add protection support (from Thomas-S)
- Pull request #38: Charcoal Pile: Ignore "ignore" nodes (from Thomas-S)
- Autocrafter: Add register function for uncraftable items
- Fix bug: Tubes do not recognize when TA2 nodes are added/removed
- TA4 chest/tank: Add 'public' checkbox to allow public access
- Add nodes TA2 Power Generator and TA3 Electric Motor
**2020-10-20 V0.24**
- Pull request #27: Liquid Tanks: Add protection support (from Thomas-S)
- Pull request #28: Quarry: Improve digging behaviour (from Thomas-S)
- Pull request #29: Distributor: Keep metadata (from Thomas-S)
- Pull request #30: TA4: Add Liquid Filter (from Thomas-S)
- Pull request #31: Fix chest crash (from Thomas-S)
- Pull request #32: Fix Filter Sink Bug (from Thomas-S)
- Pull request #33: Add TA4 High Performance Distributor (from Thomas-S)
- Pull request #34: Add TA4 High Performance Distributor to Hopper (from Thomas-S)
- Pull request #35: Fixed Gravel Sieve bug (from CosmicConveyor)
- Fix doorcontroller and ta4 doser bugs
- Add check for wind turbine areas
- Fix translation errors
- QSG: Add power consumptions and fix manual bug
- Add load command to the controller battery
- TA4 silo: Add load command
- silo/tank: Add second return value for load command
- Liquid Pumps: Fix issue with undetected pipe connection gaps
- Shrink PGN files
- Fix ta4 chest bugs
- Fix ta4 chest and ta3 firebox issues
- Remove repairkit recipe
- Switched to AGPL license
- API added for ingame manual
**2020-09-13 V0.23**
- Pull request #26: Digtron Battery: Fix duplication bug (from Thomas-S)
- Improve ta4 sensor box
- Firebox: Add check for free space when placing the node
- Lua controller: Add 'get_gametime' function
- Pull request #27: Liquid Tanks: Add protection support (from Thomas-S)
- Fix pump issue (silo source items can disappear)
- Pull request #28: Quarry: Improve digging behaviour (from Thomas-S)
- Pull request #28: Battery: Store battery load as metadata (from Thomas-S)
- Pull request #29: Distributor: Keep item metadata (from Thomas-S)
**2020-08-08 V0.22**
- Pull request #25: Growlight: Improve flower registration (from Thomas-S)
- Add tube support for digtron chests and protector:chest
**2020-08-08 V0.21**
- Pull request #18: Add a simple Digtron battery (from Thomas-S)
- Pull request #23: Lua Controller: Fix $item_description() documentation and translation (from Thomas-S)
- Pull request #24: Distributor: improve fairness by using random spread (from realmicu)
- Bugfix: TA1 meridian hammer did not glow (from realmicu)
- Bugfix: power.power_available() did not check the network state
**2020-07-31 V0.20**
- Pull request #21: Lua Controller: Allow to get itemstring and description of 8x2000 chest contents (from Thomas-S)
- Pull request #22: Trowel: Prevent hidden nodes from being dug (from Thomas-S)
- Improvement: TA3 Power Terminal: Outputs max needed power in addition
- Bugfix: Quarry: Shall not dig Techage Light Blocks
**2020-07-24 V0.19**
- Pull request #19: Refactor ICTA to use functions instead of loadstring (from Thomas-S)
- State command added for cart-, node-, and player detectors
**2020-07-21 V0.18**
- Pull request #13: Use Monospace Font for Code-Related Formspecs (from Thomas-S)
- Pull request #14: Don't allow to put items with meta or wear information into the 8x2000 chest (from Thomas-S)
- Pull request #15: Blackhole: Add support for liquids (from Thomas-S)
- Pull request #16: ICTA Controller: Add support for valves by adding on/off states (from Thomas-S)
- Bugfix: Digging Redstone gives an 'unknown block'
- ICTA Controller: Escape quotation marks for text outputs
**2020-07-16 V0.17**
- TA4 Reactor recipe bugfix
- TA3 furnace power bugfix (response to the pull request #12 from Thomas-S)
- Manual bugfix (Thomas-S)
- Charcoal pile doesn't start smoking after beeing unloaded (issue #9 from Skamiz)
**2020-07-06 V0.16**
- Oil cracking/hydrogenation recipes added
- Ethereal growlight bugfix
- Charcoal pile bugfix (issue #9) Thanks to Skamiz
- Quarry bugfix (pull request #10) Thanks to programmerjake
**2020-07-02 V0.15**
- pipe valve added
- growlight bugfix
- further textures to gate/door blocks added
- cement recipe bugfix
- manual improvements
**2020-06-29 V0.14**
- quarry sound bugfix
- grinder bugfix
- ore probability calculation changed
- lua-marshal deactivated (due to weird server crashes)
- alternative cement recipe added
- aluminum output increased
- reboiler cycle time increased to 16 s (from 6)
- many manual improvements
**2020-06-19 V0.13**
- Mesecons Converter added
**2020-06-17 V0.12**
- Ethereal support added
- manual correction
- tin ingot recipe bugfix
**2020-06-14 V0.11**
- cart commands added for both controllers
- support for moreores added
**2020-06-04 V0.10**
- minor changes and bugfixes
**2020-05-31 V0.09**
- TA4 tubes upgraded, manuals updated
**2020-05-22 V0.08**
- Support for 'lua-marshal' and 'lsqlite3' added
**2020-04-26 V0.07**
- English translation added
**2020-04-24 V0.06**
- TA4 injector added
**2020-03-14 V0.05**
- TA4 Lua controller added
**2020-02-29 V0.04**
- TA4 ICTA controller added
**2019-09-28 V0.02**
- TA3 finished
**2019-06-16 V0.01**
- First upload

View File

@ -1 +0,0 @@
theme: jekyll-theme-leap-day

View File

@ -1,225 +0,0 @@
# Techage API Functions
Techage API function to adapt/prepare techage for other mods/games.
## Move/Fly Controller
Register node names for nodes allowed to be moved by fly/move controllers.
This is only necessary for undiggable/intelligent nodes with one of the following attributes:
- ```drop = ""```
- ```diggable = false```
- ```after_dig_node ~= nil```
```lua
techage.register_simple_nodes(node_names, is_valid)
```
- `is_valid = true` - Add node to the list of simple nodes
- `is_valid = false` - Remove node from the list of simple nodes
Example:
```lua
techage.register_simple_nodes({"techage:power_lineS"}, true)
```
For door nodes used as sliding doors by means of the move controller, call in addition:
```lua
techage.flylib.protect_door_from_being_opened(node_name)
```
## TA1 Hammer
Register stone/gravel name pair for the hammer blow:
```lua
techage.register_stone_gravel_pair(stone_name, gravel_name)
```
Example:
```lua
techage.register_stone_gravel_pair("default:stone", "default:gravel")
```
## TA1 Melting Pot
Register a pot recipe:
```lua
techage.ironage_register_recipe(recipe)
```
Examples:
```lua
techage.ironage_register_recipe({
output = "default:obsidian",
recipe = {"default:cobble"},
heat = 10, -- Corresponds to the tower height
time = 8, -- Cooking time in seconds
})
techage.ironage_register_recipe({
output = "default:bronze_ingot 4",
recipe = {"default:copper_ingot", "default:copper_ingot", "default:copper_ingot", "default:tin_ingot"},
heat = 4, -- Corresponds to the tower height
time = 8, -- Cooking time in seconds
})
```
## TA2/TA3/TA4 Autocrafter
Register any nodes/items that should not be crafted via the autocrafter.
```lua
techage.register_uncraftable_items(item_name)
```
## TA2/TA3/TA4 Gravel Sieve
Change the probability of ores or register new ores for sieving.
```lua
techage.register_ore_for_gravelsieve(ore_name, probability)
```
Example:
```lua
techage.register_ore_for_gravelsieve("default:iron_lump", 30)
```
Default values for MTG are:
```lua
-- higher value means less frequent occurrence
techage:baborium_lump 100000 -- hardly ever
default:mese_crystal 548 -- every 548th time
default:gold_lump 439
default:tin_lump 60
default:diamond 843
default:copper_lump 145
default:coal_lump 11
default:iron_lump 15
```
## TA2/TA3/TA4 Gravel Rinser
Add a rinser recipe.
```lua
techage.add_rinser_recipe(recipe)
```
Example:
```lua
techage.add_rinser_recipe({input = "techage:sieved_gravel", output = "techage:usmium_nuggets", probability = 30})
```
## TA2/TA3/TA4 Grinder
Add a grinder recipe.
```lua
techage.add_grinder_recipe(recipe, ta1_permitted)
```
Examples:
```lua
echage.add_grinder_recipe({input = "default:cobble", output = "default:gravel"})
techage.add_grinder_recipe({input = "default:sandstone", output = "default:sand 4"})
```
## TA3/TA4 Electronic Fab, TA4 Doser
Add recipes to an electronic fab or doser (chemical reactor):
```lua
techage.recipes.add(rtype, recipe)
```
`rtype` is one of: `ta2_electronic_fab` , `ta4_doser`
A recipe look like:
```
{
output = "<item-name> <units>", -- units = 1..n
waste = "<item-name> <units>", -- units = 1..n
input = { -- up to 4 items
"<item-name> <units>",
"<item-name> <units>",
},
}
```
Examples:
```lua
techage.recipes.add("ta2_electronic_fab", {
output = "techage:vacuum_tube 2",
waste = "basic_materials:empty_spool 1",
input = {"default:glass 1", "basic_materials:copper_wire 1", "basic_materials:plastic_sheet 1", "techage:usmium_nuggets 1"}
})
techage.recipes.add("ta4_doser", {
output = "techage:naphtha 1",
input = {
"techage:fueloil 1",
},
catalyst = "techage:gibbsite_powder",
})
```
## TA3 Furnace
Register recipe:
```lua
techage.furnace.register_recipe(recipe)
```
Example:
```lua
techage.furnace.register_recipe({
output = "default:bronze_ingot 4",
recipe = {"default:copper_ingot", "default:copper_ingot", "default:copper_ingot", "default:tin_ingot"},
time = 2, -- in seconds
})
```
## Assembly Tool
Disable a block from being removed by the assembly tool:
```lua
techage.disable_block_for_assembly_tool(block_name)
```

View File

@ -1,556 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
The autocrafter is derived from pipeworks:
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> WTFPL
TA2/TA3/TA4 Autocrafter
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local M = minetest.get_meta
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local S = techage.S
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 4
local UncraftableItems = {}
-- Add all nodes/items which should not be crafted with the autocrafter
function techage.register_uncraftable_items(item_name)
UncraftableItems[item_name] = true
end
local function formspec(self, pos, nvm)
return "size[8,9.2]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;recipe;0,0;3,3;]"..
"image[2.9,1;1,1;techage_form_arrow.png]"..
"image[3.8,0;1,1;"..techage.get_power_image(pos, nvm).."]"..
"list[context;output;3.8,1;1,1;]"..
"image_button[3.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.8,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[context;src;0,3.2;8,2;]"..
"list[context;dst;5,0;3,3;]"..
"list[current_player;main;0,5.4;8,4;]" ..
"listring[current_player;main]"..
"listring[context;src]" ..
"listring[current_player;main]"..
"listring[context;dst]" ..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 5.4)
end
local function count_index(invlist)
local index = {}
for _, stack in pairs(invlist) do
if not stack:is_empty() then
local stack_name = stack:get_name()
index[stack_name] = (index[stack_name] or 0) + stack:get_count()
end
end
return index
end
local function flush_input_inventory(pos)
local inv = M(pos):get_inventory()
if not inv:is_empty("src") then
for idx = 1, 16 do
local stack = inv:get_stack("src", idx)
if not inv:room_for_item("dst", stack) then
return false
end
inv:add_item("dst", stack)
inv:set_stack("src", idx, nil)
end
end
return true
end
-- caches some recipe data
local autocrafterCache = {}
local function get_craft(pos, inventory, hash)
hash = hash or minetest.hash_node_position(pos)
local craft = autocrafterCache[hash]
if not craft then
local recipe = inventory:get_list("recipe")
local output, decremented_input = minetest.get_craft_result(
{method = "normal", width = 3, items = recipe})
-- check if registered item
if UncraftableItems[output.item:get_name()] then
output.item = ItemStack()
end
craft = {recipe = recipe, consumption = count_index(recipe),
output = output, decremented_input = decremented_input}
autocrafterCache[hash] = craft
end
return craft
end
local function autocraft(pos, crd, nvm, inv)
local craft = get_craft(pos, inv)
if not craft then
crd.State:idle(pos, nvm)
return
end
local output_item = craft.output.item
if output_item:get_name() == "" then
crd.State:idle(pos, nvm)
return
end
-- check if we have enough room in dst
if not inv:room_for_item("dst", output_item) then
crd.State:blocked(pos, nvm)
return
end
local consumption = craft.consumption
local inv_index = count_index(inv:get_list("src"))
-- check if we have enough material available
for itemname, number in pairs(consumption) do
if (not inv_index[itemname]) or inv_index[itemname] < number then
crd.State:idle(pos, nvm)
return
end
end
-- consume material
for itemname, number in pairs(consumption) do
for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max
inv:remove_item("src", ItemStack(itemname))
end
end
-- craft the result into the dst inventory and add any "replacements" as well
inv:add_item("dst", output_item)
for i = 1, 9 do
inv:add_item("dst", craft.decremented_input.items[i])
end
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
autocraft(pos, crd, nvm, inv)
end
-- note, that this function assumes allready being updated to virtual items
-- and doesn't handle recipes with stacksizes > 1
local function after_recipe_change(pos, inventory)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
-- if we emptied the grid, there's no point in keeping it running or cached
if inventory:is_empty("recipe") then
autocrafterCache[minetest.hash_node_position(pos)] = nil
inventory:set_stack("output", 1, "")
crd.State:stop(pos, nvm)
return
end
local recipe = inventory:get_list("recipe")
local hash = minetest.hash_node_position(pos)
local craft = autocrafterCache[hash]
if craft then
-- check if it changed
local cached_recipe = craft.recipe
for i = 1, 9 do
if recipe[i]:get_name() ~= cached_recipe[i]:get_name() then
autocrafterCache[hash] = nil -- invalidate recipe
craft = nil
break
end
end
end
craft = craft or get_craft(pos, inventory, hash)
local output_item = craft.output.item
inventory:set_stack("output", 1, output_item)
crd.State:stop(pos, nvm)
end
-- clean out unknown items and groups, which would be handled like unknown items in the crafting grid
-- if minetest supports query by group one day, this might replace them
-- with a canonical version instead
local function normalize(item_list)
for i = 1, #item_list do
local name = item_list[i]
if not minetest.registered_items[name] then
item_list[i] = ""
end
end
return item_list
end
local function get_input_from_recipeblock(pos, number, idx)
local own_num = M(pos):get_string("node_number")
local owner = M(pos):get_string("owner")
if techage.check_numbers(number, owner) then
local input = techage.send_single(own_num, number, "input", idx)
if input and type(input) == "string" then
return input
end
end
end
local function on_output_change(pos, inventory, stack)
if not stack then
inventory:set_list("output", {})
inventory:set_list("recipe", {})
else
local input = minetest.get_craft_recipe(stack:get_name())
if not input.items or input.type ~= "normal" then return end
local items, width = normalize(input.items), input.width
local item_idx, width_idx = 1, 1
for i = 1, 9 do
if width_idx <= width then
inventory:set_stack("recipe", i, items[item_idx])
item_idx = item_idx + 1
else
inventory:set_stack("recipe", i, ItemStack(""))
end
width_idx = (width_idx < 3) and (width_idx + 1) or 1
end
-- we'll set the output slot in after_recipe_change to the actual result of the new recipe
end
after_recipe_change(pos, inventory)
end
local function determine_recipe_items(pos, input)
local num, idx
if input and type(input) == "string" then -- Lua controller
-- Test if "<node-number>.<recipe-number>" input
num, idx = unpack(string.split(input, ".", false, 1))
elseif input and type(input) == "table" then -- Beduino
num = tostring(input[1] * 65536 + input[2])
idx = tostring(input[3])
end
if num and idx then
input = get_input_from_recipeblock(pos, num, idx)
if input then
-- "<item>,<item>,..." input
local items = string.split(input, ",", true, 8)
if items and type(items) == "table" and next(items) then
return items
end
end
end
end
local function on_new_recipe(pos, input)
local items = determine_recipe_items(pos, input)
local inv = M(pos):get_inventory()
if items then
for i = 1, 9 do
inv:set_stack("recipe", i, items[i])
end
else
inv:set_list("recipe", {})
end
local hash = minetest.hash_node_position(pos)
autocrafterCache[hash] = nil
local craft = get_craft(pos, inv, hash)
if craft.output and craft.output.item then
inv:set_stack("output", 1, craft.output.item)
else
inv:set_stack("output", 1, nil)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if listname == "output" then
return 0
end
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = M(pos):get_inventory()
if listname == "recipe" then
stack:set_count(1)
inv:set_stack(listname, index, stack)
after_recipe_change(pos, inv)
return 0
elseif listname == "output" then
on_output_change(pos, inv, stack)
return 0
elseif listname == "src" then
CRD(pos).State:start_if_standby(pos)
end
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if listname == "output" then
return 0
end
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
-- upgrade_autocrafter(pos)
local inv = minetest.get_meta(pos):get_inventory()
if listname == "recipe" then
inv:set_stack(listname, index, ItemStack(""))
after_recipe_change(pos, inv)
return 0
elseif listname == "output" then
on_output_change(pos, inv, nil)
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if from_list == "output" or "to_list" == "output" then
return 0
end
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = minetest.get_meta(pos):get_inventory()
local stack = inv:get_stack(from_list, from_index)
if to_list == "output" then
on_output_change(pos, inv, stack)
return 0
elseif from_list == "output" then
on_output_change(pos, inv, nil)
if to_list ~= "recipe" then
return 0
end -- else fall through to recipe list handling
end
if from_list == "recipe" or to_list == "recipe" then
if from_list == "recipe" then
inv:set_stack(from_list, from_index, ItemStack(""))
end
if to_list == "recipe" then
stack:set_count(1)
inv:set_stack(to_list, to_index, stack)
end
after_recipe_change(pos, inv)
return 0
end
return count
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("dst") and inv:is_empty("src")
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_appl_autocrafter.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_autocrafter.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_autocrafter.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
{
name = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
name = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
{
name = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
}
local INFO = [[Commands: 'state', 'recipe']]
local tubing = {
on_inv_request = function(pos, in_dir, access_type)
if access_type == "push" then
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
return meta:get_inventory(), "src"
end
end
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "dst", num)
end
end,
on_push_item = function(pos, in_dir, stack, idx)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
--CRD(pos).State:start_if_standby(pos) -- would need power!
return techage.put_items(inv, "src", stack, idx)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "dst", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "recipe" and CRD(pos).stage == 4 then
if payload and payload ~= "" then
on_new_recipe(pos, payload)
return true
else
local inv = M(pos):get_inventory()
return inv:get_stack("output", 1):get_name()
end
elseif topic == "flush" and CRD(pos).stage == 4 then
return flush_input_inventory(pos)
elseif topic == "info" and CRD(pos).stage == 4 then
return INFO
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 10 and CRD(pos).stage == 4 then
on_new_recipe(pos, payload)
return 1, ""
elseif topic == 11 and CRD(pos).stage == 4 then
if flush_input_inventory(pos) then
return 1, ""
else
return 0, ""
end
end
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("autocrafter", S("Autocrafter"), tiles, {
drawtype = "normal",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size("src", 2*8)
inv:set_size("recipe", 3*3)
inv:set_size("dst", 3*3)
inv:set_size("output", 1)
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,2,4},
power_consumption = {0,4,6,9},
},
{false, true, true, true}) -- TA2/TA3/TA4
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"group:wood", "default:diamond", "group:wood"},
{"techage:tubeS", "basic_materials:gear_steel", "techage:tubeS"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:diamond", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:diamond", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
local Cable = techage.ElectricCable
local power = networks.power
techage.register_node_for_v1_transition({"techage:ta3_autocrafter_pas", "techage:ta4_autocrafter_pas"}, function(pos, node)
power.update_network(pos, nil, Cable)
end)

View File

@ -1,89 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
All items and liquids disappear.
]]--
local S = techage.S
local Pipe = techage.LiquidPipe
local liquid = networks.liquid
local function take_liquid(pos, indir, name, amount)
return 0, name
end
local function put_liquid(pos, indir, name, amount)
return 0
end
local function peek_liquid(pos, indir)
return nil
end
minetest.register_node("techage:blackhole", {
description = S("TechAge Black Hole"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_blackhole.png^techage_appl_hole_pipe.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_blackhole.png^techage_appl_inp.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_blackhole.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_blackhole.png",
},
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local node = minetest.get_node(pos)
meta:set_int("push_dir", techage.side_to_indir("L", node.param2))
meta:set_string("infotext", S("TechAge Black Hole (let items and liquids disappear)"))
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
end,
on_rotate = screwdriver.disallow,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = "techage:blackhole",
recipe = {
{"group:wood", "", "group:wood"},
{"techage:tubeS", "default:coal_lump", "techage:ta3_pipeS"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
techage.register_node({"techage:blackhole"}, {
on_pull_item = nil, -- not needed
on_unpull_item = nil, -- not needed
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir then
return true
end
end,
})
liquid.register_nodes({"techage:blackhole"},
Pipe, "tank", {"R"}, {
capa = 9999999,
peek = peek_liquid,
put = put_liquid,
take = take_liquid,
}
)

View File

@ -1,463 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Chest
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local TA4_INV_SIZE = 50
local MP = minetest.get_modpath(minetest.get_current_modname())
local mConf = dofile(MP.."/basis/conf_inv.lua")
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = minetest.get_meta(pos):get_inventory()
return inv:is_empty("main")
end
local function after_dig_node(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end
local function formspec2()
return "size[9,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;main;0.5,0;8,4;]"..
"list[current_player;main;0.5,4.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
minetest.register_node("techage:chest_ta2", {
description = S("TA2 Protected Chest"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_front_ta3.png",
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('main', 32)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
meta:set_string("formspec", formspec2())
end,
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, S("TA2 Protected Chest"))
end,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
local function formspec3()
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;main;0,0;10,4;]"..
"list[current_player;main;1,4.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
minetest.register_node("techage:chest_ta3", {
description = S("TA3 Protected Chest"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_front_ta3.png",
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('main', 40)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local number = techage.add_node(pos, "techage:chest_ta3")
meta:set_string("node_number", number)
meta:set_string("owner", placer:get_player_name())
meta:set_string("formspec", formspec3())
meta:set_string("infotext", S("TA3 Protected Chest").." "..number)
end,
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, S("TA3 Protected Chest"))
end,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:chest_ta2", "techage:chest_ta3"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num, item_name)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_inv_state(inv, "main")
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return 0, {techage.get_inv_state_num(inv, "main")}
else
return 2, ""
end
end,
})
local function formspec4(pos)
return "size[10,9]"..
"tabheader[0,0;tab;"..S("Inventory,Pre-Assignment,Config")..";1;;true]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;main;0,0;10,5;]"..
mConf.preassigned_stacks(pos, 10, 5)..
"list[current_player;main;1,5.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function formspec4_pre(pos)
return "size[10,9]"..
"tabheader[0,0;tab;"..S("Inventory,Pre-Assignment,Config")..";2;;true]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;conf;0,0;10,5;]"..
"list[current_player;main;1,5.3;8,4;]"..
"listring[context;conf]"..
"listring[current_player;main]"
end
local function formspec4_cfg(pos)
local meta = minetest.get_meta(pos)
local label = meta:get_string("label") or ""
local public = dump((meta:get_int("public") or 0) == 1)
return "size[10,5]"..
"tabheader[0,0;tab;"..S("Inventory,Pre-Assignment,Config")..";3;;true]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"field[0.5,1;9,1;label;"..S("Node label:")..";"..label.."]" ..
"checkbox[1,2;public;"..S("Allow public access to the chest")..";"..public.."]"..
"button_exit[3.5,4;3,1;exit;"..S("Save").."]"
end
local function ta4_allow_metadata_inventory_put(pos, listname, index, stack, player)
local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "main" then
return stack:get_count()
else
return mConf.allow_conf_inv_put(pos, listname, index, stack, player)
end
end
local function ta4_allow_metadata_inventory_take(pos, listname, index, stack, player)
local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "main" then
return stack:get_count()
else
return mConf.allow_conf_inv_take(pos, listname, index, stack, player)
end
end
local function ta4_allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if from_list == "main" then
return count
else
return mConf.allow_conf_inv_move(pos, from_list, from_index, to_list, to_index, count, player)
end
end
minetest.register_node("techage:chest_ta4", {
description = S("TA4 Protected Chest"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_front_ta4.png",
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('main', 50)
inv:set_size('conf', 50)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local number = techage.add_node(pos, "techage:chest_ta4")
meta:set_string("node_number", number)
meta:set_string("owner", placer:get_player_name())
meta:set_string("formspec", formspec4(pos))
meta:set_string("infotext", S("TA4 Protected Chest").." "..number)
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = minetest.get_meta(pos)
local mem = techage.get_mem(pos)
if fields.tab == "1" then
mem.filter = nil
meta:set_string("formspec", formspec4(pos))
elseif fields.tab == "2" then
meta:set_string("formspec", formspec4_pre(pos))
elseif fields.tab == "3" then
meta:set_string("formspec", formspec4_cfg(pos))
elseif fields.quit == "true" then
mem.filter = nil
end
if fields.public then
meta:set_int("public", fields.public == "true" and 1 or 0)
end
if fields.exit then
local number = meta:get_string("node_number")
if fields.label ~= "" then
meta:set_string("infotext", minetest.formspec_escape(fields.label).." #"..number)
else
meta:set_string("infotext", S("TA4 Protected Chest").." "..number)
end
meta:set_string("label", fields.label)
meta:set_string("formspec", formspec4_cfg(pos))
end
end,
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, S("TA4 Protected Chest"))
end,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = ta4_allow_metadata_inventory_put,
allow_metadata_inventory_take = ta4_allow_metadata_inventory_take,
allow_metadata_inventory_move = ta4_allow_metadata_inventory_move,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:chest_ta4"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num, item_name)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local mem = techage.get_mem(pos)
mem.filter = mem.filter or mConf.item_filter(pos, TA4_INV_SIZE)
mem.chest_configured = mem.chest_configured or not inv:is_empty("conf")
if inv:is_empty("main") then
return nil
end
if item_name then
if mem.filter[item_name] or not mem.chest_configured then
local taken = inv:remove_item("main", {name = item_name, count = num})
if taken:get_count() > 0 then
return taken
end
end
else -- no item given
if mem.chest_configured then
return mConf.take_item(pos, inv, "main", num, mem.filter["unconfigured"])
else
return techage.get_items(pos, inv, "main", num)
end
end
end,
on_push_item = function(pos, in_dir, item, idx)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local mem = techage.get_mem(pos)
mem.filter = mem.filter or mConf.item_filter(pos, TA4_INV_SIZE)
mem.chest_configured = mem.chest_configured or not inv:is_empty("conf")
if mem.chest_configured then
local name = item:get_name()
local stacks = mem.filter[name] or mem.filter["unconfigured"]
return mConf.put_items(pos, inv, "main", item, stacks, idx)
else
return techage.put_items(inv, "main", item, idx)
end
end,
on_unpull_item = function(pos, in_dir, item)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local mem = techage.get_mem(pos)
mem.filter = mem.filter or mConf.item_filter(pos, TA4_INV_SIZE)
mem.chest_configured = mem.chest_configured or not inv:is_empty("conf")
if mem.chest_configured then
local name = item:get_name()
local stacks = mem.filter[name] or mem.filter["unconfigured"]
return mConf.put_items(pos, inv, "main", item, stacks)
else
return techage.put_items(inv, "main", item)
end
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_inv_state(inv, "main")
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return 0, {techage.get_inv_state_num(inv, "main")}
else
return 2, ""
end
end,
})
minetest.register_craft({
type = "shapeless",
output = "techage:chest_ta2",
recipe = {"default:chest", "techage:tubeS", "techage:iron_ingot"}
})
minetest.register_craft({
type = "shapeless",
output = "techage:chest_ta2",
recipe = {"default:chest_locked", "techage:tubeS", "techage:iron_ingot"}
})
minetest.register_craft({
type = "shapeless",
output = "techage:chest_ta2",
recipe = {"protector:chest", "techage:tubeS", "techage:iron_ingot"}
})
minetest.register_craft({
type = "shapeless",
output = "techage:chest_ta3",
recipe = {"techage:chest_ta2", "default:chest"}
})
minetest.register_craft({
type = "shapeless",
output = "techage:chest_ta4",
recipe = {"techage:chest_ta3", "default:chest"}
})

View File

@ -1,154 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Tube Concentrator
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local Tube = techage.Tube
local size = 2/8
local Boxes = {
{{-size, -size, size, size, size, 0.5 }}, -- z+
{{-size, -size, -size, 0.5, size, size}}, -- x+
{{-size, -size, -0.5, size, size, size}}, -- z-
{{-0.5, -size, -size, size, size, size}}, -- x-
{{-size, -0.5, -size, size, size, size}}, -- y-
{{-size, -size, -size, size, 0.5, size}}, -- y+
}
local names = networks.register_junction("techage:concentrator", 2/8, Boxes, Tube, {
description = S("Tube Concentrator"),
tiles = {
"techage_tube_junction.png^techage_appl_arrow2.png^[transformR270",
"techage_tube_junction.png^techage_appl_arrow2.png^[transformR270",
"techage_tube_junction.png^techage_tube_hole.png",
"techage_tube_junction.png",
"techage_tube_junction.png^techage_appl_arrow2.png^[transformR90",
"techage_tube_junction.png^techage_appl_arrow2.png^[transformR270",
},
paramtype2 = "facedir", -- important!
use_texture_alpha = techage.CLIP,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1},
sounds = default.node_sound_defaults(),
after_place_node = function(pos, placer, itemstack, pointed_thing)
local node = minetest.get_node(pos)
local name = "techage:concentrator"..networks.junction_type(pos, Tube, "R", node.param2)
minetest.swap_node(pos, {name = name, param2 = node.param2})
M(pos):set_int("push_dir", techage.side_to_outdir("R", node.param2))
Tube:after_place_node(pos)
end,
tubelib2_on_update2 = function(pos, dir1, tlib2, node)
local name = "techage:concentrator"..networks.junction_type(pos, Tube, "R", node.param2)
minetest.swap_node(pos, {name = name, param2 = node.param2})
end,
ta_rotate_node = function(pos, node, new_param2)
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
M(pos):set_int("push_dir", techage.side_to_outdir("R", new_param2))
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_node(pos)
end,
}, 27)
for _, name in ipairs(names) do
Tube:set_valid_sides(name, {"B", "R", "F", "L", "D", "U"})
end
techage.register_node(names, {
on_push_item = function(pos, in_dir, stack)
local push_dir = M(pos):get_int("push_dir")
if networks.Flip[push_dir] ~= in_dir then
return techage.safe_push_items(pos, push_dir, stack)
else
return stack
end
end,
is_pusher = true, -- is a pulling/pushing node
})
names = networks.register_junction("techage:ta4_concentrator", 2/8, Boxes, Tube, {
description = S("TA4 Tube Concentrator"),
tiles = {
"techage_tubeta4_junction.png^techage_appl_arrow2.png^[transformR270",
"techage_tubeta4_junction.png^techage_appl_arrow2.png^[transformR270",
"techage_tubeta4_junction.png^techage_tube_hole.png",
"techage_tubeta4_junction.png",
"techage_tubeta4_junction.png^techage_appl_arrow2.png^[transformR90",
"techage_tubeta4_junction.png^techage_appl_arrow2.png^[transformR270",
},
paramtype2 = "facedir", -- important!
use_texture_alpha = techage.CLIP,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1},
sounds = default.node_sound_defaults(),
after_place_node = function(pos, placer, itemstack, pointed_thing)
local node = minetest.get_node(pos)
local name = "techage:ta4_concentrator"..networks.junction_type(pos, Tube, "R", node.param2)
minetest.swap_node(pos, {name = name, param2 = node.param2})
M(pos):set_int("push_dir", techage.side_to_outdir("R", node.param2))
Tube:after_place_node(pos)
end,
tubelib2_on_update2 = function(pos, dir1, tlib2, node)
local name = "techage:ta4_concentrator"..networks.junction_type(pos, Tube, "R", node.param2)
minetest.swap_node(pos, {name = name, param2 = node.param2})
end,
ta_rotate_node = function(pos, node, new_param2)
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
M(pos):set_int("push_dir", techage.side_to_outdir("R", new_param2))
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_node(pos)
end,
}, 27)
for _, name in ipairs(names) do
Tube:set_valid_sides(name, {"B", "R", "F", "L", "D", "U"})
end
techage.register_node(names, {
on_push_item = function(pos, in_dir, stack)
local push_dir = M(pos):get_int("push_dir")
if networks.Flip[push_dir] ~= in_dir then
return techage.safe_push_items(pos, push_dir, stack)
else
return stack
end
end,
is_pusher = true, -- is a pulling/pushing node
})
minetest.register_craft({
output = "techage:concentrator27",
recipe = {
{"", "techage:tubeS", ""},
{"techage:tubeS", "", "techage:tubeS"},
{"", "techage:tubeS", ""},
},
})
minetest.register_craft({
output = "techage:ta4_concentrator27",
recipe = {
{"", "techage:ta4_tubeS", ""},
{"techage:ta4_tubeS", "", "techage:ta4_tubeS"},
{"", "techage:ta4_tubeS", ""},
},
})

View File

@ -1,314 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Consumer node basis functionality.
It handles:
- up to 4 stages of nodes (TA2/TA3/TA4/TA5)
- power consumption
- node state handling
- registration of passive and active nodes
- Tube connections are on left and right side (from left to right)
- Power connection are on front and back side (front or back)
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local CRDN = function(node) return (minetest.registered_nodes[node.name] or {}).consumer end
local Tube = techage.Tube
local power = networks.power
local liquid = networks.liquid
local CYCLE_TIME = 2
local function get_keys(tbl)
local keys = {}
for k,v in pairs(tbl) do
keys[#keys + 1] = k
end
return keys
end
local function has_power(pos, nvm, state)
local crd = CRD(pos)
return power.power_available(pos, crd.power_netw)
end
local function start_node(pos, nvm, state)
end
local function stop_node(pos, nvm, state)
end
local function node_timer_pas(pos, elapsed)
local crd = CRD(pos)
local nvm = techage.get_nvm(pos)
-- handle power consumption
if crd.power_netw and techage.needs_power(nvm) then
local consumed = power.consume_power(pos, crd.power_netw, nil, crd.power_consumption)
if consumed == crd.power_consumption then
crd.State:start(pos, nvm)
end
end
-- call the node timer routine
if techage.is_operational(nvm) then
nvm.node_timer_call_cyle = (nvm.node_timer_call_cyle or 0) + 1
if nvm.node_timer_call_cyle >= crd.call_cycle then
crd.node_timer(pos, crd.cycle_time)
nvm.node_timer_call_cyle = 0
end
end
return crd.State:is_active(nvm)
end
local function node_timer_act(pos, elapsed)
local crd = CRD(pos)
local nvm = techage.get_nvm(pos)
-- handle power consumption
if crd.power_netw and techage.needs_power(nvm) then
local consumed = power.consume_power(pos, crd.power_netw, nil, crd.power_consumption)
if consumed < crd.power_consumption then
crd.State:nopower(pos, nvm)
end
end
-- call the node timer routine
if techage.is_operational(nvm) then
nvm.node_timer_call_cyle = (nvm.node_timer_call_cyle or 0) + 1
if nvm.node_timer_call_cyle >= crd.call_cycle then
crd.node_timer(pos, crd.cycle_time)
nvm.node_timer_call_cyle = 0
end
end
return crd.State:is_active(nvm)
end
local function prepare_tiles(tiles, stage, power_png)
local tbl = {}
for _,item in ipairs(tiles) do
if type(item) == "string" then
tbl[#tbl+1] = item:gsub("#", stage):gsub("{power}", power_png):gsub("@@", '#')
else
local temp = table.copy(item)
temp.name = temp.name:gsub("#", stage):gsub("{power}", power_png):gsub("@@", '#')
tbl[#tbl+1] = temp
end
end
return tbl
end
-- 'validStates' is optional and can be used to e.g. enable
-- only one TA2 node {false, true, false, false}
function techage.register_consumer(base_name, inv_name, tiles, tNode, validStates, node_name_prefix, inv_name_prefix)
local names = {}
validStates = validStates or {true, true, true, true}
node_name_prefix = node_name_prefix or "techage:ta"
if inv_name_prefix then
inv_name_prefix = inv_name_prefix.." "
else
inv_name_prefix = ""
end
for stage = 2,5 do
local name_pas = node_name_prefix..stage.."_"..base_name.."_pas"
local name_act = node_name_prefix..stage.."_"..base_name.."_act"
local name_inv = inv_name_prefix.."TA"..stage.." "..inv_name
names[#names+1] = name_pas
if validStates[stage] then
local power_network
local power_png = 'techage_axle_clutch.png'
local power_used = tNode.power_consumption ~= nil
local sides
-- power needed?
if power_used then
if stage > 2 then
power_network = techage.ElectricCable
power_png = 'techage_appl_hole_electric.png'
sides = get_keys(tNode.power_sides or {F=1, B=1, U=1, D=1})
else
power_network = techage.Axle
power_png = 'techage_axle_clutch.png'
sides = get_keys(tNode.power_sides or {F=1, B=1, U=1, D=1})
end
end
local tState = techage.NodeStates:new({
node_name_passive = name_pas,
node_name_active = name_act,
infotext_name = name_inv,
cycle_time = CYCLE_TIME,
standby_ticks = tNode.standby_ticks,
formspec_func = tNode.formspec,
on_state_change = tNode.on_state_change,
can_start = tNode.can_start,
quick_start = tNode.quick_start,
has_power = tNode.has_power or power_used and has_power or nil,
start_node = power_used and start_node or nil,
stop_node = power_used and stop_node or nil,
})
local tConsumer = {
stage = stage,
State = tState,
-- number of items to be processed per cycle
num_items = tNode.num_items and tNode.num_items[stage],
power_consumption = power_used and
tNode.power_consumption[stage] or 0,
node_timer = tNode.node_timer,
cycle_time = tNode.cycle_time,
call_cycle = tNode.cycle_time / 2,
power_netw = power_network,
}
local after_place_node = function(pos, placer, itemstack, pointed_thing)
local crd = CRD(pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local node = minetest.get_node(pos)
meta:set_int("push_dir", techage.side_to_indir("L", node.param2))
meta:set_int("pull_dir", techage.side_to_indir("R", node.param2))
meta:set_string("owner", placer:get_player_name())
-- Delete existing node number. Needed for Digtron compatibility.
if (meta:contains("node_number")) then
meta:set_string("node_number", "")
end
local number = techage.add_node(pos, name_pas, stage == 2)
if crd.power_netw then
crd.power_netw:after_place_node(pos)
end
if tNode.after_place_node then
tNode.after_place_node(pos, placer, itemstack, pointed_thing)
end
crd.State:node_init(pos, nvm, number)
end
local after_dig_node = function(pos, oldnode, oldmetadata, digger)
if tNode.after_dig_node then
tNode.after_dig_node(pos, oldnode, oldmetadata, digger)
end
local crd = CRDN(oldnode)
if crd.power_netw then
crd.power_netw:after_dig_node(pos)
end
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end
tNode.groups.not_in_creative_inventory = 0
local def_pas = {
description = name_inv,
tiles = prepare_tiles(tiles.pas, stage, power_png),
consumer = tConsumer,
drawtype = tNode.drawtype,
node_box = tNode.node_box,
selection_box = tNode.selection_box,
can_dig = tNode.can_dig,
on_rotate = tNode.on_rotate or screwdriver.disallow,
on_timer = node_timer_pas,
on_receive_fields = tNode.on_receive_fields,
on_rightclick = tNode.on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
preserve_metadata = tNode.preserve_metadata,
allow_metadata_inventory_put = tNode.allow_metadata_inventory_put,
allow_metadata_inventory_move = tNode.allow_metadata_inventory_move,
allow_metadata_inventory_take = tNode.allow_metadata_inventory_take,
on_metadata_inventory_move = tNode.on_metadata_inventory_move,
on_metadata_inventory_put = tNode.on_metadata_inventory_put,
on_metadata_inventory_take = tNode.on_metadata_inventory_take,
ta_rotate_node = tNode.ta_rotate_node,
ta3_formspec = stage == 3 and tNode.ta3_formspec,
ta4_formspec = stage == 4 and tNode.ta4_formspec,
paramtype = tNode.paramtype,
paramtype2 = "facedir",
drop = tNode.drop,
groups = table.copy(tNode.groups),
is_ground_content = false,
sounds = tNode.sounds,
}
-- Copy custom properties (starting with an underscore)
for k,v in pairs(tNode) do
if string.sub(k, 1, 1) == "_" then
def_pas[k] = v
end
end
minetest.register_node(name_pas, def_pas)
tNode.groups.not_in_creative_inventory = 1
local def_act = {
description = name_inv,
tiles = prepare_tiles(tiles.act, stage, power_png),
consumer = tConsumer,
drawtype = tNode.drawtype,
node_box = tNode.node_box,
selection_box = tNode.selection_box,
on_rotate = tNode.on_rotate or screwdriver.disallow,
on_timer = node_timer_act,
on_receive_fields = tNode.on_receive_fields,
on_rightclick = tNode.on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = tNode.allow_metadata_inventory_put,
allow_metadata_inventory_move = tNode.allow_metadata_inventory_move,
allow_metadata_inventory_take = tNode.allow_metadata_inventory_take,
on_metadata_inventory_move = tNode.on_metadata_inventory_move,
on_metadata_inventory_put = tNode.on_metadata_inventory_put,
on_metadata_inventory_take = tNode.on_metadata_inventory_take,
ta_rotate_node = tNode.ta_rotate_node,
ta3_formspec = stage == 3 and tNode.ta3_formspec,
ta4_formspec = stage == 4 and tNode.ta4_formspec,
paramtype = tNode.paramtype,
paramtype2 = "facedir",
drop = "",
diggable = false,
groups = table.copy(tNode.groups),
is_ground_content = false,
sounds = tNode.sounds,
}
-- Copy custom properties (starting with an underscore)
for k,v in pairs(tNode) do
if string.sub(k, 1, 1) == "_" then
def_act[k] = v
end
end
minetest.register_node(name_act, def_act)
if power_used then
power.register_nodes({name_pas, name_act}, power_network, "con", sides)
end
techage.register_node({name_pas, name_act}, tNode.tubing)
if tNode.tube_sides then
Tube:set_valid_sides(name_pas, get_keys(tNode.tube_sides))
Tube:set_valid_sides(name_act, get_keys(tNode.tube_sides))
end
end
end
return names[1], names[2], names[3], names[4]
end

View File

@ -1,683 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Distributor
]]--
-- for lazy programmers
local M = minetest.get_meta
local N = minetest.get_node
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local Tube = techage.Tube
local S = techage.S
local SRC_INV_SIZE = 8
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 4
local FILTER_ITEM_LIMIT_PER_STACK = 12
local FILTER_ITEM_LIMIT = 36
local INFO = [[Turn port on/off or read its state: command = 'port', payload = red/green/blue/yellow{=on/off}]]
--local Side2Color = {B="red", L="green", F="blue", R="yellow"}
local SlotColors = {"red", "green", "blue", "yellow"}
local SlotNumbers = {red = 1, green = 2, blue = 3, yellow = 4}
local Num2Ascii = {"B", "L", "F", "R"}
local FilterCache = {} -- local cache for filter settings
local function filter_settings(pos)
local meta = M(pos)
local param2 = techage.get_node_lvm(pos).param2
local inv = meta:get_inventory()
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
local ItemFilter = {} -- {<item:name> = {dir,...}]
local OpenPorts = {} -- {dir, ...}
local counter = 0 -- counts total item number in filter configuration
-- collect all filter settings
for idx,slot in ipairs(SlotColors) do
if filter[idx] == true then
local side = Num2Ascii[idx]
local out_dir = techage.side_to_outdir(side, param2)
if inv:is_empty(slot) then
table.insert(OpenPorts, out_dir)
else
for idx2,stack in ipairs(inv:get_list(slot)) do
local name = stack:get_name()
if name ~= "" then
if not ItemFilter[name] then
ItemFilter[name] = {}
end
for _ = 1, math.min(FILTER_ITEM_LIMIT_PER_STACK, stack:get_count()) do
if counter > FILTER_ITEM_LIMIT then
break
end
table.insert(ItemFilter[name], out_dir)
counter = counter + 1
end
end
end
end
end
end
FilterCache[minetest.hash_node_position(pos)] = {
ItemFilter = ItemFilter,
OpenPorts = OpenPorts,
}
end
-- Return filter table and list of open ports.
-- (see test data)
local function get_filter_settings(pos)
-- local ItemFilter = {
-- ["default:dirt"] = {1,2},
-- ["default:cobble"] = {4},
-- }
-- local OpenPorts = {3}
-- return ItemFilter, OpenPorts
local hash = minetest.hash_node_position(pos)
if FilterCache[hash] == nil then
filter_settings(pos)
end
return FilterCache[hash].ItemFilter, FilterCache[hash].OpenPorts
end
local function blocking_checkbox(pos, filter, is_hp)
local cnt = 0
local _, open_ports = get_filter_settings(pos)
local fs_pos = is_hp and "0.25,5" or "3,3.9"
for _,val in ipairs(filter) do
if val then cnt = cnt + 1 end
end
if cnt > 1 and #open_ports > 0 then
local blocking = M(pos):get_int("blocking") == 1 and "true" or "false"
return "checkbox["..fs_pos..";blocking;"..S("blocking mode")..";"..blocking.."]"..
"tooltip["..fs_pos..";1,1;"..S("Block configured items for open ports")..";#0C3D32;#FFFFFF]"
else
M(pos):set_int("blocking", 0) -- disable blocking
end
return ""
end
local function formspec(self, pos, nvm)
local filter = minetest.deserialize(M(pos):get_string("filter")) or {false,false,false,false}
local is_hp = nvm.high_performance == true
local blocking = blocking_checkbox(pos, filter, is_hp)
if is_hp then
return "size[10.5,9.5]"..
"box[0.25,-0.1;9.6,1.1;#005500]"..
"label[0.6,0.2;"..S("Input").."]"..
"list[context;src;1.75,0;8,1;]"..
blocking..
"image_button[0.25,5.8;1,1;"..self:get_state_button_image(nvm)..";state_button;]"..
"tooltip[0.25,5.8;1,1;"..self:get_state_tooltip(nvm).."]"..
"checkbox[0.25,1.2;filter1;On;"..dump(filter[1]).."]"..
"checkbox[0.25,2.2;filter2;On;"..dump(filter[2]).."]"..
"checkbox[0.25,3.2;filter3;On;"..dump(filter[3]).."]"..
"checkbox[0.25,4.2;filter4;On;"..dump(filter[4]).."]"..
"image[1.25,1.2;0.3,1;techage_inv_red.png]"..
"image[1.25,2.2;0.3,1;techage_inv_green.png]"..
"image[1.25,3.2;0.3,1;techage_inv_blue.png]"..
"image[1.25,4.2;0.3,1;techage_inv_yellow.png]"..
"list[context;red;1.75,1.2;8,1;]"..
"list[context;green;1.75,2.2;8,1;]"..
"list[context;blue;1.75,3.2;8,1;]"..
"list[context;yellow;1.75,4.2;8,1;]"..
"list[current_player;main;1.75,5.8;8,4;]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(1.75,5.8)
else
return "size[10.5,8.5]"..
"list[context;src;0,0;2,4;]"..
blocking..
"image[2,1.5;1,1;techage_form_arrow.png]"..
"image_button[0,4.8;1,1;"..self:get_state_button_image(nvm)..";state_button;]"..
"tooltip[0,4.8;1,1;"..self:get_state_tooltip(nvm).."]"..
"checkbox[3,0;filter1;On;"..dump(filter[1]).."]"..
"checkbox[3,1;filter2;On;"..dump(filter[2]).."]"..
"checkbox[3,2;filter3;On;"..dump(filter[3]).."]"..
"checkbox[3,3;filter4;On;"..dump(filter[4]).."]"..
"image[4,0;0.3,1;techage_inv_red.png]"..
"image[4,1;0.3,1;techage_inv_green.png]"..
"image[4,2;0.3,1;techage_inv_blue.png]"..
"image[4,3;0.3,1;techage_inv_yellow.png]"..
"list[context;red;4.5,0;6,1;]"..
"list[context;green;4.5,1;6,1;]"..
"list[context;blue;4.5,2;6,1;]"..
"list[context;yellow;4.5,3;6,1;]"..
"list[current_player;main;1.25,4.8;8,4;]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(1.25,4.8)
end
end
local function get_total_filter_items_number(pos, except_listname, except_index)
local inv = M(pos):get_inventory()
local total = 0
for _, listname in ipairs(SlotColors) do
local list = inv:get_list(listname)
for idx, stack in ipairs(list) do
if not (listname == except_listname and idx == except_index) then
total = total + stack:get_count()
end
end
end
return total
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
CRD(pos).State:start_if_standby(pos)
return stack:get_count()
else
stack:add_item(list[index])
local max_items_to_limit = FILTER_ITEM_LIMIT - get_total_filter_items_number(pos, listname, index)
stack:set_count(math.min(FILTER_ITEM_LIMIT_PER_STACK, stack:get_count(), max_items_to_limit))
inv:set_stack(listname, index, stack)
return 0
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
return stack:get_count()
else
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
list[index]:take_item(stack:get_count())
inv:set_stack(listname, index, list[index])
return 0
end
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = minetest.get_meta(pos):get_inventory()
local stack = inv:get_stack(from_list, from_index)
if from_list == "src" and to_list ~= "src" then
stack:add_item(inv:get_stack(to_list, to_index))
local max_items_to_limit = FILTER_ITEM_LIMIT - get_total_filter_items_number(pos, to_list, to_index)
stack:set_count(math.min(FILTER_ITEM_LIMIT_PER_STACK, stack:get_count(), max_items_to_limit))
inv:set_stack(to_list, to_index, stack)
return 0
elseif from_list ~= "src" and to_list == "src" then
inv:set_stack(from_list, from_index, nil)
return 0
elseif from_list ~= "src" and to_list ~= "src" then
return math.min(stack:get_count(), FILTER_ITEM_LIMIT_PER_STACK - inv:get_stack(to_list, to_index):get_count())
else
return stack:get_count()
end
end
local function tubelib2_on_update2(pos, outdir, tlib2, node)
local is_ta4_tube = true
for dir = 1,4 do
for i, pos, node in Tube:get_tube_line(pos, dir) do
is_ta4_tube = is_ta4_tube and techage.TA4tubes[node.name]
end
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
if CRD(pos).stage == 4 and not is_ta4_tube then
nvm.num_items = crd.num_items / 2
else
nvm.num_items = crd.num_items
end
end
local function shuffle(list)
for i = #list, 2, -1 do
local j = math.random(i)
list[i], list[j] = list[j], list[i]
end
return list
end
local function push_item(pos, base_filter, itemstack, num_items, nvm)
local filter = shuffle(table.copy(base_filter))
local idx = 1
local num_pushed = 0
local num_ports = #filter
local amount = math.floor(math.max((num_items + 1) / num_ports, 1))
local num_of_trials = 0
while num_pushed < num_items and num_of_trials <= 8 do
num_of_trials = num_of_trials + 1
local push_dir = filter[idx]
local num_to_push = math.min(amount, num_items - num_pushed)
local leftover = techage.push_items(pos, push_dir, itemstack:peek_item(num_to_push))
local pushed
if not leftover then
pushed = 0
elseif leftover ~= true then
pushed = num_to_push - leftover:get_count()
else -- leftover == true
pushed = num_to_push
end
num_pushed = num_pushed + pushed
nvm.port_counter[push_dir] = (nvm.port_counter[push_dir] or 0) + pushed
-- filter start offset
idx = idx + 1
if idx > num_ports then
idx = 1
end
end
return num_pushed
end
-- move items to output slots
local function distributing(pos, inv, crd, nvm)
local item_filter, open_ports = get_filter_settings(pos)
local sum_num_pushed = 0
local num_pushed = 0
local blocking_mode = M(pos):get_int("blocking") == 1
-- start searching after last position
local offs = nvm.last_index or 1
for i = 1, SRC_INV_SIZE do
local idx = ((i + offs - 1) % 8) + 1
local stack = inv:get_stack("src", idx)
local item_name = stack:get_name()
local num_items = stack:get_count()
local num_to_push = math.min((nvm.num_items or crd.num_items) - sum_num_pushed, num_items)
local stack_to_push = stack:peek_item(num_to_push)
local filter = item_filter[item_name]
num_pushed = 0
if filter and #filter > 0 then
-- Push items based on filter
num_pushed = push_item(pos, filter, stack_to_push, num_to_push, nvm)
elseif blocking_mode and #open_ports > 0 then
-- Push items based on open ports
num_pushed = push_item(pos, open_ports, stack_to_push, num_to_push, nvm)
end
if not blocking_mode and num_pushed == 0 and #open_ports > 0 then
-- Push items based on open ports
num_pushed = push_item(pos, open_ports, stack_to_push, num_to_push, nvm)
end
sum_num_pushed = sum_num_pushed + num_pushed
stack:take_item(num_pushed)
inv:set_stack("src", idx, stack)
if sum_num_pushed >= (nvm.num_items or crd.num_items) then
nvm.last_index = idx
break
end
end
if sum_num_pushed == 0 then
crd.State:blocked(pos, nvm)
else
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
end
-- move items to the output slots
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
nvm.port_counter = nvm.port_counter or {}
local crd = CRD(pos)
local inv = M(pos):get_inventory()
if not inv:is_empty("src") then
distributing(pos, inv, crd, nvm)
else
crd.State:idle(pos, nvm)
end
return crd.State:is_active(nvm)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local crd = CRD(pos)
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
if fields.filter1 ~= nil then
filter[1] = fields.filter1 == "true"
elseif fields.filter2 ~= nil then
filter[2] = fields.filter2 == "true"
elseif fields.filter3 ~= nil then
filter[3] = fields.filter3 == "true"
elseif fields.filter4 ~= nil then
filter[4] = fields.filter4 == "true"
elseif fields.blocking ~= nil then
meta:set_int("blocking", fields.blocking == "true" and 1 or 0)
end
meta:set_string("filter", minetest.serialize(filter))
filter_settings(pos)
local nvm = techage.get_nvm(pos)
if fields.state_button ~= nil then
crd.State:state_button_event(pos, nvm, fields)
else
meta:set_string("formspec", formspec(crd.State, pos, nvm))
end
end
-- techage command to turn on/off filter channels
local function change_filter_settings(pos, slot, val)
local meta = M(pos)
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
local num = SlotNumbers[slot] or 1
if num >= 1 and num <= 4 then
filter[num] = val == "on"
end
meta:set_string("filter", minetest.serialize(filter))
local hash = minetest.hash_node_position(pos)
FilterCache[hash] = nil
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec(CRD(pos).State, pos, nvm))
return true
end
-- techage command to read filter channel status (on/off)
local function read_filter_settings(pos, slot)
local filter = minetest.deserialize(M(pos):get_string("filter")) or {false,false,false,false}
return filter[SlotNumbers[slot]] and "on" or "off"
end
local function get_payload_values(payload)
local color
local idx = 0
local items = {ItemStack(""), ItemStack(""), ItemStack(""), ItemStack(""), ItemStack(""), ItemStack("")}
for s in payload:gmatch("[^%s]+") do --- white spaces
if not color then
if SlotNumbers[s] then
color = s
else
return "red", {}
end
else
idx = idx + 1
if idx <= 6 then
items[idx] = ItemStack(s)
end
end
end
return color, items
end
local function str_of_inv_items(pos, color)
color = SlotColors[color] or color
if SlotNumbers[color] then
local inv = M(pos):get_inventory()
local t = {}
for idx = 1, 6 do
local item = inv:get_stack(color, idx)
if item:get_count() > 0 then
t[#t + 1] = item:get_name()
end
end
return table.concat(t, " ")
end
return ""
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("src")
end
local get_tiles = function(is_hp)
local variant = is_hp and "_hp" or ""
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_appl_distri.png^techage_frame_ta#_top"..variant..".png^techage_appl_color_top.png",
"techage_filling_ta#.png^techage_frame_ta#_top"..variant..".png^(techage_appl_color_top.png^[transformFY)",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_yellow.png",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_green.png",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_red.png",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_blue.png",
}
tiles.act = {
-- up, down, right, left, back, front
{
name = "techage_filling4_ta#.png^techage_appl_distri4.png^techage_frame4_ta#_top"..variant..".png^techage_appl_color_top4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1.0,
},
},
"techage_filling_ta#.png^techage_frame_ta#_top"..variant..".png^(techage_appl_color_top.png^[transformFY)",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_yellow.png",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_green.png",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_red.png",
"techage_filling_ta#.png^techage_frame_ta#"..variant..".png^techage_appl_distri_blue.png",
}
return tiles
end
local tubing = {
on_pull_item = function(pos, in_dir, num)
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "src", num)
end,
on_push_item = function(pos, in_dir, stack)
CRD(pos).State:start_if_standby(pos)
local inv = M(pos):get_inventory()
return techage.put_items(inv, "src", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local inv = M(pos):get_inventory()
return techage.put_items(inv, "src", stack)
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "info" then
return INFO
elseif topic == "port" then
-- "red"/"green"/"blue"/"yellow" = "on"/"off"
local slot, val = techage.ident_value(payload)
if val == "" then
return read_filter_settings(pos, slot)
else
return change_filter_settings(pos, slot, val)
end
elseif topic == "config" then
local color, items = get_payload_values(payload)
local inv = M(pos):get_inventory()
for idx,item in ipairs(items) do
inv:set_stack(color, idx, item)
end
local hash = minetest.hash_node_position(pos)
FilterCache[hash] = nil
return true
elseif topic == "get" then
return str_of_inv_items(pos, payload)
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 4 then
local slot = SlotColors[payload[1]]
local state = payload[2] == 1 and "on" or "off"
change_filter_settings(pos, slot, state)
return 0
elseif topic == 67 then
local color, items = get_payload_values(payload)
local inv = M(pos):get_inventory()
for idx,item in ipairs(items) do
inv:set_stack(color, idx, item)
end
local hash = minetest.hash_node_position(pos)
FilterCache[hash] = nil
return 0
else
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 148 then
return 0, str_of_inv_items(pos, payload[1])
else
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local def = {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer)
local meta = M(pos)
local filter = {false,false,false,false}
meta:set_string("filter", minetest.serialize(filter))
local inv = meta:get_inventory()
inv:set_size('src', 8)
inv:set_size('yellow', 6)
inv:set_size('green', 6)
inv:set_size('red', 6)
inv:set_size('blue', 6)
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
tubelib2_on_update2 = tubelib2_on_update2,
on_metadata_inventory_move = function(pos, from_list, from_index, to_list)
if from_list ~= "src" or to_list ~= "src" then
filter_settings(pos)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
end,
on_metadata_inventory_put = function(pos, listname)
if listname ~= "src" then
filter_settings(pos)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
end,
on_metadata_inventory_take = function(pos, listname)
if listname ~= "src" then
filter_settings(pos)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
end,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,4,12,24},
}
local node_name_ta2, node_name_ta3, node_name_ta4 = techage.register_consumer(
"distributor",
S("Distributor"),
get_tiles(false),
def
)
local hp_def = table.copy(def)
hp_def.after_place_node = function(pos, placer)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
nvm.high_performance = true
local filter = {false,false,false,false}
meta:set_string("filter", minetest.serialize(filter))
local inv = meta:get_inventory()
inv:set_size('src', 8)
inv:set_size('yellow', 8)
inv:set_size('green', 8)
inv:set_size('red', 8)
inv:set_size('blue', 8)
end
hp_def.num_items = {0,0,0,36}
local _, _, node_name_ta4_hp = techage.register_consumer(
"high_performance_distributor", S("High Performance Distributor"),
get_tiles(true),
hp_def,
{false, false, false, true}
)
minetest.register_craft({
output = node_name_ta2.." 2",
recipe = {
{"group:wood", "techage:iron_ingot", "group:wood"},
{"techage:tubeS", "default:mese_crystal", "techage:tubeS"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "techage:iron_ingot", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "techage:iron_ingot", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
minetest.register_craft({
output = node_name_ta4_hp,
recipe = {
{node_name_ta4, "default:copper_ingot"},
{"default:mese_crystal_fragment", node_name_ta4},
},
})

View File

@ -1,314 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Electronic Fab
]]--
-- for lazy programmers
local M = minetest.get_meta
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local S = techage.S
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 6
local recipes = techage.recipes
local RecipeType = {
[2] = "ta2_electronic_fab",
[3] = "ta3_electronic_fab",
[4] = "ta4_electronic_fab",
}
local function formspec(self, pos, nvm)
local rtype = RecipeType[CRD(pos).stage]
local owner = M(pos):get_string("owner")
return "size[8.4,8.4]"..
"list[context;src;0,0;2,4;]"..
recipes.formspec(2.2, 0, rtype, nvm, owner)..
"list[context;dst;6.4,0;2,4;]"..
"image_button[3.7,3.3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.7,3.3;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[current_player;main;0.2,4.5;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0.2, 4.5)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local crd = CRD(pos)
if listname == "src" then
crd.State:start_if_standby(pos)
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack(from_list, from_index)
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function get_original_waste(inv, waste)
-- Waste has meta data, so we need to find the original waste item
for i = 1, 8 do
local stack = inv:get_stack("src", i)
if stack:get_count() == 1 then
if stack:get_name() == waste:get_name() then
return stack
end
end
end
return waste
end
local function making(pos, crd, nvm, inv)
local owner = M(pos):get_string("owner")
local rtype = RecipeType[crd.stage]
local recipe = recipes.get(nvm, rtype, owner)
local output = ItemStack(recipe.output.name .. " " .. recipe.output.num)
local waste = recipe.waste and ItemStack(recipe.waste.name .. " " .. recipe.waste.num)
if inv:room_for_item("dst", output) and (not waste or inv:room_for_item("dst", waste)) then
for _,item in ipairs(recipe.input) do
local input = ItemStack(item.name.." "..item.num)
if not inv:contains_item("src", input) then
crd.State:idle(pos, nvm)
return
end
end
-- For some recipes, an item customized via metadata is used as a copy template.
-- This allows specially programmed items such as ROM chips to be produced.
-- The metadata of the copy template must be passed to the on_production function.
-- At the same time, the metadata of the copy template must not be lost when moving
-- as 'waste' to the output inventory.
local idef = minetest.registered_items[recipe.output.name]
if waste and idef and idef.on_production then
waste = get_original_waste(inv, waste)
local metadata = waste:get_meta():to_table().fields or {}
output = idef.on_production(output, metadata)
end
for _,item in ipairs(recipe.input) do
local input = ItemStack(item.name.." "..item.num)
inv:remove_item("src", input)
end
inv:add_item("dst", output)
if waste then
inv:add_item("dst", waste)
end
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
end
crd.State:idle(pos, nvm)
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
if inv then
making(pos, crd, nvm, inv)
end
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
if not nvm.running then
recipes.on_receive_fields(pos, formname, fields, player)
end
crd.State:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(crd.State, pos, nvm))
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("dst") and inv:is_empty("src")
end
local tiles = {}
-- '#' will be replaced by the stage number
tiles.pas = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_electronic_fab.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_electronic_fab.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
name = "techage_filling4_ta#.png^techage_appl_electronic_fab4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
{
name = "techage_filling4_ta#.png^techage_appl_electronic_fab4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
}
local tubing = {
on_inv_request = function(pos, in_dir, access_type)
if access_type == "push" then
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
return meta:get_inventory(), "src"
end
end
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "dst", num)
end
end,
on_push_item = function(pos, in_dir, stack, idx)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
--CRD(pos).State:start_if_standby(pos) -- would need power!
return techage.put_items(inv, "src", stack, idx)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "dst", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("electronic_fab", S("Electronic Fab"), tiles, {
drawtype = "normal",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size("src", 8)
inv:set_size("dst", 8)
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,1,1},
power_consumption = {0,8,12,12},
},
{false, true, true, true}) -- TA2/TA3/TA4
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"group:wood", "default:diamond", "group:wood"},
{"techage:tubeS", "basic_materials:gear_steel", "techage:tubeS"},
{"group:wood", "default:steel_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:diamond", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:diamond", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
techage.recipes.register_craft_type("ta2_electronic_fab", {
description = S("TA2 Ele Fab"),
icon = 'techage_filling_ta2.png^techage_appl_electronic_fab.png^techage_frame_ta2.png',
width = 2,
height = 2,
})
techage.recipes.register_craft_type("ta3_electronic_fab", {
description = S("TA3 Ele Fab"),
icon = 'techage_filling_ta3.png^techage_appl_electronic_fab.png^techage_frame_ta3.png',
width = 2,
height = 2,
})
techage.recipes.register_craft_type("ta4_electronic_fab", {
description = S("TA4 Ele Fab"),
icon = 'techage_filling_ta4.png^techage_appl_electronic_fab.png^techage_frame_ta4.png',
width = 2,
height = 2,
})

View File

@ -1,340 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Forceload block
]]--
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S = techage.S
local function calc_area(pos)
local xpos = (math.floor(pos.x / 16) * 16)
local ypos = (math.floor(pos.y / 16) * 16)
local zpos = (math.floor(pos.z / 16) * 16)
local pos1 = {x=xpos, y=ypos, z=zpos}
local pos2 = {x=xpos+15, y=ypos+15, z=zpos+15}
return pos1, pos2
end
local function in_list(list, x)
local pos1 = calc_area(x)
for _,v in ipairs(list) do
local pos2 = calc_area(v)
if vector.equals(pos1, pos2) then return true end
end
return false
end
local function remove_list_elem(list, x)
local n = nil
for idx, v in ipairs(list) do
if vector.equals(v, x) then
n = idx
break
end
end
if n then
table.remove(list, n)
end
return list
end
local function chat(player, text)
minetest.chat_send_player(player:get_player_name(), "[Techage] "..text)
end
local function postload_area(pos)
minetest.log("warning", "[FLB] area "..P2S(pos).." not loaded!")
if not minetest.forceload_block(pos, true) then
minetest.after(60, postload_area, pos)
end
end
local function add_pos(pos, player)
local meta = player:get_meta()
local lPos = minetest.deserialize(meta:get_string("techage_forceload_blocks")) or {}
if not in_list(lPos, pos) and (#lPos < techage.max_num_forceload_blocks or
minetest.global_exists("creative") and creative.is_enabled_for and
creative.is_enabled_for(player:get_player_name())) then
lPos[#lPos+1] = pos
local meta = player:get_meta()
meta:set_string("techage_forceload_blocks", minetest.serialize(lPos))
return true
end
return false
end
local function del_pos(pos, player)
local meta = player:get_meta()
local lPos = minetest.deserialize(meta:get_string("techage_forceload_blocks")) or {}
lPos = remove_list_elem(lPos, pos)
if next(lPos) then
meta:set_string("techage_forceload_blocks", minetest.serialize(lPos))
else
meta:set_string("techage_forceload_blocks", "")
end
end
local function get_pos_list(player)
local meta = player:get_meta()
return minetest.deserialize(meta:get_string("techage_forceload_blocks")) or {}
end
local function set_pos_list(player, lPos)
local meta = player:get_meta()
if next(lPos) then
meta:set_string("techage_forceload_blocks", minetest.serialize(lPos))
else
meta:set_string("techage_forceload_blocks", "")
end
end
local function show_flbs(pos, name, range)
local pos1 = {x=pos.x-range, y=pos.y-range, z=pos.z-range}
local pos2 = {x=pos.x+range, y=pos.y+range, z=pos.z+range}
for _,npos in ipairs(minetest.find_nodes_in_area(pos1, pos2, {"techage:forceload", "techage:forceloadtile"})) do
local _pos1, _pos2 = calc_area(npos)
local owner = M(npos):get_string("owner")
techage.mark_region(name, _pos1, _pos2, owner .. " " .. P2S(npos))
end
end
local function get_data(pos, player)
local pos1, pos2 = calc_area(pos)
local meta = player:get_meta()
local num = #minetest.deserialize(meta:get_string("techage_forceload_blocks")) or 0
local max = techage.max_num_forceload_blocks
return pos1, pos2, num, max
end
local function formspec(name)
local player = minetest.get_player_by_name(name)
if player then
local lPos = get_pos_list(player)
local tRes = {}
tRes[#tRes+1] = "#"
tRes[#tRes+1] = S("Block at pos")
tRes[#tRes+1] = S("Area from")
tRes[#tRes+1] = S("Area to")
tRes[#tRes+1] = S("Status")
for idx,pos in ipairs(lPos) do
local pos1, pos2 = calc_area(pos)
tRes[#tRes+1] = idx
tRes[#tRes+1] = minetest.formspec_escape(P2S(pos))
tRes[#tRes+1] = minetest.formspec_escape(P2S(pos1))
tRes[#tRes+1] = minetest.formspec_escape(P2S(pos2))
tRes[#tRes+1] = minetest.forceload_block(pos, true) and 'Loaded' or 'Unloaded'
end
return "size[9,9]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"label[0,0;"..S("List of your Forceload Blocks:").."]"..
"tablecolumns[text,width=1.8;text,width=12;text,width=12;text,width=12;text,width=12]"..
"table[0,0.6;8.8,8.4;output;"..table.concat(tRes, ",")..";1]"
end
end
local function on_place(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
return minetest.rotate_and_place(itemstack, placer, pointed_thing)
end
local function after_place_node(pos, placer, itemstack)
if add_pos(pos, placer) then
minetest.forceload_block(pos, true)
local pos1, pos2, num, max = get_data(pos, placer)
M(pos):set_string("infotext", "Area "..P2S(pos1).." to "..P2S(pos2).." "..S("loaded").."!\n"..
S("Punch the block to make the area visible."))
chat(placer, "Area ("..num.."/"..max..") "..P2S(pos1).." to "..P2S(pos2).." "..S("loaded").."!")
techage.mark_region(placer:get_player_name(), pos1, pos2)
M(pos):set_string("owner", placer:get_player_name())
else
chat(placer, S("Area already loaded or max. number of Forceload Blocks reached!"))
minetest.remove_node(pos)
return itemstack
end
end
local function after_dig_node(pos, oldnode, oldmetadata, digger)
local player = minetest.get_player_by_name(oldmetadata.fields.owner)
if player then
del_pos(pos, player)
end
minetest.forceload_free_block(pos, true)
techage.unmark_region(oldmetadata.fields.owner)
end
local function on_rightclick(pos, node, clicker, itemstack, pointed_thing)
local owner = M(pos):get_string("owner")
local name = clicker:get_player_name()
if name == owner or minetest.check_player_privs(name, "server") then
local s = formspec(owner)
if s then
minetest.show_formspec(name, "techage:forceload", s)
end
end
end
local function on_punch(pos, node, puncher, pointed_thing)
local pos1, pos2 = calc_area(pos)
techage.switch_region(puncher:get_player_name(), pos1, pos2)
end
minetest.register_node("techage:forceload", {
description = S("Techage Forceload Block"),
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta2.png^techage_frame_ta2_top.png',
'techage_filling_ta2.png^techage_frame_ta2_top.png',
{
name = "techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_forceload.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
on_rightclick = on_rightclick,
on_punch = on_punch,
paramtype = "light",
sunlight_propagates = true,
use_texture_alpha = techage.CLIP,
groups = {choppy=2, cracky=2, crumbly=2,
digtron_protected = 1,
not_in_creative_inventory = techage.max_num_forceload_blocks == 0 and 1 or 0},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:forceloadtile", {
description = S("Techage Forceload Tile"),
tiles = {
-- up, down, right, left, back, front
{
name = "techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_forceload.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.5,
},
},
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
--{-5/16, -7/16, -5/16, 5/16, -5/16, 5/16},
{-4/16, -8/16, -4/16, 4/16, -15/32, 4/16},
},
},
on_place = on_place,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
on_rightclick = on_rightclick,
on_punch = on_punch,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
groups = {choppy=2, cracky=2, crumbly=2,
not_in_creative_inventory = techage.max_num_forceload_blocks == 0 and 1 or 0},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
if techage.max_num_forceload_blocks > 0 then
minetest.register_craft({
output = "techage:forceload",
recipe = {
{"group:wood", "", "group:wood"},
{"default:mese_crystal_fragment", "techage:usmium_nuggets", "default:mese_crystal_fragment"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
type = "shapeless",
output = "techage:forceloadtile",
recipe = {"techage:forceload"},
})
minetest.register_craft({
type = "shapeless",
output = "techage:forceload",
recipe = {"techage:forceloadtile"},
})
end
minetest.register_on_joinplayer(function(player)
local lPos = {}
for _,pos in ipairs(get_pos_list(player)) do
local node = techage.get_node_lvm(pos)
if node.name == "techage:forceload" or node.name == "techage:forceloadtile" then
if not minetest.forceload_block(pos, true) then
minetest.after(60, postload_area, pos)
end
lPos[#lPos+1] = pos
end
end
set_pos_list(player, lPos)
end)
minetest.register_on_leaveplayer(function(player)
for _,pos in ipairs(get_pos_list(player)) do
minetest.forceload_free_block(pos, true)
end
end)
minetest.register_chatcommand("forceload", {
params = "",
description = S("Show all forceload blocks in a 64x64x64 range"),
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then
local pos = player:get_pos()
pos = vector.round(pos)
show_flbs(pos, name, 64)
end
end,
})
minetest.register_chatcommand("forceload_verify", {
params = "",
description = "Checks each forceload block and returns a count of active/placed blocks",
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then
local loaded = {}
local wanted = get_pos_list(player)
for _,pos in ipairs(wanted) do
if minetest.forceload_block(pos, true) then
loaded[#loaded+1] = pos
end
end
minetest.chat_send_player(name, "Found "..#loaded.." out of ".. #wanted .. " force loads")
end
end,
})

View File

@ -1,159 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Tube support for default chests and furnace
]]--
local OwnerCache = {
}
-- Check if the chest is in the protected area of the owner
local function is_owner(pos, meta)
local owner = meta:get_string("owner")
local key = minetest.hash_node_position(pos)
-- If successfull, store info in cache
if OwnerCache[key] ~= owner then
if not minetest.is_protected(pos, owner) then
OwnerCache[key] = owner
end
end
return OwnerCache[key] == owner
end
techage.register_node({"default:chest", "default:chest_open"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
techage.register_node({"default:chest_locked", "default:chest_locked_open"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
if is_owner(pos, meta) then
return meta:get_inventory(), "main"
end
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if is_owner(pos, meta) then
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
techage.register_node({"shop:shop"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
if is_owner(pos, meta) then
if access_type == "push" then
return meta:get_inventory(), "stock"
elseif access_type == "pull" then
return meta:get_inventory(), "register"
end
end
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if is_owner(pos, meta) then
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "register", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "stock", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "register", stack)
end,
})
techage.register_node({"default:furnace", "default:furnace_active"}, {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "dst", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
minetest.get_node_timer(pos):start(1.0)
if in_dir == 5 then
return techage.put_items(inv, "src", stack)
elseif minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
return techage.put_items(inv, "fuel", stack)
else
return techage.put_items(inv, "src", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "dst", stack)
end,
})
techage.register_node({"mobs:beehive"}, {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "beehive", num)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "beehive", stack)
end,
})
techage.register_node({"xdecor:hive"}, {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "honey", num)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "honey", stack)
end,
})

View File

@ -1,341 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2 Gravel Rinser, washing sieved gravel to find more ores
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 4
local Probability = {}
local function formspec(self, pos, nvm)
return "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;3,3;]"..
"item_image[0,0;1,1;default:gravel]"..
"image[0,0;1,1;techage_form_mask.png]"..
"image[3.5,0;1,1;"..techage.get_power_image(pos, nvm).."]"..
"image[3.5,1;1,1;techage_form_arrow.png]"..
"image_button[3.5,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.5,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[context;dst;5,0;3,3;]"..
"list[current_player;main;0,4;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 4)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
CRD(pos).State:start_if_standby(pos)
return stack:get_count()
elseif listname == "dst" then
return 0
end
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack(from_list, from_index)
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function get_water_level(pos)
local node = techage.get_node_lvm(pos)
if minetest.get_item_group(node.name, "water") > 0 then
local ndef = minetest.registered_nodes[node.name]
if ndef and ndef.liquidtype == "flowing" then
return node.param2
end
end
return 99
end
local function determine_water_dir(pos)
local lvl = get_water_level(pos)
if lvl > get_water_level({x=pos.x+1, y=pos.y, z=pos.z}) then
return 2
end
if lvl > get_water_level({x=pos.x-1, y=pos.y, z=pos.z}) then
return 4
end
if lvl > get_water_level({x=pos.x, y=pos.y, z=pos.z+1}) then
return 1
end
if lvl > get_water_level({x=pos.x, y=pos.y, z=pos.z-1}) then
return 3
end
return 0
end
local function set_velocity(obj, pos, vel)
if obj then
obj:set_acceleration({x = 0, y = 0, z = 0})
local p = obj:get_pos()
if p then
obj:set_pos({x=p.x, y=p.y-0.3, z=p.z})
obj:set_velocity(vel)
end
end
end
local function add_object(pos, name)
local dir = determine_water_dir(pos)
if dir > 0 then
local obj = minetest.add_item(pos, ItemStack(name))
local vel = vector.multiply(tubelib2.Dir6dToVector[dir], 0.3)
minetest.after(0.3, set_velocity, obj, pos, vel)
end
end
local function get_random_gravel_ore()
for ore, probability in pairs(Probability) do
if math.random(probability) == 1 then
return ore
end
end
end
local function remove_objects(pos)
for _, object in pairs(minetest.get_objects_inside_radius(pos, 1)) do
local lua_entity = object:get_luaentity()
if not object:is_player() and lua_entity and lua_entity.name == "__builtin:item" then
object:remove()
end
end
end
local function washing(pos, crd, nvm, inv)
-- for testing purposes
if inv:contains_item("src", ItemStack("default:stick")) then
add_object({x=pos.x, y=pos.y+1, z=pos.z}, "default:stick")
inv:remove_item("src", ItemStack("default:stick"))
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
end
local src = ItemStack("techage:sieved_gravel")
local dst = ItemStack("default:sand")
if inv:contains_item("src", src) then
if not inv:room_for_item("dst", dst) then
crd.State:blocked(pos, nvm)
return
end
local ore = get_random_gravel_ore()
if ore then
add_object({x=pos.x, y=pos.y+1, z=pos.z}, ore)
end
inv:add_item("dst", dst)
inv:remove_item("src", src)
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
else
crd.State:idle(pos, nvm)
return
end
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
washing(pos, crd, nvm, inv)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("dst") and inv:is_empty("src")
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
-- up, down, right, left, back, front
"techage_appl_rinser_top.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
{
name = "techage_appl_rinser4_top.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png",
}
local tubing = {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "dst", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
-- CRD(pos).State:start_if_standby(pos) -- would need power!
return techage.put_items(inv, "src", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "dst", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
remove_objects({x=pos.x, y=pos.y+1, z=pos.z})
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("rinser", S("Gravel Rinser"), tiles, {
drawtype = "nodebox",
paramtype = "light",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, 8/16, 8/16, -6/16},
{-8/16, -8/16, 6/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-6/16, -8/16, -6/16, 6/16, 6/16, 6/16},
{-6/16, 6/16, -1/16, 6/16, 8/16, 1/16},
{-1/16, 6/16, -6/16, 1/16, 8/16, 6/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size('src', 9)
inv:set_size('dst', 9)
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,1,1},
power_consumption = {0,3,3,3},
tube_sides = {L=1, R=1, U=1},
},
{false, true, true, false}) -- TA2/TA3
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"group:wood", "default:mese_crystal", "group:wood"},
{"techage:tubeS", "techage:sieve", "techage:tubeS"},
{"group:wood", "default:tin_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
techage.recipes.register_craft_type("rinsing", {
description = S("Rinsing"),
icon = "techage_appl_rinser_top.png^techage_frame_ta2_top.png",
width = 2,
height = 2,
})
function techage.add_rinser_recipe(recipe)
Probability[recipe.output] = recipe.probability
recipe.items = {recipe.input}
recipe.type = "rinsing"
techage.recipes.register_craft(recipe)
end
techage.add_rinser_recipe({input="techage:sieved_gravel", output="techage:usmium_nuggets", probability=30})
techage.add_rinser_recipe({input="techage:sieved_gravel", output="default:copper_lump", probability=15})

View File

@ -1,287 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Gravel Sieve, sieving gravel to find ores
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 4
local get_random_gravel_ore = techage.gravelsieve_get_random_gravel_ore
local get_random_basalt_ore = techage.gravelsieve_get_random_basalt_ore
local function formspec(self, pos, nvm)
return "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;3,3;]"..
"item_image[0,0;1,1;default:gravel]"..
"image[0,0;1,1;techage_form_mask.png]"..
"image[3.5,0;1,1;"..techage.get_power_image(pos, nvm).."]"..
"image[3.5,1;1,1;techage_form_arrow.png]"..
"image_button[3.5,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.5,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[context;dst;5,0;3,3;]"..
"list[current_player;main;0,4;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 4)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
CRD(pos).State:start_if_standby(pos)
return stack:get_count()
elseif listname == "dst" then
return 0
end
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local inv = M(pos):get_inventory()
local stack = inv:get_stack(from_list, from_index)
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function sieving(pos, crd, nvm, inv)
local src, dst
for i = 1, crd.num_items do
if inv:contains_item("src", ItemStack("techage:basalt_gravel")) then
dst, src = get_random_basalt_ore(), ItemStack("techage:basalt_gravel")
elseif inv:contains_item("src", ItemStack("default:gravel")) then
dst, src = get_random_gravel_ore(), ItemStack("default:gravel")
else
crd.State:idle(pos, nvm)
return
end
if not inv:room_for_item("dst", dst) then
crd.State:idle(pos, nvm)
return
end
inv:add_item("dst", dst)
inv:remove_item("src", src)
end
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
sieving(pos, crd, nvm, inv)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("dst") and inv:is_empty("src")
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
-- up, down, right, left, back, front
"techage_appl_sieve_top.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_sieve.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_sieve.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
{
name = "techage_appl_sieve4_top.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_sieve.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_sieve.png^techage_frame_ta#.png",
}
local tubing = {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "dst", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "src", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "dst", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("gravelsieve", S("Gravel Sieve"), tiles, {
drawtype = "nodebox",
paramtype = "light",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, 8/16, 8/16, -6/16},
{-8/16, -8/16, 6/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-6/16, -8/16, -6/16, 6/16, 4/16, 6/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size('src', 9)
inv:set_size('dst', 9)
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,2,4},
power_consumption = {0,3,4,5},
tube_sides = {L=1, R=1, U=1},
})
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"group:wood", "default:mese_crystal", "group:wood"},
{"techage:tubeS", "techage:sieve", "techage:tubeS"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
techage.recipes.register_craft_type("ta2_gravelsieve", {
description = S("TA2 Gravel Sieve"),
icon = 'techage_sieve_sieve_ta1.png',
width = 1,
height = 1,
})
techage.recipes.register_craft_type("ta3_gravelsieve", {
description = S("TA3 Gravel Sieve"),
icon = 'techage_filling_ta3.png^techage_appl_sieve.png^techage_frame_ta3.png',
width = 1,
height = 1,
})
techage.recipes.register_craft_type("ta4_gravelsieve", {
description = S("TA4 Gravel Sieve"),
icon = 'techage_filling_ta4.png^techage_appl_sieve.png^techage_frame_ta4.png',
width = 1,
height = 1,
})
techage.recipes.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta2_gravelsieve",
})
techage.recipes.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta3_gravelsieve",
})
techage.recipes.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta4_gravelsieve",
})

View File

@ -1,435 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Grinder, grinding Cobble/Basalt to Gravel
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer or {} end
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 4
-- Grinder recipes TA1
local RecipesTa1 = {}
-- Grinder recipes TA2 - TA4
local Recipes = {}
local function formspec(self, pos, nvm)
return "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;3,3;]"..
"item_image[0,0;1,1;default:cobble]"..
"image[0,0;1,1;techage_form_mask.png]"..
"image[3.5,0;1,1;"..techage.get_power_image(pos, nvm).."]"..
"image[3.5,1;1,1;techage_form_arrow.png]"..
"image_button[3.5,2;1,1;"..self:get_state_button_image(nvm)..";state_button;]"..
"tooltip[3.5,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[context;dst;5,0;3,3;]"..
"item_image[5,0;1,1;default:gravel]"..
"image[5,0;1,1;techage_form_mask.png]"..
"list[current_player;main;0,4;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 4)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
local state = CRD(pos).State
if state then
state:start_if_standby(pos)
end
end
return stack:get_count()
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local inv = M(pos):get_inventory()
local stack = inv:get_stack(from_list, from_index)
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
-- Grinder normaly handles 'num_items' per cycle. 'num_items' is node stage dependent.
-- But if 'inp_num' > 1 (wheat recipes), use 'inp_num' and produce one output item.
local function src_to_dst(src_stack, idx, src_name, num_items, inp_num, inv, dst_name)
if inp_num > 1 then
local input = ItemStack(src_name)
input:set_count(inp_num)
local output = ItemStack(dst_name)
if inv:contains_item("src", input) and inv:room_for_item("dst", output) then
inv:remove_item("src", input)
inv:add_item("dst", output)
return true
end
else
local taken = src_stack:take_item(num_items)
local output = ItemStack(dst_name)
output:set_count(output:get_count() * taken:get_count())
if inv:room_for_item("dst", output) then
inv:set_stack("src", idx, src_stack)
inv:add_item("dst", output)
return true
end
end
return false
end
local function grinding(pos, crd, nvm, inv)
local blocked = false -- idle
for idx,stack in ipairs(inv:get_list("src")) do
if not stack:is_empty() then
local name = stack:get_name()
if Recipes[name] then
local recipe = Recipes[name]
if src_to_dst(stack, idx, name, crd.num_items, recipe.inp_num, inv, recipe.output) then
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
else
blocked = true
end
else
crd.State:fault(pos, nvm)
return
end
end
end
if blocked then
crd.State:blocked(pos, nvm)
else
crd.State:idle(pos, nvm)
end
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
grinding(pos, crd, nvm, inv)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("dst") and inv:is_empty("src")
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
-- up, down, right, left, back, front
"techage_appl_grinder.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_grinder2.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_grinder2.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
{
name = "techage_appl_grinder4.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1.0,
},
},
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_grinder2.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_grinder2.png^techage_frame_ta#.png",
}
local tubing = {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "dst", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
--CRD(pos).State:start_if_standby(pos) -- would need power!
return techage.put_items(inv, "src", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "dst", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("grinder", S("Grinder"), tiles, {
drawtype = "nodebox",
paramtype = "light",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, 8/16, 8/16, -6/16},
{-8/16, -8/16, 6/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-6/16, -8/16, -6/16, 6/16, 6/16, 6/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size('src', 9)
inv:set_size('dst', 9)
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,2,4},
power_consumption = {0,4,6,9},
tube_sides = {L=1, R=1, U=1},
})
-------------------------------------------------------------------------------
-- TA1 Mill (watermill)
-------------------------------------------------------------------------------
local formspecStr = "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;1,1;1,1;]"..
"item_image[1,1;1,1;farming:wheat]"..
"image[1,1;1,1;techage_form_mask.png]"..
"image[3.5,1;1,1;techage_form_arrow.png]"..
"list[context;dst;6,1;1,1;]"..
"item_image[6,1;1,1;farming:flour]"..
"image[6,1;1,1;techage_form_mask.png]"..
"list[current_player;main;0,4;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 4)
local function node_timer(pos, elapsed)
if techage.ta1_mill_has_power(pos, 2) then
local inv = M(pos):get_inventory()
local stack = inv:get_stack("src", 1)
if not stack:is_empty() then
local name = stack:get_name()
if RecipesTa1[name] then
local recipe = RecipesTa1[name]
src_to_dst(stack, 1, name, 1, recipe.inp_num, inv, recipe.output)
end
end
end
return true
end
minetest.register_node("techage:ta1_mill_base", {
description = S("TA1 Mill Base"),
tiles = {
"techage_mill_base.png",
"default_stone_brick.png",
},
after_place_node = function(pos, placer)
M(pos):set_string("formspec", formspecStr)
local inv = M(pos):get_inventory()
inv:set_size('src', 1)
inv:set_size('dst', 1)
minetest.get_node_timer(pos):start(4)
end,
can_dig = can_dig,
on_timer = node_timer,
allow_metadata_inventory_put = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
is_ground_content = false,
groups = {cracky = 2, crumbly = 2, choppy = 2},
})
techage.register_node({"techage:ta1_mill_base"}, {
on_node_load = function(pos, node)
minetest.get_node_timer(pos):start(4)
end,
})
minetest.register_craft({
output = "techage:ta1_mill_base",
recipe = {
{"default:stonebrick", "", "default:stonebrick"},
{"", "techage:iron_ingot", ""},
{"default:stonebrick", "", "default:stonebrick"},
},
})
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"group:wood", "default:mese_crystal", "group:wood"},
{"techage:tubeS", "techage:hammer_steel", "techage:tubeS"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
techage.recipes.register_craft_type("grinding", {
description = S("Grinding"),
icon = 'techage_appl_grinder.png',
width = 2,
height = 2,
})
techage.recipes.register_craft_type("milling", {
description = S("Milling"),
icon = 'techage_mill_inv.png',
width = 2,
height = 2,
})
function techage.add_grinder_recipe(recipe, ta1_permitted)
local name, num = unpack(string.split(recipe.input, " ", false, 1))
if minetest.registered_items[name] then
if ta1_permitted then
RecipesTa1[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output}
recipe.items = {recipe.input}
recipe.type = "milling"
techage.recipes.register_craft(table.copy(recipe))
end
Recipes[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output}
recipe.items = {recipe.input}
recipe.type = "grinding"
techage.recipes.register_craft(recipe)
end
end
techage.add_grinder_recipe({input="default:cobble", output="default:gravel"})
techage.add_grinder_recipe({input="default:desert_cobble", output="default:gravel"})
techage.add_grinder_recipe({input="default:mossycobble", output="default:gravel"})
techage.add_grinder_recipe({input="default:gravel", output="default:sand"})
techage.add_grinder_recipe({input="techage:sieved_gravel", output="default:sand"})
techage.add_grinder_recipe({input="default:coral_skeleton", output="default:silver_sand"})
if minetest.global_exists("skytest") then
techage.add_grinder_recipe({input="default:desert_sand", output="skytest:dust"})
techage.add_grinder_recipe({input="default:silver_sand", output="skytest:dust"})
techage.add_grinder_recipe({input="default:sand", output="skytest:dust"})
else
techage.add_grinder_recipe({input="default:desert_sand", output="default:clay"})
techage.add_grinder_recipe({input="default:silver_sand", output="default:clay"})
techage.add_grinder_recipe({input="default:sand", output="default:clay"})
end
techage.add_grinder_recipe({input="default:sandstone", output="default:sand 4"})
techage.add_grinder_recipe({input="default:desert_sandstone", output="default:desert_sand 4"})
techage.add_grinder_recipe({input="default:silver_sandstone", output="default:silver_sand 4"})
techage.add_grinder_recipe({input="default:tree", output="default:leaves 8"})
techage.add_grinder_recipe({input="default:jungletree", output="default:jungleleaves 8"})
techage.add_grinder_recipe({input="default:pine_tree", output="default:pine_needles 8"})
techage.add_grinder_recipe({input="default:acacia_tree", output="default:acacia_leaves 8"})
techage.add_grinder_recipe({input="default:aspen_tree", output="default:aspen_leaves 8"})
if minetest.global_exists("farming") then
techage.add_grinder_recipe({input="farming:wheat 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_wheat 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:barley 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_barley 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:rye 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_rye 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:rice 3", output="farming:rice_flour"}, true)
techage.add_grinder_recipe({input="farming:seed_rice 6", output="farming:rice_flour"}, true)
techage.add_grinder_recipe({input="farming:oat 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_oat 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_cotton 3", output="basic_materials:oil_extract"}, true)
end

View File

@ -1,106 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Item Source Block
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local CYCLE_TIME = 30
local function formspec()
return "size[8,7.2]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;main;3.5,0.8;1,1;]"..
"list[current_player;main;0,3.5;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
minetest.register_node("techage:itemsource", {
description = "Techage Item Source",
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_outp.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_nodedetector.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_nodedetector.png^techage_frame_ta3.png",
},
after_place_node = function(pos, placer)
local meta = M(pos)
local node = minetest.get_node(pos)
meta:set_int("push_dir", techage.side_to_outdir("R", node.param2))
local inv = meta:get_inventory()
inv:set_size('main', 1)
minetest.get_node_timer(pos):start(CYCLE_TIME)
meta:set_string("infotext", "Techage Item Source")
meta:set_string("formspec", formspec())
end,
on_timer = function(pos, elapsed)
local meta = M(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack('main', 1)
if stack:get_count() > 0 then
local push_dir = meta:get_int("push_dir")
local leftover = techage.push_items(pos, push_dir, stack)
local pushed
if not leftover then
pushed = 0
elseif leftover ~= true then
pushed = stack:get_count() - leftover:get_count()
else -- leftover == true
pushed = stack:get_count()
end
meta:set_int("counter", pushed)
meta:set_string("infotext", "Techage Item Source: "..pushed)
end
return true
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
is_ground_content = false,
drop = "",
groups = {crumbly = 3, cracky = 3, snappy = 3},
sounds = default.node_sound_glass_defaults(),
})
techage.register_node({"techage:itemsource"}, {
on_node_load = function(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})

View File

@ -1,228 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3 Bucket based Liquid Sampler
]]--
-- for lazy programmers
local M = minetest.get_meta
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local S = techage.S
local STANDBY_TICKS = 2
local COUNTDOWN_TICKS = 3
local CYCLE_TIME = 8
local function formspec(self, pos, nvm)
return "size[9,8.5]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;1,4;]"..
"image[0,0;1,1;bucket.png]"..
"image[1,0;1,1;"..techage.get_power_image(pos, nvm).."]"..
"image[1,1.5;1,1;techage_form_arrow.png]"..
"image_button[1,3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[1,3;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[context;dst;2,0;7,4;]"..
"list[current_player;main;0.5,4.5;8,4;]"..
"listring[current_player;main]"..
"listring[context;src]" ..
"listring[current_player;main]"..
"listring[context;dst]" ..
"listring[current_player;main]"
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
CRD(pos).State:start_if_standby(pos)
end
return stack:get_count()
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local inv = M(pos):get_inventory()
local stack = inv:get_stack(from_list, from_index)
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function is_water(pos)
local node = minetest.get_node(pos)
local liquiddef = bucket.liquids[node.name]
if liquiddef ~= nil and liquiddef.itemname ~= nil and node.name == liquiddef.source then
return true
end
end
local function can_start(pos, nvm, state)
local water_pos = minetest.string_to_pos(M(pos):get_string("water_pos"))
if not is_water(water_pos) then
return S("no usable water")
end
return true
end
local function sample_liquid(pos, crd, nvm, inv)
if inv:room_for_item("dst", {name = "bucket:bucket_water"}) and
inv:contains_item("src", {name = "bucket:bucket_empty"}) then
inv:remove_item("src", {name = "bucket:bucket_empty"})
inv:add_item("dst", {name = "bucket:bucket_water"})
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
else
crd.State:idle(pos, nvm)
end
end
local function keep_running(pos, elapsed)
--if tubelib.data_not_corrupted(pos) then
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
sample_liquid(pos, crd, nvm, inv)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("dst") and inv:is_empty("src")
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^{power}^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_liquidsampler.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_liquidsampler.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^{power}^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
name = "techage_filling4_ta#.png^techage_liquidsampler4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1.0,
},
},
"techage_filling_ta#.png^techage_appl_liquidsampler.png^techage_frame_ta#.png",
}
local tubing = {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "dst", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "src", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "dst", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
}
local node_name_ta2, node_name_ta3, _ =
techage.register_consumer("liquidsampler", S("Liquid Sampler"), tiles, {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
can_start = can_start,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size("src", 4)
inv:set_size("dst", 28)
local water_pos = techage.get_pos(pos, "B")
M(pos):set_string("water_pos", minetest.pos_to_string(water_pos))
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,2,4},
power_consumption = {0,3,5,8},
power_sides = {U=1},
},
{false, true, true, false}) -- TA2/A3
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"group:wood", "default:mese_crystal", "group:wood"},
{"techage:tubeS", "bucket:bucket_empty", "techage:tubeS"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})

View File

@ -1,131 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Tube support for digtron and protector chests
]]--
-- for lazy programmers
local M = minetest.get_meta
local CacheForFuelNodeNames = {}
local function is_fuel(stack)
local name = stack:get_name()
if CacheForFuelNodeNames[name] then
return true
end
if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
CacheForFuelNodeNames[name] = true
end
return CacheForFuelNodeNames[name]
end
------------------------------------------------------------------------------
-- digtron
------------------------------------------------------------------------------
techage.register_node({"digtron:inventory"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
techage.register_node({"digtron:fuelstore"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "fuel"
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "fuel", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "fuel", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "fuel", stack)
end,
})
techage.register_node({"digtron:combined_storage"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, side, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
minetest.get_node_timer(pos):start(1.0)
if is_fuel(stack) then
return techage.put_items(inv, "fuel", stack)
else
return techage.put_items(inv, "main", stack)
end
end,
on_unpull_item = function(pos, side, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
------------------------------------------------------------------------------
-- protector
------------------------------------------------------------------------------
techage.register_node({"protector:chest"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})

View File

@ -1,438 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Pusher
Nodes for push/pull operation of StackItems from chests or other
inventory/server nodes to tubes or other inventory/server nodes.
+--------+
/ /|
+--------+ |
IN (L) -->| |X--> OUT (R)
| PUSHER | +
| |/
+--------+
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local Tube = techage.Tube
local STANDBY_TICKS = 2
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 2
local WRENCH_MENU = {
{
type = "number",
name = "limit",
label = S("Number of items"),
tooltip = S("Number of items that are allowed to be pushed"),
default = "0",
},
}
local function ta4_formspec(self, pos, nvm)
if CRD(pos).stage == 4 then -- TA4 node?
return "size[8,7.2]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3,-0.1;"..minetest.colorize("#000000", S("Pusher")).."]"..
techage.question_mark_help(7.5, S("Optionally configure\nthe pusher with one item"))..
techage.wrench_image(7.4, -0.05) ..
"list[context;main;3.5,0.8;1,1;]"..
"image_button[3.5,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.5,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[current_player;main;0,3.5;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
if list[index]:get_count() == 0 then
stack:set_count(1)
inv:set_stack(listname, index, stack)
return 0
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
inv:set_stack(listname, index, nil)
return 0
end
local function set_limit(pos, nvm, val)
val = tonumber(val) or 0
if val > 0 then
nvm.limit = val
nvm.num_items = 0
M(pos):set_int("limit", val)
else
nvm.limit = nil
nvm.num_items = nil
M(pos):set_string("limit", "")
end
end
-- Function returns the number of pushed items
local function push(pos, crd, meta, nvm, pull_dir, push_dir, num)
local items = techage.pull_items(pos, pull_dir, num, nvm.item_name)
if items ~= nil then
local taken = items:get_count()
local leftover = techage.push_items(pos, push_dir, items)
if not leftover then
-- place item back
techage.unpull_items(pos, pull_dir, items)
crd.State:blocked(pos, nvm)
return 0
elseif leftover ~= true then
-- place item back
taken = taken - leftover:get_count()
techage.unpull_items(pos, pull_dir, leftover)
crd.State:blocked(pos, nvm)
return taken
end
return taken
end
crd.State:idle(pos, nvm)
return 0
end
local function pushing(pos, crd, meta, nvm)
local pull_dir = meta:get_int("pull_dir")
local push_dir = meta:get_int("push_dir")
if not nvm.limit then
local num = nvm.item_count or nvm.num_items or crd.num_items
num = push(pos, crd, meta, nvm, pull_dir, push_dir, num)
if num > 0 then
if nvm.item_count then
nvm.item_count = nvm.item_count - num
if nvm.item_count <= 0 then
crd.State:stop(pos, nvm)
nvm.item_count = nil
end
end
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
elseif nvm.num_items < nvm.limit then
local num = math.min(crd.num_items, nvm.limit - nvm.num_items)
num = push(pos, crd, meta, nvm, pull_dir, push_dir, num)
if num > 0 then
nvm.num_items = nvm.num_items + num
if nvm.num_items >= nvm.limit then
crd.State:stop(pos, nvm)
else
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
end
end
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
pushing(pos, crd, M(pos), nvm)
crd.State:is_active(nvm)
end
local function on_rightclick(pos, node, clicker)
if CRD(pos).stage ~= 4 then -- Not TA4 node?
local nvm = techage.get_nvm(pos)
if not minetest.is_protected(pos, clicker:get_player_name()) then
if CRD(pos).State:get_state(nvm) == techage.STOPPED then
CRD(pos).State:start(pos, nvm)
else
CRD(pos).State:stop(pos, nvm)
end
end
end
end
local function on_receive_fields(pos, formname, fields, player)
if CRD(pos).stage == 4 then -- TA4 node?
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", ta4_formspec(CRD(pos).State, pos, nvm))
end
end
local function tubelib2_on_update2(pos, outdir, tlib2, node)
local pull_dir = M(pos):get_int("pull_dir")
local push_dir = M(pos):get_int("push_dir")
local is_ta4_tube = true
for i, pos, node in Tube:get_tube_line(pos, pull_dir) do
is_ta4_tube = is_ta4_tube and techage.TA4tubes[node.name]
end
for i, pos, node in Tube:get_tube_line(pos, push_dir) do
is_ta4_tube = is_ta4_tube and techage.TA4tubes[node.name]
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
if CRD(pos).stage == 4 and not is_ta4_tube then
nvm.num_items = crd.num_items / 2
else
nvm.num_items = crd.num_items
end
end
local function can_start(pos, nvm, state)
if CRD(pos).stage == 4 then -- TA4 node?
local inv = M(pos):get_inventory()
local name = inv:get_stack("main", 1):get_name()
if name ~= "" then
nvm.item_name = name
else
nvm.item_name = nil
end
else
nvm.item_name = nil
end
return true
end
local function ta_after_formspec(pos, fields, playername)
local nvm = techage.get_nvm(pos)
set_limit(pos, nvm, fields.limit)
end
local function on_state_change(pos, old_state, new_state)
if old_state == techage.STOPPED and new_state == techage.RUNNING then
local nvm = techage.get_nvm(pos)
set_limit(pos, nvm, M(pos):get_int("limit"))
end
end
local function config_item(pos, payload)
if type(payload) == "string" then
if payload == "" then
local inv = M(pos):get_inventory()
inv:set_stack("main", 1, nil)
return 0
else
local name, count = unpack(payload:split(" "))
if name and (minetest.registered_nodes[name] or minetest.registered_items[name]
or minetest.registered_craftitems[name]) then
count = tonumber(count) or 1
local inv = M(pos):get_inventory()
inv:set_stack("main", 1, {name = name, count = 1})
return count
end
end
end
return 0
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#_bottom.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_appl_pusher.png^[transformR180]^techage_frame_ta#.png",
"techage_appl_pusher.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#_bottom.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
name = "techage_appl_pusher14.png^[transformR180]^techage_frame14_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
{
name = "techage_appl_pusher14.png^techage_frame14_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
}
local tubing = {
-- push item through the pusher in opposit direction
on_push_item = function(pos, in_dir, stack)
return in_dir == M(pos):get_int("pull_dir") and techage.safe_push_items(pos, in_dir, stack)
end,
is_pusher = true, -- is a pulling/pushing node
on_recv_message = function(pos, src, topic, payload)
if topic == "pull" then -- Deprecated command, use config/limit/start instead
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
nvm.item_count = math.min(config_item(pos, payload), 12)
nvm.rmt_num = src
CRD(pos).State:start(pos, nvm)
return true
elseif topic == "config" then -- Set item type
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
config_item(pos, payload)
return true
elseif topic == "limit" then -- Set push limit
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
set_limit(pos, nvm, payload)
return true
elseif topic == "count" then -- Get number of push items
local nvm = techage.get_nvm(pos)
return nvm.num_items or 0
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 65 then -- Set item type
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
config_item(pos, payload)
return 0
elseif topic == 68 or topic == 20 then -- Set push limit
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
set_limit(pos, nvm, payload[1])
return 0
else
local nvm = techage.get_nvm(pos)
if nvm.limit then
nvm.num_items = 0
end
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 150 then -- Get number of pushed items
local nvm = techage.get_nvm(pos)
return 0, {nvm.num_items or 0}
else
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("pusher", S("Pusher"), tiles, {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = ta4_formspec,
tubing = tubing,
can_start = can_start,
on_state_change = on_state_change,
after_place_node = function(pos, placer)
local meta = M(pos)
local node = minetest.get_node(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", node.param2))
meta:set_int("push_dir", techage.side_to_outdir("R", node.param2))
if CRD(pos).stage == 4 then -- TA4 node?
local inv = M(pos):get_inventory()
inv:set_size('main', 1)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", ta4_formspec(CRD(pos).State, pos, nvm))
end
end,
ta_rotate_node = function(pos, node, new_param2)
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
local meta = M(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", new_param2))
meta:set_int("push_dir", techage.side_to_outdir("R", new_param2))
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
on_rightclick = on_rightclick,
on_receive_fields = on_receive_fields,
node_timer = keep_running,
on_rotate = screwdriver.disallow,
tubelib2_on_update2 = tubelib2_on_update2,
ta4_formspec = WRENCH_MENU,
ta_after_formspec = ta_after_formspec,
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
num_items = {0,2,6,12},
tube_sides = {L=1, R=1},
})
minetest.register_craft({
output = node_name_ta2.." 2",
recipe = {
{"group:wood", "wool:dark_green", "group:wood"},
{"techage:tubeS", "default:mese_crystal", "techage:tubeS"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "techage:iron_ingot", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "techage:iron_ingot", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})

View File

@ -1,457 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Quarry machine to dig stones and other ground blocks.
The Quarry digs a hole (default) 5x5 blocks large and up to 80 blocks deep.
It starts at the given level (0 is same level as the quarry block,
1 is one level higher and so on)) and goes down to the given depth number.
It digs one block every 4 seconds.
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local M = minetest.get_meta
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local S = techage.S
local CYCLE_TIME = 4
local STANDBY_TICKS = 4
local COUNTDOWN_TICKS = 4
local Side2Facedir = {F=0, R=1, B=2, L=3, D=4, U=5}
local Depth2Idx = {[1]=1 ,[2]=2, [3]=3, [5]=4, [7]=5, [10]=6, [15]=7, [20]=8, [25]=9, [40]=10, [60]=11, [80]=12}
local Holesize2Idx = {["3x3"] = 1, ["5x5"] = 2, ["7x7"] = 3, ["9x9"] = 4, ["11x11"] = 5}
local Holesize2Diameter = {["3x3"] = 3, ["5x5"] = 5, ["7x7"] = 7, ["9x9"] = 9, ["11x11"] = 11}
local Level2Idx = {[2]=1, [1]=2, [0]=3, [-1]=4, [-2]=5, [-3]=6,
[-5]=7, [-10]=8, [-15]=9, [-20]=10}
local function formspec(self, pos, nvm)
local tooltip = S("Start level = 0\nmeans the same level\nas the quarry is placed")
local level_idx = Level2Idx[nvm.start_level or 1] or 2
local depth_idx = Depth2Idx[nvm.quarry_depth or 1] or 1
local hsize_idx = Holesize2Idx[nvm.hole_size or "5x5"] or 2
local level = nvm.level or "-"
local hsize_list = "5x5"
if CRD(pos).stage == 4 then
hsize_list = "3x3,5x5,7x7,9x9,11x11"
elseif CRD(pos).stage == 3 then
hsize_list = "3x3,5x5,7x7"
end
local depth_list = "1,2,3,5,7,10,15,20,25,40,60,80"
if CRD(pos).stage == 3 then
depth_list = "1,2,3,5,7,10,15,20,25,40"
elseif CRD(pos).stage == 2 then
depth_list = "1,2,3,5,7,10,15,20"
end
return "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3.5,-0.1;"..minetest.colorize( "#000000", S("Quarry")).."]"..
techage.question_mark_help(8, tooltip)..
"dropdown[0,0.8;1.5;level;2,1,0,-1,-2,-3,-5,-10,-15,-20;"..level_idx.."]"..
"label[1.6,0.9;"..S("Start level").."]"..
"dropdown[0,1.8;1.5;depth;"..depth_list..";"..depth_idx.."]"..
"label[1.6,1.9;"..S("Digging depth").." ("..level..")]"..
"dropdown[0,2.8;1.5;hole_size;"..hsize_list..";"..hsize_idx.."]"..
"label[1.6,2.9;"..S("Hole size").."]"..
"list[context;main;5,0.8;3,3;]"..
"image[4,0.8;1,1;"..techage.get_power_image(pos, nvm).."]"..
"image_button[4,2.8;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[4,2.8;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[current_player;main;0,4.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function play_sound(pos)
local mem = techage.get_mem(pos)
if not mem.handle or mem.handle == -1 then
mem.handle = minetest.sound_play("techage_quarry", {
pos = pos,
gain = 1.5,
max_hear_distance = 15,
loop = true})
if mem.handle == -1 then
minetest.after(1, play_sound, pos)
end
end
end
local function stop_sound(pos)
local mem = techage.get_mem(pos)
if mem.handle then
minetest.sound_stop(mem.handle)
mem.handle = nil
end
end
local function on_node_state_change(pos, old_state, new_state)
local mem = techage.get_mem(pos)
local owner = M(pos):get_string("owner")
mem.co = nil
techage.unmark_position(owner)
if new_state == techage.RUNNING then
play_sound(pos)
else
stop_sound(pos)
end
end
local function get_pos(pos, facedir, side, steps)
facedir = (facedir + Side2Facedir[side]) % 4
local dir = vector.multiply(minetest.facedir_to_dir(facedir), steps or 1)
return vector.add(pos, dir)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function get_quarry_pos(pos, xoffs, zoffs)
return {x = pos.x + xoffs - 1, y = pos.y, z = pos.z + zoffs - 1}
end
-- pos is the quarry pos
local function get_corner_positions(pos, facedir, hole_diameter)
local _pos = get_pos(pos, facedir, "L")
local pos1 = get_pos(_pos, facedir, "F", math.floor((hole_diameter - 1) / 2))
local pos2 = get_pos(_pos, facedir, "B", math.floor((hole_diameter - 1) / 2))
pos2 = get_pos(pos2, facedir, "L", hole_diameter - 1)
if pos1.x > pos2.x then pos1.x, pos2.x = pos2.x, pos1.x end
if pos1.y > pos2.y then pos1.y, pos2.y = pos2.y, pos1.y end
if pos1.z > pos2.z then pos1.z, pos2.z = pos2.z, pos1.z end
return pos1, pos2
end
local function is_air_level(pos1, pos2, hole_diameter)
return #minetest.find_nodes_in_area(pos1, pos2, {"air"}) == hole_diameter * hole_diameter
end
local function mark_area(pos1, pos2, owner)
pos1.y = pos1.y + 0.2
techage.mark_cube(owner, pos1, pos2, "quarry", "#FF0000", 20)
pos1.y = pos1.y - 0.2
end
local function quarry_task(pos, crd, nvm)
nvm.start_level = nvm.start_level or 0
nvm.quarry_depth = nvm.quarry_depth or 1
nvm.hole_diameter = nvm.hole_diameter or 5
local y_first = pos.y + nvm.start_level
local y_last = y_first - nvm.quarry_depth + 1
local facedir = minetest.get_node(pos).param2
local owner = M(pos):get_string("owner")
local fake_player = techage.Fake_player:new()
fake_player.get_pos = function (...)
return pos
end
fake_player.get_inventory = function(...)
return M(pos):get_inventory()
end
local add_to_inv = function(itemstacks)
local at_least_one_added = false
local inv = M(pos):get_inventory()
if #itemstacks == 0 then
return true
end
for _,stack in ipairs(itemstacks) do
if inv:room_for_item("main", stack) then
inv:add_item("main", stack)
at_least_one_added = true
elseif at_least_one_added then
minetest.add_item({x=pos.x,y=pos.y+1,z=pos.z}, stack)
end
end
return at_least_one_added
end
local pos1, pos2 = get_corner_positions(pos, facedir, nvm.hole_diameter)
nvm.level = 1
for y_curr = y_first, y_last, -1 do
pos1.y = y_curr
pos2.y = y_curr
-- Restarting the server can detach the coroutine data.
-- Therefore, read nvm again.
nvm = techage.get_nvm(pos)
nvm.level = y_first - y_curr
if minetest.is_area_protected(pos1, pos2, owner, 5) then
crd.State:fault(pos, nvm, S("area is protected"))
return
end
if not is_air_level(pos1, pos2, nvm.hole_diameter) then
mark_area(pos1, pos2, owner)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
coroutine.yield()
for zoffs = 1, nvm.hole_diameter do
for xoffs = 1, nvm.hole_diameter do
local qpos = get_quarry_pos(pos1, xoffs, zoffs)
local dig_state = techage.dig_like_player(qpos, fake_player, add_to_inv)
if dig_state == techage.dig_states.INV_FULL then
crd.State:blocked(pos, nvm, S("inventory full"))
coroutine.yield()
elseif dig_state == techage.dig_states.DUG then
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
coroutine.yield()
end
end
end
techage.unmark_position(owner)
end
end
crd.State:stop(pos, nvm, S("finished"))
end
local function keep_running(pos, elapsed)
local mem = techage.get_mem(pos)
if not mem.co then
mem.co = coroutine.create(quarry_task)
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local _, err = coroutine.resume(mem.co, pos, crd, nvm)
if err then
minetest.log("error", "[TA4 Quarry Coroutine Error] at pos " .. minetest.pos_to_string(pos) .. " " .. err)
end
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(crd.State, pos, nvm))
end
if nvm.techage_state ~= techage.RUNNING then
stop_sound(pos)
end
end
local function on_rightclick(pos, node, clicker)
local nvm = techage.get_nvm(pos)
techage.set_activeformspec(pos, clicker)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("main")
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
if fields.depth then
if tonumber(fields.depth) ~= nvm.quarry_depth then
nvm.quarry_depth = tonumber(fields.depth)
if CRD(pos).stage == 2 then
nvm.quarry_depth = math.min(nvm.quarry_depth, 20)
elseif CRD(pos).stage == 3 then
nvm.quarry_depth = math.min(nvm.quarry_depth, 40)
end
mem.co = nil
CRD(pos).State:stop(pos, nvm)
end
end
if fields.level then
if tonumber(fields.level) ~= nvm.start_level then
nvm.start_level = tonumber(fields.level)
mem.co = nil
CRD(pos).State:stop(pos, nvm)
end
end
if fields.hole_size then
if CRD(pos).stage == 4 then
if fields.hole_size ~= nvm.hole_size then
nvm.hole_size = fields.hole_size
nvm.hole_diameter = Holesize2Diameter[fields.hole_size or "5x5"] or 5
mem.co = nil
CRD(pos).State:stop(pos, nvm)
end
elseif CRD(pos).stage == 3 then
if fields.hole_size ~= nvm.hole_size then
nvm.hole_size = fields.hole_size
nvm.hole_diameter = Holesize2Diameter[fields.hole_size or "7x7"] or 7
mem.co = nil
CRD(pos).State:stop(pos, nvm)
end
else
nvm.hole_size = "5x5"
nvm.hole_diameter = 5
end
end
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local tiles = {}
-- '#' will be replaced by the stage number
tiles.pas = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_quarry_left.png",
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
{
name = "techage_frame14_ta#.png^techage_quarry_left14.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
}
local tubing = {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "main", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
--CRD(pos).State:start_if_standby(pos) -- would need power!
return techage.put_items(inv, "main", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "main", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "depth" then
local nvm = techage.get_nvm(pos)
return nvm.level or 0
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 133 then -- Quarry Depth
local nvm = techage.get_nvm(pos)
return 0, {nvm.level or 0}
else
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
local nvm = techage.get_nvm(pos)
if nvm.techage_state == techage.RUNNING then
stop_sound(pos)
play_sound(pos)
end
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("quarry", S("Quarry"), tiles, {
drawtype = "normal",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
on_state_change = on_node_state_change,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
local nvm = techage.get_nvm(pos)
inv:set_size('main', 9)
M(pos):set_string("owner", placer:get_player_name())
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,1,1},
power_consumption = {0,10,12,14},
}
)
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"group:wood", "default:mese_crystal", "group:wood"},
{"techage:tubeS", "default:pick_diamond", "techage:iron_ingot"},
{"group:wood", "techage:iron_ingot", "group:wood"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})

View File

@ -1,243 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Recipe Block for the TA4 Autocrafter
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
local MAX_RECIPE = 10
local function recipes_formspec(x, y, idx)
return "container[" .. x .. "," .. y .. "]" ..
"background[0,0;8,3.2;techage_form_grey.png]" ..
"list[context;input;0.1,0.1;3,3;]" ..
"image[3,1.1;1,1;techage_form_arrow.png]" ..
"list[context;output;3.9,1.1;1,1;]" ..
"button[5.5,1.1;1,1;priv;<<]" ..
"button[6.5,1.1;1,1;next;>>]" ..
"label[5.5,0.5;"..S("Recipe") .. ": " .. idx .. "/" .. MAX_RECIPE .. "]" ..
"container_end[]"
end
local function formspec(pos, nvm)
return "size[8,7.4]"..
recipes_formspec(0, 0, nvm.recipe_idx or 1) ..
"list[current_player;main;0,3.6;8,4;]" ..
"listring[current_player;main]"..
"listring[context;src]" ..
"listring[current_player;main]"..
"listring[context;dst]" ..
"listring[current_player;main]"
end
local function determine_new_input(pos, inv)
local output = inv:get_stack("output", 1):get_name()
if output and output ~= "" then
local recipe = minetest.get_craft_recipe(output)
if recipe.items and recipe.type == "normal" then
for i = 1, 9 do
local name = recipe.items[i]
if name then
if minetest.registered_items[name] then
inv:set_stack("input", i, name)
end
end
end
inv:set_stack("output", 1, recipe.output)
end
else
for i = 1, 9 do
inv:set_stack("input", i, nil)
end
end
end
local function determine_new_output(pos, inv)
local items = {}
for i = 1, 9 do
items[i] = inv:get_stack("input", i):get_name()
end
local input = {
method = "normal",
width = 3,
items = items,
}
local output, _ = minetest.get_craft_result(input)
inv:set_stack("output", 1, output.item)
end
local function get_recipe(inv)
local items = {}
local last_idx = 0
for i = 1, 9 do
local name = inv:get_stack("input", i):get_name()
if name ~= "" then
last_idx = i
end
items[i] = name
end
local input = table.concat(items, ",", 1, last_idx)
local stack = inv:get_stack("output", 1)
return {
input = input,
output = stack:get_name() .. " " .. stack:get_count()
}
end
local function after_recipe_change(pos, inv, listname)
if listname == "input" then
determine_new_output(pos, inv)
else
determine_new_input(pos, inv)
end
local nvm = techage.get_nvm(pos)
nvm.recipes = nvm.recipes or {}
nvm.recipes[nvm.recipe_idx or 1] = get_recipe(inv)
end
local function update_inventor(pos, inv, idx)
local nvm = techage.get_nvm(pos)
nvm.recipes = nvm.recipes or {}
local recipe = nvm.recipes[idx]
if recipe then
local items = string.split(recipe.input, ",", true)
for i = 1, 9 do
inv:set_stack("input", i, items[i] or "")
end
inv:set_stack("output", 1, recipe.output)
else
for i = 1, 9 do
inv:set_stack("input", i, nil)
end
inv:set_stack("output", 1, nil)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
stack:set_count(1)
inv:set_stack(listname, index, stack)
after_recipe_change(pos, inv, listname)
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = M(pos):get_inventory()
inv:set_stack(listname, index, nil)
after_recipe_change(pos, inv, listname)
return 0
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = M(pos):get_inventory()
if from_list == to_list then
minetest.after(0.1, after_recipe_change, pos, inv, from_list)
return 1
end
return 0
end
minetest.register_node("techage:ta4_recipeblock", {
description = S("TA4 Recipe Block"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_recipeblock.png",
},
on_construct = function(pos)
local inv = M(pos):get_inventory()
inv:set_size('input', 9)
inv:set_size('output', 1)
end,
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
local number = techage.add_node(pos, "techage:ta4_chest")
M(pos):set_string("owner", placer:get_player_name())
M(pos):set_string("node_number", number)
M(pos):set_string("formspec", formspec(pos, nvm))
M(pos):set_string("infotext", S("TA4 Recipe Block") .. " " .. number)
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
nvm.recipe_idx = nvm.recipe_idx or 1
if fields.next == ">>" then
nvm.recipe_idx = techage.in_range(nvm.recipe_idx + 1, 1, MAX_RECIPE)
elseif fields.priv == "<<" then
nvm.recipe_idx = techage.in_range(nvm.recipe_idx - 1, 1, MAX_RECIPE)
end
local inv = M(pos):get_inventory()
update_inventor(pos, inv, nvm.recipe_idx or 1)
M(pos):set_string("formspec", formspec(pos, nvm))
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta4_recipeblock"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "input" and payload and payload ~= "" then
nvm.recipes = nvm.recipes or {}
local recipe = nvm.recipes[tonumber(payload) or 1]
if recipe then
return recipe.input
end
else
return "unsupported"
end
end,
})
minetest.register_craft({
output = "techage:ta4_recipeblock",
recipe = {
{"techage:ta4_carbon_fiber", "dye:blue", "techage:aluminum"},
{"", "basic_materials:ic", ""},
{"default:steel_ingot", "techage:ta4_wlanchip", "default:steel_ingot"},
},
})

View File

@ -1,358 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Recycler, recycling techage machines
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 8
local Recipes = {}
local SpecialItems = {
["techage:sieved_gravel"] = "default:sand",
["basic_materials:heating_element"] = "default:copper_ingot",
["techage:ta4_wlanchip"] = "",
["techage:basalt_cobble"] = "default:sand",
["default:stone"] = "techage:sieved_gravel",
["default:wood"] = "default:stick 5",
["basic_materials:concrete_block"] = "techage:sieved_gravel",
["dye:green"] = "",
["dye:red"] = "",
["dye:white"] = "",
["dye:blue"] = "",
["dye:brown"] = "",
["dye:cyan"] = "",
["dye:yellow"] = "",
["dye:grey"] = "",
["dye:orange"] = "",
["dye:black"] = "",
["techage:basalt_glass_thin"] = "",
["group:stone"] = "techage:sieved_gravel",
--["basic_materials:plastic_sheet"] = "",
["group:wood"] = "default:stick 5",
["techage:basalt_glass"] = "",
["default:junglewood"] = "default:stick 5",
["techage:ta4_silicon_wafer"] = "",
["default:cobble"] = "techage:sieved_gravel",
["default:pick_diamond"] = "default:stick",
["techage:hammer_steel"] = "default:stick",
["default:paper"] = "",
["stairs:slab_basalt_glass2"] = "",
["techage:basalt_stone"] = "techage:sieved_gravel",
["techage:ta4_ramchip"] = "",
["protector:chest"] = "default:chest",
["techage:ta4_rotor_blade"] = "",
["techage:ta4_carbon_fiber"] = "",
["techage:ta4_round_ceramic"] = "",
["techage:ta4_furnace_ceramic"] = "",
["techage:ta5_aichip"] = "",
["techage:ta4_leds"] = "",
}
local function formspec(self, pos, nvm)
return "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;3,3;]"..
--"item_image[0,0;1,1;default:cobble]"..
"image[0,0;1,1;techage_form_mask.png]"..
"image[3.5,0;1,1;"..techage.get_power_image(pos, nvm).."]"..
"image[3.5,1;1,1;techage_form_arrow.png]"..
"image_button[3.5,2;1,1;"..self:get_state_button_image(nvm)..";state_button;]"..
"tooltip[3.5,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[context;dst;5,0;3,3;]"..
--"item_image[5,0;1,1;default:gravel]"..
"image[5,0;1,1;techage_form_mask.png]"..
"list[current_player;main;0,4;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 4)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
CRD(pos).State:start_if_standby(pos)
end
return stack:get_count()
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local inv = M(pos):get_inventory()
local stack = inv:get_stack(from_list, from_index)
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function cook_reverse(stack, inv, idx, recipe)
-- check space
for _,item in ipairs(recipe.items) do
if not inv:room_for_item("dst", item) then
return false
end
end
-- take item
inv:remove_item("src", ItemStack(recipe.output))
-- add items
for _,item in ipairs(recipe.items) do
inv:add_item("dst", item)
end
return true
end
local function get_recipe(stack)
local name = stack:get_name()
local recipe = Recipes[name]
if recipe then
if stack:get_count() >= ItemStack(recipe.output):get_count() then
return recipe
end
end
end
local function recycling(pos, crd, nvm, inv)
for idx,stack in ipairs(inv:get_list("src")) do
local recipe = not stack:is_empty() and get_recipe(stack)
if recipe then
if cook_reverse(stack, inv, idx, recipe) then
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
else
crd.State:blocked(pos, nvm)
end
return
end
end
crd.State:idle(pos, nvm)
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
recycling(pos, crd, nvm, inv)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("dst") and inv:is_empty("src")
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
-- up, down, right, left, back, front
"techage_appl_grinder.png^[colorize:@@000000:100^techage_frame_ta#_top.png",
--"techage_appl_grinder.png^techage_frame_ta#_top.png^[multiply:#FF0000",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_recycler.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_recycler.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
{
name = "techage_appl_grinder4.png^[colorize:@@000000:100^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1.0,
},
},
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_recycler.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_recycler.png^techage_frame_ta#.png",
}
local tubing = {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(pos, inv, "dst", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
--CRD(pos).State:start_if_standby(pos) -- would need power!
return techage.put_items(inv, "src", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "dst", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local _, _, node_name_ta4 =
techage.register_consumer("recycler", S("Recycler"), tiles, {
drawtype = "nodebox",
paramtype = "light",
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, 8/16, 8/16, -6/16},
{-8/16, -8/16, 6/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-6/16, -8/16, -6/16, 6/16, 6/16, 6/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size('src', 9)
inv:set_size('dst', 9)
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,0,0,1},
power_consumption = {0,0,0,16},
},
{false, false, false, true}) -- TA4 only
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:mese_crystal", ""},
{"", "techage:ta4_grinder_pas", ""},
{"", "techage:ta4_wlanchip", ""},
},
})
-------------------------------------------------------------------------------
-- Prepare recipes
-------------------------------------------------------------------------------
-- Nodes from mods that can be recycled
local ModNames = {
techage = true,
hyperloop = true,
}
local function get_item_list(inputs)
local lst = {}
for _,input in pairs(inputs or {}) do
if SpecialItems[input] then
input = SpecialItems[input]
end
if input and input ~= "" then
if minetest.registered_nodes[input] or minetest.registered_items[input] then
table.insert(lst, input)
end
end
end
return lst
end
local function get_special_recipe(name)
if SpecialItems[name] then
return {
output = name,
items = {SpecialItems[name]}
}
end
end
local function collect_recipes()
local add = function(name, ndef)
local _, _, mod, _ = string.find(name, "([%w_]+):([%w_]+)")
local recipe = get_special_recipe(name) or
techage.recipes.get_recipe(name) or
minetest.get_craft_recipe(name)
local items = get_item_list(recipe.items)
if ModNames[mod]
and ndef.groups.not_in_creative_inventory ~= 1
and not ndef.tool_capabilities
and recipe.output
and next(items) then
local s = table.concat(items, ", ")
--print(string.format("%-36s {%s}", recipe.output, s))
Recipes[name] = {output = recipe.output, items = items}
end
end
for name, ndef in pairs(minetest.registered_nodes) do
add(name, ndef)
end
for name, ndef in pairs(minetest.registered_items) do
add(name, ndef)
end
end
minetest.after(2, collect_recipes)

View File

@ -1,265 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3 Power Test Source
]]--
-- for lazy programmers
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
local Axle = techage.Axle
--local Pipe = techage.SteamPipe
local Cable = techage.ElectricCable
local power = networks.power
local control = networks.control
local STANDBY_TICKS = 4
local CYCLE_TIME = 2
local PWR_PERF = 100
local function formspec(self, pos, nvm)
return techage.generator_formspec(self, pos, nvm, S("Power Source"), nvm.provided, PWR_PERF)
end
-- Axles texture animation
local function switch_axles(pos, on)
local outdir = M(pos):get_int("outdir")
Axle:switch_tube_line(pos, outdir, on and "on" or "off")
end
local function start_node2(pos, nvm, state)
nvm.running = true
nvm.provided = 0
local outdir = M(pos):get_int("outdir")
switch_axles(pos, true)
power.start_storage_calc(pos, Axle, outdir)
end
local function stop_node2(pos, nvm, state)
nvm.running = false
nvm.provided = 0
nvm.load = 0
local outdir = M(pos):get_int("outdir")
switch_axles(pos, false)
power.start_storage_calc(pos, Axle, outdir)
end
local function start_node3(pos, nvm, state)
local meta = M(pos)
nvm.running = true
nvm.provided = 0
techage.evaluate_charge_termination(nvm, meta)
local outdir = meta:get_int("outdir")
power.start_storage_calc(pos, Cable, outdir)
end
local function stop_node3(pos, nvm, state)
nvm.running = false
nvm.provided = 0
local outdir = M(pos):get_int("outdir")
power.start_storage_calc(pos, Cable, outdir)
end
local State2 = techage.NodeStates:new({
node_name_passive = "techage:t2_source",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec_func = formspec,
start_node = start_node2,
stop_node = stop_node2,
})
local State3 = techage.NodeStates:new({
node_name_passive = "techage:t4_source",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec_func = formspec,
start_node = start_node3,
stop_node = stop_node3,
})
local function node_timer2(pos, elapsed)
--print("node_timer2")
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local outdir = meta:get_int("outdir")
local tp1 = tonumber(meta:get_string("termpoint1"))
local tp2 = tonumber(meta:get_string("termpoint2"))
nvm.provided = power.provide_power(pos, Axle, outdir, PWR_PERF, tp1, tp2)
nvm.load = power.get_storage_load(pos, Axle, outdir, PWR_PERF)
if techage.is_activeformspec(pos) then
meta:set_string("formspec", formspec(State2, pos, nvm))
end
return true
end
local function node_timer3(pos, elapsed)
--print("node_timer4")
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local outdir = M(pos):get_int("outdir")
local tp1 = tonumber(meta:get_string("termpoint1"))
local tp2 = tonumber(meta:get_string("termpoint2"))
nvm.provided = power.provide_power(pos, Cable, outdir, PWR_PERF, tp1, tp2)
nvm.load = power.get_storage_load(pos, Cable, outdir, PWR_PERF)
if techage.is_activeformspec(pos) then
meta:set_string("formspec", formspec(State3, pos, nvm))
end
return true
end
local function on_receive_fields2(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
State2:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(State2, pos, nvm))
end
local function on_receive_fields3(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
State3:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(State3, pos, nvm))
end
local function on_rightclick2(pos, node, clicker)
techage.set_activeformspec(pos, clicker)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(State2, pos, nvm))
end
local function on_rightclick3(pos, node, clicker)
techage.set_activeformspec(pos, clicker)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(State3, pos, nvm))
end
local function after_place_node2(pos)
local nvm = techage.get_nvm(pos)
State2:node_init(pos, nvm, "")
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
M(pos):set_string("formspec", formspec(State2, pos, nvm))
Axle:after_place_node(pos)
end
local function after_place_node3(pos)
local nvm = techage.get_nvm(pos)
local number = techage.add_node(pos, "techage:t4_source")
State3:node_init(pos, nvm, number)
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
M(pos):set_string("formspec", formspec(State3, pos, nvm))
Cable:after_place_node(pos)
end
local function after_dig_node2(pos, oldnode)
Axle:after_dig_node(pos)
techage.del_mem(pos)
end
local function after_dig_node3(pos, oldnode)
Cable:after_dig_node(pos)
techage.del_mem(pos)
end
local function get_generator_data(pos, outdir, tlib2)
local nvm = techage.get_nvm(pos)
if nvm.running then
return {level = (nvm.load or 0) / PWR_PERF, perf = PWR_PERF, capa = PWR_PERF * 2}
end
end
minetest.register_node("techage:t2_source", {
description = S("Axle Power Source"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2_top.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_axle_clutch.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_source.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_source.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_source.png",
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
on_receive_fields = on_receive_fields2,
on_rightclick = on_rightclick2,
on_timer = node_timer2,
after_place_node = after_place_node2,
after_dig_node = after_dig_node2,
get_generator_data = get_generator_data,
})
minetest.register_node("techage:t4_source", {
description = S("Ele Power Source"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_appl_hole_electric.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_source.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_source.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_source.png",
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
on_receive_fields = on_receive_fields3,
on_rightclick = on_rightclick3,
on_timer = node_timer3,
after_place_node = after_place_node3,
after_dig_node = after_dig_node3,
get_generator_data = get_generator_data,
ta3_formspec = techage.generator_settings("ta3", PWR_PERF),
})
power.register_nodes({"techage:t2_source"}, Axle, "gen", {"R"})
power.register_nodes({"techage:t4_source"}, Cable, "gen", {"R"})
techage.register_node({"techage:t4_source"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "delivered" then
return nvm.provided or 0
else
return State3:on_receive_message(pos, topic, payload)
end
end,
})
control.register_nodes({"techage:t4_source"}, {
on_receive = function(pos, tlib2, topic, payload)
end,
on_request = function(pos, tlib2, topic)
if topic == "info" then
local nvm = techage.get_nvm(pos)
local meta = M(pos)
return {
type = S("Ele Power Source"),
number = meta:get_string("node_number") or "",
running = nvm.running or false,
available = PWR_PERF,
provided = nvm.provided or 0,
termpoint = meta:get_string("termpoint"),
}
end
return false
end,
}
)

View File

@ -1,715 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 8x2000 Chest
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local M = minetest.get_meta
local S = techage.S
local DESCRIPTION = S("TA4 8x2000 Chest")
local STACK_SIZE = 2000
local function gen_stack(inv, idx)
inv[idx] = {name = "", count = 0}
return inv[idx]
end
local function gen_inv(nvm)
nvm.inventory = {}
for i = 1,8 do
gen_stack(nvm.inventory, i)
end
return nvm.inventory
end
local function repair_inv(nvm)
nvm.inventory = nvm.inventory or {}
for i = 1,8 do
local item = nvm.inventory[i]
if not item or type(item) ~= "table"
or not item.name or type(item.name) ~= "string" or item.name == ""
or not item.count or type(item.count) ~= "number" or item.count < 1
then
gen_stack(nvm.inventory, i)
end
end
end
local function get_stack(nvm, idx)
nvm.inventory = nvm.inventory or {}
return nvm.inventory[idx] or gen_stack(nvm.inventory, idx)
end
local function get_count(nvm, idx)
nvm.inventory = nvm.inventory or {}
if idx and idx > 0 then
return nvm.inventory[idx] and nvm.inventory[idx].count or 0
else
local count = 0
for _,item in ipairs(nvm.inventory) do
count = count + item.count or 0
end
return count
end
end
local function get_itemstring(nvm, idx)
if idx and idx > 0 then
nvm.inventory = nvm.inventory or {}
return nvm.inventory[idx] and nvm.inventory[idx].name or ""
end
return ""
end
local function inv_empty(nvm)
for _,item in ipairs(nvm.inventory or {}) do
if item.count and item.count > 0 then
return false
end
end
return true
end
local function inv_state(nvm)
local num = 0
for _,item in ipairs(nvm.inventory or {}) do
if item.count and item.count > 0 then
num = num + 1
end
end
if num == 0 then return "empty" end
if num == 8 then return "full" end
return "loaded"
end
local function inv_state_num(nvm)
local num = 0
for _,item in ipairs(nvm.inventory or {}) do
if item.count and item.count > 0 then
num = num + 1
end
end
if num == 0 then return 0 end
if num == 8 then return 2 end
return 1
end
local function max_stacksize(item_name)
-- It is sufficient to use minetest.registered_items as all registration
-- functions (node, craftitems, tools) add the definitions there.
local ndef = minetest.registered_items[item_name]
-- Return 1 as fallback so that slots with unknown items can be emptied.
return ndef and ndef.stack_max or 1
end
local function get_stacksize(pos)
local size = M(pos):get_int("stacksize")
if size == 0 then
return STACK_SIZE
end
return size
end
-- Returns a boolean that indicates if an itemstack and nvmstack can be combined.
-- The second return value is a string describing the reason.
-- This function guarantees not to modify any of both stacks.
local function doesItemStackMatchNvmStack(itemstack, nvmstack)
if itemstack:get_count() == 0 or nvmstack.count == 0 then
return true, "Empty stack"
end
if nvmstack.name and nvmstack.name ~= "" and nvmstack.name ~= itemstack:get_name() then
return false, "Mismatching names"
end
-- The following seems to be the most reliable approach to compare meta.
local nvm_meta = ItemStack():get_meta()
nvm_meta:from_table(minetest.deserialize(nvmstack.meta or ""))
if not nvm_meta:equals(itemstack:get_meta()) then
return false, "Mismatching meta"
end
if (nvmstack.wear or 0) ~= itemstack:get_wear() then
return false, "Mismatching wear"
end
return true, "Stacks match"
end
-- Generic function for adding items to the 8x2000 Chest
-- This function guarantees not to modify the itemstack.
-- The number of items that were added to the chest is returned.
local function add_to_chest(pos, input_stack, idx)
local nvm = techage.get_nvm(pos)
local nvm_stack = get_stack(nvm, idx)
if input_stack:get_count() == 0 then
return 0
end
if not doesItemStackMatchNvmStack(input_stack, nvm_stack) then
return 0
end
local count = math.min(input_stack:get_count(), get_stacksize(pos) - (nvm_stack.count or 0))
if nvm_stack.count == 0 then
nvm_stack.name = input_stack:get_name()
nvm_stack.meta = minetest.serialize(input_stack:get_meta():to_table())
nvm_stack.wear = input_stack:get_wear()
end
nvm_stack.count = nvm_stack.count + count
return count
end
local function stackOrNil(stack)
if stack and stack.get_count and stack:get_count() > 0 then
return stack
end
return nil
end
-- Generic function for taking items from the 8x2000 Chest
-- output_stack is directly modified; but nil can also be supplied.
-- The resulting output_stack is returned from the function.
-- keep_assignment indicates if the meta information for this function should be considered (manual vs. tubes).
local function take_from_chest(pos, idx, output_stack, max_total_count, keep_assignment)
local nvm = techage.get_nvm(pos)
local nvm_stack = get_stack(nvm, idx)
output_stack = output_stack or ItemStack()
local assignment_count = keep_assignment and M(pos):get_int("assignment") == 1 and 1 or 0
local count = math.min(nvm_stack.count - assignment_count, max_stacksize(nvm_stack.name) - output_stack:get_count())
if max_total_count then
count = math.min(count, max_total_count - output_stack:get_count())
end
if count < 1 then
return stackOrNil(output_stack)
end
if not doesItemStackMatchNvmStack(output_stack, nvm_stack) then
return stackOrNil(output_stack)
end
output_stack:add_item(ItemStack({
name = nvm_stack.name,
count = count,
wear = nvm_stack.wear,
}))
output_stack:get_meta():from_table(minetest.deserialize(nvm_stack.meta or ""))
nvm_stack.count = nvm_stack.count - count
if nvm_stack.count == 0 then
gen_stack(nvm.inventory or {}, idx)
end
return stackOrNil(output_stack)
end
-- Function for adding items to the 8x2000 Chest via automation, e.g. pushers
local function tube_add_to_chest(pos, input_stack)
local nvm = techage.get_nvm(pos)
nvm.inventory = nvm.inventory or {}
for idx = 1,8 do
input_stack:take_item(add_to_chest(pos, input_stack, idx))
end
if input_stack:get_count() > 0 then
return input_stack -- Not all items were added to chest
else
return true -- All items were added
end
end
-- Function for taking items from the 8x2000 Chest via automation, e.g. pushers
local function tube_take_from_chest(pos, item_name, count)
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
nvm.inventory = nvm.inventory or {}
mem.startpos = mem.startpos or 1
local prio = M(pos):get_int("priority") == 1
local startpos = prio and 8 or mem.startpos
local endpos = prio and 1 or mem.startpos + 8
local step = prio and -1 or 1
local itemstack = ItemStack()
for idx = startpos,endpos,step do
idx = ((idx - 1) % 8) + 1
local nvmstack = get_stack(nvm, idx)
if not item_name or item_name == nvmstack.name then
take_from_chest(pos, idx, itemstack, count - itemstack:get_count(), true)
if itemstack:get_count() == count then
mem.startpos = idx + 1
return itemstack
end
end
mem.startpos = idx + 1
end
return stackOrNil(itemstack)
end
-- Function for manually adding items to the 8x2000 Chest via the formspec
local function inv_add_to_chest(pos, idx)
local inv = M(pos):get_inventory()
local inv_stack = inv:get_stack("main", idx)
local count = add_to_chest(pos, inv_stack, idx)
inv_stack:set_count(inv_stack:get_count() - count)
inv:set_stack("main", idx, inv_stack)
end
-- Function for manually taking items from the 8x2000 Chest via the formspec
local function inv_take_from_chest(pos, idx)
local inv = M(pos):get_inventory()
local inv_stack = inv:get_stack("main", idx)
if inv_stack:get_count() > 0 then
return
end
local output_stack = take_from_chest(pos, idx)
if output_stack then
inv:set_stack("main", idx, output_stack)
end
end
local function formspec_container(x, y, nvm, inv)
local tbl = {"container["..x..","..y.."]"}
for i = 1,8 do
local xpos = i - 1
tbl[#tbl+1] = "box["..(xpos - 0.03)..",0;0.86,0.9;#808080]"
local stack = get_stack(nvm, i)
if stack.name ~= "" then
local itemstack = ItemStack({
name = stack.name,
count = stack.count,
wear = stack.wear,
})
local stack_meta_table = (minetest.deserialize(stack.meta) or {}).fields or {}
for _, key in ipairs({"description", "short_description", "color", "palette_index"}) do
if stack_meta_table[key] then
itemstack:get_meta():set_string(key, stack_meta_table[key])
end
end
local itemname = itemstack:to_string()
--tbl[#tbl+1] = "item_image["..xpos..",1;1,1;"..itemname.."]"
tbl[#tbl+1] = techage.item_image(xpos, 0, itemname, stack.count)
end
if inv:get_stack("main", i):get_count() == 0 then
tbl[#tbl+1] = "image_button["..xpos..",1;1,1;techage_form_get_arrow.png;get"..i..";]"
else
tbl[#tbl+1] = "image_button["..xpos..",1;1,1;techage_form_add_arrow.png;add"..i..";]"
end
end
tbl[#tbl+1] = "list[context;main;0,2;8,1;]"
tbl[#tbl+1] = "container_end[]"
return table.concat(tbl, "")
end
local function formspec(pos)
local nvm = techage.get_nvm(pos)
local inv = M(pos):get_inventory()
local size = get_stacksize(pos)
local assignment = M(pos):get_int("assignment") == 1 and "true" or "false"
local priority = M(pos):get_int("priority") == 1 and "true" or "false"
return "size[8,8.3]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
formspec_container(0, 0, nvm, inv)..
"button[0,3.5;3,1;unlock;"..S("Unlock").."]"..
"tooltip[0,3.5;3,1;"..S("Unlock connected chest\nif all slots are below 2000")..";#0C3D32;#FFFFFF]"..
"label[0,3;"..S("Size")..": 8x"..size.."]"..
"checkbox[4,3;assignment;"..S("keep assignment")..";"..assignment.."]"..
"tooltip[4,3;2,0.6;"..S("Never completely empty the slots\nwith the pusher to keep the item assignment")..";#0C3D32;#FFFFFF]"..
"checkbox[4,3.6;priority;"..S("right to left")..";"..priority.."]"..
"tooltip[4,3.6;2,0.6;"..S("Empty the slots always \nfrom right to left")..";#0C3D32;#FFFFFF]"..
"list[current_player;main;0,4.6;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function count_number_of_chests(pos)
local node = techage.get_node_lvm(pos)
local dir = techage.side_to_outdir("B", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
local param2 = node.param2
local cnt = 1
while cnt < 50 do
node = techage.get_node_lvm(pos1)
if node.name ~= "techage:ta4_chest_dummy" then
break
end
local meta = M(pos1)
if meta:contains("param2") and meta:get_int("param2") ~= param2 then
break
end
pos1 = tubelib2.get_pos(pos1, dir)
cnt = cnt + 1
end
M(pos):set_int("stacksize", STACK_SIZE * cnt)
end
local function dummy_chest_behind(pos, node)
local dir = techage.side_to_outdir("B", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
node = techage.get_node_lvm(pos1)
return node.name == "techage:ta4_chest_dummy"
end
local function part_of_a_chain(pos, node)
local dir = techage.side_to_outdir("F", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
node = techage.get_node_lvm(pos1)
return node.name == "techage:ta4_chest_dummy" or node.name == "techage:ta4_chest"
end
local function search_chest_in_front(pos, node)
local dir = techage.side_to_outdir("F", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
local param2 = node.param2
local cnt = 1
while cnt < 50 do
node = techage.get_node_lvm(pos1)
if node.name ~= "techage:ta4_chest_dummy" then
break
end
local meta = M(pos1)
if meta:contains("param2") and meta:get_int("param2") ~= param2 then
break
end
pos1 = tubelib2.get_pos(pos1, dir)
cnt = cnt + 1
end
if node.name == "techage:ta4_chest" and node.param2 == param2 then
minetest.after(1, count_number_of_chests, pos1)
local nvm = techage.get_nvm(pos)
nvm.front_chest_pos = pos1
return true
end
return false
end
local function get_front_chest_pos(pos)
local nvm = techage.get_nvm(pos)
if nvm.front_chest_pos then
return nvm.front_chest_pos
end
local node = techage.get_node_lvm(pos)
if search_chest_in_front(pos, node) then
return nvm.front_chest_pos
end
return pos
end
local function convert_to_chest_again(pos, node, player)
local dir = techage.side_to_outdir("B", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
local node1 = techage.get_node_lvm(pos1)
if minetest.is_protected(pos1, player:get_player_name()) then
return
end
if node1.name == "techage:ta4_chest_dummy" then
node1.name = "techage:ta4_chest"
minetest.swap_node(pos1, node1)
--M(pos1):set_int("disabled", 1)
local nvm = techage.get_nvm(pos1)
gen_inv(nvm)
local number = techage.add_node(pos1, "techage:ta4_chest")
M(pos1):set_string("owner", player:get_player_name())
M(pos1):set_string("formspec", formspec(pos1))
M(pos1):set_string("infotext", DESCRIPTION.." "..number)
end
end
local function unlock_chests(pos, player)
local nvm = techage.get_nvm(pos)
for idx = 1,8 do
if get_count(nvm, idx) > STACK_SIZE then return end
end
local node = techage.get_node_lvm(pos)
convert_to_chest_again(pos, node, player)
M(pos):set_int("stacksize", STACK_SIZE)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return count
end
local function on_metadata_inventory_put(pos, listname, index, stack, player)
M(pos):set_string("formspec", formspec(pos))
techage.set_activeformspec(pos, player)
end
local function on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
M(pos):set_string("formspec", formspec(pos))
techage.set_activeformspec(pos, player)
end
local function on_metadata_inventory_take(pos, listname, index, stack, player)
M(pos):set_string("formspec", formspec(pos))
techage.set_activeformspec(pos, player)
end
local function on_rightclick(pos, node, clicker)
if M(pos):get_int("disabled") ~= 1 then
local nvm = techage.get_nvm(pos)
repair_inv(nvm)
M(pos):set_string("formspec", formspec(pos))
techage.set_activeformspec(pos, clicker)
end
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
for i = 1,8 do
if fields["get"..i] ~= nil then
inv_take_from_chest(pos, i)
break
elseif fields["add"..i] ~= nil then
inv_add_to_chest(pos, i)
break
end
end
if fields.unlock then
unlock_chests(pos, player)
end
if fields.assignment then
M(pos):set_int("assignment", fields.assignment == "true" and 1 or 0)
end
if fields.priority then
M(pos):set_int("priority", fields.priority == "true" and 1 or 0)
end
M(pos):set_string("formspec", formspec(pos))
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = minetest.get_meta(pos):get_inventory()
local nvm = techage.get_nvm(pos)
return inv:is_empty("main") and inv_empty(nvm)
end
local function on_rotate(pos, node, user, mode, new_param2)
if get_stacksize(pos) == STACK_SIZE then
return screwdriver.rotate_simple(pos, node, user, mode, new_param2)
else
return screwdriver.disallow(pos, node, user, mode, new_param2)
end
end
local function after_dig_node(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
convert_to_chest_again(pos, oldnode, digger)
end
minetest.register_node("techage:ta4_chest", {
description = DESCRIPTION,
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_front_ta4.png^techage_appl_warehouse.png",
},
on_construct = function(pos)
local inv = M(pos):get_inventory()
inv:set_size('main', 8)
end,
after_place_node = function(pos, placer)
local node = minetest.get_node(pos)
if dummy_chest_behind(pos, node) then
minetest.remove_node(pos)
return true
end
if search_chest_in_front(pos, node) then
node.name = "techage:ta4_chest_dummy"
minetest.swap_node(pos, node)
M(pos):set_int("param2", node.param2)
else
local nvm = techage.get_nvm(pos)
gen_inv(nvm)
local number = techage.add_node(pos, "techage:ta4_chest")
M(pos):set_string("owner", placer:get_player_name())
M(pos):set_string("formspec", formspec(pos))
M(pos):set_string("infotext", DESCRIPTION.." "..number)
end
end,
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, DESCRIPTION)
end,
on_rotate = on_rotate,
on_rightclick = on_rightclick,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
on_metadata_inventory_put = on_metadata_inventory_put,
on_metadata_inventory_move = on_metadata_inventory_move,
on_metadata_inventory_take = on_metadata_inventory_take,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:ta4_chest_dummy", {
description = DESCRIPTION,
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_front_ta4.png^techage_appl_warehouse.png",
},
on_rightclick = function(pos, node, clicker)
end,
paramtype2 = "facedir",
diggable = false,
groups = {not_in_creative_inventory = 1},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta4_chest"}, {
on_pull_item = function(pos, in_dir, num, item_name)
local res = tube_take_from_chest(pos, item_name, num)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return res
end,
on_push_item = function(pos, in_dir, stack)
local res = tube_add_to_chest(pos, stack)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return res
end,
on_unpull_item = function(pos, in_dir, stack)
local res = tube_add_to_chest(pos, stack)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return res
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "count" then
local nvm = techage.get_nvm(pos)
return get_count(nvm, tonumber(payload or 0) or 0)
elseif topic == "itemstring" then
local nvm = techage.get_nvm(pos)
return get_itemstring(nvm, tonumber(payload or 0) or 0)
elseif topic == "storesize" then
return get_stacksize(pos)
elseif topic == "state" then
local nvm = techage.get_nvm(pos)
return inv_state(nvm)
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 140 and payload[1] == 1 then -- Inventory Item Count
local nvm = techage.get_nvm(pos)
return 0, {get_count(nvm, tonumber(payload[2] or 0) or 0)}
elseif topic == 140 and payload[1] == 2 then -- Inventory Item Name
local nvm = techage.get_nvm(pos)
return 0, get_itemstring(nvm, tonumber(payload[2] or 0) or 0)
elseif topic == 140 and payload[1] == 3 then -- storesize
return 0, {get_stacksize(pos)}
elseif topic == 131 then -- Chest State
local nvm = techage.get_nvm(pos)
return 0, {inv_state_num(nvm)}
else
return 2, ""
end
end,
})
techage.register_node({"techage:ta4_chest_dummy"}, {
on_pull_item = function(pos, in_dir, num, item_name)
local fc_pos = get_front_chest_pos(pos)
local res = tube_take_from_chest(fc_pos, item_name, num)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end,
on_push_item = function(pos, in_dir, stack)
local fc_pos = get_front_chest_pos(pos)
local res = tube_add_to_chest(fc_pos, stack)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end,
on_unpull_item = function(pos, in_dir, stack)
local fc_pos = get_front_chest_pos(pos)
local res = tube_add_to_chest(fc_pos, stack)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end
})
minetest.register_lbm({
label = "Repair Dummy Chests",
name = "techage:chest_dummy",
nodenames = {"techage:ta4_chest_dummy"},
run_at_every_load = true,
action = function(pos, node)
if not part_of_a_chain(pos, node) then
minetest.swap_node(pos, {name = "techage:ta4_chest", param2 = node.param2})
end
end,
})
minetest.register_craft({
type = "shapeless",
output = "techage:ta4_chest",
recipe = {"techage:chest_ta4"}
})
minetest.register_craft({
type = "shapeless",
output = "techage:chest_ta4",
recipe = {"techage:ta4_chest"}
})

View File

@ -1,331 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Injector
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local tooltip = S("Switch to pull mode \nto pull items out of inventory slots \naccording the injector configuration")
local Tube = techage.Tube
local STANDBY_TICKS = 2
local COUNTDOWN_TICKS = 3
local CYCLE_TIME = 4
local function formspec(self, pos, nvm)
local pull_mode = dump(nvm.pull_mode or false)
return "size[8,7.2]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3,-0.1;"..minetest.colorize("#000000", S("Injector")).."]"..
techage.question_mark_help(8, S("Configure up to 8 items \nto be pushed by the injector"))..
"list[context;filter;0,0.8;8,1;]"..
"image_button[2,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"checkbox[3.5,1.9;pull_mode;"..S("pull mode")..";"..pull_mode.."]"..
"tooltip[3.5,1.9;2,0.8;"..tooltip..";#0C3D32;#FFFFFF]"..
"list[current_player;main;0,3.5;8,4;]"..
"listring[context;filter]"..
"listring[current_player;main]"
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
local cdr = CRD(pos)
if list[index]:get_count() < cdr.num_items then
local num = math.min(cdr.num_items - list[index]:get_count(), stack:get_count()) + list[index]:get_count()
stack:set_count(num)
inv:set_stack(listname, index, stack)
return 0
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
inv:set_stack(listname, index, nil)
return 0
end
local function pull_items(pos, out_dir, idx, name, num)
local inv, listname = techage.get_inv_access(pos, out_dir, "pull")
if inv and listname then
if idx and idx ~= 0 then
local stack = inv:get_stack(listname, idx)
if stack and not stack:is_empty() and stack:get_name() == name then
local taken = stack:take_item(num)
inv:set_stack(listname, idx, stack)
return (taken:get_count() > 0) and taken or nil
end
else
local taken = inv:remove_item(listname, {name = name, count = num})
return (taken:get_count() > 0) and taken or nil
end
else
return techage.pull_items(pos, out_dir, num, name)
end
end
local function push_items(pos, out_dir, idx, items)
local inv, listname, callafter, dpos = techage.get_inv_access(pos, out_dir, "push")
if inv and listname then
if idx and idx ~= 0 then
local stack = inv:get_stack(listname, idx)
if stack:item_fits(items) then
stack:add_item(items)
inv:set_stack(listname, idx, stack)
if callafter then
callafter(dpos)
end
return true
end
else
if inv:room_for_item(listname, items) then
inv:add_item(listname, items)
if callafter then
callafter(dpos)
end
return true
end
end
return false
else
local taken = items:get_count()
local leftover = techage.push_items(pos, out_dir, items, idx)
if not leftover or leftover == false then
return false -- No items placed
elseif leftover ~= true then
-- One or more items placed?
if leftover:get_count() < taken then
-- place the rest back
local pull_dir = M(pos):get_int("pull_dir")
techage.unpull_items(pos, pull_dir, leftover)
return true -- Some items placed
end
return false -- No items placed
end
return true -- All items placed
end
end
local function unpull_items(pos, out_dir, idx, items)
local inv, listname = techage.get_inv_access(pos, out_dir, "unpull")
if inv and listname then
if idx and idx ~= 0 then
local stack = inv:get_stack(listname, idx)
stack:add_item(items)
inv:set_stack(listname, idx, stack)
else
inv:add_item(listname, items)
end
else
techage.unpull_items(pos, out_dir, items)
end
end
local function pushing(pos, crd, meta, nvm)
local pull_dir = meta:get_int("pull_dir")
local push_dir = meta:get_int("push_dir")
local inv = M(pos):get_inventory()
local filter = inv:get_list("filter")
local pushed = false
local pulled = false
for idx, item in ipairs(filter) do
local name = item:get_name()
local num = math.min(item:get_count(), crd.num_items)
if name ~= "" and num > 0 then
local items = pull_items(pos, pull_dir, nvm.pull_mode and idx, name, num)
if items ~= nil then
pulled = true
if push_items(pos, push_dir, not nvm.pull_mode and idx, items) then
pushed = true
else -- place item back
unpull_items(pos, pull_dir, nvm.pull_mode and idx, items)
pulled = false
end
end
end
end
if not pulled then
crd.State:idle(pos, nvm)
elseif not pushed then
crd.State:blocked(pos, nvm)
else
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
end
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
pushing(pos, crd, M(pos), nvm)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
if fields.pull_mode then
nvm.pull_mode = fields.pull_mode == "true"
end
CRD(pos).State:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_appl_pusher.png^[transformR180]^techage_frame_ta#.png^techage_appl_injector.png",
"techage_appl_pusher.png^techage_frame_ta#.png^techage_appl_injector.png",
}
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
name = "techage_appl_pusher14.png^[transformR180]^techage_frame14_ta#.png^techage_appl_injector14.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
{
name = "techage_appl_pusher14.png^techage_frame14_ta#.png^techage_appl_injector14.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
}
local tubing = {
-- push item through the injector in opposit direction
on_push_item = function(pos, in_dir, stack)
return in_dir == M(pos):get_int("pull_dir") and techage.safe_push_items(pos, in_dir, stack)
end,
is_pusher = true, -- is a pulling/pushing node
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local _, node_name_ta3, node_name_ta4 =
techage.register_consumer("injector", S("Injector"), tiles, {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
quick_start = node_timer,
after_place_node = function(pos, placer)
local meta = M(pos)
local node = minetest.get_node(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", node.param2))
meta:set_int("push_dir", techage.side_to_outdir("R", node.param2))
local inv = M(pos):get_inventory()
inv:set_size('filter', 8)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end,
ta_rotate_node = function(pos, node, new_param2)
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) == techage.STOPPED then
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
local meta = M(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", new_param2))
meta:set_int("push_dir", techage.side_to_outdir("R", new_param2))
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = function() return 0 end,
on_receive_fields = on_receive_fields,
node_timer = node_timer,
on_rotate = screwdriver.disallow,
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
num_items = {0,0,1,4},
}, {false, false, true, true})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:steel_ingot", ""},
{"", "techage:ta3_pusher_pas", ""},
{"", "basic_materials:ic", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "techage:aluminum", ""},
{"", "techage:ta4_pusher_pas", ""},
{"", "basic_materials:ic", ""},
},
})

View File

@ -1,248 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA5 Hyperloop Chest
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local S = techage.S
local TA4_INV_SIZE = 32
local EX_POINTS = 15
local hyperloop = techage.hyperloop
local remote_pos = techage.hyperloop.remote_pos
local shared_inv = techage.shared_inv
local menu = techage.menu
local function formspec(pos)
local ndef = minetest.registered_nodes["techage:ta5_hl_chest"]
local status = M(pos):get_string("conn_status")
if hyperloop.is_server(pos) then
local title = ndef.description .. " " .. status
return "size[8,9]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"list[context;main;0,1;8,4;]"..
"list[current_player;main;0,5.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
elseif hyperloop.is_client(pos) then
local title = ndef.description .. " " .. status
return "size[8,9]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[0.2,2;Inventory access on this node is disabled\ndue to minetest engine issues!]" ..
"list[current_player;main;0,5.3;8,4;]"
else
return menu.generate_formspec(pos, ndef, hyperloop.SUBMENU)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if techage.hyperloop.is_client(pos) then
return 0
end
shared_inv.before_inv_access(pos, listname)
local inv = minetest.get_inventory({type="node", pos=pos})
if inv and inv:room_for_item(listname, stack) then
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if techage.hyperloop.is_client(pos) then
return 0
end
shared_inv.before_inv_access(pos, listname)
local inv = minetest.get_inventory({type="node", pos=pos})
if inv and inv:contains_item(listname, stack) then
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if shared_inv.before_inv_access(pos, "main") then
return 0
end
if techage.hyperloop.is_client(pos) then
return 0
end
return count
end
minetest.register_node("techage:ta5_hl_chest", {
description = S("TA5 Hyperloop Chest"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta5_top.png",
"techage_filling_ta4.png^techage_frame_ta5.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_front_ta4.png",
},
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('main', 32)
local number = techage.add_node(pos, "techage:ta5_hl_chest")
meta:set_string("node_number", number)
meta:set_string("owner", placer:get_player_name())
meta:set_string("formspec", formspec(pos))
meta:set_string("infotext", S("TA5 Hyperloop Chest").." "..number)
hyperloop.after_place_node(pos, placer, "chest")
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if techage.get_expoints(player) >= EX_POINTS then
if techage.menu.eval_input(pos, hyperloop.SUBMENU, fields) then
hyperloop.after_formspec(pos, fields)
shared_inv.on_rightclick(pos, player, "main")
M(pos):set_string("formspec", formspec(pos))
end
end
end,
on_timer = shared_inv.node_timer,
on_rightclick = function(pos, node, clicker)
shared_inv.on_rightclick(pos, clicker, "main")
M(pos):set_string("formspec", formspec(pos))
end,
can_dig = function(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
shared_inv.before_inv_access(pos, "main")
local inv = minetest.get_meta(pos):get_inventory()
return inv:is_empty("main")
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
hyperloop.after_dig_node(pos, oldnode, oldmetadata, digger)
techage.del_mem(pos)
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
on_metadata_inventory_put = shared_inv.after_inv_access,
on_metadata_inventory_take = shared_inv.after_inv_access,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta5_hl_chest"}, {
on_inv_request = function(pos, in_dir, access_type)
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
return meta:get_inventory(), "main"
end
end
end,
on_pull_item = function(pos, in_dir, num, item_name)
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.get_items(pos, inv, "main", num)
end
end
end
return false
end,
on_push_item = function(pos, in_dir, stack)
if techage.hyperloop.is_paired(pos) then
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.put_items(inv, "main", stack)
end
end
end
end
return false
end,
on_unpull_item = function(pos, in_dir, stack)
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.put_items(inv, "main", stack)
end
end
end
return false
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.get_inv_state(inv, "main")
end
end
return "error"
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then -- Chest State
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return 0, {techage.get_inv_state_num(inv, "main")}
end
end
else
return 2, ""
end
end,
})
minetest.register_craft({
type = "shapeless",
output = "techage:ta5_hl_chest",
recipe = {"techage:chest_ta4", "techage:ta5_aichip"}
})
minetest.register_on_mods_loaded(function()
if not minetest.global_exists("hyperloop") then
minetest.clear_craft({output = "techage:ta5_hl_chest"})
end
end)

View File

@ -1,242 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Assemble routines
]]--
-- for lazy programmers
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
techage.assemble = {}
local Face2Dir = {[0]=
{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}
}
-- Determine the destination position based on the base position,
-- param2, and a route table like : {0,3}
-- 0 = forward, 1 = right, 2 = backward, 3 = left
local function dest_pos(pos, param2, route, y_offs)
local p2 = param2
local pos1 = {x=pos.x, y=pos.y+y_offs, z=pos.z}
for _,dir in ipairs(route) do
p2 = (param2 + dir) % 4
pos1 = vector.add(pos1, Face2Dir[p2])
end
return pos1, p2
end
-- timer based function
local function build(pos, param2, AssemblyPlan, idx)
local item = AssemblyPlan[idx]
if item ~= nil then
local y, path, fd_offs, node_name = item[1], item[2], item[3], item[4]
local pos1 = dest_pos(pos, param2, path, y)
minetest.add_node(pos1, {name=node_name, param2=(param2 + fd_offs) % 4})
minetest.after(0.5, build, pos, param2, AssemblyPlan, idx+1)
else
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
-- timer based function
local function remove(pos, param2, AssemblyPlan, idx)
local item = AssemblyPlan[idx]
if item ~= nil then
local y, path = item[1], item[2]
local pos1 = dest_pos(pos, param2, path, y)
minetest.remove_node(pos1)
minetest.after(0.5, remove, pos, param2, AssemblyPlan, idx-1)
else
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
local function check_space(pos, param2, AssemblyPlan, player_name)
for _,item in ipairs(AssemblyPlan) do
local y, path, node_name = item[1], item[2], item[4]
local pos1 = dest_pos(pos, param2, path, y)
if minetest.is_protected(pos1, player_name) then
minetest.chat_send_player(player_name, S("[TA] Area is protected!"))
return false
end
local node = techage.get_node_lvm(pos1)
local ndef = minetest.registered_nodes[node.name]
if not ndef or not ndef.buildable_to and node.name ~= node_name then
minetest.chat_send_player(player_name, S("[TA] Not enough space!"))
return false
end
end
return true
end
-- Two important flags:
-- 1) nvm.assemble_locked is true while the object is being assembled/disassembled
-- 2) nvm.assemble_build is true if the object is assembled
function techage.assemble.build(pos, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
end
local node = minetest.get_node(pos)
if check_space(pos, node.param2, AssemblyPlan, player_name) then
nvm.assemble_locked = true
build(pos, node.param2, AssemblyPlan, 1)
nvm.assemble_build = true
end
end
function techage.assemble.remove(pos, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
end
local node = minetest.get_node(pos)
nvm.assemble_locked = true
remove(pos, node.param2, AssemblyPlan, #AssemblyPlan)
nvm.assemble_build = false
end
--------------------------------------------------------------------------------
-- Assembly functions based on nodes from node inventory
--------------------------------------------------------------------------------
local function play_sound(pos, sound)
minetest.sound_play(sound, {
pos = pos,
gain = 1,
max_hear_distance = 10,
})
end
local function build_inv(pos, inv, param2, AssemblyPlan, player_name, idx)
local item = AssemblyPlan[idx]
if item ~= nil then
local y, path, fd_offs, node_name = item[1], item[2], item[3], item[4]
local pos1 = dest_pos(pos, param2, path, y)
if not minetest.is_protected(pos1, player_name) then
local node = minetest.get_node(pos1)
if techage.is_air_like(node.name) then
local stack = inv:remove_item("src", ItemStack(node_name))
if stack:get_count() == 1 then
minetest.add_node(pos1, {name=node_name, param2=(param2 + fd_offs) % 4})
play_sound(pos, "default_place_node_hard")
local ndef = minetest.registered_nodes[node_name]
if ndef and ndef.after_place_node then
local placer = minetest.get_player_by_name(player_name)
ndef.after_place_node(pos1, placer, ItemStack(node_name))
end
end
end
end
minetest.after(0.5, build_inv, pos, inv, param2, AssemblyPlan, player_name, idx + 1)
else
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
local function remove_inv(pos, inv, param2, AssemblyPlan, player_name, idx)
local item = AssemblyPlan[idx]
if item ~= nil then
local y, path, fd_offs, node_name = item[1], item[2], item[3], item[4]
local pos1 = dest_pos(pos, param2, path, y)
if not minetest.is_protected(pos1, player_name) then
local stack = ItemStack(node_name)
if inv:room_for_item("src", stack) then
local node = minetest.get_node(pos1)
if node.name == node_name then
local meta = M(pos1):to_table()
minetest.remove_node(pos1)
inv:add_item("src", stack)
play_sound(pos, "default_dig_cracky")
local ndef = minetest.registered_nodes[node_name]
if ndef and ndef.after_dig_node then
local digger = minetest.get_player_by_name(player_name)
ndef.after_dig_node(pos1, node, meta, digger)
end
end
end
end
minetest.after(0.5, remove_inv, pos, inv, param2, AssemblyPlan, player_name, idx - 1)
else
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
function techage.assemble.build_inv(pos, inv, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
end
local node = minetest.get_node(pos)
nvm.assemble_locked = true
build_inv(pos, inv, node.param2, AssemblyPlan, player_name, 1)
end
function techage.assemble.remove_inv(pos, inv, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
end
local node = minetest.get_node(pos)
nvm.assemble_locked = true
remove_inv(pos, inv, node.param2, AssemblyPlan, player_name, #AssemblyPlan)
end
function techage.assemble.count_items(AssemblyPlan)
local t = {}
for _, item in ipairs(AssemblyPlan) do
local node_name = item[4]
local ndef = minetest.registered_nodes[node_name]
local name = ndef.description
if not t[name] then
t[name] = 1
else
t[name] = t[name] + 1
end
end
return t
end
-- Determine the destination position based on the given route
-- param2, and a route table like : {0,3}
-- 0 = forward, 1 = right, 2 = backward, 3 = left
-- techage.assemble.get_pos(pos, param2, route, y_offs)
techage.assemble.get_pos = dest_pos

View File

@ -1,150 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Boiler common functions
]]--
-- for lazy programmers
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
local HEAT_STEP = 10
local MAX_WATER = 10
local BLOCKING_TIME = 0.3 -- 300ms
techage.boiler = {}
local IsWater = {
["bucket:bucket_river_water"] = "bucket:bucket_empty",
}
local IsBucket = {}
local function node_description(name)
name = string.split(name, " ")[1]
local ndef = minetest.registered_nodes[name] or minetest.registered_items[name] or minetest.registered_craftitems[name]
if ndef and ndef.description then
return minetest.formspec_escape(ndef.description)
end
return ""
end
local function item_image(x, y, itemname)
return "box["..x..","..y..";0.85,0.9;#808080]"..
"item_image["..x..","..y..";1,1;"..itemname.."]"
end
function techage.boiler.formspec(pos, nvm)
local title = S("Water Boiler")
local temp = nvm.temperature or 20
local ratio = nvm.power_ratio or 0
local tooltip = S("To add water punch\nthe boiler\nwith a water bucket")
return "size[5,3]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;4.8,0.5;#c6e8ff]"..
"label[1.5,-0.1;"..minetest.colorize("#000000", title).."]"..
item_image(1, 1.5, "default:water_source "..(nvm.num_water or 0))..
"tooltip[1,1.5;1,1;"..tooltip..";#0C3D32;#FFFFFF]"..
"image[3,1.0;1,2;techage_form_temp_bg.png^[lowpart:"..
temp..":techage_form_temp_fg.png]"..
"tooltip[3,1;1,2;"..S("water temperature")..";#0C3D32;#FFFFFF]"
end
function techage.boiler.water_temperature(pos, nvm)
nvm.temperature = nvm.temperature or 20
nvm.num_water = nvm.num_water or 0
nvm.water_level = nvm.water_level or 0
if nvm.fire_trigger then
nvm.temperature = math.min(nvm.temperature + HEAT_STEP, 100)
else
nvm.temperature = math.max(nvm.temperature - HEAT_STEP, 20)
end
nvm.fire_trigger = false
if nvm.water_level == 0 then
if nvm.num_water > 0 then
nvm.num_water = nvm.num_water - 1
nvm.water_level = 100
else
nvm.temperature = 20
end
end
return nvm.temperature
end
function techage.boiler.on_rightclick(pos, node, clicker)
techage.set_activeformspec(pos, clicker)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", techage.boiler.formspec(pos, nvm))
end
function techage.boiler.can_dig(pos, player)
local nvm = techage.get_nvm(pos)
nvm.num_water = nvm.num_water or 0
return nvm.num_water == 0
end
local function space_in_inventory(wielded_item, item_count, puncher)
-- check if holding more than 1 empty container
if item_count > 1 then
local inv = puncher:get_inventory()
local item = ItemStack({name=wielded_item, count = item_count - 1})
if inv:room_for_item("main", item) then
inv:add_item("main", item)
return true
end
return false
end
return true
end
function techage.boiler.on_punch(pos, node, puncher, pointed_thing)
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
mem.blocking_time = mem.blocking_time or 0
if mem.blocking_time > techage.SystemTime then
return
end
nvm.num_water = nvm.num_water or 0
local wielded_item = puncher:get_wielded_item():get_name()
local item_count = puncher:get_wielded_item():get_count()
if IsWater[wielded_item] and nvm.num_water < MAX_WATER then
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
nvm.num_water = nvm.num_water + 1
puncher:set_wielded_item(ItemStack(IsWater[wielded_item]))
M(pos):set_string("formspec", techage.boiler.formspec(pos, nvm))
elseif IsBucket[wielded_item] and nvm.num_water > 0 then
if item_count > 1 then
local inv = puncher:get_inventory()
local item = ItemStack(IsBucket[wielded_item])
if inv:room_for_item("main", item) then
inv:add_item("main", item)
puncher:set_wielded_item({name=wielded_item, count = item_count - 1})
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
nvm.num_water = nvm.num_water - 1
end
else
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
nvm.num_water = nvm.num_water - 1
puncher:set_wielded_item(ItemStack(IsBucket[wielded_item]))
end
M(pos):set_string("formspec", techage.boiler.formspec(pos, nvm))
end
end
function techage.register_water_bucket(empty_bucket, full_bucket)
IsWater[full_bucket] = empty_bucket
IsBucket[empty_bucket] = full_bucket
end

View File

@ -1,691 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Basis functions for inter-node communication
]]--
--- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
--local P = minetest.string_to_pos
--local M = minetest.get_meta
local has_mesecons = minetest.global_exists("mesecon")
local NodeInfoCache = {}
local NumbersToBeRecycled = {}
local MP = minetest.get_modpath("techage")
local techage_use_sqlite = minetest.settings:get_bool('techage_use_sqlite', false)
-- Localize functions to avoid table lookups (better performance)
local string_split = string.split
local NodeDef = techage.NodeDef
local Tube = techage.Tube
local is_cart_available = minecart.is_nodecart_available
local techage_counting_hit = techage.counting_hit
local tubelib2_side_to_dir = tubelib2.side_to_dir
-------------------------------------------------------------------
-- Database
-------------------------------------------------------------------
local backend
if techage_use_sqlite then
backend = dofile(MP .. "/basis/numbers_sqlite.lua")
else
backend = dofile(MP .. "/basis/numbers_storage.lua")
end
local function update_nodeinfo(number)
local pos = backend.get_nodepos(number)
if pos then
NodeInfoCache[number] = {pos = pos, name = techage.get_node_lvm(pos).name}
return NodeInfoCache[number]
end
end
local function delete_nodeinfo_entry(number)
if number and NodeInfoCache[number] then
number = next(NodeInfoCache, number)
if number then
NodeInfoCache[number] = nil
end
else
number = next(NodeInfoCache, nil)
end
return number
end
-- Keep the cache size small by deleting entries randomly
local function keep_small(number)
number = delete_nodeinfo_entry(number)
minetest.after(10, keep_small, number)
end
keep_small()
minetest.after(2, backend.delete_invalid_entries, NodeDef)
-------------------------------------------------------------------
-- Local helper functions
-------------------------------------------------------------------
local function in_list(list, x)
for _, v in ipairs(list) do
if v == x then return true end
end
return false
end
-- Determine position related node number for addressing purposes
local function get_number(pos, new)
local meta = minetest.get_meta(pos)
if meta:contains("node_number") then
return meta:get_string("node_number")
end
-- generate new number
if new then
local num = backend.add_nodepos(pos)
meta:set_string("node_number", num)
return num
end
end
local function not_protected(pos, placer_name, clicker_name)
local meta = minetest.get_meta(pos)
if meta then
if placer_name and not minetest.is_protected(pos, placer_name) then
if clicker_name == nil or placer_name == clicker_name then
return true
end
if not minetest.is_protected(pos, clicker_name) then
return true
end
end
end
return false
end
local function register_lbm(name, nodenames)
minetest.register_lbm({
label = "[TechAge] Node update",
name = name.."update",
nodenames = nodenames,
run_at_every_load = true,
action = function(pos, node)
if NodeDef[node.name] and NodeDef[node.name].on_node_load then
NodeDef[node.name].on_node_load(pos, node)
end
end
})
end
local SideToDir = {B=1, R=2, F=3, L=4, D=5, U=6}
local function side_to_dir(side, param2)
return tubelib2_side_to_dir(side, param2)
end
techage.side_to_outdir = side_to_dir
function techage.side_to_indir(side, param2)
return tubelib2.Turn180Deg[side_to_dir(side, param2)]
end
local function get_next_node(pos, out_dir)
local res, npos, node = Tube:compatible_node(pos, out_dir)
local in_dir = tubelib2.Turn180Deg[out_dir]
return res, npos, in_dir, node.name
end
local function get_dest_node(pos, out_dir)
local spos, in_dir = Tube:get_connected_node_pos(pos, out_dir)
local _,node = Tube:get_node(spos)
return spos, in_dir, node.name
end
local function item_handling_node(name)
local node_def = name and NodeDef[name]
if node_def then
return node_def.on_pull_item or node_def.on_push_item or node_def.is_pusher
end
end
local function is_air_like(name)
local ndef = minetest.registered_nodes[name]
if ndef and ndef.buildable_to then
return true
end
return false
end
techage.SystemTime = 0
minetest.register_globalstep(function(dtime)
techage.SystemTime = techage.SystemTime + dtime
end)
-- used by TA1 hammer: dug_node[player_name] = pos
techage.dug_node = {}
minetest.register_on_dignode(function(pos, oldnode, digger)
if not digger then return end
-- store the position of the dug block for tools like the TA1 hammer
techage.dug_node[digger:get_player_name()] = pos
end)
-------------------------------------------------------------------
-- API helper functions
-------------------------------------------------------------------
-- Check if both strings are the same or one string starts with the other string.
function techage.string_compare(s1, s2)
if s1 and s2 then
local minLength = math.min(#s1, #s2)
return string.sub(s1, 1, minLength) == string.sub(s2, 1, minLength)
end
end
-- Function returns { pos, name } for the node referenced by number
function techage.get_node_info(dest_num)
return NodeInfoCache[dest_num] or update_nodeinfo(dest_num)
end
-- Function returns the node number from the given position or
-- nil, if no node number for this position is assigned.
function techage.get_node_number(pos)
return get_number(pos)
end
function techage.get_pos(pos, side)
local node = techage.get_node_lvm(pos)
local dir = nil
if node.name ~= "air" and node.name ~= "ignore" then
dir = side_to_dir(side, node.param2)
end
return tubelib2.get_pos(pos, dir)
end
-- Function is used for available nodes with lost numbers, only.
function techage.get_new_number(pos, name)
-- store position
return get_number(pos, true)
end
-- extract ident and value from strings like "ident=value"
function techage.ident_value(s)
local ident, value = unpack(string.split(s, "=", true, 1))
return (ident or ""):trim(), (value or ""):trim()
end
-------------------------------------------------------------------
-- Node construction/destruction functions
-------------------------------------------------------------------
-- Add node to the techage lists.
-- Function determines and returns the node position number,
-- needed for message communication.
-- If TA2 node, return '-' instead of a real number, because
-- TA2 nodes should not support number based commands.
function techage.add_node(pos, name, is_ta2)
if item_handling_node(name) then
Tube:after_place_node(pos)
end
if is_ta2 then
return "-"
end
local key = minetest.hash_node_position(pos)
local num = NumbersToBeRecycled[key]
if num then
NodeInfoCache[num] = nil
backend.set_nodepos(num, pos)
NumbersToBeRecycled[key] = nil
return num
end
return get_number(pos, true)
end
-- Function removes the node from the techage lists.
function techage.remove_node(pos, oldnode, oldmetadata)
local number = oldmetadata and oldmetadata.fields and (oldmetadata.fields.node_number or oldmetadata.fields.number)
number = number or get_number(pos)
if number and tonumber(number) then
local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = number
NodeInfoCache[number] = nil
end
if oldnode and item_handling_node(oldnode.name) then
Tube:after_dig_node(pos)
end
end
-- Repairs the node number after it was erased by `backend.delete_invalid_entries`
function techage.repair_number(pos)
local number = techage.get_node_number(pos)
if number then
backend.set_nodepos(number, pos)
end
end
-- Like techage.add_node, but use the old number again
function techage.unpack_node(pos, name, number)
if item_handling_node(name) then
Tube:after_place_node(pos)
end
local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = nil
if number then
backend.set_nodepos(number, pos)
end
end
-- Like techage.remove_node but don't store the number for this position
function techage.pack_node(pos, oldnode, number)
if number then
NodeInfoCache[number] = nil
end
if oldnode and item_handling_node(oldnode.name) then
Tube:after_dig_node(pos)
end
end
-------------------------------------------------------------------
-- Used by the assembly tool
-------------------------------------------------------------------
function techage.pre_add_node(pos, number)
local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = number
end
function techage.post_remove_node(pos)
local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = nil
end
-------------------------------------------------------------------
-- Node register function
-------------------------------------------------------------------
-- Register node for techage communication
-- Call this function only at load time!
-- Param names: List of node names like {"techage:pusher_off", "techage:pusher_on"}
-- Param node_definition: A table according to:
-- {
-- on_inv_request = func(pos, in_dir, access_type)
-- on_pull_item = func(pos, in_dir, num, (opt.) item_name),
-- on_push_item = func(pos, in_dir, item),
-- on_unpull_item = func(pos, in_dir, item),
-- on_recv_message = func(pos, src, topic, payload),
-- on_node_load = func(pos), -- LBM function
-- on_transfer = func(pos, in_dir, topic, payload),
-- }
function techage.register_node(names, node_definition)
-- store facedir table for all known node names
for _,n in ipairs(names) do
NodeDef[n] = node_definition
end
if node_definition.on_pull_item or node_definition.on_push_item or
node_definition.is_pusher then
Tube:add_secondary_node_names(names)
for _,n in ipairs(names) do
techage.KnownNodes[n] = true
end
end
-- register LBM
if node_definition.on_node_load then
register_lbm(names[1], names)
end
-- register mvps stopper
if has_mesecons then
for _, name in ipairs(names) do
mesecon.register_mvps_stopper(name)
end
end
end
-------------------------------------------------------------------
-- Send message functions
-------------------------------------------------------------------
function techage.not_protected(number, placer_name, clicker_name)
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
if ninfo and ninfo.pos then
return not_protected(ninfo.pos, placer_name, clicker_name)
end
return false
end
-- Check the given number value.
-- Returns true if the number is valid, point to real node and
-- and the node is not protected for the given player_name.
function techage.check_number(number, placer_name)
if number then
if not techage.not_protected(number, placer_name, nil) then
return false
end
return true
end
return false
end
-- Check the given list of numbers.
-- Returns true if number(s) is/are valid, point to real nodes and
-- and the nodes are not protected for the given player_name.
function techage.check_numbers(numbers, placer_name)
if numbers then
for _,num in ipairs(string_split(numbers, " ")) do
if not techage.not_protected(num, placer_name, nil) then
return false
end
end
return true
end
return false
end
function techage.send_multi(src, numbers, topic, payload)
--print("send_multi", src, numbers, topic)
for _,num in ipairs(string_split(numbers, " ")) do
local ninfo = NodeInfoCache[num] or update_nodeinfo(num)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_recv_message then
techage_counting_hit()
ndef.on_recv_message(ninfo.pos, src, topic, payload)
end
end
end
end
function techage.send_single(src, number, topic, payload)
--print("send_single", src, number, topic)
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_recv_message then
techage_counting_hit()
return ndef.on_recv_message(ninfo.pos, src, topic, payload)
end
end
return false
end
-- The destination node location is either:
-- A) a destination position, specified by pos
-- B) a neighbor position, specified by caller pos/outdir, or pos/side
-- C) a tubelib2 network connection, specified by caller pos/outdir, or pos/side
-- outdir is one of: 1..6
-- side is one of: "B", "R", "F", "L", "D", "U"
-- network is a tuebelib2 network instance
-- opt: nodenames is a table of valid the callee node names
function techage.transfer(pos, outdir, topic, payload, network, nodenames)
-- determine out-dir
if outdir and type(outdir) == "string" then
local param2 = techage.get_node_lvm(pos).param2
outdir = side_to_dir(outdir, param2)
end
-- determine destination pos
local dpos, indir
if network then
dpos, indir = network:get_connected_node_pos(pos, outdir)
else
dpos, indir = tubelib2.get_pos(pos, outdir), outdir
end
-- check node name
local name = techage.get_node_lvm(dpos).name
if nodenames and not in_list(nodenames, name) then
return false
end
-- call "on_transfer"
local ndef = NodeDef[name]
if ndef and ndef.on_transfer then
return ndef.on_transfer(dpos, indir, topic, payload)
end
return false
end
-------------------------------------------------------------------
-- Beduino functions (see "bep-005_ta_cmnd.md")
-------------------------------------------------------------------
function techage.beduino_send_cmnd(src, number, topic, payload)
--print("beduino_send_cmnd", src, number, topic)
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_beduino_receive_cmnd then
techage_counting_hit()
return ndef.on_beduino_receive_cmnd(ninfo.pos, src, topic, payload or {})
end
end
return 1, ""
end
function techage.beduino_request_data(src, number, topic, payload)
--print("beduino_request_data", src, number, topic)
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_beduino_request_data then
techage_counting_hit()
return ndef.on_beduino_request_data(ninfo.pos, src, topic, payload or {})
end
end
return 1, ""
end
-------------------------------------------------------------------
-- Client side Push/Pull item functions
-------------------------------------------------------------------
function techage.get_inv_access(pos, out_dir, access_type)
local npos, in_dir, name = get_dest_node(pos, out_dir)
if npos and NodeDef[name] and NodeDef[name].on_inv_request then
return NodeDef[name].on_inv_request(npos, in_dir, access_type)
end
end
function techage.pull_items(pos, out_dir, num, item_name)
local npos, in_dir, name = get_dest_node(pos, out_dir)
if npos and NodeDef[name] and NodeDef[name].on_pull_item then
return NodeDef[name].on_pull_item(npos, in_dir, num, item_name)
end
end
function techage.push_items(pos, out_dir, stack, idx)
local npos, in_dir, name = get_dest_node(pos, out_dir)
if npos and NodeDef[name] and NodeDef[name].on_push_item then
return NodeDef[name].on_push_item(npos, in_dir, stack, idx)
elseif is_air_like(name) or is_cart_available(npos) then
minetest.add_item(npos, stack)
return true
end
return stack
end
-- Check for recursion and too long distances
local start_pos
function techage.safe_push_items(pos, out_dir, stack, idx)
local mem = techage.get_mem(pos)
if not mem.pushing then
if not start_pos then
start_pos = pos
mem.pushing = true
local res = techage.push_items(pos, out_dir, stack, idx)
mem.pushing = nil
start_pos = nil
return res
else
local npos, in_dir, name = get_dest_node(pos, out_dir)
if vector.distance(start_pos, npos) < (Tube.max_tube_length or 100) then
mem.pushing = true
local res = techage.push_items(pos, out_dir, stack, idx)
mem.pushing = nil
return res
end
end
end
return stack
end
function techage.unpull_items(pos, out_dir, stack)
local npos, in_dir, name = get_dest_node(pos, out_dir)
if npos and NodeDef[name] and NodeDef[name].on_unpull_item then
return NodeDef[name].on_unpull_item(npos, in_dir, stack)
end
return false
end
-------------------------------------------------------------------
-- Server side helper functions
-------------------------------------------------------------------
-- Get the given number of items from the inv. The position within the list
-- is incremented each time so that different item stacks will be considered.
-- Returns nil if ItemList is empty.
function techage.get_items(pos, inv, listname, num)
if inv:is_empty(listname) then
return nil
end
local size = inv:get_size(listname)
local mem = techage.get_mem(pos)
mem.ta_startpos = mem.ta_startpos or 0
for idx = mem.ta_startpos, mem.ta_startpos+size do
idx = (idx % size) + 1
local items = inv:get_stack(listname, idx)
if items:get_count() > 0 then
local taken = items:take_item(num)
inv:set_stack(listname, idx, items)
mem.ta_startpos = idx
return taken
end
end
return nil
end
-- Put the given stack into the given ItemList/inventory.
-- Function returns:
-- - true, if all items are moved
-- - false, if no item is moved
-- - leftover, if less than all items are moved
-- (true/false is the legacy mode and can't be removed)
function techage.put_items(inv, listname, item, idx)
local leftover
if idx and inv and idx <= inv:get_size(listname) then
local stack = inv:get_stack(listname, idx)
leftover = stack:add_item(item)
inv:set_stack(listname, idx, stack)
elseif inv then
leftover = inv:add_item(listname, item)
else
return false
end
local cnt = leftover:get_count()
if cnt == item:get_count() then
return false
elseif cnt == 0 then
return true
else
return leftover
end
end
-- Return "full", "loaded", or "empty" depending
-- on the inventory load.
-- Full is returned, when no empty stack is available.
function techage.get_inv_state(inv, listname)
local state
if inv:is_empty(listname) then
state = "empty"
else
local list = inv:get_list(listname)
state = "full"
for _, item in ipairs(list) do
if item:is_empty() then
return "loaded"
end
end
end
return state
end
-- Beduino variant
function techage.get_inv_state_num(inv, listname)
local state
if inv:is_empty(listname) then
state = 0
else
local list = inv:get_list(listname)
state = 2
for _, item in ipairs(list) do
if item:is_empty() then
return 1
end
end
end
return state
end
minetest.register_chatcommand("ta_send", {
description = minetest.formspec_escape(
"Send a techage command to the block with the number given: /ta_send <number> <command> [<data>]"),
func = function(name, param)
local num, cmnd, payload = param:match('^([0-9]+)%s+(%w+)%s*(.*)$')
if num and cmnd then
if techage.not_protected(num, name) then
local resp = techage.send_single("0", num, cmnd, payload)
if type(resp) == "string" then
return true, resp
else
return true, dump(resp)
end
else
return false, "Destination block is protected"
end
end
return false, "Syntax: /ta_send <number> <command> [<data>]"
end
})
minetest.register_chatcommand("expoints", {
privs = {
server = true
},
func = function(name, param)
local player_name, points = param:match("^(%S+)%s*(%d*)$")
if player_name then
local player = minetest.get_player_by_name(player_name)
if player then
if points and points ~= "" then
if techage.set_expoints(player, tonumber(points)) then
return true, "The player "..player_name.." now has "..points.." experience points."
end
else
points = techage.get_expoints(player)
return true, "The player "..player_name.." has "..points.." experience points."
end
else
return false, "Unknown player "..player_name
end
end
return false, "Syntax error! Syntax: /expoints <name> [<points>]"
end
})
minetest.register_chatcommand("my_expoints", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then
local points = techage.get_expoints(player)
if points then
return true, "You have "..points.." experience points."
end
end
end
})

View File

@ -1,118 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Configured inventory lib
Assuming the inventory has the name "conf"
Otherwise the name has to be provided as argument
]]--
local StackName = ... or "conf"
-- for lazy programmers
local M = minetest.get_meta
local inv_lib = {}
function inv_lib.preassigned_stacks(pos, xsize, ysize)
local inv = M(pos):get_inventory()
local tbl = {}
for idx = 1, xsize * ysize do
local item_name = inv:get_stack(StackName, idx):get_name()
if item_name ~= "" then
local x = (idx - 1) % xsize
local y = math.floor((idx - 1) / xsize)
tbl[#tbl+1] = "item_image["..x..","..y..";1,1;"..item_name.."]"
end
end
return table.concat(tbl, "")
end
function inv_lib.item_filter(pos, size)
local inv = M(pos):get_inventory()
local filter = {}
for idx = 1, size do
local item_name = inv:get_stack(StackName, idx):get_name()
if item_name == "" then item_name = "unconfigured" end
if not filter[item_name] then
filter[item_name] = {}
end
table.insert(filter[item_name], idx)
end
return filter
end
function inv_lib.allow_conf_inv_put(pos, listname, index, stack, player)
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
if list[index]:get_count() == 0 then
stack:set_count(1)
inv:set_stack(listname, index, stack)
return 0
end
return 0
end
function inv_lib.allow_conf_inv_take(pos, listname, index, stack, player)
local inv = M(pos):get_inventory()
inv:set_stack(listname, index, nil)
return 0
end
function inv_lib.allow_conf_inv_move(pos, from_list, from_index, to_list, to_index, count, player)
local inv = minetest.get_meta(pos):get_inventory()
local stack = inv:get_stack(to_list, to_index)
if stack:get_count() == 0 then
return 1
else
return 0
end
end
function inv_lib.put_items(pos, inv, listname, item, stacks, idx)
local name = item:get_name()
local count = item:get_count()
for _, i in ipairs(stacks or {}) do
if not idx or idx == i then
local stack = inv:get_stack(listname, i)
local leftover = stack:add_item({name = name, count = count})
count = leftover:get_count()
inv:set_stack(listname, i, stack)
if count == 0 then
return true
end
end
end
if count > 0 then
return ItemStack({name = name, count = count})
end
return false
end
function inv_lib.take_item(pos, inv, listname, num, stacks)
local mem = techage.get_mem(pos)
mem.ta_startpos = mem.ta_startpos or 1
local size = #(stacks or {})
for i = 1, size do
local idx = stacks[((i + mem.ta_startpos) % size) + 1]
local stack = inv:get_stack(listname, idx)
local taken = stack:take_item(num)
if taken:get_count() > 0 then
inv:set_stack(listname, idx, stack)
mem.ta_startpos = mem.ta_startpos + i
return taken
end
end
end
return inv_lib

View File

@ -1,71 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Count techage commands player related
]]--
local PlayerName
local PlayerPoints = {}
local LastPlayerPoints = {}
local S = techage.S
local MAX_POINTS = tonumber(minetest.settings:get("techage_command_limit")) or 1200
function techage.counting_start(player_name)
PlayerName = player_name
PlayerPoints[PlayerName] = PlayerPoints[PlayerName] or 0
end
function techage.counting_stop()
PlayerName = nil
end
function techage.counting_hit()
if PlayerName then
PlayerPoints[PlayerName] = PlayerPoints[PlayerName] + 1
end
end
function techage.counting_add(player_name, points)
PlayerPoints[player_name] = (PlayerPoints[player_name] or 0) + points
end
local function output()
for name, val in pairs(PlayerPoints) do
if val > MAX_POINTS then
local obj = minetest.get_player_by_name(name)
if obj then
minetest.chat_send_player(name,
S("[techage] The limit for 'number of commands per minute' has been exceeded.") ..
" " .. string.format(MAX_POINTS .. " " .. S("is allowed. Current value is") .. " " .. val));
minetest.log("action", "[techage] " .. name ..
" exceeds the limit for commands per minute. value = " .. val)
local factor = 100 / (obj:get_armor_groups().fleshy or 100)
obj:punch(obj, 1.0, {full_punch_interval=1.0, damage_groups = {fleshy=factor * 5}})
end
end
end
LastPlayerPoints = table.copy(PlayerPoints)
PlayerPoints = {}
minetest.after(60, output)
end
minetest.after(60, output)
minetest.register_chatcommand("ta_limit", {
description = "Get your current techage command limit value",
func = function(name)
local num = LastPlayerPoints[name] or 0
return true, S("Your current value is") .. " " .. num .. " " .. S("per minute") .. ". " ..
MAX_POINTS .. " " .. S("is allowed")
end
})

View File

@ -1,117 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2020 Thomas S.
AGPL v3
See LICENSE.txt for more information
Fake Player
]]--
-- Map method names to their return values
local methods = {
get_pos = { x = 0, y = 0, z = 0 },
set_pos = nil,
moveto = nil,
punch = nil,
right_click = nil,
get_hp = 20,
set_hp = nil,
get_inventory = nil,
get_wield_list = "",
get_wield_index = 0,
get_wielded_item = ItemStack(),
set_wielded_item = true,
set_armor_groups = nil,
get_armor_groups = {},
set_animation = nil,
get_animation = {},
set_animation_frame_speed = nil,
set_attach = nil,
get_attach = nil,
set_detach = nil,
get_bone_position = {},
set_properties = nil,
get_properties = {},
is_player = false,
get_nametag_attributes = {},
set_nametag_attributes = nil,
get_player_name = "",
get_player_velocity = nil,
add_player_velocity = nil,
get_look_dir = vector.new(0, 0, 1),
get_look_vertical = 0,
get_look_horizontal = 0,
set_look_vertical = nil,
set_look_horizontal = nil,
get_look_pitch = 0,
get_look_yaw = 0,
set_look_pitch = nil,
set_look_yaw = nil,
get_breath = 10,
set_breath = nil,
set_fov = nil,
get_fov = 0,
set_attribute = nil,
get_attribute = nil,
get_meta = nil,
set_inventory_formspec = nil,
get_inventory_formspec = "",
set_formspec_prepend = nil,
get_formspec_prepend = "",
get_player_control = {},
get_player_control_bits = 0,
set_physics_override = nil,
get_physics_override = {},
hud_add = 0,
hud_remove = nil,
hud_change = nil,
hud_get = {},
hud_set_flags = nil,
hud_get_flags = {},
hud_set_hotbar_itemcount = nil,
hud_get_hotbar_itemcount = 8,
hud_set_hotbar_image = nil,
hud_get_hotbar_image = "",
hud_set_hotbar_selected_image = nil,
hud_get_hotbar_selected_image = "",
set_sky = nil,
get_sky = {},
get_sky_color = {},
set_sun = nil,
get_sun = {},
set_moon = nil,
get_moon = {},
set_stars = nil,
get_stars = {},
set_clouds = nil,
get_clouds = {},
override_day_night_ratio = nil,
get_day_night_ratio = nil,
set_local_animation = nil,
get_local_animation = {},
set_eye_offset = nil,
get_eye_offset = {},
send_mapblock = nil,
}
techage.Fake_player = {}
techage.Fake_player.__index = techage.Fake_player
function techage.Fake_player:new()
local fake_player = {}
setmetatable(fake_player, techage.Fake_player)
return fake_player
end
for method_name, return_value in pairs(methods) do
techage.Fake_player[method_name] = function(self, ...)
return return_value
end
end

View File

@ -1,150 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Firebox basic functions
]]--
-- for lazy programmers
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
techage.firebox = {}
techage.firebox.Burntime = {
["techage:charcoal"] = 1, -- will be replaced by burntime
["default:coal_lump"] = 1,
["default:coalblock"] = 1,
["techage:oil_source"] = 1,
["techage:gas"] = 1,
["techage:gasoline"] = 1,
["techage:naphtha"] = 1,
["techage:fueloil"] = 1,
}
techage.firebox.ValidOilFuels = {
["techage:gasoline"] = 1, -- category
["techage:naphtha"] = 2,
["techage:fueloil"] = 3,
["techage:oil_source"] = 4,
}
local function determine_burntimes()
for k,_ in pairs(techage.firebox.Burntime)do
local fuel,_ = minetest.get_craft_result({method = "fuel", width = 1, items = {k}})
techage.firebox.Burntime[k] = fuel.time
end
end
minetest.register_on_mods_loaded(determine_burntimes)
function techage.firebox.formspec(nvm)
local fuel_percent = 0
if nvm.running then
fuel_percent = ((nvm.burn_cycles or 1) * 100) / (nvm.burn_cycles_total or 1)
end
return "size[8,6]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3,-0.1;"..minetest.colorize( "#000000", S("Firebox")).."]"..
"list[current_name;fuel;3,1;1,1;]"..
"image[4,1;1,1;default_furnace_fire_bg.png^[lowpart:"..
fuel_percent..":default_furnace_fire_fg.png]"..
"list[current_player;main;0,2.3;8,4;]"..
"listring[current_name;fuel]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 2.3)
end
function techage.firebox.can_dig(pos, player)
local inv = M(pos):get_inventory()
return inv:is_empty("fuel")
end
function techage.firebox.allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if techage.firebox.Burntime[stack:get_name()] then
return stack:get_count()
end
return 0
end
function techage.firebox.allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
function techage.firebox.on_rightclick(pos, node, clicker)
local nvm = techage.get_nvm(pos)
techage.set_activeformspec(pos, clicker)
M(pos):set_string("formspec", techage.firebox.formspec(nvm))
end
function techage.firebox.swap_node(pos, name)
local node = techage.get_node_lvm(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
function techage.firebox.get_fuel(pos)
local inv = M(pos):get_inventory()
local items = inv:get_stack("fuel", 1)
if items:get_count() > 0 then
local taken = items:take_item(1)
inv:set_stack("fuel", 1, items)
return taken
end
end
function techage.firebox.has_fuel(pos)
local inv = M(pos):get_inventory()
local items = inv:get_stack("fuel", 1)
return items:get_count() > 0
end
function techage.firebox.is_free_position(pos, player_name)
local pos2 = techage.get_pos(pos, 'F')
if minetest.is_protected(pos2, player_name) then
minetest.chat_send_player(player_name, S("[TA] Area is protected!"))
return false
end
local node = techage.get_node_lvm(pos2)
local ndef = minetest.registered_nodes[node.name]
if not ndef or not ndef.buildable_to then
minetest.chat_send_player(player_name, S("[TA] Not enough space!"))
return false
end
return true
end
function techage.firebox.set_firehole(pos, on)
local param2 = techage.get_node_lvm(pos).param2
local pos2 = techage.get_pos(pos, 'F')
if on == true then
minetest.swap_node(pos2, {name="techage:coalfirehole_on", param2 = param2})
elseif on == false then
minetest.swap_node(pos2, {name="techage:coalfirehole", param2 = param2})
else
local node = techage.get_node_lvm(pos2)
if node.name == "techage:coalfirehole" or node.name == "techage:coalfirehole_on" then
minetest.swap_node(pos2, {name="air"})
end
end
end

View File

@ -1,955 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Block fly/move library
]]--
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local S = techage.S
local flylib = {}
local function lvect_add_vec(lvect1, offs)
if not lvect1 or not offs then return end
local lvect2 = {}
for _, v in ipairs(lvect1) do
lvect2[#lvect2 + 1] = vector.add(v, offs)
end
return lvect2
end
-- yaw in radiant
local function rotate(v, yaw)
local sinyaw = math.sin(yaw)
local cosyaw = math.cos(yaw)
return {x = v.x * cosyaw - v.z * sinyaw, y = v.y, z = v.x * sinyaw + v.z * cosyaw}
end
-- playername is needed for carts, to attach the player to the cart entity
local function set_node(item, playername)
local dest_pos = item.dest_pos
local name = item.name or "air"
local param2 = item.param2 or 0
local nvm = techage.get_nvm(item.base_pos)
local node = techage.get_node_lvm(dest_pos)
local ndef1 = minetest.registered_nodes[name]
local ndef2 = minetest.registered_nodes[node.name]
nvm.running = false
M(item.base_pos):set_string("status", S("Stopped"))
if ndef1 and ndef2 then
if minecart.is_cart(name) and (minecart.is_rail(dest_pos, node.name) or minecart.is_cart(name)) then
local player = playername and minetest.get_player_by_name(playername)
minecart.place_and_start_cart(dest_pos, {name = name, param2 = param2}, item.cartdef, player)
return
elseif ndef2.buildable_to then
local meta = M(dest_pos)
if name ~= "techage:moveblock" then
minetest.set_node(dest_pos, {name=name, param2=param2})
meta:from_table(item.metadata or {})
meta:set_string("ta_move_block", "")
meta:set_int("ta_door_locked", 1)
end
return
end
local meta = M(dest_pos)
if not meta:contains("ta_move_block") then
meta:set_string("ta_move_block", minetest.serialize({name=name, param2=param2}))
return
end
elseif ndef1 then
if name ~= "techage:moveblock" then
minetest.add_item(dest_pos, ItemStack(name))
end
end
end
-------------------------------------------------------------------------------
-- Entity monitoring
-------------------------------------------------------------------------------
local queue = {}
local first = 0
local last = -1
local function push(item)
last = last + 1
queue[last] = item
end
local function pop()
if first > last then return end
local item = queue[first]
queue[first] = nil -- to allow garbage collection
first = first + 1
return item
end
local function monitoring()
local num = last - first + 1
for _ = 1, num do
local item = pop()
if item.ttl >= techage.SystemTime then
-- still valud
push(item)
elseif item.ttl ~= 0 then
set_node(item)
end
end
minetest.after(1, monitoring)
end
minetest.after(1, monitoring)
minetest.register_on_shutdown(function()
local num = last - first + 1
for _ = 1, num do
local item = pop()
if item.ttl ~= 0 then
set_node(item)
end
end
end)
local function monitoring_add_entity(item)
item.ttl = techage.SystemTime + 1
push(item)
end
local function monitoring_del_entity(item)
-- Mark as timed out
item.ttl = 0
end
local function monitoring_trigger_entity(item)
item.ttl = techage.SystemTime + 1
end
-------------------------------------------------------------------------------
-- to_path function for the fly/move path
-------------------------------------------------------------------------------
local function strsplit(text)
text = text:gsub("\r\n", "\n")
text = text:gsub("\r", "\n")
return string.split(text, "\n", true)
end
local function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function flylib.distance(v)
return math.abs(v.x) + math.abs(v.y) + math.abs(v.z)
end
function flylib.to_vector(s, max_dist)
local x,y,z = unpack(string.split(s, ","))
x = tonumber(x) or 0
y = tonumber(y) or 0
z = tonumber(z) or 0
if x and y and z then
if not max_dist or (math.abs(x) + math.abs(y) + math.abs(z)) <= max_dist then
return {x = x, y = y, z = z}
end
end
end
function flylib.to_path(s, max_dist)
local tPath
local dist = 0
for _, line in ipairs(strsplit(s or "")) do
line = trim(line)
line = string.split(line, "--", true, 1)[1] or ""
if line ~= "" then
local v = flylib.to_vector(line)
if v then
dist = dist + flylib.distance(v)
if not max_dist or dist <= max_dist then
tPath = tPath or {}
tPath[#tPath + 1] = v
else
return tPath, S("Error: Max. length of the flight route exceeded by @1 blocks !!", dist - max_dist)
end
else
return tPath, S("Error: Invalid path !!")
end
end
end
return tPath
end
local function next_path_pos(pos, lpath, idx)
local offs = lpath[idx]
if offs then
return vector.add(pos, offs)
end
end
local function reverse_path(lpath)
local lres = {}
for i = #lpath, 1, -1 do
lres[#lres + 1] = vector.multiply(lpath[i], -1)
end
return lres
end
local function dest_offset(lpath)
local offs = {x=0, y=0, z=0}
for i = 1,#lpath do
offs = vector.add(offs, lpath[i])
end
return offs
end
-------------------------------------------------------------------------------
-- Protect the doors from being opened by hand
-------------------------------------------------------------------------------
local function new_on_rightclick(old_on_rightclick)
return function(pos, node, clicker, itemstack, pointed_thing)
if M(pos):contains("ta_door_locked") then
return itemstack
end
if old_on_rightclick then
return old_on_rightclick(pos, node, clicker, itemstack, pointed_thing)
else
return itemstack
end
end
end
function flylib.protect_door_from_being_opened(name)
-- Change on_rightclick function.
local ndef = minetest.registered_nodes[name]
if ndef then
local old_on_rightclick = ndef.on_rightclick
minetest.override_item(ndef.name, {
on_rightclick = new_on_rightclick(old_on_rightclick)
})
end
end
-------------------------------------------------------------------------------
-- Entity / Move / Attach / Detach
-------------------------------------------------------------------------------
local MIN_SPEED = 0.4
local MAX_SPEED = 8
local CORNER_SPEED = 4
local function calc_speed(v)
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
end
-- Only the ID ist stored, not the object
local function get_object_id(object)
for id, entity in pairs(minetest.luaentities) do
if entity.object == object then
return id
end
end
end
-- determine exact position of attached entities
local function obj_pos(obj)
local _, _, pos = obj:get_attach()
if pos then
pos = vector.divide(pos, 29)
return vector.add(obj:get_pos(), pos)
end
end
-- Check access conflicts with other mods
local function lock_player(player)
local meta = player:get_meta()
if meta:get_int("player_physics_locked") == 0 then
meta:set_int("player_physics_locked", 1)
meta:set_string("player_physics_locked_by", "ta_flylib")
return true
end
return false
end
local function unlock_player(player)
local meta = player:get_meta()
if meta:get_int("player_physics_locked") == 1 then
if meta:get_string("player_physics_locked_by") == "ta_flylib" then
meta:set_int("player_physics_locked", 0)
meta:set_string("player_physics_locked_by", "")
return true
end
end
return false
end
local function detach_player(player)
local pos = obj_pos(player)
if pos then
player:set_detach()
player:set_properties({visual_size = {x=1, y=1}})
player:set_pos(pos)
end
-- TODO: move to save position
end
-- Attach player/mob to given parent object (block)
local function attach_single_object(parent, obj, distance)
local self = parent:get_luaentity()
local res = obj:get_attach()
if not res then -- not already attached
local yaw
if obj:is_player() then
yaw = obj:get_look_horizontal()
else
yaw = obj:get_rotation().y
end
-- store for later use
local offs = table.copy(distance)
-- Calc entity rotation, which is relative to the parent's rotation
local rot = parent:get_rotation()
if self.param2 >= 20 then
distance = rotate(distance, 2 * math.pi - rot.y)
distance.y = -distance.y
distance.x = -distance.x
rot.y = rot.y - yaw
elseif self.param2 < 4 then
distance = rotate(distance, 2 * math.pi - rot.y)
rot.y = rot.y - yaw
end
distance = vector.multiply(distance, 29)
obj:set_attach(parent, "", distance, vector.multiply(rot, 180 / math.pi))
obj:set_properties({visual_size = {x=2.9, y=2.9}})
if obj:is_player() then
if lock_player(obj) then
table.insert(self.players, {name = obj:get_player_name(), offs = offs})
end
else
table.insert(self.entities, {objID = get_object_id(obj), offs = offs})
end
end
end
-- Attach all objects around to the parent object
-- offs is the search/attach position offset
-- distance (optional) is the attach distance to the center of the entity
local function attach_objects(pos, offs, parent, yoffs, distance)
local pos1 = vector.add(pos, offs)
for _, obj in pairs(minetest.get_objects_inside_radius(pos1, 0.9)) do
-- keep relative object position
distance = distance or vector.subtract(obj:get_pos(), pos)
local entity = obj:get_luaentity()
if entity then
local mod = entity.name:gmatch("(.-):")()
if techage.RegisteredMobsMods[mod] then
distance.y = distance.y + yoffs
attach_single_object(parent, obj, distance)
end
elseif obj:is_player() then
attach_single_object(parent, obj, distance)
end
end
end
-- Detach all attached objects from the parent object
local function detach_objects(pos, self)
for _, item in ipairs(self.entities or {}) do
local entity = minetest.luaentities[item.objID]
if entity then
local obj = entity.object
obj:set_detach()
obj:set_properties({visual_size = {x=1, y=1}})
local pos1 = vector.add(pos, item.offs)
pos1.y = pos1.y - (self.yoffs or 0)
obj:set_pos(pos1)
end
end
for _, item in ipairs(self.players or {}) do
local obj = minetest.get_player_by_name(item.name)
if obj then
obj:set_detach()
obj:set_properties({visual_size = {x=1, y=1}})
local pos1 = vector.add(pos, item.offs)
pos1.y = pos1.y + 0.1
obj:set_pos(pos1)
unlock_player(obj)
end
end
self.entities = {}
self.players = {}
end
local function entity_to_node(pos, obj)
local self = obj:get_luaentity()
if self and self.item then
local playername = self.players and self.players[1] and self.players[1].name
detach_objects(pos, self)
monitoring_del_entity(self.item)
minetest.after(0.1, obj.remove, obj)
set_node(self.item, playername)
end
end
-- Create a node entitiy.
-- * base_pos is controller block related
-- * start_pos and dest_pos are entity positions
local function node_to_entity(base_pos, start_pos, dest_pos)
local meta = M(start_pos)
local node, metadata, cartdef
node = techage.get_node_lvm(start_pos)
if minecart.is_cart(node.name) then
cartdef = minecart.remove_cart(start_pos)
elseif meta:contains("ta_move_block") then
-- Move-block stored as metadata
node = minetest.deserialize(meta:get_string("ta_move_block"))
metadata = {}
meta:set_string("ta_move_block", "")
meta:set_string("ta_block_locked", "true")
elseif not meta:contains("ta_block_locked") then
-- Block with other metadata
node = techage.get_node_lvm(start_pos)
metadata = meta:to_table()
minetest.after(0.1, minetest.remove_node, start_pos)
else
return
end
local obj = minetest.add_entity(start_pos, "techage:move_item")
if obj then
local self = obj:get_luaentity()
local rot = techage.facedir_to_rotation(node.param2)
obj:set_rotation(rot)
obj:set_properties({wield_item=node.name})
obj:set_armor_groups({immortal=1})
-- To be able to revert to node
self.param2 = node.param2
self.item = {
name = node.name,
param2 = node.param2,
metadata = metadata or {},
dest_pos = dest_pos,
base_pos = base_pos,
cartdef = cartdef,
}
monitoring_add_entity(self.item)
-- Prepare for attachments
self.players = {}
self.entities = {}
-- Prepare for path walk
self.path_idx = 1
return obj, self.item.cartdef ~= nil
end
end
-- move block direction
local function determine_dir(pos1, pos2)
local vdist = vector.subtract(pos2, pos1)
local ndist = vector.length(vdist)
if ndist > 0 then
return vector.divide(vdist, ndist)
end
return {x=0, y=0, z=0}
end
local function move_entity(obj, next_pos, dir, is_corner)
local self = obj:get_luaentity()
self.next_pos = next_pos
self.dir = dir
if is_corner then
local vel = vector.multiply(dir, math.min(CORNER_SPEED, self.max_speed))
obj:set_velocity(vel)
end
local acc = vector.multiply(dir, self.max_speed / 2)
obj:set_acceleration(acc)
end
local function moveon_entity(obj, self, pos1)
local pos2 = next_path_pos(pos1, self.lmove, self.path_idx)
if pos2 then
self.path_idx = self.path_idx + 1
local dir = determine_dir(pos1, pos2)
move_entity(obj, pos2, dir, true)
return true
end
end
minetest.register_entity("techage:move_item", {
initial_properties = {
pointable = true,
makes_footstep_sound = true,
static_save = false,
collide_with_objects = false,
physical = false,
visual = "wielditem",
wield_item = "default:dirt",
visual_size = {x=0.67, y=0.67, z=0.67},
selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
on_step = function(self, dtime, moveresult)
local stop_obj = function(obj, self)
local next_pos = self.next_pos
obj:move_to(self.next_pos, true)
obj:set_acceleration({x=0, y=0, z=0})
obj:set_velocity({x=0, y=0, z=0})
self.next_pos = nil
self.old_dist = nil
return next_pos
end
if self.next_pos then
local obj = self.object
local pos = obj:get_pos()
local dist = vector.distance(pos, self.next_pos)
local speed = calc_speed(obj:get_velocity())
self.old_dist = self.old_dist or dist
if self.lmove and self.lmove[self.path_idx] then
local min_dist = math.min(1, self.max_speed / 8)
if dist < min_dist or dist > self.old_dist then
-- change of direction
local next_pos = stop_obj(obj, self)
if not moveon_entity(obj, self, next_pos) then
minetest.after(0.5, entity_to_node, next_pos, obj)
end
return
end
elseif dist < 0.05 or dist > self.old_dist then
-- Landing
local next_pos = stop_obj(obj, self)
local dest_pos = self.item.dest_pos or next_pos
minetest.after(0.5, entity_to_node, dest_pos, obj)
return
end
self.old_dist = dist
-- Braking or limit max speed
if speed > (dist * 2) or speed > self.max_speed then
speed = math.min(speed, math.max(dist * 2, MIN_SPEED))
local vel = vector.multiply(self.dir,speed)
obj:set_velocity(vel)
obj:set_acceleration({x=0, y=0, z=0})
end
monitoring_trigger_entity(self.item)
end
end,
})
local function is_valid_dest(pos)
local node = techage.get_node_lvm(pos)
if techage.is_air_like(node.name) then
return true
end
if minecart.is_rail(pos, node.name) or minecart.is_cart(node.name) then
return true
end
if not M(pos):contains("ta_move_block") then
return true
end
return false
end
local function is_simple_node(pos)
local node = techage.get_node_lvm(pos)
if not minecart.is_rail(pos, node.name) then
local ndef = minetest.registered_nodes[node.name]
return node.name ~= "air" and techage.can_dig_node(node.name, ndef) or minecart.is_cart(node.name)
end
end
-- Move node from 'pos1' to the destination, calculated by means of 'lmove'
-- * pos and meta are controller block related
-- * lmove is the movement as a list of `moves`
-- * height is move block height as value between 0 and 1 and used to calculate the offset
-- for the attached object (player).
local function move_node(pos, meta, pos1, lmove, max_speed, height)
local pos2 = next_path_pos(pos1, lmove, 1)
local offs = dest_offset(lmove)
local dest_pos = vector.add(pos1, offs)
-- optional for non-player objects
local yoffs = meta:get_float("offset")
if pos2 then
local dir = determine_dir(pos1, pos2)
local obj, is_cart = node_to_entity(pos, pos1, dest_pos)
if obj then
if is_cart then
attach_objects(pos1, 0, obj, yoffs, {x = 0, y = -0.4, z = 0})
else
local offs = {x=0, y=height or 1, z=0}
attach_objects(pos1, offs, obj, yoffs)
if dir.y == 0 then
if (dir.x ~= 0 and dir.z == 0) or (dir.x == 0 and dir.z ~= 0) then
attach_objects(pos1, dir, obj, yoffs)
end
end
end
local self = obj:get_luaentity()
self.path_idx = 2
self.lmove = lmove
self.max_speed = max_speed
self.yoffs = yoffs
move_entity(obj, pos2, dir)
return true
else
return false
end
end
end
--
-- Default Move Mode
--
-- Move the nodes from nvm.lpos1 to nvm.lpos2
-- * nvm.lpos1 is a list of nodes
-- * lmove is the movement as a list of `moves`
-- * pos, meta, and nvm are controller block related
--- height is move block height as value between 0 and 1 and used to calculate the offset
-- for the attached object (player).
local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1)
local owner = meta:get_string("owner")
techage.counting_add(owner, #lmove, #nvm.lpos1 * #lmove)
for idx = 1, #nvm.lpos1 do
local pos1 = nvm.lpos1[idx]
local pos2 = nvm.lpos2[idx]
--print("multi_move_nodes", idx, P2S(pos1), P2S(pos2))
if move2to1 then
pos1, pos2 = pos2, pos1
end
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
if is_simple_node(pos1) and is_valid_dest(pos2) then
if move_node(pos, meta, pos1, lmove, max_speed, height) == false then
meta:set_string("status", S("No valid node at the start position"))
return false
end
else
if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid node at the start position") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("No valid destination position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2))
end
return false
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Start position is protected") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("Destination position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2))
end
return false
end
end
meta:set_string("status", S("Running"))
return true
end
-- Move the nodes from lpos1 to lpos2.
-- * lpos1 is a list of nodes
-- * lpos2 = lpos1 + move
-- * pos and meta are controller block related
-- * height is move block height as value between 0 and 1 and used to calculate the offset
-- for the attached object (player).
local function move_nodes(pos, meta, lpos1, move, max_speed, height)
local owner = meta:get_string("owner")
lpos1 = lpos1 or {}
techage.counting_add(owner, #lpos1)
local lpos2 = {}
for idx = 1, #lpos1 do
local pos1 = lpos1[idx]
local pos2 = vector.add(lpos1[idx], move)
lpos2[idx] = pos2
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
if is_simple_node(pos1) and is_valid_dest(pos2) then
move_node(pos, meta, pos1, {move}, max_speed, height)
else
if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid node at the start position") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("No valid destination position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2))
end
return false, lpos1
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Start position is protected") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("Destination position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2))
end
return false, lpos1
end
end
meta:set_string("status", S("Running"))
return true, lpos2
end
--
-- Teleport Mode
--
local function is_player_available(lpos1)
if #lpos1 == 1 then
for _, obj in pairs(minetest.get_objects_inside_radius(lpos1[1], 0.9)) do
if obj:is_player() then
return true
end
end
end
end
local function teleport(base_pos, pos1, pos2, meta, owner, lmove, max_speed)
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
local node1 = techage.get_node_lvm(pos1)
local node2 = techage.get_node_lvm(pos2)
if techage.is_air_like(node1.name) and techage.is_air_like(node2.name) then
minetest.swap_node(pos1, {name = "techage:moveblock", param2 = 0})
if move_node(base_pos, meta, pos1, lmove, max_speed, 0) == false then
meta:set_string("status", S("No valid start position"))
return false
end
else
if not techage.is_air_like(node1.name) then
meta:set_string("status", S("No valid start position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid start position") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("No valid destination position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2))
end
return false
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Start position is protected") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("Destination position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2))
end
return false
end
meta:set_string("status", S("Running"))
return true
end
-- Move the player from nvm.lpos1 to nvm.lpos2
-- * nvm.lpos1 is a list of length one(!) with the not to be moved block below the player
-- * lmove is the movement as a list of `moves`
-- * pos, meta, and nvm are controller block related
local function multi_teleport_player(base_pos, meta, nvm, lmove, max_speed, move2to1)
local owner = meta:get_string("owner")
techage.counting_add(owner, #lmove, #nvm.lpos1 * #lmove)
local pos1 = vector.add(nvm.lpos1[1], {x=0, y=1, z=0})
local pos2 = vector.add(nvm.lpos2[1], {x=0, y=1, z=0})
if move2to1 then
pos1, pos2 = pos2, pos1
end
return teleport(base_pos, pos1, pos2, meta, owner, lmove, max_speed)
end
-- Move the player from lpos1 to lpos2.
-- * lpos1 is a list of length one(!) with the not to be moved block below the player
-- * lpos2 = lpos1 + move
-- * pos and meta are controller block related
local function teleport_player(base_pos, meta, lpos1, move, max_speed)
local owner = meta:get_string("owner")
lpos1 = lpos1 or {}
techage.counting_add(owner, #lpos1)
local pos1 = vector.add(lpos1[1], {x=0, y=1, z=0})
local pos2 = vector.add(pos1, move)
return teleport(base_pos, pos1, pos2, meta, owner, {move}, max_speed), nil
end
--------------------------------------------------------------------------------------
-- API
--------------------------------------------------------------------------------------
-- move2to1 is the direction and is true for 'from pos2 to pos1'
-- Move path and other data is stored as meta data of pos
function flylib.move_to_other_pos(pos, move2to1)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local lmove, err = flylib.to_path(meta:get_string("path")) or {}
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
local height = meta:contains("height") and meta:get_float("height") or 1
local teleport_mode = meta:get_string("teleport_mode") == "enable"
if err or nvm.running then return false end
height = techage.in_range(height, 0, 1)
max_speed = techage.in_range(max_speed, MIN_SPEED, MAX_SPEED)
nvm.lpos1 = nvm.lpos1 or {}
local offs = dest_offset(lmove)
if move2to1 then
lmove = reverse_path(lmove)
end
-- calc destination positions
nvm.lpos2 = lvect_add_vec(nvm.lpos1, offs)
local lpos = move2to1 and nvm.lpos2 or nvm.lpos1
if teleport_mode and is_player_available(lpos) then
nvm.running = multi_teleport_player(pos, meta, nvm, lmove, max_speed, move2to1)
elseif not teleport_mode then
nvm.running = multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1)
end
nvm.moveBA = nvm.running and not move2to1
return nvm.running
end
-- `move` the movement as a vector
function flylib.move_to(pos, move)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1)
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
local teleport_mode = meta:get_string("teleport_mode") == "enable"
if nvm.running then return false end
-- TODO: Not working so far. There is no known 'nvm.lastpos' as start pos.
--if teleport_mode and is_player_available(nvm.lpos1) then
-- nvm.running, nvm.lastpos = teleport_player(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed)
--elseif not teleport_mode then
nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height)
--end
return nvm.running
end
function flylib.reset_move(pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1)
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
if nvm.running then return false end
if meta:get_string("teleport_mode") == "enable" then return false end
if nvm.lpos1 and nvm.lpos1[1] then
local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos1)[1])
nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height)
return nvm.running
end
return false
end
-- pos is the controller block pos
-- lpos is a list of node positions to be moved
-- rot is one of "l", "r", "2l", "2r"
function flylib.rotate_nodes(pos, lpos, rot)
local meta = M(pos)
local owner = meta:get_string("owner")
-- cpos is the center pos
local cpos = meta:contains("center") and flylib.to_vector(meta:get_string("center"))
local lpos2 = techage.rotate_around_center(lpos, rot, cpos)
local param2
local nodes2 = {}
techage.counting_add(owner, #lpos * 2)
for i, pos1 in ipairs(lpos) do
local node = techage.get_node_lvm(pos1)
if rot == "l" then
param2 = techage.param2_turn_right(node.param2)
elseif rot == "r" then
param2 = techage.param2_turn_left(node.param2)
else
param2 = techage.param2_turn_right(techage.param2_turn_right(node.param2))
end
if not minetest.is_protected(pos1, owner) and is_simple_node(pos1) then
minetest.remove_node(pos1)
nodes2[#nodes2 + 1] = {pos = lpos2[i], name = node.name, param2 = param2}
end
end
for _,item in ipairs(nodes2) do
if not minetest.is_protected(item.pos, owner) and is_valid_dest(item.pos) then
minetest.add_node(item.pos, {name = item.name, param2 = item.param2})
end
end
return lpos2
end
function flylib.exchange_node(pos, name, param2)
local meta = M(pos)
local move_block
-- consider stored "objects"
if meta:contains("ta_move_block") then
move_block = meta:get_string("ta_move_block")
end
minetest.swap_node(pos, {name = name, param2 = param2})
if move_block then
meta:set_string("ta_move_block", move_block)
end
end
function flylib.remove_node(pos)
local meta = M(pos)
local move_block
-- consider stored "objects"
if meta:contains("ta_move_block") then
move_block = meta:get_string("ta_move_block")
end
minetest.remove_node(pos)
if move_block then
local node = minetest.deserialize(move_block)
minetest.add_node(pos, node)
meta:set_string("ta_move_block", "")
end
end
minetest.register_on_joinplayer(function(player)
unlock_player(player)
end)
minetest.register_on_leaveplayer(function(player)
if unlock_player(player) then
detach_player(player)
end
end)
minetest.register_on_dieplayer(function(player)
if unlock_player(player) then
detach_player(player)
end
end)
techage.flylib = flylib

View File

@ -1,52 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Keep only one formspec active per player
]]--
local P2S = minetest.pos_to_string
local ActiveFormspecs = {}
local ActivePlayer = {}
function techage.is_activeformspec(pos)
return ActiveFormspecs[P2S(pos)]
end
function techage.set_activeformspec(pos, player)
local name = player and player:get_player_name()
if name then
if ActivePlayer[name] then
ActiveFormspecs[ActivePlayer[name]] = nil
end
ActivePlayer[name] = P2S(pos)
ActiveFormspecs[P2S(pos)] = true
end
end
function techage.reset_activeformspec(pos, player)
local name = player and player:get_player_name()
if name then
if ActivePlayer[name] then
ActiveFormspecs[ActivePlayer[name]] = nil
ActivePlayer[name] = nil
end
end
end
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
if ActivePlayer[name] then
ActiveFormspecs[ActivePlayer[name]] = nil
ActivePlayer[name] = nil
end
end)

View File

@ -1,197 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Oil fuel burning lib
]]--
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.LiquidPipe
local liquid = networks.liquid
local ValidOilFuels = techage.firebox.ValidOilFuels
local Burntime = techage.firebox.Burntime
techage.fuel = {}
local CAPACITY = 50
local BLOCKING_TIME = 0.3 -- 300ms
techage.fuel.CAPACITY = CAPACITY
-- fuel burning categories (equal or better than...)
techage.fuel.BT_BITUMEN = 5
techage.fuel.BT_OIL = 4
techage.fuel.BT_FUELOIL = 3
techage.fuel.BT_NAPHTHA = 2
techage.fuel.BT_GASOLINE = 1
function techage.fuel.fuel_container(x, y, nvm)
local itemname = ""
if nvm.liquid and nvm.liquid.name and nvm.liquid.amount and nvm.liquid.amount > 0 then
itemname = nvm.liquid.name.." "..nvm.liquid.amount
end
local fuel_percent = 0
if nvm.running or techage.is_running(nvm) then
fuel_percent = ((nvm.burn_cycles or 1) * 100) / (nvm.burn_cycles_total or 1)
end
return "container["..x..","..y.."]"..
"box[0,0;1.05,2.1;#000000]"..
"image[0.1,0.1;1,1;default_furnace_fire_bg.png^[lowpart:"..
fuel_percent..":default_furnace_fire_fg.png]"..
techage.item_image(0.1, 1.1, itemname)..
"container_end[]"
end
local function help(x, y)
local tooltip = S("To add fuel punch\nthis block\nwith a fuel container")
return "label["..x..","..y..";"..minetest.colorize("#000000", minetest.formspec_escape("[?]")).."]"..
"tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end
function techage.fuel.formspec(nvm)
local title = S("Fuel Menu")
return "size[4,3]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;3.8,0.5;#c6e8ff]"..
"label[1,-0.1;"..minetest.colorize("#000000", title).."]"..
help(3.4, -0.1)..
techage.fuel.fuel_container(1.5, 1, nvm)
end
function techage.fuel.can_dig(pos, player)
if not player or minetest.is_protected(pos, player:get_player_name()) then
return false
end
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
local inv = M(pos):get_inventory()
return not inv or inv:is_empty("fuel") and nvm.liquid.amount == 0
end
function techage.fuel.on_rightclick(pos, node, clicker)
techage.set_activeformspec(pos, clicker)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", techage.fuel.formspec(nvm))
end
-- name is the fuel item name
function techage.fuel.burntime(name)
if ValidOilFuels[name] then
return Burntime[name] or 0.01 -- not zero !
end
return 0.01 -- not zero !
end
-- equal or better than the given category (see 'techage.fuel.BT_BITUMEN,...')
function techage.fuel.valid_fuel(name, category)
return ValidOilFuels[name] and ValidOilFuels[name] <= category
end
function techage.fuel.on_punch(pos, node, puncher, pointed_thing)
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
mem.blocking_time = mem.blocking_time or 0
if mem.blocking_time > techage.SystemTime then
return
end
local wielded_item = puncher:get_wielded_item():get_name()
local item_count = puncher:get_wielded_item():get_count()
local new_item = techage.liquid.fill_on_punch(nvm, wielded_item, item_count, puncher)
if new_item then
puncher:set_wielded_item(new_item)
M(pos):set_string("formspec", techage.fuel.formspec(pos, nvm))
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
return
end
local ldef = techage.liquid.get_liquid_def(wielded_item)
if ldef and ValidOilFuels[ldef.inv_item] then
local lqd = (minetest.registered_nodes[node.name] or {}).liquid
if not lqd.fuel_cat or ValidOilFuels[ldef.inv_item] <= lqd.fuel_cat then
local new_item = techage.liquid.empty_on_punch(pos, nvm, wielded_item, item_count)
if new_item then
puncher:set_wielded_item(new_item)
M(pos):set_string("formspec", techage.fuel.formspec(pos, nvm))
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
end
end
end
end
function techage.fuel.get_fuel(nvm)
if nvm.liquid and nvm.liquid.name and nvm.liquid.amount then
if nvm.liquid.amount > 0 then
nvm.liquid.amount = nvm.liquid.amount - 1
return nvm.liquid.name
end
nvm.liquid.name = nil
end
return nil
end
function techage.fuel.has_fuel(nvm)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
return nvm.liquid.amount > 0
end
function techage.fuel.get_fuel_amount(nvm)
if nvm.liquid and nvm.liquid.amount then
return nvm.liquid.amount
end
return 0
end
function techage.fuel.get_liquid_table(valid_fuel, capacity, start_firebox)
return {
capa = capacity,
fuel_cat = valid_fuel,
peek = function(pos)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end,
put = function(pos, indir, name, amount)
if techage.fuel.valid_fuel(name, valid_fuel) then
local nvm = techage.get_nvm(pos)
local res = liquid.srv_put(nvm, name, amount, capacity)
start_firebox(pos, nvm)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", techage.fuel.formspec(nvm))
end
return res
end
return amount
end,
take = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
amount, name = liquid.srv_take(nvm, name, amount)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", techage.fuel.formspec(nvm))
end
return amount, name
end,
untake = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
local leftover = liquid.srv_put(nvm, name, amount, capacity)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", techage.fuel.formspec(nvm))
end
return leftover
end
}
end

View File

@ -1,102 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Gravel Sieve basis functions
]]--
-- Increase the probability over the natural occurrence
local PROBABILITY_FACTOR = 2
-- Ore probability table (1/n)
local ore_probability = {
}
local ProbabilityCorrections = {
["default:tin_lump"] = 0.3, -- extensively used
["default:coal_lump"] = 0.2, -- extensively used
["default:iron_lump"] = 0.5, -- extensively used
["techage:baborium_lump"] = 99999, -- mining required
}
-- collect all registered ores and calculate the probability
local function add_ores()
for _,item in pairs(minetest.registered_ores) do
if not ore_probability[item.ore] and minetest.registered_nodes[item.ore] then
local drop = minetest.registered_nodes[item.ore].drop
if type(drop) == "string"
and drop ~= item.ore
and drop ~= ""
and item.ore_type == "scatter"
and item.wherein == "default:stone"
and item.clust_scarcity ~= nil and item.clust_scarcity > 0
and item.clust_num_ores ~= nil and item.clust_num_ores > 0
and item.y_max ~= nil and item.y_min ~= nil then
local factor = 0.5
if item.y_max < -250 then
factor = -250 / item.y_max
end
local probability = (techage.ore_rarity / PROBABILITY_FACTOR) * item.clust_scarcity /
(item.clust_num_ores * factor)
-- lower value means higher probability
ore_probability[drop] = math.min(ore_probability[drop] or 100000, probability)
end
end
end
-- some corrections
for key, correction in pairs(ProbabilityCorrections) do
if ore_probability[key] then
ore_probability[key] = ore_probability[key] * correction
-- consider upper and lower level
ore_probability[key] = techage.in_range(ore_probability[key], 10, 100000)
end
end
local overall_probability = 0.0
for name,probability in pairs(ore_probability) do
minetest.log("info", string.format("[techage] %-32s %u", name, probability))
overall_probability = overall_probability + 1.0/probability
end
minetest.log("info", string.format("[techage] Overall probability %g", overall_probability))
end
minetest.register_on_mods_loaded(add_ores)
--
-- Change the probability of ores or register new ores for sieving
--
function techage.register_ore_for_gravelsieve(ore_name, probability)
ore_probability[ore_name] = probability
end
-- determine ore based on the calculated probability
function techage.gravelsieve_get_random_gravel_ore()
for ore, probability in pairs(ore_probability) do
if math.random(probability) == 1 then
return ItemStack(ore)
end
end
if math.random(2) == 1 then
return ItemStack("default:gravel")
else
return ItemStack("techage:sieved_gravel")
end
end
function techage.gravelsieve_get_random_basalt_ore()
if math.random(40) == 1 then
return ItemStack("default:coal_lump")
elseif math.random(40) == 1 then
return ItemStack("default:iron_lump")
elseif math.random(2) == 1 then
return ItemStack("techage:basalt_gravel")
else
return ItemStack("techage:sieved_basalt_gravel")
end
end

View File

@ -1,240 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
For chests and tanks with hyperloop support
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local N = techage.get_node_lvm
local S = techage.S
-- Will be initialized when mods are loaded
local Stations = nil
local Tube = nil
local HYPERLOOP = nil
techage.hyperloop = {}
--[[
tStations["(x,y,z)"] = {
conn = {dir = "(200,0,20)", ...},
name = <node_type>, -- chest/tank
owner = "singleplayer",
conn_name = <own name>,
single = true/nil,
}
]]--
minetest.register_on_mods_loaded(function()
if minetest.global_exists("hyperloop") then
Stations = hyperloop.Stations
Tube = hyperloop.Tube
HYPERLOOP = true
Tube:add_secondary_node_names({"techage:ta5_hl_chest", "techage:ta5_hl_tank"})
end
end)
local function get_remote_pos(pos, rmt_name)
local owner = M(pos):get_string("owner")
for key,item in pairs(Stations:get_node_table(pos)) do
if item.owner == owner and item.conn_name == rmt_name then
return S2P(key)
end
end
end
local function get_free_server_list(pos, owner)
if Stations and Stations.get_node_table then
local tbl = {M(pos):get_string("remote_name")}
for key,item in pairs(Stations:get_node_table(pos) or {}) do
if item.single and item.owner == owner then
if M(pos):get_string("node_type") == M(S2P(key)):get_string("node_type") then
tbl[#tbl+1] = item.conn_name
end
end
end
tbl[#tbl+1] = ""
return tbl
end
return {}
end
local function on_lose_connection(pos, node_type)
local name = techage.get_node_lvm(pos).name
local ndef = minetest.registered_nodes[name]
if ndef and ndef.on_lose_connection then
ndef.on_lose_connection(pos, node_type)
end
end
local function on_dropdown(pos)
if pos then
local owner = M(pos):get_string("owner")
return table.concat(get_free_server_list(pos, owner), ",") or ""
end
return ""
end
local function update_node_data(pos, state, conn_name, remote_name, rmt_pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if state == "server_connected" then
Stations:update(pos, {conn_name=conn_name, single="nil"})
meta:set_string("status", "server")
meta:set_string("conn_name", conn_name)
meta:set_string("remote_name", "")
meta:set_string("conn_status", S("connected to") .. " " .. P2S(rmt_pos))
nvm.rmt_pos = rmt_pos
elseif state == "client_connected" then
Stations:update(pos, {conn_name="nil", single="nil"})
meta:set_string("status", "client")
meta:set_string("conn_name", "")
meta:set_string("remote_name", remote_name)
meta:set_string("conn_status", S("connected to") .. " " .. P2S(rmt_pos))
nvm.rmt_pos = rmt_pos
elseif state == "server_not_connected" then
Stations:update(pos, {conn_name=conn_name, single=true})
meta:set_string("status", "server")
meta:set_string("conn_name", conn_name)
meta:set_string("remote_name", "")
meta:set_string("conn_status", S("not connected"))
nvm.rmt_pos = nil
on_lose_connection(pos, "server")
elseif state == "client_not_connected" then
Stations:update(pos, {conn_name="nil", single=nil})
meta:set_string("status", "not connected")
meta:set_string("conn_name", "")
meta:set_string("remote_name", "")
meta:set_string("conn_status", S("not connected"))
nvm.rmt_pos = nil
on_lose_connection(pos, "client")
end
end
techage.hyperloop.SUBMENU = {
{
type = "label",
label = S("Enter a block name or select an existing one"),
tooltip = "",
name = "l1",
},
{
type = "ascii",
name = "conn_name",
label = S("Block name"),
tooltip = S("Connection name for this block"),
default = "",
},
{
type = "dropdown",
choices = "",
on_dropdown = on_dropdown,
name = "remote_name",
label = S("Remote name"),
tooltip = S("Connection name of the remote block"),
},
}
function techage.hyperloop.is_client(pos)
if HYPERLOOP then
local nvm = techage.get_nvm(pos)
if Stations:get(nvm.rmt_pos) then
if M(pos):get_string("status") == "client" then
return true
end
end
end
end
function techage.hyperloop.is_server(pos)
if HYPERLOOP then
if M(pos):get_string("status") == "server" then
return true
end
end
end
function techage.hyperloop.is_paired(pos)
if HYPERLOOP then
local nvm = techage.get_nvm(pos)
if Stations:get(nvm.rmt_pos) then
if M(pos):get_string("status") ~= "not connected" then
return true
end
end
end
end
function techage.hyperloop.remote_pos(pos)
if HYPERLOOP then
local nvm = techage.get_nvm(pos)
if Stations:get(nvm.rmt_pos) then
if M(pos):contains("remote_name") then
return nvm.rmt_pos or pos
end
end
end
return pos
end
function techage.hyperloop.after_place_node(pos, placer, node_type)
if HYPERLOOP then
Stations:set(pos, node_type, {owner=placer:get_player_name()})
M(pos):set_string("node_type", node_type)
Tube:after_place_node(pos)
end
end
function techage.hyperloop.after_dig_node(pos, oldnode, oldmetadata, digger)
if HYPERLOOP then
local conn_name = oldmetadata.fields.conn_name
local remote_name = oldmetadata.fields.remote_name
local loc_pos, rmt_pos = pos, techage.get_nvm(pos).rmt_pos
-- Close connections
if remote_name and rmt_pos then -- Connected client
update_node_data(rmt_pos, "server_not_connected", remote_name, "")
elseif conn_name and rmt_pos then -- Connected server
update_node_data(rmt_pos, "client_not_connected", "", conn_name)
end
Tube:after_dig_node(pos)
Stations:delete(pos)
end
end
function techage.hyperloop.after_formspec(pos, fields)
if HYPERLOOP and fields.save or fields.key_enter_field then
local meta = M(pos)
local conn_name = meta:get_string("conn_name")
local remote_name = meta:get_string("remote_name")
local status = meta:contains("status") and meta:get_string("status") or "not connected"
local loc_pos, rmt_pos = pos, techage.get_nvm(pos).rmt_pos
if status == "not connected" then
if fields.remote_name ~= "" then -- Client
local rmt_pos = get_remote_pos(pos, fields.remote_name)
if rmt_pos then
update_node_data(loc_pos, "client_connected", "", fields.remote_name, rmt_pos)
update_node_data(rmt_pos, "server_connected", fields.remote_name, "", loc_pos)
end
elseif fields.conn_name ~= "" then -- Server
update_node_data(loc_pos, "server_not_connected", fields.conn_name, "")
end
end
end
end

View File

@ -1,146 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
GPL v3
See LICENSE.txt for more information
Laser basis functions
]]--
local Entities = {}
local SIZES = {1, 2, 3, 6, 12, 24, 48} -- for laser entities
local GAP_MIN = 1 -- between 2 blocks
local GAP_MAX = 2 * 48 -- between 2 blocks
-- Return the area (pos1,pos2) for a destination node
local function get_pos_range(pos, dir)
local pos1 = vector.add(pos, vector.multiply(dir, GAP_MIN + 1)) -- min
local pos2 = vector.add(pos, vector.multiply(dir, GAP_MAX + 1)) -- max
return pos1, pos2
end
-- Return first pos after start pos and the destination pos
local function get_positions(pos, mem, dir)
local pos1 = vector.add(pos, dir) -- start pos
local _, pos2 = get_pos_range(pos, dir) -- last pos
local _, pos3 = minetest.line_of_sight(pos1, pos2)
pos3 = pos3 or pos2 -- destination node pos
if not mem.peer_node_pos or not vector.equals(pos3, mem.peer_node_pos) then
mem.peer_node_pos = pos3
local dist = vector.distance(pos1, pos3)
if dist > GAP_MIN and dist <= GAP_MAX then
return true, pos1, pos3 -- new values
else
return false -- invalid values
end
end
return true -- no new values
end
-- return for both laser entities the pos and length
local function get_laser_length_and_pos(pos1, pos2, dir)
local dist = vector.distance(pos1, pos2)
for _, size in ipairs(SIZES) do
if dist <= (size * 2) then
pos1 = vector.add (pos1, vector.multiply(dir, (size / 2) - 0.5))
pos2 = vector.subtract(pos2, vector.multiply(dir, (size / 2) + 0.5))
return size, pos1, pos2
end
end
end
local function del_laser(pos)
local key = minetest.hash_node_position(pos)
local items = Entities[key]
if items then
local laser1, laser2 = items[1], items[2]
laser1:remove()
laser2:remove()
Entities[key] = nil
end
return key
end
local function add_laser(pos, pos1, pos2, size, param2)
local key = del_laser(pos)
local laser1 = minetest.add_entity(pos1, "techage:laser" .. size)
if laser1 then
local yaw = math.pi / 2 * (param2 + 1)
laser1:set_rotation({x = 0, y = yaw, z = 0})
end
local laser2 = minetest.add_entity(pos2, "techage:laser" .. size)
if laser2 then
param2 = (param2 + 2) % 4 -- flip dir
local yaw = math.pi / 2 * (param2 + 1)
laser2:set_rotation({x = 0, y = yaw, z = 0})
end
Entities[key] = {laser1, laser2}
end
for _, size in ipairs(SIZES) do
minetest.register_entity("techage:laser" .. size, {
initial_properties = {
visual = "cube",
textures = {
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
},
use_texture_alpha = true,
physical = false,
collide_with_objects = false,
pointable = false,
static_save = false,
visual_size = {x = size, y = 0.05, z = 0.05},
glow = 14,
shaded = true,
},
})
end
-------------------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------------------
-- if force is not true, do not redraw the laser if nothing has changed
function techage.renew_laser(pos, force)
local mem = techage.get_mem(pos)
if force then
mem.peer_node_pos = nil
mem.param2 = nil
end
mem.param2 = mem.param2 or minetest.get_node(pos).param2
local dir = minetest.facedir_to_dir(mem.param2)
local res, pos1, pos2 = get_positions(pos, mem, dir)
if pos1 then
local size, pos3, pos4 = get_laser_length_and_pos(pos1, pos2, dir)
if size then
add_laser(pos, pos3, pos4, size, mem.param2)
return res, pos1, pos2
end
end
return res
end
function techage.add_laser(pos, pos1, pos2)
local dir = vector.direction(pos1, pos2)
local param2 = minetest.dir_to_facedir(dir)
local size, pos3, pos4 = get_laser_length_and_pos(pos1, pos2, dir)
if size then
add_laser(pos, pos3, pos4, size, param2)
end
end
-- techage.del_laser(pos)
techage.del_laser = del_laser

View File

@ -1,25 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
For the transition from v0.26 to v1.0
]]--
function techage.register_node_for_v1_transition(nodenames, on_node_load)
minetest.register_lbm({
label = "[TechAge] V1 transition",
name = nodenames[1].."transition",
nodenames = nodenames,
run_at_every_load = false,
action = function(pos, node)
on_node_load(pos, node)
end
})
end

View File

@ -1,633 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Helper functions
]]--
-- for lazy programmers
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
-- Input data to generate the Param2ToDir table
local Input = {
8,9,10,11, -- 1
16,17,18,19, -- 2
4,5,6,7, -- 3
12,13,14,15, -- 4
0,1,2,3, -- 5
20,21,22,23, -- 6
}
-- Input data to turn a "facedir" block to the right/left
local ROTATION = {
{5,14,11,16}, -- x+
{7,12,9,18}, -- x-
{0,1,2,3}, -- y+
{22,21,20,23}, -- y-
{6,15,8,17}, -- z+
{4,13,10,19}, -- z-
}
local FACEDIR_TO_ROT = {[0] =
{x=0.000000, y=0.000000, z=0.000000},
{x=0.000000, y=4.712389, z=0.000000},
{x=0.000000, y=3.141593, z=0.000000},
{x=0.000000, y=1.570796, z=0.000000},
{x=4.712389, y=0.000000, z=0.000000},
{x=3.141593, y=1.570796, z=1.570796},
{x=1.570796, y=4.712389, z=4.712389},
{x=3.141593, y=4.712389, z=4.712389},
{x=1.570796, y=0.000000, z=0.000000},
{x=0.000000, y=4.712389, z=1.570796},
{x=4.712389, y=1.570796, z=4.712389},
{x=0.000000, y=1.570796, z=4.712389},
{x=0.000000, y=0.000000, z=1.570796},
{x=4.712389, y=0.000000, z=1.570796},
{x=0.000000, y=3.141593, z=4.712389},
{x=1.570796, y=3.141593, z=4.712389},
{x=0.000000, y=0.000000, z=4.712389},
{x=1.570796, y=0.000000, z=4.712389},
{x=0.000000, y=3.141593, z=1.570796},
{x=4.712389, y=0.000000, z=4.712389},
{x=0.000000, y=0.000000, z=3.141593},
{x=0.000000, y=1.570796, z=3.141593},
{x=0.000000, y=3.141593, z=3.141593},
{x=0.000000, y=4.712389, z=3.141593},
}
local RotationViaYAxis = {}
for _,row in ipairs(ROTATION) do
for i = 1,4 do
local val = row[i]
local left = row[i == 1 and 4 or i - 1]
local right = row[i == 4 and 1 or i + 1]
RotationViaYAxis[val] = {left, right}
end
end
function techage.facedir_to_rotation(facedir)
return FACEDIR_TO_ROT[facedir] or FACEDIR_TO_ROT[0]
end
function techage.param2_turn_left(param2)
return (RotationViaYAxis[param2] or RotationViaYAxis[0])[2]
end
function techage.param2_turn_right(param2)
return (RotationViaYAxis[param2] or RotationViaYAxis[0])[1]
end
-- Roll a block in north direction (south is vice versa)
local RollNorth = {
{0,4,22,8},
{1,5,23,9},
{2,6,20,10},
{3,7,21,11},
{12,13,14,15},
{16,19,18,17},
}
-- Roll a block in east direction (west is vice versa)
local RollEast = {
{0,12,20,16},
{1,13,21,17},
{2,14,22,18},
{3,15,23,19},
{4,7,6,5},
{8,9,10,11},
}
-- Generate a table for all facedir and param2 values:
-- TurnUp[facedir][param2] = new_param2
local TurnUp = {[0] = {}, {}, {}, {}}
for i = 1,6 do
for j = 1,4 do
local idx = RollNorth[i][j]
TurnUp[0][idx] = RollNorth[i][j == 4 and 1 or j + 1] -- north
TurnUp[2][idx] = RollNorth[i][j == 1 and 4 or j - 1] -- south
idx = RollEast[i][j]
TurnUp[1][idx] = RollEast[i][j == 4 and 1 or j + 1] -- east
TurnUp[3][idx] = RollEast[i][j == 1 and 4 or j - 1] -- west
end
end
-- facedir is from the players (0..3)
-- param2 is from the node (0..23)
function techage.param2_turn_up(facedir, param2)
return TurnUp[facedir % 4][param2 % 24]
end
-------------------------------------------------------------------------------
-- Rotate nodes around the center
-------------------------------------------------------------------------------
function techage.positions_center(lpos)
local c = {x=0, y=0, z=0}
for _,v in ipairs(lpos) do
c = vector.add(c, v)
end
c = vector.divide(c, #lpos)
c = vector.round(c)
c.y = 0
return c
end
function techage.rotate_around_axis(v, c, turn)
local dx, dz = v.x - c.x, v.z - c.z
if turn == "l" then
return {
x = c.x - dz,
y = v.y,
z = c.z + dx,
}
elseif turn == "r" then
return {
x = c.x + dz,
y = v.y,
z = c.z - dx,
}
elseif turn == "" then
return v
else -- turn 180 degree
return {
x = c.x - dx,
y = v.y,
z = c.z - dz,
}
end
end
-- Function returns a list ẃith the new node positions
-- turn is one of "l", "r", "2l", "2r"
-- cpos is the center pos (optional)
function techage.rotate_around_center(nodes1, turn, cpos)
cpos = cpos or techage.positions_center(nodes1)
local nodes2 = {}
for _,pos in ipairs(nodes1) do
nodes2[#nodes2 + 1] = techage.rotate_around_axis(pos, cpos, turn)
end
return nodes2
end
-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
-- allowed for digging
local SimpleNodes = {}
-- translation from param2 to dir (out of the node upwards)
local Param2Dir = {}
for idx,val in ipairs(Input) do
Param2Dir[val] = math.floor((idx - 1) / 4) + 1
end
-- used by lamps and power switches
function techage.determine_node_bottom_as_dir(node)
return tubelib2.Turn180Deg[Param2Dir[node.param2] or 1]
end
function techage.determine_node_top_as_dir(node)
return Param2Dir[node.param2] or 1
end
-- rotation rules (screwdriver) for wallmounted "facedir" nodes
function techage.rotate_wallmounted(param2)
local offs = math.floor(param2 / 4) * 4
local rot = ((param2 % 4) + 1) % 4
return offs + rot
end
function techage.in_range(val, min, max)
val = tonumber(val)
if val < min then return min end
if val > max then return max end
return val
end
function techage.one_of(val, selection)
for _,v in ipairs(selection) do
if val == v then return val end
end
return selection[1]
end
function techage.index(list, x)
for idx, v in pairs(list) do
if v == x then return idx end
end
return nil
end
function techage.in_list(list, x)
for idx, v in pairs(list) do
if v == x then return true end
end
return false
end
function techage.add_to_set(set, x)
if not techage.index(set, x) then
table.insert(set, x)
end
end
-- techage.tbl_filter({"a", "b", "c", "d"}, function(v, k, t) return v >= "c" end) --> {"c","d"}
techage.tbl_filter = function(t, filterIter)
local out = {}
for k, v in pairs(t) do
if filterIter(v, k, t) then out[k] = v end
end
return out
end
function techage.get_node_lvm(pos)
local node = minetest.get_node_or_nil(pos)
if node then
return node
end
local vm = minetest.get_voxel_manip()
local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
local data = vm:get_data()
local param2_data = vm:get_param2_data()
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
local idx = area:indexp(pos)
if data[idx] and param2_data[idx] then
return {
name = minetest.get_name_from_content_id(data[idx]),
param2 = param2_data[idx]
}
end
return {name="ignore", param2=0}
end
function techage.is_air_like(name)
local ndef = minetest.registered_nodes[name]
if ndef and ndef.buildable_to then
return true
end
return false
end
-- returns true, if node can be dug, otherwise false
function techage.can_dig_node(name, ndef)
if not ndef then return false end
if SimpleNodes[name] ~= nil then
return SimpleNodes[name]
end
if ndef.groups and ndef.groups.techage_door == 1 then
SimpleNodes[name] = true
return true
end
if name == "ignore" then
SimpleNodes[name] = false
return false
end
if name == "air" then
SimpleNodes[name] = true
return true
end
if ndef.buildable_to == true then
SimpleNodes[name] = true
return true
end
-- don't remove nodes with some intelligence or undiggable nodes
if ndef.drop == "" then
SimpleNodes[name] = false
return false
end
if ndef.diggable == false then
SimpleNodes[name] = false
return false
end
if ndef.after_dig_node then
SimpleNodes[name] = false
return false
end
-- add it to the white list
SimpleNodes[name] = true
return true
end
-- Simple nodes
function techage.register_simple_nodes(node_names, is_valid)
if is_valid == nil then is_valid = true end
for _,name in ipairs(node_names or {}) do
SimpleNodes[name] = is_valid
end
end
techage.dig_states = {
NOT_DIGGABLE = 1,
INV_FULL = 2,
DUG = 3
}
-- Digs a node like a player would by utilizing a fake player object.
-- add_to_inv(itemstacks) is a method that should try to add the dropped stacks to an appropriate inventory.
-- The node will only be dug, if add_to_inv(itemstacks) returns true.
function techage.dig_like_player(pos, fake_player, add_to_inv)
local node = techage.get_node_lvm(pos)
local ndef = minetest.registered_nodes[node.name]
if not ndef or ndef.diggable == false or (ndef.can_dig and not ndef.can_dig(pos, fake_player)) then
return techage.dig_states.NOT_DIGGABLE
end
local drop_as_strings = minetest.get_node_drops(node)
local drop_as_stacks = {}
for _,itemstring in ipairs(drop_as_strings) do
drop_as_stacks[#drop_as_stacks+1] = ItemStack(itemstring)
end
local meta = M(pos)
if ndef.preserve_metadata then
ndef.preserve_metadata(pos, node, meta, drop_as_stacks)
end
if add_to_inv(drop_as_stacks) then
local oldmeta = meta:to_table()
minetest.remove_node(pos)
if ndef.after_dig_node then
ndef.after_dig_node(pos, node, oldmeta, fake_player)
end
return techage.dig_states.DUG
end
return techage.dig_states.INV_FULL
end
local function handle_drop(drop)
-- To keep it simple, return only the item with the lowest rarity
if drop.items then
local rarity = 9999
local name
for idx,item in ipairs(drop.items) do
if item.rarity and item.rarity < rarity then
rarity = item.rarity
name = item.items[1] -- take always the first item
else
return item.items[1] -- take always the first item
end
end
return name
end
return false
end
-- returns the node name, if node can be dropped, otherwise nil
function techage.dropped_node(node, ndef)
if node.name == "air" then return end
--if ndef.buildable_to == true then return end
if not ndef.diggable then return end
if ndef.drop == "" then return end
if type(ndef.drop) == "table" then
return handle_drop(ndef.drop)
end
return ndef.drop or node.name
end
-- needed for windmill plants
local function determine_ocean_ids()
techage.OceanIdTbl = {}
for name, _ in pairs(minetest.registered_biomes) do
if string.find(name, "ocean") then
local id = minetest.get_biome_id(name)
--print(id, name)
techage.OceanIdTbl[id] = true
end
end
end
determine_ocean_ids()
-- check if natural water is on given position (water placed by player has param2 = 1)
function techage.is_ocean(pos)
if pos.y > 1 then return false end
local node = techage.get_node_lvm(pos)
if node.name ~= "default:water_source" then return false end
if node.param2 == 1 then return false end
return true
end
function techage.item_image(x, y, itemname, count)
local name, size = unpack(string.split(itemname, " "))
size = count and count or size
size = tonumber(size) or 1
local label = ""
local text = minetest.formspec_escape(ItemStack(itemname):get_description())
local tooltip = "tooltip["..x..","..y..";1,1;"..text..";#0C3D32;#FFFFFF]"
if minetest.registered_tools[name] and size > 1 then
local offs = 0
if size < 10 then
offs = 0.65
elseif size < 100 then
offs = 0.5
elseif size < 1000 then
offs = 0.35
else
offs = 0.2
end
label = "label["..(x + offs)..","..(y + 0.45)..";"..tostring(size).."]"
end
return "box["..x..","..y..";0.85,0.9;#808080]"..
"item_image["..x..","..y..";1,1;"..itemname.."]"..
tooltip..
label
end
function techage.item_image_small(x, y, itemname, tooltip_prefix)
local name = unpack(string.split(itemname, " "))
local tooltip = ""
local ndef = minetest.registered_nodes[name] or minetest.registered_items[name] or minetest.registered_craftitems[name]
if ndef and ndef.description then
local text = minetest.formspec_escape(ndef.description)
tooltip = "tooltip["..x..","..y..";0.8,0.8;"..tooltip_prefix..": "..text..";#0C3D32;#FFFFFF]"
end
return "box["..x..","..y..";0.65,0.7;#808080]"..
"item_image["..x..","..y..";0.8,0.8;"..name.."]"..
tooltip
end
function techage.vector_dump(posses)
local t = {}
for _,pos in ipairs(posses) do
t[#t + 1] = minetest.pos_to_string(pos)
end
return table.concat(t, " ")
end
-- title bar help (width is the fornmspec width)
function techage.question_mark_help(width, tooltip)
local x = width- 0.6
return "label["..x..",-0.1;"..minetest.colorize("#000000", minetest.formspec_escape("[?]")).."]"..
"tooltip["..x..",-0.1;0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end
function techage.wrench_tooltip(x, y)
local tooltip = S("Block has an\nadditional wrench menu")
return "image["..x.."," .. y .. ";0.5,0.5;techage_inv_wrench.png]" ..
"tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end
techage.RegisteredMobsMods = {}
-- Register mobs mods for the move/fly controllers
function techage.register_mobs_mods(mod)
techage.RegisteredMobsMods[mod] = true
end
function techage.beduino_signed_var(val)
val = val or 0
return val >= 32768 and val - 0x10000 or val
end
-------------------------------------------------------------------------------
-- Terminal history buffer
-------------------------------------------------------------------------------
local BUFFER_DEPTH = 10
function techage.historybuffer_add(pos, s)
local mem = techage.get_mem(pos)
mem.hisbuf = mem.hisbuf or {}
if #s > 2 then
table.insert(mem.hisbuf, s)
if #mem.hisbuf > BUFFER_DEPTH then
table.remove(mem.hisbuf, 1)
end
mem.hisbuf_idx = #mem.hisbuf + 1
end
end
function techage.historybuffer_priv(pos)
local mem = techage.get_mem(pos)
mem.hisbuf = mem.hisbuf or {}
mem.hisbuf_idx = mem.hisbuf_idx or 1
mem.hisbuf_idx = math.max(1, mem.hisbuf_idx - 1)
return mem.hisbuf[mem.hisbuf_idx]
end
function techage.historybuffer_next(pos)
local mem = techage.get_mem(pos)
mem.hisbuf = mem.hisbuf or {}
mem.hisbuf_idx = mem.hisbuf_idx or 1
mem.hisbuf_idx = math.min(#mem.hisbuf, mem.hisbuf_idx + 1)
return mem.hisbuf[mem.hisbuf_idx]
end
-------------------------------------------------------------------------------
-- Player TA5 Experience Points
-------------------------------------------------------------------------------
function techage.get_expoints(player)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
return meta:get_int("techage_ex_points")
end
end
end
-- Can only be used from one collider
function techage.add_expoint(player, number)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
if not meta:contains("techage_collider_number") then
meta:set_string("techage_collider_number", number)
end
if meta:get_string("techage_collider_number") == number then
meta:set_int("techage_ex_points", meta:get_int("techage_ex_points") + 1)
return true
else
minetest.chat_send_player(player:get_player_name(), "[techage] More than one collider is not allowed!")
return false
end
end
end
end
-- Delete number with: `//lua minetest.get_player_by_name("<name>"):get_meta():set_string("techage_collider_number", "")`
function techage.on_remove_collider(player)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
meta:set_string("techage_collider_number", "")
end
end
end
function techage.set_expoints(player, ex_points)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
meta:set_int("techage_ex_points", ex_points)
return true
end
end
end
-------------------------------------------------------------------------------
-- Scheduler for a table-based, cyclic call of functions
-------------------------------------------------------------------------------
local TABLE_SIZE = 256
techage.scheduler = {}
local function add_to_table(tbl, i, func)
while i < TABLE_SIZE do
if not tbl[i] then
tbl[i] = func
return i + 1
end
i = i + 1
end
return i
end
function techage.scheduler.init(pos)
local mem = techage.get_mem(pos)
mem.sched_idx = 0
end
-- tFunc : (empty) table of functions
-- call_rate : (2,4,8,16,32,64 or 128)
-- offset : 0-128
-- func : function to be called
function techage.scheduler.register(tFunc, call_rate, offset, func)
local i= 0
while i < TABLE_SIZE do
if (i % call_rate) == offset then
i = add_to_table(tFunc, i, func)
else
i = i + 1
end
end
return tFunc
end
-- tFunc : table of functions
-- default : default function (optional)
-- Returns a function to be called be the callee
function techage.scheduler.get(pos, tFunc, default)
local mem = techage.get_mem(pos)
mem.sched_idx = ((mem.sched_idx or 0) + 1) % TABLE_SIZE
return tFunc[mem.sched_idx] or default or function() end
end

View File

@ -1,278 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Liquid lib
]]--
local M = minetest.get_meta
local S = techage.S
local P2S = minetest.pos_to_string
local LQD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).liquid end
local BLOCKING_TIME = 0.3 -- 300ms
techage.liquid = {}
local LiquidDef = {}
local IsLiquid = {}
local ContainerDef = {}
local function help(x, y)
local tooltip = S("To add liquids punch\nthe tank\nwith a liquid container")
return "label["..x..","..y..";"..minetest.colorize("#000000", minetest.formspec_escape("[?]")).."]"..
"tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end
function techage.liquid.formspec(pos, nvm, title)
title = title or S("Liquid Tank")
local itemname = "techage:liquid"
if nvm.liquid and nvm.liquid.amount and nvm.liquid.amount > 0 and nvm.liquid.name then
itemname = nvm.liquid.name.." "..nvm.liquid.amount
end
local name = minetest.get_node(pos).name
if name == "techage:ta4_tank" then
local meta = M(pos)
local public = dump((meta:get_int("public") or 0) == 1)
local keep_assignment = dump((meta:get_int("keep_assignment") or 0) == 1)
return "size[8,3.5]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[0.2,-0.1;"..minetest.colorize("#000000", title).."]"..
help(7.4, -0.1)..
techage.item_image(3.5, 1, itemname)..
"checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]"..
"checkbox[0.1,3;keep_assignment;"..S("keep assignment")..";"..keep_assignment.."]"
else
return "size[8,2]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[0.2,-0.1;"..minetest.colorize("#000000", title).."]"..
help(7.4, -0.1)..
techage.item_image(3.5, 1, itemname)
end
end
function techage.liquid.is_empty(pos)
local nvm = techage.get_nvm(pos)
return not nvm.liquid or (nvm.liquid.amount or 0) <= 0
end
techage.liquid.recv_message = {
on_recv_message = function(pos, src, topic, payload)
if topic == "load" then
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
return techage.power.percent(LQD(pos).capa, nvm.liquid.amount), nvm.liquid.amount
elseif topic == "size" then
return LQD(pos).capa
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 134 then
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
if payload[1] == 1 then
local value = techage.power.percent(LQD(pos).capa, nvm.liquid.amount)
return 0, {math.floor(value + 0.5)}
else
return 0, {nvm.liquid.amount}
end
else
return 2, ""
end
end,
}
-- like: register_liquid("techage:ta3_barrel_oil", "techage:ta3_barrel_empty", 10, "techage:oil")
function techage.register_liquid(full_container, empty_container, container_size, inv_item)
LiquidDef[full_container] = {container = empty_container, size = container_size, inv_item = inv_item}
ContainerDef[empty_container] = ContainerDef[empty_container] or {}
ContainerDef[empty_container][inv_item] = full_container
IsLiquid[inv_item] = true
if inv_item == "techage:water" and container_size == 1 then
techage.register_water_bucket(empty_container, full_container)
end
end
local function get_liquid_def(full_container)
return LiquidDef[full_container]
end
local function get_container_def(container_name)
return ContainerDef[container_name]
end
local function is_container_empty(container_name)
return ContainerDef[container_name]
end
local function get_full_container(empty_container, inv_item)
return ContainerDef[empty_container] and ContainerDef[empty_container][inv_item]
end
-- used by filler
local function fill_container(pos, inv, empty_container)
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
local full_container = get_full_container(empty_container, nvm.liquid.name)
if empty_container and full_container then
local ldef = get_liquid_def(full_container)
if ldef and nvm.liquid.amount - ldef.size >= 0 then
if inv:room_for_item("dst", {name = full_container}) then
inv:add_item("dst", {name = full_container})
nvm.liquid.amount = nvm.liquid.amount - ldef.size
if nvm.liquid.amount == 0 then
nvm.liquid.name = nil
end
return true
end
end
end
-- undo
inv:add_item("src", {name = empty_container})
return false
end
-- used by filler
local function empty_container(pos, inv, full_container)
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
local ndef_lqd = LQD(pos)
local tank_size = (ndef_lqd and ndef_lqd.capa) or 0
local ldef = get_liquid_def(full_container)
if ldef and (not nvm.liquid.name or ldef.inv_item == nvm.liquid.name) then
if nvm.liquid.amount + ldef.size <= tank_size then
if inv:room_for_item("dst", {name = ldef.container}) then
inv:add_item("dst", {name = ldef.container})
nvm.liquid.amount = nvm.liquid.amount + ldef.size
nvm.liquid.name = ldef.inv_item
return true
end
end
end
-- undo
inv:add_item("src", {name = full_container})
return false
end
-- check if the wielded empty container can be replaced by a full
-- container and added to the players inventory
local function fill_on_punch(nvm, empty_container, item_count, puncher)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
local full_container = get_full_container(empty_container, nvm.liquid.name)
if empty_container and full_container then
local item = {name = full_container}
local ldef = get_liquid_def(full_container)
if ldef and nvm.liquid.amount - ldef.size >= 0 then
if item_count > 1 then -- can't be simply replaced?
-- check for extra free space
local inv = puncher:get_inventory()
if inv:room_for_item("main", {name = full_container}) then
-- add full container and return
-- the empty once - 1
inv:add_item("main", {name = full_container})
item = {name = empty_container, count = item_count - 1}
else
return -- no free space
end
end
nvm.liquid.amount = nvm.liquid.amount - ldef.size
if nvm.liquid.amount == 0 then
nvm.liquid.name = nil
end
return item -- to be added to the players inv.
end
elseif nvm.liquid.name and not IsLiquid[nvm.liquid.name] then
if empty_container == "" then
local count = math.max(nvm.liquid.amount, 99)
local name = nvm.liquid.name
nvm.liquid.amount = nvm.liquid.amount - count
if nvm.liquid.amount == 0 then
nvm.liquid.name = nil
end
return {name = name, count = count}
end
end
end
local function legacy_items(full_container, item_count)
if full_container == "techage:isobutane" then
return {container = "", size = item_count, inv_item = full_container}
elseif full_container == "techage:oil_source" then
return {container = "", size = item_count, inv_item = full_container}
end
end
-- check if the wielded full container can be emptied into the tank
local function empty_on_punch(pos, nvm, full_container, item_count)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
local lqd_def = get_liquid_def(full_container) or legacy_items(full_container, item_count)
local ndef_lqd = LQD(pos)
if lqd_def and ndef_lqd then
local tank_size = ndef_lqd.capa or 0
if not nvm.liquid.name or lqd_def.inv_item == nvm.liquid.name then
if nvm.liquid.amount + lqd_def.size <= tank_size then
nvm.liquid.amount = nvm.liquid.amount + lqd_def.size
nvm.liquid.name = lqd_def.inv_item
return {name = lqd_def.container}
end
end
end
end
function techage.liquid.on_punch(pos, node, puncher, pointed_thing)
local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, puncher:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
mem.blocking_time = mem.blocking_time or 0
if mem.blocking_time > techage.SystemTime then
return
end
local wielded_item = puncher:get_wielded_item():get_name()
local item_count = puncher:get_wielded_item():get_count()
local new_item = fill_on_punch(nvm, wielded_item, item_count, puncher)
or empty_on_punch(pos, nvm, wielded_item, item_count)
if new_item then
puncher:set_wielded_item(new_item)
M(pos):set_string("formspec", techage.fuel.formspec(pos, nvm))
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
return
end
end
function techage.liquid.get_liquid_amount(nvm)
if nvm.liquid and nvm.liquid.amount then
return nvm.liquid.amount
end
return 0
end
techage.liquid.get_liquid_def = get_liquid_def
techage.liquid.get_container_def = get_container_def
techage.liquid.is_container_empty = is_container_empty
techage.liquid.get_full_container = get_full_container
techage.liquid.fill_container = fill_container
techage.liquid.empty_container = empty_container
techage.liquid.fill_on_punch = fill_on_punch
techage.liquid.empty_on_punch = empty_on_punch

View File

@ -1,91 +0,0 @@
techage.manual_DE = {}
techage.manual_DE.aTitel = {
"1,SaferLua Controller with Periphery",
"2,SaferLua Controller",
"3,Central Server",
"3,SaferLua Controller Terminal",
}
techage.manual_DE.aText = {
"",
"The SaferLua Controller is a small computer programmable in Lua to control your machinery.\n"..
"In contrast to the SmartLine Controller this controller allows to implement larger and smarter control and monitoring tasks.\n"..
"\n"..
"The controller can be programmed in SaferLua a subset of Lua for safe and secure Lua programs the Minetest server.\n"..
"\n",
"The Server node can be placed everywhere. It can also be used for communication purposes between several Controllers.\n"..
"The Server has a form to enter valid usernames for server access.\n"..
"\n"..
"The controller has a menu form with the following tabs:\n"..
"\n"..
" - the 'init' tab for the initialization code block\n"..
" - the 'func' tab for the Lua functions\n"..
" - the 'loop' tab for the main code block\n"..
" - the 'outp' tab for debugging outputs via '$print()'\n"..
" - the 'notes' tab for your code snippets or other notes\n"..
" - the 'help' tab with information to the available commands\n"..
"\n"..
"\n"..
"The controller needs battery power to work.\n"..
"\n",
"The Terminal is used to send command strings to the controller.\n"..
"In turn\\, the controller can send text strings to the terminal.\n"..
"The Terminal has a help system for internal commands. Its supports the following commands:\n"..
"\n"..
" - 'clear' = clear the screen\n"..
" - 'help' = output this message\n"..
" - 'pub' = switch terminal to public use (everybody can enter commands)\n"..
" - 'priv' = switch terminal to private use (only the owner can enter commands)\n"..
" - 'send <num> on/off' = send on/off event to e. g. lamps (for testing purposes)\n"..
" - 'msg <num> <text>' = send a text message to another Controller (for testing purposes)\n"..
"\n"..
"\n",
}
techage.manual_DE.aItemName = {
"",
"",
"",
"",
}
techage.manual_DE.aPlanTable = {
"",
"",
"",
"",
}

View File

@ -1,98 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
mark.lua:
]]--
local marker_region = {}
function techage.unmark_region(name)
if marker_region[name] ~= nil then --marker already exists
--wip: make the area stay loaded somehow
for _, entity in ipairs(marker_region[name]) do
entity:remove()
end
marker_region[name] = nil
end
end
function techage.mark_region(name, pos1, pos2, owner, secs)
if not name or not pos1 or not pos2 then return end
techage.unmark_region(name)
local thickness = 0.2
local sizex, sizey, sizez = (1 + pos2.x - pos1.x) / 2, (1 + pos2.y - pos1.y) / 2, (1 + pos2.z - pos1.z) / 2
local markers = {}
--XY plane markers
for _, z in ipairs({pos1.z - 0.5, pos2.z + 0.5}) do
local marker = minetest.add_entity({x=pos1.x + sizex - 0.5, y=pos1.y + sizey - 0.5, z=z}, "techage:region_cube")
if marker ~= nil then
marker:set_properties({
visual_size={x=sizex * 2, y=sizey * 2},
--collisionbox = {-sizex, -sizey, -thickness, sizex, sizey, thickness},
collisionbox = {0,0,0, 0,0,0},
})
if owner then
marker:set_nametag_attributes({text = owner})
end
marker:get_luaentity().player_name = name
table.insert(markers, marker)
end
end
--YZ plane markers
for _, x in ipairs({pos1.x - 0.5, pos2.x + 0.5}) do
local marker = minetest.add_entity({x=x, y=pos1.y + sizey - 0.5, z=pos1.z + sizez - 0.5}, "techage:region_cube")
if marker ~= nil then
marker:set_properties({
visual_size={x=sizez * 2, y=sizey * 2},
--collisionbox = {-thickness, -sizey, -sizez, thickness, sizey, sizez},
collisionbox = {0,0,0, 0,0,0},
})
marker:set_yaw(math.pi / 2)
marker:get_luaentity().player_name = name
table.insert(markers, marker)
end
end
marker_region[name] = markers
minetest.after(secs or 20, techage.unmark_region, name)
end
function techage.switch_region(name, pos1, pos2)
if marker_region[name] ~= nil then --marker already exists
techage.unmark_region(name)
else
techage.mark_region(name, pos1, pos2)
end
end
minetest.register_entity(":techage:region_cube", {
initial_properties = {
visual = "upright_sprite",
textures = {"techage_cube_mark.png"},
use_texture_alpha = true,
physical = false,
glow = 12,
},
on_step = function(self, dtime)
if marker_region[self.player_name] == nil then
self.object:remove()
return
end
end,
on_punch = function(self, hitter)
techage.unmark_region(self.player_name)
end,
})

View File

@ -1,128 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
mark.lua:
]]--
local marker_region = {}
function techage.unmark_position(name)
if marker_region[name] ~= nil then --marker already exists
--wip: make the area stay loaded somehow
for _, entity in ipairs(marker_region[name]) do
entity:remove()
end
marker_region[name] = nil
end
end
function techage.mark_position(name, pos, nametag, color, time)
local marker = minetest.add_entity(pos, "techage:position_cube")
if marker ~= nil then
marker:set_nametag_attributes({color = color, text = nametag})
marker:get_luaentity().player_name = name
if not marker_region[name] then
marker_region[name] = {}
end
marker_region[name][#marker_region[name] + 1] = marker
end
minetest.after(time or 30, techage.unmark_position, name)
end
function techage.mark_cube(name, pos1, pos2, nametag, color, time)
local new_x = pos1.x + ((pos2.x - pos1.x) / 2)
local new_y = pos1.y + ((pos2.y - pos1.y) / 2)
local new_z = pos1.z + ((pos2.z - pos1.z) / 2)
local size_x = math.abs(pos1.x - pos2.x) + 1
local size_y = math.abs(pos1.y - pos2.y) + 1
local size_z = math.abs(pos1.z - pos2.z) + 1
local marker = minetest.add_entity(
{x = new_x, y = new_y, z = new_z}, "techage:position_cube")
if marker ~= nil then
marker:set_nametag_attributes({color = color, text = nametag, visual_size = {x = size_x, y = size_y, z = size_z}})
marker:get_luaentity().player_name = name
marker:set_properties({visual_size = {x = size_x, y = size_y, z = size_z}})
if not marker_region[name] then
marker_region[name] = {}
end
marker_region[name][#marker_region[name] + 1] = marker
end
minetest.after(time or 30, techage.unmark_position, name)
end
minetest.register_entity(":techage:position_cube", {
initial_properties = {
visual = "cube",
textures = {
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
},
use_texture_alpha = true,
physical = false,
visual_size = {x = 1.1, y = 1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 8,
},
on_step = function(self, dtime)
if marker_region[self.player_name] == nil then
self.object:remove()
return
end
end,
on_punch = function(self, hitter)
techage.unmark_position(self.player_name)
end,
})
function techage.mark_side(name, pos, dir, nametag, color, time)
local v = vector.multiply(tubelib2.Dir6dToVector[dir or 0], 0.7)
local pos2 = vector.add(pos, v)
local marker = minetest.add_entity(pos2, "techage:position_side")
if marker ~= nil then
marker:set_nametag_attributes({color = color, text = nametag})
marker:get_luaentity().player_name = name
if dir == 2 or dir == 4 then
marker:setyaw(math.pi / 2)
end
if not marker_region[name] then
marker_region[name] = {}
end
marker_region[name][#marker_region[name] + 1] = marker
end
minetest.after(time or 30, techage.unmark_position, name)
end
minetest.register_entity(":techage:position_side", {
initial_properties = {
visual = "upright_sprite",
textures = {"techage_side_mark.png"},
physical = false,
visual_size = {x = 1.1, y = 1.1, z = 1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 12,
},
on_step = function(self, dtime)
if marker_region[self.player_name] == nil then
self.object:remove()
return
end
end,
on_punch = function(self, hitter)
techage.unmark_position(self.player_name)
end,
})

View File

@ -1,130 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Block marker lib for door/move/fly controller
]]--
local MAX_NUM = 128
local marker = {}
local MarkedNodes = {} -- t[player] = {{entity, pos},...}
local MaxNumber = {}
local CurrentPos -- to mark punched entities
local function unmark_position(name, pos)
pos = vector.round(pos)
for idx,item in ipairs(MarkedNodes[name] or {}) do
if vector.equals(pos, item.pos) then
item.entity:remove()
table.remove(MarkedNodes[name], idx)
CurrentPos = pos
return
end
end
end
function marker.unmark_all(name)
for _,item in ipairs(MarkedNodes[name] or {}) do
item.entity:remove()
end
MarkedNodes[name] = nil
end
local function mark_position(name, pos)
pos = vector.round(pos)
if not CurrentPos or not vector.equals(pos, CurrentPos) then -- entity not punched?
if #MarkedNodes[name] < MaxNumber[name] then
local entity = minetest.add_entity(pos, "techage:block_marker")
if entity ~= nil then
entity:get_luaentity().player_name = name
table.insert(MarkedNodes[name], {pos = pos, entity = entity})
end
CurrentPos = nil
return true
end
end
CurrentPos = nil
end
function marker.get_poslist(name)
local idx = 0
local lst = {}
for _,item in ipairs(MarkedNodes[name] or {}) do
table.insert(lst, item.pos)
idx = idx + 1
if idx >= MAX_NUM then break end
end
return lst
end
minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
if puncher and puncher:is_player() then
local name = puncher:get_player_name()
if not MarkedNodes[name] then
return
end
mark_position(name, pointed_thing.under)
end
end)
function marker.start(name, max_num)
MaxNumber[name] = max_num or 99
MarkedNodes[name] = {}
end
function marker.stop(name)
MarkedNodes[name] = nil
MaxNumber[name] = nil
end
minetest.register_on_leaveplayer(function(ObjectRef, timed_out)
if ObjectRef and ObjectRef:is_player() then
local name = ObjectRef:get_player_name()
marker.unmark_all(name)
end
end)
minetest.register_entity(":techage:block_marker", {
initial_properties = {
visual = "cube",
textures = {
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
},
physical = false,
visual_size = {x=1.1, y=1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 8,
},
on_step = function(self, dtime)
self.ttl = (self.ttl or 2400) - 1
if self.ttl <= 0 then
local pos = self.object:get_pos()
unmark_position(self.player_name, pos)
end
end,
on_punch = function(self, hitter)
local pos = self.object:get_pos()
local name = hitter:get_player_name()
if name == self.player_name then
unmark_position(name, pos)
end
end,
})
return marker

View File

@ -1,561 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
A state model/class for TechAge nodes.
]]--
--[[
Node states:
+-----------------------------------+ +------------+
| | | |
| V V |
| +---------+ |
| | | |
| +---------| STOPPED | |
| | | | |
| button | +---------+ |
| | ^ |
button | V | button |
| +---------+ | | button
| +--------->| |---------+ |
| | power | RUNNING | |
| | +------| |---------+ |
| | | +---------+ | |
| | | ^ | | |
| | | | | | |
| | V | V V |
| +---------+ +----------+ +---------+ |
| | | | | | | |
+---| NOPOWER | | STANDBY/ | | FAULT |----------+
| | | BLOCKED | | |
+---------+ +----------+ +---------+
| cycle time operational needs power
+---------+------------+-------------+-------------
| RUNNING normal yes yes
| BLOCKED long yes no
| STANDBY long yes no
| NOPOWER long no no
| FAULT none no no
| STOPPED none no no
Node nvm data:
"techage_state" - node state, like "RUNNING"
"techage_countdown" - countdown to standby mode
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local N = techage.get_node_lvm
local MAX_CYCLE_TIME = 20
--
-- TechAge machine states
--
techage.RUNNING = 1 -- in normal operation/turned on
techage.BLOCKED = 2 -- a pushing node is blocked due to a full destination inventory
techage.STANDBY = 3 -- nothing to do (e.g. no input items), or node (world) not loaded
techage.NOPOWER = 4 -- only for power consuming nodes, no operation
techage.FAULT = 5 -- any fault state (e.g. wrong source items), which can be fixed by the player
techage.STOPPED = 6 -- not operational/turned off
techage.UNLOADED = 7 -- Map block unloaded
techage.INACTIVE = 8 -- Map block loaded but node is not actively working
techage.StatesImg = {
"techage_inv_button_on.png",
"techage_inv_button_warning.png",
"techage_inv_button_standby.png",
"techage_inv_button_nopower.png",
"techage_inv_button_error.png",
"techage_inv_button_off.png",
}
local function error(pos, msg)
minetest.log("error", "[TA states] "..msg.." at "..S(pos).." "..N(pos).name)
end
-- Return state button image for the node inventory
function techage.state_button(state)
if state and state < 7 and state > 0 then
return techage.StatesImg[state]
end
return "techage_inv_button_off.png"
end
function techage.get_power_image(pos, nvm)
local node = techage.get_node_lvm(pos)
local s = "3" -- electrical power
if string.find(node.name, "techage:ta2") then
s = "2" -- axles power
end
return "techage_inv_powerT"..s..".png"
end
-- State string based on button states
techage.StateStrings = {"running", "blocked", "standby", "nopower", "fault", "stopped"}
--
-- Local States
--
local RUNNING = techage.RUNNING
local BLOCKED = techage.BLOCKED
local STANDBY = techage.STANDBY
local NOPOWER = techage.NOPOWER
local FAULT = techage.FAULT
local STOPPED = techage.STOPPED
--
-- NodeStates Class Functions
--
techage.NodeStates = {}
local NodeStates = techage.NodeStates
local function can_start(pos, nvm)
--if false, node goes in FAULT
return true
end
local function has_power(pos, nvm)
--if false, node goes in NOPOWER
return true
end
local function swap_node(pos, new_name, old_name)
local node = techage.get_node_lvm(pos)
if node.name == new_name then
return
end
if node.name == old_name then
node.name = new_name
minetest.swap_node(pos, node)
end
end
-- true if node_timer should be executed
function techage.is_operational(nvm)
local state = nvm.techage_state or STOPPED
return state < NOPOWER
end
function techage.is_running(nvm)
return (nvm.techage_state or STOPPED) == RUNNING
end
-- consumes power
function techage.needs_power(nvm)
local state = nvm.techage_state or STOPPED
return state == RUNNING or state == NOPOWER
end
-- consumes power
function techage.needs_power2(state)
state = state or STOPPED
return state == RUNNING or state == NOPOWER
end
function techage.get_state_string(nvm)
return techage.StateStrings[nvm.techage_state or STOPPED]
end
function NodeStates:new(attr)
local o = {
-- mandatory
cycle_time = attr.cycle_time, -- for running state
standby_ticks = attr.standby_ticks, -- for standby state
-- optional
countdown_ticks = attr.countdown_ticks or 1,
node_name_passive = attr.node_name_passive,
node_name_active = attr.node_name_active,
infotext_name = attr.infotext_name,
has_power = attr.has_power or has_power,
can_start = attr.can_start or can_start,
start_node = attr.start_node,
stop_node = attr.stop_node,
formspec_func = attr.formspec_func,
on_state_change = attr.on_state_change,
quick_start = attr.quick_start,
}
setmetatable(o, self)
self.__index = self
return o
end
function NodeStates:node_init(pos, nvm, number)
nvm.techage_state = STOPPED
M(pos):set_string("node_number", number)
if self.infotext_name then
M(pos):set_string("infotext", self.infotext_name.." "..number..": stopped")
end
if self.formspec_func then
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm))
end
end
-- to be used to re-start the timer outside of node_timer()
local function start_timer_delayed(pos, cycle_time)
local t = minetest.get_node_timer(pos)
t:stop()
if cycle_time > 0.9 then
minetest.after(0.1, t.start, t, cycle_time)
else
error(pos, "invalid cycle_time")
end
end
function NodeStates:stop(pos, nvm)
local state = nvm.techage_state or STOPPED
nvm.techage_state = STOPPED
if self.stop_node then
self.stop_node(pos, nvm, state)
end
if self.node_name_passive then
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
M(pos):set_string("infotext", self.infotext_name.." "..number..": stopped")
end
if self.formspec_func then
nvm.ta_state_tooltip = "stopped"
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm))
end
if self.on_state_change then
self.on_state_change(pos, state, STOPPED)
end
if minetest.get_node_timer(pos):is_started() then
minetest.get_node_timer(pos):stop()
end
return true
end
function NodeStates:start(pos, nvm)
local state = nvm.techage_state or STOPPED
if state ~= RUNNING and state ~= FAULT then
local res = self.can_start(pos, nvm, state)
if res ~= true then
self:fault(pos, nvm, res)
return false
end
if not self.has_power(pos, nvm, state) then
self:nopower(pos, nvm)
return false
end
nvm.techage_state = RUNNING
if self.start_node then
self.start_node(pos, nvm, state)
end
nvm.techage_countdown = self.countdown_ticks
if self.node_name_active then
swap_node(pos, self.node_name_active, self.node_name_passive)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
M(pos):set_string("infotext", self.infotext_name.." "..number..": running")
end
if self.formspec_func then
nvm.ta_state_tooltip = "running"
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm))
end
if minetest.get_node_timer(pos):is_started() then
minetest.get_node_timer(pos):stop()
end
if self.on_state_change then
self.on_state_change(pos, state, RUNNING)
end
start_timer_delayed(pos, self.cycle_time)
if self.quick_start and state == STOPPED then
self.quick_start(pos, 0)
end
self:trigger_state(pos, nvm)
return true
end
return false
end
function NodeStates:standby(pos, nvm, err_string)
local state = nvm.techage_state or STOPPED
if state == RUNNING or state == BLOCKED then
nvm.techage_state = STANDBY
if self.node_name_passive then
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..(err_string or "standby"))
end
if self.formspec_func then
nvm.ta_state_tooltip = err_string or "standby"
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm))
end
if self.on_state_change then
self.on_state_change(pos, state, STANDBY)
end
start_timer_delayed(pos, self.cycle_time * self.standby_ticks)
return true
end
return false
end
-- special case of standby for pushing nodes
function NodeStates:blocked(pos, nvm, err_string)
local state = nvm.techage_state or STOPPED
if state == RUNNING then
nvm.techage_state = BLOCKED
if self.node_name_passive then
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..(err_string or "blocked"))
end
if self.formspec_func then
nvm.ta_state_tooltip = err_string or "blocked"
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm))
end
if self.on_state_change then
self.on_state_change(pos, state, BLOCKED)
end
start_timer_delayed(pos, self.cycle_time * self.standby_ticks)
return true
end
return false
end
function NodeStates:nopower(pos, nvm, err_string)
local state = nvm.techage_state or RUNNING
if state ~= NOPOWER then
nvm.techage_state = NOPOWER
if self.node_name_passive then
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..(err_string or "no power"))
end
if self.formspec_func then
nvm.ta_state_tooltip = err_string or "no power"
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm))
end
if self.on_state_change then
self.on_state_change(pos, state, NOPOWER)
end
start_timer_delayed(pos, self.cycle_time * self.standby_ticks)
return true
end
return false
end
function NodeStates:fault(pos, nvm, err_string)
local state = nvm.techage_state or STOPPED
err_string = err_string or "fault"
if state == RUNNING or state == STOPPED then
nvm.techage_state = FAULT
if self.node_name_passive then
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..err_string)
end
if self.formspec_func then
nvm.ta_state_tooltip = err_string or "fault"
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm))
end
if self.on_state_change then
self.on_state_change(pos, state, FAULT)
end
minetest.get_node_timer(pos):stop()
return true
end
return false
end
function NodeStates:get_state(nvm)
return nvm.techage_state or techage.STOPPED
end
-- keep the timer running?
function NodeStates:is_active(nvm)
local state = nvm.techage_state or STOPPED
return state < FAULT
end
function NodeStates:start_if_standby(pos)
local nvm = techage.get_nvm(pos)
if nvm.techage_state == STANDBY then
self:start(pos, nvm)
end
end
-- To be called if node is idle.
-- If countdown reaches zero, the node is set to STANDBY.
function NodeStates:idle(pos, nvm)
local countdown = (nvm.techage_countdown or 0) - 1
nvm.techage_countdown = countdown
if countdown <= 0 then
self:standby(pos, nvm)
end
end
-- To be called after successful node action to raise the timer
-- and keep the node in state RUNNING
function NodeStates:keep_running(pos, nvm, val)
-- set to RUNNING if not already done
if nvm.techage_state ~= RUNNING then
self:start(pos, nvm)
end
nvm.techage_countdown = val or 4
nvm.last_active = minetest.get_gametime()
end
function NodeStates:trigger_state(pos, nvm)
nvm.last_active = minetest.get_gametime()
end
-- Start/stop node based on button events.
-- if function returns false, no button was pressed
function NodeStates:state_button_event(pos, nvm, fields)
if fields.state_button ~= nil then
local state = nvm.techage_state or STOPPED
if state == STOPPED or state == STANDBY or state == BLOCKED then
if not self:start(pos, nvm) and (state == STANDBY or state == BLOCKED) then
self:stop(pos, nvm)
end
elseif state == RUNNING or state == FAULT or state == NOPOWER then
self:stop(pos, nvm)
end
return true
end
return false
end
function NodeStates:get_state_button_image(nvm)
local state = nvm.techage_state or STOPPED
return techage.state_button(state)
end
function NodeStates:get_state_tooltip(nvm)
local tp = nvm.ta_state_tooltip or ""
return tp..";#0C3D32;#FFFFFF"
end
-- command interface
function NodeStates:on_receive_message(pos, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "on" then
self:start(pos, techage.get_nvm(pos))
return true
elseif topic == "off" then
self:stop(pos, techage.get_nvm(pos))
return true
elseif topic == "state" then
local node = minetest.get_node(pos)
if node.name == "ignore" then -- unloaded node?
return "unloaded"
elseif nvm.techage_state == RUNNING then
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
if ttl < minetest.get_gametime() then
return "inactive"
end
end
return techage.get_state_string(techage.get_nvm(pos))
elseif topic == "fuel" then
return techage.fuel.get_fuel_amount(nvm)
elseif topic == "load" then
return techage.liquid.get_liquid_amount(nvm)
else
return "unsupported"
end
end
function NodeStates:on_beduino_receive_cmnd(pos, topic, payload)
if topic == 1 then
if payload[1] == 0 then
self:stop(pos, techage.get_nvm(pos))
return 0
else
self:start(pos, techage.get_nvm(pos))
return 0
end
else
return 2 -- unknown or invalid topic
end
end
function NodeStates:on_beduino_request_data(pos, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 129 then
local node = minetest.get_node(pos)
if node.name == "ignore" then -- unloaded node?
return 0, {techage.UNLOADED}
elseif nvm.techage_state == RUNNING then
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
if ttl < minetest.get_gametime() then
return 0, {techage.INACTIVE}
end
end
return 0, {nvm.techage_state or STOPPED}
else
return 2, "" -- topic is unknown or invalid
end
end
function NodeStates.get_beduino_state(pos)
local node = minetest.get_node(pos)
local nvm = techage.get_nvm(pos)
if node.name == "ignore" then -- unloaded node?
return 0, {techage.UNLOADED}
elseif nvm.techage_state == RUNNING then
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
if ttl < minetest.get_gametime() then
return 0, {techage.INACTIVE}
end
end
return 0, {nvm.techage_state or STOPPED}
end
-- restart timer
function NodeStates:on_node_load(pos)
local nvm = techage.get_nvm(pos)
local state = nvm.techage_state or STOPPED
if state == RUNNING then
minetest.get_node_timer(pos):start(self.cycle_time)
elseif state < FAULT then
minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks)
end
end
minetest.register_node("techage:defect_dummy", {
description = "Corrupted Node (to be replaced)",
tiles = {
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_defect.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_defect.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_defect.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_defect.png",
},
drop = "",
groups = {cracky=2, crumbly=2, choppy=2, not_in_creative_inventory=1},
is_ground_content = false,
})

View File

@ -1,183 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Data storage system for node related volatile and non-volatile data.
Non-volatile data is stored from time to time and at shutdown.
Volatile data is lost at every shutdown.
]]--
local NvmStore = {} -- non-volatile data cache
local MemStore = {} -- volatile data cache
local N = function(pos) print(minetest.pos_to_string(pos), minetest.get_node(pos).name) end
-------------------------------------------------------------------
-- Backend
-------------------------------------------------------------------
local MP = minetest.get_modpath("techage")
local techage_use_sqlite = minetest.settings:get_bool('techage_use_sqlite', false)
local backend
if techage_use_sqlite then
backend = dofile(MP .. "/basis/nodedata_sqlite.lua")
else
backend = dofile(MP .. "/basis/nodedata_meta.lua")
end
-- return keys for mapblock and inner-mapblock addressing based on the node position
local function get_keys(pos)
local kx1, kx2 = math.floor(pos.x / 16) + 2048, pos.x % 16
local ky1, ky2 = math.floor(pos.y / 16) + 2048, pos.y % 16
local kz1, kz2 = math.floor(pos.z / 16) + 2048, pos.z % 16
return kx1 * 4096 * 4096 + ky1 * 4096 + kz1, kx2 * 16 * 16 + ky2 * 16 + kz2
end
local function pos_from_key(key1, key2)
local x1 = (math.floor(key1 / (4096 * 4096)) - 2048) * 16
local y1 = ((math.floor(key1 / 4096) % 4096) - 2048) * 16
local z1 = ((key1 % 4096) - 2048) * 16
local x2 = math.floor(key2 / (16 * 16))
local y2 = math.floor(key2 / 16) % 16
local z2 = key2 % 16
return {x = x1 + x2, y = y1 + y2, z = z1 + z2}
end
local function debug(key1, item)
--local pos1 = pos_from_key(key1, 0)
--local pos2 = {x = pos1.x + 15, y = pos1.y + 15, z = pos1.z + 15}
--techage.mark_region("mapblock", pos1, pos2, "singleplayer", 5)
local cnt = 0
for key2, tbl in pairs(item) do
if key2 ~= "in_use" then
cnt = cnt + 1
--N(pos_from_key(key1, key2))
end
end
print("mapblock", string.format("%09X", key1), cnt.." nodes")
end
-------------------------------------------------------------------
-- Storage scheduler
-------------------------------------------------------------------
local CYCLE_TIME = 600 -- store data every 10 min
local JobQueue = {}
local first = 0
local last = -1
local SystemTime = 0
local function push(key)
last = last + 1
JobQueue[last] = {key = key, time = SystemTime + CYCLE_TIME}
end
local function pop()
if first > last then return end
local item = JobQueue[first]
if item.time <= SystemTime then
JobQueue[first] = nil -- to allow garbage collection
first = first + 1
return item.key
end
end
-- check every 100 msec if any data has to be stored
minetest.register_globalstep(function(dtime)
SystemTime = SystemTime + dtime
local key = pop()
if key and NvmStore[key] then
-- minetest.log("warning",
-- string.format("[TA Storage] SystemTime = %.3f, #JobQueue = %d, in_use = %s",
-- SystemTime, last - first, NvmStore[key].in_use))
local t = minetest.get_us_time()
if NvmStore[key].in_use then
NvmStore[key].in_use = nil
backend.store_mapblock_data(key, NvmStore[key])
push(key)
else
NvmStore[key] = nil -- remove unused data from cache
end
t = minetest.get_us_time() - t
if t > 20000 then
minetest.log("warning", "[TA Storage] duration = "..(t/1000.0).." ms")
end
end
end)
-------------------------------------------------------------------
-- Store/Restore NVM data
-------------------------------------------------------------------
NvmStore = backend.restore_at_startup()
minetest.register_on_shutdown(function()
backend.freeze_at_shutdown(NvmStore)
end)
-------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------
-- Returns volatile node data as table
function techage.get_mem(pos)
local hash = minetest.hash_node_position(pos)
if not MemStore[hash] then
MemStore[hash] = {}
end
return MemStore[hash]
end
-- Returns non-volatile node data as table
function techage.get_nvm(pos)
local key1, key2 = get_keys(pos)
if not NvmStore[key1] then
NvmStore[key1] = backend.get_mapblock_data(key1)
push(key1)
end
local block = NvmStore[key1]
block.in_use = true
if not block[key2] then
block[key2] = backend.get_node_data(pos)
end
return block[key2]
end
-- Returns true/false
function techage.has_nvm(pos)
local key1, key2 = get_keys(pos)
if not NvmStore[key1] then
NvmStore[key1] = backend.get_mapblock_data(key1)
push(key1)
end
return NvmStore[key1][key2] ~= nil
end
function techage.peek_nvm(pos)
local key1, key2 = get_keys(pos)
local block = NvmStore[key1] or {}
return block[key2] or {}
end
-- To be called when a node is removed
function techage.del_mem(pos)
local hash = minetest.hash_node_position(pos)
MemStore[hash] = nil
local key1, key2 = get_keys(pos)
NvmStore[key1] = NvmStore[key1] or backend.get_mapblock_data(key1)
NvmStore[key1][key2] = nil
backend.store_mapblock_data(key1, NvmStore[key1])
end

View File

@ -1,103 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Storage backend for node related data as node metadata
]]--
-- for lazy programmers
local M = minetest.get_meta
local storage = techage.storage
-------------------------------------------------------------------
-- Marshaling
-------------------------------------------------------------------
local use_marshal = minetest.settings:get_bool('techage_use_marshal', false)
local MAR_MAGIC = 0x8e
-- default functions
local serialize = minetest.serialize
local deserialize = minetest.deserialize
if use_marshal then
if not techage.IE then
error("Please add 'secure.trusted_mods = techage' to minetest.conf!")
end
local marshal = techage.IE.require("marshal")
if not marshal then
error("Please install marshal via 'luarocks install lua-marshal'")
end
serialize = marshal.encode
deserialize = function(s)
if s ~= "" then
if s:byte(1) == MAR_MAGIC then
return marshal.decode(s)
else
return minetest.deserialize(s)
end
end
end
end
-------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------
local api = {}
function api.get_mapblock_data(key)
return {}
end
function api.store_mapblock_data(key, mapblock_data)
for key, item in pairs(mapblock_data) do
if key ~= "in_use" then
local pos = item and item._POS_
if pos then
item._POS_ = nil
local data = serialize(item)
item._POS_ = pos
local meta = M(pos)
meta:set_string("ta_data", data)
meta:mark_as_private("ta_data")
end
end
end
end
function api.get_node_data(pos)
local tbl = {}
local s = M(pos):get_string("ta_data")
if s ~= "" then
tbl = deserialize(s) or {}
end
tbl._POS_ = table.copy(pos)
return tbl
end
-- Meta data can't be written reliable at shutdown,
-- so we have to store/restore the data differently
function api.freeze_at_shutdown(data)
storage:set_string("shutdown_nodedata", serialize(data))
end
function api.restore_at_startup()
local s = storage:get_string("shutdown_nodedata")
if s ~= "" then
return deserialize(s) or {}
end
return {}
end
return api

View File

@ -1,123 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Storage backend for node related data via sqlite database
]]--
-- for lazy programmers
local M = minetest.get_meta
-------------------------------------------------------------------
-- Database
-------------------------------------------------------------------
local MN = minetest.get_current_modname()
local WP = minetest.get_worldpath()
local use_marshal = minetest.settings:get_bool('techage_use_marshal', false)
local MAR_MAGIC = 0x8e
if not techage.IE then
error("Please add 'secure.trusted_mods = techage' to minetest.conf!")
end
local sqlite3 = techage.IE.require("lsqlite3")
local marshal = techage.IE.require("marshal")
if not sqlite3 then
error("Please install sqlite3 via 'luarocks install lsqlite3'")
end
if not marshal then
error("Please install marshal via 'luarocks install lua-marshal'")
end
local db = sqlite3.open(WP.."/techage_nodedata.sqlite")
local ROW = sqlite3.ROW
-- Prevent use of this db instance.
if sqlite3 then sqlite3 = nil end
db:exec[[
CREATE TABLE mapblocks(id INTEGER PRIMARY KEY, key INTEGER, data BLOB);
CREATE UNIQUE INDEX idx ON mapblocks(key);
]]
local set = db:prepare("INSERT or REPLACE INTO mapblocks VALUES(NULL, ?, ?);")
local get = db:prepare("SELECT * FROM mapblocks WHERE key=?;")
local function set_block(key, data)
set:reset()
set:bind(1, key)
set:bind_blob(2, data)
set:step()
end
local function get_block(key)
get:reset()
get:bind(1, key)
if get:step() == ROW then
return get:get_value(2)
end
end
-------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------
local api = {}
function api.store_mapblock_data(key, mapblock_data)
if use_marshal and mapblock_data then
local data = marshal.encode(mapblock_data)
if data then
set_block(key, data)
end
else
set_block(key, minetest.serialize(mapblock_data))
end
end
function api.get_mapblock_data(key)
local s = get_block(key)
if s then
if s:byte(1) == MAR_MAGIC then
return marshal.decode(s)
else
return minetest.deserialize(s)
end
end
api.store_mapblock_data(key, {})
return {}
end
function api.get_node_data(pos)
-- legacy data available?
local s = M(pos):get_string("ta_data")
if s ~= "" then
M(pos):set_string("ta_data", "")
if s:byte(1) == MAR_MAGIC then
return marshal.decode(s)
else
return minetest.deserialize(s)
end
end
return {}
end
function api.freeze_at_shutdown(data)
for key, item in pairs(data) do
api.store_mapblock_data(key, item)
end
end
function api.restore_at_startup()
-- nothing to restore
return {}
end
return api

View File

@ -1,142 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Storage backend for node number mapping via sqlite database
]]--
-- for lazy programmers
local M = minetest.get_meta
local storage = techage.storage
-------------------------------------------------------------------
-- Database
-------------------------------------------------------------------
local MN = minetest.get_current_modname()
local WP = minetest.get_worldpath()
local MAR_MAGIC = 0x8e
if not techage.IE then
error("Please add 'secure.trusted_mods = techage' to minetest.conf!")
end
local sqlite3 = techage.IE.require("lsqlite3")
local marshal = techage.IE.require("marshal")
if not sqlite3 then
error("Please install sqlite3 via 'luarocks install lsqlite3'")
end
if not marshal then
error("Please install marshal via 'luarocks install lua-marshal'")
end
local db = sqlite3.open(WP.."/techage_numbers.sqlite")
local ROW = sqlite3.ROW
-- Prevent use of this db instance.
if sqlite3 then sqlite3 = nil end
db:exec[[
CREATE TABLE numbers(id INTEGER PRIMARY KEY, number INTEGER, x INTEGER, y INTEGER, z INTEGER);
CREATE UNIQUE INDEX idx ON numbers(number);
]]
local set = db:prepare("INSERT or REPLACE INTO numbers VALUES(NULL, ?, ?, ?, ?);")
local get = db:prepare("SELECT * FROM numbers WHERE number=?;")
local function set_block(number, pos)
set:reset()
set:bind(1, number)
set:bind(2, pos.x)
set:bind(3, pos.y)
set:bind(4, pos.z)
set:step()
return true
end
local function get_block(number)
get:reset()
get:bind(1, number)
if get:step() == ROW then
return {x = get:get_value(2), y = get:get_value(3), z = get:get_value(4)}
end
end
local function del_block(number)
db:exec("DELETE FROM numbers WHERE number="..number..";")
end
-------------------------------------------------------------------
-- Migration from mod storage
-------------------------------------------------------------------
local Version = storage:get_int("Version") or 0
local NextNumber = 0
if Version == 0 then
Version = 4
end
if Version == 3 then
Version = 4
NextNumber = storage:get_int("NextNumber")
for i = 1, NextNumber do
local number = tostring(i)
if storage:contains(number) then
local pos = minetest.string_to_pos(storage:get_string(number))
set_block(number, pos)
storage:set_string(number, "")
end
end
elseif Version == 4 then
NextNumber = storage:get_int("NextNumber")
else
error("[] Invalid version number for 'number to pos mapping' table!")
end
-------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------
local api = {}
function api.get_nodepos(number)
return get_block(number)
end
function api.set_nodepos(number, pos)
set_block(number, pos)
end
function api.add_nodepos(pos)
local num = tostring(NextNumber)
NextNumber = NextNumber + 1
storage:set_int("NextNumber", NextNumber)
set_block(num, pos)
return num
end
function api.del_nodepos(number)
del_block(number)
end
-- delete invalid entries
function api.delete_invalid_entries(node_def)
minetest.log("info", "[TechAge] Data maintenance started")
for id, num, x, y, z in db:urows('SELECT * FROM numbers') do
local pos = {x = x, y = y, z = z}
local name = techage.get_node_lvm(pos).name
if not node_def[name] then
del_block(num)
end
end
minetest.log("info", "[TechAge] Data maintenance finished")
end
return api

View File

@ -1,98 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Storage backend for node number mapping via mod storage
]]--
local backend = {}
local storage = techage.storage
-- legacy method
local function deserialize(s)
local tbl = {}
for line in s:gmatch("[^;]+") do
local num, spos = unpack(string.split(line, "="))
tbl[num] = minetest.string_to_pos(spos)
end
return tbl
end
local Version = minetest.deserialize(storage:get_string("Version")) or 3
local NextNumber = 0
if Version == 1 then
Version = 3
local tbl = minetest.deserialize(storage:get_string("Number2Pos")) or {}
NextNumber = minetest.deserialize(storage:get_string("NextNumber")) or 1
for num, pos in pairs(tbl) do
storage:set_string(num, minetest.pos_to_string(pos))
end
storage:set_string("Number2Pos", "")
elseif Version == 2 then
Version = 3
NextNumber = minetest.deserialize(storage:get_string("NextNumber")) or 1
local tbl = deserialize(storage:get_string("Number2Pos"))
for num, pos in pairs(tbl) do
storage:set_string(num, minetest.pos_to_string(pos))
end
storage:set_string("Number2Pos", "")
else
Version = 3
NextNumber = storage:get_int("NextNumber")
end
storage:set_int("NextNumber", NextNumber)
storage:set_int("Version", Version)
-------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------
function backend.get_nodepos(number)
return minetest.string_to_pos(storage:get_string(number))
end
function backend.set_nodepos(number, pos)
storage:set_string(number, minetest.pos_to_string(pos))
end
function backend.add_nodepos(pos)
local num = tostring(NextNumber)
NextNumber = NextNumber + 1
storage:set_int("NextNumber", NextNumber)
storage:set_string(num, minetest.pos_to_string(pos))
return num
end
function backend.del_nodepos(number)
storage:set_string(number, "")
end
-- delete invalid entries
function backend.delete_invalid_entries(node_def)
minetest.log("info", "[TechAge] Data maintenance started")
for i = 1, NextNumber do
local number = tostring(i)
if storage:contains(number) then
local pos = backend.get_nodepos(number)
local name = techage.get_node_lvm(pos).name
if not node_def[name] then
backend.del_nodepos(number)
else
minetest.get_meta(pos):set_string("node_number", number)
end
end
end
minetest.log("info", "[TechAge] Data maintenance finished")
end
return backend

View File

@ -1,103 +0,0 @@
techage.OggFileList = {
"autobahn_motor", -- ./mods/autobahn/sounds
"signs_bot_ping", -- ./mods/signs_bot/sounds
"signs_bot_go_away", -- ./mods/signs_bot/sounds
"signs_bot_step", -- ./mods/signs_bot/sounds
"signs_bot_pong", -- ./mods/signs_bot/sounds
"signs_bot_error", -- ./mods/signs_bot/sounds
"normal2", -- ./mods/hyperloop/sounds
"up2", -- ./mods/hyperloop/sounds
"down2", -- ./mods/hyperloop/sounds
"ele_norm", -- ./mods/hyperloop/sounds
"door", -- ./mods/hyperloop/sounds
"hyperloop_crowbar", -- ./mods/hyperloop/sounds
"ele_door", -- ./mods/hyperloop/sounds
"techage_watermill", -- ./mods/techage/sounds
"techage_button", -- ./mods/techage/sounds
"techage_steamengine", -- ./mods/techage/sounds
"techage_generator", -- ./mods/techage/sounds
"techage_gasflare", -- ./mods/techage/sounds
"techage_explore", -- ./mods/techage/sounds
"techage_mill", -- ./mods/techage/sounds
"techage_reactor", -- ./mods/techage/sounds
"techage_valve", -- ./mods/techage/sounds
"techage_oildrill", -- ./mods/techage/sounds
"techage_turbine", -- ./mods/techage/sounds
"techage_booster", -- ./mods/techage/sounds
"techage_quarry", -- ./mods/techage/sounds
"techage_reboiler", -- ./mods/techage/sounds
"jetpack_loop", -- ./mods/jetpack/sounds
"paperflip1", -- ./mods/unified_inventory/sounds
"teleport", -- ./mods/unified_inventory/sounds
"electricity", -- ./mods/unified_inventory/sounds
"owl", -- ./mods/unified_inventory/sounds
"click", -- ./mods/unified_inventory/sounds
"birds", -- ./mods/unified_inventory/sounds
"paperflip2", -- ./mods/unified_inventory/sounds
"dingdong", -- ./mods/unified_inventory/sounds
"trash", -- ./mods/unified_inventory/sounds
"trash_all", -- ./mods/unified_inventory/sounds
"ta4_jetpack", -- ./mods/ta4_jetpack/sounds
"ta4_jetpack_alarm", -- ./mods/ta4_jetpack/sounds
"ta4_jetpack_on", -- ./mods/ta4_jetpack/sounds
"player_damage", -- ./games/minetest_game/mods/player_api/sounds
"env_sounds_water", -- ./games/minetest_game/mods/env_sounds/sounds
"env_sounds_lava", -- ./games/minetest_game/mods/env_sounds/sounds
"doors_door_close", -- ./games/minetest_game/mods/doors/sounds
"doors_steel_door_close", -- ./games/minetest_game/mods/doors/sounds
"doors_door_open", -- ./games/minetest_game/mods/doors/sounds
"doors_fencegate_close", -- ./games/minetest_game/mods/doors/sounds
"doors_glass_door_close", -- ./games/minetest_game/mods/doors/sounds
"doors_fencegate_open", -- ./games/minetest_game/mods/doors/sounds
"doors_glass_door_open", -- ./games/minetest_game/mods/doors/sounds
"doors_steel_door_open", -- ./games/minetest_game/mods/doors/sounds
"fire_flint_and_steel", -- ./games/minetest_game/mods/fire/sounds
"fire_large", -- ./games/minetest_game/mods/fire/sounds
"fire_fire", -- ./games/minetest_game/mods/fire/sounds
"fire_extinguish_flame", -- ./games/minetest_game/mods/fire/sounds
"fire_small", -- ./games/minetest_game/mods/fire/sounds
"tnt_ignite", -- ./games/minetest_game/mods/tnt/sounds
"tnt_gunpowder_burning", -- ./games/minetest_game/mods/tnt/sounds
"tnt_explode", -- ./games/minetest_game/mods/tnt/sounds
"carts_cart_new", -- ./games/minetest_game/mods/carts/sounds
"carts_cart_moving", -- ./games/minetest_game/mods/carts/sounds
"xpanes_steel_bar_door_open", -- ./games/minetest_game/mods/xpanes/sounds
"xpanes_steel_bar_door_close", -- ./games/minetest_game/mods/xpanes/sounds
"default_break_glass", -- ./games/minetest_game/mods/default/sounds
"default_dig_dig_immediate", -- ./games/minetest_game/mods/default/sounds
"default_dig_cracky", -- ./games/minetest_game/mods/default/sounds
"default_dig_choppy", -- ./games/minetest_game/mods/default/sounds
"default_water_footstep", -- ./games/minetest_game/mods/default/sounds
"player_damage", -- ./games/minetest_game/mods/default/sounds
"default_gravel_footstep", -- ./games/minetest_game/mods/default/sounds
"default_dig_metal", -- ./games/minetest_game/mods/default/sounds
"default_gravel_dug", -- ./games/minetest_game/mods/default/sounds
"default_hard_footstep", -- ./games/minetest_game/mods/default/sounds
"default_sand_footstep", -- ./games/minetest_game/mods/default/sounds
"default_grass_footstep", -- ./games/minetest_game/mods/default/sounds
"default_chest_close", -- ./games/minetest_game/mods/default/sounds
"default_cool_lava", -- ./games/minetest_game/mods/default/sounds
"default_place_node_hard", -- ./games/minetest_game/mods/default/sounds
"default_ice_dug", -- ./games/minetest_game/mods/default/sounds
"default_dig_crumbly", -- ./games/minetest_game/mods/default/sounds
"default_tool_breaks", -- ./games/minetest_game/mods/default/sounds
"default_ice_footstep", -- ./games/minetest_game/mods/default/sounds
"default_dig_cracky", -- ./games/minetest_game/mods/default/sounds
"default_chest_open", -- ./games/minetest_game/mods/default/sounds
"default_gravel_dig", -- ./games/minetest_game/mods/default/sounds
"default_dig_oddly_breakable_by_hand", -- ./games/minetest_game/mods/default/sounds
"default_dug_metal", -- ./games/minetest_game/mods/default/sounds
"default_dirt_footstep", -- ./games/minetest_game/mods/default/sounds
"default_dig_choppy", -- ./games/minetest_game/mods/default/sounds
"default_glass_footstep", -- ./games/minetest_game/mods/default/sounds
"default_snow_footstep", -- ./games/minetest_game/mods/default/sounds
"default_place_node", -- ./games/minetest_game/mods/default/sounds
"default_dig_snappy", -- ./games/minetest_game/mods/default/sounds
"default_dug_node", -- ./games/minetest_game/mods/default/sounds
"default_metal_footstep", -- ./games/minetest_game/mods/default/sounds
"default_ice_dig", -- ./games/minetest_game/mods/default/sounds
"default_place_node_metal", -- ./games/minetest_game/mods/default/sounds
"default_wood_footstep", -- ./games/minetest_game/mods/default/sounds
"default_furnace_active", -- ./games/minetest_game/mods/default/sounds
"default_item_smoke", -- ./games/minetest_game/mods/default/sounds
}

View File

@ -1,88 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2024 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Packing functions
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local M = minetest.get_meta
-- string/usercode conversion
local function usercode_to_string(tbl)
if tbl and tbl.inventory then
for list_name,list in pairs(tbl.inventory) do
for i,item in ipairs(list) do
tbl.inventory[list_name][i] = item:to_string()
end
end
end
end
local function string_to_usercode(tbl)
if tbl and tbl.inventory then
for list_name,list in pairs(tbl.inventory) do
for i,item in ipairs(list) do
tbl.inventory[list_name][i] = ItemStack(item)
end
end
end
end
-- pack/unpack node nvm data
local function pack_nvm(pos)
if techage.has_nvm(pos) then
local s = minetest.serialize(techage.get_nvm(pos))
techage.del_mem(pos)
return s
end
end
local function unpack_nvm(pos, s)
if s and s ~= "" then
local tbl = minetest.deserialize(s)
local nvm = techage.get_nvm(pos)
for k,v in pairs(tbl) do
nvm.k = v
end
end
end
-- pack/unpack node metedata
local function pack_meta(pos)
local tbl = M(pos):to_table() or {}
usercode_to_string(tbl)
return minetest.serialize(tbl)
end
local function unpack_meta(pos, s)
if s and s ~= "" then
local tbl = minetest.deserialize(s) or {}
string_to_usercode(tbl)
M(pos):from_table(tbl)
end
end
-------------------------------------------------------------------------------
-- preserve/restore API functions
-------------------------------------------------------------------------------
function techage.preserve_nodedata(pos)
local smeta = pack_meta(pos)
local snvm = pack_nvm(pos)
return minetest.serialize({smeta = smeta, snvm = snvm})
end
function techage.restore_nodedata(pos, s)
local tbl = minetest.deserialize(s) or {}
unpack_nvm(pos, tbl.snvm)
unpack_meta(pos, tbl.smeta)
end

View File

@ -1,292 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Recipe lib for formspecs
]]--
local S = techage.S
local M = minetest.get_meta
local Recipes = {} -- {rtype = {ouput = {....},...}}
local NormalizedRecipes = {} -- {output = "", items = {...}}
local range = techage.in_range
techage.recipes = {}
local GROUP_ITEMS = {
stone = "default:cobble",
wood = "default:wood",
book = "default:book",
sand = "default:sand",
leaves = "default:leaves",
stick = "default:stick",
tree = "default:tree",
vessel = "vessels:glass_bottle",
wool = "wool:white",
}
local RECIPE = {
output = {name = "", num = 0},
waste = {name = "", num = 0},
input = {
{name = "", num =0},
{name = "", num =0},
{name = "", num =0},
{name = "", num =0},
},
}
local function filter_recipes_based_on_points(recipes, owner)
local ex_points = 0
if owner then
local player = minetest.get_player_by_name(owner)
ex_points = techage.get_expoints(player) or 0
end
local tbl = {}
for _,item in ipairs(recipes) do
if ex_points >= (item.ex_points or 0) then
tbl[#tbl + 1] = item
end
end
return tbl
end
-- Formspec
local function input_string(recipe)
local tbl = {}
for idx, item in ipairs(recipe.input) do
local x = ((idx-1) % 2)
local y = math.floor((idx-1) / 2)
tbl[idx] = techage.item_image(x, y, item.name.." "..item.num)
end
return table.concat(tbl, "")
end
function techage.recipes.get(nvm, rtype, owner)
local recipes = Recipes[rtype] or {}
if owner then
recipes = filter_recipes_based_on_points(recipes, owner)
end
return recipes[nvm.recipe_idx or 1] or recipes[1]
end
-- Add 4 input/output/waste recipe
-- {
-- output = "<item-name> <units>", -- units = 1..n
-- waste = "<item-name> <units>", -- units = 1..n
-- input = { -- up to 4 items
-- "<item-name> <units>",
-- "<item-name> <units>",
-- },
-- }
function techage.recipes.add(rtype, recipe)
if not Recipes[rtype] then
Recipes[rtype] = {}
end
local name, num, output
local item = {input = {}}
for idx = 1,4 do
local inp = recipe.input[idx] or ""
name, num = unpack(string.split(inp, " "))
item.input[idx] = {name = name or "", num = tonumber(num) or 0}
end
if recipe.waste then
name, num = unpack(string.split(recipe.waste, " "))
else
name, num = "", "0"
end
item.waste = {name = name or "", num = tonumber(num) or 0}
name, num = unpack(string.split(recipe.output, " "))
item.output = {name = name or "", num = tonumber(num) or 0}
item.catalyst = recipe.catalyst
item.ex_points = recipe.ex_points or 0
Recipes[rtype][#Recipes[rtype]+1] = item
output = name
techage.recipes.register_craft({
output = recipe.output,
items = recipe.input,
type = rtype,
})
NormalizedRecipes[output] = {
output = recipe.output,
items = recipe.input,
}
end
function techage.recipes.formspec(x, y, rtype, nvm, owner)
local recipes = Recipes[rtype] or {}
recipes = filter_recipes_based_on_points(recipes, owner)
nvm.recipe_idx = range(nvm.recipe_idx or 1, 1, #recipes)
local idx = nvm.recipe_idx
local recipe = recipes[idx] or RECIPE
local output = recipe.output.name.." "..recipe.output.num
local waste = recipe.waste.name.." "..recipe.waste.num
local catalyst = recipe.catalyst and techage.item_image_small(2.05, 0, recipe.catalyst, S("Catalyst")) or ""
return "container["..x..","..y.."]"..
"background[0,0;4,3;techage_form_grey.png]"..
input_string(recipe)..
"image[2,0.7;1,1;techage_form_arrow.png]"..
catalyst..
techage.item_image(2.95, 0, output)..
techage.item_image(2.95, 1, waste)..
"button[0,2;1,1;priv;<<]"..
"button[1,2;1,1;next;>>]"..
"label[1.9,2.2;"..S("Recipe")..": "..idx.."/"..#recipes.."]"..
"container_end[]"
end
function techage.recipes.on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
nvm.recipe_idx = nvm.recipe_idx or 1
if not nvm.running then
if fields.next == ">>" then
nvm.recipe_idx = nvm.recipe_idx + 1
return true
elseif fields.priv == "<<" then
nvm.recipe_idx = nvm.recipe_idx - 1
return true
end
end
end
function techage.recipes.get_recipe(name)
return NormalizedRecipes[name]
end
function techage.recipes.set_recipe(pos, rtype, idx)
local nvm = techage.get_nvm(pos)
if not nvm.running then
local recipes = Recipes[rtype] or {}
idx = tonumber(idx) or 1
nvm.recipe_idx = range(idx, 1, #recipes)
end
end
function techage.recipes.get_default_group_item_name(item_name)
if item_name and item_name:sub(1, 6) == "group:" then
local default_name = GROUP_ITEMS[item_name:sub(7)]
if default_name then
return default_name
end
end
return item_name
end
function techage.recipes.add_group_item(group, default_item_name)
GROUP_ITEMS[group] = default_item_name
end
-------------------------------------------------------------------------------
-- Borrowed from ghaydn
-------------------------------------------------------------------------------
local has_i3 = minetest.get_modpath("i3")
local has_ui = minetest.get_modpath("unified_inventory")
local has_cg = minetest.get_modpath("craftguide")
local function format_i3(input)
local output = {}
for _, entry in ipairs(input) do
local secondput = ""
if type(entry) == "table" then
for _, secondtry in ipairs(entry) do
secondput = secondput..secondtry..","
end
table.insert(output, secondput)
else
table.insert(output, entry)
end
end
return output
end
techage.recipes.register_craft_type = function(name, def)
if has_cg then
local cg_def = {
description = def.description,
icon = def.icon,
}
craftguide.register_craft_type(name, cg_def)
end
if has_i3 then
local i3_def = {
description = def.description,
icon = def.icon,
width = def.width or 3,
height = def.height or 3,
dynamic_display_size = def.dynamic_display_size or nil,
uses_crafting_grid = def.uses_crafting_grid,
}
i3.register_craft_type(name, i3_def)
end
if has_ui then
local ui_def = {
description = def.description,
icon = def.icon,
width = def.width or 3,
height = def.height or 3,
dynamic_display_size = def.dynamic_display_size or nil,
uses_crafting_grid = def.uses_crafting_grid,
}
unified_inventory.register_craft_type(name, ui_def)
end
end
techage.recipes.register_craft = function(def)
if not def.items then
if def.input then
def.items = table.copy(def.input)
elseif def.recipe then
def.items = table.copy(def.recipe)
end
end
if not def.result then
if def.output then def.result = def.output end
end
if has_cg then
local cg_def = {
result = def.result,
type = def.type,
items = def.items,
}
craftguide.register_craft(cg_def)
end
if has_i3 then
local i3_def = {
result = def.result,
type = def.type,
items = format_i3(def.items),
width = def.width or 3,
}
i3.register_craft(i3_def)
end
if has_ui then
local ui_def = {
output = def.result,
type = def.type,
items = def.items,
width = def.width or 3,
height = def.height or 3,
}
unified_inventory.register_craft(ui_def)
end
end

View File

@ -1,74 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Library for shared inventories
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local S = techage.S
techage.shared_inv = {}
local hyperloop = techage.hyperloop
local remote_pos = techage.hyperloop.remote_pos
local function copy_inventory_list(from_pos, to_pos, listname)
local inv1 = minetest.get_inventory({type="node", pos=from_pos})
local inv2 = minetest.get_inventory({type="node", pos=to_pos})
inv2:set_list(listname, inv1:get_list(listname))
end
function techage.shared_inv.node_timer(pos, elapsed)
local rmt_pos = remote_pos(pos)
if rmt_pos and techage.is_activeformspec(pos) then
copy_inventory_list(rmt_pos, pos, "main")
return true
end
return false
end
-- Synchronize the client inventory with the server one
function techage.shared_inv.before_inv_access(pos, listname)
if hyperloop.is_client(pos) then
local rmt_pos = remote_pos(pos)
if rmt_pos then
copy_inventory_list(rmt_pos, pos, listname)
return true
end
end
return false
end
-- Synchronize the client inventory with the server one
function techage.shared_inv.after_inv_access(pos, listname)
if hyperloop.is_client(pos) then
local rmt_pos = remote_pos(pos)
if rmt_pos then
copy_inventory_list(pos, rmt_pos, listname)
return true
end
end
return false
end
function techage.shared_inv.on_rightclick(pos, clicker, listname)
if hyperloop.is_client(pos) then
local rmt_pos = remote_pos(pos)
if rmt_pos then
copy_inventory_list(rmt_pos, pos, listname)
techage.set_activeformspec(pos, clicker)
minetest.get_node_timer(pos):start(2)
end
end
end

View File

@ -1,116 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Library for shared inventories
]]--
-- for lazy programmers
local M = minetest.get_meta
local NDEF = function(pos) return minetest.registered_nodes[techage.get_node_lvm(pos).name] or {} end
techage.shared_tank = {}
local liquid = networks.liquid
local hyperloop = techage.hyperloop
local remote_pos = techage.hyperloop.remote_pos
local is_paired = techage.hyperloop.is_paired
local menu = techage.menu
local function formspec(pos)
local ndef = NDEF(pos)
local status = M(pos):get_string("conn_status")
if hyperloop.is_client(pos) or hyperloop.is_server(pos) then
local title = ndef.description .. " " .. status
local nvm = techage.get_nvm(remote_pos(pos))
return techage.liquid.formspec(pos, nvm, title)
else
return menu.generate_formspec(pos, ndef, hyperloop.SUBMENU)
end
end
function techage.shared_tank.node_timer(pos)
if techage.is_activeformspec(pos) and is_paired(pos) then
M(pos):set_string("formspec", formspec(pos))
return true
end
return false
end
function techage.shared_tank.on_rightclick(pos, node, clicker)
--if hyperloop.is_client(pos) then
techage.set_activeformspec(pos, clicker)
minetest.get_node_timer(pos):start(2)
--end
M(pos):set_string("formspec", formspec(pos))
end
function techage.shared_tank.can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
pos = remote_pos(pos)
return techage.liquid.is_empty(pos)
end
function techage.shared_tank.peek_liquid(pos, indir)
if is_paired(pos) then
pos = remote_pos(pos)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end
end
function techage.shared_tank.take_liquid(pos, indir, name, amount)
if is_paired(pos) then
pos = remote_pos(pos)
local nvm = techage.get_nvm(pos)
amount, name = liquid.srv_take(nvm, name, amount)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return amount, name
end
return 0, name
end
function techage.shared_tank.put_liquid(pos, indir, name, amount)
if is_paired(pos) then
pos = remote_pos(pos)
-- check if it is not powder
local ndef = minetest.registered_craftitems[name] or {}
if not ndef.groups or ndef.groups.powder ~= 1 then
local nvm = techage.get_nvm(pos)
local ndef = NDEF(pos)
local leftover = liquid.srv_put(nvm, name, amount, ndef.liquid.capa)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return leftover
end
end
return amount
end
function techage.shared_tank.untake_liquid(pos, indir, name, amount)
if is_paired(pos) then
pos = remote_pos(pos)
local nvm = techage.get_nvm(pos)
local ndef = NDEF(pos)
local leftover = liquid.srv_put(nvm, name, amount, ndef.liquid.capa)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return leftover
end
return amount
end
techage.shared_tank.formspec = formspec

View File

@ -1,318 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
A formspec control to generate formspec strings for machine settings and monitoring
]]--
local S = techage.S
techage.menu = {}
local function index(list, x)
for idx, v in ipairs(list or {}) do
if tostring(v) == x then return idx end
end
return nil
end
local function allow_put(inv, listname, index, stack, player)
local list = inv:get_list(listname)
stack:set_count(1)
inv:set_stack(listname, index, stack)
return 0
end
local function allow_take(inv, listname, index, stack, player)
local list = inv:get_list(listname)
stack:set_count(0)
inv:set_stack(listname, index, stack)
return 0
end
-- generate the formspec string to be placed into a container frame
local function generate_formspec_substring(pos, meta, form_def, player_name)
local tbl = {}
local player_inv_needed = false
if meta and form_def then
local nvm = techage.get_nvm(pos)
for i,elem in ipairs(form_def) do
local offs = (i - 1) * 0.9 - 0.2
tbl[#tbl+1] = "label[0," .. offs .. ";" .. minetest.formspec_escape(elem.label) .. ":]"
tbl[#tbl+1] = "tooltip[0," .. offs .. ";4,1;" .. elem.tooltip .. "]"
if elem.type == "label" then
-- none
elseif elem.type == "number" then
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_int(elem.name)
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]"
end
elseif elem.type == "numbers" then
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name)
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]"
end
elseif elem.type == "float" then
local val = elem.default
if meta:contains(elem.name) then
val = tonumber(meta:get_string(elem.name)) or 0
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]"
end
elseif elem.type == "ascii" then
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name)
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. minetest.formspec_escape(val) .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. minetest.formspec_escape(val) .. "]"
end
elseif elem.type == "const" then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. elem.value .. "]"
elseif elem.type == "output" then
local val = nvm[elem.name] or meta:get_string(elem.name) or ""
if tonumber(val) then
val = techage.round(val)
end
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
elseif elem.type == "dropdown" then
if nvm.running or techage.is_running(nvm) then
local val = elem.default or ""
if meta:contains(elem.name) then
val = meta:get_string(elem.name) or ""
end
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
elseif elem.on_dropdown then -- block provides a specific list of choice elements
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name) or ""
end
local choices = elem.on_dropdown(pos)
local l = choices:split(",")
local idx = index(l, val) or 1
tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. choices .. ";" .. idx .. "]"
else
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name) or ""
end
local idx
if elem.values then
idx = index(elem.values, val) or 1
else
local l = elem.choices:split(",")
idx = index(l, val) or 1
end
tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]"
end
elseif elem.type == "items" then -- inventory
if elem.size then
tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]"
else
tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.width .. "," .. elem.height .. ";]"
end
player_inv_needed = true
end
end
if nvm.running or techage.is_running(nvm) then
local offs = #form_def * 0.9 - 0.2
tbl[#tbl+1] = "label[0," .. offs .. ";" .. S("Note: You can't change any values while the block is running!") .. "]"
end
end
return player_inv_needed, table.concat(tbl, "")
end
local function value_check(elem, value, player_name)
if elem.check then
return elem.check(value, player_name)
end
return value ~= nil
end
local function evaluate_data(pos, meta, form_def, fields, player_name)
local res = true
if meta and form_def then
local nvm = techage.get_nvm(pos)
if nvm.running or techage.is_running(nvm) then
return res
end
for idx,elem in ipairs(form_def) do
if elem.type == "number" then
if fields[elem.name] then
if fields[elem.name] == "" then
meta:set_string(elem.name, "")
elseif fields[elem.name]:find("^[%d ]+$") then
local val = tonumber(fields[elem.name])
if value_check(elem, val, player_name) then
meta:set_int(elem.name, val)
--print("set_int", elem.name, val)
else
res = false
end
else
res = false
end
end
elseif elem.type == "numbers" then
if fields[elem.name] then
if fields[elem.name] == "" then
meta:set_string(elem.name, "")
elseif fields[elem.name]:find("^[%d ]+$") and
value_check(elem, fields[elem.name], player_name) then
meta:set_string(elem.name, fields[elem.name])
else
res = false
end
end
elseif elem.type == "float" then
if fields[elem.name] == ""then
meta:set_string(elem.name, "")
elseif fields[elem.name] then
local val = tonumber(fields[elem.name])
if val and value_check(elem, val, player_name) then
meta:set_string(elem.name, val)
else
res = false
end
end
elseif elem.type == "ascii" then
if fields[elem.name] == ""then
meta:set_string(elem.name, "")
elseif fields[elem.name] then
if value_check(elem, fields[elem.name], player_name) then
meta:set_string(elem.name, fields[elem.name])
else
res = false
end
end
elseif elem.type == "dropdown" then
if fields[elem.name] ~= nil then
if elem.values then
local l = elem.choices:split(",")
local idx = index(l, fields[elem.name]) or 1
local text = elem.values[idx]
meta:set_string(elem.name, text)
else
meta:set_string(elem.name, fields[elem.name])
end
end
elseif elem.type == "items" and player_name then
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
local dinv = minetest.get_inventory({type = "detached", name = inv_name})
local ninv = minetest.get_inventory({type = "node", pos = pos})
if dinv and ninv then
for i = 1, ninv:get_size("cfg") do
ninv:set_stack("cfg", i, dinv:get_stack("cfg", i))
end
end
end
end
end
return res
end
function techage.menu.generate_formspec(pos, ndef, form_def, player_name)
local meta = minetest.get_meta(pos)
local number = techage.get_node_number(pos) or "-"
local mem = techage.get_mem(pos)
mem.star = ((mem.star or 0) + 1) % 2
local star = mem.star == 1 and "*" or ""
if player_name then
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
minetest.create_detached_inventory(inv_name, {
allow_put = allow_put,
allow_take = allow_take})
local dinv = minetest.get_inventory({type = "detached", name = inv_name})
local ninv = minetest.get_inventory({type = "node", pos = pos})
if dinv and ninv then
dinv:set_size('cfg', ninv:get_size("cfg"))
for i = 1, ninv:get_size("cfg") do
dinv:set_stack("cfg", i, ninv:get_stack("cfg", i))
end
end
end
if meta and number and ndef and form_def then
local title = ndef.description .. " (" .. number .. ")"
local player_inv_needed, text = generate_formspec_substring(pos, meta, form_def, player_name)
local buttons
if player_inv_needed then
buttons = "button[0.5,6.2;3,1;refresh;" .. S("Refresh") .. "]" ..
"button_exit[3.5,6.2;3,1;cancel;" .. S("Cancel") .. "]" ..
"button[6.5,6.2;3,1;save;" .. S("Save") .. "]" ..
"list[current_player;main;1,7.2;8,2;]"
else
buttons = "button[0.5,8.4;3,1;refresh;" .. S("Refresh") .. "]" ..
"button_exit[3.5,8.4;3,1;cancel;" .. S("Cancel") .. "]" ..
"button[6.5,8.4;3,1;save;" .. S("Save") .. "]"
end
if #form_def > 8 then
local size = (#form_def * 10) - 60
return "size[10,9]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"box[0,-0.1;9.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" ..
"scrollbaroptions[max=" .. size .. "]" ..
"scrollbar[9.4,0.6;0.4,7.7;vertical;wrenchmenu;]" ..
"scroll_container[0,1;12,9;wrenchmenu;vertical;]" ..
text ..
"scroll_container_end[]" ..
buttons
else
return "size[10,9]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"box[0,-0.1;9.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" ..
"container[0,1]" ..
text ..
"container_end[]" ..
buttons
end
end
return ""
end
function techage.menu.eval_input(pos, form_def, fields, player_name)
if fields.save or fields.key_enter_field then
local meta = minetest.get_meta(pos)
evaluate_data(pos, meta, form_def, fields, player_name)
end
return fields.refresh or fields.save or fields.key_enter_field
end
function techage.dropdown_index(sChoices, selected_value)
local l = sChoices:split(",")
return index(l, selected_value) or 1
end

View File

@ -1,167 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
For tupe/pipe blocks with teleport support
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local NDEF = function(pos) return minetest.registered_nodes[techage.get_node_lvm(pos).name] or {} end
local M = minetest.get_meta
local S = techage.S
local menu = techage.menu
techage.teleport = {}
local PairingList = {} -- {owner = {node_type = {channel = pos}}}
local function get_pairing_table1(meta)
local owner = meta:get_string("owner")
local node_type = meta:get_string("tele_node_type")
PairingList[owner] = PairingList[owner] or {}
PairingList[owner][node_type] = PairingList[owner][node_type] or {}
return PairingList[owner][node_type]
end
local function get_pairing_table2(oldmetadata)
local owner = oldmetadata.fields.owner
local node_type = oldmetadata.fields.tele_node_type
PairingList[owner] = PairingList[owner] or {}
PairingList[owner][node_type] = PairingList[owner][node_type] or {}
return PairingList[owner][node_type]
end
local function get_free_server_list(pos)
local tbl = {""}
for name, pos in pairs(get_pairing_table1(M(pos))) do
table.insert(tbl, name)
end
return table.concat(tbl, ",")
end
local TELE_MENU = {
{
type = "label",
label = S("Enter a block name or select an existing one"),
tooltip = "",
name = "l1",
},
{
type = "ascii",
name = "conn_name",
label = S("Block name"),
tooltip = S("Connection name for this block"),
default = "",
},
{
type = "dropdown",
choices = "",
on_dropdown = get_free_server_list,
name = "remote_name",
label = S("Remote name"),
tooltip = S("Connection name of the remote block"),
},
{
type = "output",
label = S("Status"),
tooltip = S("Connection status"),
name = "status",
default = "",
},
}
function techage.teleport.formspec(pos)
local ndef = NDEF(pos)
return menu.generate_formspec(pos, ndef, TELE_MENU)
end
local function store_connection(pos, peer_pos)
local meta = M(pos)
local status = S("connected to") .. " " .. P2S(peer_pos)
meta:set_string("tele_status", status)
meta:set_string("tele_peer_pos", P2S(peer_pos))
meta:set_string("formspec", "")
end
function techage.teleport.prepare_pairing(pos, node_type, status)
local meta = M(pos)
if node_type then
meta:set_string("tele_node_type", node_type)
end
status = status or S("not connected")
meta:set_string("tele_status", status)
meta:set_string("tele_peer_pos", "")
meta:set_string("formspec", techage.teleport.formspec(pos))
end
function techage.teleport.stop_pairing(pos, oldmetadata)
-- disconnect peer node
if oldmetadata and oldmetadata.fields then
if oldmetadata.fields.tele_peer_pos then
local peer_pos = S2P(oldmetadata.fields.tele_peer_pos)
local meta = M(peer_pos)
if meta:get_string("conn_name") ~= "" then -- Server
local tbl = get_pairing_table1(meta)
tbl[meta:get_string("conn_name")] = peer_pos
techage.teleport.prepare_pairing(peer_pos, nil, S("server not connected"))
else
techage.teleport.prepare_pairing(peer_pos)
end
elseif oldmetadata.fields.conn_name then
local tbl = get_pairing_table2(oldmetadata)
tbl[oldmetadata.fields.conn_name] = nil
end
end
end
function techage.teleport.is_connected(pos)
return M(pos):get_string("tele_peer_pos") ~= ""
end
function techage.teleport.get_remote_pos(pos)
local s = M(pos):get_string("tele_peer_pos")
if s ~= "" then
return S2P(s)
end
end
function techage.teleport.after_formspec(pos, player, fields, max_dist, ex_points)
if techage.get_expoints(player) >= ex_points then
if techage.menu.eval_input(pos, TELE_MENU, fields) then
if not techage.teleport.is_connected(pos) then
local meta = M(pos)
if fields.remote_name ~= "" then -- Client
local tbl = get_pairing_table1(meta)
local peer_pos = tbl[fields.remote_name]
if peer_pos then
if vector.distance(pos, peer_pos) <= max_dist then
tbl[fields.remote_name] = nil
store_connection(pos, peer_pos)
store_connection(peer_pos, pos)
M(pos):set_string("status", S("Connected"))
else
M(pos):set_string("status", S("Distance > @1 blocks", max_dist))
meta:set_string("formspec", techage.teleport.formspec(pos))
end
end
elseif fields.conn_name ~= "" then -- Server
local tbl = get_pairing_table1(meta)
tbl[fields.conn_name] = pos
techage.teleport.prepare_pairing(pos, nil, S("server not connected"))
end
end
end
else
M(pos):set_string("status", S("Ex-points missing (@1 < @2)", techage.get_expoints(player), ex_points))
M(pos):set_string("formspec", techage.teleport.formspec(pos))
end
end

View File

@ -1,57 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Tube wall entry
]]--
local S = techage.S
local Tube = techage.Tube
minetest.register_node("techage:tube_wall_entry", {
description = S("Tube Wall Entry"),
tiles = {
-- up, down, right, left, back, front
"basic_materials_concrete_block.png",
"basic_materials_concrete_block.png",
"basic_materials_concrete_block.png",
"basic_materials_concrete_block.png",
"basic_materials_concrete_block.png^techage_tube_hole.png",
"basic_materials_concrete_block.png^techage_tube_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Tube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
groups = {crumbly = 2, cracky = 2, snappy = 2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
minetest.register_craft({
output = "techage:tube_wall_entry",
recipe = {
{"", "techage:tubeS", ""},
{"", "basic_materials:concrete_block", ""},
{"", "",""},
},
})

View File

@ -1,148 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Tubes based on tubelib2
]]--
local S = techage.S
-- used for registered nodes
techage.KnownNodes = {
["techage:tubeS"] = true,
["techage:tubeA"] = true,
["techage:ta4_tubeS"] = true,
["techage:ta4_tubeA"] = true,
}
local Tube = tubelib2.Tube:new({
-- North, East, South, West, Down, Up
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 200,
show_infotext = false,
primary_node_names = {
"techage:tubeS", "techage:tubeA",
"techage:ta4_tubeS", "techage:ta4_tubeA",
"techage:tube_wall_entry",
},
after_place_tube = function(pos, param2, tube_type, num_tubes, tbl)
local name = minetest.get_node(pos).name
if name == "techage:tubeS" or name == "techage:tubeA" then
minetest.swap_node(pos, {name = "techage:tube"..tube_type, param2 = param2})
elseif name == "techage:tube_wall_entry" then
minetest.swap_node(pos, {name = "techage:tube_wall_entry", param2 = param2})
else
minetest.swap_node(pos, {name = "techage:ta4_tube"..tube_type, param2 = param2})
end
end,
})
techage.Tube = Tube
minetest.register_node("techage:tubeS", {
description = S("TechAge Tube"),
tiles = { -- Top, base, right, left, front, back
"techage_tube_tube.png^[transformR90",
"techage_tube_tube.png^[transformR90",
"techage_tube_tube.png",
"techage_tube_tube.png",
"techage_tube_hole.png",
"techage_tube_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Tube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/8, -2/8, -4/8, 2/8, 2/8, 4/8},
},
},
selection_box = {
type = "fixed",
fixed = { -1/4, -1/4, -1/2, 1/4, 1/4, 1/2 },
},
collision_box = {
type = "fixed",
fixed = { -1/4, -1/4, -1/2, 1/4, 1/4, 1/2 },
},
on_rotate = screwdriver.disallow,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy=2, cracky=3},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:tubeA", {
description = S("TechAge Tube"),
tiles = { -- Top, base, right, left, front, back
"techage_tube_knee2.png",
"techage_tube_hole2.png^[transformR180",
"techage_tube_knee.png^[transformR270",
"techage_tube_knee.png",
"techage_tube_knee2.png",
"techage_tube_hole2.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/8, -4/8, -2/8, 2/8, 2/8, 2/8},
{-2/8, -2/8, -4/8, 2/8, 2/8, -2/8},
},
},
selection_box = {
type = "fixed",
fixed = { -1/4, -1/2, -1/2, 1/4, 1/4, 1/4 },
},
collision_box = {
type = "fixed",
fixed = { -1/4, -1/2, -1/2, 1/4, 1/4, 1/4 },
},
on_rotate = screwdriver.disallow,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy=2, cracky=3, not_in_creative_inventory=1},
sounds = default.node_sound_wood_defaults(),
drop = "techage:tubeS",
})
minetest.register_craft({
output = "techage:tubeS 4",
recipe = {
{"default:steel_ingot", "", "group:wood"},
{"", "group:wood", ""},
{"group:wood", "", "default:tin_ingot"},
},
})

View File

@ -1,120 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Tubes in TA4 design based on tubelib2
]]--
local Tube = techage.Tube
local S = techage.S
minetest.register_node("techage:ta4_tubeS", {
description = S("TA4 Tube"),
tiles = { -- Top, base, right, left, front, back
"techage_tubeta4_tube.png^[transformR90",
"techage_tubeta4_tube.png^[transformR90",
"techage_tubeta4_tube.png",
"techage_tubeta4_tube.png",
"techage_tube_hole.png",
"techage_tube_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Tube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/8, -2/8, -4/8, 2/8, 2/8, 4/8},
},
},
selection_box = {
type = "fixed",
fixed = { -1/4, -1/4, -1/2, 1/4, 1/4, 1/2 },
},
collision_box = {
type = "fixed",
fixed = { -1/4, -1/4, -1/2, 1/4, 1/4, 1/2 },
},
on_rotate = screwdriver.disallow,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy=2, cracky=3},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:ta4_tubeA", {
description = S("TA4 Tube"),
tiles = { -- Top, base, right, left, front, back
"techage_tubeta4_knee2.png",
"techage_tubeta4_hole2.png^[transformR180",
"techage_tubeta4_knee.png^[transformR270",
"techage_tubeta4_knee.png",
"techage_tubeta4_knee2.png",
"techage_tubeta4_hole2.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/8, -4/8, -2/8, 2/8, 2/8, 2/8},
{-2/8, -2/8, -4/8, 2/8, 2/8, -2/8},
},
},
selection_box = {
type = "fixed",
fixed = { -1/4, -1/2, -1/2, 1/4, 1/4, 1/4 },
},
collision_box = {
type = "fixed",
fixed = { -1/4, -1/2, -1/2, 1/4, 1/4, 1/4 },
},
on_rotate = screwdriver.disallow,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy=2, cracky=3, not_in_creative_inventory=1},
sounds = default.node_sound_wood_defaults(),
drop = "techage:ta4_tubeS",
})
minetest.register_craft({
output = "techage:ta4_tubeS 6",
recipe = {
{"dye:blue", "", "basic_materials:plastic_sheet"},
{"", "basic_materials:plastic_sheet", ""},
{"basic_materials:plastic_sheet", "", "techage:aluminum"},
},
})
techage.TA4tubes = {
["techage:ta4_tubeS"] = true,
["techage:ta4_tubeA"] = true,
}

View File

@ -1,86 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Wind turbine helper function
]]--
local S = techage.S
local P = minetest.string_to_pos
local M = minetest.get_meta
local OCEAN = "ocean"
if minetest.global_exists("asuna") then
OCEAN = "below"
end
local function chat_message(player_name, msg)
if player_name then
minetest.chat_send_player(player_name, S("[TA4 Wind Turbine]").." "..msg)
end
return false, msg
end
-- num_turbines is the mx number of valid wind turbines. In the case of a tool
-- it should be 0, in case of the rotor: 1
function techage.valid_place_for_windturbine(pos, player_name, num_turbines)
local pos1, pos2, num
-- Check if occean (only for tool)
if num_turbines == 0 and pos.y ~= 1 then
return chat_message(player_name, S("This is not the surface of the ocean!"))
end
local node = minetest.get_node(pos)
if num_turbines == 0 and node.name ~= "default:water_source" then
return chat_message(player_name, S("This is no ocean water!"))
end
local data = minetest.get_biome_data({x=pos.x, y=-2, z=pos.z})
if data then
local name = minetest.get_biome_name(data.biome)
if not string.find(name, OCEAN) then
return chat_message(player_name, S("This is a").." "..name.." "..S("biome and no ocean!"))
end
end
-- check the space over ocean
pos1 = {x=pos.x-20, y=2, z=pos.z-20}
pos2 = {x=pos.x+20, y=22, z=pos.z+20}
num = #minetest.find_nodes_in_area(pos1, pos2, {"air", "ignore"})
if num < (41 * 41 * 21 * 0.9) then
techage.mark_region(player_name, pos1, pos2, "")
return chat_message(player_name,
S("Here is not enough wind\n(A free air space of 41x41x21 m is necessary)!"))
end
-- Check for water surface (occean)
pos1 = {x=pos.x-20, y=1, z=pos.z-20}
pos2 = {x=pos.x+20, y=1, z=pos.z+20}
num = #minetest.find_nodes_in_area(pos1, pos2,
{"default:water_source", "default:water_flowing", "ignore"})
if num < (41*41 * 0.8) then
techage.mark_region(player_name, pos1, pos2, "")
return chat_message(player_name, S("Here is not enough water (41x41 m)!"))
end
-- Check for next wind turbine
pos1 = {x=pos.x-13, y=2, z=pos.z-13}
pos2 = {x=pos.x+13, y=22, z=pos.z+13}
num = #minetest.find_nodes_in_area(pos1, pos2, {"techage:ta4_wind_turbine"})
if num > num_turbines then
techage.mark_region(player_name, pos1, pos2, "")
return chat_message(player_name, S("The next wind turbines is too close!"))
end
if num_turbines == 0 then
chat_message(player_name, minetest.pos_to_string(pos).." "..
S("is a suitable place for a wind turbine!"))
end
return true, "ok"
end

View File

@ -1,60 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
K/V Store for the Beduino controller
]]--
local COSTS = 400
local function ta_kv_init(cpu_pos, address, regA, regB, regC)
local nvm = techage.get_nvm(cpu_pos)
nvm.kv_store = {}
return 1, COSTS
end
local function ta_kv_add(cpu_pos, address, regA, regB, regC)
local nvm = techage.get_nvm(cpu_pos)
local text = vm16.read_ascii(cpu_pos, regA, 32)
nvm.kv_store[text] = regB
return 1, COSTS
end
local function ta_kv_get(cpu_pos, address, regA, regB, regC)
local nvm = techage.get_nvm(cpu_pos)
local text = vm16.read_ascii(cpu_pos, regA, 32)
return nvm.kv_store[text] or 0, COSTS
end
local kvstore_c = [[
// Initialize the key/value store
func ta_kv_init() {
return system(0x140, 0);
}
// Add a key/value pair to the store
func ta_kv_add(key_str, value) {
return system(0x141, key_str, value);
}
// Returns the value for the given key string
func ta_kv_get(key_str) {
return system(0x142, key_str);
}
]]
minetest.register_on_mods_loaded(function()
if minetest.global_exists("beduino") and minetest.global_exists("vm16") then
beduino.lib.register_SystemHandler(0x140, ta_kv_init)
beduino.lib.register_SystemHandler(0x141, ta_kv_add)
beduino.lib.register_SystemHandler(0x142, ta_kv_get)
vm16.register_ro_file("beduino", "lib/ta_kvstore.c", kvstore_c)
end
end)

View File

@ -1,181 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Chest Cart
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local MP = minetest.get_modpath("minecart")
local Tube = techage.Tube
local function on_rightclick(pos, node, clicker)
if clicker and clicker:is_player() then
if M(pos):get_int("userID") == 0 then
minecart.show_formspec(pos, clicker)
end
end
end
local function formspec()
return "size[8,6]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;main;3,0;2,2;]"..
"list[current_player;main;0,2.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
local owner = M(pos):get_string("owner")
if owner ~= "" and owner ~= player:get_player_name() then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
local owner = M(pos):get_string("owner")
if owner ~= "" and owner ~= player:get_player_name() then
return 0
end
return stack:get_count()
end
minetest.register_node("techage:chest_cart", {
description = S("TA Chest Cart"),
tiles = {
-- up, down, right, left, back, front
"techage_chest_cart_top.png",
"techage_chest_cart_bottom.png",
"techage_chest_cart_side.png",
"techage_chest_cart_side.png",
"techage_chest_cart_front.png",
"techage_chest_cart_front.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-7/16, 3/16, -7/16, 7/16, 8/16, 7/16},
{-8/16, -8/16, -8/16, 8/16, 3/16, 8/16},
},
},
paramtype2 = "facedir",
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {cracky = 2, crumbly = 2, choppy = 2},
node_placement_prediction = "",
diggable = false,
on_place = minecart.on_nodecart_place,
on_punch = minecart.on_nodecart_punch,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
on_rightclick = on_rightclick,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size('main', 4)
if placer and placer:is_player() then
minecart.show_formspec(pos, placer)
else
M(pos):set_string("formspec", formspec())
end
end,
set_cargo = function(pos, data)
local inv = M(pos):get_inventory()
for idx, stack in ipairs(data) do
inv:set_stack("main", idx, stack)
end
end,
get_cargo = function(pos)
local inv = M(pos):get_inventory()
local data = {}
for idx = 1, 4 do
local stack = inv:get_stack("main", idx)
data[idx] = {name = stack:get_name(), count = stack:get_count()}
end
return data
end,
has_cargo = function(pos)
local inv = minetest.get_meta(pos):get_inventory()
return not inv:is_empty("main")
end
})
minecart.register_cart_entity("techage:chest_cart_entity", "techage:chest_cart", "chest", {
initial_properties = {
physical = false,
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
visual = "wielditem",
textures = {"techage:chest_cart"},
visual_size = {x=0.66, y=0.66, z=0.66},
static_save = false,
},
})
techage.register_node({"techage:chest_cart"}, {
on_pull_item = function(pos, in_dir, num, item_name)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_inv_state(inv, "main")
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then -- Chest State
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return 0, {techage.get_inv_state_num(inv, "main")}
else
return 2, ""
end
end,
})
Tube:set_valid_sides("techage:chest_cart", {"L", "R", "F", "B"})
minetest.register_craft({
output = "techage:chest_cart",
recipe = {
{"default:junglewood", "default:chest_locked", "default:junglewood"},
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
},
})

View File

@ -1,176 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Tank Cart
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local Pipe = techage.LiquidPipe
local MP = minetest.get_modpath("minecart")
local liquid = networks.liquid
local CAPACITY = 200
local function on_rightclick(pos, node, clicker)
if clicker and clicker:is_player() then
if M(pos):get_int("userID") == 0 then
minecart.show_formspec(pos, clicker)
else
local nvm = techage.get_nvm(pos)
techage.set_activeformspec(pos, clicker)
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
minetest.get_node_timer(pos):start(2)
end
end
end
local function node_timer(pos, elapsed)
if techage.is_activeformspec(pos) then
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
return true
end
return false
end
local function peek_liquid(pos)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end
local function take_liquid(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
amount, name = liquid.srv_take(nvm, name, amount)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
end
return amount, name
end
local function put_liquid(pos, indir, name, amount)
-- check if it is not powder
local ndef = minetest.registered_craftitems[name] or {}
if not ndef.groups or ndef.groups.powder ~= 1 then
local nvm = techage.get_nvm(pos)
local leftover = liquid.srv_put(nvm, name, amount, CAPACITY)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
end
return leftover
end
return amount
end
local function untake_liquid(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
local leftover = liquid.srv_put(nvm, name, amount, CAPACITY)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
end
return leftover
end
minetest.register_node("techage:tank_cart", {
description = S("TA Tank Cart"),
tiles = {
-- up, down, right, left, back, front
"techage_tank_cart_top.png",
"techage_tank_cart_bottom.png",
"techage_tank_cart_side.png",
"techage_tank_cart_side.png",
"techage_tank_cart_front.png",
"techage_tank_cart_front.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/16, 7/16, -3/16, 3/16, 8/16, 3/16},
{-7/16, 3/16, -7/16, 7/16, 7/16, 7/16},
{-8/16, -8/16, -8/16, 8/16, 3/16, 8/16},
},
},
paramtype2 = "facedir",
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {cracky = 2, crumbly = 2, choppy = 2},
node_placement_prediction = "",
diggable = false,
on_place = minecart.on_nodecart_place,
on_punch = minecart.on_nodecart_punch,
after_place_node = function(pos)
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
-- Delete the network between pump and cart
Pipe:after_dig_node(pos)
Pipe:after_place_node(pos)
end,
set_cargo = function(pos, data)
local nvm = techage.get_nvm(pos)
nvm.liquid = data
end,
get_cargo = function(pos)
local nvm = techage.get_nvm(pos)
local data = nvm.liquid
nvm.liquid = {}
return data
end,
has_cargo = function(pos)
return not techage.liquid.is_empty(pos)
end,
on_timer = node_timer,
on_rightclick = on_rightclick,
})
techage.register_node({"techage:tank_cart"}, techage.liquid.recv_message)
liquid.register_nodes({"techage:tank_cart"},
Pipe, "tank", {"U"}, {
capa = CAPACITY,
peek = peek_liquid,
put = put_liquid,
take = take_liquid,
untake = untake_liquid,
}
)
minecart.register_cart_entity("techage:tank_cart_entity", "techage:tank_cart", "tank", {
initial_properties = {
physical = false,
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
visual = "wielditem",
textures = {"techage:tank_cart"},
visual_size = {x=0.66, y=0.66, z=0.66},
static_save = false,
},
only_dig_if_empty = 1,
})
minetest.register_craft({
output = "techage:tank_cart",
recipe = {
{"default:junglewood", "techage:ta3_tank", "default:junglewood"},
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
},
})

View File

@ -1,394 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Doser
]]--
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.LiquidPipe
local liquid = networks.liquid
local recipes = techage.recipes
local Liquids = {} -- {hash(pos) = {name = outdir},...}
local STANDBY_TICKS = 2
local COUNTDOWN_TICKS = 3
local CYCLE_TIME = 10
local function formspec(self, pos, nvm)
return "size[6,3.6]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;5.8,0.5;#c6e8ff]"..
"label[2.5,-0.1;"..minetest.colorize( "#000000", S("Doser")).."]"..
recipes.formspec(0.1, 0.8, "ta4_doser", nvm)..
"image_button[5,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[5,2;1,1;"..self:get_state_tooltip(nvm).."]"
end
local function get_liquids(pos)
local hash = minetest.hash_node_position(pos)
if Liquids[hash] then
return Liquids[hash]
end
-- determine the available input liquids
local tbl = {}
for outdir = 1,4 do
local name, num = liquid.peek(pos, Pipe, outdir)
if name then
tbl[name] = outdir
end
end
Liquids[hash] = tbl
return Liquids[hash]
end
local function del_liquids(pos)
local hash = minetest.hash_node_position(pos)
Liquids[hash] = nil
end
-- if liquids are missing, update the cached liquid table
local function reload_liquids(pos)
local hash = minetest.hash_node_position(pos)
-- determine the available input liquids
local tbl = {}
for outdir = 1,4 do
local name, num = liquid.peek(pos, Pipe, outdir)
if name then
tbl[name] = outdir
end
end
Liquids[hash] = tbl
return Liquids[hash]
end
local function reactor_cmnd(pos, cmnd, payload)
return techage.transfer(
pos,
6, -- outdir
cmnd, -- topic
payload, -- payload
Pipe, -- network
{"techage:ta4_reactor_fillerpipe"})
end
local function can_start(pos, nvm, state)
-- check reactor
local res = reactor_cmnd(pos, "check")
if not res then
return S("reactor defect")
end
res = reactor_cmnd(pos, "can_start")
if not res then
return S("reactor defect or no power")
end
local recipe = recipes.get(nvm, "ta4_doser")
if recipe.catalyst then
res = reactor_cmnd(pos, "catalyst")
if not res or res == "" then
return S("catalyst missing")
end
if res ~= recipe.catalyst then
return S("wrong catalyst")
end
end
return true
end
local function start_node(pos, nvm, state)
reactor_cmnd(pos, "start")
del_liquids(pos)
nvm.running = true
end
local function stop_node(pos, nvm, state)
reactor_cmnd(pos, "stop")
nvm.running = false
end
local State = techage.NodeStates:new({
node_name_passive = "techage:ta4_doser",
node_name_active = "techage:ta4_doser_on",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec_func = formspec,
infotext_name = "TA4 Doser",
can_start = can_start,
start_node = start_node,
stop_node = stop_node,
})
local function untake(pos, taken)
for _,item in pairs(taken) do
liquid.untake(pos, Pipe, item.outdir, item.name, item.num)
end
end
local function dosing(pos, nvm, elapsed)
-- trigger reactor (power)
if not reactor_cmnd(pos, "power") then
if not nvm.techage_countdown or nvm.techage_countdown < 3 then
reactor_cmnd(pos, "stop")
State:nopower(pos, nvm, S("reactor has no power"))
return
end
State:idle(pos, nvm)
return
end
-- available liquids
local liquids = get_liquids(pos)
local recipe = recipes.get(nvm, "ta4_doser")
if not liquids or not recipe then return end
-- check from time to time
nvm.check_cnt = (nvm.check_cnt or 0) + 1
if nvm.check_cnt >= 4 then
nvm.check_cnt = 0
local res = reactor_cmnd(pos, "check")
if not res then
State:fault(pos, nvm, S("reactor defect"))
reactor_cmnd(pos, "stop")
return
end
if recipe.catalyst then
res = reactor_cmnd(pos, "catalyst")
if not res then
State:fault(pos, nvm, S("catalyst missing"))
reactor_cmnd(pos, "stop")
return
end
if res ~= recipe.catalyst then
State:fault(pos, nvm, S("wrong catalyst"))
reactor_cmnd(pos, "stop")
return
end
end
end
-- check leftover
local leftover
local mem = techage.get_mem(pos)
if mem.waste_leftover then
leftover = reactor_cmnd(pos, "waste", {
name = mem.waste_leftover.name,
amount = mem.waste_leftover.num}) or mem.waste_leftover.num
if leftover > 0 then
mem.waste_leftover.num = leftover
State:blocked(pos, nvm)
return
end
mem.waste_leftover = nil
end
if mem.output_leftover then
leftover = reactor_cmnd(pos, "output", {
name = mem.output_leftover.name,
amount = mem.output_leftover.num}) or mem.output_leftover.num
if leftover > 0 then
mem.output_leftover.num = leftover
State:blocked(pos, nvm)
return
end
mem.output_leftover = nil
end
-- inputs
local taken = {}
mem.dbg_cycles = (mem.dbg_cycles or 0) - 1
for _,item in pairs(recipe.input) do
if item.name ~= "" then
local outdir = liquids[item.name] or reload_liquids(pos)[item.name]
if not outdir then
State:standby(pos, nvm)
reactor_cmnd(pos, "stop")
untake(pos, taken)
return
end
local num = liquid.take(pos, Pipe, outdir, item.name, item.num, mem.dbg_cycles > 0)
if num < item.num then
taken[#taken + 1] = {outdir = outdir, name = item.name, num = num}
State:standby(pos, nvm)
reactor_cmnd(pos, "stop")
untake(pos, taken)
return
end
taken[#taken + 1] = {outdir = outdir, name = item.name, num = item.num}
end
end
-- waste
if recipe.waste.name ~= "" then
leftover = reactor_cmnd(pos, "waste", {
name = recipe.waste.name,
amount = recipe.waste.num}) or recipe.waste.num
if leftover > 0 then
mem.waste_leftover = {name = recipe.waste.name, num = leftover}
mem.output_leftover = {name = recipe.output.name, num = recipe.output.num}
State:blocked(pos, nvm)
reactor_cmnd(pos, "stop")
return
end
end
-- output
leftover = reactor_cmnd(pos, "output", {
name = recipe.output.name,
amount = recipe.output.num}) or recipe.output.num
if leftover > 0 then
mem.output_leftover = {name = recipe.output.name, num = leftover}
State:blocked(pos, nvm)
reactor_cmnd(pos, "stop")
return
end
State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
dosing(pos, nvm, elapsed)
return State:is_active(nvm)
end
local function on_rightclick(pos)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(State, pos, nvm))
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
if not nvm.running then
if recipes.on_receive_fields(pos, formname, fields, player) then
local mem = techage.get_mem(pos)
mem.waste_leftover = nil
mem.output_leftover = nil
end
end
local mem = techage.get_mem(pos)
mem.dbg_cycles = 5
State:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(State, pos, nvm))
end
minetest.register_node("techage:ta4_doser", {
description = S("TA4 Doser"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_hole_pipe.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_pump_up.png",
},
after_place_node = function(pos, placer)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local number = techage.add_node(pos, "techage:ta4_doser")
meta:set_string("node_number", number)
meta:set_string("owner", placer:get_player_name())
meta:set_string("formspec", formspec(State, pos, nvm))
meta:set_string("infotext", S("TA4 Doser").." "..number)
State:node_init(pos, nvm, number)
Pipe:after_place_node(pos)
end,
tubelib2_on_update2 = function(pos, dir, tlib2, node)
liquid.update_network(pos, dir, tlib2, node)
del_liquids(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_timer = node_timer,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:ta4_doser_on", {
description = S("TA4 Doser"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_hole_pipe.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
{
name = "techage_filling8_ta4.png^techage_frame8_ta4.png^techage_appl_pump_up8.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
},
tubelib2_on_update2 = function(pos, dir, tlib2, node)
liquid.update_network(pos, dir, tlib2, node)
del_liquids(pos)
end,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_timer = node_timer,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
diggable = false,
groups = {not_in_creative_inventory=1},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
liquid.register_nodes({"techage:ta4_doser", "techage:ta4_doser_on"}, Pipe, "pump", nil, {})
techage.register_node({"techage:ta4_doser", "techage:ta4_doser_on"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "recipe" then
techage.recipes.set_recipe(pos, "ta4_doser", payload)
return true
else
return State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return State:on_beduino_request_data(pos, topic, payload)
end,
})
techage.recipes.register_craft_type("ta4_doser", {
description = S("TA4 Reactor"),
icon = 'techage_reactor_filler_plan.png',
width = 2,
height = 2,
})
minetest.register_craft({
output = "techage:ta4_doser",
recipe = {
{"", "techage:ta3_pipeS", ""},
{"techage:ta3_pipeS", "techage:t4_pump", "techage:ta3_pipeS"},
{"", "techage:ta4_wlanchip", ""},
},
})

View File

@ -1,209 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2020 Thomas S.
AGPL v3
See LICENSE.txt for more information
TA4 Liquid Filter
]]--
-- For now, the Red Mud -> Lye/Desert Cobble recipe is hardcoded.
-- If necessary, this can be adjusted later.
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.LiquidPipe
local liquid = networks.liquid
-- Checks if the filter structure is ok and returns the amount of gravel
local function checkStructure(pos)
local pos1_outer = {x=pos.x-2,y=pos.y-7,z=pos.z-2}
local pos2_outer = {x=pos.x+2,y=pos.y,z=pos.z+2}
local pos1_inner = {x=pos.x-1,y=pos.y-1,z=pos.z-1}
local pos2_inner = {x=pos.x+1,y=pos.y-7,z=pos.z+1}
local pos1_top = {x=pos.x-1,y=pos.y,z=pos.z-1}
local pos2_top = {x=pos.x+1,y=pos.y,z=pos.z+1}
local pos1_bottom = {x=pos.x-2,y=pos.y-8,z=pos.z-2}
local pos2_bottom = {x=pos.x+2,y=pos.y-8,z=pos.z+2}
local gravel = minetest.find_nodes_in_area(pos1_inner, pos2_inner, {"default:gravel"})
local _, inner = minetest.find_nodes_in_area(pos1_inner, pos2_inner, {
"default:desert_cobble"
})
if #gravel + (inner["default:desert_cobble"] or 0) ~= 63 then -- 7x3x3=63
return false, gravel
end
local _, outer = minetest.find_nodes_in_area(pos1_outer, pos2_outer, {
"basic_materials:concrete_block",
"default:obsidian_glass"
})
-- + 4x7=28 (corners)
-- + 5x5-3x3=16 (top ring)
-- ------------------------------
-- = 44 (total concrete)
if outer["basic_materials:concrete_block"] ~= 44 then
return false, gravel
end
if outer["default:obsidian_glass"] ~= 84 then -- 4x7x3=84
return false, gravel
end
local _,top = minetest.find_nodes_in_area(pos1_top, pos2_top, {"air"})
if top["air"] ~= 8 then
return false, gravel
end
local _,bottom = minetest.find_nodes_in_area(pos1_bottom, pos2_bottom, {
"basic_materials:concrete_block",
"techage:ta3_pipe_wall_entry"
})
if bottom["basic_materials:concrete_block"] ~= 22 or bottom["techage:ta3_pipe_wall_entry"] ~= 2 then
return false, gravel
end
if minetest.get_node({x=pos.x,y=pos.y-8,z=pos.z}).name ~= "techage:ta4_liquid_filter_sink" then
return false, gravel
end
return true, gravel
end
minetest.register_node("techage:ta4_liquid_filter_filler", {
description = S("TA4 Liquid Filter Filler"),
tiles = {
-- up, down, right, left, back, front
"basic_materials_concrete_block.png^techage_gaspipe_hole.png",
"basic_materials_concrete_block.png^techage_liquid_filter_filler_bottom.png",
"basic_materials_concrete_block.png^techage_liquid_filter_filler.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-6/8, -0.5, -6/8, 6/8, -0.25, 6/8},
{-7/16, -0.25, -7/16, 7/16, 0, 7/16},
{-1/8, 0, -1/8, 1/8, 13/32, 1/8},
{-2/8, 13/32, -2/8, 2/8, 0.5, 2/8},
},
},
after_place_node = function(pos)
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = techage.CLIP,
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
liquid.register_nodes({"techage:ta4_liquid_filter_filler"},
Pipe, "tank", {"U"}, {
capa = 1,
peek = function(...) return nil end,
put = function(pos, indir, name, amount)
local structure_ok, gravel = checkStructure(pos)
if name ~= "techage:redmud" then
return amount
end
if not structure_ok then
return amount
end
if #gravel < 33 then
return amount
end
if math.random() < 0.5 then
local out_pos = {x=pos.x,y=pos.y-8,z=pos.z}
local leftover = liquid.put(out_pos, Pipe, networks.side_to_outdir(out_pos, "R"), "techage:lye", 1)
if leftover > 0 then
return amount
end
else
minetest.swap_node(gravel[math.random(#gravel)], {name = "default:desert_cobble"})
end
return amount - 1
end,
take = function(...) return 0 end,
untake = function(pos, outdir, name, amount, player_name)
return amount
end,
}
)
minetest.register_node("techage:ta4_liquid_filter_sink", {
description = S("TA4 Liquid Filter Sink"),
tiles = {
-- up, down, right, left, back, front
"basic_materials_concrete_block.png^techage_appl_arrow.png",
"basic_materials_concrete_block.png",
"basic_materials_concrete_block.png^techage_appl_hole_pipe.png",
"basic_materials_concrete_block.png",
"basic_materials_concrete_block.png",
"basic_materials_concrete_block.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 3/16, 0.5},
{-0.5, 3/16, -0.5, 0.5, 5/16, -0.25},
{0.25, 3/16, -0.5, 0.5, 5/16, 0.5},
{-0.5, 3/16, 0.25, 0.5, 5/16, 0.5},
{-0.5, 3/16, -0.5, -0.25, 5/16, 0.5}
},
},
after_place_node = function(pos)
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
end,
paramtype = "light",
use_texture_alpha = techage.CLIP,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
liquid.register_nodes({"techage:ta4_liquid_filter_sink"},
Pipe, "pump", {"R"}, {}
)
minetest.register_craft({
output = 'techage:ta4_liquid_filter_filler',
recipe = {
{'', 'techage:ta3_pipeS', ''},
{'basic_materials:concrete_block', 'basic_materials:concrete_block', 'basic_materials:concrete_block'},
{'', 'default:steel_ingot', ''},
}
})
minetest.register_craft({
output = 'techage:ta4_liquid_filter_sink 2',
recipe = {
{'basic_materials:concrete_block', '', 'basic_materials:concrete_block'},
{'basic_materials:concrete_block', 'techage:ta3_pipeS', 'techage:ta3_pipeS'},
{'basic_materials:concrete_block', 'basic_materials:concrete_block', 'basic_materials:concrete_block'},
}
})

View File

@ -1,226 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Reactor
]]--
local S = techage.S
local M = minetest.get_meta
local Pipe = techage.LiquidPipe
local Cable = techage.ElectricCable
local liquid = networks.liquid
minetest.register_node("techage:ta4_reactor_fillerpipe", {
description = S("TA4 Reactor Filler Pipe"),
tiles = {
-- up, down, right, left, back, front
"techage_reactor_filler_top.png",
"techage_reactor_filler_top.png",
"techage_reactor_filler_side.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/8, 13/32, -2/8, 2/8, 4/8, 2/8},
{-1/8, 0/8, -1/8, 1/8, 4/8, 1/8},
{-5/16, 0/8, -5/16, 5/16, 2/8, 5/16},
},
},
selection_box = {
type = "fixed",
fixed = {-2/8, 0/8, -2/8, 2/8, 4/8, 2/8},
},
after_place_node = function(pos)
local pos1 = {x = pos.x, y = pos.y-1, z = pos.z}
if minetest.get_node(pos1).name == "air" then
local node = minetest.get_node(pos)
minetest.remove_node(pos)
minetest.set_node(pos1, node)
Pipe:after_place_node(pos1)
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
end,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
local function stand_cmnd(pos, cmnd, payload)
return techage.transfer(
{x = pos.x, y = pos.y-1, z = pos.z},
5, -- outdir
cmnd, -- topic
payload, -- payload
nil, -- network
{"techage:ta4_reactor_stand"})
end
local function base_waste(pos, payload)
local pos2 = {x = pos.x, y = pos.y-3, z = pos.z}
local outdir = M(pos2):get_int("outdir")
return liquid.put(pos2, Pipe, outdir, payload.name, payload.amount, payload.player_name)
end
-- controlled by the doser
techage.register_node({"techage:ta4_reactor_fillerpipe"}, {
on_transfer = function(pos, in_dir, topic, payload)
if topic == "check" then
local pos2,node = Pipe:get_node(pos, 5)
if not node or node.name ~= "techage:ta4_reactor" then
return false
end
pos2,node = Pipe:get_node(pos2, 5)
if not node or node.name ~= "techage:ta4_reactor_stand" then
return false
end
return true
elseif topic == "waste" then
return base_waste(pos, payload or {})
elseif topic == "catalyst" then
local pos2,node = Pipe:get_node(pos, 5)
if not node or node.name ~= "techage:ta4_reactor" then
return
end
local inv = M(pos2):get_inventory()
local stack = inv:get_stack("main", 1)
return stack and stack:get_name()
else
return stand_cmnd(pos, topic, payload or {})
end
end,
})
liquid.register_nodes({"techage:ta4_reactor_fillerpipe"}, Pipe, "tank", {"U"}, {})
local function formspec()
local title = S("TA4 Reactor")
return "size[8,6]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3,-0.1;"..minetest.colorize("#000000", title).."]"..
"label[4.5,1.2;"..S("Catalyst").."]"..
"list[context;main;3.5,1;1,1;]"..
"list[current_player;main;0,2.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return 1
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
minetest.register_node("techage:ta4_reactor", {
description = S("TA4 Reactor"),
tiles = {"techage_reactor_side.png"},
drawtype = "mesh",
mesh = "techage_cylinder_12h.obj",
selection_box = {
type = "fixed",
fixed = {-1/2, -23/32, -1/2, 1/2, 32/32, 1/2},
},
collision_box = {
type = "fixed",
fixed = {-1/2, -23/32, -1/2, 1/2, 32/32, 1/2},
},
after_place_node = function(pos)
local inv = M(pos):get_inventory()
inv:set_size('main', 1)
M(pos):set_string("formspec", formspec())
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
paramtype = "light",
use_texture_alpha = techage.CLIP,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
techage.register_node({"techage:ta4_reactor"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num, item_name)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
minetest.register_craft({
output = 'techage:ta4_reactor',
recipe = {
{'default:steel_ingot', 'techage:ta3_pipeS', 'default:steel_ingot'},
{'techage:iron_ingot', '', 'techage:iron_ingot'},
{'default:steel_ingot', 'techage:ta3_pipeS', 'default:steel_ingot'},
}
})
minetest.register_craft({
output = 'techage:ta4_reactor_fillerpipe',
recipe = {
{'', '', ''},
{'', 'techage:ta3_pipeS', ''},
{'default:steel_ingot', 'basic_materials:motor', 'default:steel_ingot'},
}
})
minetest.register_lbm({
label = "Upgrade reactor",
name = "techage:update_reactor",
nodenames = {
"techage:ta4_reactor",
},
run_at_every_load = true,
action = function(pos, node)
local inv = M(pos):get_inventory()
inv:set_size('main', 1)
M(pos):set_string("formspec", formspec())
end,
})

View File

@ -1,209 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Reactor Stand and Base
]]--
local S = techage.S
local M = minetest.get_meta
local Cable = techage.ElectricCable
local Pipe = techage.LiquidPipe
local power = networks.power
local liquid = networks.liquid
local PWR_NEEDED = 8
local CYCLE_TIME = 2
local function play_sound(pos)
local mem = techage.get_mem(pos)
if not mem.handle or mem.handle == -1 then
mem.handle = minetest.sound_play("techage_reactor", {
pos = pos,
gain = 0.5,
max_hear_distance = 10,
loop = true})
if mem.handle == -1 then
minetest.after(1, play_sound, pos)
end
end
end
local function stop_sound(pos)
local mem = techage.get_mem(pos)
if mem.handle then
minetest.sound_stop(mem.handle)
mem.handle = nil
end
end
local function on_power(pos)
M(pos):set_string("infotext", S("on"))
play_sound(pos)
local nvm = techage.get_nvm(pos)
nvm.running = true
end
local function on_nopower(pos)
M(pos):set_string("infotext", S("no power"))
stop_sound(pos)
local nvm = techage.get_nvm(pos)
nvm.running = false
end
local function is_running(pos, nvm)
return nvm.running
end
minetest.register_node("techage:ta4_reactor_stand", {
description = S("TA4 Reactor Stand"),
tiles = {
-- up, down, right, left, back, front
"techage_reactor_stand_top.png^[transformR90",
"techage_reactor_stand_bottom.png^[transformFY^[transformR270",
"techage_reactor_stand_front.png",
"techage_reactor_stand_back.png",
"techage_reactor_stand_side.png^[transformFX",
"techage_reactor_stand_side.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, 2/16, -8/16, 8/16, 4/16, 8/16 },
{ -8/16, -8/16, -8/16, -6/16, 8/16, -6/16 },
{ 6/16, -8/16, -8/16, 8/16, 8/16, -6/16 },
{ -8/16, -8/16, 6/16, -6/16, 8/16, 8/16 },
{ 6/16, -8/16, 6/16, 8/16, 8/16, 8/16 },
{-1/8, -4/8, -1/8, 1/8, 4/8, 1/8},
{-4/8, -1/8, -1/8, 4/8, 1/8, 1/8},
{-4/8, -1/8, -3/8, -3/8, 1/8, 3/8},
{ 3/8, -1/8, -3/8, 4/8, 1/8, 3/8},
},
},
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, 1/2, 1/2},
},
after_place_node = function(pos, placer)
local nvm = techage.get_nvm(pos)
M(pos):set_string("infotext", S("off"))
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
Pipe:after_place_node(pos)
Cable:after_place_node(pos)
end,
on_timer = function(pos, elapsed)
local nvm = techage.get_nvm(pos)
local consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
if not nvm.running and consumed == PWR_NEEDED then
on_power(pos)
elseif nvm.running and consumed < PWR_NEEDED then
on_nopower(pos)
end
return true
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
Cable:after_dig_node(pos)
techage.del_mem(pos)
end,
paramtype = "light",
use_texture_alpha = techage.CLIP,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
-- controlled by the fillerpipe
techage.register_node({"techage:ta4_reactor_stand"}, {
on_transfer = function(pos, in_dir, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "power" then
return nvm.running or power.power_available(pos, Cable)
elseif topic == "output" then
local outdir = M(pos):get_int("outdir")
return liquid.put(pos, Pipe, outdir, payload.name, payload.amount, payload.player_name)
elseif topic == "can_start" then
return power.power_available(pos, Cable)
elseif topic == "start" then
nvm.running = false
minetest.get_node_timer(pos):start(CYCLE_TIME)
M(pos):set_string("infotext", "...")
return true
elseif topic == "stop" then
nvm.has_power = false
stop_sound(pos)
minetest.get_node_timer(pos):stop()
M(pos):set_string("infotext", S("off"))
return true
end
end,
on_node_load = function(pos, node)
local nvm = techage.get_nvm(pos)
if nvm.has_power then
play_sound(pos)
end
end,
})
minetest.register_node("techage:ta4_reactor_base", {
description = S("TA4 Reactor Base"),
tiles = {
-- up, down, right, left, back, front
"techage_concrete.png^techage_appl_arrowXL.png^techage_appl_hole_pipe.png^[transformR270",
"techage_concrete.png",
"techage_concrete.png^techage_appl_hole_pipe.png",
"techage_concrete.png",
"techage_concrete.png",
"techage_concrete.png",
},
after_place_node = function(pos, placer)
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
end,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
liquid.register_nodes({"techage:ta4_reactor_base"}, Pipe, "pump", {"R"}, {})
liquid.register_nodes({"techage:ta4_reactor_stand"}, Pipe, "pump", {"R"}, {})
power.register_nodes({"techage:ta4_reactor_stand"}, Cable, "con", {"L"})
minetest.register_craft({
output = 'techage:ta4_reactor_stand',
recipe = {
{'', 'dye:blue', ''},
{'basic_materials:steel_bar', 'techage:ta3_pipeS', 'basic_materials:steel_bar'},
{'basic_materials:steel_bar', '', 'basic_materials:steel_bar'},
}
})
minetest.register_craft({
output = 'techage:ta4_reactor_base',
recipe = {
{'basic_materials:concrete_block', '', ''},
{'techage:ta3_pipeS', '', ''},
{'', '', ''},
}
})

View File

@ -1,67 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Boiler Base
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.SteamPipe
local networks = techage.networks
local function after_place_node(pos)
Pipe:after_place_node(pos)
end
local function after_dig_node(pos, oldnode)
Pipe:after_dig_node(pos)
end
minetest.register_node("techage:coalboiler_base", {
description = S("TA3 Boiler Base"),
tiles = {"techage_coal_boiler_mesh_base.png"},
drawtype = "mesh",
mesh = "techage_cylinder_12.obj",
selection_box = {
type = "fixed",
fixed = {-13/32, -16/32, -13/32, 13/32, 16/32, 13/32},
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype = "light",
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
Pipe:add_secondary_node_names({"techage:coalboiler_base"})
-- for logical communication
techage.register_node({"techage:coalboiler_base"}, {
on_transfer = function(pos, in_dir, topic, payload)
return true
end
})
minetest.register_craft({
output = "techage:coalboiler_base",
recipe = {
{"default:stone", "", "default:stone"},
{"techage:iron_ingot", "", "techage:iron_ingot"},
{"default:stone", "default:stone", "default:stone"},
},
})

View File

@ -1,110 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Boiler Top
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local CYCLE_TIME = 4
local WATER_CONSUMPTION = 0.1
local Pipe = techage.SteamPipe
local boiler = techage.boiler
local function steaming(pos, nvm, temp)
if temp >= 80 then
local wc = WATER_CONSUMPTION * (nvm.power_ratio or 1)
nvm.water_level = math.max((nvm.water_level or 0) - wc, 0)
end
end
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local temp = boiler.water_temperature(pos, nvm)
steaming(pos, nvm, temp)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", boiler.formspec(pos, nvm))
end
return temp > 20
end
local function after_place_node(pos)
local node = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z})
if node.name == "techage:coalboiler_base" then
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", boiler.formspec(pos, nvm))
Pipe:after_place_node(pos)
end
end
local function after_dig_node(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end
minetest.register_node("techage:coalboiler_top", {
description = S("TA3 Boiler Top"),
tiles = {"techage_coal_boiler_mesh_top.png"},
drawtype = "mesh",
mesh = "techage_cylinder_12.obj",
selection_box = {
type = "fixed",
fixed = {-13/32, -48/32, -13/32, 13/32, 16/32, 13/32},
},
can_dig = boiler.can_dig,
on_timer = node_timer,
on_rightclick = boiler.on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
on_punch = boiler.on_punch,
paramtype = "light",
paramtype2 = "facedir",
groups = {cracky=1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
Pipe:add_secondary_node_names({"techage:coalboiler_top"})
techage.register_node({"techage:coalboiler_top"}, {
on_transfer = function(pos, in_dir, topic, payload)
if topic == "trigger" then
local nvm = techage.get_nvm(pos)
nvm.fire_trigger = true
if not minetest.get_node_timer(pos):is_started() then
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
if (nvm.temperature or 20) > 80 then
nvm.power_ratio = techage.transfer(pos, "F", "trigger", nil, Pipe, {
"techage:turbine", "techage:turbine_on"}) or 0
return nvm.power_ratio
else
return 0
end
end
end,
})
minetest.register_craft({
output = "techage:coalboiler_top",
recipe = {
{"default:stone", "default:stone", "default:stone"},
{"techage:iron_ingot", "", "techage:iron_ingot"},
{"default:stone", "", "default:stone"},
},
})

View File

@ -1,133 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Cooler
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.SteamPipe
local function transfer(pos, in_dir, topic, payload)
return techage.transfer(pos, in_dir, topic, payload, Pipe,
{"techage:coalboiler_base"})
end
local function after_place_node(pos)
Pipe:after_place_node(pos)
end
local function after_dig_node(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end
minetest.register_node("techage:cooler", {
description = S("TA3 Cooler"),
tiles = {
-- up, down, right, left, back, front
{
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
{
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
-- legacy node
minetest.register_node("techage:cooler_on", {
description = S("TA3 Cooler"),
tiles = {
-- up, down, right, left, back, front
{
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
{
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype2 = "facedir",
drop = "techage:cooler",
groups = {cracky=2, crumbly=2, choppy=2, not_in_creative_inventory=1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
Pipe:add_secondary_node_names({"techage:cooler", "techage:cooler_on"})
-- for logical communication
techage.register_node({"techage:cooler", "techage:cooler_on"}, {
on_transfer = function(pos, in_dir, topic, payload)
return transfer(pos, in_dir, topic, payload)
end
})
minetest.register_craft({
output = "techage:cooler",
recipe = {
{"basic_materials:steel_bar", "default:wood", "basic_materials:steel_bar"},
{"techage:steam_pipeS", "basic_materials:gear_steel", "techage:steam_pipeS"},
{"basic_materials:steel_bar", "default:wood", "basic_materials:steel_bar"},
},
})

View File

@ -1,231 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Firebox
]]--
-- for lazy programmers
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
local firebox = techage.firebox
local CYCLE_TIME = 2
local BURN_CYCLE_FACTOR = 0.5
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local power = techage.transfer(
{x=pos.x, y=pos.y+2, z=pos.z},
nil, -- outdir
"trigger", -- topic
nil, -- payload
nil, -- network
{"techage:coalboiler_top"} -- nodenames
)
nvm.burn_cycles = (nvm.burn_cycles or 0) - math.max((power or 0.02), 0.02)
if nvm.burn_cycles <= 0 then
local taken = firebox.get_fuel(pos)
if taken then
nvm.burn_cycles = (firebox.Burntime[taken:get_name()] or 1) / CYCLE_TIME * BURN_CYCLE_FACTOR
nvm.burn_cycles_total = nvm.burn_cycles
else
nvm.running = false
firebox.set_firehole(pos, false)
M(pos):set_string("formspec", firebox.formspec(nvm))
return false
end
end
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", firebox.formspec(nvm))
end
return true
end
local function start_firebox(pos, nvm)
if not nvm.running then
nvm.running = true
node_timer(pos, 0)
firebox.set_firehole(pos, true)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
end
minetest.register_node("techage:coalfirebox", {
description = S("TA3 Power Station Firebox"),
inventory_image = "techage_coal_boiler_inv.png",
tiles = {"techage_coal_boiler_mesh_top.png"},
drawtype = "mesh",
mesh = "techage_cylinder_12.obj",
selection_box = {
type = "fixed",
fixed = {-13/32, -16/32, -13/32, 13/32, 16/32, 13/32},
},
paramtype = "light",
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
on_timer = node_timer,
can_dig = firebox.can_dig,
allow_metadata_inventory_put = firebox.allow_metadata_inventory_put,
allow_metadata_inventory_take = firebox.allow_metadata_inventory_take,
on_rightclick = firebox.on_rightclick,
after_place_node = function(pos, placer)
if firebox.is_free_position(pos, placer:get_player_name()) then
techage.add_node(pos, "techage:coalfirebox", true)
local nvm = techage.get_nvm(pos)
nvm.running = false
nvm.burn_cycles = 0
local meta = M(pos)
meta:set_string("formspec", firebox.formspec(nvm))
local inv = meta:get_inventory()
inv:set_size('fuel', 1)
firebox.set_firehole(pos, false)
else
minetest.remove_node(pos)
return true
end
end,
on_destruct = function(pos)
firebox.set_firehole(pos, nil)
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
local nvm = techage.get_nvm(pos)
start_firebox(pos, nvm)
M(pos):set_string("formspec", firebox.formspec(nvm))
end,
})
minetest.register_node("techage:coalfirehole", {
description = S("TA3 Coal Power Station Firebox"),
tiles = {
-- up, down, right, left, back, front
"techage_coal_boiler.png",
"techage_coal_boiler.png",
"techage_coal_boiler.png",
"techage_coal_boiler.png",
"techage_coal_boiler.png",
"techage_coal_boiler.png^techage_appl_firehole.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-6/16, -6/16, 6/16, 6/16, 6/16, 12/16},
},
},
paramtype = "light",
paramtype2 = "facedir",
pointable = false,
diggable = false,
is_ground_content = false,
groups = {not_in_creative_inventory=1},
})
minetest.register_node("techage:coalfirehole_on", {
description = S("TA3 Coal Power Station Firebox"),
tiles = {
-- up, down, right, left, back, front
"techage_coal_boiler.png^[colorize:black:80",
"techage_coal_boiler.png^[colorize:black:80",
"techage_coal_boiler.png^[colorize:black:80",
"techage_coal_boiler.png^[colorize:black:80",
"techage_coal_boiler.png^[colorize:black:80",
{
name = "techage_coal_boiler4.png^[colorize:black:80^techage_appl_firehole4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-6/16, -6/16, 6/16, 6/16, 6/16, 12/16},
},
},
paramtype = "light",
paramtype2 = "facedir",
light_source = 8,
pointable = false,
diggable = false,
is_ground_content = false,
groups = {not_in_creative_inventory=1},
})
techage.register_node({"techage:coalfirebox"}, {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "fuel", num)
end,
on_push_item = function(pos, in_dir, stack)
if firebox.Burntime[stack:get_name()] then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local nvm = techage.get_nvm(pos)
start_firebox(pos, nvm)
return techage.put_items(inv, "fuel", stack)
end
return false
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "fuel", stack)
end,
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "state" then
return nvm.running and "running" or "stopped"
elseif topic == "fuel" then
return techage.fuel.get_fuel_amount(nvm)
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 129 then
return 0, {nvm.running and techage.RUNNING or techage.STOPPED}
elseif topic == 132 then
return 0, {techage.fuel.get_fuel_amount(nvm)}
else
return 2, ""
end
end,
})
minetest.register_craft({
output = "techage:coalfirebox",
recipe = {
{'default:stone', 'default:stone', 'default:stone'},
{'default:steel_ingot', '', 'default:steel_ingot'},
{'default:stone', 'default:stone', 'default:stone'},
},
})

View File

@ -1,276 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Power Station Generator
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local Cable = techage.ElectricCable
local power = networks.power
local control = networks.control
local CYCLE_TIME = 2
local STANDBY_TICKS = 4
local COUNTDOWN_TICKS = 4
local PWR_PERF = 80
local function formspec(self, pos, nvm)
return techage.generator_formspec(self, pos, nvm, S("Generator"), nvm.provided, PWR_PERF)
end
local function transfer_turbine(pos, topic, payload)
return techage.transfer(pos, "L", topic, payload, nil,
{"techage:turbine", "techage:turbine_on"})
end
local function can_start(pos, nvm, state)
return (nvm.firebox_trigger or 0) > 0 -- by means of firebox
end
local function has_fire(nvm)
nvm.firebox_trigger = (nvm.firebox_trigger or 0) - 1
return nvm.firebox_trigger > 0
end
local function start_node(pos, nvm, state)
local meta = M(pos)
nvm.provided = 0
local outdir = meta:get_int("outdir")
transfer_turbine(pos, "start")
power.start_storage_calc(pos, Cable, outdir)
techage.evaluate_charge_termination(nvm, meta)
end
local function stop_node(pos, nvm, state)
nvm.provided = 0
local outdir = M(pos):get_int("outdir")
transfer_turbine(pos, "stop")
power.start_storage_calc(pos, Cable, outdir)
end
local State = techage.NodeStates:new({
node_name_passive = "techage:generator",
node_name_active = "techage:generator_on",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec_func = formspec,
infotext_name = S("TA3 Generator"),
can_start = can_start,
start_node = start_node,
stop_node = stop_node,
})
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local running = techage.is_running(nvm)
local fire = has_fire(nvm)
if running and not fire then
State:standby(pos, nvm)
stop_node(pos, nvm, State)
elseif not running and fire then
State:start(pos, nvm)
-- start_node() is called implicit
elseif running then
local meta = M(pos)
local outdir = meta:get_int("outdir")
local tp1 = tonumber(meta:get_string("termpoint1"))
local tp2 = tonumber(meta:get_string("termpoint2"))
nvm.provided = power.provide_power(pos, Cable, outdir, PWR_PERF, tp1, tp2)
local val = power.get_storage_load(pos, Cable, outdir, PWR_PERF)
if val > 0 then
nvm.load = val
end
State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(State, pos, nvm))
end
return State:is_active(nvm)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
State:state_button_event(pos, nvm, fields)
end
local function on_rightclick(pos, node, clicker)
local nvm = techage.get_nvm(pos)
techage.set_activeformspec(pos, clicker)
M(pos):set_string("formspec", formspec(State, pos, nvm))
end
local function after_place_node(pos)
local nvm = techage.get_nvm(pos)
local number = techage.add_node(pos, "techage:generator")
State:node_init(pos, nvm, number)
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
M(pos):set_string("formspec", formspec(State, pos, nvm))
Cable:after_place_node(pos)
end
local function after_dig_node(pos, oldnode)
Cable:after_dig_node(pos)
techage.del_mem(pos)
end
local function get_generator_data(pos, outdir, tlib2)
local nvm = techage.get_nvm(pos)
if techage.is_running(nvm) then
return {level = (nvm.load or 0) / PWR_PERF, perf = PWR_PERF, capa = PWR_PERF * 2}
end
end
minetest.register_node("techage:generator", {
description = S("TA3 Generator"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_hole_electric.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_open.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_generator.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_generator.png^[transformFX]",
},
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_timer = node_timer,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
get_generator_data = get_generator_data,
ta3_formspec = techage.generator_settings("ta3", PWR_PERF),
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:generator_on", {
description = S("TA3 Generator"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_hole_electric.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_open.png^techage_frame_ta3.png",
{
name = "techage_filling4_ta3.png^techage_appl_generator4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.3,
},
},
{
name = "techage_filling4_ta3.png^techage_appl_generator4.png^[transformFX]^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.3,
},
},
},
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_timer = node_timer,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
get_generator_data = get_generator_data,
ta3_formspec = techage.generator_settings("ta3", PWR_PERF),
drop = "",
paramtype2 = "facedir",
groups = {not_in_creative_inventory=1},
diggable = false,
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
power.register_nodes({"techage:generator", "techage:generator_on"}, Cable, "gen", {"R"})
-- controlled by the turbine
techage.register_node({"techage:generator", "techage:generator_on"}, {
on_transfer = function(pos, in_dir, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "trigger" then
nvm.firebox_trigger = 3
if techage.is_running(nvm) then
return math.max((nvm.provided or PWR_PERF) / PWR_PERF, 0.02)
else
return 0
end
end
end,
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "delivered" then
return math.floor((nvm.provided or 0) + 0.5)
else
return State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 135 then -- Delivered Power
return 0, {math.floor((nvm.provided or 0) + 0.5)}
else
return State:on_beduino_request_data(pos, topic, payload)
end
end,
})
-- used by power terminal
control.register_nodes({"techage:generator", "techage:generator_on"}, {
on_receive = function(pos, tlib2, topic, payload)
end,
on_request = function(pos, tlib2, topic)
if topic == "info" then
local nvm = techage.get_nvm(pos)
local meta = M(pos)
return {
type = S("TA3 Generator"),
number = meta:get_string("node_number") or "",
running = techage.is_running(nvm) or false,
available = PWR_PERF,
provided = nvm.provided or 0,
termpoint = meta:get_string("termpoint"),
}
end
return false
end,
}
)
minetest.register_craft({
output = "techage:generator",
recipe = {
{"basic_materials:steel_bar", "dye:green", "default:wood"},
{"", "basic_materials:gear_steel", "techage:electric_cableS"},
{"default:wood", "techage:iron_ingot", "basic_materials:steel_bar"},
},
})

View File

@ -1,156 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Firebox
]]--
-- for lazy programmers
local P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
local firebox = techage.firebox
local fuel = techage.fuel
local Pipe = techage.LiquidPipe
local liquid = networks.liquid
local CYCLE_TIME = 2
local BURN_CYCLE_FACTOR = 0.5
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local power = techage.transfer(
{x=pos.x, y=pos.y+2, z=pos.z},
nil, -- outdir
"trigger", -- topic
nil, -- payload
nil, -- network
{"techage:coalboiler_top"} -- nodenames
)
nvm.burn_cycles = (nvm.burn_cycles or 0) - math.max((power or 0.02), 0.02)
if nvm.burn_cycles <= 0 then
local liq_name = fuel.get_fuel(nvm)
if liq_name then
nvm.burn_cycles = fuel.burntime(liq_name) / CYCLE_TIME * BURN_CYCLE_FACTOR
nvm.burn_cycles_total = nvm.burn_cycles
else
nvm.running = false
firebox.set_firehole(pos, false)
M(pos):set_string("formspec", fuel.formspec(nvm))
return false
end
end
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", fuel.formspec(nvm))
end
return true
end
local function start_firebox(pos, nvm)
if not nvm.running and fuel.has_fuel(nvm) then
nvm.running = true
node_timer(pos, 0)
firebox.set_firehole(pos, true)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
end
minetest.register_node("techage:oilfirebox", {
description = S("TA3 Power Station Oil Burner"),
inventory_image = "techage_oil_boiler_inv.png",
tiles = {"techage_coal_boiler_mesh_top.png"},
drawtype = "mesh",
mesh = "techage_cylinder_12.obj",
selection_box = {
type = "fixed",
fixed = {-13/32, -16/32, -13/32, 13/32, 16/32, 13/32},
},
paramtype = "light",
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
on_timer = node_timer,
can_dig = fuel.can_dig,
on_rightclick = fuel.on_rightclick,
on_receive_fields = fuel.on_receive_fields,
after_place_node = function(pos, placer)
if firebox.is_free_position(pos, placer:get_player_name()) then
techage.add_node(pos, "techage:oilfirebox", true)
local nvm = techage.get_nvm(pos)
nvm.running = false
nvm.burn_cycles = 0
nvm.liquid = {}
nvm.liquid.amount = 0
local meta = M(pos)
meta:set_string("formspec", fuel.formspec(nvm))
local inv = meta:get_inventory()
firebox.set_firehole(pos, false)
else
minetest.remove_node(pos)
return true
end
end,
on_destruct = function(pos)
firebox.set_firehole(pos, nil)
end,
on_punch = function(pos, node, puncher, pointed_thing)
local nvm = techage.get_nvm(pos)
fuel.on_punch(pos, node, puncher, pointed_thing)
if nvm.liquid and nvm.liquid.amount and nvm.liquid.amount > 0 then
minetest.after(1, start_firebox, pos, nvm)
end
end,
})
liquid.register_nodes({"techage:oilfirebox"},
Pipe, "tank", nil, fuel.get_liquid_table(fuel.BT_OIL, fuel.CAPACITY, start_firebox))
techage.register_node({"techage:oilfirebox"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "state" then
return nvm.running and "running" or "stopped"
elseif topic == "fuel" then
return fuel.get_fuel_amount(nvm)
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 129 then
return 0, {nvm.running and techage.RUNNING or techage.STOPPED}
elseif topic == 132 then
return 0, {fuel.get_fuel_amount(nvm)}
else
return 2, ""
end
end,
})
minetest.register_craft({
output = "techage:oilfirebox",
recipe = {
{'', 'techage:coalfirebox', ''},
{'', 'techage:ta3_barrel_empty', ''},
{'', '', ''},
},
})

View File

@ -1,182 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Power Station Turbine
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.SteamPipe
local function transfer_cooler(pos, topic, payload)
return techage.transfer(pos, 6, topic, payload, Pipe,
{"techage:cooler", "techage:cooler_on"})
end
local function transfer_generator(pos, topic, payload)
return techage.transfer(pos, "R", topic, payload, nil,
{"techage:generator", "techage:generator_on"})
end
local function swap_node(pos, name)
local node = techage.get_node_lvm(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function play_sound(pos)
local mem = techage.get_mem(pos)
if not mem.handle or mem.handle == -1 then
mem.handle = minetest.sound_play("techage_turbine", {
pos = pos,
gain = 1,
max_hear_distance = 15,
loop = true})
if mem.handle == -1 then
minetest.after(1, play_sound, pos)
end
end
end
local function stop_sound(pos)
local mem = techage.get_mem(pos)
if mem.handle then
minetest.sound_stop(mem.handle)
mem.handle = nil
end
end
local function after_place_node(pos)
Pipe:after_place_node(pos)
end
local function after_dig_node(pos, oldnode)
stop_sound(pos)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end
local function tubelib2_on_update2(pos, outdir, tlib2, node)
swap_node(pos, "techage:turbine")
stop_sound(pos)
end
minetest.register_node("techage:turbine", {
description = S("TA3 Turbine"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_open.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_appl_turbine.png^techage_frame_ta3.png^[transformFX",
"techage_filling_ta3.png^techage_appl_turbine.png^techage_frame_ta3.png",
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
tubelib2_on_update2 = tubelib2_on_update2,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:turbine_on", {
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_open.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
{
name = "techage_filling4_ta3.png^techage_appl_turbine4.png^techage_frame4_ta3.png^[transformFX",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
{
name = "techage_filling4_ta3.png^techage_appl_turbine4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
},
tubelib2_on_update2 = tubelib2_on_update2,
paramtype2 = "facedir",
groups = {not_in_creative_inventory=1},
diggable = false,
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
Pipe:add_secondary_node_names({"techage:turbine", "techage:turbine_on"})
techage.register_node({"techage:turbine", "techage:turbine_on"}, {
on_transfer = function(pos, in_dir, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "trigger" then -- used by boiler
if not transfer_cooler(pos, topic, payload) then
return 0
end
local power = transfer_generator(pos, topic, payload)
if not power or power <= 0 and nvm.running then
swap_node(pos, "techage:turbine")
stop_sound(pos)
nvm.running = false
return 0
end
return power
elseif topic == "start" then -- used by generator
swap_node(pos, "techage:turbine_on")
play_sound(pos)
nvm.running = true
return true
elseif topic == "stop" then -- used by generator
swap_node(pos, "techage:turbine")
stop_sound(pos)
nvm.running = false
return true
end
end,
on_node_load = function(pos, node)
if node.name == "techage:turbine_on" then
play_sound(pos)
end
end,
})
minetest.register_craft({
output = "techage:turbine",
recipe = {
{"basic_materials:steel_bar", "techage:steam_pipeS", "default:wood"},
{"techage:steam_pipeS", "basic_materials:gear_steel", ""},
{"default:wood", "techage:iron_ingot", "basic_materials:steel_bar"},
},
})

View File

@ -1,89 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Cooler as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.LiquidPipe
minetest.register_node("techage:ta4_collider_cooler", {
description = S("TA4 Collider Cooler"),
tiles = {
-- up, down, right, left, back, front
{
name = "techage_appl_cooler4.png^techage_frame4_ta4_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
{
name = "techage_appl_cooler4.png^techage_frame4_ta4_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_pipe.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_pipe.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_cooler.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_cooler.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
})
Pipe:add_secondary_node_names({"techage:ta4_collider_cooler"})
Pipe:set_valid_sides("techage:ta4_collider_cooler", {"R", "L"})
techage.register_node({"techage:ta4_collider_cooler"}, {
on_transfer = function(pos, in_dir, topic, payload)
if topic == "cooler" then
return true
else
return false
end
end,
})
minetest.register_craft({
output = "techage:ta4_collider_cooler",
recipe = {
{'', 'dye:blue', ''},
{'', 'techage:cooler', ''},
{'', 'techage:aluminum', ''},
},
})

View File

@ -1,448 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Detector as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local getpos = techage.assemble.get_pos
local CYCLE_TIME = 2
local TNO_MAGNETS = 22
local IMPROBABILITY = 40 -- every 40 min
-- one point per 40 min: check every 20 s => factor = 40 * 3 = 120
IMPROBABILITY = (minetest.settings:get("techage_expoint_rate_in_min") or 40) * 3
local TIME_SLOTS = 10
local Schedule = {[0] =
-- Route: 0 = forward, 1 = right, 2 = backward, 3 = left
-- Gas left/right
{name = "techage:ta4_collider_pipe_inlet", yoffs = 1, route = {3,3,3,2}, check = techage.gas_inlet_check},
{name = "techage:ta4_collider_pipe_inlet", yoffs = 1, route = {1,1,1,2}, check = techage.gas_inlet_check},
-- Power left/right
{name = "techage:ta4_collider_cable_inlet", yoffs = 2, route = {3,3,3}, check = techage.power_inlet_check},
{name = "techage:ta4_collider_cable_inlet", yoffs = 2, route = {1,1,1}, check = techage.power_inlet_check},
-- Cooler
{name = "techage:ta4_collider_pipe_inlet", yoffs = 0, route = {0}, check = techage.cooler_check},
{name = "techage:ta4_collider_pipe_inlet", yoffs = 2, route = {0}, check = techage.cooler_check},
-- Air outlet
{name = "techage:ta4_collider_pipe_outlet", yoffs = 2, route = {}, check = techage.air_outlet_check},
-- All nodes
{name = "shell", yoffs = 0, route = {}, check = nil},
}
local function play_sound(pos)
minetest.sound_play("techage_hum", {
pos = pos,
gain = 0.5,
max_hear_distance = 10,
})
end
local function terminal_message(pos, msg)
local term_num = M(pos):contains("term_num") and M(pos):get_string("term_num")
local own_num = M(pos):get_string("node_number")
if term_num and own_num then
techage.send_single(own_num, term_num, "text", msg)
end
end
local function experience_points(pos)
if math.random(IMPROBABILITY) == 1 then
local owner = M(pos):get_string("owner")
local own_num = M(pos):get_string("node_number")
local player = minetest.get_player_by_name(owner)
if player then
if techage.add_expoint(player, own_num) then
terminal_message(pos, "Experience point reached!")
end
end
end
end
local function check_shell(pos, param2)
local pos1 = getpos(pos, param2, {3,3,3,2}, 0)
local pos2 = getpos(pos, param2, {1,1,1,0}, 2)
local _, tbl = minetest.find_nodes_in_area(pos1, pos2, {"techage:ta4_detector_magnet", "techage:ta4_colliderblock", "default:obsidian_glass"})
if tbl["techage:ta4_detector_magnet"] < 16 then
return false, "Magnet missing"
elseif tbl["techage:ta4_colliderblock"] < 31 then
return false, "Steel block missing"
elseif tbl["default:obsidian_glass"] < 1 then
return false, "Obsidian glass missing"
end
return true
end
local function check_state(pos)
-- Cyclically check all connections
local param2 = minetest.get_node(pos).param2
local nvm = techage.get_nvm(pos)
nvm.ticks = (nvm.ticks or 0) + 1
local idx = nvm.ticks % TIME_SLOTS
local item = Schedule[idx]
if idx == 1 then
nvm.result = true
end
if item then
if item.name == "shell" then
local res, err = check_shell(pos, param2)
if not res then
nvm.result = false
nvm.runnning = false
terminal_message(pos, (err or "unknown") .. "!!!")
return nvm.result
end
else
local pos2 = getpos(pos, param2, item.route, item.yoffs)
local nvm2 = techage.get_nvm(pos2)
local meta2 = M(pos2)
local node2 = minetest.get_node(pos2)
if item.name == node2.name then
local res, err = item.check(pos2, node2, meta2, nvm2)
--print("check_state", idx, res, err)
if not res then
nvm.result = false
nvm.runnning = false
terminal_message(pos, (err or "unknown") .. "!!!")
return nvm.result
end
else
nvm.result = false
nvm.runnning = false
terminal_message(pos, "Detector defect!!!")
end
end
elseif idx == #Schedule + 1 then
return nvm.result
end
end
local function add_laser(pos)
local param2 = minetest.get_node(pos).param2
local pos1 = getpos(pos, param2, {3,3}, 1)
local pos2 = getpos(pos, param2, {1,1,1}, 1)
techage.del_laser(pos)
techage.add_laser(pos, pos1, pos2)
end
local function create_task(pos, task)
local mem = techage.get_mem(pos)
if not mem.co then
mem.co = coroutine.create(task)
end
local _, err = coroutine.resume(mem.co, pos)
if err then
mem.co = nil
--print(err)
return
end
minetest.after(0.4, create_task, pos, task)
end
-- Call on_cyclic_check of all magents so that the magnets don't need a FLB.
local function magnets_on_cyclic_check(pos, nvm)
local ndef = minetest.registered_nodes["techage:ta4_magnet"]
for idx,pos2 in ipairs(nvm.magnet_positions or {}) do
local res = ndef.on_cyclic_check(pos2)
if res == -2 then
terminal_message(pos, "Magnet #" .. idx .. " defect!!!")
return false
elseif res == -1 then
terminal_message(pos, "Vacuum defect!!!")
techage.air_outlet_reset({x=pos.x, y=pos.y + 2, z=pos.z})
return false
end
end
return true
end
-- Turn off all magnets so that they don't consume power
local function magnets_turn_off(pos, nvm)
local ndef = minetest.registered_nodes["techage:ta4_magnet"]
for idx,pos2 in ipairs(nvm.magnet_positions or {}) do
ndef.on_turn_off(pos2)
end
end
local function cable_inlets_turn_on_off(pos, on)
local turn_on_off = function(pos, param2, item)
local pos2 = getpos(pos, param2, item.route, item.yoffs)
local node2 = minetest.get_node(pos2)
if item.name == node2.name then
local nvm = techage.get_nvm(pos2)
techage.power_inlet_turn_on_off(pos2, nvm, on)
end
end
local param2 = minetest.get_node(pos).param2
turn_on_off(pos, param2, Schedule[2])
turn_on_off(pos, param2, Schedule[3])
end
minetest.register_node("techage:ta4_detector_core", {
description = S("TA4 Collider Detector Core"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_collider_detector_core.png",
"default_steel_block.png^techage_collider_detector_core.png",
"default_steel_block.png^techage_collider_detector_core.png",
"default_steel_block.png^techage_collider_detector_core.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
local meta = M(pos)
local own_num = techage.add_node(pos, "techage:ta4_detector_core")
meta:set_string("node_number", own_num)
meta:set_string("owner", placer:get_player_name())
M({x=pos.x, y=pos.y - 1, z=pos.z}):set_string("infotext", S("TA4 Collider Detector") .. " " .. own_num)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
on_timer = function(pos, elapsed)
local nvm = techage.get_nvm(pos)
if nvm.running then
if not magnets_on_cyclic_check(pos, nvm) then
techage.del_laser(pos)
terminal_message(pos, "Detector stopped.")
magnets_turn_off(pos, nvm)
cable_inlets_turn_on_off(pos, false)
nvm.running = false
nvm.magnet_positions = nil
else
local res = check_state(pos)
if res == true then
experience_points(pos)
add_laser(pos)
if nvm.ticks <= TIME_SLOTS then -- only once
terminal_message(pos, "Detector running.")
end
elseif res == false then
techage.del_laser(pos)
magnets_turn_off(pos, nvm)
cable_inlets_turn_on_off(pos, false)
nvm.running = false
nvm.magnet_positions = nil
terminal_message(pos, "Detector stopped.")
end
if nvm.running then
play_sound(pos)
end
end
end
return true
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.on_remove_collider(digger)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end,
})
local function check_expr(own_num, term_num, text, expr)
techage.send_single(own_num, term_num, "text", text .. "..." .. (expr and "ok" or "error!!!"))
return expr
end
local function start_task(pos)
local term_num = M(pos):contains("term_num") and M(pos):get_string("term_num")
local param2 = minetest.get_node(pos).param2
local pos2 = getpos(pos, param2, {3,3,3}, 1)
local own_num = M(pos):get_string("node_number")
local nvm = techage.get_nvm(pos)
nvm.magnet_positions = {}
if term_num and param2 and pos2 then
techage.send_single(own_num, term_num, "text", "#### Start ####")
coroutine.yield()
local resp = techage.tube_inlet_command(pos2, "enumerate", 1)
if not check_expr(own_num, term_num, "- Check number of magnets", resp == TNO_MAGNETS) then
nvm.locked = false
return
end
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Check position of magnets...")
resp = techage.tube_inlet_command(pos2, "distance")
if resp ~= true then
techage.send_single(own_num, term_num, "append", "#" .. resp .. " defect!!!")
nvm.locked = false
return
end
techage.send_single(own_num, term_num, "append", "ok")
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Start magnets...")
local t = {}
for num = 1, TNO_MAGNETS do
local resp = techage.tube_inlet_command(pos2, "pos", num)
if not resp or type(resp) ~= "table" then
techage.send_single(own_num, term_num, "append", "#" .. num .. " defect!!!")
nvm.magnet_positions = nil
nvm.locked = false
return
else
t[#t + 1] = resp
end
coroutine.yield()
end
nvm.magnet_positions = t
techage.send_single(own_num, term_num, "append", "ok")
cable_inlets_turn_on_off(pos, true)
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Check magnets...")
-- The check will be performed by the timer, so wait 5 sec.
for i = 1,14 do
coroutine.yield()
end
if nvm.magnet_positions then
techage.send_single(own_num, term_num, "append", "ok")
else
nvm.locked = false
return
end
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Check detector...")
for _,item in ipairs(Schedule)do
if item.name == "shell" then
local res, err = check_shell(pos, param2)
if not res then
techage.send_single(own_num, term_num, "append", err .. "!!!")
nvm.magnet_positions = nil
nvm.locked = false
cable_inlets_turn_on_off(pos, false)
return
end
else
local pos2 = getpos(pos, param2, item.route, item.yoffs)
local nvm2 = techage.get_nvm(pos2)
local meta2 = M(pos2)
local node2 = minetest.get_node(pos2)
if item.name == node2.name then
local res, err = item.check(pos2, node2, meta2, nvm2)
if not res then
techage.send_single(own_num, term_num, "append", err .. "!!!")
nvm.magnet_positions = nil
nvm.locked = false
cable_inlets_turn_on_off(pos, false)
return
end
else
techage.send_single(own_num, term_num, "append", "defect!!!")
nvm.magnet_positions = nil
nvm.locked = false
cable_inlets_turn_on_off(pos, false)
return
end
coroutine.yield()
end
end
techage.send_single(own_num, term_num, "append", "ok")
coroutine.yield()
techage.send_single(own_num, term_num, "text", "Collider starting...")
nvm.ticks = 0
nvm.running = true
end
end
local function test_magnet(pos, payload)
local term_num = M(pos):contains("term_num") and M(pos):get_string("term_num")
local param2 = minetest.get_node(pos).param2
local pos2 = getpos(pos, param2, {3,3,3}, 1)
local own_num = M(pos):get_string("node_number")
local magnet_num = tonumber(payload)
local res, err = techage.tube_inlet_command(pos2, "test", magnet_num)
if res then
techage.send_single(own_num, term_num, "text", "magnet #" .. magnet_num .. ": ok")
else
techage.send_single(own_num, term_num, "text", "magnet #" .. magnet_num .. ": " .. (err or "unknown error") .. "!!!")
end
end
techage.register_node({"techage:ta4_detector_core"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "connect" then
M(pos):set_string("term_num", src)
return true
elseif topic == "start" then
-- Worker block
nvm.locked = true
create_task(pos, start_task)
return true
elseif topic == "stop" then
nvm.running = false
techage.del_laser(pos)
nvm.locked = false
magnets_turn_off(pos, nvm)
cable_inlets_turn_on_off(pos, false)
nvm.magnet_positions = nil
return "Detector stopped."
elseif topic == "status" then
if nvm.running == true then
return "running"
elseif nvm.result == false then
return "fault"
else
return "stopped"
end
elseif topic == "test"then
if payload and tonumber(payload) then
test_magnet(pos, payload)
return true
else
return "Invalid magnet number"
end
elseif topic == "points" then
local owner = M(pos):get_string("owner")
local player = minetest.get_player_by_name(owner)
if player then
local points = techage.get_expoints(player)
return "Ex. Points = " .. points
end
else
return "unsupported"
end
end,
on_node_load = function(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
minetest.register_craft({
output = "techage:ta4_detector_core",
recipe = {
{'techage:aluminum', 'basic_materials:heating_element', 'default:steel_ingot'},
{'default:diamond', 'techage:ta4_wlanchip', 'techage:electric_cableS'},
{'default:steel_ingot', '', 'techage:aluminum'},
},
})

View File

@ -1,375 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Tube/Pipe Inputs/Outputs as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local PWR_NEEDED = 15
local CYCLE_TIME = 2
local GAS_CAPA = 20
local AIR_CAPA = 1000
local VTube = techage.VTube
local Pipe = techage.LiquidPipe
local Cable = techage.ElectricCable
local power = networks.power
local liquid = networks.liquid
--------------------------------------------------------------------------------
-- Tube Input
--------------------------------------------------------------------------------
minetest.register_node("techage:ta4_collider_tube_inlet", {
description = S("TA4 Collider Tube Input"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_collider_tube_open.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-4/8, -4/8, -4/8, -1/8, 4/8, 4/8},
{ 1/8, -4/8, -4/8, 4/8, 4/8, 4/8},
{-4/8, 1/8, -4/8, 4/8, 4/8, 4/8},
{-4/8, -4/8, -4/8, 4/8, -1/8, 4/8},
},
},
selection_box = {
type = "fixed",
fixed = {-4/8, -4/8, -4/8, 4/8, 4/8, 4/8},
},
paramtype2 = "facedir",
paramtype = "light",
use_texture_alpha = techage.CLIP,
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
VTube:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode)
VTube:after_dig_node(pos)
techage.del_mem(pos)
end,
})
VTube:add_secondary_node_names({"techage:ta4_collider_tube_inlet"})
VTube:set_valid_sides("techage:ta4_collider_tube_inlet", {"F"})
-- Called from the detector via tube ring
techage.register_node({"techage:ta4_collider_tube_inlet"}, {
on_transfer = function(pos, in_dir, topic, payload)
if topic == "distance" then
return pos
elseif topic == "enumerate" and payload then
return payload - 1
elseif topic == "check" then
local nvm = techage.get_nvm(pos)
nvm.check_received = true
return true
end
end,
})
-- Used by the detector to check the tube connection
function techage.tube_inlet_command(pos, command, payload)
if command == "distance" then
local pos2 = techage.transfer(pos, "F", command, payload, VTube, {"techage:ta4_magnet"})
if type(pos2) == "table" then
local dist = math.abs(pos.x - pos2.x) + math.abs(pos.z - pos2.z)
if pos.y == pos2.y and dist == VTube.max_tube_length + 1 then
return true
end
return 0
else
return pos2
end
end
return techage.transfer(pos, "F", command, payload, VTube, {"techage:ta4_magnet"})
end
minetest.register_craft({
output = "techage:ta4_collider_tube_inlet",
recipe = {
{'', '', ''},
{'techage:ta4_vtubeS', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})
--------------------------------------------------------------------------------
-- Pipe Input (gas)
--------------------------------------------------------------------------------
minetest.register_node("techage:ta4_collider_pipe_inlet", {
description = S("TA4 Collider Pipe Input"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_appl_hole_pipe.png",
},
drawtype = "nodebox",
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
Pipe:after_place_node(pos)
nvm.liquid = {}
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
})
liquid.register_nodes({"techage:ta4_collider_pipe_inlet"}, Pipe, "tank", {"F"}, {
capa = GAS_CAPA,
peek = function(pos, indir)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end,
put = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_put(nvm, name, amount, GAS_CAPA)
end,
take = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_take(nvm, name, amount)
end,
untake = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
liquid.srv_put(nvm, name, amount, GAS_CAPA)
end,
})
techage.register_node({"techage:ta4_collider_pipe_inlet"}, {
on_transfer = function(pos, in_dir, topic, payload)
-- called from heatexchanger
if topic == "detector" then
local nvm = techage.get_nvm(pos)
nvm.detector_received = true
return true
end
end,
})
-- Used by the detector to check for gas pressure
function techage.gas_inlet_check(pos, node, meta, nvm)
nvm.liquid = nvm.liquid or {}
if nvm.liquid.amount == GAS_CAPA and nvm.liquid.name == "techage:isobutane" then
return true
end
return false, "no gas"
end
-- Used by the detector to check for cooler connection
function techage.cooler_check(pos, node, meta, nvm)
if nvm.detector_received then
nvm.detector_received = nil
return true
end
return false, "Cooler defect"
end
minetest.register_craft({
output = "techage:ta4_collider_pipe_inlet",
recipe = {
{'', '', ''},
{'techage:ta3_pipeS', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})
--------------------------------------------------------------------------------
-- Pipe Output (air)
--------------------------------------------------------------------------------
local function init_air(nvm)
nvm.liquid = {
amount = AIR_CAPA,
name = "air",
}
return nvm.liquid
end
minetest.register_node("techage:ta4_collider_pipe_outlet", {
description = S("TA4 Collider Pipe Output"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png^techage_appl_hole_pipe.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
},
drawtype = "nodebox",
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
init_air(nvm)
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
})
liquid.register_nodes({"techage:ta4_collider_pipe_outlet"}, Pipe, "tank", {"U"}, {
capa = AIR_CAPA,
peek = function(pos, indir)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end,
put = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_put(nvm, name, amount, AIR_CAPA)
end,
take = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_take(nvm, name, amount)
end,
untake = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
liquid.srv_put(nvm, name, amount, AIR_CAPA)
end,
})
-- Used by the detector to check the vacuum
function techage.air_outlet_check(pos, node, meta, nvm)
nvm.liquid = nvm.liquid or {}
if nvm.liquid.amount == 0 then
return true
end
return false, "no vacuum"
end
function techage.air_outlet_reset(pos)
local nvm = techage.get_nvm(pos)
init_air(nvm)
end
minetest.register_craft({
output = "techage:ta4_collider_pipe_outlet",
recipe = {
{'', 'techage:ta3_pipeS', ''},
{'', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})
--------------------------------------------------------------------------------
-- Cable Input (power)
--------------------------------------------------------------------------------
minetest.register_node("techage:ta4_collider_cable_inlet", {
description = S("TA4 Collider Cable Input"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_appl_hole_electric.png",
},
drawtype = "nodebox",
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
Cable:after_place_node(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
on_timer = function(pos, elapsed)
local nvm = techage.get_nvm(pos)
if nvm.running then
nvm.consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
else
nvm.consumed = 0
end
return true
end,
after_dig_node = function(pos, oldnode)
Cable:after_dig_node(pos)
techage.del_mem(pos)
end,
})
-- Used by the detector to check for power
function techage.power_inlet_check(pos, node, meta, nvm)
if nvm.consumed == PWR_NEEDED then
return true
end
return false, "no power"
end
-- Used by the detector to turn on/off the node
function techage.power_inlet_turn_on_off(pos, nvm, on)
nvm.running = on
end
power.register_nodes({"techage:ta4_collider_cable_inlet"}, Cable, "con", {"F"})
techage.register_node({"techage:ta4_collider_cable_inlet"}, {
on_node_load = function(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
minetest.register_craft({
output = "techage:ta4_collider_cable_inlet",
recipe = {
{'', '', ''},
{'techage:electric_cableS', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})

View File

@ -1,333 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Magnet as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local PWR_NEEDED = 5
local CYCLE_TIME = 2
local CAPACITY = 10
local Cable = techage.ElectricCable
local Pipe = techage.LiquidPipe
local VTube = techage.VTube
local power = networks.power
local liquid = networks.liquid
local function is_junction(pos, side)
local node = techage.get_node_lvm(techage.get_pos(pos, side))
return node and techage.string_compare(node.name, "techage:ta3_junction")
end
-- Turn the magnet to the right direction
local function handle_legacy_magnet(pos)
if M(pos):get_string("version") ~= "V2" then
if is_junction(pos, "B") and not is_junction(pos, "F") then
local node = techage.get_node_lvm(pos)
node.param2 = (node.param2 + 2) % 4
minetest.swap_node(pos, node)
end
end
M(pos):set_string("version", "V2")
end
minetest.register_node("techage:ta4_colliderblock", {
description = S("TA4 Collider Steel Block"),
tiles = {
"default_steel_block.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:ta4_detector_magnet", {
description = S("TA4 Collider Detector Magnet"),
tiles = {
-- up, down, right, left, back, front
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
"techage_collider_magnet.png",
"techage_collider_magnet.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:ta4_magnet", {
description = S("TA4 Collider Magnet"),
inventory_image = minetest.inventorycube(
"techage_collider_magnet.png^techage_appl_hole_electric.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png^techage_appl_hole_pipe.png^techage_collider_magnet_sign.png",
"techage_collider_magnet.png^techage_collider_magnet_tube.png"),
tiles = {
-- up, down, right, left, back, front
"techage_collider_magnet.png^techage_appl_hole_electric.png",
"techage_collider_magnet.png",
"techage_collider_magnet.png^techage_collider_magnet_tube.png",
"techage_collider_magnet.png^techage_collider_magnet_tube.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png^techage_collider_magnet_sign.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png^techage_appl_hole_pipe.png^techage_collider_magnet_sign.png",
},
drawtype = "nodebox",
use_texture_alpha = techage.CLIP,
node_box = {
type = "fixed",
fixed = {
{-11/16, -11/16, -11/16, 11/16, 11/16, -2/16},
{-11/16, -11/16, 2/16, 11/16, 11/16, 11/16},
{-11/16, 2/16, -11/16, 11/16, 11/16, 11/16},
{-11/16, -11/16, -11/16, 11/16, -2/16, 11/16},
},
},
selection_box = {
type = "fixed",
fixed = {-4/8, -4/8, -4/8, 4/8, 4/8, 4/8},
},
collision_box = {
type = "fixed",
fixed = {-11/16, -11/16, -11/16, 11/16, 11/16, 11/16},
},
wield_scale = {x = 0.8, y = 0.8, z = 0.8},
paramtype2 = "facedir",
paramtype = "light",
use_texture_alpha = techage.CLIP,
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
if pos.y > techage.collider_min_depth then
minetest.remove_node(pos)
minetest.add_item(pos, ItemStack("techage:ta4_magnet"))
return
end
local nvm = techage.get_nvm(pos)
nvm.liquid = {}
Pipe:after_place_node(pos)
Cable:after_place_node(pos)
VTube:after_place_node(pos)
M(pos):set_string("infotext", S("TA4 Collider Magnet") .. " #0")
M(pos):set_string("version", "V2")
end,
-- To be called by the detector
on_cyclic_check = function(pos)
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.consumed = power.consume_power(pos, Cable, 6, PWR_NEEDED)
if nvm.tube_damage then
nvm.tube_damage = nil
nvm.running = nil
return -1
elseif nvm.liquid.amount == CAPACITY and
nvm.liquid.name == "techage:isobutane" and
nvm.consumed == PWR_NEEDED then
nvm.running = true
return 0
end
nvm.running = nil
return -2
end,
on_turn_off = function(pos)
local nvm = techage.get_nvm(pos)
nvm.running = nil
end,
tubelib2_on_update2 = function(pos, outdir, tlib2, node)
if tlib2.tube_type == "vtube" then
local nvm = techage.get_nvm(pos)
nvm.tube_damage = true
elseif tlib2.tube_type == "pipe2" then
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = 0
end
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
Cable:after_dig_node(pos)
VTube:after_dig_node(pos)
techage.del_mem(pos)
end,
})
power.register_nodes({"techage:ta4_magnet"}, Cable, "con", {"U"})
liquid.register_nodes({"techage:ta4_magnet"}, Pipe, "tank", {"F"}, {
capa = CAPACITY,
peek = function(pos, indir)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end,
put = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_put(nvm, name, amount, CAPACITY)
end,
take = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_take(nvm, name, amount)
end,
untake = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
liquid.srv_put(nvm, name, amount, CAPACITY)
end,
})
VTube:add_secondary_node_names({"techage:ta4_magnet"})
VTube:set_valid_sides("techage:ta4_magnet", {"R", "L"})
local function send_to_next(pos, in_dir, topic, payload)
return techage.transfer(pos, in_dir, topic, payload, VTube,
{"techage:ta4_magnet", "techage:ta4_collider_tube_inlet"})
end
--[[
Commands
--------
distance : Check distance between all magnets.
Returns pos of next magnet or the number of the defect magnet.
enumerate : Give each magnet a unique number (1...n)
pos : Read the position
test : Test all magnet attributs.
Returns true or false, err
]]--
techage.register_node({"techage:ta4_magnet"}, {
on_transfer = function(pos, in_dir, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "distance" then
local pos2 = send_to_next(pos, in_dir, topic, payload)
if type(pos2) == "table" then
local dist = math.abs(pos.x - pos2.x) + math.abs(pos.z - pos2.z)
if pos.y == pos2.y and dist == VTube.max_tube_length + 1 then
return pos
end
return nvm.number or 0
else
return pos2
end
elseif topic == "enumerate" and payload then
handle_legacy_magnet(pos)
payload = tonumber(payload) or 1
nvm.number = payload
M(pos):set_string("infotext", S("TA4 Collider Magnet") .. " #" .. payload)
return send_to_next(pos, in_dir, topic, payload + 1)
elseif topic == "pos" then
if payload and tonumber(payload) == nvm.number then
nvm.tube_damage = nil
return pos
else
return send_to_next(pos, in_dir, topic, payload)
end
elseif topic == "test" then
if payload and tonumber(payload) == nvm.number then
if not nvm.liquid or not nvm.liquid.amount or nvm.liquid.amount < CAPACITY then
return false, "no gas"
elseif nvm.liquid.name ~= "techage:isobutane" then
return false, "wrong gas"
elseif nvm.consumed ~= PWR_NEEDED then
return false, "no power"
elseif nvm.tube_damage then
nvm.tube_damage = nil
return false, "no vacuum"
end
return true
else
return send_to_next(pos, in_dir, topic, payload)
end
end
end,
})
minetest.register_node("techage:ta4_magnet_base", {
description = S("TA4 Collider Magnet Base"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-6/16, -8/16, -6/16, 6/16, 5/16, 6/16},
},
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_craft({
output = "techage:ta4_colliderblock",
recipe = {
{'techage:aluminum', '', 'default:steel_ingot'},
{'', '', ''},
{'default:steel_ingot', '', 'techage:aluminum'},
},
})
minetest.register_craft({
output = "techage:ta4_detector_magnet 2",
recipe = {
{'default:steel_ingot', '', 'techage:aluminum'},
{'dye:red', 'basic_materials:gold_wire', 'dye:brown'},
{'techage:aluminum', '', 'default:steel_ingot'},
},
})
minetest.register_craft({
output = "techage:ta4_magnet",
recipe = {
{'techage:ta3_pipeS', '', 'techage:electric_cableS'},
{'techage:ta4_round_ceramic', 'techage:ta4_detector_magnet', 'techage:ta4_round_ceramic'},
{'', '', ''},
},
})
minetest.register_craft({
output = "techage:ta4_magnet_base 4",
recipe = {
{'techage:aluminum', 'default:steel_ingot', ''},
{'techage:aluminum', 'default:steel_ingot', ''},
{'techage:aluminum', 'default:steel_ingot', ''},
},
})
minetest.register_lbm({
label = "Repair Magnets",
name = "techage:magnets",
nodenames = {"techage:ta4_magnet", "techage:ta4_collider_pipe_inlet"},
run_at_every_load = false,
action = function(pos, node)
local nvm = techage.get_nvm(pos)
if nvm.liquid and nvm.liquid.name == "techage:hydrogen" then
nvm.liquid.name = "techage:isobutane"
end
end,
})

View File

@ -1,130 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Vacuum Tube as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local VTube = tubelib2.Tube:new({
dirs_to_check = {1,2,3,4},
max_tube_length = 5,
tube_type = "vtube",
show_infotext = false,
primary_node_names = {"techage:ta4_vtubeS", "techage:ta4_vtubeA"},
secondary_node_names = {"techage:ta4_magnet"},
after_place_tube = function(pos, param2, tube_type, num_tubes)
minetest.swap_node(pos, {name = "techage:ta4_vtube"..tube_type, param2 = param2})
end,
})
techage.VTube = VTube
minetest.register_node("techage:ta4_vtubeS", {
description = S("TA4 Vacuum Tube"),
drawtype = "nodebox",
tiles = {
-- up, down, right, left, back, front
"techage_collider_tube.png^[transformR90",
"techage_collider_tube.png^[transformR90",
"techage_collider_tube.png",
"techage_collider_tube.png",
'techage_collider_tube_open.png',
'techage_collider_tube_open.png',
},
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 6/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -6/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not VTube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
VTube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {cracky = 2},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:ta4_vtubeA", {
description = S("TA4 Vacuum Tube"),
drawtype = "nodebox",
tiles = {
-- up, down, right, left, back, front
"techage_collider_tube.png^[transformR90",
'techage_collider_tube.png^techage_collider_tube_open.png',
"techage_collider_tube.png",
"techage_collider_tube.png",
"techage_collider_tube.png^[transformR90",
'techage_collider_tube.png^techage_collider_tube_open.png',
},
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 6/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, 6/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -6/16, -6/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
VTube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {cracky = 1, not_in_creative_inventory=1},
drop = "techage:ta4_vtubeS",
sounds = default.node_sound_metal_defaults(),
})
minetest.register_craft({
output = "techage:ta4_vtubeS 4",
recipe = {
{'', 'default:steel_ingot', ''},
{'techage:aluminum', 'dye:blue', 'techage:aluminum'},
{'', 'default:steel_ingot', ''},
},
})

View File

@ -1,208 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Detector Worlker as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local AssemblyPlan = {
-- y-offs, path, facedir-offs, name
-- 0 = forward, 1 = right, 2 = backward, 3 = left
-- level 1
-- left/right
{ 1, {3,3,3,2}, 0, "techage:ta4_colliderblock"},
{ 1, {3,3,3}, 0, "techage:ta4_colliderblock"},
{ 1, {3,3,3,0}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,1,2}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,1}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,1,0}, 0, "techage:ta4_colliderblock"},
-- front
{ 1, {3,3,2}, 0, "techage:ta4_colliderblock"},
{ 1, {3,2}, 0, "techage:ta4_colliderblock"},
{ 1, {2}, 0, "techage:ta4_colliderblock"},
{ 1, {1,2}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,2}, 0, "techage:ta4_colliderblock"},
-- back
{ 1, {3,3,0}, 0, "techage:ta4_colliderblock"},
{ 1, {3,0}, 0, "techage:ta4_colliderblock"},
{ 1, {0}, 2, "techage:ta4_collider_pipe_inlet"},
{ 1, {1,0}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,0}, 0, "techage:ta4_colliderblock"},
-- middle
{ 1, {3,3}, 0, "techage:ta4_detector_magnet"},
{ 1, {3}, 0, "techage:ta4_detector_magnet"},
{ 1, {1}, 0, "techage:ta4_detector_magnet"},
{ 1, {1,1}, 0, "techage:ta4_detector_magnet"},
-- level 2
-- left/right
{ 2, {3,3,3,2}, 1, "techage:ta4_collider_pipe_inlet"},
{ 2, {3,3,3}, 1, "techage:ta4_collider_tube_inlet"},
{ 2, {3,3,3,0}, 0, "techage:ta4_colliderblock"},
{ 2, {1,1,1,2}, 3, "techage:ta4_collider_pipe_inlet"},
{ 2, {1,1,1}, 3, "techage:ta4_collider_tube_inlet"},
{ 2, {1,1,1,0}, 0, "techage:ta4_colliderblock"},
-- front
{ 2, {3,3,2}, 0, "techage:ta4_detector_magnet"},
{ 2, {3,2}, 0, "techage:ta4_detector_magnet"},
{ 2, {2}, 0, "default:obsidian_glass"},
{ 2, {1,2}, 0, "techage:ta4_detector_magnet"},
{ 2, {1,1,2}, 0, "techage:ta4_detector_magnet"},
-- back
{ 2, {3,3,0}, 0, "techage:ta4_detector_magnet"},
{ 2, {3,0}, 0, "techage:ta4_detector_magnet"},
{ 2, {0}, 0, "techage:ta4_colliderblock"},
{ 2, {1,0}, 0, "techage:ta4_detector_magnet"},
{ 2, {1,1,0}, 0, "techage:ta4_detector_magnet"},
-- level 3
-- left/right
{ 3, {3,3,3,2}, 0, "techage:ta4_colliderblock"},
{ 3, {3,3,3}, 1, "techage:ta4_collider_cable_inlet"},
{ 3, {3,3,3,0}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,1,2}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,1}, 3, "techage:ta4_collider_cable_inlet"},
{ 3, {1,1,1,0}, 0, "techage:ta4_colliderblock"},
-- front
{ 3, {3,3,2}, 0, "techage:ta4_colliderblock"},
{ 3, {3,2}, 0, "techage:ta4_colliderblock"},
{ 3, {2}, 0, "techage:ta4_colliderblock"},
{ 3, {1,2}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,2}, 0, "techage:ta4_colliderblock"},
-- back
{ 3, {3,3,0}, 0, "techage:ta4_colliderblock"},
{ 3, {3,0}, 0, "techage:ta4_colliderblock"},
{ 3, {0}, 2, "techage:ta4_collider_pipe_inlet"},
{ 3, {1,0}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,0}, 0, "techage:ta4_colliderblock"},
-- middle
{ 3, {3,3}, 0, "techage:ta4_detector_magnet"},
{ 3, {3}, 0, "techage:ta4_detector_magnet"},
{ 3, {}, 0, "techage:ta4_collider_pipe_outlet"},
{ 3, {1}, 0, "techage:ta4_detector_magnet"},
{ 3, {1,1}, 0, "techage:ta4_detector_magnet"},
-- Core block
{ 1, {}, 0, "techage:ta4_detector_core"},
}
local t = {}
for name, cnt in pairs(techage.assemble.count_items(AssemblyPlan)) do
t[#t + 1] = " - " .. cnt .. " " .. name
end
local LABEL = table.concat(t, "\n")
local function build(pos, player_name)
minetest.chat_send_player(player_name, S("[TA4] Detector is being built!"))
local inv = M(pos):get_inventory()
techage.assemble.build_inv(pos, inv, AssemblyPlan, player_name)
end
local function remove(pos, player_name)
minetest.chat_send_player(player_name, S("[TA4] Detector is being removed!"))
local inv = M(pos):get_inventory()
techage.assemble.remove_inv(pos, inv, AssemblyPlan, player_name)
end
local function formspec()
return "size[8,8.2]"..
"list[context;src;5,0;3,3;]"..
"label[0.2,-0.2;" .. S("Item list") .. ":\n" .. LABEL .. "]" ..
"button_exit[0,3.5;4,1;build;" .. S("Build detector") .. "]" ..
"button_exit[4,3.5;4,1;remove;" .. S("Remove detector") .. "]" ..
"list[current_player;main;0,4.5;8,4;]"..
"listring[context;src]"..
"listring[current_player;main]"
end
minetest.register_node("techage:ta4_collider_detector_worker", {
description = S("TA4 Collider Detector Worker"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png^techage_collider_detector_appl.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_appl.png^techage_collider_detector_banner.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
if pos.y > (techage.collider_min_depth - 2) then
minetest.remove_node(pos)
minetest.add_item(pos, ItemStack("techage:ta4_collider_detector_worker"))
return
end
local inv = M(pos):get_inventory()
inv:set_size("src", 9)
M(pos):set_string("formspec", formspec())
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
if fields.build then
if not nvm.assemble_locked then
build(pos, player:get_player_name())
end
elseif fields.remove then
if not nvm.assemble_locked then
local nvm = techage.get_nvm({x=pos.x, y=pos.y + 1, z=pos.z})
if not nvm.locked then
remove(pos, player:get_player_name())
end
end
end
end,
after_dig_node = function(pos, oldnode)
techage.del_mem(pos)
end,
can_dig = function(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked or nvm.assemble_build then
minetest.after(30, function(pos)
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end, pos)
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("src")
end,
})
minetest.register_craft({
output = "techage:ta4_collider_detector_worker",
recipe = {
{'techage:aluminum', 'default:chest', 'default:steel_ingot'},
{'', 'basic_materials:gear_steel', ''},
{'default:steel_ingot', 'default:mese_crystal', 'techage:aluminum'},
},
})

View File

@ -1,175 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2020 Thomas S.
AGPL v3
See LICENSE.txt for more information
Electricity powered battery for Digtron
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 4
local INV_SIZE = 4
local FUEL = "default:coal_lump"
local FUEL_STACK_MAX = ItemStack(FUEL):get_stack_max()
local TOTAL_MAX = INV_SIZE * FUEL_STACK_MAX
local function count_coal(metadata)
local total = 0
for _,stack in pairs(metadata.inventory.fuel or {}) do
total = total + stack:get_count()
end
return total
end
local function formspec(self, pos, nvm)
local meta = M(pos):to_table()
local total = 0
if meta.inventory then
total = count_coal(meta)
end
return "size[5,4]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;4.8,0.5;#c6e8ff]"..
"label[1,-0.1;"..minetest.colorize("#000000", S("Digtron Battery")).."]"..
techage.formspec_label_bar(pos, 0, 0.8, S("Load"), TOTAL_MAX, total, S("Coal Equivalents"))..
"image_button[2.6,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.6,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"image[3.75,2;1,1;"..techage.get_power_image(pos, nvm).."]"
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
return 0
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
return 0
end
local function produce_coal(pos, crd, nvm, inv)
local stack = ItemStack(FUEL)
if inv:room_for_item("fuel", stack) then
inv:add_item("fuel", stack)
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
else
crd.State:idle(pos, nvm)
end
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
produce_coal(pos, crd, nvm, inv)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles = {
-- up, down, right, left, back, front
"digtron_plate.png^digtron_core.png",
"digtron_plate.png^digtron_core.png",
"digtron_plate.png^digtron_battery.png",
"digtron_plate.png^digtron_battery.png",
"digtron_plate.png^digtron_battery.png",
"digtron_plate.png^digtron_battery.png",
}
local tubing = {
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("digtron_battery", S("Digtron Battery"), { act = tiles, pas = tiles }, {
drawtype = "normal",
paramtype = "light",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
after_place_node = function(pos, placer, itemstack)
local inv = M(pos):get_inventory()
inv:set_size('fuel', INV_SIZE)
if itemstack then
local stack_meta = itemstack:get_meta()
if stack_meta then
local coal_amount = techage.in_range(stack_meta:get_int("coal"), 0, TOTAL_MAX)
while coal_amount > 0 do
local amount = math.min(coal_amount, FUEL_STACK_MAX)
inv:add_item("fuel", ItemStack(FUEL.." "..amount))
coal_amount = coal_amount - amount;
end
end
end
end,
preserve_metadata = function(pos, oldnode, oldmetadata, drops)
local metadata = M(pos):to_table()
if metadata.inventory then
local total = count_coal(metadata)
local meta = drops[1]:get_meta()
meta:set_int("coal", total)
local text = S("Digtron Battery").." ("..math.floor(total/TOTAL_MAX * 100).." %)"
meta:set_string("description", text)
end
end,
on_rightclick = function(pos, node, clicker)
techage.set_activeformspec(pos, clicker)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2, digtron=5},
sounds = default.node_sound_wood_defaults(),
power_consumption = {0,25,25,25},
power_sides = {L=1, R=1, U=1, D=1, F=1, B=1},
}, {false, false, true, false})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"group:wood", "default:copper_ingot", "group:wood"},
{"techage:electric_cableS", "default:tin_ingot", "digtron:digtron_core"},
{"group:wood", "default:copper_ingot", "group:wood"},
},
})

View File

@ -1,279 +0,0 @@
--[[
]]--
local S = techage.S
local M = minetest.get_meta
local MP = minetest.get_modpath("techage")
local settings = {
symbol_item = "techage:construction_board_EN",
}
doclib.create_manual("techage", "DE", settings)
doclib.create_manual("techage", "EN", settings)
doclib.create_manual("techage", "pt-BR", settings)
doclib.create_manual("techage", "RU", settings)
local content
content = dofile(MP.."/doc/manual_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta1_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta2_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta3_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta4_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta5_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta1_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta2_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta3_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta4_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta5_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_RU.lua")
doclib.add_to_manual("techage", "RU", content)
content = dofile(MP.."/doc/manual_ta1_RU.lua")
doclib.add_to_manual("techage", "RU", content)
content = dofile(MP.."/doc/manual_ta2_RU.lua")
doclib.add_to_manual("techage", "RU", content)
content = dofile(MP.."/doc/manual_ta3_RU.lua")
doclib.add_to_manual("techage", "RU", content)
content = dofile(MP.."/doc/manual_ta4_RU.lua")
doclib.add_to_manual("techage", "RU", content)
content = dofile(MP.."/doc/manual_ta5_RU.lua")
doclib.add_to_manual("techage", "RU", content)
content = dofile(MP.."/doc/manual_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta1_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta2_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta3_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta4_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta5_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
local board_box = {
type = "wallmounted",
wall_side = {-16/32, -11/32, -16/32, -15/32, 6/16, 8/16},
}
minetest.register_node("techage:construction_board", {
description = "TA Konstruktionsplan (DE)",
inventory_image = 'techage_constr_plan_inv_de.png',
tiles = {"techage_constr_plan_de.png"},
drawtype = "nodebox",
node_box = board_box,
selection_box = board_box,
after_place_node = function(pos, placer, itemstack)
M(pos):set_string("infotext", "TA Konstruktionsplan (DE)")
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "DE"))
end,
on_receive_fields = function(pos, formname, fields, player)
local player_name = player:get_player_name()
if minetest.is_protected(pos, player_name) then
return
end
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "DE", fields))
end,
paramtype2 = "wallmounted",
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = "techage:construction_board",
recipe = {
{"default:stick", "default:stick", "default:stick"},
{"default:paper", "default:paper", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
},
})
minetest.register_node("techage:construction_board_EN", {
description = "TA Construction Board (EN)",
inventory_image = 'techage_constr_plan_inv.png',
tiles = {"techage_constr_plan.png"},
drawtype = "nodebox",
node_box = board_box,
selection_box = board_box,
after_place_node = function(pos, placer, itemstack)
M(pos):set_string("infotext", "TA Construction Board (EN)")
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "EN"))
end,
on_receive_fields = function(pos, formname, fields, player)
local player_name = player:get_player_name()
if minetest.is_protected(pos, player_name) then
return
end
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "EN", fields))
end,
paramtype2 = "wallmounted",
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = "techage:construction_board_EN",
recipe = {
{"default:stick", "default:paper", "default:stick"},
{"default:paper", "default:paper", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
},
})
minetest.register_node("techage:construction_board_RU", {
description = "TA Construction Board (RU)",
inventory_image = 'techage_constr_plan_inv_ru.png',
tiles = {"techage_constr_plan_ru.png"},
drawtype = "nodebox",
node_box = board_box,
selection_box = board_box,
after_place_node = function(pos, placer, itemstack)
M(pos):set_string("infotext", "План строительства ТА (RU)")
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "RU"))
end,
on_receive_fields = function(pos, formname, fields, player)
local player_name = player:get_player_name()
if minetest.is_protected(pos, player_name) then
return
end
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "RU", fields))
end,
paramtype2 = "wallmounted",
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = "techage:construction_board_RU",
recipe = {
{"default:paper", "default:paper", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
},
})
minetest.register_node("techage:construction_board_pt_BR", {
description = "TA Placa de construção (pt-BR)",
inventory_image = 'techage_constr_plan_inv_br.png',
tiles = {"techage_constr_plan_br.png"},
drawtype = "nodebox",
node_box = board_box,
selection_box = board_box,
after_place_node = function(pos, placer, itemstack)
M(pos):set_string("infotext", "TA Placa de construção (pt-BR)")
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "pt-BR"))
end,
on_receive_fields = function(pos, formname, fields, player)
local player_name = player:get_player_name()
if minetest.is_protected(pos, player_name) then
return
end
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "pt-BR", fields))
end,
paramtype2 = "wallmounted",
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = "techage:construction_board_pt_BR",
recipe = {
{"default:stick", "default:stick", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
},
})
minetest.register_craft({
type = "shapeless",
output = "techage:construction_board_EN",
recipe = {"techage:construction_board"},
})
minetest.register_craft({
type = "shapeless",
output = "techage:construction_board_RU",
recipe = { "techage:construction_board_EN" },
})
minetest.register_craft({
type = "shapeless",
output = "techage:construction_board_pt_BR",
recipe = {"techage:construction_board_RU"},
})
minetest.register_craft({
type = "shapeless",
output = "techage:construction_board",
recipe = {"techage:construction_board_pt_BR"},
})
--
-- Legacy API functions
--
function techage.add_to_manual(language, titles, texts, items, plans)
local content = {titles = titles, texts = texts, images = items or {}, plans = plans or {}}
doclib.add_to_manual("techage", language, content)
end
function techage.add_manual_items(table_with_items)
for name, image in pairs(table_with_items) do
doclib.add_manual_image("techage", "EN", name, image)
doclib.add_manual_image("techage", "DE", name, image)
doclib.add_manual_image("techage", "pt-BR", name, image)
doclib.add_manual_image("techage", "RU", name, image)
end
end
function techage.add_manual_plans(table_with_plans)
for name, plan in pairs(table_with_plans) do
doclib.add_manual_plan("techage", "EN", name, plan)
doclib.add_manual_plan("techage", "DE", name, plan)
doclib.add_manual_plan("techage", "RU", name, plan)
doclib.add_manual_plan("techage", "pt-BR", name, plan)
end
end

View File

@ -1,234 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA Items Table
]]--
local items = {
techage_ta1 = "techage_ta1.png",
iron = "techage:iron_ingot",
charcoal = "techage:charcoal",
lighter = "techage:lighter",
ta1_gravelsieve = "techage:sieve3",
hammer = "techage:hammer_bronze",
meridium = "techage:meridium_ingot",
baborium = "techage:stone_with_baborium",
bauxite = "techage:bauxite_stone",
usmium = "techage:usmium_nuggets",
basalt = "techage:basalt_stone",
oil = "techage:oil_source",
ta1_hopper = "techage:hopper_ta1",
wlanchip = "techage:ta4_wlanchip",
tube = "techage:tubeS",
concentrator = "techage:concentrator27",
ta1_sluice = "techage:ta1_sluice_closed",
ta1_sluice_handle = "techage:ta1_sluice_handle_closed",
ta1_board1 = "techage:ta1_board1_apple",
ta1_board2 = "techage:ta1_board2_apple",
----------------
techage_ta2 = "techage_ta2.png",
ta2_firebox = "techage:firebox",
ta2_boiler = "techage:boiler2",
ta2_cylinder = "techage:cylinder",
ta2_flywheel = "techage:flywheel",
ta2_steampipe = "techage:steam_pipeS",
ta2_distributor = "techage:ta2_distributor_pas",
ta2_pusher = "techage:ta2_pusher_pas",
ta2_gravelrinser = "techage:ta2_rinser_pas",
ta2_grinder = "techage:ta2_grinder_pas",
ta2_quarry = "techage:ta2_quarry_pas",
ta2_autocrafter = "techage:ta2_autocrafter_pas",
ta2_electronicfab = "techage:ta2_electronic_fab_pas",
ta2_gravelsieve = "techage:ta2_gravelsieve_pas",
ta2_liquidsampler = "techage:ta2_liquidsampler_pas",
ta2_rinser = "techage:ta2_rinser_pas",
ta2_chest = "techage:chest_ta2",
ta2_forceload = "techage:forceload",
ta2_driveaxle = "techage:axle",
ta2_generator = "techage:ta2_generator_off",
ta2_winch = "techage:ta2_winch",
ta2_weight_chest = "techage:ta2_weight_chest",
---------------------
techage_ta3 = "techage_ta3.png",
techage_ta31 = "techage_ta3b.png",
ta3_firebox = "techage:coalfirebox",
ta3_oilbox = "techage:oilfirebox",
ta3_boiler = "techage:coalboiler_top",
ta3_turbine = "techage:turbine",
ta3_generator = "techage:generator",
ta3_cooler = "techage:cooler",
ta3_distributor = "techage:ta3_distributor_pas",
ta3_pusher = "techage:ta3_pusher_pas",
ta3_gravelrinser = "techage:ta3_rinser_pas",
ta3_grinder = "techage:ta3_grinder_pas",
ta3_quarry = "techage:ta3_quarry_pas",
ta3_autocrafter = "techage:ta3_autocrafter_pas",
ta3_electronicfab = "techage:ta3_electronic_fab_pas",
ta3_gravelsieve = "techage:ta3_gravelsieve_pas",
ta3_liquidsampler = "techage:ta3_liquidsampler_pas",
ta3_powercable = "techage:electric_cableS",
ta3_powerline = "techage:power_lineS",
ta3_powerswitch = "techage:powerswitch",
ta3_powerswitchsmall = "techage:powerswitchsmall",
ta3_powerjunction = "techage:electric_junction0",
ta3_powerpole = "techage:power_pole3",
ta3_powerpole2 = "techage:power_pole2",
ta3_powerpole4 = "techage:power_pole",
ta3_powerswitchbox = "techage:powerswitch_box",
ta3_powerterminal = "techage:ta3_power_terminal",
ta3_trowel = "techage:trowel",
ta3_screwdriver = "techage:screwdriver",
ta3_tinygenerator = "techage:tiny_generator",
ta3_akkublock = "techage:ta3_akku",
ta3_furnace = "techage:ta3_furnace_pas",
ta3_furnacefirebox = "techage:furnace_firebox",
ta3_booster = "techage:ta3_booster",
ta3_oilexplorer = "techage:oilexplorer",
ta3_drillbox = "techage:ta3_drillbox_pas",
ta3_pumpjack = "techage:ta3_pumpjack_pas",
ta3_drillbit = "techage:oil_drillbit",
ta3_end_wrench = "techage:end_wrench",
ta3_tank = "techage:ta3_tank",
ta3_pump = "techage:t3_pump",
oiltank = "techage:oiltank",
reboiler = "techage:ta3_reboiler",
ta3_filler = "techage:filler",
tank_cart = "techage:tank_cart",
chest_cart = "techage:chest_cart",
----------------------------
ta3_button = "techage:ta3_button_off",
ta3_cartdetector = "techage:ta3_cartdetector_off",
ta3_detector = "techage:ta3_detector_off",
ta3_logic = "techage:ta3_logic",
ta3_nodedetector = "techage:ta3_nodedetector_off",
ta3_playerdetector = "techage:ta3_playerdetector_off",
ta3_lightdetector = "techage:ta3_lightdetector_off",
ta3_repeater = "techage:ta3_repeater",
ta3_sequencer = "techage:ta3_sequencer",
ta3_timer = "techage:ta3_timer",
ta3_terminal = "techage:terminal2",
ta3_colorlamp = "techage:color_lamp_off",
ta3_doorblock = "techage:doorblock20",
ta3_soundblock = "techage:ta3_soundblock",
ta3_programmer = "techage:programmer",
ta3_doorcontroller = "techage:ta3_doorcontroller",
ta3_drill_pipe_wrench = "techage:ta3_drill_pipe_wrench",
ta3_pipe = "techage:ta3_pipeS",
ta3_pipe_wall_entry = "techage:ta3_pipe_wall_entry",
ta3_mesecons_converter = "techage:ta3_mesecons_converter",
ta3_valve = "techage:ta3_valve_closed",
ta3_motor = "techage:ta3_motor_off",
ta3_injector = "techage:ta3_injector_pas",
ta3_command_converter = "techage:ta3_command_converter_off",
ta3_flipflop = "techage:ta3_flipflop_off",
----------------------------
techage_ta4 = "techage_ta4.png",
techage_ta4c = "techage_ta4c.png",
ta4_windturbine = "techage:ta4_wind_turbine",
ta4_pillar = "techage:pillar",
ta4_blinklamp = "techage:rotor_signal_lamp_off",
ta4_nacelle = "techage:ta4_wind_turbine_nacelle",
ta4_minicell = "techage:ta4_solar_minicell",
ta4_pipe = "techage:ta4_pipeS",
ta4_tube = "techage:ta4_tubeS",
ta4_junctionpipe = "techage:ta4_junctionpipe25",
ta4_pipeinlet = "techage:ta4_pipe_inlet",
ta4_turbine = "techage:ta4_turbine",
ta4_generator = "techage:ta4_generator",
ta4_heatexchanger = "techage:heatexchanger3",
ta4_powercable = "techage:ta4_power_cableS",
ta4_powerbox = "techage:ta4_power_box",
ta4_solarmodule = "techage:ta4_solar_module",
ta4_solarcarrier = "techage:ta4_solar_carrier",
ta4_solar_inverter = "techage:ta4_solar_inverter",
techage_ta4_solar = "techage_ta4_solar.png",
ta4_hydrogen = "techage_hydrogen_inv.png",
ta4_electrolyzer = "techage:ta4_electrolyzer",
ta4_fuelcell = "techage:ta4_fuelcell",
ta4_reactor = "techage:ta4_reactor",
ta4_tank = "techage:ta4_tank",
ta4_pump = "techage:t4_pump",
ta4_doser = "techage:ta4_doser",
ta4_silo = "techage:ta4_silo",
ta4_fillerpipe = "techage:ta4_reactor_fillerpipe",
ta4_reactorstand = "techage:ta4_reactor_stand",
ta4_reactorbase = "techage:ta4_reactor_base",
ta4_furnaceheater = "techage:furnace_heater",
ta4_waterpump = "techage:t4_waterpump",
ta4_icta_controller = "techage:ta4_icta_controller",
ta4_battery = "techage:ta4_battery",
ta4_display = "techage:ta4_display",
ta4_displayXL = "techage:ta4_displayXL",
ta4_signaltower = "techage:ta4_signaltower",
ta4_lua_controller = "techage:ta4_lua_controller",
ta4_lua_server = "techage:ta4_server",
ta4_sensor_chest = "techage:ta4_sensor_chest",
ta4_terminal = "techage:ta4_terminal",
ta4_button = "techage:ta4_button_off",
ta4_playerdetector = "techage:ta4_playerdetector_off",
ta4_collector = "techage:ta4_collector",
ta4_pusher = "techage:ta4_pusher_pas",
ta4_distributor = "techage:ta4_distributor_pas",
ta4_high_performance_distributor = "techage:ta4_high_performance_distributor_pas",
ta4_gravelsieve = "techage:ta4_gravelsieve_pas",
ta4_grinder = "techage:ta4_grinder_pas",
ta4_detector = "techage:ta4_detector_off",
ta4_chest = "techage:chest_ta4",
ta4_8x2000_chest = "techage:ta4_chest",
ta4_growlight = "techage:growlight_on",
ta4_streetlamp = "techage_ta4_streetlamp.png",
ta4_industriallamp = "techage:industriallamp4_off",
ta4_quarry = "techage:ta4_quarry_pas",
ta4_electronicfab = "techage:ta4_electronic_fab_pas",
ta4_injector = "techage:ta4_injector_pas",
ta4_liquid_filter = "techage_ta4_filter.png",
ta4_recycler = "techage:ta4_recycler_pas",
ta4_waterinlet = "techage:ta4_waterinlet",
ta4_laser = "techage:ta4_laser_emitter",
ta4_concentrator = "techage:ta4_concentrator27",
ta4_electricmeter = "techage:ta4_electricmeter",
ta4_transformer = "techage:ta4_transformer",
power_reduction = "techage_power_reduction.png",
ta4_button_2x = "techage:ta4_button_2x",
ta4_button_4x = "techage:ta4_button_4x",
ta4_sequencer = "techage:ta4_sequencer",
ta4_movecontroller = "techage:ta4_movecontroller",
ta4_turncontroller = "techage:ta4_turncontroller",
ta4_signallamp_2x = "techage:ta4_signallamp_2x",
ta4_signallamp_4x = "techage:ta4_signallamp_4x",
ta4_terminal = "techage:terminal3",
ta4_autocrafter = "techage:ta4_autocrafter_pas",
ta4_recipeblock = "techage:ta4_recipeblock",
ta4_chargedetector = "techage:ta4_chargedetector_off",
ta4_gaze_sensor = "techage:ta4_gaze_sensor_off",
ta4_nodedetector = "techage:ta4_nodedetector_off",
----------------------------
techage_ta5 = "techage:ta5_fr_nucleus",
ta5_flycontroller = "techage:ta5_flycontroller",
ta5_aichip = "techage:ta5_aichip",
ta5_aichip2 = "techage:ta5_aichip2",
ta5_tele_pipe = "techage:ta5_tele_pipe",
ta5_tele_tube = "techage:ta5_tele_tube",
ta5_chest = "techage:ta5_hl_chest",
ta5_tank = "techage:ta5_hl_tank",
ta5_magnet = "techage:ta5_magnet1",
ta5_pump = "techage:ta5_pump",
ta5_fr_shell = "techage:ta5_fr_shell",
ta5_fr_nucleus = "techage:ta5_fr_nucleus",
ta5_fr_controller = "techage:ta5_fr_controller_pas",
}
for name, image in pairs(items) do
doclib.add_manual_image("techage", "DE", name, image)
doclib.add_manual_image("techage", "EN", name, image)
doclib.add_manual_image("techage", "pt-BR", name, image)
doclib.add_manual_image("techage", "RU", name, image)
end

View File

@ -1,132 +0,0 @@
return {
titles = {
"1,Tech Age Mod",
"2,Hinweise",
"2,Änderungen ab Version 1.0",
"3,Tipps zur Umstellung",
"2,Erze und Mineralien",
"3,Meridium",
"3,Usmium",
"3,Baborium",
"3,Erdöl",
"3,Bauxit",
"3,Basalt",
},
texts = {
"Tech Age ist eine Technik-Mod mit 5 Entwicklungsstufen:\n"..
"\n"..
"TA1: Eisenzeitalter (Iron Age)\n"..
"Benutze Werkzeuge und Hilfsmittel wie Köhler\\, Kohlebrenner\\, Kiessieb\\, Hammer\\, Hopper um notwendige Erze und Metalle zu schürfen und zu verarbeiten.\n"..
"\n"..
"TA2: Dampfzeitalter (Steam Age)\n"..
"Baue eine Dampfmaschine mit Antriebsachsen und betreibe damit deine ersten Maschinen zur Verarbeitung von Erzen.\n"..
"\n"..
"TA3: Ölzeitalter (Oil Age)\n"..
"Suche und fördere Öl\\, baute Schienenwege zur Ölbeförderung. Ein Kraftwerk liefert den notwendigen Strom für deine Maschinen. Elektrisches Licht erhellt deine Industrieanlagen.\n"..
"\n"..
"TA4: Gegenwart (Present)\n"..
"Regenerative Energiequellen wie Wind\\, Sonne und Biokraft helfen dir\\, das Ölzeitalter zu verlassen. Mit modernen Technologien und intelligenten Maschinen machst du dich auf in die Zukunft.\n"..
"\n"..
"TA5: Zukunft (Future)\n"..
"Maschinen zur Überwindung von Raum und Zeit\\, neue Energiequellen und andere Errungenschaften prägen dein Leben.\n"..
"\n"..
"Hinweis: Mit Klicken auf die Pluszeichen kommst du in die Unterkapitel dieser Anleitung.\n"..
"\n"..
"\n"..
"\n",
"Diese Dokumentation ist sowohl \"ingame\" (Block Konstruktionsplan) als auch auf GitHub als MD-Files verfügbar.\n"..
"\n"..
" - Link: https://github.com/joe7575/techage/wiki\n"..
"\n"..
"Die Konstruktionspläne (Diagramme) für den Aufbau der Maschinen sowie die Bilder sind aber nur ingame verfügbar.\n"..
"\n"..
"Bei Tech Age musst du von vorne beginnen. Nur mit den Items aus TA1 kannst du TA2 Blöcke herstellen\\, für TA3 benötigst du die Ergebnisse aus TA2\\, usw.\n"..
"\n"..
"In TA2 laufen die Maschinen nur mit Antriebsachsen.\n"..
"\n"..
"Ab TA3 laufen die Maschinen mit Strom und besitzen eine Kommunikationsschnittstelle zur Fernsteuerung.\n"..
"\n"..
"Mit TA4 kommen weitere Stromquellen dazu\\, aber auch höhere logistische Herausforderungen (Stromtrassen\\, Item Transport).\n"..
"\n",
"Ab V1.0 (17.07.2021) hat sich folgendes geändert:\n"..
"\n"..
" - Der Algorithmus zur Berechnung der Stromverteilung hat sich geändert. Energiespeichersystem werden dadurch wichtiger. Diese gleichen Schankungen aus\\, was bei größeren Netzen mit mehreren Generatoren wichtig wird.\n"..
" - Aus diesem Grund hat TA2 seinen eigenen Energiespeicher erhalten.\n"..
" - Die Akkublöcke aus TA3 dienen auch als Energiespeicher. Ihre Funktionsweise wurde entsprechend angepasst.\n"..
" - Das TA4 Speichersystem wurde überarbeitet. Die Wärmetauscher (heatexchanger) haben eine neue Nummer bekommen\\, da die Funktionalität vom unteren in den mittleren Block verschoben wurde. Sofern diese ferngesteuert wurden\\, muss die Knotennummer angepasst werden. Die Generatoren haben kein eigenes Menü mehr\\, sondern werden nur noch über den Wärmetauscher ein-/ausgeschaltet. Wärmetauscher und Generator müssen jetzt am gleichen Netz hängen!\n"..
" - Mehrere Stromnetze können jetzt über einen TA4 Transformator Blöcke gekoppelt werden.\n"..
" - Neu ist auch ein TA4 Stromzähler Block für Unternetze.\n"..
"\n",
"Viele weitere Blöcke haben kleinere Änderungen bekommen. Daher kann es sein\\, dass Maschinen oder Anlagen nach der Umstellung nicht gleich wieder anlaufen. Sollte es zu Störungen kommen\\, helfen folgende Tipps:\n"..
"\n"..
" - Maschinen aus- und wieder eingeschalten\n"..
" - ein Stromkabel-Block entfernen und wieder setzen\n"..
" - den Block ganz entfernen und wieder setzen\n"..
" - mindestens ein Akkublock oder Speichersystem in jedes Netzwerk\n"..
"\n",
"Techage fügt dem Spiel einige neue Items hinzu:\n"..
"\n"..
" - Meridium - eine Legierung zur Herstellung von leuchtenden Werkzeugen in TA1\n"..
" - Usmium - ein Erz\\, was in TA2 gefördert und für TA3 benötigt wird\n"..
" - Baborium - ein Metall\\, welches für Rezepte in TA3 benötigt wird\n"..
" - Erdöl - wird in TA3 benötigt\n"..
" - Bauxit - ein Aluminiumerz\\, was in TA4 zur Herstellung von Aluminium benötigt wird\n"..
" - Basalt - entsteht\\, wenn sich Wasser und Lave berühren\n"..
"\n",
"Meridium ist eine Legierung aus Stahl und Mesekristallen. Meridium Ingots können mit dem Kohlebrenner aus Stahl und Mesesplitter hergestellt werden. Meridium leuchtet im Dunkeln. Auch Werkzeuge aus Meridium leuchten und sind daher im Untertagebau sehr hilfreich.\n"..
"\n"..
"\n"..
"\n",
"Usmium kommt nur als Nuggets vor und kann nur beim Waschen von Kies mit der TA2/TA3 Kieswaschanlage gewonnen werden.\n"..
"\n"..
"\n"..
"\n",
"Barborium kann nur im Untertagebau gewonnen werden. Diesen Stoff findet man nur in einer Tiefe von -250 bis -340 Metern.\n"..
"Baborium kann nur im TA3 Industrieofen geschmolzen werden.\n"..
"\n"..
"\n"..
"\n",
"Erdöl kann nur mit Hilfe des Explorers gefunden und mit Hilfe entsprechender TA3 Maschinen gefördert werden. Siehe TA3.\n"..
"\n"..
"\n"..
"\n",
"Bauxit wird nur im Untertagebau gewonnen. Bauxit findet man nur in Stein in einer Höhe zwischen -50 und -500 Meter.\n"..
"Es wird zur Herstellung von Aluminium benötigt\\, was vor allem in TA4 Verwendung findet.\n"..
"\n"..
"\n"..
"\n",
"Basalt entsteht nur\\, wenn Lava und Wasser zusammen kommen.\n"..
"Dazu sollte man am besten eine Anlage aufbauen\\, bei der eine Lava- und eine Wasserquelle zusammenfließen.\n"..
"Dort wo sich beide Flüssigkeiten treffen\\, entsteht Basalt.\n"..
"Einen automatisierten Basalt Generator kann man mit dem Sign Bot aufbauen.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta4",
"",
"",
"",
"",
"meridium",
"usmium",
"baborium",
"oil",
"bauxite",
"basalt",
},
plans = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

View File

@ -1,144 +0,0 @@
return {
titles = {
"1,Tech Age Mod",
"2,Hints",
"2,Changes from version 1.0",
"3,Tips on switching",
"2,Ores and Minerals",
"3,Meridium",
"3,Usmium",
"3,Baborium",
"3,Petroleum",
"3,Bauxite",
"3,Basalt",
"2,History",
},
texts = {
"Tech Age is a technology mod with 5 development stages:\n"..
"\n"..
"TA1: Iron Age\n"..
"Use tools and aids such as coal burners\\, coal burners\\, gravel sieves\\, hammers and hoppers to mine and process the necessary ores and metals.\n"..
"\n"..
"TA2: Steam Age\n"..
"Build a steam engine with drive axles and use it to operate your first ore processing machines.\n"..
"\n"..
"TA3: Oil Age\n"..
"Find and extract oil\\, built railways for oil transportation. A power plant provides the necessary electricity for your machines. Electric light illuminates your industrial plants.\n"..
"\n"..
"TA4: Present\n"..
"Renewable energy sources such as wind\\, sun and bio-fuels help you to leave the oil age. With modern technologies and intelligent machines you set out into the future.\n"..
"\n"..
"TA5: Future\n"..
"Machines to overcome space and time\\, new sources of energy and other achievements shape your life.\n"..
"\n"..
"Note: With a click on the plus sign you get into the sub-chapters of this manual.\n"..
"\n"..
"\n"..
"\n",
"This documentation is available both \"ingame\" (block construction plan) and on GitHub as MD files.\n"..
"\n"..
" - Link: https://github.com/joe7575/techage/wiki\n"..
"\n"..
"The construction plans (diagrams) for the construction of the machines and the pictures are only available in-game.\n"..
"\n"..
"With Tech Age you have to start over. You can only create TA2 blocks with the items from TA1\\, for TA3 you need the results from TA2\\, etc.\n"..
"\n"..
"In TA2\\, the machines only run with drive axes.\n"..
"\n"..
"From TA3\\, the machines run on electricity and have a communication interface for remote control.\n"..
"\n"..
"TA4 adds more power sources\\, but also higher logistical challenges (power lines\\, item transport).\n"..
"\n",
"From V1.0 (07/17/2021) the following has changed:\n"..
"\n"..
" - The algorithm for calculating the power distribution has changed. This makes energy storage systems more important. These compensate for fluctuations\\, which is important in larger networks with several generators.\n"..
" - For this reason TA2 got its own energy storage.\n"..
" - The battery blocks from TA3 also serve as energy storage. Their functionality has been adapted accordingly.\n"..
" - The TA4 storage system has been revised. The heat heat exchanger have been given a new number because the functionality has been moved from the lower to the middle block. If these were remotely controlled\\, the node number must be adapted. The generators no longer have their own menu\\, but are only switched on / off via the heat exchanger. The heat exchanger and generator must now be connected to the same network!\n"..
" - Several power grids can now be coupled via a TA4 transformer blocks.\n"..
" - A TA4 electricity meter block for sub-networks is also new.\n"..
" - At least one battery block or a storage system in each network\n"..
"\n",
"Many more blocks have received minor changes. It is therefore possible that machines or systems do not start up again immediately after the changeover. In the event of malfunctions\\, the following tips will help:\n"..
"\n"..
" - Switch machines off and on again\n"..
" - remove a power cable block and put it back in place\n"..
" - remove the block completely and put it back in place\n"..
"\n",
"Techage adds some new items to the game:\n"..
"\n"..
" - Meridium - an alloy for the production of luminous tools in TA1\n"..
" - Usmium - an ore that is mined in TA2 and needed for TA3\n"..
" - Baborium - a metal that is needed for recipes in TA3\n"..
" - Petroleum - is needed in TA3\n"..
" - Bauxite - an aluminum ore that is needed in TA4 to produce aluminum\n"..
" - Basalt - arises when water and lave touch\n"..
"\n",
"Meridium is an alloy of steel and mesecons crystals. Meridium ingots can be made with the coal burner from steel and mesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.\n"..
"\n"..
"\n"..
"\n",
"Usmium only occurs as nuggets and can only be obtained by washing gravel with the TA2/TA3 gravel washing system.\n"..
"\n"..
"\n"..
"\n",
"Barborium can only be obtained from underground mining. This substance can only be found at a depth of -250 to -340 meters.\n"..
"\n"..
"Baborium can only be melted in the TA3 Industrial Furnace.\n"..
"\n"..
"\n"..
"\n",
"Petroleum can only be found with the help of the Explorer and extracted with the help of appropriate TA3 machines. See TA3.\n"..
"\n"..
"\n"..
"\n",
"Bauxite is only extracted in underground mining. Bauxite is only found in stone at a height between -50 and -500 meters.\n"..
"It is required for the production of aluminum\\, which is mainly used in TA4.\n"..
"\n"..
"\n"..
"\n",
"Basalt is only created when lava and water come together.\n"..
"The best thing to do is to set up a system where a lava and a water source flow together.\n"..
"Basalt is formed where both liquids meet.\n"..
"You can build an automated basalt generator with the Sign Bot.\n"..
"\n"..
"\n"..
"\n",
" - 28.09.2019: Solar system added\n"..
" - 05.10.2019: Data on the solar system and description of the inverter and the power terminal changed\n"..
" - 18.11.2019: Chapter for ores\\, reactor\\, aluminum\\, silo\\, bauxite\\, furnace heating\\, gravel washing system added\n"..
" - 22.02.2020: corrections and chapters on the update\n"..
" - 29.02.2020: ICTA controller added and further corrections\n"..
" - 14.03.2020 Lua controller added and further corrections\n"..
" - 22.03.2020 More TA4 blocks added\n"..
"\n",
},
images = {
"techage_ta4",
"",
"",
"",
"",
"meridium",
"usmium",
"baborium",
"oil",
"bauxite",
"basalt",
"",
},
plans = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

View File

@ -1,144 +0,0 @@
return {
titles = {
"1,Tech Age Mod",
"2,Подсказки",
"2,Изменения по сравнению с версией 1.0",
"3,Советы по переключению",
"2,Руды и минералы",
"3,Меридий",
"3,Усмий",
"3,Баборий",
"3,Нефть",
"3,Боксит",
"3,Базальт",
"2,History",
},
texts = {
"Tech Age - это технологический мод с 5 стадиями развития:\n"..
"\n"..
"TA1: Железный век\n"..
"Используйте инструменты и приспособления\\, такие как угольные горелки\\, угольные горелки\\, гравийные сита\\, молоты и бункеры\\, чтобы добывать и обрабатывать необходимые руды и металлы.\n"..
"\n"..
"TA2: Паровой век\n"..
"Постройте паровой двигатель с ведущими осями и используйте его для работы своих первых машин по переработке руды.\n"..
"\n"..
"TA3: Нефтяной век\n"..
"Найдите и добывайте нефть\\, постройте железные дороги для транспортировки нефти. Электростанция дает необходимое электричество для ваших машин. Электрический свет освещает ваши промышленные предприятия.\n"..
"\n"..
"TA4: Настоящее время\n"..
"Возобновляемые источники энергии\\, такие как ветер\\, солнце и биотопливо\\, помогают вам покинуть нефтяной век. С помощью современных технологий и умных машин вы отправляетесь в будущее.\n"..
"\n"..
"TA5: Будущее\n"..
"Машины\\, преодолевающие пространство и время\\, новые источники энергии и другие достижения определяют вашу жизнь.\n"..
"\n"..
"Примечание: Нажав на знак \"плюс\"\\, вы попадаете в подразделы этого руководства.\n"..
"\n"..
"\n"..
"\n",
"Эта документация доступна как \"в игре\" (план строительства блоков)\\, так и на GitHub в виде MD-файлов.\n"..
"\n"..
" - Ссылка: https://github.com/joe7575/techage/wiki\n"..
"\n"..
"Строительные планы (схемы) для постройки машин и картинки доступны только в игре.\n"..
"\n"..
"В Tech Age вам придется начинать все сначала. Вы можете создавать блоки TA2 только с помощью предметов из TA1\\, для TA3 вам нужны результаты из TA2 и т.д.\n"..
"\n"..
"В TA2 машины работают только с приводными осями.\n"..
"\n"..
"В TA3 машины работают от электричества и имеют коммуникационный интерфейс для дистанционного управления.\n"..
"\n"..
"TA4 добавляет больше источников энергии\\, но также и более сложные логистические задачи (линии электропередач\\, транспортировка изделий).\n"..
"\n",
"С версии 1.0 (07/17/2021) изменилось следующее:\n"..
"\n"..
" - Изменился алгоритм расчета распределения энергии. Это делает системы хранения энергии более важными. Они компенсируют колебания\\, что важно для больших сетей с несколькими генераторами.\n"..
" - По этой причине TA2 обзавелась собственным накопителем энергии.\n"..
" - Аккумуляторные блоки из TA3 также служат в качестве накопителей энергии. Их функциональность была соответствующим образом адаптирована.\n"..
" - Система хранения TA4 была пересмотрена. Теплообменник получил новый номер\\, поскольку его функциональность была перенесена с нижнего на средний блок. Если они управлялись дистанционно\\, номер узла должен быть адаптирован. Генераторы больше не имеют собственного меню\\, а включаются/выключаются только через теплообменник. Теплообменник и генератор теперь должны быть подключены к одной сети!\n"..
" - Несколько электросетей теперь могут быть соединены через трансформаторные блоки TA4.\n"..
" - Также появился блок счетчиков электроэнергии TA4 для подсетей.\n"..
" - Как минимум один блок аккумуляторов или система хранения в каждой сети\n"..
"\n",
"Многие другие блоки получили незначительные изменения. Поэтому возможно\\, что машины или системы не будут запускаться сразу после переключения. В случае неполадок помогут следующие советы:\n"..
"\n"..
" - выключите и снова включите машины\n"..
" - снимите блок силовых кабелей и установите его на место\n"..
" - полностью снимите блок и установите его на место\n"..
"\n",
"Techage добавляет в игру несколько новых предметов:\n"..
"\n"..
" - Меридий - сплав для производства светящихся инструментов в TA1\n"..
" - Усмий - руда\\, которая добывается в TA2 и необходима для TA3\n"..
" - Бабориум - металл\\, необходимый для рецептов в TA3\n"..
" - Нефть - необходима в TA3\n"..
" - Боксит - алюминиевая руда\\, которая необходима в TA4 для производства алюминия\n"..
" - Базальт - возникает при соприкосновении воды и лав\n"..
"\n",
"Меридий - это сплав стали и кристаллов мезекона. Слитки меридиума можно изготовить с помощью угольной горелки из стали и кристаллов мезекона. Меридий светится в темноте. Инструменты из меридиума также светятся и поэтому очень полезны при подземной добыче.\n"..
"\n"..
"\n"..
"\n",
"Усмий встречается только в виде самородков и может быть получен только при промывке гравия с помощью системы промывки гравия TA2/TA3.\n"..
"\n"..
"\n"..
"\n",
"Барборий можно получить только при подземной добыче. Это вещество можно найти только на глубине от -250 до -340 метров.\n"..
"\n"..
"Бабориум можно переплавить только в промышленной печи TA3.\n"..
"\n"..
"\n"..
"\n",
"Нефть можно найти только с помощью Исследователя и добыть с помощью соответствующих машин TA3. См. TA3.\n"..
"\n"..
"\n"..
"\n",
"Боксит можно добыть только в подземной шахте. Боксит можно найти только в камне на высоте от -50 до -500 метров.\n"..
"Он необходим для производства алюминия\\, который в основном используется в TA4.\n"..
"\n"..
"\n"..
"\n",
"Базальт образуется только при соединении лавы и воды.\n"..
"Лучше всего создать систему\\, в которой лава и вода будут течь вместе.\n"..
"Базальт образуется там\\, где встречаются обе жидкости.\n"..
"Вы можете создать автоматический генератор базальта с помощью Sign Bot.\n"..
"\n"..
"\n"..
"\n",
" - 28.09.2019: Solar system added\n"..
" - 05.10.2019: Data on the solar system and description of the inverter and the power terminal changed\n"..
" - 18.11.2019: Chapter for ores\\, reactor\\, aluminum\\, silo\\, bauxite\\, furnace heating\\, gravel washing system added\n"..
" - 22.02.2020: corrections and chapters on the update\n"..
" - 29.02.2020: ICTA controller added and further corrections\n"..
" - 14.03.2020 Lua controller added and further corrections\n"..
" - 22.03.2020 More TA4 blocks added\n"..
"\n",
},
images = {
"techage_ta4",
"",
"",
"",
"",
"meridium",
"usmium",
"baborium",
"oil",
"bauxite",
"basalt",
"",
},
plans = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

View File

@ -1,152 +0,0 @@
return {
titles = {
"1,Mod Tech Age",
"2,TA1: Idade do Ferro",
"2,TA2: Idade do Vapor",
"2,TA3: Idade do Petróleo",
"2,TA4: Tempos atuais (Presente)",
"2,TA5: Futuro",
"1,Dicas",
"1,Mudanças a partir da versão 1.0",
"2,Dicas sobre a troca",
"1,Minérios e Minerais",
"2,Meridium",
"2,Usmium",
"2,Baborium",
"2,Petróleo",
"2,Bauxita",
"2,Basalto",
"2,History",
},
texts = {
"O Tech Age é um mod de tecnologia com 5 estágios de desenvolvimento:\n"..
"\n",
"Utilize ferramentas e instrumentos auxiliares como queimadores de carvão\\, peneiras de cascalho\\, martelos e funis para extrair e processar minérios e metais necessários.\n"..
"\n",
"Construa uma máquina a vapor com eixos de transmissão e use-a para operar suas primeiras máquinas de processamento de minérios.\n"..
"\n",
"Encontre e extraia óleo\\, construa ferrovias para transporte de óleo. Uma usina fornece a eletricidade necessária para suas máquinas. A luz elétrica ilumina suas instalações industriais.\n"..
"\n",
"Fontes de energia renovável\\, como vento\\, sol e biocombustíveis\\, ajudam você a sair da era do petróleo. Com tecnologias modernas e máquinas inteligentes\\, você parte para o futuro.\n"..
"\n",
"Máquinas para superar espaço e tempo\\, novas fontes de energia e outras conquistas moldam sua vida.\n"..
"\n"..
"Nota: Clicando no sinal de adição\\, você acessa os subcapítulos deste manual.\n"..
"\n"..
"\n"..
"\n",
"Esta documentação está disponível tanto \"dentro do jogo\" (plano de construção de blocos) quanto no GitHub como arquivos MD.\n"..
"\n"..
" - Link: https://github.com/joe7575/techage/wiki\nOs planos de construção (diagramas) para a construção das máquinas e as imagens estão disponíveis apenas no jogo.\n"..
"\n"..
"Com o Tech Age\\, você precisa começar do zero. Você só pode criar blocos TA2 com os itens do TA1\\, para o TA3 você precisa dos resultados do TA2\\, e assim por diante.\n"..
"\n"..
"No TA2\\, as máquinas só funcionam com eixos de transmissão.\n"..
"\n"..
"A partir do TA3\\, as máquinas funcionam com eletricidade e têm uma interface de comunicação para controle remoto.\n"..
"\n"..
"O TA4 adiciona mais fontes de energia\\, mas também desafios logísticos mais altos (linhas de energia\\, transporte de itens).\n"..
"\n",
"A partir da V1.0 (17/07/2021)\\, as seguintes alterações foram feitas:\n"..
"\n"..
" - O algoritmo para calcular a distribuição de energia foi alterado. Isso torna os sistemas de armazenamento de energia mais importantes. Eles compensam as flutuações\\, o que é importante em redes maiores com vários geradores.\n"..
" - Por esse motivo\\, o TA2 recebeu seu próprio sistema de armazenamento de energia.\n"..
" - Os blocos de bateria do TA3 também servem como armazenamento de energia. Sua funcionalidade foi adaptada de acordo.\n"..
" - O sistema de armazenamento do TA4 foi revisado. O permutador de calor recebeu um novo número porque a funcionalidade foi movida do bloco inferior para o bloco central. Se eles estiverem sendo controlados remotamente\\, o número do nó deve ser adaptado. Os geradores não têm mais um menu próprio\\, mas são ligados/desligados apenas através do permutador de calor. O permutador de calor e o gerador agora devem estar conectados à mesma rede!\n"..
" - Vários sistemas de energia podem agora ser acoplados via blocos transformadores TA4.\n"..
" - Um novo bloco medidor de eletricidade TA4 para sub-redes também foi adicionado.\n"..
" - Pelo menos um bloco de bateria ou um sistema de armazenamento em cada rede.\n"..
"\n",
"Muitos outros blocos receberam alterações menores. Portanto\\, é possível que máquinas ou sistemas não reiniciem imediatamente após a troca. Em caso de falhas\\, as seguintes dicas ajudarão:\n"..
"\n"..
" - Desligue e ligue as máquinas novamente.\n"..
" - Remova um bloco de cabo de energia e coloque-o de volta no lugar.\n"..
" - Remova completamente o bloco e coloque-o de volta no lugar.\n"..
"\n",
"Techage adiciona novos itens ao jogo:\n"..
"\n"..
" - Meridium - uma liga para a produção de ferramentas luminosas no TA1\n"..
" - Usmium - um minério que é extraído no TA2 e necessário para o TA3\n"..
" - Baborium - um metal necessário para receitas no TA3\n"..
" - Petróleo - necessário no TA3\n"..
" - Bauxita - um minério de alumínio necessário no TA4 para produzir alumínio\n"..
" - Basalto - surge quando água e lava se encontram\n"..
"\n",
"O Meridium é uma liga de aço e cristais de mesecons. Lingotes de Meridium podem ser feitos com a caldeira a carvão a partir de aço e cristais de mesecons. O Meridium brilha no escuro. Ferramentas feitas de Meridium também emitem luz e são\\, portanto\\, muito úteis na mineração subterrânea.\n"..
"\n"..
"\n"..
"\n",
"O Usmium ocorre apenas como pepitas e só pode ser obtido lavando cascalho com o sistema de lavagem de cascalho TA2/TA3.\n"..
"\n"..
"\n"..
"\n",
"O Baborium só pode ser obtido através da mineração subterrânea. Essa substância só pode ser encontrada a uma profundidade de -250 a -340 metros.\n"..
"\n"..
"O Baborium só pode ser derretido na Fornalha Industrial TA3.\n"..
"\n"..
"\n"..
"\n",
"O Petróleo só pode ser encontrado com a ajuda do Explorer e extraído com a ajuda de máquinas apropriadas do TA3. Veja TA3.\n"..
"\n"..
"\n"..
"\n",
"A Bauxita é extraída apenas na mineração subterrânea. A Bauxita só é encontrada na pedra a uma altura entre -50 e -500 metros.\n"..
"É necessária para a produção de alumínio\\, que é principalmente usada no TA4.\n"..
"\n"..
"\n"..
"\n",
"O Basalto só é criado quando lava e água se encontram.\n"..
"A melhor coisa a fazer é montar um sistema onde uma fonte de lava e uma fonte de água se encontram.\n"..
"O Basalto é formado onde ambos os líquidos se encontram.\n"..
"Você pode construir um gerador automático de basalto com o Sign Bot.\n"..
"\n"..
"\n"..
"\n",
" - 28.09.2019: Solar system added\n"..
" - 05.10.2019: Data on the solar system and description of the inverter and the power terminal changed\n"..
" - 18.11.2019: Chapter for ores\\, reactor\\, aluminum\\, silo\\, bauxite\\, furnace heating\\, gravel washing system added\n"..
" - 22.02.2020: corrections and chapters on the update\n"..
" - 29.02.2020: ICTA controller added and further corrections\n"..
" - 14.03.2020 Lua controller added and further corrections\n"..
" - 22.03.2020 More TA4 blocks added\n"..
"\n",
},
images = {
"",
"",
"",
"",
"",
"techage_ta4",
"",
"",
"",
"",
"meridium",
"usmium",
"baborium",
"oil",
"bauxite",
"basalt",
"",
},
plans = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

View File

@ -1,172 +0,0 @@
return {
titles = {
"1,TA1: Eisenzeitalter",
"2,Köhler / Coal Pile",
"2,Kohlebrenner / Coal Burner",
"2,Wassermühle",
"3,TA1 Mühle",
"3,TA1 Schleusenschieber / TA1 Sluice Gate",
"3,TA1 Schleusengriff / TA1 Sluice Handle",
"3,TA1 Apfelholzbrett / TA1 Apple Wood Board",
"3,TA1 Apfel Mühlbachbrett / TA1 Apple Millrace Board",
"2,Erze und Werkzeuge",
"3,Hammer",
"3,Kiessieb / Gravel Sieve",
"3,Trichter / Hopper",
"3,Kies sieben mit dem Trichter",
"3,Meridium",
},
texts = {
"In TA1 geht es darum\\, mit einfachen Werkzeugen und Gerätschaften ausreichend Erze zu schürfen und Holzkohle herzustellen\\, so dass damit TA2 Maschinen hergestellt und betrieben werden können.\n"..
"\n"..
"Natürlich muss es für ein Eisenzeitalter auch Eisen geben und nicht nur Stahl (steel)\\, wie in \"Minetest Game\". Daher wurden einige Rezepte geändert\\, so dass zuerst Eisen hergestellt werden muss und erst später dann Stahl.\n"..
"\n"..
"Auch ist die Haltbarkeit der Werkzeuge an die Zeitalter angelehnt und entspricht damit nicht dem Minetest Originalspiel.\n"..
"Die Haltbarkeit/Härte bspw. für eine Axt ist:\n"..
"\n"..
" - Bronze: 20\n"..
" - Stahl: 30\n"..
"\n"..
"\n"..
"\n",
"Den Köhler brauchst du\\, um Holzkohle herzustellen. Holzkohle wird für den Brenner\\, aber auch bspw. in TA2 für die Dampfmaschine benötigt.\n"..
"\n"..
"Für den Köhler brauchst du:\n"..
"\n"..
" - einen Anzünderblock ('techage:lighter')\n"..
" - 26 Hölzblöcke (wood)\\, die zu einem Würfen aufgeschichtet werden. Die Holzsorte spielt keine Rolle.\n"..
" - Erde (dirt) um den Holzhaufen abzudecken.\n"..
" - Feuerstein und Eisen (technischer Name: 'fire:flint_and_steel') um den Anzünderblock anzuzünden.\n"..
"\n"..
"Bauanleitung (siehe auch Plan):\n"..
"\n"..
" - Baue eine 5x5 große Fläche aus Erde (dirt)\n"..
" - Platziere in die Mitte einen Anzünder (lighter)\n"..
" - Platziere rund um den Anzünder 7 Holz (wood)\\, aber lasse ein Loch zum Anzünder frei\n"..
" - Baue weitere 2 Schichten Holz darüber\\, so dass ein 3x3x3 großer Holzwürfel entsteht\n"..
" - Überdecke alles mit einer Schicht Erde zu einem 5x5x5 großen Würfel\\, aber lasse das Loch zum Anzünder frei\n"..
" - Entzünde den Anzünder und verschließe das Loch sofort mit jeweils einem Block Holz und Erde\n"..
" - Wenn du alles richtig gemacht hast\\, fängt der Köhler nach wenigen Sekunden an zu rauchen\n"..
" - Öffne den Köhler erst\\, wenn der Rauch verschwunden ist (ca. 20 min)\n"..
"\n"..
"Dann kannst du die 9 Holzkohleblöcke entnehmen und den Köhler erneut füllen.\n"..
"\n"..
"\n"..
"\n",
"Den Kohlebrenner benötigst du bspw. um Eisen und andere Erze im Schmelztiegel zu schmelzen. Es gibt verschiedene Rezepte\\, welche verschiedene Temperaturen benötigen. Je höher der Turm\\, um so heißer ist die Flamme. Eine Höhe von 11 Blöcken über der Bodenplatte ist für alle Rezepte ausreichend\\, ein Brenner mit dieser Höhe verbraucht aber auch mehr Holzkohle.\n"..
"\n"..
"Bauanleitung (siehe auch Plan):\n"..
"\n"..
" - Baue einen Turm aus Stein (cobble) mit einer 3x3 Grundfläche (7-11 Blöcke hoch)\n"..
" - Lasse unten ein Loch an einer Seite offen\n"..
" - Lege einen Anzünder (lighter) hinein\n"..
" - Fülle den Turm bis zum Rand mit Holzkohle\\, in dem du die Holzkohle von oben in das Loch fallen lässt\n"..
" - Entzünde den Anzünder durch das Loch\n"..
" - Platziere den Schmelztiegel oben auf dem Turm direkt in die Flamme\\, einen Block über dem Turmrand\n"..
" - Um den Brenner anzuhalten\\, schließe das Loch vorübergehend bspw. mit einem Erdblock.\n"..
"\n"..
"Der Schmelztiegel hat ein eigenes Menü mit Rezepten und ein Inventar\\, wo du die Erze hinein legst.\n"..
"\n"..
"\n"..
"\n",
"Mit der Wassermühle können Weizen und andere Getreide zu Mehl gemahlen und dann im Ofen zu Brot gebacken werden. Die Mühle wird mit\n"..
"Wasserkraft angetrieben. Dazu muss ein Mühlbach über einen Kanal zum Mühlrad geführt werden.\n"..
"Über eine Schleuse kann der Wasserfluss und damit das Mühlrad gesteuert werden.\n"..
"Die Schleuse besteht aus Schleusenschieber und Schleusengriff.\n"..
"\n"..
"Die Abbildung rechts (auf \"Plan\" klicken) zeigt den Aufbau der Wassermühle.\n"..
"\n"..
"\n"..
"\n",
"Mit der Wassermühle können Weizen und andere Getreide zu Mehl gemahlen und dann im Ofen zu Brot gebacken werden.\n"..
"Die Mühle muss mit einer TA1 Achse mit dem Mühlrad verbunden werden. Die Kraft des Mühlrades reicht nur für eine Mühle.\n"..
"\n"..
"Die Mühle kann mit Hilfe eines Minecart Hoppers automatisiert werden\\, so dass das Mehl bspw. direkt von der Mühle in einen Ofen befördert wird\\, um daraus Brot zu backen.\n"..
"\n"..
"\n"..
"\n",
"Der Schleusenschieber muss auf gleicher Höhe wie die Wasseroberfläche direkt an einen Teich oder in einen Bach gesetzt werden.\n"..
"Wird die Schleuse geöffnet\\, so fließt Wasser durch den Schieber. Dieses Wasser muss dann zum Mühlrad geleitet werden und treibt dort die Mühle an.\n"..
"\n"..
"\n"..
"\n",
"Der TA1 Schleusengriff muss auf den Schleusenschieber gesetzt werden. Mit Hilfe des Schleusengriffs (Rechtsklick) kann der Schieber geöffnet werden.\n"..
"\n"..
"\n"..
"\n",
"Block in verschiedenen Holzsorten zum Bauen des Mühlbachkanals. Es kann aber auch jedes andere Material verwendet werden.\n"..
"\n"..
"\n"..
"\n",
"Block in verschiedenen Holzsorten zum Bauen des Mühlbachkanals. Dieser Block eignet sich speziell in Verbindung mit den Pfosten des Holzzauns um eine Stütze für den Kanal zu bauen.\n"..
"\n"..
"\n"..
"\n",
"TA1 hat seine eigenen Werkzeuge wie Hammer und Kiessieb\\, aber auch der Minecart Hopper kann genutzt werden.\n"..
"\n"..
"\n"..
"\n",
"Mit dem TA1 Hammer können Steine (stone) und Kopfsteinpflaster-Steine (cobble) zu Kies (gravel) zertrümmert werden. Der Hammer ist in verschiedenen Ausführungen und damit verschiedenen Eigenschaften verfügbar: Bronze\\, Stahl\\, Mese und Diamant.\n"..
"\n"..
"\n"..
"\n",
"Mit dem Kiessieb können Erze aus dem Kies gesiebt werden. Dazu mit dem Kies (gravel) auf das Sieb klicken. Der gesiebte Kies und die Erze fallen unten heraus.\n"..
"\n"..
"Um hier nicht stundenlang am Sieb zu stehen\\, kann das Sieben mit dem Trichter (hopper) automatisiert werden.\n"..
"\n"..
"\n"..
"\n",
"Der Hopper aus der Mod \"Minecart\" dient in erster Linie zum Be- und Entladen von Minecarts. Er saugt Gegenstände (items) von oben ein und gibt diese nach rechts weiter. Beim Platzieren des Trichters muss daher auf die Ausgaberichtung geachtet werden.\n"..
"\n"..
"Der Trichter kann aber auch Items aus Kisten (chest) ziehen\\, sofern die Kiste neben oder auf dem Trichter steht. \n"..
"\n"..
"Der Trichter kann auch Items in Kisten legen\\, sofern die Kiste neben dem Trichter steht.\n"..
"\n"..
"\n"..
"\n",
"Mit Hilfe von zwei Kisten\\, zwei Trichtern und einem Kiessieb kann der Siebevorgang automatisiert werden. Der Plan rechts zeigt den Aufbau.\n"..
"\n"..
"Bei den Kisten darauf achten\\, dass es die \"chest_locked\" ist\\, sonst klaut dir jemand die wertvollen Erze aus der Kiste unten.\n"..
"\n"..
"\n"..
"\n",
"TA1 hat seine eigene Metalllegierung Meridium. Meridium Ingots können mit dem Kohlebrenner aus Stahl und Mesesplittern hergestellt werden. Meridium leuchtet im Dunkeln. Auch Werkzeuge aus Meridium leuchten und sind daher im Untertagebau sehr hilfreich.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta1",
"",
"",
"",
"",
"ta1_sluice",
"ta1_sluice_handle",
"ta1_board1",
"ta1_board2",
"ta1_gravelsieve",
"hammer",
"ta1_gravelsieve",
"ta1_hopper",
"",
"meridium",
},
plans = {
"",
"coalpile",
"coalburner",
"watermill1",
"watermill2",
"",
"",
"",
"",
"",
"",
"",
"",
"hoppersieve",
"",
}
}

View File

@ -1,170 +0,0 @@
return {
titles = {
"1,TA1: Iron Age",
"2,Charcoal Pile (charcoal burner)",
"2,Melting Furnace",
"2,Watermill",
"3,TA1 mill",
"3,TA1 sluice gate",
"3,TA1 sluice handle",
"3,TA1 Apple Wood Board",
"3,TA1 Apple Millrace Board",
"2,Ores and Tools",
"3,Hammer",
"3,Gravel Sieve",
"3,Hopper",
"3,Gravel seven with the hopper",
"3,Meridium",
},
texts = {
"TA1 is about mining sufficient ores and producing charcoal with simple tools and equipment\\, so that TA2 machines can be manufactured and operated.\n"..
"\n"..
"Of course\\, for an iron age there must also be iron and not just steel\\, as in \"Minetest Game\". As a result\\, some recipes have been changed so that iron has to be produced first and then steel later.\n"..
"\n"..
"The durability of the tools is based on the ages and therefore does not correspond to the original Minetest game.\n"..
"The durability / hardness for an axe\\, for example:\n"..
"\n"..
" - Bronze: 20\n"..
" - Steel: 30\n"..
"\n"..
"\n"..
"\n",
"You need the Charcoal Pile to make charcoal. Charcoal is required for the melting furnace\\, but also\\, for example\\, in TA2 for the steam engine.\n"..
"\n"..
"For the charcoal burner you need:\n"..
"\n"..
" - a lighter block ('techage:lighter')\n"..
" - 26 wooden blocks that are stacked into a pile of wood. The type of wood is irrelevant\n"..
" - Dirt to cover the pile of wood\n"..
" - Flint and Iron (technical name: 'fire:flint_and_steel') to light the lighter block\n"..
"\n"..
"Building instructions (see also plan):\n"..
"\n"..
" - Build a 5x5 area of dirt\n"..
" - Place 7 wood around the lighter but leave a hole to the lighter\n"..
" - Build another 2 layers of wood on top\\, making a 3x3x3 wooden cube\n"..
" - Cover everything with a layer of dirt into a 5x5x5 cube\\, but keep the hole to the lighter open\n"..
" - Light the lighter and immediately close the hole with a block of wood and dirt\n"..
" - If you have done everything correctly\\, the coal burner will start smoking after a few seconds\n"..
" - Only open the charcoal burner when the smoke has disappeared (approx. 20 min)\n"..
"\n"..
"Then you can remove the 9 charcoal blocks and refill the Charcoal Pile.\n"..
"\n"..
"\n"..
"\n",
"You need the melting furnace\\, for example\\, to melt iron and other ores in the melting pot. There are different recipes that require different temperatures. The higher the melting tower\\, the hotter the flame. A height of 11 blocks above the base plate is for all recipes\\, but a burner with this height also requires more charcoal.\n"..
"\n"..
"Building instructions (see also plan):\n"..
"\n"..
" - Build a stone tower (cobble) with a 3x3 base (7-11 blocks high)\n"..
" - Leave a hole open on one side at the bottom\n"..
" - Put a lighter in it\n"..
" - Fill the tower to the brim with charcoal by dropping the charcoal into the hole from above\n"..
" - Light the lighter through the hole\n"..
" - Place the melting pot on top of the tower directly into the flame\\, one block above the tower edge\n"..
" - To stop the burner\\, temporarily close the hole with an dirt block\\, for example.\n"..
"\n"..
"The melting pot has its own menu of recipes and an inventory where you have to put the ores in.\n"..
"\n"..
"\n"..
"\n",
"The watermill can be used to grind wheat and other grains into flour and then bake them in the furnace to make bread. \n"..
"The mill is powered by water power. To do this\\, a millrace must be led to the mill wheel via a canal.\n"..
"The water flow and thus the mill wheel can be controlled via a sluice. The sluice consists of the sluice lock and sluice handle.\n"..
"\n"..
"The picture on the right (click on \"Plan\") shows the structure of the watermill. \n"..
"\n"..
"\n"..
"\n",
"The watermill can be used to grind wheat and other grains into flour and then bake them in the oven to make bread. The mill must be connected to the mill wheel with a TA1 axle. The power of the mill wheel is only enough for one mill.\n"..
"\n"..
"The mill can be automated with the help of a Minecart Hopper\\, so that the flour\\, for example\\, is transported directly from the mill into an furnace in order to bake bread from it.\n"..
"\n"..
"\n"..
"\n",
"The sluice gate valve must be placed directly next to a pond or in a stream at the same height as the water surface.\n"..
"When the gate is opened\\, water flows through the slide. This water then has to be fed to the mill wheel\\, where it drives the mill.\n"..
"\n"..
"\n"..
"\n",
"The TA1 sluice handle must be placed on the sluice gate. The gate can be opened with the aid of the sluice handle (right click).\n"..
"\n"..
"\n"..
"\n",
"Block in different types of wood for building the millrace canal. However\\, any other material can also be used.\n"..
"\n"..
"\n"..
"\n",
"Block in different types of wood for building the millrace canal. This block is especially suitable in connection\n"..
"with posts of the wooden fence to build a support of the canal.\n"..
"\n"..
"\n"..
"\n",
"TA1 has its own tools such as hammer and gravel sieve\\, but the Minecart Hopper can also be used.\n"..
"\n"..
"\n"..
"\n",
"The TA1 hammer can be used to knock/dig stone in a mine\\, but also to smash cobble to gravel. The hammer is available in different versions and therefore different properties: bronze\\, steel\\, brass and diamond.\n"..
"\n"..
"\n"..
"\n",
"Ores can be sifted from the gravel with the gravel sieve. To do this\\, click on the sieve with the gravel. The sifted gravel and ores fall out below.\n"..
"\n"..
"In order not to stand at the sieve for hours\\, sieving can be automated with the hopper.\n"..
"\n"..
"\n"..
"\n",
"The hopper from the \"Minecart\" mod is primarily used for loading and unloading Minecarts. He sucks in items from above and passes them on to the right. Therefore\\, when placing the hopper\\, pay attention to the direction of dispensing.\n"..
"\n"..
"The hopper can also pull items from boxes (chest)\\, provided the box is next to or on the hopper.\n"..
"\n"..
"The hopper can also put items in boxes if the box is next to the hopper.\n"..
"\n"..
"\n"..
"\n",
"With the help of two boxes\\, two hoppers and a gravel sieve\\, the sieving process can be automated. The plan on the right shows the structure.\n"..
"\n"..
"Make sure that the boxes are \"chest_locked\"\\, otherwise someone will steal the valuable ores from the box below.\n"..
"\n"..
"\n"..
"\n",
"TA1 has its own metal alloy meridium. Meridium ingots can be made with the coal burner from steel and mesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta1",
"",
"",
"",
"",
"ta1_sluice",
"ta1_sluice_handle",
"ta1_board1",
"ta1_board2",
"ta1_gravelsieve",
"hammer",
"ta1_gravelsieve",
"ta1_hopper",
"",
"meridium",
},
plans = {
"",
"coalpile",
"coalburner",
"watermill1",
"watermill2",
"",
"",
"",
"",
"",
"",
"",
"",
"hoppersieve",
"",
}
}

View File

@ -1,170 +0,0 @@
return {
titles = {
"1,TA1: Эпоха железа",
"2,Углевыжигательная куча (древесноугольная печь)",
"2,Плавильная печь",
"2,Водяная мельница",
"3,TA1 мельница",
"3,TA1 шлюзовой затвор",
"3,TA1 шлюзовой рычаг",
"3,TA1 яблоневая доска",
"3,TA1 яблоневая мельничная доска",
"2,Руды и инструменты",
"3,Молот",
"3,Гравийное сито",
"3,Хоппер",
"3,Просеивание гравия и хоппер",
"3,Меридий",
},
texts = {
"TA1 - про добычу необходимейших руд и изготовление древесного угля простейшими инструментами и оборудованием\\, чтобы ТА2 машины можно было построить и запустить.\n"..
"\n"..
"Конечно\\, для Эпохи железа потребуется также железо и не только сталь\\, как в ванильной \"Minetest Game\". В результате\\, некоторые рецепты были изменены, и теперь сперва нужно произвести железо, а сталь - позже.\n"..
"\n"..
"Долговечность инструментов зависит от эпохи и поэтому не соответствует оригинальной игре Майнтест.\n"..
"Долговечность / прочность топора\\, например:\n"..
"\n"..
" - Бронза: 20\n"..
" - Сталь: 30\n"..
"\n"..
"\n"..
"\n",
"Для изготовления древесного угля потребуется Углевыжигательная Куча. Древесный уголь используется в плавильной печи\\, но также\\, например\\, в TA2 для парового двигателя.\n"..
"\n"..
"Для жжения угля понадобится:\n"..
"\n"..
" - блок-поджигатель ('techage:lighter')\n"..
" - 26 деревянный блоков досок, составленных в кучу. Тип дерева не важен.\n"..
" - Земля для покрытия кучи дерева.\n"..
" - Огниво (техническое наименование: 'fire:flint_and_steel') чтобы зажечь блок-поджигатель\n"..
"\n"..
"Инструкция по строительству (см. также чертёж):\n"..
"\n"..
" - Соорудите площадку из земли 5х5\n"..
" - Поставьте 7 досок вокруг поджигателя но оставьте отверстие для доступа к поджигателю\n"..
" - Постройте ещё 2 слоя досок вверх\\, формируя деревянный куб 3х3х3\n"..
" - Покройте всё слоем земли, формируя земляной куб 5х5х5\\, но оставьте отверстие для доступа к поджигателю\n"..
" - Воспламените поджигатель и немедленно закройте отверстие блоком досок и блоком земли.\n"..
" - Если всё сделано верно\\, углесжигательная куча начнёт пускать дым вверх через несколько секунд\n"..
" - Вскрывайте кучу только тогда, когда дым исчезнет! (примерно 20 минут)\n"..
"\n"..
"Теперь можно забрать 9 блоков древесного угля и заполнить Кучу снова.\n"..
"\n"..
"\n"..
"\n",
"Плавильная печь понадобится\\, например\\, чтобы выплавлять железо и другие руды в плавильном тигеле. Для разных рецептов требуется разная температура. Чем выше плавильная башня\\, тем горячее пламя. Высота 11 блоков приемлема для всех рецептов\\, однако и потребляет больше всего древесного угля.\n"..
"\n"..
"Инструкция по строительству (см. также чертёж):\n"..
"\n"..
" - Соорудите каменную башню (булыжник) с основанием 3х3 высотой 7-11 блоков.\n"..
" - Оставьте отверстие внизу с одной стороны.\n"..
" - Поместите поджигатель в отверстие.\n"..
" - Заполните башню древесным углем до краёв, сбрасывая древесный уголь сверху в шахту.\n"..
" - Воспламените поджигатель через отверстие.\n"..
" - Установите плавильный тигель наверху башни\n(на один блок выше пламени)\n"..
" - Чтобы временно прервать горение\\, закройте отверстие блоком земли\\, например.\n"..
"\n"..
"У плавильного тигеля есть своё меню рецептов и инвентарь, куда помещать руды.\n"..
"\n"..
"\n"..
"\n",
"Мельница используется для перемалывания пшеницы и других зёрен в муку, затем муку испекают в печи для получения хлеба.\n"..
"Мельница крутится силой воды. Для этого\\, к мельнице нужно подвести водный поток каналом.\n"..
"Поток воды и мельничное колесо можно контролировать шлюзом. Шлюз состоит из шлюзового замка и шлюзового рычага.\n"..
"\n"..
"Картинка справа (кликните на \"Plan\") иллюстрирует устройство мельницы. \n"..
"\n"..
"\n"..
"\n",
"Мельница используется для перемалывания пшеницы и других зёрен в муку, затем муку испекают в печи для получения хлеба. Мельница должна быть соединена с мельничным колесом посредством ТА1 оси. Мощности мельничного колеса хватает только для одной мельницы.\n"..
"\n"..
"Автоматизировать мельницу можно Железнодорожным хоппером\\, так что мука\\, например\\, будет перевозиться от мельницы до печи для дальнейшей выпечки.\n"..
"\n"..
"\n"..
"\n",
"Шлюзовой затвор нужно размещать непосредственно рядом с водоёмом или в потоке, на том же уровне что и поверхность воды.\n"..
"Когда шлюзовой затвор открыт\\, вода стекает вниз. Эта вода напирает на мельничное колесо.\\, и крутит мельницу.\n"..
"\n"..
"\n"..
"\n",
"TA1 шлюзовой рычаг размещается на шлюзовом затворе. Затвор можно открывать рычагом (правый клик).\n"..
"\n"..
"\n"..
"\n",
"Блок любого типа дерева для строительства мельничного водоканала. Впрочем\\, можно использовать любой другой материал.\n"..
"\n"..
"\n"..
"\n",
"Блок любого типа дерева для строительства мельничного водоканала. Этот блок оптимально подходит для соединения.\n"..
"со столбами деревянного забора, для строительства опор канала.\n"..
"\n"..
"\n"..
"\n",
"TA1 содержит собственные инструменты, такие как молот и гравийное сито\\, но также можно использовать Железнодорожный хоппер.\n"..
"\n"..
"\n"..
"\n",
"TA1 молот используется для разбивания/выкапывания камня\\, а также для раздробления булыжника в гравий. Молот доступен в разных исполнениях с разными свойствами: бронза\\, сталь\\, латунь и алмаз.\n"..
"\n"..
"\n"..
"\n",
"Руды можно высеивать из гравия через гравийное сито. Для этого\\, кликайте гравием на сито. Просеянный гравий и руды выпадут снизу.\n"..
"\n"..
"Чтобы не стоять возле сита часами\\, процесс можно автоматизировать хоппером.\n"..
"\n"..
"\n"..
"\n",
"Хоппер из мода \"Minecart\" (Вагонетка) задуман для погрузки-разгрузки вагонеток. Хоппер втягивает предметы сверху от себя и выгружает направо от себя. Так\\, располагая хоппер\\, обращайте внимание на направление выгрузки.\n"..
"\n"..
"Хоппер также может вытягивать предметы из коробок (сундуков)\\, при условии что коробка расположена рядом или над хоппером.\n"..
"\n"..
"Хоппер также может помещать предметы в коробки, при условии что коробка расположена рядом с хоппером.\n"..
"\n"..
"\n"..
"\n",
"С помощью двух коробок\\, двух хопперов и гравийного сита\\, процесс просеивания может быть автоматизирован. Чертёж справа иллюстрирует механизм.\n"..
"\n"..
"Убедитесь, что коробки \"chest_locked\"\\ (защищённые), иначе кто-нибудь похитит ценные руды из верхней коробки.\n"..
"\n"..
"\n"..
"\n",
"TA1 отркрывает собственный сплав - меридий. Меридиевые слитки изготавливаются в плавильном тигеле из стали и месекон кристаллов. Меридий светится в темноте. Меридиевые инструменты тоже светятся, становясь хорошей поддержкой в подземных раскопках.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta1",
"",
"",
"",
"",
"ta1_sluice",
"ta1_sluice_handle",
"ta1_board1",
"ta1_board2",
"ta1_gravelsieve",
"hammer",
"ta1_gravelsieve",
"ta1_hopper",
"",
"meridium",
},
plans = {
"",
"coalpile",
"coalburner",
"watermill1",
"watermill2",
"",
"",
"",
"",
"",
"",
"",
"",
"hoppersieve",
"",
}
}

View File

@ -1,153 +0,0 @@
return {
titles = {
"1,TA1: Idade do Ferro",
"2,Pilha de Carvão (queimador de carvão)",
"2,Forno de Fundição",
"2,Moinho d'Água",
"3,Moinho d'Água TA1",
"3,Comporta TA1",
"3,Alavanca de Comporta TA1",
"3,Placa de Madeira de Maçã TA1",
"3,Placa de Curso d'Água de Maçã TA1",
"1,Minérios e Ferramentas",
"2,Martelo",
"2,Peneira de Cascalho(Sieve)",
"2,Funil (Minecart Hopper)",
"2,Peneirando sete cascalhos com Funil",
},
texts = {
"TA1 trata da extração de minérios suficientes e da produção de carvão com ferramentas e equipamentos simples\\, para que as máquinas TA2 possam ser fabricadas e operadas.\n"..
"\n"..
"É claro que\\, para uma Idade do Ferro\\, deve haver ferro e não apenas aço\\, como em \"Minetest Game\". Como resultado\\, algumas receitas foram alteradas para que o ferro precise ser produzido primeiro e\\, posteriormente\\, o aço.\n"..
"\n"..
"A durabilidade das ferramentas é baseada nas eras e\\, portanto\\, não corresponde ao jogo original do Minetest.\n"..
"A durabilidade/dureza de um machado\\, por exemplo:\n"..
"\n"..
" - Bronze: 20\n"..
" - Aço: 30\n"..
"\n"..
"\n"..
"\n",
"Você precisa da Pilha de Carvão para fazer carvão. O carvão é necessário para a fundição\\, mas também\\, por exemplo\\, em TA2 para a máquina a vapor.\n"..
"\n"..
"Para o queimador de carvão\\, você precisa de:\n"..
"\n"..
" - Um bloco de acendedor ('techage:lighter')\n"..
" - 26 blocos de madeira empilhados para formar um monte de madeira. O tipo de madeira é irrelevante.\n"..
" - Terra para cobrir o monte de madeira\n"..
" - Pedra lascada e Ferro (nome técnico: 'fire:flint_and_steel') para acender o bloco de acendedor\n"..
"\n"..
"Instruções de construção (veja também o plano):\n"..
"\n"..
" - Construa uma área de 5x5 de terra\n"..
" - Coloque 7 blocos de madeira ao redor do acendedor\\, mas deixe um buraco para o acendedor\n"..
" - Construa mais 2 camadas de madeira em cima\\, formando um cubo de madeira 3x3x3\n"..
" - Cubra tudo com uma camada de terra formando um cubo de 5x5x5\\, mas mantenha o buraco para o acendedor aberto\n"..
" - Acenda utilizando o isqueiro e feche imediatamente o buraco com um bloco de madeira e terra\n"..
" - Se você fez tudo corretamente\\, o queimador de carvão começará a soltar fumaça após alguns segundos\n"..
" - Só abra o queimador de carvão quando a fumaça tiver desaparecido (aproximadamente 20 minutos)\n"..
" - Então você pode remover os 9 blocos de carvão e reabastecer a Pilha de Carvão.\n"..
"\n"..
"\n"..
"\n",
"Você precisa do forno de fundição\\, por exemplo\\, para fundir ferro e outros minérios no Vaso de fundição(cadinho). Existem receitas diferentes que requerem diferentes temperaturas. Quanto mais alto a torre de fusão\\, mais quente é a chama. Uma altura de 11 blocos acima da placa base é para todas as receitas\\, mas um queimador com essa altura também requer mais carvão.\n"..
"\n"..
"Instruções de construção (veja também o plano):\n"..
"\n"..
" - Construa uma torre de pedregulho (cobble) com uma base de 3x3 (7-11 blocos de altura)\n"..
" - Deixe um buraco aberto de um lado na parte inferior\n"..
" - Coloque um acendedor nele\n"..
" - Encha a torre até a borda com carvão despejando o carvão no buraco de cima para baixo\n"..
" - Acenda o acendedor através do buraco\n"..
" - Coloque o Vaso de fundição(cadinho) no topo da torre diretamente na chama\\, um bloco acima da borda da torre\n"..
" - Para parar o queimador\\, feche temporariamente o buraco com um bloco de terra\\, por exemplo.\n"..
" - O Vaso de fundição(cadinho) tem seu próprio menu de receitas e um inventário onde você precisa colocar os minérios.\n"..
"\n"..
"\n"..
"\n",
"O moinho d'água pode ser usado para moer trigo e outros grãos para fazer farinha e depois assá-los no forno para fazer pão.\n"..
"O moinho é alimentado por energia hidráulica. Para isso\\, um curso de água deve ser conduzido até a roda do moinho através de um canal.\n"..
"O fluxo de água e\\, portanto\\, a roda do moinho\\, podem ser controlados por meio de uma comporta. A comporta é composta pelo bloqueio de comporta e pela alavanca de comporta.\n"..
"\n"..
"A imagem à direita (clique em \"Plano\") mostra a estrutura do moinho d'água.\n"..
"\n"..
"\n"..
"\n",
"O moinho d'água pode ser usado para moer trigo e outros grãos para fazer farinha e depois assá-los no forno para fazer pão. O moinho deve ser conectado à roda do moinho com um eixo TA1. A potência da roda do moinho é apenas suficiente para um moinho.\n"..
"\n"..
"O moinho pode ser automatizado com a ajuda de um Funil(Minecart Hopper)\\, para que a farinha\\, por exemplo\\, seja transportada diretamente do moinho para um forno para assar pão.\n"..
"\n"..
"\n"..
"\n",
"A válvula de comporta deve ser colocada diretamente ao lado de um lago ou em um riacho na mesma altura que a superfície da água.\n"..
"Quando a comporta é aberta\\, a água flui através do canal. Essa água deve ser conduzida até a roda do moinho\\, onde movimenta o moinho.\n"..
"\n"..
"\n"..
"\n",
"A alavanca de comporta TA1 deve ser colocada na comporta. A comporta pode ser aberta com a ajuda da alavanca de comporta (clique com o botão direito).\n"..
"\n"..
"\n"..
"\n",
"Podem ser usados bloco de diferentes tipos de madeira para construir o canal do curso d'água. No entanto\\, qualquer outro material também pode ser usado.\n"..
"\n"..
"\n"..
"\n",
"Podem ser utilizados blocos em diferentes tipos de madeira para construir o canal do curso d'água. Este bloco é especialmente adequado em conexão com postes da cerca de madeira para construir um suporte do canal.\n"..
"\n"..
"\n"..
"\n",
"O TA1 possui suas próprias ferramentas\\, como martelo e peneira de cascalho\\, mas o Funil(Minecart Hopper) também pode ser utilizado.\n"..
"\n",
"O martelo TA1 pode ser utilizado para bater/escavar pedra em uma mina\\, mas também para quebrar pedregulho(cobble) em cascalho(gravel). O martelo está disponível em diferentes versões\\, cada uma com propriedades distintas: bronze\\, aço\\, latão e diamante.\n"..
"\n",
"Minérios podem ser peneirados do cascalho com a peneira de cascalho. Para fazer isso\\, clique na peneira com o cascalho. O cascalho peneirado e os minérios caem abaixo.\n"..
"\n"..
"Para não ficar horas na peneira\\, é possível automatizar o processo com o Funil(Minecart Hopper).\n"..
"\n",
"O funil do mod \"Minecart Hopper\" é utilizado principalmente para carregar e descarregar carrinhos de mineração. Ele suga itens de cima e os passa para a direita. Portanto\\, ao posicionar o funil\\, preste atenção na direção de dispensa.\n"..
"\n"..
"O funil também pode puxar itens de baús\\, desde que a caixa esteja ao lado ou em cima do funil.\n"..
"\n"..
"O funil também pode colocar itens em baús se a caixa estiver ao lado do funil.\n"..
"\n",
"Com a ajuda de dois baús\\, dois funis e uma peneira de cascalho\\, o processo de peneiração pode ser automatizado. O plano à direita mostra a estrutura.\n"..
"\n"..
"Certifique-se de que os baús são protegidos\\, caso contrário\\, alguém pode roubar os minérios valiosos do baú abaixo.\n"..
"\n"..
"Meridium\n"..
"O TA1 possui sua própria liga metálica\\, o Meridium. Lingotes de meridium podem ser feitos com a caldeira a carvão\\, utilizando aço e cristais de mesecons. O meridium brilha no escuro. Ferramentas feitas de meridium também emitem luz\\, sendo\\, portanto\\, muito úteis na mineração subterrânea.\n"..
"\n",
},
images = {
"techage_ta1",
"",
"",
"",
"",
"ta1_sluice",
"ta1_sluice_handle",
"ta1_board1",
"ta1_board2",
"",
"",
"",
"",
"",
},
plans = {
"",
"coalpile",
"coalburner",
"watermill1",
"watermill2",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

View File

@ -1,308 +0,0 @@
return {
titles = {
"1,TA2: Dampfzeitalter",
"2,Dampfmaschine",
"3,TA2 Feuerbox / Firebox",
"3,TA2 Boiler",
"3,TA2 Zylinder /Cylinder",
"3,TA2 Schwungrad / Flywheel",
"3,TA2 Dampfleitungen / Steam Pipe",
"3,TA2 Antriebsachsen / TA2 Drive Axle",
"3,TA2 Stromgenerator / TA2 Power Generator",
"2,TA2 Energiespeicher",
"3,TA2 Seilwinde / TA2 Winch",
"3,TA2 Gewichtekiste / TA2 Weight Chest",
"3,TA2 Kupplung / TA2 Clutch",
"2,Items schieben und sortieren",
"3,Röhren / TechAge Tube",
"3,Röhren Konzentrator / Tube Concentrator",
"3,TA2 Schieber / Pusher",
"3,TA2 Verteiler / Distributor",
"2,Kieswaschanlage",
"3,TA2 Kiesspüler / Gravel Rinser",
"2,Stein brechen\\, mahlen und sieben",
"3,TA2 Steinbrecher / Quarry",
"3,TA2 Mühle / Grinder",
"3,TA2 Kiessieb / Gravel Sieve",
"2,Items produzieren",
"3,TA2 Autocrafter",
"3,TA2 Elektronikfabrik / Electronic Fab",
"2,Sonstige Blöcke",
"3,TA2 Flüssigkeitensammler / Liquid Sampler",
"3,TA2 Gesicherte Kiste / Protected Chest",
"3,Techage Forceload Block",
},
texts = {
"In TA2 geht es darum\\, erste Maschinen zur Verarbeitung von Erzen zu bauen und zu betreiben. Einige Maschinen müssen dazu über Antriebsachsen angetrieben werden. Dazu musst du eine Dampfmaschine bauen und diese mit Kohle oder Holzkohle anheizen.\n"..
"\n"..
"In TA2 steht auch ein Kiesspüler zur Verfügung\\, mit dem seltene Erze wie Usmium Nuggets ausgewaschen werden können. Diese Nuggets wirst du später für weitere Rezepte brauchen.\n"..
"\n"..
"\n"..
"\n",
"Die Dampfmaschine besteht aus mehreren Blöcken und muss wie im Plan rechts abgebildet\\, zusammen gebaut werden. Dazu werden die Blöcke TA2 Feuerbox\\, TA2 Boiler oben\\, TA2 Boiler unten\\, TA2 Zylinder\\, TA2 Schwungrad und Dampfleitungen benötigt.\n"..
"\n"..
"Zusätzlich werden Antriebsachsen sowie Getriebeblöcke für Richtungswechsel benötigt. Das Schwungrad muss über die Antriebsachsen mit allen Maschinen verbunden werden\\, die angetrieben werden müssen.\n"..
"\n"..
"Bei allen Blöcken beim Setzen immer auch die Ausrichtung achten:\n"..
"\n"..
" - Zylinder links\\, Schwungrad rechts daneben\n"..
" - Dampfleitungen anschließen\\, wo ein entsprechendes Loch ist\n"..
" - Antriebsachse beim Schwungrad nur rechts\n"..
" - bei allen Maschinen kann die Antriebsachse an allen Seiten angeschlossen werden\\, welche nicht durch andere Funktionen belegt wird\\, wie bspw. die IN und OUT Löcher bei Mühle und Sieb.\n"..
"\n"..
"Der Boiler muss mit Wasser gefüllt werden. Dazu bis zu 10 Eimer Wasser in den Boiler füllen.\n"..
"Die Feuerbox muss mit Kohle oder Holzkohle gefüllt werden.\n"..
"Wenn das Wasser heiß ist (Temperaturanzeige ganz oben)\\, kann die Dampfmaschine am Schwungrad gestartet werden.\n"..
"\n"..
"Die Dampfmaschine leistet 25 ku und kann damit mehrere Maschinen gleichzeitig antreiben.\n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine. \n"..
"\n"..
"Die Feuerbox muss mit Kohle oder Holzkohle gefüllt werden. Die Brenndauer ist abhängig von der Leistung\\, die von der Dampfmaschine angefordert wird. Unter Volllast brennt Kohle 32 s und Holzkohle 96 s.\n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine. Muss mit Wasser gefüllt werden. Dies erfolgt durch Klicken mit einem Wassereimer auf den Boiler. Wenn kein Wasser mehr vorhanden ist oder die Temperatur zu weit absinkt\\, schaltet sich die Dampfmaschine ab. Bei der Dampfmaschine geht bei jedem Kolbenhub etwas Wasser als Dampf verloren\\, daher muss regelmäßig Wasser nachgefüllt werden.\n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine.\n"..
"\n"..
"\n"..
"\n",
"Antriebsteil der Dampfmaschine. Das Schwungrad muss über Antriebsachsen mit den Maschinen verbunden werden. \n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine. Der Boiler muss mit dem Zylinder über die Dampfleitungen (steam pipes) verbunden werden. Die Dampfleitung besitzt keine Abzweigungen\\, die maximale Länge beträgt 12 m (Blöcke).\n"..
"\n"..
"\n"..
"\n",
"Die Antriebsachsen dienen zur Kraftübertragung von der Dampfmaschine zu anderen Maschinen. Die maximale Länge einer Antriebsachse beträgt 10 Blöcke. Über Getriebeblöcke können auch größere Strecken überbrückt\\, sowie Abzweigungen und Richtungswechsel realisiert werden.\n"..
"\n"..
"\n"..
"\n",
"Um Lampen oder andere Stromverbraucher an einer Dampfmaschine betreiben zu können\\, wird der TA2 Stromgenerator benötigt. Der TA2 Stromgenerator muss auf einer Seite mit Antriebsachsen verbunden werden und liefert dann auf der anderen Seite elektrischen Strom.\n"..
"\n"..
"Wird der Stromgenerator nicht mit ausreichend Kraft versorgt\\, geht er in einen Fehlerzustand und muss über einen Rechtsklick wieder aktiviert werden.\n"..
"\n"..
"Das Stromgenerator nimmt primär max. 25 ku an Achsenkraft auf und gibt sekundär max. 24 ku als Strom wieder ab. Er verbraucht also ein ku für die Umwandlung.\n"..
"\n"..
"\n"..
"\n",
"Bei größeren Anlagen mit mehreren Dampfmaschinen oder vielen angetriebenen Maschinen empfiehlt sich ein Energiespeicher. Der Energiespeicher bei TA2 arbeitet mit Lageenergie. Dazu wird Balast (Steine\\, Kies) in einer Kiste mit Hilfe einer Seilwinde in die Höhe gezogen. Ist überschüssige Energie im Achsen-Netzwerk vorhanden\\, so wird die Kiste nach oben gezogen. Wird kurzfristig mehr Energie benötigt\\, als die Dampfmaschine liefern kann\\, so gibt der Energiespeicher die gespeicherte Energie wieder ab\\, und die Balast-Kiste bewegt sich wieder nach unten.\n"..
"\n"..
"Der Energiespeicher besteht aus mehreren Blöcken und muss wie im Plan rechts abgebildet\\, zusammen gebaut werden.\n"..
"\n"..
"Um die maximale Speicherkapazität zu erreichen\\, muss die Kiste mit Gewichten komplett gefüllt\\, und der Mast inklusive der zwei Getriebeblöcke 12 Blöcke hoch sein. Kleinere Aufbauten sind aber auch möglich.\n"..
"\n"..
"\n"..
"\n",
"Die Seilwinde muss mit einem Getriebeblock verbunden werden und kann so überschüssige Energie aufnehmen und damit eine Gewichtekiste nach oben ziehen. Achte beim Aufbau der Seilwinde darauf\\, dass der Pfeil auf der Blockoberseite zum Getriebeblock zeigt. Die maximale Seillänge beträgt 10 Blöcke.\n"..
"\n"..
"\n"..
"\n",
"Diese Kiste muss mit bis zu 10 Blöcken Abstand unter die Seilwinde gesetzt und mit Pflastersteinen Kies oder Sand gefüllt werden. Ist das Mindestgewicht von einem Stack (99+ Items) erreicht und überschüssige Energie vorhanden\\, wird die Kiste automatisch über eine Seil mit der Seilwinde verbunden und in die Höhe gezogen.\n"..
"\n"..
"\n"..
"\n",
"Mit der Kupplung können Achsen und Maschinen vom Energiespeicher getrennt werden. Damit kommen die Achsen nach der Kupplung zum Stillstand und Maschinenanlagen können umgebaut werden. Achte beim Aufbau der Kupplung darauf\\, dass der Pfeil auf der Blockoberseite zum Energiespeicher zeigt. \n"..
"\n"..
"\n"..
"\n",
"Um Gegenstände (Items) von einer Verarbeitungsstation zur nächsten weiter zu transportieren\\, werden Schieber und Röhren verwendet. Siehe Plan.\n"..
"\n"..
"\n"..
"\n",
"Zwei Maschinen können mit Hilfe eines Schiebers und einer Röhre (tube) verbunden werden. Röhren besitzen keine Abzweigungen. Die maximale Länge beträgt 200 m (Blöcke).\n"..
"\n"..
"Röhren können alternativ mit Hilfe der Shift-Taste platziert werden. Dies erlaubt bspw. Röhren parallel zu verlegen\\, ohne dass diese sich unbeabsichtigt verbinden.\n"..
"\n"..
"Die Transportkapazität einer Röhre ist unbegrenzt und nur durch die Schieber begrenzt.\n"..
"\n"..
"\n"..
"\n",
"Über den Konzentrator können mehrere Röhren zu einer Röhre zusammengeführt werden. Die Richtung\\, in der alle Items weitergegeben werden\\, ist mit einem Pfeil markiert.\n"..
"\n"..
"\n"..
"\n",
"Ein Schieber ist in der Lage\\, Items aus Kisten oder Maschinen zu ziehen und in andere Kisten oder Maschinen zu schieben. Oder anders gesagt: Zwischen zwei Blöcken mit Inventar muss ein und genau ein Schieber sein. Mehrere Schieber in Reihe sind nicht möglich.\n"..
"In die Gegenrichtung ist ein Schieber für Items aber durchlässig\\, so dass eine Kiste über eine Röhre gefüllt und ebenso geleert werden kann. \n"..
"\n"..
"Ein Schieber geht in den Zustand \"standby\"\\, wenn der keine Items zum Schieben hat. Ist der Ausgang blockiert oder das Inventory des Empfängers voll\\, so geht der Schieber in den Zustand \"blocked\". Aus beiden Zuständen kommt der Schieber nach einigen Sekunden selbsttätig wieder raus\\, sofern sich die Situation geändert hat.\n"..
"\n"..
"Der Verarbeitungsleistung eines TA2 Schiebers beträgt 2 Items alle 2 s.\n"..
"\n"..
"\n"..
"\n",
"Der Verteiler ist in der Lage\\, die Items aus seinem Inventar sortiert in bis zu vier Richtungen weiter zu transportieren. Dazu muss der Verteiler entsprechend konfiguriert werden. \n"..
"\n"..
"Der Verteiler besitzt dazu ein Menü mit 4 Filter mit unterschiedlichen Farben\\, entsprechend den 4 Ausgängen. Soll ein Ausgang genutzt werden\\, so muss der entsprechende Filter über die \"on\" Checkbox aktiviert werden. Alle Items\\, die für diesen Filter konfiguriert sind\\, werden über den zugeordneten Ausgang ausgegeben. Wird ein Filter aktiviert\\, ohne das Items konfiguriert werden\\, so sprechen wir hier von einem \"nicht-konfigurierten\"\\, offenen Ausgang.\n"..
"\n"..
"*Achtung: Der Verteiler ist an seinen Ausgängen gleichzeitig ein Schieber. Daher niemals die Gegenstände mit einem Schieber aus dem Verteiler ziehen!*\n"..
"\n"..
"Für einen nicht-konfigurierten Ausgang gibt es zwei Betriebsarten:\n"..
"\n"..
"1) Alle Items ausgeben\\, die an keine anderen Ausgängen ausgegeben werden können\\, auch wenn diese blockiert sind.\n"..
"\n"..
"2) Nur die Items ausgeben\\, die für keinen anderen Filter konfiguriert wurden.\n"..
"\n"..
"Im ersten Fall werden immer alle Items weitergeleitet und der Verteiler läuft nicht voll. Im zweiten Fall werden Items zurückgehalten und der Verteiler kann voll laufen und in der Folge blockieren.\n"..
"\n"..
"Einstellbar ist die Betriebsart über die \"blockiere\" Checkbox.\n"..
"\n"..
"Der Verarbeitungsleistung eines TA2 Verteilers beträgt 4 Items alle 2 s\\, wobei der Verteiler dabei versucht\\, die 4 Items auf die offenen Ausgänge zu verteilen.\n"..
"\n"..
"Wird dasselbe Item in einem Filter mehrfach hinterlegt\\, so beeinflusst dies das langfristige Verteilungsverhältnis entsprechend.\n"..
"\n"..
"Bitte beachte\\, dass die Verteilung ein probabilistischer Vorgang ist\\, d.h. die Verhältnisse werden nicht exakt\\, sondern nur langfristig eingehalten.\n"..
"\n"..
"In den Filtern beträgt die maximale Stackgröße 12\\; insgesamt können höchstens 36 Items konfiguriert werden.\n"..
"\n"..
"\n"..
"\n",
"Die Kieswaschanlage ist eine komplexere Maschine mit dem Ziel\\, Usmium Nuggets aus gesiebtem Kies auszuwaschen. Für den Aufbau wird ein TA2 Kiesspüler mit Achsenantrieb\\, ein Trichter\\, eine Kiste\\, sowie fließendes Wasser benötigt. \n"..
"\n"..
"Aufbau von links nach rechts (siehe auch Plan):\n"..
"\n"..
" - Ein Erdblock\\, darauf die Wasserquelle\\, umgeben auf 3 Seiten von bspw. Glasblöcken\n"..
" - daneben den Kiesspüler\\, ggf. mit Röhrenanschlüssen für den Kies An- und Abtransport\n"..
" - dann den Trichter mit Kiste\n"..
"\n"..
"Das Ganze umgeben von weiteren Glasblöcken\\, so dass das Wasser über den Kiesspüler und den Trichter fließt und ausgespülten Nuggets vom Trichter wieder eingesammelt werden können.\n"..
"\n"..
"\n"..
"\n",
"Der Kiesspüler ist in der Lage\\, aus bereits gesiebtem Kies die Erze Usmium und Kupfer auszuspülen\\, sofern dieser von Wasser überspült wird.\n"..
"\n"..
"Ob der Kiesspüler korrekt arbeitet\\, kann mit Hilfe von Stöcken (sticks) getestet werden\\, wenn diese in das Inventar des Kiesspülers getan werden. Diese müssen einzeln ausgespült und vom Trichter eingefangen werden.\n"..
"\n"..
"Die Verarbeitungsleistung ist ein Kies Item alle 2 s. Der Kiesspüler benötigt 3 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Das Brechen\\, Mahlen und Siebe von Gestein dient zur Gewinnung von Erzen. Gesiebtes Kies kann aber auch anderweitig genutzt werden. Steinbrecher\\, Mühle und Sieb müssen angetrieben und damit in der Nähe einer Dampfmaschine aufgebaut werden.\n"..
"\n"..
"\n"..
"\n",
"Der Steinbrecher dient zum Abbau von Steinen und anderen Materialien aus dem Untergrund. Der Steinbrecher gräbt ein 5x5 Blöcke großes Loch. Die Tiefe ist einstellbar.\n"..
"Die Verarbeitungsleistung ist ein Block alle 4 s. Der Steinbrecher benötigt 10 ku Energie. Die maximale Tiefe beträgt 20 Meter. Für größere Tiefen siehe TA3/TA4.\n"..
"\n"..
"\n"..
"\n",
"Die Mühle ist in der Lage\\, verschiedenes Gestein\\, aber auch Holz und andere Items zu mahlen.\n"..
"Die Verarbeitungsleistung ist ein Item alle 4 s. Die Mühle benötigt 4 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Das Kiessieb ist in der Lage\\, Kies zu sieben um Erze zu gewinnen. Als Ergebnis erhält man teilweise \"gesiebtes Kies\"\\, was nicht wieder gesiebt werden kann.\n"..
"Die Verarbeitungsleistung ist ein Item alle 4 s. Das Kiessieb benötigt 3 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Mit TA2 Maschinen können nicht nur Erze gewonnen\\, sondern auch Gegenstände hergestellt werden.\n"..
"\n",
"Der Autocrafter dient zur automatischen Herstellung von Waren. Alles was der Spieler über das \"Crafting Grid\" herstellen kann\\, kann auch durch den Autocrafter erledigt werden. Dazu müssen im Menü des Autocrafters das Rezept eingegeben und die notwendigen Zutaten hinzugefügt werden.\n"..
"\n"..
"Zutaten und hergestellte Waren können über Röhren und Schieber in und aus dem Block transportiert werden.\n"..
"\n"..
"Die Verarbeitungsleistung ist ein Item alle 4 s. Der Autocrafter benötigt 4 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Die Elektronikfabrik ist eine Spezialmaschine und nur für die Herstellung der Vakuumröhren nutzbar. Vakuumröhren werden für TA3 Maschinen und Blöcke benötigt.\n"..
"\n"..
"Die Verarbeitungsleistung ist eine Vakuumröhre alle 6 s. Die Elektronikfabrik benötigt 8 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"",
"Für manche Rezepte wird Wasser benötigt. Damit auch diese Rezepte automatisiert mit dem Autocrafter bearbeitet werden können\\, muss Wasser in Eimern bereitgestellt werden. Hierzu dient der Flüssigkeitensammler. Er benötigt leere Eimer und muss ins Wasser gestellt werden.\n"..
"\n"..
"Die Verarbeitungsleistung ist ein Wassereimer alle 8 s. Der Flüssigkeitensammler benötigt 3 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Die gesicherte Kiste kann nur von den Spielern genutzt werden\\, die an diesem Ort auch bauen können\\, also Protection Rechte besitzen. Es spielt dabei keine Rolle\\, wer die Kiste setzt. \n"..
"\n"..
"\n"..
"\n",
"Minetest teilt die Karte in sogenannte Map-Blocks ein. Das sind Würfel mit 16x16x16 Blöcke Kantenlänge. So ein Map-Block wird vom Server immer komplett geladen\\, aber es werden nur die Blöcke um einen Spieler herum geladen (ca. 2-3 Blöcke in alle Richtungen). In Sichtrichtung des Spielers sind es auch mehr Map-Blöcke. Nur dieser Teil der Welt ist aktiv und nur hier wachsen Pflanzen und Bäume bzw. laufen die Maschinen.\n"..
"\n"..
"Mit einem Forceload-Block kannst du erzwingen\\, dass der Map-Block\\, in dem der Forceload Block steht\\, immer geladen bleibt\\, solange du auf dem Server bist. Wenn alle deine Farmen und Maschinen mit Forceload Blöcken abgedeckt sind\\, ist immer alles am Laufen.\n"..
"\n"..
"Die Map-Blöcke mit ihren Koordinaten sind vordefiniert\\, also bspw. (0\\,0\\,0) bis (15\\,15\\,15)\\, oder (16\\,16\\,16) bis (31\\,31\\,31).\n"..
"Man kann einen Forceload-Block innerhalb eines Map-Blockes verschieben wie man will\\, die Position des Map-Blocks bleibt dabei unverändert. \n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta2",
"",
"ta2_firebox",
"ta2_boiler",
"ta2_cylinder",
"ta2_flywheel",
"ta2_steampipe",
"ta2_driveaxle",
"ta2_generator",
"",
"ta2_winch",
"ta2_weight_chest",
"techage:ta2_clutch_off",
"",
"tube",
"concentrator",
"ta2_pusher",
"ta2_distributor",
"",
"ta2_rinser",
"ta2_grinder",
"ta2_quarry",
"ta2_grinder",
"ta2_gravelsieve",
"",
"ta2_autocrafter",
"ta2_electronicfab",
"",
"ta2_liquidsampler",
"ta2_chest",
"ta2_forceload",
},
plans = {
"",
"steamengine",
"",
"",
"",
"",
"",
"",
"",
"ta2_storage",
"",
"",
"",
"itemtransport",
"",
"",
"",
"",
"gravelrinser",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

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