built on 03/01/2022 11:59:31

This commit is contained in:
Joachim Stolberg 2022-01-03 11:59:31 +01:00
parent 073b994ead
commit 65266a918d
209 changed files with 9106 additions and 3779 deletions

View File

@ -1,8 +0,0 @@
stages:
- test
luacheck:
stage: test
image: pipelinecomponents/luacheck:latest
script:
- luacheck .

View File

@ -1,30 +0,0 @@
std = "lua51+minetest"
unused_args = false
allow_defined_top = true
max_line_length = 999
stds.minetest = {
read_globals = {
"DIR_DELIM",
"minetest",
"core",
"dump",
"vector",
"nodeupdate",
"VoxelManip",
"VoxelArea",
"PseudoRandom",
"ItemStack",
"default",
table = {
fields = {
"copy",
},
},
}
}
read_globals = {
"default",
"moreores",
}

View File

@ -1,600 +0,0 @@
License for code: LGPL 3.0
License for media and all other assets: CC-by-SA 4.0
###############################################################################
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
###############################################################################
Attribution-ShareAlike 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.
c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

View File

@ -1,86 +0,0 @@
-- Translation support
local S = minetest.get_translator("basic_materials")
-- items
minetest.register_craftitem("basic_materials:silicon", {
description = S("Silicon lump"),
inventory_image = "basic_materials_silicon.png",
})
minetest.register_craftitem("basic_materials:ic", {
description = S("Simple Integrated Circuit"),
inventory_image = "basic_materials_ic.png",
})
minetest.register_craftitem("basic_materials:motor", {
description = S("Simple Motor"),
inventory_image = "basic_materials_motor.png",
})
minetest.register_craftitem("basic_materials:heating_element", {
description = S("Heating element"),
inventory_image = "basic_materials_heating_element.png",
})
minetest.register_craftitem("basic_materials:energy_crystal_simple", {
description = S("Simple energy crystal"),
inventory_image = "basic_materials_energy_crystal.png",
})
-- crafts
minetest.register_craft( {
output = "mesecons_materials:silicon 4",
recipe = {
{ "default:sand", "default:sand" },
{ "default:sand", "default:steel_ingot" },
},
})
minetest.register_craft( {
output = "basic_materials:ic 4",
recipe = {
{ "mesecons_materials:silicon", "mesecons_materials:silicon" },
{ "mesecons_materials:silicon", "default:copper_ingot" },
},
})
minetest.register_craft( {
output = "basic_materials:motor 2",
recipe = {
{ "default:mese_crystal_fragment", "basic_materials:copper_wire", "basic_materials:plastic_sheet" },
{ "default:copper_ingot", "default:steel_ingot", "default:steel_ingot" },
{ "default:mese_crystal_fragment", "basic_materials:copper_wire", "basic_materials:plastic_sheet" }
},
replacements = {
{ "basic_materials:copper_wire", "basic_materials:empty_spool" },
{ "basic_materials:copper_wire", "basic_materials:empty_spool" },
}
})
minetest.register_craft( {
output = "basic_materials:heating_element 2",
recipe = {
{ "default:copper_ingot", "default:mese_crystal_fragment", "default:copper_ingot" }
},
})
minetest.register_craft({
--type = "shapeless",
output = "basic_materials:energy_crystal_simple 2",
recipe = {
{ "default:mese_crystal_fragment", "default:torch", "default:mese_crystal_fragment" },
{ "default:diamond", "default:gold_ingot", "default:diamond" }
},
})
-- aliases
minetest.register_alias("homedecor:ic", "basic_materials:ic")
minetest.register_alias("homedecor:motor", "basic_materials:motor")
minetest.register_alias("technic:motor", "basic_materials:motor")
minetest.register_alias("homedecor:heating_element", "basic_materials:heating_element")
minetest.register_alias("homedecor:power_crystal", "basic_materials:energy_crystal_simple")
minetest.register_alias_force("mesecons_materials:silicon", "basic_materials:silicon")

View File

@ -1,15 +0,0 @@
-- Basic materials mod
-- by Vanessa Dannenberg
-- This mod supplies all those little random craft items that everyone always
-- seems to need, such as metal bars (ala rebar), plastic, wire, and so on.
local modpath = minetest.get_modpath("basic_materials")
basic_materials = {}
basic_materials.mod = { author = "Vanessa Dannenberg" }
dofile(modpath.."/metals.lua")
dofile(modpath.."/plastics.lua")
dofile(modpath.."/electrical-electronic.lua")
dofile(modpath.."/misc.lua")

View File

@ -1,33 +0,0 @@
# textdomain: basic_materials
Silicon lump=Siliziumklumpen
Simple Integrated Circuit=Einfacher Integrierter Schaltkreis
Simple Motor=Einfacher Motor
Heating element=Heizelement
Simple energy crystal=Einfacher Energiekristall
Spool of steel wire=Spule mit Stahldraht
Spool of copper wire=Spule mit Kupferdraht
Spool of silver wire=Spule mit Silberdraht
Spool of gold wire=Spule mit Golddraht
Steel Strip=Stahlstreifen
Copper Strip=Kupferstreifen
Steel Bar=Stahlstab
Chainlinks (brass)=Messingkettenglieder
Chainlinks (steel)=Stahlkettenglieder
Brass Ingot=Messingbarren
Steel gear=Stahlzahnrad
Padlock=Vorhängeschloss
Chain (steel, hanging)=Hängende Stahlkette
Chain (brass, hanging)=Hängende Messingkette
Brass Block=Messingblock
Oil extract=Ölextrakt
Unprocessed paraffin=Unverarbeitetes Paraffin
Uncooked Terracotta Base=Ungebranntes Terrakotta
Wet Cement=Nasser Zement
Cement=Zement
Concrete Block=Betonblock
Plastic sheet=Kunststoffplatte
Plastic strips=Kunststoffstreifen
Empty wire spool=Leere Drahtspule

View File

@ -1,33 +0,0 @@
# textdomain: basic_materials
Silicon lump=Morceau de silicium
Simple Integrated Circuit=Circuit intégré simple
Simple Motor=Moteur simple
Heating element=Élément chauffant
Simple energy crystal=Cristal dénergie simple
Spool of steel wire=Bobine de fil dacier
Spool of copper wire=Bobine de fil de cuivre
Spool of silver wire=Bobine de fil dargent
Spool of gold wire=Bobine de fil dor
Steel Strip=Bande de acier
Copper Strip=Bande de cuivre
Steel Bar=Barre dacier
Chainlinks (brass)=Maillon en laiton
Chainlinks (steel)=Maillon en acier
Brass Ingot=Lingot de laiton
Steel gear=Rouage en acier
Padlock=Cadenas
Chain (steel, hanging)=Chaine en acier
Chain (brass, hanging)=Chaine en laiton
Brass Block=Bloc de laiton
Oil extract=Extrait dhuile
Unprocessed paraffin=Paraffine non transformée
Uncooked Terracotta Base=Argile crue
Wet Cement=Ciment humide
Cement=Ciment
Concrete Block=Bloc de béton
Plastic sheet=Morceau de plastique
Plastic strips=Bande de plastique
Empty wire spool=Bobine de fil vide

View File

@ -1,34 +0,0 @@
# textdomain: basic_materials
# Author: Salvo 'LtWorf' Tomaselli <tiposchi@tiscali.it>
Silicon lump=Grumo di silicio
Simple Integrated Circuit=Circuito integrato semplice
Simple Motor=Motore semplice
Heating element=Elemento riscaldante
Simple energy crystal=Cristallo di energia semplice
Spool of steel wire=Bobina di filo d'acciaio
Spool of copper wire=Bobina di filo di rame
Spool of silver wire=Bobina di filo d'argento
Spool of gold wire=Bobina di filo d'oro
Steel Strip=Striscia d'acciaio
Copper Strip=Striscia di rame
Steel Bar=Barra d'acciaio
Chainlinks (brass)=Catena (ottone)
Chainlinks (steel)=Catena (acciaio)
Brass Ingot=Lingotto di ottone
Steel gear=Ingranaggio d'acciaio
Padlock=Catenaccio
Chain (steel, hanging)=Catena (acciaio, pendente)
Chain (brass, hanging)=Catena (ottone, pendente)
Brass Block=Blocco di ottone
Oil extract=Estratto d'olio
Unprocessed paraffin=Paraffina grezza
Uncooked Terracotta Base=Argilla cruda
Wet Cement=Cemento umido
Cement=Cemento
Concrete Block=Blocco di calcestruzzo
Plastic sheet=Foglio di plastica
Plastic strips=Striscia di plastica
Empty wire spool=Rocchetto vuoto

View File

@ -1,33 +0,0 @@
# textdomain: basic_materials
Silicon lump=Кусок Кремния
Simple Integrated Circuit=Микросхема
Simple Motor=Мотор
Heating element=Нить Накала
Simple energy crystal=Энергетический Кристалл
Spool of steel wire=Катушка Стальной Проволоки
Spool of copper wire=Катушка Медной Проволоки
Spool of silver wire=Катушка Серебрянной Проволоки
Spool of gold wire=Катушка Золотой Проволоки
Steel Strip=Стальная Полоса
Copper Strip=Медная Полоса
Steel Bar=Стальной Прут
Chainlinks (brass)=Латунные Звенья
Chainlinks (steel)=Стальные Звенья
Brass Ingot=Латунный Брусок
Steel gear=Стальная Шестерня
Padlock=Навесной Замок
Chain (steel, hanging)=Стальная Цепь
Chain (brass, hanging)=Латунная Цепь
Brass Block=Латунный Блок
Oil extract=Масляный Экстракт
Unprocessed paraffin=Необработанный Парафин
Uncooked Terracotta Base=Ком Мокрого Терракота
Wet Cement=Ком Мокрого Цемента
Cement=Цемент
Concrete Block=Железобетон
Plastic sheet=Пластиковый Лист
Plastic strips=Пластиковая Полоса
Empty wire spool=Пустая Катушка

View File

@ -1,300 +0,0 @@
-- Translation support
local S = minetest.get_translator("basic_materials")
-- items
minetest.register_craftitem("basic_materials:steel_wire", {
description = S("Spool of steel wire"),
groups = { wire = 1 },
inventory_image = "basic_materials_steel_wire.png"
})
minetest.register_craftitem("basic_materials:copper_wire", {
description = S("Spool of copper wire"),
groups = { wire = 1 },
inventory_image = "basic_materials_copper_wire.png"
})
minetest.register_craftitem("basic_materials:silver_wire", {
description = S("Spool of silver wire"),
groups = { wire = 1 },
inventory_image = "basic_materials_silver_wire.png"
})
minetest.register_craftitem("basic_materials:gold_wire", {
description = S("Spool of gold wire"),
groups = { wire = 1 },
inventory_image = "basic_materials_gold_wire.png"
})
minetest.register_craftitem("basic_materials:steel_strip", {
description = S("Steel Strip"),
groups = { strip = 1 },
inventory_image = "basic_materials_steel_strip.png"
})
minetest.register_craftitem("basic_materials:copper_strip", {
description = S("Copper Strip"),
groups = { strip = 1 },
inventory_image = "basic_materials_copper_strip.png"
})
minetest.register_craftitem("basic_materials:steel_bar", {
description = S("Steel Bar"),
inventory_image = "basic_materials_steel_bar.png",
})
minetest.register_craftitem("basic_materials:chainlink_brass", {
description = S("Chainlinks (brass)"),
groups = { chainlinks = 1 },
inventory_image = "basic_materials_chainlink_brass.png"
})
minetest.register_craftitem("basic_materials:chainlink_steel", {
description = S("Chainlinks (steel)"),
groups = { chainlinks = 1 },
inventory_image = "basic_materials_chainlink_steel.png"
})
minetest.register_craftitem("basic_materials:brass_ingot", {
description = S("Brass Ingot"),
inventory_image = "basic_materials_brass_ingot.png",
})
minetest.register_craftitem("basic_materials:gear_steel", {
description = S("Steel gear"),
inventory_image = "basic_materials_gear_steel.png"
})
minetest.register_craftitem("basic_materials:padlock", {
description = S("Padlock"),
inventory_image = "basic_materials_padlock.png"
})
-- nodes
local chains_sbox = {
type = "fixed",
fixed = { -0.1, -0.5, -0.1, 0.1, 0.5, 0.1 }
}
minetest.register_node("basic_materials:chain_steel", {
description = S("Chain (steel, hanging)"),
drawtype = "mesh",
mesh = "basic_materials_chains.obj",
tiles = {"basic_materials_chain_steel.png"},
walkable = false,
climbable = true,
sunlight_propagates = true,
paramtype = "light",
inventory_image = "basic_materials_chain_steel_inv.png",
groups = {cracky=3},
selection_box = chains_sbox,
})
minetest.register_node("basic_materials:chain_brass", {
description = S("Chain (brass, hanging)"),
drawtype = "mesh",
mesh = "basic_materials_chains.obj",
tiles = {"basic_materials_chain_brass.png"},
walkable = false,
climbable = true,
sunlight_propagates = true,
paramtype = "light",
inventory_image = "basic_materials_chain_brass_inv.png",
groups = {cracky=3},
selection_box = chains_sbox,
})
minetest.register_node("basic_materials:brass_block", {
description = S("Brass Block"),
tiles = { "basic_materials_brass_block.png" },
is_ground_content = false,
groups = {cracky=1, level=2},
sounds = default.node_sound_metal_defaults()
})
-- crafts
minetest.register_craft( {
output = "basic_materials:copper_wire 2",
type = "shapeless",
recipe = {
"default:copper_ingot",
"basic_materials:empty_spool",
"basic_materials:empty_spool",
},
})
minetest.register_craft( {
output = "basic_materials:silver_wire 2",
type = "shapeless",
recipe = {
"moreores:silver_ingot",
"basic_materials:empty_spool",
"basic_materials:empty_spool",
},
})
minetest.register_craft( {
output = "basic_materials:gold_wire 2",
type = "shapeless",
recipe = {
"default:gold_ingot",
"basic_materials:empty_spool",
"basic_materials:empty_spool",
},
})
minetest.register_craft( {
output = "basic_materials:steel_wire 2",
type = "shapeless",
recipe = {
"default:steel_ingot",
"basic_materials:empty_spool",
"basic_materials:empty_spool",
},
})
minetest.register_craft( {
output = "basic_materials:steel_strip 12",
recipe = {
{ "", "default:steel_ingot", "" },
{ "default:steel_ingot", "", "" },
},
})
minetest.register_craft( {
output = "basic_materials:copper_strip 12",
recipe = {
{ "", "default:copper_ingot", "" },
{ "default:copper_ingot", "", "" },
},
})
minetest.register_craft( {
output = "basic_materials:steel_bar 6",
recipe = {
{ "", "", "default:steel_ingot" },
{ "", "default:steel_ingot", "" },
{ "default:steel_ingot", "", "" },
},
})
minetest.register_craft( {
output = "basic_materials:padlock 2",
recipe = {
{ "basic_materials:steel_bar" },
{ "default:steel_ingot" },
{ "default:steel_ingot" },
},
})
minetest.register_craft({
output = "basic_materials:chainlink_steel 12",
recipe = {
{"", "default:steel_ingot", "default:steel_ingot"},
{ "default:steel_ingot", "", "default:steel_ingot" },
{ "default:steel_ingot", "default:steel_ingot", "" },
},
})
minetest.register_craft({
output = "basic_materials:chainlink_brass 12",
recipe = {
{"", "basic_materials:brass_ingot", "basic_materials:brass_ingot"},
{ "basic_materials:brass_ingot", "", "basic_materials:brass_ingot" },
{ "basic_materials:brass_ingot", "basic_materials:brass_ingot", "" },
},
})
minetest.register_craft({
output = 'basic_materials:chain_steel 2',
recipe = {
{"basic_materials:chainlink_steel"},
{"basic_materials:chainlink_steel"},
{"basic_materials:chainlink_steel"}
}
})
minetest.register_craft({
output = 'basic_materials:chain_brass 2',
recipe = {
{"basic_materials:chainlink_brass"},
{"basic_materials:chainlink_brass"},
{"basic_materials:chainlink_brass"}
}
})
minetest.register_craft( {
output = "basic_materials:gear_steel 6",
recipe = {
{ "", "default:steel_ingot", "" },
{ "default:steel_ingot","basic_materials:chainlink_steel", "default:steel_ingot" },
{ "", "default:steel_ingot", "" }
},
})
minetest.register_craft( {
type = "shapeless",
output = "basic_materials:brass_ingot 3",
recipe = {
"default:copper_ingot",
"default:copper_ingot",
"moreores:silver_ingot",
},
})
if not minetest.get_modpath("moreores") then
-- Without moreores, there still should be a way to create brass.
minetest.register_craft( {
output = "basic_materials:brass_ingot 9",
recipe = {
{"default:copper_ingot", "default:tin_ingot", "default:copper_ingot"},
{"default:gold_ingot", "default:copper_ingot", "default:gold_ingot"},
{"default:copper_ingot", "default:tin_ingot", "default:copper_ingot"},
},
})
end
minetest.register_craft( {
type = "shapeless",
output = "basic_materials:brass_ingot 9",
recipe = { "basic_materials:brass_block" },
})
minetest.register_craft( {
output = "basic_materials:brass_block",
recipe = {
{ "basic_materials:brass_ingot", "basic_materials:brass_ingot", "basic_materials:brass_ingot" },
{ "basic_materials:brass_ingot", "basic_materials:brass_ingot", "basic_materials:brass_ingot" },
{ "basic_materials:brass_ingot", "basic_materials:brass_ingot", "basic_materials:brass_ingot" },
},
})
-- aliases
minetest.register_alias("homedecor:copper_wire", "basic_materials:copper_wire")
minetest.register_alias("technic:fine_copper_wire", "basic_materials:copper_wire")
minetest.register_alias("technic:fine_silver_wire", "basic_materials:silver_wire")
minetest.register_alias("technic:fine_gold_wire", "basic_materials:gold_wire")
minetest.register_alias("homedecor:steel_wire", "basic_materials:steel_wire")
minetest.register_alias("homedecor:brass_ingot", "basic_materials:brass_ingot")
minetest.register_alias("technic:brass_ingot", "basic_materials:brass_ingot")
minetest.register_alias("technic:brass_block", "basic_materials:brass_block")
minetest.register_alias("homedecor:copper_strip", "basic_materials:copper_strip")
minetest.register_alias("homedecor:steel_strip", "basic_materials:steel_strip")
minetest.register_alias_force("glooptest:chainlink", "basic_materials:chainlink_steel")
minetest.register_alias_force("homedecor:chainlink_steel", "basic_materials:chainlink_steel")
minetest.register_alias("homedecor:chainlink_brass", "basic_materials:chainlink_brass")
minetest.register_alias("chains:chain", "basic_materials:chain_steel")
minetest.register_alias("chains:chain_brass", "basic_materials:chain_brass")
minetest.register_alias("pipeworks:gear", "basic_materials:gear_steel")
minetest.register_alias("technic:rebar", "basic_materials:steel_bar")

View File

@ -1,126 +0,0 @@
-- Translation support
local S = minetest.get_translator("basic_materials")
-- items
minetest.register_craftitem("basic_materials:oil_extract", {
description = S("Oil extract"),
inventory_image = "basic_materials_oil_extract.png",
})
minetest.register_craftitem("basic_materials:paraffin", {
description = S("Unprocessed paraffin"),
inventory_image = "basic_materials_paraffin.png",
})
minetest.register_craftitem("basic_materials:terracotta_base", {
description = S("Uncooked Terracotta Base"),
inventory_image = "basic_materials_terracotta_base.png",
})
minetest.register_craftitem("basic_materials:wet_cement", {
description = S("Wet Cement"),
inventory_image = "basic_materials_wet_cement.png",
})
-- nodes
minetest.register_node("basic_materials:cement_block", {
description = S("Cement"),
tiles = {"basic_materials_cement_block.png"},
is_ground_content = true,
groups = {cracky=2},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("basic_materials:concrete_block", {
description = S("Concrete Block"),
tiles = {"basic_materials_concrete_block.png",},
groups = {cracky=1, level=2, concrete=1},
sounds = default.node_sound_stone_defaults(),
})
-- crafts
minetest.register_craft({
type = "shapeless",
output = "basic_materials:oil_extract 2",
recipe = {
"group:leaves",
"group:leaves",
"group:leaves",
"group:leaves",
"group:leaves",
"group:leaves"
}
})
minetest.register_craft({
type = "cooking",
output = "basic_materials:paraffin",
recipe = "basic_materials:oil_extract",
})
minetest.register_craft({
type = "fuel",
recipe = "basic_materials:oil_extract",
burntime = 30,
})
minetest.register_craft({
type = "fuel",
recipe = "basic_materials:paraffin",
burntime = 30,
})
minetest.register_craft( {
type = "shapeless",
output = "basic_materials:terracotta_base 8",
recipe = {
"bucket:bucket_water",
"default:clay_lump",
"default:gravel",
},
replacements = { {"bucket:bucket_water", "bucket:bucket_empty"}, },
})
minetest.register_craft({
type = "shapeless",
output = "basic_materials:wet_cement 3",
recipe = {
"default:dirt",
"dye:dark_grey",
"dye:dark_grey",
"dye:dark_grey",
"bucket:bucket_water"
},
replacements = {{'bucket:bucket_water', 'bucket:bucket_empty'},},
})
minetest.register_craft({
type = "cooking",
output = "basic_materials:cement_block",
recipe = "basic_materials:wet_cement",
cooktime = 8
})
minetest.register_craft({
output = 'basic_materials:concrete_block 6',
recipe = {
{'group:sand', 'basic_materials:wet_cement', 'default:gravel'},
{'basic_materials:steel_bar', 'basic_materials:wet_cement', 'basic_materials:steel_bar'},
{'default:gravel', 'basic_materials:wet_cement', 'group:sand'},
}
})
-- aliases
minetest.register_alias("homedecor:oil_extract", "basic_materials:oil_extract")
minetest.register_alias("homedecor:paraffin", "basic_materials:paraffin")
minetest.register_alias("homedecor:plastic_base", "basic_materials:paraffin")
minetest.register_alias("homedecor:terracotta_base", "basic_materials:terracotta_base")
minetest.register_alias("gloopblocks:wet_cement", "basic_materials:wet_cement")
minetest.register_alias("gloopblocks:cement", "basic_materials:cement_block")
minetest.register_alias("technic:concrete", "basic_materials:concrete_block")

View File

@ -1,4 +0,0 @@
name = basic_materials
depends = default
optional_depends = moreores
min_minetest_version = 5.2.0

View File

@ -1,881 +0,0 @@
# Blender v2.73 (sub 0) OBJ File: 'chains.blend'
# www.blender.org
o Torus.016_Torus
v 0.000000 -0.429978 0.000002
v 0.000000 -0.401109 0.055211
v -0.014044 -0.391975 0.048870
v -0.014044 -0.423304 0.000002
v -0.009826 -0.379748 0.040970
v -0.009826 -0.406012 0.000002
v 0.009826 -0.379748 0.040970
v 0.009826 -0.406012 0.000002
v 0.014044 -0.391975 0.048870
v 0.014044 -0.423304 0.000002
v 0.000000 -0.316336 0.080195
v -0.014044 -0.316336 0.069112
v -0.009826 -0.316336 0.057941
v 0.009826 -0.316336 0.057941
v 0.014044 -0.316336 0.069112
v 0.000000 -0.231564 0.055211
v -0.014044 -0.240700 0.048870
v -0.009826 -0.252925 0.040970
v 0.009826 -0.252925 0.040970
v 0.014044 -0.240700 0.048870
v 0.000000 -0.202695 0.000002
v -0.014044 -0.209368 0.000002
v -0.009826 -0.226661 0.000002
v 0.009826 -0.226661 0.000002
v 0.014044 -0.209368 0.000002
v 0.000000 -0.231564 -0.055206
v -0.014044 -0.240700 -0.048868
v -0.009826 -0.252925 -0.040967
v 0.009826 -0.252925 -0.040967
v 0.014044 -0.240700 -0.048865
v 0.000000 -0.316336 -0.080190
v -0.014044 -0.316336 -0.069108
v -0.009826 -0.316336 -0.057936
v 0.009826 -0.316336 -0.057936
v 0.014044 -0.316336 -0.069108
v 0.000000 -0.400361 -0.055206
v -0.014044 -0.391975 -0.048868
v -0.009826 -0.379748 -0.040967
v 0.009826 -0.379748 -0.040967
v 0.014044 -0.391975 -0.048868
v 0.000000 -0.262249 0.000002
v -0.061672 -0.233381 0.000002
v -0.054590 -0.224245 -0.012569
v 0.000000 -0.255577 -0.012569
v -0.045765 -0.212018 -0.008794
v 0.000000 -0.238285 -0.008794
v -0.045765 -0.212018 0.008798
v 0.000000 -0.238285 0.008798
v -0.054590 -0.224245 0.012574
v 0.000000 -0.255577 0.012574
v -0.089582 -0.148609 0.000002
v -0.077200 -0.148609 -0.012569
v -0.064722 -0.148609 -0.008794
v -0.064722 -0.148609 0.008799
v -0.077200 -0.148609 0.012574
v -0.061672 -0.063837 0.000002
v -0.054590 -0.072971 -0.012569
v -0.045765 -0.085198 -0.008794
v -0.045765 -0.085198 0.008799
v -0.054590 -0.072971 0.012574
v 0.000000 -0.034967 0.000002
v 0.000000 -0.041641 -0.012569
v 0.000000 -0.058933 -0.008794
v 0.000000 -0.058933 0.008799
v 0.000000 -0.041641 0.012574
v 0.061672 -0.063837 0.000002
v 0.054590 -0.072971 -0.012569
v 0.045765 -0.085198 -0.008794
v 0.045765 -0.085198 0.008799
v 0.054590 -0.072971 0.012574
v 0.089582 -0.148609 0.000002
v 0.077200 -0.148609 -0.012569
v 0.064722 -0.148609 -0.008794
v 0.064722 -0.148609 0.008799
v 0.077200 -0.148609 0.012574
v 0.061672 -0.232631 0.000002
v 0.054590 -0.224245 -0.012569
v 0.045765 -0.212018 -0.008794
v 0.045765 -0.212018 0.008798
v 0.054590 -0.224245 0.012574
v 0.000000 0.073316 0.000002
v 0.061672 0.102183 0.000002
v 0.054590 0.111319 0.012574
v 0.000000 0.079988 0.012574
v 0.045765 0.123546 0.008799
v 0.000000 0.097280 0.008799
v 0.045765 0.123546 -0.008794
v 0.000000 0.097280 -0.008794
v 0.054590 0.111319 -0.012569
v 0.000000 0.079988 -0.012569
v 0.089582 0.186956 0.000002
v 0.077200 0.186956 0.012574
v 0.064722 0.186956 0.008799
v 0.064722 0.186956 -0.008794
v 0.077200 0.186956 -0.012569
v 0.061672 0.271728 0.000002
v 0.054590 0.262594 0.012574
v 0.045765 0.250367 0.008799
v 0.045765 0.250367 -0.008794
v 0.054590 0.262594 -0.012569
v 0.000000 0.300597 0.000002
v 0.000000 0.293923 0.012574
v 0.000000 0.276631 0.008799
v 0.000000 0.276631 -0.008794
v 0.000000 0.293923 -0.012569
v -0.061672 0.271728 0.000002
v -0.054590 0.262594 0.012574
v -0.045765 0.250367 0.008799
v -0.045765 0.250367 -0.008794
v -0.054590 0.262594 -0.012569
v -0.089582 0.186956 0.000002
v -0.077200 0.186956 0.012574
v -0.064722 0.186956 0.008799
v -0.064722 0.186956 -0.008794
v -0.077200 0.186956 -0.012569
v -0.061672 0.102931 0.000002
v -0.054590 0.111319 0.012574
v -0.045765 0.123546 0.008799
v -0.045765 0.123546 -0.008794
v -0.054590 0.111319 -0.012569
v 0.000000 -0.095037 0.000002
v 0.000000 -0.066168 -0.055206
v 0.014044 -0.057034 -0.048868
v 0.014044 -0.088363 0.000002
v 0.009826 -0.044807 -0.040967
v 0.009826 -0.071071 0.000002
v -0.009826 -0.044807 -0.040967
v -0.009826 -0.071071 0.000002
v -0.014044 -0.057034 -0.048868
v -0.014044 -0.088363 0.000002
v 0.000000 0.018605 -0.080190
v 0.014044 0.018605 -0.069108
v 0.009826 0.018605 -0.057936
v -0.009826 0.018605 -0.057936
v -0.014044 0.018605 -0.069108
v 0.000000 0.103377 -0.055206
v 0.014044 0.094243 -0.048868
v 0.009826 0.082016 -0.040967
v -0.009826 0.082016 -0.040967
v -0.014044 0.094243 -0.048868
v 0.000000 0.132246 0.000002
v 0.014044 0.125572 0.000002
v 0.009826 0.108280 0.000002
v -0.009826 0.108280 0.000002
v -0.014044 0.125572 0.000002
v 0.000000 0.103377 0.055211
v 0.014044 0.094243 0.048870
v 0.009826 0.082016 0.040970
v -0.009826 0.082016 0.040970
v -0.014044 0.094243 0.048870
v 0.000000 0.018605 0.080195
v 0.014044 0.018605 0.069112
v 0.009826 0.018605 0.057941
v -0.009826 0.018605 0.057941
v -0.014044 0.018605 0.069112
v 0.000000 -0.065420 0.055211
v 0.014044 -0.057032 0.048870
v 0.009826 -0.044807 0.040970
v -0.009826 -0.044807 0.040970
v -0.014044 -0.057032 0.048870
v 0.000000 -0.598329 0.000002
v 0.061672 -0.569460 0.000002
v 0.054590 -0.560326 0.012574
v 0.000000 -0.591655 0.012574
v 0.045765 -0.548099 0.008798
v 0.000000 -0.574363 0.008798
v 0.045765 -0.548099 -0.008794
v 0.000000 -0.574363 -0.008794
v 0.054590 -0.560326 -0.012569
v 0.000000 -0.591655 -0.012569
v 0.089582 -0.484687 0.000002
v 0.077200 -0.484687 0.012574
v 0.064722 -0.484687 0.008798
v 0.064722 -0.484687 -0.008794
v 0.077200 -0.484687 -0.012569
v 0.061672 -0.399915 0.000002
v 0.054590 -0.409051 0.012574
v 0.045765 -0.421278 0.008798
v 0.045765 -0.421278 -0.008794
v 0.054590 -0.409051 -0.012569
v 0.000000 -0.371048 0.000002
v 0.000000 -0.377719 0.012574
v 0.000000 -0.395012 0.008798
v 0.000000 -0.395012 -0.008794
v 0.000000 -0.377719 -0.012569
v -0.061672 -0.399915 0.000002
v -0.054590 -0.409051 0.012574
v -0.045765 -0.421278 0.008798
v -0.045765 -0.421278 -0.008794
v -0.054590 -0.409051 -0.012569
v -0.089582 -0.484687 0.000002
v -0.077200 -0.484687 0.012574
v -0.064722 -0.484687 0.008798
v -0.064722 -0.484687 -0.008794
v -0.077200 -0.484687 -0.012569
v -0.061672 -0.568712 0.000002
v -0.054590 -0.560326 0.012574
v -0.045765 -0.548099 0.008798
v -0.045765 -0.548099 -0.008794
v -0.054590 -0.560326 -0.012569
v 0.000000 0.241043 0.000002
v 0.000000 0.269910 0.055211
v -0.014044 0.279047 0.048870
v -0.014044 0.247717 0.000002
v -0.009826 0.291274 0.040970
v -0.009826 0.265007 0.000002
v 0.009826 0.291274 0.040970
v 0.009826 0.265007 0.000002
v 0.014044 0.279047 0.048870
v 0.014044 0.247717 0.000002
v 0.000000 0.354683 0.080195
v -0.014044 0.354683 0.069112
v -0.009826 0.354683 0.057941
v 0.009826 0.354683 0.057941
v 0.014044 0.354683 0.069112
v 0.000000 0.439455 0.055211
v -0.014044 0.430321 0.048870
v -0.009826 0.418094 0.040970
v 0.009826 0.418094 0.040970
v 0.014044 0.430321 0.048870
v 0.000000 0.468325 0.000002
v -0.014044 0.461651 0.000002
v -0.009826 0.444361 0.000002
v 0.009826 0.444361 0.000002
v 0.014044 0.461651 0.000002
v 0.000000 0.439455 -0.055206
v -0.014044 0.430321 -0.048868
v -0.009826 0.418094 -0.040967
v 0.009826 0.418094 -0.040967
v 0.014044 0.430321 -0.048868
v 0.000000 0.354683 -0.080190
v -0.014044 0.354683 -0.069108
v -0.009826 0.354683 -0.057936
v 0.009826 0.354683 -0.057936
v 0.014044 0.354683 -0.069108
v 0.000000 0.270661 -0.055206
v -0.014044 0.279047 -0.048868
v -0.009826 0.291274 -0.040967
v 0.009826 0.291274 -0.040967
v 0.014044 0.279047 -0.048868
vt 0.187500 0.125000
vt 0.250000 0.125000
vt 0.250000 0.187500
vt 0.187500 0.187500
vt 0.250000 0.250000
vt 0.187500 0.250000
vt 0.250000 0.312500
vt 0.187500 0.312500
vt 0.250000 0.375000
vt 0.187500 0.375000
vt 0.187500 0.062500
vt 0.250000 0.062500
vt 0.312500 0.125000
vt 0.312500 0.187500
vt 0.312500 0.250000
vt 0.312500 0.312500
vt 0.312500 0.375000
vt 0.312500 0.062500
vt 0.375000 0.125000
vt 0.375000 0.187500
vt 0.375000 0.250000
vt 0.375000 0.312500
vt 0.375000 0.375000
vt 0.375000 0.062500
vt 0.437500 0.125000
vt 0.437500 0.187500
vt 0.437500 0.250000
vt 0.437500 0.312500
vt 0.437500 0.375000
vt 0.437500 0.062500
vt 0.500000 0.125000
vt 0.500000 0.187500
vt 0.500000 0.250000
vt 0.500000 0.312500
vt 0.500000 0.375000
vt 0.500000 0.062500
vt -0.000000 0.125000
vt 0.062500 0.125000
vt 0.062500 0.187500
vt -0.000000 0.187500
vt 0.062500 0.250000
vt -0.000000 0.250000
vt 0.062500 0.312500
vt -0.000000 0.312500
vt 0.062500 0.375000
vt -0.000000 0.375000
vt -0.000000 0.062500
vt 0.062500 0.062500
vt 0.125000 0.125000
vt 0.125000 0.187500
vt 0.125000 0.250000
vt 0.125000 0.312500
vt 0.125000 0.375000
vt 0.125000 0.062500
vt 0.750000 0.625000
vt 0.812500 0.625000
vt 0.812500 0.687500
vt 0.750000 0.687500
vt 0.750000 0.375000
vt 0.812500 0.375000
vt 0.812500 0.437500
vt 0.750000 0.437500
vt 0.812500 0.500000
vt 0.750000 0.500000
vt 0.812500 0.562500
vt 0.750000 0.562500
vt 0.875000 0.625000
vt 0.875000 0.687500
vt 0.875000 0.375000
vt 0.875000 0.437500
vt 0.875000 0.500000
vt 0.875000 0.562500
vt 0.937500 0.625000
vt 0.937500 0.687500
vt 0.937500 0.375000
vt 0.937500 0.437500
vt 0.937500 0.500000
vt 0.937500 0.562500
vt 1.000000 0.625000
vt 1.000000 0.687500
vt 1.000000 0.375000
vt 1.000000 0.437500
vt 1.000000 0.500000
vt 1.000000 0.562500
vt 0.500000 0.625000
vt 0.562500 0.625000
vt 0.562500 0.687500
vt 0.500000 0.687500
vt 0.562500 0.375000
vt 0.562500 0.437500
vt 0.500000 0.437500
vt 0.562500 0.500000
vt 0.500000 0.500000
vt 0.562500 0.562500
vt 0.500000 0.562500
vt 0.625000 0.625000
vt 0.625000 0.687500
vt 0.625000 0.375000
vt 0.625000 0.437500
vt 0.625000 0.500000
vt 0.625000 0.562500
vt 0.687500 0.625000
vt 0.687500 0.687500
vt 0.687500 0.375000
vt 0.687500 0.437500
vt 0.687500 0.500000
vt 0.687500 0.562500
vt 0.250000 0.625000
vt 0.312500 0.625000
vt 0.312500 0.687500
vt 0.250000 0.687500
vt 0.312500 0.437500
vt 0.250000 0.437500
vt 0.312500 0.500000
vt 0.250000 0.500000
vt 0.312500 0.562500
vt 0.250000 0.562500
vt 0.375000 0.625000
vt 0.375000 0.687500
vt 0.375000 0.437500
vt 0.375000 0.500000
vt 0.375000 0.562500
vt 0.437500 0.625000
vt 0.437500 0.687500
vt 0.437500 0.437500
vt 0.437500 0.500000
vt 0.437500 0.562500
vt -0.000000 0.625000
vt 0.062500 0.625000
vt 0.062500 0.687500
vt -0.000000 0.687500
vt 0.062500 0.437500
vt -0.000000 0.437500
vt 0.062500 0.500000
vt -0.000000 0.500000
vt 0.062500 0.562500
vt -0.000000 0.562500
vt 0.125000 0.625000
vt 0.125000 0.687500
vt 0.125000 0.437500
vt 0.125000 0.500000
vt 0.125000 0.562500
vt 0.187500 0.625000
vt 0.187500 0.687500
vt 0.187500 0.437500
vt 0.187500 0.500000
vt 0.187500 0.562500
vt 0.687500 0.750000
vt 0.750000 0.750000
vt 0.750000 0.812500
vt 0.687500 0.812500
vt 0.750000 0.875000
vt 0.687500 0.875000
vt 0.750000 0.937500
vt 0.687500 0.937500
vt 0.750000 1.000000
vt 0.687500 1.000000
vt 0.812500 0.750000
vt 0.812500 0.812500
vt 0.812500 0.875000
vt 0.812500 0.937500
vt 0.812500 1.000000
vt 0.875000 0.750000
vt 0.875000 0.812500
vt 0.875000 0.875000
vt 0.875000 0.937500
vt 0.875000 1.000000
vt 0.937500 0.750000
vt 0.937500 0.812500
vt 0.937500 0.875000
vt 0.937500 0.937500
vt 0.937500 1.000000
vt 1.000000 0.750000
vt 1.000000 0.812500
vt 1.000000 0.875000
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.500000 0.750000
vt 0.562500 0.750000
vt 0.562500 0.812500
vt 0.500000 0.812500
vt 0.562500 0.875000
vt 0.500000 0.875000
vt 0.562500 0.937500
vt 0.500000 0.937500
vt 0.562500 1.000000
vt 0.500000 1.000000
vt 0.625000 0.750000
vt 0.625000 0.812500
vt 0.625000 0.875000
vt 0.625000 0.937500
vt 0.625000 1.000000
vt 0.750000 0.312500
vt 0.812500 0.312500
vt 0.750000 0.062500
vt 0.812500 0.062500
vt 0.812500 0.125000
vt 0.750000 0.125000
vt 0.812500 0.187500
vt 0.750000 0.187500
vt 0.812500 0.250000
vt 0.750000 0.250000
vt 0.875000 0.312500
vt 0.875000 0.062500
vt 0.875000 0.125000
vt 0.875000 0.187500
vt 0.875000 0.250000
vt 0.937500 0.312500
vt 0.937500 0.062500
vt 0.937500 0.125000
vt 0.937500 0.187500
vt 0.937500 0.250000
vt 1.000000 0.312500
vt 1.000000 0.062500
vt 1.000000 0.125000
vt 1.000000 0.187500
vt 1.000000 0.250000
vt 0.562500 0.312500
vt 0.562500 0.062500
vt 0.562500 0.125000
vt 0.562500 0.187500
vt 0.562500 0.250000
vt 0.625000 0.312500
vt 0.625000 0.062500
vt 0.625000 0.125000
vt 0.625000 0.187500
vt 0.625000 0.250000
vt 0.687500 0.312500
vt 0.687500 0.062500
vt 0.687500 0.125000
vt 0.687500 0.187500
vt 0.687500 0.250000
vt 0.250000 0.937500
vt 0.312500 0.937500
vt 0.312500 1.000000
vt 0.250000 1.000000
vt 0.312500 0.750000
vt 0.250000 0.750000
vt 0.312500 0.812500
vt 0.250000 0.812500
vt 0.312500 0.875000
vt 0.250000 0.875000
vt 0.375000 0.937500
vt 0.375000 1.000000
vt 0.375000 0.750000
vt 0.375000 0.812500
vt 0.375000 0.875000
vt 0.437500 0.937500
vt 0.437500 1.000000
vt 0.437500 0.750000
vt 0.437500 0.812500
vt 0.437500 0.875000
vt 0.000000 0.937500
vt 0.062500 0.937500
vt 0.062500 1.000000
vt 0.000000 1.000000
vt 0.062500 0.750000
vt 0.000000 0.750000
vt 0.062500 0.812500
vt 0.000000 0.812500
vt 0.062500 0.875000
vt 0.000000 0.875000
vt 0.125000 0.937500
vt 0.125000 1.000000
vt 0.125000 0.750000
vt 0.125000 0.812500
vt 0.125000 0.875000
vt 0.187500 0.937500
vt 0.187500 1.000000
vt 0.187500 0.750000
vt 0.187500 0.812500
vt 0.187500 0.875000
vn 0.000000 -1.000000 -0.004800
vn 0.000000 -0.657400 0.753500
vn -0.898300 -0.248500 0.362300
vn -0.863600 -0.504100 -0.003400
vn -0.661500 0.421500 -0.620200
vn -0.746000 0.665900 0.000000
vn 0.661500 0.421500 -0.620200
vn 0.746000 0.665900 0.000000
vn 0.898300 -0.248500 0.362300
vn 0.863600 -0.504100 -0.003400
vn 0.000000 0.000000 1.000000
vn -0.925200 0.000000 0.379500
vn -0.617100 0.000000 -0.786900
vn 0.617100 0.000000 -0.786900
vn 0.925200 0.000000 0.379500
vn 0.000000 0.657400 0.753500
vn -0.898300 0.248400 0.362300
vn -0.661500 -0.421500 -0.620200
vn 0.661500 -0.421500 -0.620200
vn 0.898300 0.248400 0.362300
vn 0.000000 1.000000 0.000000
vn -0.866100 0.499800 0.000000
vn -0.746000 -0.665900 0.000000
vn 0.746000 -0.665900 0.000000
vn 0.866100 0.499800 0.000000
vn 0.000000 0.657400 -0.753500
vn -0.898300 0.248400 -0.362400
vn -0.661600 -0.421500 0.620200
vn 0.661500 -0.421500 0.620200
vn 0.898300 0.248400 -0.362300
vn 0.000000 -0.000900 -1.000000
vn -0.924600 -0.000600 -0.380700
vn -0.617100 0.000000 0.786900
vn 0.617100 0.000000 0.786900
vn 0.924700 -0.000600 -0.380700
vn 0.000000 -0.650300 -0.759600
vn -0.895600 -0.254600 -0.364800
vn -0.661600 0.421500 0.620200
vn 0.661600 0.421500 0.620200
vn 0.895600 -0.254600 -0.364800
vn 0.004900 -1.000000 0.000000
vn -0.729700 -0.683800 0.000000
vn -0.324500 -0.256300 -0.910500
vn 0.003300 -0.475500 -0.879700
vn 0.578700 0.436200 -0.689100
vn 0.000000 0.666600 -0.745400
vn 0.578700 0.436200 0.689100
vn 0.000000 0.666600 0.745400
vn -0.324500 -0.256300 0.910500
vn 0.003300 -0.475500 0.879700
vn -1.000000 0.000000 0.000000
vn -0.359600 0.000000 -0.933100
vn 0.756400 0.000000 -0.654100
vn 0.756400 0.000000 0.654100
vn -0.359600 0.000000 0.933100
vn -0.729700 0.683700 0.000000
vn -0.324500 0.256300 -0.910500
vn 0.578700 -0.436200 -0.689100
vn 0.578700 -0.436200 0.689100
vn -0.324500 0.256300 0.910500
vn 0.000000 0.470900 -0.882200
vn 0.000000 -0.666600 -0.745400
vn 0.000000 -0.666600 0.745400
vn 0.000000 0.470900 0.882200
vn 0.729700 0.683700 0.000000
vn 0.324500 0.256300 -0.910500
vn -0.578700 -0.436200 -0.689100
vn -0.578700 -0.436200 0.689100
vn 0.324500 0.256300 0.910500
vn 1.000000 -0.001100 0.000000
vn 0.361000 -0.000700 -0.932600
vn -0.756400 0.000000 -0.654100
vn -0.756400 0.000000 0.654100
vn 0.361000 -0.000700 0.932600
vn 0.736100 -0.676800 0.000000
vn 0.327100 -0.263100 -0.907600
vn -0.578700 0.436200 -0.689100
vn -0.578700 0.436200 0.689100
vn 0.327100 -0.263100 0.907600
vn -0.004900 -1.000000 0.000000
vn 0.729700 -0.683800 0.000000
vn 0.324500 -0.256300 0.910500
vn -0.003300 -0.475400 0.879700
vn 0.324500 -0.256300 -0.910500
vn -0.003300 -0.475400 -0.879700
vn 1.000000 0.000000 0.000000
vn 0.359600 0.000000 0.933100
vn 0.359600 0.000000 -0.933100
vn -1.000000 -0.001100 0.000000
vn -0.361000 -0.000700 0.932600
vn -0.361000 -0.000700 -0.932600
vn -0.736100 -0.676800 0.000000
vn -0.327100 -0.263100 0.907600
vn -0.327100 -0.263100 -0.907600
vn 0.000000 -1.000000 0.004800
vn 0.000000 -0.657400 -0.753500
vn 0.898300 -0.248500 -0.362400
vn 0.863600 -0.504100 0.003400
vn -0.898300 -0.248500 -0.362400
vn -0.863600 -0.504100 0.003400
vn 0.000000 0.000000 -1.000000
vn 0.925200 0.000000 -0.379500
vn -0.925200 0.000000 -0.379500
vn 0.898300 0.248500 -0.362400
vn 0.661600 -0.421500 0.620200
vn -0.898300 0.248500 -0.362400
vn 0.898300 0.248500 0.362300
vn -0.898300 0.248500 0.362300
vn 0.000000 -0.000900 1.000000
vn 0.924700 -0.000600 0.380700
vn -0.924700 -0.000600 0.380700
vn 0.000000 -0.650300 0.759600
vn 0.895600 -0.254600 0.364700
vn -0.895600 -0.254600 0.364700
vn 0.729700 -0.683700 0.000000
vn 0.729700 0.683800 0.000000
vn -0.729700 0.683800 0.000000
vn -0.898300 -0.248400 0.362300
vn -0.863600 -0.504100 -0.003500
vn 0.898300 -0.248400 0.362300
vn 0.863600 -0.504100 -0.003500
vn -0.661500 -0.421500 0.620200
vn 0.924600 -0.000600 -0.380700
vn -0.661500 0.421500 0.620200
vn 0.661500 0.421500 0.620200
s 1
f 1/1/1 2/2/2 3/3/3 4/4/4
f 4/4/4 3/3/3 5/5/5 6/6/6
f 6/6/6 5/5/5 7/7/7 8/8/8
f 8/8/8 7/7/7 9/9/9 10/10/10
f 1/1/1 10/11/10 9/12/9 2/2/2
f 2/2/2 11/13/11 12/14/12 3/3/3
f 3/3/3 12/14/12 13/15/13 5/5/5
f 5/5/5 13/15/13 14/16/14 7/7/7
f 7/7/7 14/16/14 15/17/15 9/9/9
f 9/12/9 15/18/15 11/13/11 2/2/2
f 11/13/11 16/19/16 17/20/17 12/14/12
f 12/14/12 17/20/17 18/21/18 13/15/13
f 13/15/13 18/21/18 19/22/19 14/16/14
f 14/16/14 19/22/19 20/23/20 15/17/15
f 15/18/15 20/24/20 16/19/16 11/13/11
f 16/19/16 21/25/21 22/26/22 17/20/17
f 17/20/17 22/26/22 23/27/23 18/21/18
f 18/21/18 23/27/23 24/28/24 19/22/19
f 19/22/19 24/28/24 25/29/25 20/23/20
f 20/24/20 25/30/25 21/25/21 16/19/16
f 21/25/21 26/31/26 27/32/27 22/26/22
f 22/26/22 27/32/27 28/33/28 23/27/23
f 23/27/23 28/33/28 29/34/29 24/28/24
f 24/28/24 29/34/29 30/35/30 25/29/25
f 25/30/25 30/36/30 26/31/26 21/25/21
f 26/37/26 31/38/31 32/39/32 27/40/27
f 27/40/27 32/39/32 33/41/33 28/42/28
f 28/42/28 33/41/33 34/43/34 29/44/29
f 29/44/29 34/43/34 35/45/35 30/46/30
f 30/47/30 35/48/35 31/38/31 26/37/26
f 31/38/31 36/49/36 37/50/37 32/39/32
f 32/39/32 37/50/37 38/51/38 33/41/33
f 33/41/33 38/51/38 39/52/39 34/43/34
f 34/43/34 39/52/39 40/53/40 35/45/35
f 35/48/35 40/54/40 36/49/36 31/38/31
f 36/49/36 1/1/1 4/4/4 37/50/37
f 37/50/37 4/4/4 6/6/6 38/51/38
f 38/51/38 6/6/6 8/8/8 39/52/39
f 39/52/39 8/8/8 10/10/10 40/53/40
f 1/1/1 36/49/36 40/54/40 10/11/10
f 41/55/41 42/56/42 43/57/43 44/58/44
f 44/59/44 43/60/43 45/61/45 46/62/46
f 46/62/46 45/61/45 47/63/47 48/64/48
f 48/64/48 47/63/47 49/65/49 50/66/50
f 41/55/41 50/66/50 49/65/49 42/56/42
f 42/56/42 51/67/51 52/68/52 43/57/43
f 43/60/43 52/69/52 53/70/53 45/61/45
f 45/61/45 53/70/53 54/71/54 47/63/47
f 47/63/47 54/71/54 55/72/55 49/65/49
f 49/65/49 55/72/55 51/67/51 42/56/42
f 51/67/51 56/73/56 57/74/57 52/68/52
f 52/69/52 57/75/57 58/76/58 53/70/53
f 53/70/53 58/76/58 59/77/59 54/71/54
f 54/71/54 59/77/59 60/78/60 55/72/55
f 55/72/55 60/78/60 56/73/56 51/67/51
f 56/73/56 61/79/21 62/80/61 57/74/57
f 57/75/57 62/81/61 63/82/62 58/76/58
f 58/76/58 63/82/62 64/83/63 59/77/59
f 59/77/59 64/83/63 65/84/64 60/78/60
f 60/78/60 65/84/64 61/79/21 56/73/56
f 61/85/21 66/86/65 67/87/66 62/88/61
f 62/35/61 67/89/66 68/90/67 63/91/62
f 63/91/62 68/90/67 69/92/68 64/93/63
f 64/93/63 69/92/68 70/94/69 65/95/64
f 65/95/64 70/94/69 66/86/65 61/85/21
f 66/86/65 71/96/70 72/97/71 67/87/66
f 67/89/66 72/98/71 73/99/72 68/90/67
f 68/90/67 73/99/72 74/100/73 69/92/68
f 69/92/68 74/100/73 75/101/74 70/94/69
f 70/94/69 75/101/74 71/96/70 66/86/65
f 71/96/70 76/102/75 77/103/76 72/97/71
f 72/98/71 77/104/76 78/105/77 73/99/72
f 73/99/72 78/105/77 79/106/78 74/100/73
f 74/100/73 79/106/78 80/107/79 75/101/74
f 75/101/74 80/107/79 76/102/75 71/96/70
f 76/102/75 41/55/41 44/58/44 77/103/76
f 77/104/76 44/59/44 46/62/46 78/105/77
f 78/105/77 46/62/46 48/64/48 79/106/78
f 79/106/78 48/64/48 50/66/50 80/107/79
f 41/55/41 76/102/75 80/107/79 50/66/50
f 81/108/80 82/109/81 83/110/82 84/111/83
f 84/9/83 83/17/82 85/112/78 86/113/48
f 86/113/48 85/112/78 87/114/77 88/115/46
f 88/115/46 87/114/77 89/116/84 90/117/85
f 81/108/80 90/117/85 89/116/84 82/109/81
f 82/109/81 91/118/86 92/119/87 83/110/82
f 83/17/82 92/23/87 93/120/73 85/112/78
f 85/112/78 93/120/73 94/121/72 87/114/77
f 87/114/77 94/121/72 95/122/88 89/116/84
f 89/116/84 95/122/88 91/118/86 82/109/81
f 91/118/86 96/123/65 97/124/69 92/119/87
f 92/23/87 97/29/69 98/125/68 93/120/73
f 93/120/73 98/125/68 99/126/67 94/121/72
f 94/121/72 99/126/67 100/127/66 95/122/88
f 95/122/88 100/127/66 96/123/65 91/118/86
f 96/123/65 101/85/21 102/88/64 97/124/69
f 97/29/69 102/35/64 103/91/63 98/125/68
f 98/125/68 103/91/63 104/93/62 99/126/67
f 99/126/67 104/93/62 105/95/61 100/127/66
f 100/127/66 105/95/61 101/85/21 96/123/65
f 101/128/21 106/129/56 107/130/60 102/131/64
f 102/46/64 107/45/60 108/132/59 103/133/63
f 103/133/63 108/132/59 109/134/58 104/135/62
f 104/135/62 109/134/58 110/136/57 105/137/61
f 105/137/61 110/136/57 106/129/56 101/128/21
f 106/129/56 111/138/89 112/139/90 107/130/60
f 107/45/60 112/53/90 113/140/54 108/132/59
f 108/132/59 113/140/54 114/141/53 109/134/58
f 109/134/58 114/141/53 115/142/91 110/136/57
f 110/136/57 115/142/91 111/138/89 106/129/56
f 111/138/89 116/143/92 117/144/93 112/139/90
f 112/53/90 117/10/93 118/145/47 113/140/54
f 113/140/54 118/145/47 119/146/45 114/141/53
f 114/141/53 119/146/45 120/147/94 115/142/91
f 115/142/91 120/147/94 116/143/92 111/138/89
f 116/143/92 81/108/80 84/111/83 117/144/93
f 117/10/93 84/9/83 86/113/48 118/145/47
f 118/145/47 86/113/48 88/115/46 119/146/45
f 119/146/45 88/115/46 90/117/85 120/147/94
f 81/108/80 116/143/92 120/147/94 90/117/85
f 121/148/95 122/149/96 123/150/97 124/151/98
f 124/151/98 123/150/97 125/152/39 126/153/8
f 126/153/8 125/152/39 127/154/38 128/155/6
f 128/155/6 127/154/38 129/156/99 130/157/100
f 121/148/95 130/103/100 129/58/99 122/149/96
f 122/149/96 131/158/101 132/159/102 123/150/97
f 123/150/97 132/159/102 133/160/34 125/152/39
f 125/152/39 133/160/34 134/161/33 127/154/38
f 127/154/38 134/161/33 135/162/103 129/156/99
f 129/58/99 135/57/103 131/158/101 122/149/96
f 131/158/101 136/163/26 137/164/104 132/159/102
f 132/159/102 137/164/104 138/165/105 133/160/34
f 133/160/34 138/165/105 139/166/28 134/161/33
f 134/161/33 139/166/28 140/167/106 135/162/103
f 135/57/103 140/68/106 136/163/26 131/158/101
f 136/163/26 141/168/21 142/169/25 137/164/104
f 137/164/104 142/169/25 143/170/24 138/165/105
f 138/165/105 143/170/24 144/171/23 139/166/28
f 139/166/28 144/171/23 145/172/22 140/167/106
f 140/68/106 145/74/22 141/168/21 136/163/26
f 141/168/21 146/173/16 147/174/107 142/169/25
f 142/169/25 147/174/107 148/175/19 143/170/24
f 143/170/24 148/175/19 149/176/18 144/171/23
f 144/171/23 149/176/18 150/177/108 145/172/22
f 145/74/22 150/80/108 146/173/16 141/168/21
f 146/178/16 151/179/109 152/180/110 147/181/107
f 147/181/107 152/180/110 153/182/14 148/183/19
f 148/183/19 153/182/14 154/184/13 149/185/18
f 149/185/18 154/184/13 155/186/111 150/187/108
f 150/88/108 155/87/111 151/179/109 146/178/16
f 151/179/109 156/188/112 157/189/113 152/180/110
f 152/180/110 157/189/113 158/190/7 153/182/14
f 153/182/14 158/190/7 159/191/5 154/184/13
f 154/184/13 159/191/5 160/192/114 155/186/111
f 155/87/111 160/97/114 156/188/112 151/179/109
f 156/188/112 121/148/95 124/151/98 157/189/113
f 157/189/113 124/151/98 126/153/8 158/190/7
f 158/190/7 126/153/8 128/155/6 159/191/5
f 159/191/5 128/155/6 130/157/100 160/192/114
f 121/148/95 156/188/112 160/97/114 130/103/100
f 161/193/80 162/194/115 163/60/82 164/59/83
f 164/195/83 163/196/82 165/197/78 166/198/48
f 166/198/48 165/197/78 167/199/77 168/200/46
f 168/200/46 167/199/77 169/201/84 170/202/85
f 161/193/80 170/202/85 169/201/84 162/194/115
f 162/194/115 171/203/86 172/69/87 163/60/82
f 163/196/82 172/204/87 173/205/73 165/197/78
f 165/197/78 173/205/73 174/206/72 167/199/77
f 167/199/77 174/206/72 175/207/88 169/201/84
f 169/201/84 175/207/88 171/203/86 162/194/115
f 171/203/86 176/208/116 177/75/69 172/69/87
f 172/204/87 177/209/69 178/210/68 173/205/73
f 173/205/73 178/210/68 179/211/67 174/206/72
f 174/206/72 179/211/67 180/212/66 175/207/88
f 175/207/88 180/212/66 176/208/116 171/203/86
f 176/208/116 181/213/21 182/81/64 177/75/69
f 177/209/69 182/214/64 183/215/63 178/210/68
f 178/210/68 183/215/63 184/216/62 179/211/67
f 179/211/67 184/216/62 185/217/61 180/212/66
f 180/212/66 185/217/61 181/213/21 176/208/116
f 181/34/21 186/218/117 187/89/60 182/35/64
f 182/36/64 187/219/60 188/220/59 183/31/63
f 183/31/63 188/220/59 189/221/58 184/32/62
f 184/32/62 189/221/58 190/222/57 185/33/61
f 185/33/61 190/222/57 186/218/117 181/34/21
f 186/218/117 191/223/89 192/98/90 187/89/60
f 187/219/60 192/224/90 193/225/54 188/220/59
f 188/220/59 193/225/54 194/226/53 189/221/58
f 189/221/58 194/226/53 195/227/91 190/222/57
f 190/222/57 195/227/91 191/223/89 186/218/117
f 191/223/89 196/228/92 197/104/93 192/98/90
f 192/224/90 197/229/93 198/230/47 193/225/54
f 193/225/54 198/230/47 199/231/45 194/226/53
f 194/226/53 199/231/45 200/232/94 195/227/91
f 195/227/91 200/232/94 196/228/92 191/223/89
f 196/228/92 161/193/80 164/59/83 197/104/93
f 197/229/93 164/195/83 166/198/48 198/230/47
f 198/230/47 166/198/48 168/200/46 199/231/45
f 199/231/45 168/200/46 170/202/85 200/232/94
f 161/193/80 196/228/92 200/232/94 170/202/85
f 201/233/1 202/234/2 203/235/118 204/236/119
f 204/111/119 203/110/118 205/237/5 206/238/6
f 206/238/6 205/237/5 207/239/7 208/240/8
f 208/240/8 207/239/7 209/241/120 210/242/121
f 201/233/1 210/242/121 209/241/120 202/234/2
f 202/234/2 211/243/11 212/244/12 203/235/118
f 203/110/118 212/119/12 213/245/13 205/237/5
f 205/237/5 213/245/13 214/246/14 207/239/7
f 207/239/7 214/246/14 215/247/15 209/241/120
f 209/241/120 215/247/15 211/243/11 202/234/2
f 211/243/11 216/248/16 217/249/108 212/244/12
f 212/119/12 217/124/108 218/250/18 213/245/13
f 213/245/13 218/250/18 219/251/19 214/246/14
f 214/246/14 219/251/19 220/252/107 215/247/15
f 215/247/15 220/252/107 216/248/16 211/243/11
f 216/248/16 221/185/21 222/187/22 217/249/108
f 217/124/108 222/88/22 223/178/23 218/250/18
f 218/250/18 223/178/23 224/181/24 219/251/19
f 219/251/19 224/181/24 225/183/25 220/252/107
f 220/252/107 225/183/25 221/185/21 216/248/16
f 221/253/21 226/254/26 227/255/106 222/256/22
f 222/131/22 227/130/106 228/257/122 223/258/23
f 223/258/23 228/257/122 229/259/29 224/260/24
f 224/260/24 229/259/29 230/261/104 225/262/25
f 225/262/25 230/261/104 226/254/26 221/253/21
f 226/254/26 231/263/31 232/264/32 227/255/106
f 227/130/106 232/139/32 233/265/33 228/257/122
f 228/257/122 233/265/33 234/266/34 229/259/29
f 229/259/29 234/266/34 235/267/123 230/261/104
f 230/261/104 235/267/123 231/263/31 226/254/26
f 231/263/31 236/268/36 237/269/37 232/264/32
f 232/139/32 237/144/37 238/270/124 233/265/33
f 233/265/33 238/270/124 239/271/125 234/266/34
f 234/266/34 239/271/125 240/272/40 235/267/123
f 235/267/123 240/272/40 236/268/36 231/263/31
f 236/268/36 201/233/1 204/236/119 237/269/37
f 237/144/37 204/111/119 206/238/6 238/270/124
f 238/270/124 206/238/6 208/240/8 239/271/125
f 239/271/125 208/240/8 210/242/121 240/272/40
f 201/233/1 236/268/36 240/272/40 210/242/121

View File

@ -1,56 +0,0 @@
-- Translation support
local S = minetest.get_translator("basic_materials")
-- items
minetest.register_craftitem("basic_materials:plastic_sheet", {
description = S("Plastic sheet"),
inventory_image = "basic_materials_plastic_sheet.png",
})
minetest.register_craftitem("basic_materials:plastic_strip", {
description = S("Plastic strips"),
groups = { strip = 1 },
inventory_image = "basic_materials_plastic_strip.png",
})
minetest.register_craftitem("basic_materials:empty_spool", {
description = S("Empty wire spool"),
inventory_image = "basic_materials_empty_spool.png"
})
-- crafts
minetest.register_craft({
type = "cooking",
output = "basic_materials:plastic_sheet",
recipe = "basic_materials:paraffin",
})
minetest.register_craft({
type = "fuel",
recipe = "basic_materials:plastic_sheet",
burntime = 30,
})
minetest.register_craft( {
output = "basic_materials:plastic_strip 9",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" }
},
})
minetest.register_craft( {
output = "basic_materials:empty_spool 3",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ "", "basic_materials:plastic_sheet", "" },
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" }
},
})
-- aliases
minetest.register_alias("homedecor:plastic_sheeting", "basic_materials:plastic_sheet")
minetest.register_alias("homedecor:plastic_strips", "basic_materials:plastic_strip")
minetest.register_alias("homedecor:empty_spool", "basic_materials:empty_spool")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 B

View File

@ -54,7 +54,7 @@ minetest.register_on_shutdown(function()
end) end)
-- delete data base entries without corresponding nodes -- delete data base entries without corresponding nodes
minetest.after(5, check_data_base) --minetest.after(5, check_data_base)
-- store data after one hour -- store data after one hour
minetest.after(60*60, update_mod_storage) minetest.after(60*60, update_mod_storage)

View File

@ -35,13 +35,14 @@
2020-03-12 v2.05 minetest translator added (thanks to acmgit/Clyde) 2020-03-12 v2.05 minetest translator added (thanks to acmgit/Clyde)
2020-06-14 v2.06 The default value for `hyperloop_free_tube_placement_enabled` is now true 2020-06-14 v2.06 The default value for `hyperloop_free_tube_placement_enabled` is now true
2021-02-07 v2.07 tube_crowbar: Add tube length check 2021-02-07 v2.07 tube_crowbar: Add tube length check
2021-11-01 v2.08 Enable the use of hyperloop networks for other mods
]]-- ]]--
hyperloop = {} hyperloop = {}
-- Version for compatibility checks, see history -- Version for compatibility checks, see history
hyperloop.version = 2.06 hyperloop.version = 2.08
if minetest.global_exists("techage") and techage.version < 0.06 then if minetest.global_exists("techage") and techage.version < 0.06 then
error("[hyperloop] Hyperloop requires techage version 0.06 or newer!") error("[hyperloop] Hyperloop requires techage version 0.06 or newer!")
@ -71,7 +72,7 @@ else
hyperloop.wifi_enabled = minetest.settings:get_bool("hyperloop_wifi_enabled") hyperloop.wifi_enabled = minetest.settings:get_bool("hyperloop_wifi_enabled")
hyperloop.wifi_crafting_enabled = minetest.settings:get_bool("hyperloop_wifi_crafting_enabled") hyperloop.wifi_crafting_enabled = minetest.settings:get_bool("hyperloop_wifi_crafting_enabled")
hyperloop.free_tube_placement_enabled = minetest.settings:get_bool("hyperloop_free_tube_placement_enabled", true) hyperloop.free_tube_placement_enabled = minetest.settings:get_bool("hyperloop_free_tube_placement_enabled", true)
hyperloop.subnet_enabled = minetest.settings:get_bool("hyperloop_subnet_enabled") hyperloop.subnet_enabled = minetest.settings:get_bool("hyperloop_subnet_enabled", true)
dofile(minetest.get_modpath("hyperloop") .. "/network.lua") dofile(minetest.get_modpath("hyperloop") .. "/network.lua")
dofile(minetest.get_modpath("hyperloop") .. "/data_base.lua") dofile(minetest.get_modpath("hyperloop") .. "/data_base.lua")

View File

@ -28,12 +28,18 @@ Tube:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
if out_dir <= 5 then if out_dir <= 5 then
Stations:update_connections(pos, out_dir, peer_pos) Stations:update_connections(pos, out_dir, peer_pos)
local s = hyperloop.get_connection_string(pos) local s = hyperloop.get_connection_string(pos)
M(pos):set_string("infotext", S("Station connected with ")..s) M(pos):set_string("infotext", S("Station connected to ")..s)
end end
elseif node.name == "hyperloop:junction" then elseif node.name == "hyperloop:junction" then
Stations:update_connections(pos, out_dir, peer_pos) Stations:update_connections(pos, out_dir, peer_pos)
local s = hyperloop.get_connection_string(pos) local s = hyperloop.get_connection_string(pos)
M(pos):set_string("infotext", S("Junction connected with ")..s) M(pos):set_string("infotext", S("Junction connected to ")..s)
elseif Tube.secondary_node_names[node.name] then
if out_dir == 5 then
Stations:update_connections(pos, out_dir, peer_pos)
local s = hyperloop.get_connection_string(pos)
M(pos):set_string("conn_to", s)
end
end end
end) end)

View File

@ -57,8 +57,8 @@ Save=Speichern
### junction.lua ### ### junction.lua ###
Station connected with =Station verbunden mit Station connected to =Station verbunden mit
Junction connected with =Anschlussstelle verbunden mit Junction connected to =Anschlussstelle verbunden mit
Hyperloop Junction Block=Hyperloop Anschlussstelle Hyperloop Junction Block=Hyperloop Anschlussstelle
Hyperloop Pillar=Hyperloop Stütze Hyperloop Pillar=Hyperloop Stütze
@ -77,7 +77,7 @@ Dist.=Entf.
Station/Junction=Station/Anschlussstelle Station/Junction=Station/Anschlussstelle
Position=Position Position=Position
Owner=Besitzer Owner=Besitzer
Conn. with=Verb. mit Conn. to=Verb. mit
Close=Schließen Close=Schließen
Hyperloop Station Book=Hyperloop Stationsbuch Hyperloop Station Book=Hyperloop Stationsbuch

View File

@ -37,7 +37,7 @@ local function generate_string(sortedList)
"label[1.8,0;"..S("Station/Junction").."]".. "label[1.8,0;"..S("Station/Junction").."]"..
"label[5.4,0;"..S("Position").."]".. "label[5.4,0;"..S("Position").."]"..
"label[7.9,0;"..S("Owner").."]".. "label[7.9,0;"..S("Owner").."]"..
"label[10,0;"..S("Conn. with").."]"} "label[10,0;"..S("Conn. to").."]"}
for idx,dataSet in ipairs(sortedList) do for idx,dataSet in ipairs(sortedList) do
if idx == 23 then if idx == 23 then
break break

View File

@ -278,3 +278,11 @@ function Network:serialize()
return minetest.serialize(self) return minetest.serialize(self)
end end
-- Return a pos/item table with all network nodes, the node at pos is connected with
function Network:get_node_table(pos)
local tRes = {}
local key = S(pos)
get_stations(self.tStations, key, tRes)
tRes[key] = nil
return tRes
end

View File

@ -12,4 +12,4 @@ hyperloop_free_tube_placement_enabled (free tube placement enabled) bool false
# The ticket block has an additional field for specifying a subnet name. # The ticket block has an additional field for specifying a subnet name.
# Stations with the same subnet name (optional) represent an isolated # Stations with the same subnet name (optional) represent an isolated
# subnet within the Hyperloop network. # subnet within the Hyperloop network.
hyperloop_subnet_enabled (enable building of subnets) bool false hyperloop_subnet_enabled (enable building of subnets) bool true

View File

@ -256,7 +256,12 @@ function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID)
if not minecart.is_rail(pos) then if not minecart.is_rail(pos) then
pos2 = minetest.find_node_near(pos, 1, minecart.lRails) pos2 = minetest.find_node_near(pos, 1, minecart.lRails)
if not pos2 or not minecart.is_rail(pos2) then if not pos2 or not minecart.is_rail(pos2) then
pos2 = minetest.find_node_near(pos, 2, minecart.lRails) -- If no rail is around, use an available cart as new search center
pos2 = minetest.find_node_near(pos, 1, minecart.lRailsExt)
-- ...and search again.
if pos2 then
pos2 = minetest.find_node_near(pos2, 1, minecart.lRails)
end
end end
else else
pos2 = vector.new(pos) pos2 = vector.new(pos)

View File

@ -217,9 +217,20 @@ local function on_step(self, dtime)
recording_waypoints(self) recording_waypoints(self)
self.rec_time = self.rec_time + 2.0 self.rec_time = self.rec_time + 2.0
end end
recording_junctions(self) if recording_junctions(self) then
local pos = vector.round(self.object:get_pos())
minecart.stop_recording(self, pos, true)
local player = minetest.get_player_by_name(self.driver)
minecart.manage_attachment(player, self, false)
minecart.entity_to_node(pos, self)
end
else else
player_ctrl(self) if player_ctrl(self) then
local pos = vector.round(self.object:get_pos())
local player = minetest.get_player_by_name(self.driver)
minecart.manage_attachment(player, self, false)
minecart.entity_to_node(pos, self)
end
end end
end end
end end
@ -241,7 +252,7 @@ local function on_entitycard_punch(self, puncher, time_from_last_punch, tool_cap
-- Dig cart -- Dig cart
if self.driver then if self.driver then
-- remove cart as driver -- remove cart as driver
minecart.stop_recording(self, pos) minecart.stop_recording(self, pos, true)
minecart.monitoring_remove_cart(self.owner, self.userID) minecart.monitoring_remove_cart(self.owner, self.userID)
minecart.remove_entity(self, pos, puncher) minecart.remove_entity(self, pos, puncher)
minecart.manage_attachment(puncher, self, false) minecart.manage_attachment(puncher, self, false)
@ -273,12 +284,13 @@ local function on_entitycard_rightclick(self, clicker)
if self.driver then if self.driver then
-- get off -- get off
local pos = vector.round(self.object:get_pos()) local pos = vector.round(self.object:get_pos())
minecart.stop_recording(self, pos, true)
minecart.manage_attachment(clicker, self, false) minecart.manage_attachment(clicker, self, false)
minecart.entity_to_node(pos, self) minecart.entity_to_node(pos, self)
else else
-- get on -- get on
local pos = vector.round(self.object:get_pos()) local pos = vector.round(self.object:get_pos())
minecart.stop_recording(self, pos) minecart.stop_recording(self, pos, true)
minecart.manage_attachment(clicker, self, true) minecart.manage_attachment(clicker, self, true)
end end
end end

View File

@ -213,7 +213,9 @@ function minecart.monitoring_remove_cart(owner, userID)
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then
-- Cart stopped? -- Cart stopped?
if tCartsOnRail[owner][userID].objID == 0 then if tCartsOnRail[owner][userID].objID == 0 then
-- Can directly be deleted -- Mark as "to be deleted" by monitoring (if part of monitoring)
tCartsOnRail[owner][userID].objID = nil
-- And delete directly in addition
tCartsOnRail[owner][userID] = nil tCartsOnRail[owner][userID] = nil
else -- Cart running else -- Cart running
-- Mark as "to be deleted" by monitoring -- Mark as "to be deleted" by monitoring
@ -292,7 +294,7 @@ minetest.register_chatcommand("stopcart", {
minecart.remove_entity(entity, data.pos) minecart.remove_entity(entity, data.pos)
else else
-- Cart as zombie/invalid/corrupted -- Cart as zombie/invalid/corrupted
-- nothing to do minetest.log("warning", "[Minecart] data.objID ~= 0, but no entity available!")
end end
minetest.add_item(player_pos, ItemStack({name = data.node_name})) minetest.add_item(player_pos, ItemStack({name = data.node_name}))
minecart.monitoring_remove_cart(owner, userID) minecart.monitoring_remove_cart(owner, userID)

View File

@ -103,12 +103,14 @@ function minecart.start_recording(self, pos)
end end
end end
function minecart.stop_recording(self, pos) function minecart.stop_recording(self, pos, force_exit)
--print("stop_recording") --print("stop_recording")
if self.driver and self.is_recording then if self.driver and self.is_recording then
local dest_pos = minecart.get_buffer_pos(pos, self.driver) local dest_pos = minecart.get_buffer_pos(pos, self.driver)
local player = minetest.get_player_by_name(self.driver) local player = minetest.get_player_by_name(self.driver)
if dest_pos and player and #self.checkpoints > 3 then if force_exit then
minetest.chat_send_player(self.driver, S("[minecart] Recording canceled!"))
elseif dest_pos and player and #self.checkpoints > 3 then
-- Remove last checkpoint, because it is potentially too close to the dest_pos -- Remove last checkpoint, because it is potentially too close to the dest_pos
table.remove(self.checkpoints) table.remove(self.checkpoints)
if self.start_pos then if self.start_pos then
@ -163,6 +165,8 @@ function minecart.recording_junctions(self)
self.ctrl = {right = true} self.ctrl = {right = true}
elseif ctrl.up or ctrl.down then elseif ctrl.up or ctrl.down then
self.ctrl = nil self.ctrl = nil
elseif ctrl.jump then
return true
end end
end end
if self.hud_time <= self.timebase then if self.hud_time <= self.timebase then
@ -186,6 +190,8 @@ function minecart.player_ctrl(self)
self.ctrl = {left = true} self.ctrl = {left = true}
elseif ctrl.right then elseif ctrl.right then
self.ctrl = {right = true} self.ctrl = {right = true}
elseif ctrl.jump then
return true
end end
end end
end end

View File

@ -57,8 +57,8 @@ minetest.register_on_mods_loaded(function()
-- mark all entity carts as zombified -- mark all entity carts as zombified
if cart.objID ~= 0 then if cart.objID ~= 0 then
cart.objID = -1 cart.objID = -1
minecart.push(1, cart)
end end
minecart.push(1, cart)
end end
end end
end end

View File

@ -61,11 +61,14 @@ local BASE_ENV = {
if separator == "" then separator = " " end if separator == "" then separator = " " end
return safer_lua.Array(unpack(string.split(str, separator, include_empty, max_splits, sep_is_pattern))) return safer_lua.Array(unpack(string.split(str, separator, include_empty, max_splits, sep_is_pattern)))
end, end,
split2 = function(str, separator, include_empty, max_splits, sep_is_pattern)
if separator == "" then separator = " " end
return unpack(string.split(str, separator, include_empty, max_splits, sep_is_pattern))
end,
trim = string.trim, trim = string.trim,
}, },
tonumber = tonumber, tonumber = tonumber,
tostring = tostring, tostring = tostring,
unpack = unpack,
type = type, type = type,
ticks = 0, ticks = 0,
} }

View File

@ -15,7 +15,7 @@
safer_lua = {} safer_lua = {}
-- Version for compatibility checks, see readme.md/history -- Version for compatibility checks, see readme.md/history
safer_lua.version = 1.0 safer_lua.version = 1.01
dofile(minetest.get_modpath("safer_lua") .. "/data_struct.lua") dofile(minetest.get_modpath("safer_lua") .. "/data_struct.lua")
dofile(minetest.get_modpath("safer_lua") .. "/scanner.lua") dofile(minetest.get_modpath("safer_lua") .. "/scanner.lua")

View File

@ -8,7 +8,7 @@ A subset of the language Lua for safe and secure Lua sandboxes with:
- limited posibilities to call functions - limited posibilities to call functions
### License ### License
Copyright (C) 2018-2020 Joachim Stolberg Copyright (C) 2018-2021 Joachim Stolberg
Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt
@ -18,3 +18,4 @@ none
### History ### History
- 2018-06-24 v0.01 * first draft - 2018-06-24 v0.01 * first draft
- 2020-03-14 v1.00 * extracted from TechPack and released - 2020-03-14 v1.00 * extracted from TechPack and released
- 2021-11-28 v1.01 * function `string.split2` added, `unpack` removed

View File

@ -199,6 +199,12 @@ function signs_bot.infotext(pos, state)
meta:set_string("infotext", S("Robot Box").." "..number..": "..state) meta:set_string("infotext", S("Robot Box").." "..number..": "..state)
end end
local function free_start_pos(pos, mem)
local param2 = (minetest.get_node(pos).param2 + 1) % 4
local robot_pos = lib.next_pos(pos, param2, 1)
return signs_bot.lib.is_air_like(robot_pos)
end
local function reset_robot(pos, mem) local function reset_robot(pos, mem)
mem.robot_param2 = (minetest.get_node(pos).param2 + 1) % 4 mem.robot_param2 = (minetest.get_node(pos).param2 + 1) % 4
mem.robot_pos = lib.next_pos(pos, mem.robot_param2, 1) mem.robot_pos = lib.next_pos(pos, mem.robot_param2, 1)
@ -208,24 +214,26 @@ end
function signs_bot.start_robot(base_pos) function signs_bot.start_robot(base_pos)
local mem = tubelib2.get_mem(base_pos) local mem = tubelib2.get_mem(base_pos)
mem.steps = nil if free_start_pos(base_pos, mem) then
mem.script = "cond_move" mem.steps = nil
local meta = M(base_pos) mem.script = "cond_move"
signs_bot.reset(base_pos, mem) local meta = M(base_pos)
mem.running = true signs_bot.reset(base_pos, mem)
mem.charging = false mem.running = true
mem.error = false mem.charging = false
mem.stored_node = nil mem.error = false
if minetest.global_exists("techage") then mem.stored_node = nil
mem.capa = mem.capa or 0 -- enable power consumption if minetest.global_exists("techage") then
else mem.capa = mem.capa or 0 -- enable power consumption
mem.capa = nil else
mem.capa = nil
end
meta:set_string("formspec", formspec(base_pos, mem))
signs_bot.infotext(base_pos, S("running"))
reset_robot(base_pos, mem)
minetest.get_node_timer(base_pos):start(CYCLE_TIME)
return true
end end
meta:set_string("formspec", formspec(base_pos, mem))
signs_bot.infotext(base_pos, S("running"))
reset_robot(base_pos, mem)
minetest.get_node_timer(base_pos):start(CYCLE_TIME)
return true
end end
function signs_bot.stop_robot(base_pos, mem) function signs_bot.stop_robot(base_pos, mem)

View File

@ -239,17 +239,19 @@ signs_bot.register_botcommand("drop_items", {
end, end,
}) })
signs_bot.register_botcommand("punch_cart", { if minetest.global_exists("minecart") then
mod = "item", signs_bot.register_botcommand("punch_cart", {
params = "", mod = "item",
num_param = 0, params = "",
description = S("Punch a rail cart to start it"), num_param = 0,
cmnd = function(base_pos, mem) description = S("Punch a rail cart to start it"),
local punch_dir = minetest.facedir_to_dir(mem.robot_param2) cmnd = function(base_pos, mem)
minecart.punch_cart(mem.robot_pos, mem.robot_param2, 1, punch_dir) local punch_dir = minetest.facedir_to_dir(mem.robot_param2)
return signs_bot.DONE minecart.punch_cart(mem.robot_pos, mem.robot_param2, 1, punch_dir)
end, return signs_bot.DONE
}) end,
})
end
-- def is a table with following data: -- def is a table with following data:
-- { -- {

View File

@ -65,7 +65,9 @@ dofile(MP.."/nodes.lua")
dofile(MP.."/bot_sensor.lua") dofile(MP.."/bot_sensor.lua")
dofile(MP.."/node_sensor.lua") dofile(MP.."/node_sensor.lua")
dofile(MP.."/crop_sensor.lua") dofile(MP.."/crop_sensor.lua")
dofile(MP.."/cart_sensor.lua") if minetest.global_exists("minecart") then
dofile(MP.."/cart_sensor.lua")
end
dofile(MP.."/chest.lua") dofile(MP.."/chest.lua")
dofile(MP.."/legacy.lua") dofile(MP.."/legacy.lua")
dofile(MP.."/techage.lua") dofile(MP.."/techage.lua")

View File

@ -195,7 +195,7 @@ minetest.register_craft({
} }
}) })
if minetest.get_modpath("minecart") then if minetest.global_exists("minecart") then
register_sign({ register_sign({
name = "sign_add_cart", name = "sign_add_cart",
description = S('Sign "add to cart"'), description = S('Sign "add to cart"'),
@ -273,7 +273,7 @@ if minetest.get_modpath("doc") then
}) })
end end
if minetest.get_modpath("doc") and minetest.get_modpath("minecart") then if minetest.get_modpath("doc") and minetest.global_exists("minecart") then
doc.add_entry("signs_bot", "sign_add_cart", { doc.add_entry("signs_bot", "sign_add_cart", {
name = S('Sign "add to cart"'), name = S('Sign "add to cart"'),
data = { data = {

View File

@ -1,6 +1,6 @@
# Tech Age [techage] (Minetest 5.3+) # Tech Age [techage] (Minetest 5.4+)
Tech Age, a mod to go through 4 tech ages in search of wealth and power. Tech Age, a mod to go through 5 tech ages in search of wealth and power.
**Tech Age (techage) is the successor to TechPack V2, at first glance similar and yet completely different!** **Tech Age (techage) is the successor to TechPack V2, at first glance similar and yet completely different!**
@ -11,13 +11,12 @@ Tech Age, a mod to go through 4 tech ages in search of wealth and power.
Important facts: Important facts:
- techage is not backwards compatible and cannot be installed on a server together with TechPack - 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 is significantly more extensive, since additional mods are integrated
- techage represents 4 technological ages: - techage represents 5 technological ages:
- Iron Age (TA1) - simple tools like coal pile, coal burner, gravel sieve, hammer for getting ores and making goods - 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 - 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. - Oil Age (TA3) - More modern machines that are powered by electricity.
The electricity is generated by coal & oil power plants. The oil must be explored, extracted and transported. - Present (TA4) - Electricity from renewable energy sources such as sun and wind.
- Future Age (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.
Environmentally friendly electricity storage, intelligent machines and means of transport of the future
- Since the levels build on each other, all ages have to be run through one after the other - 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. In contrast to TechPack, the resources are more limited and it is much more difficult to pass all levels.
@ -81,6 +80,20 @@ Available worlds will be converted to 'lsqlite3', but there is no way back, so:
### History ### History
**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** **2021-10-24 V1.03**
- Add TA4 Sequencer for time controlled command sequences - Add TA4 Sequencer for time controlled command sequences
- Add TA4 Move Controller for moving blocks - Add TA4 Move Controller for moving blocks

View File

@ -189,6 +189,17 @@ local function normalize(item_list)
return item_list return item_list
end 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) local function on_output_change(pos, inventory, stack)
if not stack then if not stack then
inventory:set_list("output", {}) inventory:set_list("output", {})
@ -212,6 +223,47 @@ local function on_output_change(pos, inventory, stack)
after_recipe_change(pos, inventory) after_recipe_change(pos, inventory)
end end
local function determine_recipe_items(pos, input)
if input and type(input) == "string" then
-- Test if "<node-number>.<recipe-number>" input
local num, idx = unpack(string.split(input, ".", false, 1))
if num and idx then
input = get_input_from_recipeblock(pos, num, idx)
end
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)
if items then
input = {
method = "normal",
width = 3,
items = items,
}
local output, _ = minetest.get_craft_result(input)
if output.item:get_name() ~= "" then
local inv = M(pos):get_inventory()
for i = 1, 9 do
inv:set_stack("recipe", i, input.items[i])
end
after_recipe_change(pos, inv)
end
else
local inv = M(pos):get_inventory()
inv:set_list("recipe", {})
after_recipe_change(pos, inv)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player) local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then if minetest.is_protected(pos, player:get_player_name()) then
@ -346,6 +398,8 @@ tiles.act = {
}, },
} }
local INFO = [[Commands: 'state', 'recipe']]
local tubing = { local tubing = {
on_inv_request = function(pos, in_dir, access_type) on_inv_request = function(pos, in_dir, access_type)
if access_type == "push" then if access_type == "push" then
@ -378,7 +432,20 @@ local tubing = {
end end
end, end,
on_recv_message = function(pos, src, topic, payload) on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload) if topic == "recipe" and CRD(pos).stage == 4 then
if payload and payload ~= "" then
local inv = M(pos):get_inventory()
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 == "info" and CRD(pos).stage == 4 then
return INFO
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end, end,
on_node_load = function(pos) on_node_load = function(pos)
CRD(pos).State:on_node_load(pos) CRD(pos).State:on_node_load(pos)
@ -410,7 +477,7 @@ local node_name_ta2, node_name_ta3, node_name_ta4 =
num_items = {0,1,2,4}, num_items = {0,1,2,4},
power_consumption = {0,4,6,9}, power_consumption = {0,4,6,9},
}, },
{false, true, true, false}) -- TA2/TA3 {false, true, true, true}) -- TA2/TA3/TA4
minetest.register_craft({ minetest.register_craft({
output = node_name_ta2, output = node_name_ta2,
@ -430,9 +497,18 @@ minetest.register_craft({
}, },
}) })
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:diamond", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
local Cable = techage.ElectricCable local Cable = techage.ElectricCable
local power = networks.power local power = networks.power
techage.register_node_for_v1_transition({"techage:ta3_autocrafter_pas"}, function(pos, node) techage.register_node_for_v1_transition({"techage:ta3_autocrafter_pas", "techage:ta4_autocrafter_pas"}, function(pos, node)
power.update_network(pos, nil, Cable) power.update_network(pos, nil, Cable)
end) end)

View File

@ -45,6 +45,7 @@ end
local function after_dig_node(pos, oldnode, oldmetadata, digger) local function after_dig_node(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata) techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end end
local function formspec2() local function formspec2()

View File

@ -3,14 +3,14 @@
TechAge TechAge
======= =======
Copyright (C) 2019-2020 Joachim Stolberg Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3 AGPL v3
See LICENSE.txt for more information See LICENSE.txt for more information
Consumer node basis functionality. Consumer node basis functionality.
It handles: It handles:
- up to 3 stages of nodes (TA2/TA3/TA4) - up to 4 stages of nodes (TA2/TA3/TA4/TA5)
- power consumption - power consumption
- node state handling - node state handling
- registration of passive and active nodes - registration of passive and active nodes
@ -119,7 +119,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
if not node_name_prefix then if not node_name_prefix then
node_name_prefix = "techage:ta" node_name_prefix = "techage:ta"
end end
for stage = 2,4 do for stage = 2,5 do
local name_pas = node_name_prefix..stage.."_"..base_name.."_pas" local name_pas = node_name_prefix..stage.."_"..base_name.."_pas"
local name_act = node_name_prefix..stage.."_"..base_name.."_act" local name_act = node_name_prefix..stage.."_"..base_name.."_act"
local name_inv = "TA"..stage.." "..inv_name local name_inv = "TA"..stage.." "..inv_name
@ -178,6 +178,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
meta:set_int("push_dir", techage.side_to_indir("L", node.param2)) 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_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. -- Delete existing node number. Needed for Digtron compatibility.
if (meta:contains("node_number")) then if (meta:contains("node_number")) then
meta:set_string("node_number", "") meta:set_string("node_number", "")
@ -298,5 +299,5 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
end end
end end
end end
return names[1], names[2], names[3] return names[1], names[2], names[3], names[4]
end end

View File

@ -32,21 +32,19 @@ local RecipeType = {
local function formspec(self, pos, nvm) local function formspec(self, pos, nvm)
local rtype = RecipeType[CRD(pos).stage] local rtype = RecipeType[CRD(pos).stage]
local owner = M(pos):get_string("owner")
return "size[8.4,8.4]".. return "size[8.4,8.4]"..
default.gui_bg.. "list[context;src;0,0;2,4;]"..
default.gui_bg_img.. recipes.formspec(2.2, 0, rtype, nvm, owner)..
default.gui_slots.. "list[context;dst;6.4,0;2,4;]"..
"list[context;src;0,0;2,4;]".. "image_button[3.7,3.3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
recipes.formspec(2.2, 0, rtype, nvm).. "tooltip[3.7,3.3;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[context;dst;6.4,0;2,4;]".. "list[current_player;main;0.2,4.5;8,4;]"..
"image_button[3.7,3.3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "listring[context;dst]"..
"tooltip[3.7,3.3;1,1;"..self:get_state_tooltip(nvm).."]".. "listring[current_player;main]"..
"list[current_player;main;0.2,4.5;8,4;]".. "listring[context;src]"..
"listring[context;dst]".. "listring[current_player;main]"..
"listring[current_player;main]".. default.get_hotbar_bg(0.2, 4.5)
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0.2, 4.5)
end end
local function allow_metadata_inventory_put(pos, listname, index, stack, player) local function allow_metadata_inventory_put(pos, listname, index, stack, player)
@ -261,24 +259,22 @@ minetest.register_craft({
}, },
}) })
if minetest.global_exists("unified_inventory") then techage.recipes.register_craft_type("ta2_electronic_fab", {
unified_inventory.register_craft_type("ta2_electronic_fab", { description = S("TA2 Ele Fab"),
description = S("TA2 Ele Fab"), icon = 'techage_filling_ta2.png^techage_appl_electronic_fab.png^techage_frame_ta2.png',
icon = 'techage_filling_ta2.png^techage_appl_electronic_fab.png^techage_frame_ta2.png', width = 2,
width = 2, height = 2,
height = 2, })
}) techage.recipes.register_craft_type("ta3_electronic_fab", {
unified_inventory.register_craft_type("ta3_electronic_fab", { description = S("TA3 Ele Fab"),
description = S("TA3 Ele Fab"), icon = 'techage_filling_ta3.png^techage_appl_electronic_fab.png^techage_frame_ta3.png',
icon = 'techage_filling_ta3.png^techage_appl_electronic_fab.png^techage_frame_ta3.png', width = 2,
width = 2, height = 2,
height = 2, })
}) techage.recipes.register_craft_type("ta4_electronic_fab", {
unified_inventory.register_craft_type("ta4_electronic_fab", { description = S("TA4 Ele Fab"),
description = S("TA4 Ele Fab"), icon = 'techage_filling_ta4.png^techage_appl_electronic_fab.png^techage_frame_ta4.png',
icon = 'techage_filling_ta4.png^techage_appl_electronic_fab.png^techage_frame_ta4.png', width = 2,
width = 2, height = 2,
height = 2, })
})
end

View File

@ -317,22 +317,18 @@ minetest.register_craft({
}) })
if minetest.global_exists("unified_inventory") then techage.recipes.register_craft_type("rinsing", {
unified_inventory.register_craft_type("rinsing", { description = S("Rinsing"),
description = S("Rinsing"), icon = "techage_appl_rinser_top.png^techage_frame_ta2_top.png",
icon = "techage_appl_rinser_top.png^techage_frame_ta2_top.png", width = 2,
width = 2, height = 2,
height = 2, })
})
end
function techage.add_rinser_recipe(recipe) function techage.add_rinser_recipe(recipe)
Probability[recipe.output] = recipe.probability Probability[recipe.output] = recipe.probability
if minetest.global_exists("unified_inventory") then recipe.items = {recipe.input}
recipe.items = {recipe.input} recipe.type = "rinsing"
recipe.type = "rinsing" techage.recipes.register_craft(recipe)
unified_inventory.register_craft(recipe)
end
end end
techage.add_rinser_recipe({input="techage:sieved_gravel", output="techage:usmium_nuggets", probability=30}) techage.add_rinser_recipe({input="techage:sieved_gravel", output="techage:usmium_nuggets", probability=30})

View File

@ -246,38 +246,36 @@ minetest.register_craft({
}, },
}) })
if minetest.global_exists("unified_inventory") then techage.recipes.register_craft_type("ta2_gravelsieve", {
unified_inventory.register_craft_type("ta2_gravelsieve", { description = S("TA2 Gravel Sieve"),
description = S("TA2 Gravel Sieve"), icon = 'techage_sieve_sieve_ta1.png',
icon = 'techage_sieve_sieve_ta1.png', width = 1,
width = 1, height = 1,
height = 1, })
}) techage.recipes.register_craft_type("ta3_gravelsieve", {
unified_inventory.register_craft_type("ta3_gravelsieve", { description = S("TA3 Gravel Sieve"),
description = S("TA3 Gravel Sieve"), icon = 'techage_filling_ta3.png^techage_appl_sieve.png^techage_frame_ta3.png',
icon = 'techage_filling_ta3.png^techage_appl_sieve.png^techage_frame_ta3.png', width = 1,
width = 1, height = 1,
height = 1, })
}) techage.recipes.register_craft_type("ta4_gravelsieve", {
unified_inventory.register_craft_type("ta4_gravelsieve", { description = S("TA4 Gravel Sieve"),
description = S("TA4 Gravel Sieve"), icon = 'techage_filling_ta4.png^techage_appl_sieve.png^techage_frame_ta4.png',
icon = 'techage_filling_ta4.png^techage_appl_sieve.png^techage_frame_ta4.png', width = 1,
width = 1, height = 1,
height = 1, })
}) techage.recipes.register_craft({
unified_inventory.register_craft({ output = "techage:sieved_basalt_gravel",
output = "techage:sieved_basalt_gravel", items = {"techage:basalt_gravel"},
items = {"techage:basalt_gravel"}, type = "ta2_gravelsieve",
type = "ta2_gravelsieve", })
}) techage.recipes.register_craft({
unified_inventory.register_craft({ output = "techage:sieved_basalt_gravel",
output = "techage:sieved_basalt_gravel", items = {"techage:basalt_gravel"},
items = {"techage:basalt_gravel"}, type = "ta3_gravelsieve",
type = "ta3_gravelsieve", })
}) techage.recipes.register_craft({
unified_inventory.register_craft({ output = "techage:sieved_basalt_gravel",
output = "techage:sieved_basalt_gravel", items = {"techage:basalt_gravel"},
items = {"techage:basalt_gravel"}, type = "ta4_gravelsieve",
type = "ta4_gravelsieve", })
})
end

View File

@ -351,20 +351,18 @@ minetest.register_craft({
}, },
}) })
if minetest.global_exists("unified_inventory") then techage.recipes.register_craft_type("grinding", {
unified_inventory.register_craft_type("grinding", { description = S("Grinding"),
description = S("Grinding"), icon = 'techage_appl_grinder.png',
icon = 'techage_appl_grinder.png', width = 2,
width = 2, height = 2,
height = 2, })
}) techage.recipes.register_craft_type("milling", {
unified_inventory.register_craft_type("milling", { description = S("Milling"),
description = S("Milling"), icon = 'techage_mill_inv.png',
icon = 'techage_mill_inv.png', width = 2,
width = 2, height = 2,
height = 2, })
})
end
function techage.add_grinder_recipe(recipe, ta1_permitted) function techage.add_grinder_recipe(recipe, ta1_permitted)
local name, num = unpack(string.split(recipe.input, " ", false, 1)) local name, num = unpack(string.split(recipe.input, " ", false, 1))
@ -372,20 +370,16 @@ function techage.add_grinder_recipe(recipe, ta1_permitted)
if ta1_permitted then if ta1_permitted then
RecipesTa1[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output} RecipesTa1[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output}
if minetest.global_exists("unified_inventory") then recipe.items = {recipe.input}
recipe.items = {recipe.input} recipe.type = "milling"
recipe.type = "milling" techage.recipes.register_craft(table.copy(recipe))
unified_inventory.register_craft(table.copy(recipe))
end
end end
Recipes[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output} Recipes[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output}
if minetest.global_exists("unified_inventory") then recipe.items = {recipe.input}
recipe.items = {recipe.input} recipe.type = "grinding"
recipe.type = "grinding" techage.recipes.register_craft(recipe)
unified_inventory.register_craft(recipe)
end
end end
end end

View File

@ -0,0 +1,244 @@
--[[
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

@ -26,40 +26,44 @@ local CYCLE_TIME = 8
local Recipes = {} local Recipes = {}
local SpecialItems = { local SpecialItems = {
["techage:sieved_gravel"] = "default:sand", ["techage:sieved_gravel"] = "default:sand",
["basic_materials:heating_element"] = "default:copper_ingot", ["basic_materials:heating_element"] = "default:copper_ingot",
["techage:ta4_wlanchip"] = "", ["techage:ta4_wlanchip"] = "",
["techage:basalt_cobble"] = "default:sand", ["techage:basalt_cobble"] = "default:sand",
["default:stone"] = "techage:sieved_gravel", ["default:stone"] = "techage:sieved_gravel",
["default:wood"] = "default:stick 5", ["default:wood"] = "default:stick 5",
["basic_materials:concrete_block"] = "techage:sieved_gravel", ["basic_materials:concrete_block"] = "techage:sieved_gravel",
["dye:green"] = "", ["dye:green"] = "",
["dye:red"] = "", ["dye:red"] = "",
["dye:white"] = "", ["dye:white"] = "",
["dye:blue"] = "", ["dye:blue"] = "",
["dye:brown"] = "", ["dye:brown"] = "",
["dye:cyan"] = "", ["dye:cyan"] = "",
["dye:yellow"] = "", ["dye:yellow"] = "",
["dye:grey"] = "", ["dye:grey"] = "",
["dye:orange"] = "", ["dye:orange"] = "",
["dye:black"] = "", ["dye:black"] = "",
["techage:basalt_glass_thin"] = "", ["techage:basalt_glass_thin"] = "",
["group:stone"] = "techage:sieved_gravel", ["group:stone"] = "techage:sieved_gravel",
["basic_materials:plastic_sheet"] = "", ["basic_materials:plastic_sheet"] = "",
["group:wood"] = "default:stick 5", ["group:wood"] = "default:stick 5",
["techage:basalt_glass"] = "", ["techage:basalt_glass"] = "",
["default:junglewood"] = "default:stick 5", ["default:junglewood"] = "default:stick 5",
["techage:ta4_silicon_wafer"] = "", ["techage:ta4_silicon_wafer"] = "",
["default:cobble"] = "techage:sieved_gravel", ["default:cobble"] = "techage:sieved_gravel",
["default:pick_diamond"] = "default:stick", ["default:pick_diamond"] = "default:stick",
["techage:hammer_steel"] = "default:stick", ["techage:hammer_steel"] = "default:stick",
["default:paper"] = "", ["default:paper"] = "",
["stairs:slab_basalt_glass2"] = "", ["stairs:slab_basalt_glass2"] = "",
["techage:basalt_stone"] = "techage:sieved_gravel", ["techage:basalt_stone"] = "techage:sieved_gravel",
["techage:ta4_ramchip"] = "", ["techage:ta4_ramchip"] = "",
["protector:chest"] = "default:chest", ["protector:chest"] = "default:chest",
["techage:ta4_rotor_blade"] = "", ["techage:ta4_rotor_blade"] = "",
["techage:ta4_carbon_fiber"] = "", ["techage:ta4_carbon_fiber"] = "",
["techage:ta4_round_ceramic"] = "",
["techage:ta4_furnace_ceramic"] = "",
["techage:ta5_aichip"] = "",
["techage:ta4_leds"] = "",
} }
local function formspec(self, pos, nvm) local function formspec(self, pos, nvm)

View File

@ -0,0 +1,185 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 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 = 20
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_client(pos) or 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]"
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
shared_inv.before_inv_access(pos, listname)
local inv = minetest.get_inventory({type="node", pos=pos})
if 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
shared_inv.before_inv_access(pos, listname)
local inv = minetest.get_inventory({type="node", pos=pos})
if 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
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)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num, item_name)
pos = remote_pos(pos)
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)
if techage.hyperloop.is_paired(pos) then
pos = remote_pos(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end
return false
end,
on_unpull_item = function(pos, in_dir, stack)
pos = remote_pos(pos)
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
pos = remote_pos(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_inv_state(inv, "main")
else
return "unsupported"
end
end,
})
minetest.register_craft({
type = "shapeless",
output = "techage:ta5_hl_chest",
recipe = {"techage:chest_ta4", "techage:ta5_aichip"}
})

View File

@ -124,3 +124,118 @@ function techage.assemble.remove(pos, AssemblyPlan, player_name)
remove(pos, node.param2, AssemblyPlan, #AssemblyPlan) remove(pos, node.param2, AssemblyPlan, #AssemblyPlan)
nvm.assemble_build = false nvm.assemble_build = false
end 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
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, pos, ItemStack(node_name), {}, 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

@ -262,6 +262,28 @@ function techage.repair_number(pos)
end end
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
------------------------------------------------------------------- -------------------------------------------------------------------
-- Node register function -- Node register function
@ -544,3 +566,62 @@ function techage.get_inv_state(inv, listname)
end end
return state return state
end 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

@ -34,6 +34,10 @@ function techage.counting_hit()
end end
end end
function techage.counting_add(player_name, points)
PlayerPoints[player_name] = (PlayerPoints[player_name] or 0) + points
end
local function output() local function output()
for name, val in pairs(PlayerPoints) do for name, val in pairs(PlayerPoints) do
if val > MAX_POINTS then if val > MAX_POINTS then

733
techage/basis/fly_lib.lua Normal file
View File

@ -0,0 +1,733 @@
--[[
TechAge
=======
Copyright (C) 2020-2021 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
local function lvect_add(lvect1, lvect2)
if not lvect1 or not lvect2 then return end
local lvect3 = {}
for i, v in ipairs(lvect1) do
lvect3[#lvect3 + 1] = vector.add(v, lvect2[i])
end
return lvect3
end
local function lvect_subtract(lvect1, lvect2)
if not lvect1 or not lvect2 then return end
local lvect3 = {}
for i, v in ipairs(lvect1) do
lvect3[#lvect3 + 1] = vector.subtract(v, lvect2[i])
end
return lvect3
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
-------------------------------------------------------------------------------
-- 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)
local x,y,z = unpack(string.split(s, ","))
if x and y and z then
return {
x=tonumber(x) or 0,
y=tonumber(y) or 0,
z=tonumber(z) or 0,
}
end
end
function flylib.to_path(s, max_dist)
local tPath
local dist = 0
for _, line in ipairs(strsplit(s)) 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 !!")
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
-------------------------------------------------------------------------------
-- Entity / Move / Attach / Detach
-------------------------------------------------------------------------------
local MIN_SPEED = 0.4
local MAX_SPEED = 8
local CORNER_SPEED = 4
local SimpleNodes = techage.logic.SimpleNodes
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, dir)
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(dir)
-- Calc entity rotation, which is relative to the parent's rotation
local rot = parent:get_rotation()
if self.param2 >= 20 then
dir = rotate(dir, 2 * math.pi - rot.y)
dir.y = -dir.y
dir.x = -dir.x
rot.y = rot.y - yaw
elseif self.param2 < 4 then
dir = rotate(dir, 2 * math.pi - rot.y)
rot.y = rot.y - yaw
end
dir = vector.multiply(dir, 29)
obj:set_attach(parent, "", dir, 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
local function attach_objects(pos, offs, parent, yoffs)
local pos1 = vector.add(pos, offs)
for _, obj in pairs(minetest.get_objects_inside_radius(pos1, 0.9)) do
local dir = vector.subtract(obj:get_pos(), pos)
local entity = obj:get_luaentity()
if entity then
if entity.name == "__builtin:item" then -- dropped items
--obj:set_attach(objref, "", {x=0, y=0, z=0}, {x=0, y=0, z=0}, true) -- hier kracht es
elseif entity.name ~= "techage:move_item" then
dir.y = dir.y + yoffs
attach_single_object(parent, obj, dir)
end
elseif obj:is_player() then
attach_single_object(parent, obj, dir)
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 then
local name = self.item_name or "air"
local param2 = self.param2 or 0
local metadata = self.metadata or {}
detach_objects(pos, self)
if self.base_pos then
local nvm = techage.get_nvm(self.base_pos)
nvm.running = nil
end
obj:remove()
local node = minetest.get_node(pos)
local ndef1 = minetest.registered_nodes[name]
local ndef2 = minetest.registered_nodes[node.name]
if ndef1 and ndef2 then
if ndef2.buildable_to then
local meta = M(pos)
minetest.set_node(pos, {name=name, param2=param2})
meta:from_table(metadata)
meta:set_string("ta_move_block", "")
return
end
local meta = M(pos)
if not meta:contains("ta_move_block") then
meta:set_string("ta_move_block", minetest.serialize({name=name, param2=param2}))
return
end
minetest.add_item(pos, ItemStack(name))
elseif ndef1 then
minetest.add_item(pos, ItemStack(name))
end
end
end
local function node_to_entity(start_pos)
local meta = M(start_pos)
local node, metadata
if 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", "")
else
-- Block with other metadata
node = minetest.get_node(start_pos)
metadata = meta:to_table()
minetest.remove_node(start_pos)
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.item_name = node.name
self.param2 = node.param2
self.metadata = metadata or {}
-- Prepare for attachments
self.players = {}
self.entities = {}
-- Prepare for path walk
self.path_idx = 1
return obj
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, dest_pos, dir, is_corner)
local self = obj:get_luaentity()
self.dest_pos = dest_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.lpath, 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
-- Handover the entity to the next movecontroller
local function handover_to(obj, self, pos1)
local info = techage.get_node_info(self.handover)
if info and info.name == "techage:ta4_movecontroller" then
local meta = M(info.pos)
if self.move2to1 then
self.handover = meta:contains("handoverA") and meta:get_string("handoverA")
else
self.handover = meta:contains("handoverB") and meta:get_string("handoverB")
end
self.lpath = flylib.to_path(meta:get_string("path"))
if pos1 and self.lpath then
self.path_idx = 2
if self.move2to1 then
self.lpath[1] = vector.multiply(self.lpath[1], - 1)
end
local pos2 = next_path_pos(pos1, self.lpath, 1)
local dir = determine_dir(pos1, pos2)
--print("handover_to", P2S(pos1), P2S(pos2), P2S(dir), P2S(info.pos), meta:get_string("path"))
if not self.handover then
local nvm = techage.get_nvm(info.pos)
nvm.lpos1 = nvm.lpos1 or {}
if self.move2to1 then
nvm.lpos1[self.pos1_idx] = pos2
else
nvm.lpos1[self.pos1_idx] = pos1
end
end
move_entity(obj, pos2, dir)
return true
end
end
end
minetest.register_entity("techage:move_item", {
initial_properties = {
pointable = true,
makes_footstep_sound = true,
static_save = true,
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},
},
get_staticdata = function(self)
return minetest.serialize({
item_name = self.item_name,
param2 = self.param2,
metadata = self.metadata,
move2to1 = self.move2to1,
handover = self.handover,
path_idx = self.path_idx,
pos1_idx = self.pos1_idx,
lpath = self.lpath,
start_pos = self.start_pos,
base_pos = self.base_pos,
max_speed = self.max_speed,
dest_pos = self.dest_pos,
dir = self.dir,
respawn = true,
})
end,
on_activate = function(self, staticdata)
if staticdata then
local tbl = minetest.deserialize(staticdata) or {}
self.item_name = tbl.item_name or "air"
self.param2 = tbl.param2 or 0
self.metadata = tbl.metadata or {}
self.move2to1 = tbl.move2to1 or false
self.handover = tbl.handover
self.path_idx = tbl.path_idx or 1
self.pos1_idx = tbl.pos1_idx or 1
self.lpath = tbl.lpath or {}
self.max_speed = tbl.max_speed or MAX_SPEED
self.dest_pos = tbl.dest_pos or self.object:get_pos()
self.start_pos = tbl.start_pos or self.object:get_pos()
self.base_pos = tbl.base_pos
self.dir = tbl.dir or {x=0, y=0, z=0}
self.object:set_properties({wield_item = self.item})
--print("tbl.respawn", tbl.respawn)
if tbl.respawn then
entity_to_node(self.start_pos, self.object)
end
end
end,
on_step = function(self, dtime, moveresult)
local stop_obj = function(obj, self)
local dest_pos = self.dest_pos
obj:move_to(self.dest_pos, true)
obj:set_acceleration({x=0, y=0, z=0})
obj:set_velocity({x=0, y=0, z=0})
self.dest_pos = nil
self.old_dist = nil
self.ttl = 2
return dest_pos
end
if self.dest_pos then
local obj = self.object
local pos = obj:get_pos()
local dist = vector.distance(pos, self.dest_pos)
local speed = calc_speed(obj:get_velocity())
self.old_dist = self.old_dist or dist
-- Landing
if self.lpath and self.lpath[self.path_idx] then
if dist < 1 or dist > self.old_dist then
local dest_pos = stop_obj(obj, self)
if not moveon_entity(obj, self, dest_pos) then
minetest.after(0.5, entity_to_node, dest_pos, obj)
end
return
end
elseif self.handover and dist < 0.2 or dist > self.old_dist then
local dest_pos = stop_obj(obj, self)
if not handover_to(obj, self, dest_pos) then
minetest.after(0.5, entity_to_node, dest_pos, obj)
end
return
else
if dist < 0.05 or dist > self.old_dist then
local dest_pos = stop_obj(obj, self)
minetest.after(0.5, entity_to_node, dest_pos, obj)
return
end
end
self.old_dist = dist
-- Braking or limit max speed
if self.handover then
if speed > (dist * 4) or speed > self.max_speed then
speed = math.min(speed, math.max(dist * 4, MIN_SPEED))
local vel = vector.multiply(self.dir,speed)
obj:set_velocity(vel)
obj:set_acceleration({x=0, y=0, z=0})
end
else
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
end
elseif self.ttl then
self.ttl = self.ttl - dtime
if self.ttl < 0 then
local obj = self.object
local pos = obj:get_pos()
entity_to_node(pos, obj)
end
end
end,
})
local function is_valid_dest(pos)
local node = minetest.get_node(pos)
local ndef = minetest.registered_nodes[node.name]
if ndef and ndef.buildable_to 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)
-- special handling
local name = minetest.get_node(pos).name
if SimpleNodes[name] ~= nil then
return SimpleNodes[name]
end
local ndef = minetest.registered_nodes[name]
if not ndef or name == "air" or name == "ignore" then return false end
-- don't remove nodes with some intelligence or undiggable nodes
if ndef.drop == "" then return false end
if ndef.diggable == false then return false end
if ndef.after_dig_node then return false end
return true
end
local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, move2to1, handover, cpos)
local pos2 = next_path_pos(start_pos, lpath, 1)
--print("move_node", P2S(pos), P2S(start_pos), lpath, max_speed, height, move2to1, P2S(pos2))
-- optional for non-player objects
local yoffs = M(pos):get_float("offset")
if pos2 then
local dir = determine_dir(start_pos, pos2)
local obj = node_to_entity(start_pos)
if obj then
local offs = {x=0, y=height or 1, z=0}
attach_objects(start_pos, 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(start_pos, dir, obj, yoffs)
end
end
local self = obj:get_luaentity()
self.path_idx = 2
self.pos1_idx = pos1_idx
self.lpath = lpath
self.max_speed = max_speed
self.start_pos = start_pos
self.base_pos = pos
self.move2to1 = move2to1
self.handover = handover
self.yoffs = yoffs
--print("move_node", P2S(start_pos), P2S(pos2), P2S(dir), P2S(pos))
move_entity(obj, pos2, dir)
end
end
end
local function move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover)
--print("move_nodes", dump(nvm), dump(lpath), max_speed, height, move2to1, handover)
local owner = meta:get_string("owner")
techage.counting_add(owner, #nvm.lpos1 * #lpath)
for idx = 1, #nvm.lpos1 do
local pos1 = nvm.lpos1[idx]
local pos2 = nvm.lpos2[idx]
if move2to1 then
pos1, pos2 = pos2, pos1
end
--print("move_nodes", P2S(pos1), P2S(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, idx, pos1, lpath, max_speed, height, move2to1, handover)
else
if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position"))
else
meta:set_string("status", S("No valid destination position"))
end
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
else
meta:set_string("status", S("Destination position is protected"))
end
return false
end
end
return true
end
function flylib.move_to_other_pos(pos, move2to1)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local lpath, 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 handover
if err 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(lpath)
if move2to1 then
lpath = reverse_path(lpath)
end
-- calc destination positions
nvm.lpos2 = lvect_add_vec(nvm.lpos1, offs)
if move2to1 then
handover = meta:contains("handoverA") and meta:get_string("handoverA")
else
handover = meta:contains("handoverB") and meta:get_string("handoverB")
end
return move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover)
end
-- rot is one of "l", "r", "2l", "2r"
-- cpos is the center pos (optional)
function flylib.rotate_nodes(pos, posses1, rot)
local meta = M(pos)
local owner = meta:get_string("owner")
local cpos = meta:contains("center") and flylib.to_vector(meta:get_string("center"))
local posses2 = techage.rotate_around_center(posses1, rot, cpos)
local param2
local nodes2 = {}
techage.counting_add(owner, #posses1 * 2)
for i, pos1 in ipairs(posses1) do
local node = techage.get_node_lvm(pos1)
if rot == "l" then
param2 = techage.param2_turn_left(node.param2)
elseif rot == "r" then
param2 = techage.param2_turn_right(node.param2)
else
param2 = techage.param2_turn_left(techage.param2_turn_left(node.param2))
end
if not minetest.is_protected(pos1, owner) and is_simple_node(pos1) then
minetest.remove_node(pos1)
nodes2[#nodes2 + 1] = {pos = posses2[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 posses2
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)
return flylib

235
techage/basis/hyperloop.lua Normal file
View File

@ -0,0 +1,235 @@
--[[
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)
local tbl = {M(pos):get_string("remote_name")}
for key,item in pairs(Stations:get_node_table(pos)) 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
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)
local owner = M(pos):get_string("owner")
return table.concat(get_free_server_list(pos, owner), ",")
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
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

@ -42,7 +42,7 @@ local function get_positions(pos, mem, dir)
return true -- no new values return true -- no new values
end end
-- return both both laser entities the pos and length -- return for both laser entities the pos and length
local function get_laser_length_and_pos(pos1, pos2, dir) local function get_laser_length_and_pos(pos1, pos2, dir)
local dist = vector.distance(pos1, pos2) local dist = vector.distance(pos1, pos2)
@ -133,5 +133,14 @@ function techage.renew_laser(pos, force)
return res return res
end 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(pos)
techage.del_laser = del_laser techage.del_laser = del_laser

View File

@ -3,7 +3,7 @@
TechAge TechAge
======= =======
Copyright (C) 2019 Joachim Stolberg Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3 AGPL v3
See LICENSE.txt for more information See LICENSE.txt for more information
@ -27,6 +27,117 @@ local Input = {
20,21,22,23, -- 6 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]
end
function techage.param2_turn_left(param2)
return (RotationViaYAxis[param2] or RotationViaYAxis[0])[1]
end
function techage.param2_turn_right(param2)
return (RotationViaYAxis[param2] or RotationViaYAxis[0])[2]
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
-- allowed for digging -- allowed for digging
local RegisteredNodesToBeDug = {} local RegisteredNodesToBeDug = {}
@ -330,6 +441,14 @@ function techage.mydump(o, indent, nested, level)
return "{"..table.concat(t, ", ").."}" return "{"..table.concat(t, ", ").."}"
end 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) -- title bar help (width is the fornmspec width)
function techage.question_mark_help(width, tooltip) function techage.question_mark_help(width, tooltip)
local x = width- 0.6 local x = width- 0.6
@ -343,3 +462,88 @@ function techage.wrench_tooltip(x, y)
"tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]" "tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end 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
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

View File

@ -30,8 +30,8 @@ local function help(x, y)
"tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]" "tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end end
function techage.liquid.formspec(pos, nvm) function techage.liquid.formspec(pos, nvm, title)
local title = S("Liquid Tank") title = title or S("Liquid Tank")
local itemname = "techage:liquid" local itemname = "techage:liquid"
if nvm.liquid and nvm.liquid.amount and nvm.liquid.amount > 0 and nvm.liquid.name then if nvm.liquid and nvm.liquid.amount and nvm.liquid.amount > 0 and nvm.liquid.name then
itemname = nvm.liquid.name.." "..nvm.liquid.amount itemname = nvm.liquid.name.." "..nvm.liquid.amount
@ -41,19 +41,19 @@ function techage.liquid.formspec(pos, nvm)
local meta = M(pos) local meta = M(pos)
local public = dump((meta:get_int("public") or 0) == 1) local public = dump((meta:get_int("public") or 0) == 1)
local keep_assignment = dump((meta:get_int("keep_assignment") or 0) == 1) local keep_assignment = dump((meta:get_int("keep_assignment") or 0) == 1)
return "size[5,3.5]".. return "size[8,3.5]"..
"box[0,-0.1;4.8,0.5;#c6e8ff]".. "box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[1.5,-0.1;"..minetest.colorize("#000000", title).."]".. "label[0.2,-0.1;"..minetest.colorize("#000000", title).."]"..
help(4.4, -0.1).. help(7.4, -0.1)..
techage.item_image(2, 1, itemname).. techage.item_image(3.5, 1, itemname)..
"checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]".. "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.."]" "checkbox[0.1,3;keep_assignment;"..S("keep assignment")..";"..keep_assignment.."]"
else else
return "size[4,2]".. return "size[8,2]"..
"box[0,-0.1;3.8,0.5;#c6e8ff]".. "box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[1,-0.1;"..minetest.colorize("#000000", title).."]".. "label[0.2,-0.1;"..minetest.colorize("#000000", title).."]"..
help(3.4, -0.1).. help(7.4, -0.1)..
techage.item_image(1.5, 1, itemname) techage.item_image(3.5, 1, itemname)
end end
end end

122
techage/basis/mark_lib.lua Normal file
View File

@ -0,0 +1,122 @@
--[[
TechAge
=======
Copyright (C) 2020-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Block marker lib for door/move/fly controller
]]--
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 >= 16 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_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",
},
--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)
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

@ -174,6 +174,7 @@ function NodeStates:new(attr)
cycle_time = attr.cycle_time, -- for running state cycle_time = attr.cycle_time, -- for running state
standby_ticks = attr.standby_ticks, -- for standby state standby_ticks = attr.standby_ticks, -- for standby state
-- optional -- optional
countdown_ticks = attr.countdown_ticks or 1,
node_name_passive = attr.node_name_passive, node_name_passive = attr.node_name_passive,
node_name_active = attr.node_name_active, node_name_active = attr.node_name_active,
infotext_name = attr.infotext_name, infotext_name = attr.infotext_name,
@ -254,7 +255,7 @@ function NodeStates:start(pos, nvm)
if self.start_node then if self.start_node then
self.start_node(pos, nvm, state) self.start_node(pos, nvm, state)
end end
nvm.techage_countdown = 1 nvm.techage_countdown = self.countdown_ticks
if self.node_name_active then if self.node_name_active then
swap_node(pos, self.node_name_active) swap_node(pos, self.node_name_active)
end end

103
techage/basis/oggfiles.lua Normal file
View File

@ -0,0 +1,103 @@
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

@ -22,6 +22,19 @@ local range = techage.in_range
techage.recipes = {} 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 = { local RECIPE = {
output = {name = "", num = 0}, output = {name = "", num = 0},
waste = {name = "", num = 0}, waste = {name = "", num = 0},
@ -33,6 +46,22 @@ local RECIPE = {
}, },
} }
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 -- Formspec
local function input_string(recipe) local function input_string(recipe)
@ -80,24 +109,24 @@ function techage.recipes.add(rtype, recipe)
name, num = unpack(string.split(recipe.output, " ")) name, num = unpack(string.split(recipe.output, " "))
item.output = {name = name or "", num = tonumber(num) or 0} item.output = {name = name or "", num = tonumber(num) or 0}
item.catalyst = recipe.catalyst item.catalyst = recipe.catalyst
item.ex_points = recipe.ex_points or 0
Recipes[rtype][#Recipes[rtype]+1] = item Recipes[rtype][#Recipes[rtype]+1] = item
output = name output = name
if minetest.global_exists("unified_inventory") then techage.recipes.register_craft({
unified_inventory.register_craft({ output = recipe.output,
output = recipe.output, items = recipe.input,
items = recipe.input, type = rtype,
type = rtype, })
})
end
NormalizedRecipes[output] = { NormalizedRecipes[output] = {
output = recipe.output, output = recipe.output,
items = recipe.input, items = recipe.input,
} }
end end
function techage.recipes.formspec(x, y, rtype, nvm) function techage.recipes.formspec(x, y, rtype, nvm, owner)
local recipes = Recipes[rtype] or {} local recipes = Recipes[rtype] or {}
recipes = filter_recipes_based_on_points(recipes, owner)
nvm.recipe_idx = range(nvm.recipe_idx or 1, 1, #recipes) nvm.recipe_idx = range(nvm.recipe_idx or 1, 1, #recipes)
local idx = nvm.recipe_idx local idx = nvm.recipe_idx
local recipe = recipes[idx] or RECIPE local recipe = recipes[idx] or RECIPE
@ -137,3 +166,114 @@ function techage.recipes.get_recipe(name)
return NormalizedRecipes[name] return NormalizedRecipes[name]
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

@ -0,0 +1,69 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 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 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)
copy_inventory_list(rmt_pos, pos, listname)
return true
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)
copy_inventory_list(pos, rmt_pos, listname)
return true
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)
copy_inventory_list(rmt_pos, pos, listname)
techage.set_activeformspec(pos, clicker)
minetest.get_node_timer(pos):start(2)
end
end

View File

@ -0,0 +1,105 @@
--[[
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 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) 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)
pos = remote_pos(pos)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end
function techage.shared_tank.take_liquid(pos, indir, name, amount)
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
function techage.shared_tank.put_liquid(pos, indir, name, amount)
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
return amount
end
function techage.shared_tank.untake_liquid(pos, indir, name, amount)
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
techage.shared_tank.formspec = formspec

View File

@ -3,7 +3,7 @@
TechAge TechAge
======= =======
Copyright (C) 2019-2021 Joachim Stolberg Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3 AGPL v3
See LICENSE.txt for more information See LICENSE.txt for more information
@ -13,7 +13,7 @@
local S = techage.S local S = techage.S
local menu = {} techage.menu = {}
local function index(list, x) local function index(list, x)
for idx, v in ipairs(list) do for idx, v in ipairs(list) do
@ -48,7 +48,9 @@ local function generate_formspec_substring(pos, meta, form_def, player_name)
local offs = (i - 1) * 0.9 - 0.2 local offs = (i - 1) * 0.9 - 0.2
tbl[#tbl+1] = "label[0," .. offs .. ";" .. minetest.formspec_escape(elem.label) .. ":]" tbl[#tbl+1] = "label[0," .. offs .. ";" .. minetest.formspec_escape(elem.label) .. ":]"
tbl[#tbl+1] = "tooltip[0," .. offs .. ";4,1;" .. elem.tooltip .. "]" tbl[#tbl+1] = "tooltip[0," .. offs .. ";4,1;" .. elem.tooltip .. "]"
if elem.type == "number" then if elem.type == "label" then
-- none
elseif elem.type == "number" then
local val = elem.default local val = elem.default
if meta:contains(elem.name) then if meta:contains(elem.name) then
val = meta:get_int(elem.name) val = meta:get_int(elem.name)
@ -91,7 +93,7 @@ local function generate_formspec_substring(pos, meta, form_def, player_name)
elseif elem.type == "const" then elseif elem.type == "const" then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. elem.value .. "]" tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. elem.value .. "]"
elseif elem.type == "output" then elseif elem.type == "output" then
local val = nvm[elem.name] or "" local val = nvm[elem.name] or meta:get_string(elem.name) or ""
if tonumber(val) then if tonumber(val) then
val = techage.round(val) val = techage.round(val)
end end
@ -104,6 +106,15 @@ local function generate_formspec_substring(pos, meta, form_def, player_name)
val = meta:get_string(elem.name) or "" val = meta:get_string(elem.name) or ""
end end
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" 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 else
local val = elem.default local val = elem.default
if meta:contains(elem.name) then if meta:contains(elem.name) then
@ -112,7 +123,7 @@ local function generate_formspec_substring(pos, meta, form_def, player_name)
local idx = index(l, val) or 1 local idx = index(l, val) or 1
tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]" tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]"
end end
elseif elem.type == "items" then elseif elem.type == "items" then -- inventory
tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]" tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]"
player_inv_needed = true player_inv_needed = true
end end
@ -193,7 +204,7 @@ local function evaluate_data(pos, meta, form_def, fields, player_name)
if fields[elem.name] ~= nil then if fields[elem.name] ~= nil then
meta:set_string(elem.name, fields[elem.name]) meta:set_string(elem.name, fields[elem.name])
end end
elseif elem.type == "items" then elseif elem.type == "items" and player_name then
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu" local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
local dinv = minetest.get_inventory({type = "detached", name = inv_name}) local dinv = minetest.get_inventory({type = "detached", name = inv_name})
local ninv = minetest.get_inventory({type = "node", pos = pos}) local ninv = minetest.get_inventory({type = "node", pos = pos})
@ -208,25 +219,26 @@ local function evaluate_data(pos, meta, form_def, fields, player_name)
return res return res
end end
function menu.generate_formspec(pos, ndef, form_def, player_name) function techage.menu.generate_formspec(pos, ndef, form_def, player_name)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local number = techage.get_node_number(pos) local number = techage.get_node_number(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
mem.star = ((mem.star or 0) + 1) % 2 mem.star = ((mem.star or 0) + 1) % 2
local star = mem.star == 1 and "*" or "" local star = mem.star == 1 and "*" or ""
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu" if player_name then
minetest.create_detached_inventory(inv_name, { local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
allow_put = allow_put, minetest.create_detached_inventory(inv_name, {
allow_take = allow_take}) allow_put = allow_put,
local dinv = minetest.get_inventory({type = "detached", name = inv_name}) allow_take = allow_take})
local ninv = minetest.get_inventory({type = "node", pos = pos}) local dinv = minetest.get_inventory({type = "detached", name = inv_name})
if dinv and ninv then local ninv = minetest.get_inventory({type = "node", pos = pos})
dinv:set_size('cfg', ninv:get_size("cfg")) if dinv and ninv then
for i = 1, ninv:get_size("cfg") do dinv:set_size('cfg', ninv:get_size("cfg"))
dinv:set_stack("cfg", i, ninv:get_stack("cfg", i)) for i = 1, ninv:get_size("cfg") do
dinv:set_stack("cfg", i, ninv:get_stack("cfg", i))
end
end end
end end
if meta and number and ndef and form_def then if meta and number and ndef and form_def then
local title = ndef.description .. " (" .. number .. ")" local title = ndef.description .. " (" .. number .. ")"
local player_inv_needed, text = generate_formspec_substring(pos, meta, form_def, player_name) local player_inv_needed, text = generate_formspec_substring(pos, meta, form_def, player_name)
@ -275,13 +287,10 @@ function menu.generate_formspec(pos, ndef, form_def, player_name)
return "" return ""
end end
function menu.eval_input(pos, form_def, fields, player_name) function techage.menu.eval_input(pos, form_def, fields, player_name)
--print(dump(fields)) if fields.save or fields.key_enter_field then
if fields.save then
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
evaluate_data(pos, meta, form_def, fields, player_name) evaluate_data(pos, meta, form_def, fields, player_name)
end end
return fields.refresh or fields.save return fields.refresh or fields.save or fields.key_enter_field
end end
return menu

167
techage/basis/teleport.lua Normal file
View File

@ -0,0 +1,167 @@
--[[
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

@ -362,14 +362,12 @@ techage.register_node({"techage:ta4_doser", "techage:ta4_doser_on"}, {
end, end,
}) })
if minetest.global_exists("unified_inventory") then techage.recipes.register_craft_type("ta4_doser", {
unified_inventory.register_craft_type("ta4_doser", { description = S("TA4 Reactor"),
description = S("TA4 Reactor"), icon = 'techage_reactor_filler_plan.png',
icon = 'techage_reactor_filler_plan.png', width = 2,
width = 2, height = 2,
height = 2, })
})
end
minetest.register_craft({ minetest.register_craft({
output = "techage:ta4_doser", output = "techage:ta4_doser",

View File

@ -0,0 +1,91 @@
--[[
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
{
image = "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,
},
},
{
image = "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",
},
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)
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

@ -0,0 +1,414 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 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 PROBABILITY = 180 -- check every 20 s => 20 * 180 * 50% = 30 min
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(PROBABILITY) == 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)
end
-- Call on_cyclic_check of all magents so that the magnets don't need a FLB.
local function magnet_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
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",
},
drawtype = "nodebox",
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 not magnet_on_cyclic_check(pos, nvm) then
techage.del_laser(pos)
if nvm.running then
terminal_message(pos, "Detector stopped.")
nvm.running = false
end
nvm.magnet_positions = nil
elseif nvm.running then
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)
nvm.running = false
nvm.magnet_positions = nil
terminal_message(pos, "Detector stopped.")
end
if nvm.running then
play_sound(pos)
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")
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
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
return
end
else
techage.send_single(own_num, term_num, "append", "defect!!!")
nvm.magnet_positions = nil
nvm.locked = 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 started.")
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
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'},
},
})

364
techage/collider/inlets.lua Normal file
View File

@ -0,0 +1,364 @@
--[[
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",
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)
nvm.consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
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
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', ''},
{'', '', ''},
},
})

305
techage/collider/magnet.lua Normal file
View File

@ -0,0 +1,305 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 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
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",
},
drawtype = "nodebox",
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_appl_hole_pipe.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_appl_hole_pipe.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",
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")
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
return -1
elseif nvm.liquid.amount == CAPACITY and
nvm.liquid.name == "techage:isobutane" and
nvm.consumed == PWR_NEEDED then
return 0
end
return -2
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", "B"}, {
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
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

@ -0,0 +1,208 @@
--[[
Techage
=======
Copyright (C) 2020-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Terminal
]]--
local M = minetest.get_meta
local S = techage.S
local STR_LEN = 80
local HELP = [[#### TA4 Terminal ####
Send commands to the connected machine
and output text messages from the
machine.
Commands can have up to 80 characters.
Local commands:
- clear = clear screen
- help = this message
- pub = switch to public use
- priv = switch to private use
- connect <num> = connect the machine
All other commands are machine dependent.
]]
local function get_string(meta, num, default)
local s = meta:get_string("bttn_text"..num)
if not s or s == "" then
return default
end
return s
end
local function formspec2(mem)
mem.command = mem.command or ""
mem.output = mem.output or ""
local output = minetest.formspec_escape(mem.output)
output = output:gsub("\n", ",")
local command = minetest.formspec_escape(mem.command)
local bttn_text1 = get_string(meta, 1, "User1")
local bttn_text2 = get_string(meta, 2, "User2")
local bttn_text3 = get_string(meta, 3, "User3")
local bttn_text4 = get_string(meta, 4, "User4")
local bttn_text5 = get_string(meta, 5, "User5")
local bttn_text6 = get_string(meta, 6, "User6")
local bttn_text7 = get_string(meta, 7, "User7")
local bttn_text8 = get_string(meta, 8, "User8")
local bttn_text9 = get_string(meta, 9, "User9")
return "size[10,8]"..
"style_type[table,field;font=mono]"..
"button[0,0;3.3,1;bttn1;"..bttn_text1.."]button[3.3,0;3.3,1;bttn2;"..bttn_text2.."]button[6.6,0;3.3,1;bttn3;"..bttn_text3.."]"..
"button[0,0.8;3.3,1;bttn4;"..bttn_text4.."]button[3.3,0.8;3.3,1;bttn5;"..bttn_text5.."]button[6.6,0.8;3.3,1;bttn6;"..bttn_text6.."]"..
"button[0,1.6;3.3,1;bttn7;"..bttn_text7.."]button[3.3,1.6;3.3,1;bttn8;"..bttn_text8.."]button[6.6,1.6;3.3,1;bttn9;"..bttn_text9.."]"..
"table[0,2.5;9.8,4.7;output;"..output..";200]"..
"field[0.4,7.7;7.6,1;cmnd;;"..mem.command.."]" ..
"field_close_on_enter[cmnd;false]"..
"button[7.9,7.4;2,1;enter;"..S("Enter").."]"
end
local function output(pos, text)
local mem = techage.get_mem(pos)
mem.output = mem.output .. "\n" .. (text or "")
mem.output = mem.output:sub(-500,-1)
M(pos):set_string("formspec", formspec2(mem))
end
local function command(pos, mem, player)
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if mem.command == "clear" then
mem.output = ""
mem.command = ""
meta:set_string("formspec", formspec2(mem))
elseif mem.command == "" then
output(pos, ">")
mem.command = ""
meta:set_string("formspec", formspec2(mem))
elseif mem.command == "help" then
local meta = minetest.get_meta(pos)
mem.output = HELP
mem.command = ""
meta:set_string("formspec", formspec2(mem))
elseif mem.command == "pub" and owner == player then
meta:set_int("public", 1)
output(pos, "> "..mem.command)
mem.command = ""
output(pos, "Switched to public use!")
elseif mem.command == "priv" and owner == player then
meta:set_int("public", 0)
output(pos, "> "..mem.command)
mem.command = ""
output(pos, "Switched to private use!")
elseif meta:get_int("public") == 1 or owner == player then
if mem.command == "clear" then
mem.output =
mem.command = ""
meta:set_string("formspec", formspec2(mem))
end
end
end
minetest.register_node("techage:ta4_terminal", {
description = "TA4 Collider Terminal",
tiles = {
-- up, down, right, left, back, front
'techage_terminal1_top.png',
'techage_terminal1_bottom.png',
'techage_terminal1_side.png',
'techage_terminal1_side.png',
'techage_terminal1_bottom.png',
"techage_terminal1_front.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-12/32, -16/32, -8/32, 12/32, -14/32, 12/32},
{-12/32, -14/32, 12/32, 12/32, 6/32, 14/32},
},
},
selection_box = {
type = "fixed",
fixed = {
{-12/32, -16/32, -8/32, 12/32, -14/32, 12/32},
{-12/32, -14/32, 12/32, 12/32, 6/32, 14/32},
},
},
after_place_node = function(pos, placer)
local number = techage.add_node(pos, minetest.get_node(pos).name)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formspec1())
meta:set_string("owner", placer:get_player_name())
meta:set_string("infotext", S("TA4 Collider Terminal") .. ": " .. S("not connected")
end,
on_receive_fields = function(pos, formname, fields, player)
local meta = minetest.get_meta(pos)
local mem = techage.get_mem(pos)
if fields.number and fields.number ~= "" then
local owner = meta:get_string("owner")
if techage.check_numbers(fields.number, owner) then
local own_number = meta:get_string("own_number")
if techage.send_single(own_number, fields.number, "connect") == true then
meta:set_string("number", fields.number)
meta:set_string("infotext", S("TA4 Collider Terminal") .. ": " .. S("connected with") .. " " .. fields.number)
meta:set_string("formspec", formspec2(mem))
end
end
elseif (fields.enter or fields.key_enter_field) and fields.cmnd then
mem.command = string.sub(fields.cmnd, 1, STR_LEN)
command(pos, mem, player:get_player_name())
elseif fields.key_up then
mem.command = pdp13.historybuffer_priv(pos)
meta:set_string("formspec", formspec2(mem))
elseif fields.key_down then
mem.command = pdp13.historybuffer_next(pos)
meta:set_string("formspec", formspec2(mem))
end
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_craft({
output = "techage:ta4_terminal",
recipe = {
{"", "techage:ta4_display", ""},
{"dye:black", "techage:ta4_wlanchip", "default:copper_ingot"},
{"", "techage:aluminum", ""},
},
})
techage.register_node({"techage:ta4_terminal"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "term" then
output(pos, payload)
return true
elseif topic == "clear" then
local mem = techage.get_mem(pos)
mem.output = ""
mem.command = ""
M(pos):set_string("formspec", formspec2(mem))
return true
end
end,
})

View File

@ -0,0 +1,130 @@
--[[
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', ''},
},
})

210
techage/collider/worker.lua Normal file
View File

@ -0,0 +1,210 @@
--[[
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",
},
drawtype = "nodebox",
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

@ -13,6 +13,8 @@ local function tooltip(item)
local img, name = item[1], item[2] local img, name = item[1], item[2]
if img == "" then -- larger image for the plan? if img == "" then -- larger image for the plan?
return "", name return "", name
elseif img == "10x10" then -- huge image for the plan?
return "10x10", name
end end
local ndef = minetest.registered_nodes[name] local ndef = minetest.registered_nodes[name]
if ndef and ndef.description then if ndef and ndef.description then
@ -41,6 +43,9 @@ local function plan(images)
elseif img == "" then elseif img == "" then
img = tooltip -- use tooltip for bigger image img = tooltip -- use tooltip for bigger image
tbl[#tbl+1] = "image["..x_offs..","..y_offs..";2.2,2.2;"..img.."]" tbl[#tbl+1] = "image["..x_offs..","..y_offs..";2.2,2.2;"..img.."]"
elseif img == "10x10" then
img = tooltip -- use tooltip for bigger image
tbl[#tbl+1] = "image["..x_offs..","..y_offs..";10,10;"..img.."]"
elseif string.find(img, ":") then elseif string.find(img, ":") then
tbl[#tbl+1] = "item_image["..x_offs..","..y_offs..";1,1;"..img.."]" tbl[#tbl+1] = "item_image["..x_offs..","..y_offs..";1,1;"..img.."]"
else else

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