diff --git a/mods/Minetest-WorldEdit/Chat Commands.md b/mods/Minetest-WorldEdit/Chat Commands.md new file mode 100644 index 0000000..c3d5250 --- /dev/null +++ b/mods/Minetest-WorldEdit/Chat Commands.md @@ -0,0 +1,360 @@ +Chat Commands +------------- +For more information, see the [README](README.md). + +Many commands also have shorter names that can be typed faster. For example, if we wanted to use `//move ? 5`, we could instead type `//m ? 5`. All shortened names are listed below: + +| Short Name | Original Name | +|:-----------|:-------------------| +| `//i` | `//inspect` | +| `//rst` | `//reset` | +| `//mk` | `//mark` | +| `//umk` | `//unmark` | +| `//1` | `//pos1` | +| `//2` | `//pos2` | +| `//fp` | `//fixedpos` | +| `//v` | `//volume` | +| `//s` | `//set` | +| `//r` | `//replace` | +| `//ri` | `//replaceinverse` | +| `//hspr` | `//hollowsphere` | +| `//spr` | `//sphere` | +| `//hdo` | `//hollowdome` | +| `//do` | `//dome` | +| `//hcyl` | `//hollowcylinder` | + +### `//about` + +Get information about the mod. + + //about + +### `//inspect on/off/1/0/true/false/yes/no/enable/disable/` + +Enable or disable node inspection. + + //inspect on + //inspect off + //inspect 1 + //inspect 0 + //inspect true + //inspect false + //inspect yes + //inspect no + //inspect enable + //inspect disable + //inspect + +### `//reset` + +Reset the region so that it is empty. + + //reset + +### `//mark` + +Show markers at the region positions. + + //mark + +### `//unmark` + +Hide markers if currently shown. + + //unmark + +### `//pos1` + +Set WorldEdit region position 1 to the player's location. + + //pos1 + +### `//pos2` + +Set WorldEdit region position 2 to the player's location. + + //pos2 + +### `//p set/set1/set2/get` + +Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region. + + //p set + //p set1 + //p set2 + //p get + +### `//fixedpos set1 x y z` + +Set a WorldEdit region position to the position at (``, ``, ``). + + //fixedpos set1 0 0 0 + //fixedpos set1 -30 5 28 + //fixedpos set2 1004 -200 432 + +### `//volume` + +Display the volume of the current WorldEdit region. + + //volume + +### `//set ` + +Set the current WorldEdit region to ``. + + //set air + //set cactus + //set Bronze Block + //set mesecons:wire_00000000_off + +### `//replace ` + +Replace all instances of `` with `` in the current WorldEdit region. + + //replace Cobblestone air + //replace lightstone_blue glass + //replace dirt Bronze Block + //replace mesecons:wire_00000000_off flowers:flower_tulip + +### `//replaceinverse ` + +Replace all nodes other than `` with `` in the current WorldEdit region. + + //replaceinverse Cobblestone air + //replaceinverse flowers:flower_waterlily glass + //replaceinverse dirt Bronze Block + //replaceinverse mesecons:wire_00000000_off flowers:flower_tulip + +### `//hollowsphere ` + +Add hollow sphere centered at WorldEdit position 1 with radius ``, composed of ``. + + //hollowsphere 5 Diamond Block + //hollowsphere 12 glass + //hollowsphere 17 mesecons:wire_00000000_off + +### `//sphere ` + +Add sphere centered at WorldEdit position 1 with radius ``, composed of ``. + + //sphere 5 Diamond Block + //sphere 12 glass + //sphere 17 mesecons:wire_00000000_off + +### `//hollowdome ` + +Add hollow dome centered at WorldEdit position 1 with radius ``, composed of ``. + + //hollowdome 5 Diamond Block + //hollowdome -12 glass + //hollowdome 17 mesecons:wire_00000000_off + +### `//dome ` + +Add dome centered at WorldEdit position 1 with radius ``, composed of ``. + + //dome 5 Diamond Block + //dome -12 glass + //dome 17 mesecons:wire_00000000_off + +### `//hollowcylinder x/y/z/? ` + +Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length `` and radius ``, composed of ``. + + //hollowcylinder x +5 8 Bronze Block + //hollowcylinder y 28 10 glass + //hollowcylinder z -12 3 mesecons:wire_00000000_off + //hollowcylinder ? 2 4 default:stone + +### `//cylinder x/y/z/? ` + +Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length `` and radius ``, composed of ``. + + //cylinder x +5 8 Bronze Block + //cylinder y 28 10 glass + //cylinder z -12 3 mesecons:wire_00000000_off + //cylinder ? 2 4 default:stone + +### `//pyramid x/y/z? ` + +Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height ``, composed of ``. + + //pyramid x 8 Diamond Block + //pyramid y -5 glass + //pyramid z 2 mesecons:wire_00000000_off + //pyramid ? 12 mesecons:wire_00000000_off + +### `//spiral ` + +Add spiral centered at WorldEdit position 1 with side length ``, height ``, space between walls ``, composed of ``. + + //spiral 20 5 3 Diamond Block + //spiral 5 2 1 glass + //spiral 7 1 5 mesecons:wire_00000000_off + +### `//copy x/y/z/? ` + +Copy the current WorldEdit region along the x/y/z/? axis by `` nodes. + + //copy x 15 + //copy y -7 + //copy z +4 + //copy ? 8 + +### `//move x/y/z/? ` + +Move the current WorldEdit positions and region along the x/y/z/? axis by `` nodes. + + //move x 15 + //move y -7 + //move z +4 + //move ? -1 + +### `//stack x/y/z/? ` + +Stack the current WorldEdit region along the x/y/z/? axis `` times. + + //stack x 3 + //stack y -1 + //stack z +5 + //stack ? 12 + +### `//scale ` + +Scale the current WorldEdit positions and region by a factor of positive integer `` with position 1 as the origin. + + //scale 2 + //scale 1 + //scale 10 + +### `//transpose x/y/z/? x/y/z/?` + +Transpose the current WorldEdit positions and region along the x/y/z/? and x/y/z/? axes. + + //transpose x y + //transpose x z + //transpose y z + //transpose ? y + +### `//flip x/y/z/?` + +Flip the current WorldEdit region along the x/y/z/? axis. + + //flip x + //flip y + //flip z + //flip ? + +### `//rotate x/y/z/? ` + +Rotate the current WorldEdit positions and region along the x/y/z/? axis by angle `` (90 degree increment). + + //rotate x 90 + //rotate y 180 + //rotate z 270 + //rotate ? -90 + +### `//orient ` + +Rotate oriented nodes in the current WorldEdit region around the Y axis by angle `` (90 degree increment) + + //orient 90 + //orient 180 + //orient 270 + //orient -90 + +### `//fixlight` + +Fixes the lighting in the current WorldEdit region. + + //fixlight + +### `//hide` + +Hide all nodes in the current WorldEdit region non-destructively. + + //hide + +### `//suppress ` + +Suppress all in the current WorldEdit region non-destructively. + + //suppress Diamond Block + //suppress glass + //suppress mesecons:wire_00000000_off + +### `//highlight ` + +Highlight in the current WorldEdit region by hiding everything else non-destructively. + + //highlight Diamond Block + //highlight glass + //highlight mesecons:wire_00000000_off + +### `//restore` + +Restores nodes hidden with WorldEdit in the current WorldEdit region. + + //restore + +### `//save ` + +Save the current WorldEdit region to "(world folder)/schems/``.we". + + //save some random filename + //save huge_base + +### `//allocate ` + +Set the region defined by nodes from "(world folder)/schems/``.we" as the current WorldEdit region. + + //allocate some random filename + //allocate huge_base + +### `//load ` + +Load nodes from "(world folder)/schems/``.we" with position 1 of the current WorldEdit region as the origin. + + //load some random filename + //load huge_base + +### `//lua ` + +Executes `` as a Lua chunk in the global namespace. + + //lua worldedit.pos1["singleplayer"] = {x=0, y=0, z=0} + //lua worldedit.rotate(worldedit.pos1["singleplayer"], worldedit.pos2["singleplayer"], "y", 90) + +### `//luatransform ` + +Executes `` as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region. + + //luatransform minetest.add_node(pos, {name="default:stone"}) + //luatransform if minetest.get_node(pos).name == "air" then minetest.add_node(pos, {name="default:water_source"}) + +### `//mtschemcreate ` + +Save the current WorldEdit region using the Minetest Schematic format to "(world folder)/schems/``.mts". + + //mtschemcreate some random filename + //mtschemcreate huge_base + +### `//mtschemplace ` + +Load nodes from "(world folder)/schems/``.mts" with position 1 of the current WorldEdit region as the origin. + + //mtschemplace some random filename + //mtschemplace huge_base + +### `//mtschemprob start/finish/get` + +After using `//mtschemprob start` all nodes punched will bring up a text field where a probablity can be entered. +This mode can be left with `//mtschemprob finish`. `//mtschemprob get` will display the probabilities saved for the nodes. + + //mtschemprob get + +### `//clearobjects` + +Clears all objects within the WorldEdit region. + + //clearobjects diff --git a/mods/Minetest-WorldEdit/LICENSE.txt b/mods/Minetest-WorldEdit/LICENSE.txt new file mode 100644 index 0000000..dba13ed --- /dev/null +++ b/mods/Minetest-WorldEdit/LICENSE.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/mods/Minetest-WorldEdit/README.md b/mods/Minetest-WorldEdit/README.md new file mode 100644 index 0000000..62d245a --- /dev/null +++ b/mods/Minetest-WorldEdit/README.md @@ -0,0 +1,141 @@ +WorldEdit v1.0 for MineTest 0.4.8+ +================================== +The ultimate in-game world editing tool for [Minetest](http://minetest.net/)! Tons of functionality to help with building, fixing, and more. + +For more information, see the [forum topic](https://forum.minetest.net/viewtopic.php?id=572) at the Minetest forums. + +# New users should see the [tutorial](Tutorial.md). + +![Screenshot](http://i.imgur.com/lwhodrv.png) + +Installing +---------- + +If you are using Windows, consider installing this mod using [MODSTER](https://forum.minetest.net/viewtopic.php?id=6497), a super simple mod installer that will take care of everything for you. If you are using MODSTER, skip directly to step 6 in the instructions below. + +There is a nice installation guide over at the [Minetest Wiki](http://wiki.minetest.com/wiki/Installing_mods). Here is a short summary: + +1. Download the mod from the [official releases page](https://github.com/Uberi/Minetest-WorldEdit/releases). The download links are labelled "Source Code". If you are using Windows, you will probably want to download the ZIP version. +2. You should have a file named `SOMETHING.zip` or `SOMETHING.tar.gz`. +3. Extract this file using your archiver of choice. If you are using Windows, open the ZIP file and move the folder inside to a safe place outside of the ZIP file. +4. Make sure that you now have a folder with a file named README.md inside it. If you just have another folder inside this folder, use this nested folder instead. +5. Move this folder into the `MINETEST_FOLDER/mods` folder, where `MINETEST_FOLDER` is the folder Minetest is located in. +6. Open Minetest to a world selection screen. +7. Select a world you want to use WorldEdit in by left clicking on it once, and press the **Configure** button. +8. You should have a mod selection screen. Select the one named something like `Minetest-WorldEdit` by left clicking once and press the **Enable MP** button. +9. Press the **Save** button. You can now use WorldEdit in that world. Repeat steps 7 to 9 to enable WorldEdit for other worlds too. + +If you are having trouble, try asking for help in the [IRC channel](http://webchat.freenode.net/?channels=#minetest) (faster but may not always have helpers online) or ask on the [forum topic](https://forum.minetest.net/viewtopic.php?id=572) (slower but more likely to get help). + +Usage +----- +WorldEdit works primarily through the WorldEdit GUI and chat commands. Depending on your key bindings, you can invoke chat entry with the "t" key, and open the chat console with the "F10" key. + +WorldEdit has a huge potential for abuse by untrusted players. Therefore, users will not be able to use WorldEdit unless they have the `worldedit` privelege. This is available by default in single player, but in multiplayer the permission must be explicitly given by someone with the right credentials, using the follwoing chat command: `/grant worldedit`. This privelege can later be removed using the following chat command: `/revoke worldedit`. + +Certain functions/commands such as WorldEdit GUI's "Run Lua" function (equivalent to the `//lua` and `//luatransform` chat command) additionally require the `server` privilege. This is because it is extremely dangerous to give access to these commands to untrusted players, since they essentially are able to control the computer the server is running on. Give this privilege only to people you trust with your computer. + +For in-game information about these commands, type `/help ` in the chat. For example, to learn more about the `//copy` command, simply type `/help /copy` to display information relevant to copying a region. + +Interface +--------- +WorldEdit is accessed in-game in two main ways. + +The GUI adds a screen to each player's inventory that gives access to various WorldEdit functions. The [tutorial](Tutorial.md) and the [Chat Commands Reference](Chat Commands.md) may be helpful in learning to use it. + +The chat interface adds many chat commands that perform various WorldEdit powered tasks. It is documented in the [Chat Commands Reference](Chat Commands.md). + +Compatibility +------------- +This mod supports Minetest versions 0.4.8 and newer. Older versions of WorldEdit may work with older versions of Minetest, but are not recommended or supported. + +WorldEdit works quite well with other mods, and does not have any known mod conflicts. + +WorldEdit GUI works with [Unified Inventory](https://forum.minetest.net/viewtopic.php?id=3933) and [Inventory++](https://forum.minetest.net/viewtopic.php?id=6204), but these are not required to use the mod. + +If you use any other inventory manager mods, note that they may conflict with the WorldEdit GUI. If this is the case, it may be necessary to disable them. + +WorldEdit API +------------- +WorldEdit exposes all significant functionality in a simple Lua interface. Adding WorldEdit to the file "depends.txt" in your mod gives you access to all of the `worldedit` functions. The API is useful for tasks such as high-performance node manipulation, alternative interfaces, and map creation. + +If you don't add WorldEdit to your "depends.txt" file, each file in the WorldEdit mod is also independent. For example, one may import the WorldEdit primitives API using the following code: + + dofile(minetest.get_modpath("worldedit").."/primitives.lua") + +AGPLv3 compatible mods may further include WorldEdit files in their own mods. This may be useful if a modder wishes to completely avoid any dependencies on WorldEdit. Note that it is required to give credit to the authors. + +This API is documented in the [WorldEdit API Reference](WorldEdit API.md). + +Axes +---- +The coordinate system is the same as that used by Minetest; positive Y is upwards, positive X is rightwards, and positive Z is forwards, if a player is facing North (positive Z axis). + +When an axis is specified in a WorldEdit chat command, it is specified as one of the following values: `x`, `y`, `z`, or `?`. + +In the GUI, there is a dropdown menu for this purpose. The "Look direction" option has the same effect as `?` does in chat commands. + +The value `?` represents the axis the player is currently facing. If the player is facing more than one axis, the axis the player face direction is closest to will be used. + +Nodes +----- +Node names are required for many types of commands that identify or modify specific types of nodes. They can be specified in a number of ways. + +First, by description - the tooltip that appears when hovering over the item in an inventory. This is case insensitive and includes values such as "Cobblestone" and "bronze block". Note that certain commands (namely, `//replace` and `//replaceinverse`) do not support descriptions that contain spaces in the `` field. + +Second, by name - the node name that is defined by code, but without the mod name prefix. This is case sensitive and includes values such as "piston_normal_off" and "cactus". Nodes defined in the `default` mod always take precedence over other nodes when searching for the correct one, and if there are multiple possible nodes (such as "a:celery" and "b:celery"), one is chosen in no particular order. + +Finally, by full name - the unambiguous identifier of the node, prefixes and all. This is case sensitive and includes values such as "default:stone" and "mesecons:wire_00000000_off". + +The node name "air" can be used anywhere a normal node name can, and acts as a blank node. This is useful for clearing or removing nodes. For example, `//set air` would remove all the nodes in the current WorldEdit region. Similarly, `//sphere 10 air`, when WorldEdit position 1 underground, would dig a large sphere out of the ground. + +Regions +------- +Most WorldEdit commands operate on regions. Regions are a set of two positions that define a 3D cuboid. They are local to each player and chat commands affect only the region for the player giving the commands. + +Each positions together define two opposing corners of the cube. With two opposing corners it is possible to determine both the location and dimensions of the region. + +Regions are not saved between server restarts. They start off as empty regions, and cannot be used with most WorldEdit commands until they are set to valid values. + +Markers +------- +Entities are used to mark the location of the WorldEdit regions. They appear as boxes containing the number 1 or 2, and represent position 1 and 2 of the WorldEdit region, respectively. + +To remove the entities, simply punch them. This does not reset the positions themselves. + +Schematics +---------- +WorldEdit supports two different types of schematics. + +The first is the WorldEdit Schematic format, with the file extension ".we", and in some older versions, ".wem". There have been several previous versions of the WorldEdit Schematic format, but WorldEdit is capable of loading any past versions, and will always support them - there is no need to worry about schematics becoming obselete. + +The current version of the WorldEdit Schematic format, internally known as version 4, is essentially an array of node data tables in Lua 5.2 table syntax. Specifically: + + return { + { + ["y"] = , + ["x"] = , + ["name"] = , + ["z"] = , + ["meta"] = , + ["param2"] = , + ["param1"] = , + }, + <...> + } + +The ordering of the values and minor aspects of the syntax, such as trailing commas or newlines, are not guaranteed to stay the same in future versions. + +The WorldEdit Schematic format is accessed via the WorldEdit API, or WorldEdit serialization chat commands such as `//serialize` and `//deserialize`. + +The second is the Minetest Schematic format (MTS). The details of this format may be found in the Minetest documentation and are out of the scope of this document. Access to this format is done via specialized MTS commands such as `//mtschemcreate` and `//mtschemplace`. + +License +------- +Copyright 2013 sfan5, Anthony Zhang (Uberi/Temperest), and Brett O'Donnell (cornernote). + +This mod is licensed under the [GNU Affero General Public License](http://www.gnu.org/licenses/agpl-3.0.html). + +Basically, this means everyone is free to use, modify, and distribute the files, as long as these modifications are also licensed the same way. + +Most importantly, the Affero variant of the GPL requires you to publish your modifications in source form, even if the mod is run only on the server, and not distributed. diff --git a/mods/Minetest-WorldEdit/Tutorial.md b/mods/Minetest-WorldEdit/Tutorial.md new file mode 100644 index 0000000..abe554a --- /dev/null +++ b/mods/Minetest-WorldEdit/Tutorial.md @@ -0,0 +1,120 @@ +WorldEdit Tutorial +================== +This is a step-by-step tutorial outlining the basic usage of WorldEdit. For more information, see the [README](README.md). + +Let's start with a few assumptions: + +* You have a compatible version of Minetest working. + * See the [README](README.md) for compatibility information. +* You have WorldEdit installed as a mod. + * If using Windows, [MODSTER](https://forum.minetest.net/viewtopic.php?pid=101463) makes installing mods totally painless. + * Simply download the file, extract the archive, and move it to the correct mod folder for Minetest. + * See the installation instructions in [README](README.md) if you need more details. +* You are familiar with the basics of the game. + * How to walk, jump, and climb. + * How to dig, place, and punch blocks. + * One of the following: + * How to type into the chat and read text from it. + * How to open the inventory screen and press buttons on it. + +Overview +-------- +WorldEdit has a "region", which is simply a cuboid area defined by two markers, both of which the player can move around. Every player can have their own region with their own two markers. + +WorldEdit GUI buttons and chat commands generally work inside the region selected, or around the first marker. + +If you are using the chat commands, follow the steps under **Chat Commands**. If you are using the WorldEdit GUI, follow the steps under **WorldEdit GUI**. + +Step 1: Selecting a region +-------------------------- +### Chat Commands + +In the chat prompt, enter `//p set`. In the chat, you are prompted to punch two nodes to set the positions of the two markers. + +Punch a nearby node. Be careful of breakable ones such as torches. A black cube reading "1" will appear around the node. This is the marker for WorldEdit position 1. + +Walk away from the node you just punched. Now, punch another node. A black cube reading "2" will appear around the node. This is the marker for WorldEdit position 2. + +### WorldEdit GUI + +Open the main WorldEdit GUI from your inventory screen. The icon looks like a globe with a red dot in the center. + +Press the "Get/Set Positions" button. On the new screen, press the "Set Position 1" button. The inventory screen should close. + +Punch a nearby node. Be careful of breakable ones such as torches. A black cube reading "1" will appear around the node. This is the marker for WorldEdit position 1. + +Walk away from the node you just punched. Open your inventory again. It should be on the same page as it was before. + +Press the "Set Position 2" button. The inventory screen should close. + +Now, punch another node. A black cube reading "2" will appear around the node. This is the marker for WorldEdit position 2. + +Step 2: Region commands +----------------------- +### Chat Commands + +In the chat prompt, enter `//set mese`. In the chat, you will see a message showing the number of nodes set after a small delay. + +Look at the place between the two markers: it is now filled with MESE blocks! + +The `//set ` command fills the region with whatever node you want. It is a region-oriented command, which means it works inside the WorldEdit region only. + +Now, try a few different variations, such as `//set torch`, `//set cobble`, and `//set water`. + +### WorldEdit GUI + +Open the main WorldEdit GUI from your inventory screen. + +Press the "Set Nodes" button. You should see a new screen with various options for setting nodes. + +Enter "mese" in the "Name" field. Press Search if you would like to see what the node you just entered looks like. + +Press the "Set Nodes" button on this screen. In the chat, you will see a message showing the number of nodes set after a small delay. + +Look at the place between the two markers: it is now filled with MESE blocks! + +The "Set Nodes" function fills the region with whatever node you want. It is a region-oriented command, which means it works inside the WorldEdit region only. + +Now, try a few different variations on the node name, such as "torch", "cobble", and "water". + +Step 3: Position commands +------------------------- +### Chat Commands + +In the chat prompt, enter `//hollowdome 30 glass`. In the chat, you will see a message showing the number of nodes set after a small delay. + +Look around marker 1: it is now surrounded by a hollow glass dome! + +The `//hollowdome ` command creates a hollow dome centered around marker 1, made of any node you want. It is a position-oriented command, which means it works around marker 1 and can go outside the WorldEdit region. + +### WorldEdit GUI + +Open the main WorldEdit GUI from your inventory screen. + +Press the "Sphere/Dome" button. You should see a new screen with various options for making spheres or domes. + +Enter "glass" in the "Name" field. Press Search if you would like to see what the node you just entered looks like. + +Enter "30" in the "Radius" field. + +Press the "Hollow Dome" button on this screen. In the chat, you will see a message showing the number of nodes added after a small delay. + +Look around marker 1: it is now surrounded by a hollow glass dome! + +The "Hollow Dome" function creates a hollow dome centered around marker 1, made of any node you want. It is a position-oriented command, which means it works around marker 1 and can go outside the WorldEdit region. + +Step 4: Other commands +---------------------- +### Chat Commands + +There are many more commands than what is shown here. See the [Chat Commands Reference](Chat Commands.md) for a detailed list of them, along with descriptions and examples for every single one. + +If you're in-game and forgot how a command works, just use the `/help ` command, without the first forward slash. For example, to see some information about the `//set ` command mentioned earlier, simply use `/help /set`. + +A very useful command to check out is the `//save ` command, which can save everything inside the WorldEdit region to a file, stored on the computer hosting the server (the player's computer, in single player mode). You can then later use `//load ` to load the data in a file into a world, even another world on another computer. + +### WorldEdit GUI + +This only scratches the surface of what WorldEdit is capable of. Most of the functions in the WorldEdit GUI correspond to chat commands, and so the [Chat Commands Reference](Chat Commands.md) may be useful if you get stuck. + +It is helpful to explore the various buttons in the interface and check out what they do. Learning the chat command interface is also useful if you use WorldEdit intensively - an experienced chat command user can usually work faster than an experienced WorldEdit GUI user. \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/WorldEdit API.md b/mods/Minetest-WorldEdit/WorldEdit API.md new file mode 100644 index 0000000..c05958e --- /dev/null +++ b/mods/Minetest-WorldEdit/WorldEdit API.md @@ -0,0 +1,230 @@ +WorldEdit API +============= +The WorldEdit API is composed of multiple modules, each of which is independent and can be used without the other. Each module is contained within a single file. + +If needed, individual modules such as visualization.lua can be removed without affecting the rest of the program. The only file that cannot be removed is init.lua, which is necessary for the mod to run. + +For more information, see the [README](README.md). + +General +------- + +### value = worldedit.version + +Contains the current version of WorldEdit in a table of the form `{major=MAJOR_INTEGER, minor=MINOR_INTEGER}`, where `MAJOR_INTEGER` is the major version (the number before the period) as an integer, and `MINOR_INTEGER` is the minor version (the number after the period) as an integer. This is intended for version checking purposes. + +### value = worldedit.version_string + +Contains the current version of WorldEdit in the form of a string `"MAJOR_INTEGER.MINOR_INTEGER"`, where `MAJOR_INTEGER` is the major version (the number before the period) as an integer, and `MINOR_INTEGER` is the minor version (the number after the period) as an integer. This is intended for display purposes. + +Manipulations +------------- +Contained in manipulations.lua, this module allows several node operations to be applied over a region. + +### count = worldedit.set(pos1, pos2, nodename) + +Sets a region defined by positions `pos1` and `pos2` to `nodename`. To clear a region, use "air" as the value of `nodename`. + +Returns the number of nodes set. + +### count = worldedit.replace(pos1, pos2, searchnode, replacenode) + +Replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`. + +Returns the number of nodes replaced. + +### count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode) + +Replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`. + +Returns the number of nodes replaced. + +### count = worldedit.copy(pos1, pos2, axis, amount) + +Copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes. + +Returns the number of nodes copied. + +### count = worldedit.move(pos1, pos2, axis, amount) + +Moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes. + +Returns the number of nodes moved. + +### count = worldedit.stack(pos1, pos2, axis, count) + +Duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times. + +Returns the number of nodes stacked. + +### count, newpos1, newpos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz) + +Stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin. + +Returns the number of nodes stretched, the new scaled position 1, and the new scaled position 2. + +### count, newpos1, newpos2 = worldedit.transpose(pos1, pos2, axis1, axis2) + +Transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes ("x" or "y" or "z"). + +Returns the number of nodes transposed, the new transposed position 1, and the new transposed position 2. + +### count = worldedit.flip(pos1, pos2, axis) + +Flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"). + +Returns the number of nodes flipped. + +### count, newpos2, newpos2 = worldedit.rotate(pos1, pos2, angle) + +Rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around the y axis (supporting 90 degree increments only). + +Returns the number of nodes rotated, the new position 1, and the new position 2. + +### count = worldedit.orient(pos1, pos2, angle) + +Rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis. + +Returns the number of nodes oriented. + +### count = worldedit.fixlight(pos1, pos2) + +Fixes the lighting in a region defined by positions `pos1` and `pos2`. + +Returns the number of nodes updated. + +### count = worldedit.clearobjects(pos1, pos2) + +Clears all objects in a region defined by the positions `pos1` and `pos2`. + +Returns the number of objects cleared. + +Primitives +---------- +Contained in primitives.lua, this module allows the creation of several geometric primitives. + +### count = worldedit.hollow_sphere(pos, radius, nodename) + +Adds a hollow sphere centered at `pos` with radius `radius`, composed of `nodename`. + +Returns the number of nodes added. + +### count = worldedit.sphere(pos, radius, nodename) + +Adds a sphere centered at `pos` with radius `radius`, composed of `nodename`. + +Returns the number of nodes added. + +### count = worldedit.hollow_dome(pos, radius, nodename) + +Adds a hollow dome centered at `pos` with radius `radius`, composed of `nodename`. + +Returns the number of nodes added. + +### count = worldedit.dome(pos, radius, nodename) + +Adds a dome centered at `pos` with radius `radius`, composed of `nodename`. + +Returns the number of nodes added. + +### count = worldedit.hollow_cylinder(pos, axis, length, radius, nodename) + +Adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`. + +Returns the number of nodes added. + +### count = worldedit.cylinder(pos, axis, length, radius, nodename) + +Adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`. + +Returns the number of nodes added. + +### count = worldedit.pyramid(pos, axis, height, nodename) + +Adds a pyramid centered at `pos` along the `axis` axis ("x" or "y" or "z") with height `height`. + +Returns the number of nodes added. + +### count = worldedit.spiral(pos, length, height, spacer, nodename) + +Adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `nodename`. + +Returns the number of nodes added. + +Visualization +------------- +Contained in visualization.lua, this module allows nodes to be visualized in different ways. + +### volume = worldedit.volume(pos1, pos2) + +Determines the volume of the region defined by positions `pos1` and `pos2`. + +Returns the volume. + +### count = worldedit.hide(pos1, pos2) + +Hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes. + +Returns the number of nodes hidden. + +### count = worldedit.suppress(pos1, pos2, nodename) + +Suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes. + +Returns the number of nodes suppressed. + +### count = worldedit.highlight(pos1, pos2, nodename) + +Highlights all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes. + +Returns the number of nodes found. + +### count = worldedit.restore(pos1, pos2) + +Restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`. + +Returns the number of nodes restored. + +Serialization +------------- +Contained in serialization.lua, this module allows regions of nodes to be serialized and deserialized to formats suitable for use outside MineTest. + +### version = worldedit.valueversion(value) + +Determines the version of serialized data `value`. + +Returns the version as a positive integer or 0 for unknown versions. + +### data, count = worldedit.serialize(pos1, pos2) + +Converts the region defined by positions `pos1` and `pos2` into a single string. + +Returns the serialized data and the number of nodes serialized. + +### pos1, pos2, count = worldedit.allocate(originpos, value) + +Determines the volume the nodes represented by string `value` would occupy if deserialized at `originpos`. + +Returns the two corner positions and the number of nodes. + +### count = worldedit.deserialize(originpos, value) + +Loads the nodes represented by string `value` at position `originpos`. + +Returns the number of nodes deserialized. + +Code +---- +Contained in code.lua, this module allows arbitrary Lua code to be used with WorldEdit. + +### error = worldedit.lua(code) + +Executes `code` as a Lua chunk in the global namespace. + +Returns an error if the code fails or nil otherwise. + +### error = worldedit.luatransform(pos1, pos2, code) + +Executes `code` as a Lua chunk in the global namespace with the variable `pos` available, for each node in a region defined by positions `pos1` and `pos2`. + +Returns an error if the code fails or nil otherwise. \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/modpack.txt b/mods/Minetest-WorldEdit/modpack.txt new file mode 100644 index 0000000..e69de29 diff --git a/mods/Minetest-WorldEdit/worldedit/code.lua b/mods/Minetest-WorldEdit/worldedit/code.lua new file mode 100644 index 0000000..8e2d362 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit/code.lua @@ -0,0 +1,48 @@ +worldedit = worldedit or {} +local minetest = minetest --local copy of global + +--executes `code` as a Lua chunk in the global namespace, returning an error if the code fails or nil otherwise +worldedit.lua = function(code) + local operation, message = loadstring(code) + if operation == nil then --code parsing failed + return message + end + local status, message = pcall(operation) + if status == nil then --operation failed + return message + end + return nil +end + +--executes `code` as a Lua chunk in the global namespace with the variable pos available, for each node in a region defined by positions `pos1` and `pos2`, returning an error if the code fails or nil otherwise +worldedit.luatransform = function(pos1, pos2, code) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + local factory, message = loadstring("return function(pos) " .. code .. " end") + if factory == nil then --code parsing failed + return message + end + local operation = factory() + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local pos = {x=pos1.x, y=0, z=0} + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local status, message = pcall(operation, pos) + if status == nil then --operation failed + return message + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return nil +end \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit/compatibility.lua b/mods/Minetest-WorldEdit/worldedit/compatibility.lua new file mode 100644 index 0000000..ff3447f --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit/compatibility.lua @@ -0,0 +1,23 @@ +worldedit = worldedit or {} +local minetest = minetest --local copy of global + +worldedit.allocate_old = worldedit.allocate +worldedit.deserialize_old = worldedit.deserialize +worldedit.metasave = function(pos1, pos2, filename) + local file, err = io.open(filename, "wb") + if err then return 0 end + local data, count = worldedit.serialize(pos1, pos2) + file:write(data) + file:close() + return count +end +worldedit.metaload = function(originpos, filename) + filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem" + local file, err = io.open(filename, "wb") + if err then return 0 end + local data = file:read("*a") + return worldedit.deserialize(originpos, data) +end +worldedit.scale = function(pos1, pos2, factor) + return worldedit.stretch(pos1, pos2, factor, factor, factor) +end \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit/init.lua b/mods/Minetest-WorldEdit/worldedit/init.lua new file mode 100644 index 0000000..a6361b5 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit/init.lua @@ -0,0 +1,25 @@ +worldedit = worldedit or {} +worldedit.version = {major=1, minor=0} +worldedit.version_string = "1.0" + +assert(minetest.get_voxel_manip, string.rep(">", 300) .. "HEY YOU! YES, YOU OVER THERE. THIS VERSION OF WORLDEDIT REQUIRES MINETEST 0.4.8 OR LATER! YOU HAVE AN OLD VERSION." .. string.rep("<", 300)) + +local path = minetest.get_modpath(minetest.get_current_modname()) + +local loadmodule = function(path) + local file = io.open(path) + if not file then + return + end + file:close() + return dofile(path) +end + +loadmodule(path .. "/manipulations.lua") +loadmodule(path .. "/primitives.lua") +loadmodule(path .. "/visualization.lua") +loadmodule(path .. "/serialization.lua") +loadmodule(path .. "/code.lua") +loadmodule(path .. "/compatibility.lua") + +print("[MOD] WorldEdit loaded!") diff --git a/mods/Minetest-WorldEdit/worldedit/manipulations.lua b/mods/Minetest-WorldEdit/worldedit/manipulations.lua new file mode 100644 index 0000000..1d4c6dc --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit/manipulations.lua @@ -0,0 +1,587 @@ +worldedit = worldedit or {} +local minetest = minetest --local copy of global + +--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions +worldedit.sort_pos = function(pos1, pos2) + pos1 = {x=pos1.x, y=pos1.y, z=pos1.z} + pos2 = {x=pos2.x, y=pos2.y, z=pos2.z} + if pos1.x > pos2.x then + pos2.x, pos1.x = pos1.x, pos2.x + end + if pos1.y > pos2.y then + pos2.y, pos1.y = pos1.y, pos2.y + end + if pos1.z > pos2.z then + pos2.z, pos1.z = pos1.z, pos2.z + end + return pos1, pos2 +end + +--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume +worldedit.volume = function(pos1, pos2) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1) +end + +--sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled +worldedit.set = function(pos1, pos2, nodename) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + for i in area:iterp(pos1, pos2) do + nodes[i] = node_id + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return worldedit.volume(pos1, pos2) +end + +--replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced +worldedit.replace = function(pos1, pos2, searchnode, replacenode) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + local nodes = manip:get_data() + local searchnode_id = minetest.get_content_id(searchnode) + local replacenode_id = minetest.get_content_id(replacenode) + local count = 0 + for i in area:iterp(pos1, pos2) do --replace searchnode with replacenode + if nodes[i] == searchnode_id then + nodes[i] = replacenode_id + count = count + 1 + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced +worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + local nodes = manip:get_data() + local searchnode_id = minetest.get_content_id(searchnode) + local replacenode_id = minetest.get_content_id(replacenode) + local count = 0 + for i in area:iterp(pos1, pos2) do --replace anything that is not searchnode with replacenode + if nodes[i] ~= searchnode_id then + nodes[i] = replacenode_id + count = count + 1 + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +worldedit.copy = function(pos1, pos2, axis, amount) --wip: replace the old version below + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + if amount == 0 then + return + end + + local other1, other2 + if axis == "x" then + other1, other2 = "y", "z" + elseif axis == "y" then + other1, other2 = "x", "z" + else --axis == "z" + other1, other2 = "x", "y" + end + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + --prepare slice along axis + local extent = { + [axis] = 1, + [other1]=pos2[other1] - pos1[other1] + 1, + [other2]=pos2[other2] - pos1[other2] + 1, + } + local nodes = {} + local schematic = {size=extent, data=nodes} + + local currentpos = {x=pos1.x, y=pos1.y, z=pos1.z} + local stride = {x=1, y=extent.x, z=extent.x * extent.y} + local get_node = minetest.get_node + for index1 = 1, extent[axis] do --go through each slice + --copy slice into schematic + local newindex1 = (index1 + offset[axis]) * stride[axis] + 1 --offset contributed by axis plus 1 to make it 1-indexed + for index2 = 1, extent[other1] do + local newindex2 = newindex1 + (index2 + offset[other1]) * stride[other1] + for index3 = 1, extent[other2] do + local i = newindex2 + (index3 + offset[other2]) * stride[other2] + local node = get_node(pos) + node.param1 = 255 --node will always appear + nodes[i] = node + end + end + + --copy schematic to target + currentpos[axis] = currentpos[axis] + amount + place_schematic(currentpos, schematic) + + --wip: copy meta + + currentpos[axis] = currentpos[axis] + 1 + end + return worldedit.volume(pos1, pos2) +end + +--copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied +worldedit.copy = function(pos1, pos2, axis, amount) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + if amount < 0 then + local pos = {x=pos1.x, y=0, z=0} + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) --obtain current node + local meta = get_meta(pos):to_table() --get meta of current node + local value = pos[axis] --store current position + pos[axis] = value + amount --move along axis + add_node(pos, node) --copy node to new position + get_meta(pos):from_table(meta) --set metadata of new node + pos[axis] = value --restore old position + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + else + local pos = {x=pos2.x, y=0, z=0} + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) --obtain current node + local meta = get_meta(pos):to_table() --get meta of current node + local value = pos[axis] --store current position + pos[axis] = value + amount --move along axis + add_node(pos, node) --copy node to new position + get_meta(pos):from_table(meta) --set metadata of new node + pos[axis] = value --restore old position + pos.z = pos.z - 1 + end + pos.y = pos.y - 1 + end + pos.x = pos.x - 1 + end + end + return worldedit.volume(pos1, pos2) +end + +--moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved +worldedit.move = function(pos1, pos2, axis, amount) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + --wip: move slice by slice using schematic method in the move axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time and erase original after, using schematic method) + local get_node, get_meta, add_node, remove_node = minetest.get_node, minetest.get_meta, minetest.add_node, minetest.remove_node + if amount < 0 then + local pos = {x=pos1.x, y=0, z=0} + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) --obtain current node + local meta = get_meta(pos):to_table() --get metadata of current node + remove_node(pos) + local value = pos[axis] --store current position + pos[axis] = value + amount --move along axis + add_node(pos, node) --move node to new position + get_meta(pos):from_table(meta) --set metadata of new node + pos[axis] = value --restore old position + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + else + local pos = {x=pos2.x, y=0, z=0} + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) --obtain current node + local meta = get_meta(pos):to_table() --get metadata of current node + remove_node(pos) + local value = pos[axis] --store current position + pos[axis] = value + amount --move along axis + add_node(pos, node) --move node to new position + get_meta(pos):from_table(meta) --set metadata of new node + pos[axis] = value --restore old position + pos.z = pos.z - 1 + end + pos.y = pos.y - 1 + end + pos.x = pos.x - 1 + end + end + return worldedit.volume(pos1, pos2) +end + +--duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked +worldedit.stack = function(pos1, pos2, axis, count) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local length = pos2[axis] - pos1[axis] + 1 + if count < 0 then + count = -count + length = -length + end + local amount = 0 + local copy = worldedit.copy + for i = 1, count do + amount = amount + length + copy(pos1, pos2, axis, amount) + end + return worldedit.volume(pos1, pos2) * count +end + +--stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin, returning the number of nodes scaled, the new scaled position 1, and the new scaled position 2 +worldedit.stretch = function(pos1, pos2, stretchx, stretchy, stretchz) --wip: test this + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --prepare schematic of large node + local get_node, get_meta, place_schematic = minetest.get_node, minetest.get_meta, minetest.place_schematic + local placeholder_node = {name="", param1=255, param2=0} + local nodes = {} + for i = 1, stretchx * stretchy * stretchz do + nodes[i] = placeholder_node + end + local schematic = {size={x=stretchx, y=stretchy, z=stretchz}, data=nodes} + + local sizex, sizey, sizez = stretchx - 1, stretchy - 1, stretchz - 1 + + --make area stay loaded + local manip = minetest.get_voxel_manip() + local new_pos2 = { + x=pos1.x + (pos2.x - pos1.x) * stretchx + sizex, + y=pos1.y + (pos2.y - pos1.y) * stretchy + sizey, + z=pos1.z + (pos2.z - pos1.z) * stretchz + sizez, + } + manip:read_from_map(pos1, new_pos2) + + local pos = {x=pos2.x, y=0, z=0} + local bigpos = {x=0, y=0, z=0} + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) --obtain current node + local meta = get_meta(pos):to_table() --get meta of current node + + --calculate far corner of the big node + local posx = pos1.x + (pos.x - pos1.x) * stretchx + local posy = pos1.y + (pos.y - pos1.y) * stretchy + local posz = pos1.z + (pos.z - pos1.z) * stretchz + + --create large node + placeholder_node.name = node.name + placeholder_node.param2 = node.param2 + bigpos.x, bigpos.y, bigpos.z = posx, posy, posz + place_schematic(bigpos, schematic) + + --fill in large node meta + if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then --node has meta fields + for x = 0, sizex do + for y = 0, sizey do + for z = 0, sizez do + bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z + get_meta(bigpos):from_table(meta) --set metadata of new node + end + end + end + end + pos.z = pos.z - 1 + end + pos.y = pos.y - 1 + end + pos.x = pos.x - 1 + end + return worldedit.volume(pos1, pos2) * stretchx * stretchy * stretchz, pos1, new_pos2 +end + +--transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed, the new transposed position 1, and the new transposed position 2 +worldedit.transpose = function(pos1, pos2, axis1, axis2) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + local compare + local extent1, extent2 = pos2[axis1] - pos1[axis1], pos2[axis2] - pos1[axis2] + + if extent1 > extent2 then + compare = function(extent1, extent2) + return extent1 > extent2 + end + else + compare = function(extent1, extent2) + return extent1 < extent2 + end + end + + --calculate the new position 2 after transposition + local new_pos2 = {x=pos2.x, y=pos2.y, z=pos2.z} + new_pos2[axis1] = pos1[axis1] + extent2 + new_pos2[axis2] = pos1[axis2] + extent1 + + --make area stay loaded + local manip = minetest.get_voxel_manip() + local upperbound = {x=pos2.x, y=pos2.y, z=pos2.z} + if upperbound[axis1] < new_pos2[axis1] then upperbound[axis1] = new_pos2[axis1] end + if upperbound[axis2] < new_pos2[axis2] then upperbound[axis2] = new_pos2[axis2] end + manip:read_from_map(pos1, upperbound) + + local pos = {x=pos1.x, y=0, z=0} + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2] + if compare(extent1, extent2) then --transpose only if below the diagonal + local node1 = get_node(pos) + local meta1 = get_meta(pos):to_table() + local value1, value2 = pos[axis1], pos[axis2] --save position values + pos[axis1], pos[axis2] = pos1[axis1] + extent2, pos1[axis2] + extent1 --swap axis extents + local node2 = get_node(pos) + local meta2 = get_meta(pos):to_table() + add_node(pos, node1) + get_meta(pos):from_table(meta1) + pos[axis1], pos[axis2] = value1, value2 --restore position values + add_node(pos, node2) + get_meta(pos):from_table(meta2) + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return worldedit.volume(pos1, pos2), pos1, new_pos2 +end + +--flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"), returning the number of nodes flipped +worldedit.flip = function(pos1, pos2, axis) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + --wip: flip the region slice by slice along the flip axis using schematic method + local pos = {x=pos1.x, y=0, z=0} + local start = pos1[axis] + pos2[axis] + pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2) + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node1 = get_node(pos) + local meta1 = get_meta(pos):to_table() + local value = pos[axis] + pos[axis] = start - value + local node2 = get_node(pos) + local meta2 = get_meta(pos):to_table() + add_node(pos, node1) + get_meta(pos):from_table(meta1) + pos[axis] = value + add_node(pos, node2) + get_meta(pos):from_table(meta2) + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return worldedit.volume(pos1, pos2) +end + +--rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated +worldedit.rotate = function(pos1, pos2, axis, angle) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + local axis1, axis2 + if axis == "x" then + axis1, axis2 = "z", "y" + elseif axis == "y" then + axis1, axis2 = "x", "z" + else --axis == "z" + axis1, axis2 = "y", "x" + end + angle = angle % 360 + + local count + if angle == 90 then + worldedit.flip(pos1, pos2, axis1) + count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2) + elseif angle == 180 then + worldedit.flip(pos1, pos2, axis1) + count = worldedit.flip(pos1, pos2, axis2) + elseif angle == 270 then + worldedit.flip(pos1, pos2, axis2) + count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2) + end + return count, pos1, pos2 +end + +--rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis, returning the number of nodes oriented +worldedit.orient = function(pos1, pos2, angle) --wip: support 6D facedir rotation along arbitrary axis + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local registered_nodes = minetest.registered_nodes + + local wallmounted = { + [90]={[0]=0, [1]=1, [2]=5, [3]=4, [4]=2, [5]=3}, + [180]={[0]=0, [1]=1, [2]=3, [3]=2, [4]=5, [5]=4}, + [270]={[0]=0, [1]=1, [2]=4, [3]=5, [4]=3, [5]=2} + } + local facedir = { + [90]={[0]=1, [1]=2, [2]=3, [3]=0}, + [180]={[0]=2, [1]=3, [2]=0, [3]=1}, + [270]={[0]=3, [1]=0, [2]=1, [3]=2} + } + + angle = angle % 360 + if angle == 0 then + return 0 + end + local wallmounted_substitution = wallmounted[angle] + local facedir_substitution = facedir[angle] + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local count = 0 + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + local pos = {x=pos1.x, y=0, z=0} + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) + local def = registered_nodes[node.name] + if def then + if def.paramtype2 == "wallmounted" then + node.param2 = wallmounted_substitution[node.param2] + local meta = get_meta(pos):to_table() + add_node(pos, node) + get_meta(pos):from_table(meta) + count = count + 1 + elseif def.paramtype2 == "facedir" then + node.param2 = facedir_substitution[node.param2] + local meta = get_meta(pos):to_table() + add_node(pos, node) + get_meta(pos):from_table(meta) + count = count + 1 + end + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return count +end + +--fixes the lighting in a region defined by positions `pos1` and `pos2`, returning the number of nodes updated +worldedit.fixlight = function(pos1, pos2) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local nodes = minetest.find_nodes_in_area(pos1, pos2, "air") + local dig_node = minetest.dig_node + for _, pos in ipairs(nodes) do + dig_node(pos) + end + return #nodes +end + +--clears all objects in a region defined by the positions `pos1` and `pos2`, returning the number of objects cleared +worldedit.clearobjects = function(pos1, pos2) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local pos1x, pos1y, pos1z = pos1.x, pos1.y, pos1.z + local pos2x, pos2y, pos2z = pos2.x + 1, pos2.y + 1, pos2.z + 1 + local center = {x=(pos1x + pos2x) / 2, y=(pos1y + pos2y) / 2, z=(pos1z + pos2z) / 2} --center of region + local radius = ((center.x - pos1x + 0.5) + (center.y - pos1y + 0.5) + (center.z - pos1z + 0.5)) ^ 0.5 --bounding sphere radius + local count = 0 + for _, obj in pairs(minetest.get_objects_inside_radius(center, radius)) do --all objects in bounding sphere + local entity = obj:get_luaentity() + if not (entity and entity.name:find("^worldedit:")) then --avoid WorldEdit entities + local pos = obj:getpos() + if pos.x >= pos1x and pos.x <= pos2x + and pos.y >= pos1y and pos.y <= pos2y + and pos.z >= pos1z and pos.z <= pos2z then --inside region + obj:remove() + count = count + 1 + end + end + end + return count +end diff --git a/mods/Minetest-WorldEdit/worldedit/primitives.lua b/mods/Minetest-WorldEdit/worldedit/primitives.lua new file mode 100644 index 0000000..1baa29e --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit/primitives.lua @@ -0,0 +1,470 @@ +worldedit = worldedit or {} +local minetest = minetest --local copy of global + +--adds a hollow sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added +worldedit.hollow_sphere = function(pos, radius, nodename) + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius} + local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius} + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1) + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride + local count = 0 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed + for y = -radius, radius do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + local squared = x * x + y * y + z * z + if squared >= min_radius and squared <= max_radius then --position is on surface of sphere + local i = newy + (x + offsetx) + nodes[i] = node_id + count = count + 1 + end + end + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--adds a sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added +worldedit.sphere = function(pos, radius, nodename) + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius} + local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius} + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local max_radius = radius * (radius + 1) + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride + local count = 0 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed + for y = -radius, radius do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + if x * x + y * y + z * z <= max_radius then --position is inside sphere + local i = newy + (x + offsetx) + nodes[i] = node_id + count = count + 1 + end + end + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--adds a hollow dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added +worldedit.hollow_dome = function(pos, radius, nodename) + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius} + local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius} + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + local miny, maxy = 0, radius + if radius < 0 then + radius = -radius + miny, maxy = -radius, 0 + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1) + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride + local count = 0 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed + for y = miny, maxy do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + local squared = x * x + y * y + z * z + if squared >= min_radius and squared <= max_radius then --position is on surface of sphere + local i = newy + (x + offsetx) + nodes[i] = node_id + count = count + 1 + end + end + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--adds a dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added +worldedit.dome = function(pos, radius, nodename) + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius} + local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius} + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + local miny, maxy = 0, radius + if radius < 0 then + radius = -radius + miny, maxy = -radius, 0 + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local max_radius = radius * (radius + 1) + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride + local count = 0 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed + for y = miny, maxy do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + if x * x + y * y + z * z <= max_radius then --position is inside sphere + local i = newy + (x + offsetx) + nodes[i] = node_id + count = count + 1 + end + end + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added +worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename) + local other1, other2 + if axis == "x" then + other1, other2 = "y", "z" + elseif axis == "y" then + other1, other2 = "x", "z" + else --axis == "z" + other1, other2 = "x", "y" + end + + --handle negative lengths + local currentpos = {x=pos.x, y=pos.y, z=pos.z} + if length < 0 then + length = -length + currentpos[axis] = currentpos[axis] - length + end + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local pos1 = { + [axis]=currentpos[axis], + [other1]=currentpos[other1] - radius, + [other2]=currentpos[other2] - radius + } + local pos2 = { + [axis]=currentpos[axis] + length - 1, + [other1]=currentpos[other1] + radius, + [other2]=currentpos[other2] + radius + } + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1) + local stride = {x=1, y=area.ystride, z=area.zstride} + local offset = {x=currentpos.x - emerged_pos1.x, y=currentpos.y - emerged_pos1.y, z=currentpos.z - emerged_pos1.z} + local min_slice, max_slice = offset[axis], offset[axis] + length - 1 + local count = 0 + for index2 = -radius, radius do + local newindex2 = (index2 + offset[other1]) * stride[other1] + 1 --offset contributed by other axis 1 plus 1 to make it 1-indexed + for index3 = -radius, radius do + local newindex3 = newindex2 + (index3 + offset[other2]) * stride[other2] + local squared = index2 * index2 + index3 * index3 + if squared >= min_radius and squared <= max_radius then --position is on surface of cylinder + for index1 = min_slice, max_slice do --add column along axis + local i = newindex3 + index1 * stride[axis] + nodes[i] = node_id + end + count = count + length + end + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added +worldedit.cylinder = function(pos, axis, length, radius, nodename) + local other1, other2 + if axis == "x" then + other1, other2 = "y", "z" + elseif axis == "y" then + other1, other2 = "x", "z" + else --axis == "z" + other1, other2 = "x", "y" + end + + --handle negative lengths + local currentpos = {x=pos.x, y=pos.y, z=pos.z} + if length < 0 then + length = -length + currentpos[axis] = currentpos[axis] - length + end + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local pos1 = { + [axis]=currentpos[axis], + [other1]=currentpos[other1] - radius, + [other2]=currentpos[other2] - radius + } + local pos2 = { + [axis]=currentpos[axis] + length - 1, + [other1]=currentpos[other1] + radius, + [other2]=currentpos[other2] + radius + } + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local max_radius = radius * (radius + 1) + local stride = {x=1, y=area.ystride, z=area.zstride} + local offset = {x=currentpos.x - emerged_pos1.x, y=currentpos.y - emerged_pos1.y, z=currentpos.z - emerged_pos1.z} + local min_slice, max_slice = offset[axis], offset[axis] + length - 1 + local count = 0 + for index2 = -radius, radius do + local newindex2 = (index2 + offset[other1]) * stride[other1] + 1 --offset contributed by other axis 1 plus 1 to make it 1-indexed + for index3 = -radius, radius do + local newindex3 = newindex2 + (index3 + offset[other2]) * stride[other2] + if index2 * index2 + index3 * index3 <= max_radius then --position is within cylinder + for index1 = min_slice, max_slice do --add column along axis + local i = newindex3 + index1 * stride[axis] + nodes[i] = node_id + end + count = count + length + end + end + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--adds a pyramid centered at `pos` with height `height`, composed of `nodename`, returning the number of nodes added +worldedit.pyramid = function(pos, axis, height, nodename) + local other1, other2 + if axis == "x" then + other1, other2 = "y", "z" + elseif axis == "y" then + other1, other2 = "x", "z" + else --axis == "z" + other1, other2 = "x", "y" + end + + local pos1 = {x=pos.x - height, y=pos.y - height, z=pos.z - height} + local pos2 = {x=pos.x + height, y=pos.y + height, z=pos.z + height} + + --handle inverted pyramids + local startaxis, endaxis, step + if height > 0 then + height = height - 1 + step = 1 + pos1[axis] = pos[axis] --upper half of box + else + height = height + 1 + step = -1 + pos2[axis] = pos[axis] --lower half of box + end + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local stride = {x=1, y=area.ystride, z=area.zstride} + local offset = {x=pos.x - emerged_pos1.x, y=pos.y - emerged_pos1.y, z=pos.z - emerged_pos1.z} + local size = height * step + local count = 0 + for index1 = 0, height, step do --go through each level of the pyramid + local newindex1 = (index1 + offset[axis]) * stride[axis] + 1 --offset contributed by axis plus 1 to make it 1-indexed + for index2 = -size, size do + local newindex2 = newindex1 + (index2 + offset[other1]) * stride[other1] + for index3 = -size, size do + local i = newindex2 + (index3 + offset[other2]) * stride[other2] + nodes[i] = node_id + end + end + count = count + (size * 2 + 1) ^ 2 + size = size - 1 + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end + +--adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added +worldedit.spiral = function(pos, length, height, spacer, nodename) + local extent = math.ceil(length / 2) + local pos1 = {x=pos.x - extent, y=pos.y, z=pos.z - extent} + local pos2 = {x=pos.x + extent, y=pos.y + height, z=pos.z + extent} + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --set up variables + local node_id = minetest.get_content_id(nodename) + local stride = {x=1, y=area.ystride, z=area.zstride} + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local i = offsetz * stride.z + offsety * stride.y + offsetx + 1 + + --add first column + local count = height + local column = i + for y = 1, height do + nodes[column] = node_id + column = column + stride.y + end + + --add spiral segments + local strideaxis, strideother = stride.x, stride.z + local sign = -1 + local segment_length = 0 + spacer = spacer + 1 + for segment = 1, math.floor(length / spacer) * 2 do --go through each segment except the last + if segment % 2 == 1 then --change sign and length every other turn starting with the first + sign = -sign + segment_length = segment_length + spacer + end + for index = 1, segment_length do --fill segment + i = i + strideaxis * sign --move along the direction of the segment + local column = i + for y = 1, height do --add column + nodes[column] = node_id + column = column + stride.y + end + end + count = count + segment_length * height + strideaxis, strideother = strideother, strideaxis --swap axes + end + + --add shorter final segment + sign = -sign + for index = 1, segment_length do + i = i + strideaxis * sign + local column = i + for y = 1, height do --add column + nodes[column] = node_id + column = column + stride.y + end + end + count = count + segment_length * height + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + + return count +end \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit/serialization.lua b/mods/Minetest-WorldEdit/worldedit/serialization.lua new file mode 100644 index 0000000..bbedca5 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit/serialization.lua @@ -0,0 +1,273 @@ +worldedit = worldedit or {} +local minetest = minetest --local copy of global + +--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions +worldedit.sort_pos = function(pos1, pos2) + pos1 = {x=pos1.x, y=pos1.y, z=pos1.z} + pos2 = {x=pos2.x, y=pos2.y, z=pos2.z} + if pos1.x > pos2.x then + pos2.x, pos1.x = pos1.x, pos2.x + end + if pos1.y > pos2.y then + pos2.y, pos1.y = pos1.y, pos2.y + end + if pos1.z > pos2.z then + pos2.z, pos1.z = pos1.z, pos2.z + end + return pos1, pos2 +end + +--determines the version of serialized data `value`, returning the version as a positive integer or 0 for unknown versions +worldedit.valueversion = function(value) + if value:find("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)") and not value:find("%{") then --previous list format + return 3 + elseif value:find("^[^\"']+%{%d+%}") then + if value:find("%[\"meta\"%]") then --previous meta flat table format + return 2 + end + return 1 --original flat table format + elseif value:find("%{") then --current nested table format + return 4 + end + return 0 --unknown format +end + +--converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized +worldedit.serialize = function(pos1, pos2) + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local pos = {x=pos1.x, y=0, z=0} + local count = 0 + local result = {} + local get_node, get_meta = minetest.get_node, minetest.get_meta + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) + if node.name ~= "air" and node.name ~= "ignore" then + count = count + 1 + local meta = get_meta(pos):to_table() + + --convert metadata itemstacks to itemstrings + for name, inventory in pairs(meta.inventory) do + for index, stack in ipairs(inventory) do + inventory[index] = stack.to_string and stack:to_string() or stack + end + end + + result[count] = { + x = pos.x - pos1.x, + y = pos.y - pos1.y, + z = pos.z - pos1.z, + name = node.name, + param1 = node.param1, + param2 = node.param2, + meta = meta, + } + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + result = minetest.serialize(result) --convert entries to a string + return result, count +end + +--determines the volume the nodes represented by string `value` would occupy if deserialized at `originpos`, returning the two corner positions and the number of nodes +--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible) +worldedit.allocate = function(originpos, value) + local huge = math.huge + local pos1x, pos1y, pos1z = huge, huge, huge + local pos2x, pos2y, pos2z = -huge, -huge, -huge + local originx, originy, originz = originpos.x, originpos.y, originpos.z + local count = 0 + local version = worldedit.valueversion(value) + if version == 1 or version == 2 then --flat table format + --obtain the node table + local get_tables = loadstring(value) + if get_tables then --error loading value + return originpos, originpos, count + end + local tables = get_tables() + + --transform the node table into an array of nodes + for i = 1, #tables do + for j, v in pairs(tables[i]) do + if type(v) == "table" then + tables[i][j] = tables[v[1]] + end + end + end + local nodes = tables[1] + + --check the node array + count = #nodes + if version == 1 then --original flat table format + for index = 1, count do + local entry = nodes[index] + local pos = entry[1] + local x, y, z = originx - pos.x, originy - pos.y, originz - pos.z + if x < pos1x then pos1x = x end + if y < pos1y then pos1y = y end + if z < pos1z then pos1z = z end + if x > pos2x then pos2x = x end + if y > pos2y then pos2y = y end + if z > pos2z then pos2z = z end + end + else --previous meta flat table format + for index = 1, count do + local entry = nodes[index] + local x, y, z = originx - entry.x, originy - entry.y, originz - entry.z + if x < pos1x then pos1x = x end + if y < pos1y then pos1y = y end + if z < pos1z then pos1z = z end + if x > pos2x then pos2x = x end + if y > pos2y then pos2y = y end + if z > pos2z then pos2z = z end + end + end + elseif version == 3 then --previous list format + for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do --match node entries + x, y, z = originx + tonumber(x), originy + tonumber(y), originz + tonumber(z) + if x < pos1x then pos1x = x end + if y < pos1y then pos1y = y end + if z < pos1z then pos1z = z end + if x > pos2x then pos2x = x end + if y > pos2y then pos2y = y end + if z > pos2z then pos2z = z end + count = count + 1 + end + elseif version == 4 then --current nested table format + --wip: this is a filthy hack that works surprisingly well + value = value:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1) + local escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end) + local startpos, startpos1, endpos = 1, 1 + local nodes = {} + while true do + startpos, endpos = escaped:find("},%s*{", startpos) + if not startpos then + break + end + local current = value:sub(startpos1, startpos) + table.insert(nodes, minetest.deserialize("return " .. current)) + startpos, startpos1 = endpos, endpos + end + table.insert(nodes, minetest.deserialize("return " .. value:sub(startpos1))) + + --local nodes = minetest.deserialize(value) --wip: this is broken for larger tables in the current version of LuaJIT + + count = #nodes + for index = 1, count do + local entry = nodes[index] + x, y, z = originx + entry.x, originy + entry.y, originz + entry.z + if x < pos1x then pos1x = x end + if y < pos1y then pos1y = y end + if z < pos1z then pos1z = z end + if x > pos2x then pos2x = x end + if y > pos2y then pos2y = y end + if z > pos2z then pos2z = z end + end + end + local pos1 = {x=pos1x, y=pos1y, z=pos1z} + local pos2 = {x=pos2x, y=pos2y, z=pos2z} + return pos1, pos2, count +end + +--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized +--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible) +worldedit.deserialize = function(originpos, value) + --make area stay loaded + local pos1, pos2 = worldedit.allocate(originpos, value) + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local originx, originy, originz = originpos.x, originpos.y, originpos.z + local count = 0 + local add_node, get_meta = minetest.add_node, minetest.get_meta + local version = worldedit.valueversion(value) + if version == 1 or version == 2 then --original flat table format + --obtain the node table + local get_tables = loadstring(value) + if not get_tables then --error loading value + return count + end + local tables = get_tables() + + --transform the node table into an array of nodes + for i = 1, #tables do + for j, v in pairs(tables[i]) do + if type(v) == "table" then + tables[i][j] = tables[v[1]] + end + end + end + local nodes = tables[1] + + --load the node array + count = #nodes + if version == 1 then --original flat table format + for index = 1, count do + local entry = nodes[index] + local pos = entry[1] + pos.x, pos.y, pos.z = originx - pos.x, originy - pos.y, originz - pos.z + add_node(pos, entry[2]) + end + else --previous meta flat table format + for index = 1, #nodes do + local entry = nodes[index] + entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z + add_node(entry, entry) --entry acts both as position and as node + get_meta(entry):from_table(entry.meta) + end + end + elseif version == 3 then --previous list format + local pos = {x=0, y=0, z=0} + local node = {name="", param1=0, param2=0} + for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do --match node entries + pos.x, pos.y, pos.z = originx + tonumber(x), originy + tonumber(y), originz + tonumber(z) + node.name, node.param1, node.param2 = name, param1, param2 + add_node(pos, node) + count = count + 1 + end + elseif version == 4 then --current nested table format + --wip: this is a filthy hack that works surprisingly well + value = value:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1) + local escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end) + local startpos, startpos1, endpos = 1, 1 + local nodes = {} + while true do + startpos, endpos = escaped:find("},%s*{", startpos) + if not startpos then + break + end + local current = value:sub(startpos1, startpos) + table.insert(nodes, minetest.deserialize("return " .. current)) + startpos, startpos1 = endpos, endpos + end + table.insert(nodes, minetest.deserialize("return " .. value:sub(startpos1))) + + --local nodes = minetest.deserialize(value) --wip: this is broken for larger tables in the current version of LuaJIT + + --load the nodes + count = #nodes + for index = 1, count do + local entry = nodes[index] + entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z + add_node(entry, entry) --entry acts both as position and as node + end + + --load the metadata + for index = 1, count do + local entry = nodes[index] + get_meta(entry):from_table(entry.meta) + end + end + return count +end diff --git a/mods/Minetest-WorldEdit/worldedit/visualization.lua b/mods/Minetest-WorldEdit/worldedit/visualization.lua new file mode 100644 index 0000000..dbee5d0 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit/visualization.lua @@ -0,0 +1,142 @@ +worldedit = worldedit or {} +local minetest = minetest --local copy of global + +--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions +worldedit.sort_pos = function(pos1, pos2) + pos1 = {x=pos1.x, y=pos1.y, z=pos1.z} + pos2 = {x=pos2.x, y=pos2.y, z=pos2.z} + if pos1.x > pos2.x then + pos2.x, pos1.x = pos1.x, pos2.x + end + if pos1.y > pos2.y then + pos2.y, pos1.y = pos1.y, pos2.y + end + if pos1.z > pos2.z then + pos2.z, pos1.z = pos1.z, pos2.z + end + return pos1, pos2 +end + +--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume +worldedit.volume = function(pos1, pos2) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1) +end + +minetest.register_node("worldedit:placeholder", { + drawtype = "airlike", + paramtype = "light", + sunlight_propagates = true, + diggable = false, + groups = {not_in_creative_inventory=1}, +}) + +--hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes hidden +worldedit.hide = function(pos1, pos2) + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local pos = {x=pos1.x, y=0, z=0} + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) + if node.name ~= "worldedit:placeholder" then + local data = get_meta(pos):to_table() --obtain metadata of original node + data.fields.worldedit_placeholder = node.name --add the node's name + node.name = "worldedit:placeholder" --set node name + add_node(pos, node) --add placeholder node + get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return worldedit.volume(pos1, pos2) +end + +--suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes suppressed +worldedit.suppress = function(pos1, pos2, nodename) + --ignore placeholder supression + if nodename == "worldedit:placeholder" then + return 0 + end + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local nodes = minetest.find_nodes_in_area(pos1, pos2, nodename) + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + for _, pos in ipairs(nodes) do + local node = get_node(pos) + local data = get_meta(pos):to_table() --obtain metadata of original node + data.fields.worldedit_placeholder = node.name --add the node's name + node.name = "worldedit:placeholder" --set node name + add_node(pos, node) --add placeholder node + get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata + end + return #nodes +end + +--highlights all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes, returning the number of nodes found +worldedit.highlight = function(pos1, pos2, nodename) + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local pos = {x=pos1.x, y=0, z=0} + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + local count = 0 + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) + if node.name == nodename then --node found + count = count + 1 + elseif node.name ~= "worldedit:placeholder" then --hide other nodes + local data = get_meta(pos):to_table() --obtain metadata of original node + data.fields.worldedit_placeholder = node.name --add the node's name + node.name = "worldedit:placeholder" --set node name + add_node(pos, node) --add placeholder node + get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return count +end + +--restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`, returning the number of nodes restored +worldedit.restore = function(pos1, pos2) + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local nodes = minetest.find_nodes_in_area(pos1, pos2, "worldedit:placeholder") + local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node + for _, pos in ipairs(nodes) do + local node = get_node(pos) + local data = get_meta(pos):to_table() --obtain node metadata + node.name = data.fields.worldedit_placeholder --set node name + data.fields.worldedit_placeholder = nil --delete old nodename + add_node(pos, node) --add original node + get_meta(pos):from_table(data) --set original node metadata + end + return #nodes +end diff --git a/mods/Minetest-WorldEdit/worldedit_commands/depends.txt b/mods/Minetest-WorldEdit/worldedit_commands/depends.txt new file mode 100644 index 0000000..df8caff --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_commands/depends.txt @@ -0,0 +1 @@ +worldedit \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit_commands/init.lua b/mods/Minetest-WorldEdit/worldedit_commands/init.lua new file mode 100644 index 0000000..2bbfeed --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_commands/init.lua @@ -0,0 +1,1079 @@ +minetest.register_privilege("worldedit", "Can use WorldEdit commands") + +--wip: fold the hollow stuff into the main functions and add a hollow flag at the end, then add the compatibility stuff + +worldedit.set_pos = {} +worldedit.inspect = {} + +worldedit.pos1 = {} +worldedit.pos2 = {} +if minetest.place_schematic then + worldedit.prob_pos = {} + worldedit.prob_list = {} +end + +dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua") +dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua") + +local get_position = function(name) + local pos1 = worldedit.pos1[name] + if pos1 == nil then + worldedit.player_notify(name, "no position 1 selected") + end + return pos1 +end + +local get_node = function(name, nodename) + local node = worldedit.normalize_nodename(nodename) + if not node then + worldedit.player_notify(name, "invalid node name: " .. nodename) + return nil + end + return node +end + +worldedit.player_notify = function(name, message) + minetest.chat_send_player(name, "WorldEdit -!- " .. message, false) +end + +--determines whether `nodename` is a valid node name, returning a boolean +worldedit.normalize_nodename = function(nodename) + if nodename == "" then return nil end + local fullname = ItemStack({name=nodename}):get_name() --resolve aliases of node names to full names + if minetest.registered_nodes[fullname] or fullname == "air" then --directly found node name or alias of nodename + return fullname + end + for key, value in pairs(minetest.registered_nodes) do + if key:find(":" .. nodename, 1, true) then --found in mod + return key + end + end + nodename = nodename:lower() --lowercase both for case insensitive comparison + for key, value in pairs(minetest.registered_nodes) do + if value.description:lower() == nodename then --found in description + return key + end + end + return nil +end + +--determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1) +worldedit.player_axis = function(name) + local dir = minetest.get_player_by_name(name):get_look_dir() + local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z) + if x > y then + if x > z then + return "x", dir.x > 0 and 1 or -1 + end + elseif y > z then + return "y", dir.y > 0 and 1 or -1 + end + return "z", dir.z > 0 and 1 or -1 +end + +minetest.register_chatcommand("/about", { + params = "", + description = "Get information about the mod", + func = function(name, param) + worldedit.player_notify(name, "WorldEdit " .. worldedit.version_string .. " is available on this server. Type /help to get a list of commands, or get more information at https://github.com/Uberi/MineTest-WorldEdit/") + end, +}) + +minetest.register_chatcommand("/inspect", { + params = "on/off/1/0/true/false/yes/no/enable/disable/", + description = "Enable or disable node inspection", + privs = {worldedit=true}, + func = function(name, param) + if param == "on" or param == "1" or param == "true" or param == "yes" or param == "enable" or param == "" then + worldedit.inspect[name] = true + local axis, sign = worldedit.player_axis(name) + worldedit.player_notify(name, string.format("inspector: inspection enabled for %s, currently facing the %s axis", + name, axis .. (sign > 0 and "+" or "-"))) + elseif param == "off" or param == "0" or param == "false" or param == "no" or param == "disable" then + worldedit.inspect[name] = nil + worldedit.player_notify(name, "inspector: inspection disabled") + else + worldedit.player_notify(name, "invalid usage: " .. param) + end + end, +}) + +minetest.register_on_punchnode(function(pos, node, puncher) + local name = puncher:get_player_name() + if worldedit.inspect[name] then + if minetest.check_player_privs(name, {worldedit=true}) then + local axis, sign = worldedit.player_axis(name) + message = string.format("inspector: %s at %s (param1=%d, param2=%d) punched by %s facing the %s axis", + node.name, minetest.pos_to_string(pos), node.param1, node.param2, name, axis .. (sign > 0 and "+" or "-")) + else + message = "inspector: worldedit privileges required" + end + worldedit.player_notify(name, message) + end +end) + +minetest.register_chatcommand("/reset", { + params = "", + description = "Reset the region so that it is empty", + privs = {worldedit=true}, + func = function(name, param) + worldedit.pos1[name] = nil + worldedit.pos2[name] = nil + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + worldedit.set_pos[name] = nil + worldedit.player_notify(name, "region reset") + end, +}) + +minetest.register_chatcommand("/mark", { + params = "", + description = "Show markers at the region positions", + privs = {worldedit=true}, + func = function(name, param) + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + worldedit.player_notify(name, "region marked") + end, +}) + +minetest.register_chatcommand("/unmark", { + params = "", + description = "Hide markers if currently shown", + privs = {worldedit=true}, + func = function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + worldedit.pos1[name] = nil + worldedit.pos2[name] = nil + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + worldedit.pos1[name] = pos1 + worldedit.pos2[name] = pos2 + worldedit.player_notify(name, "region unmarked") + end, +}) + +minetest.register_chatcommand("/pos1", { + params = "", + description = "Set WorldEdit region position 1 to the player's location", + privs = {worldedit=true}, + func = function(name, param) + local pos = minetest.get_player_by_name(name):getpos() + pos.x, pos.y, pos.z = math.floor(pos.x + 0.5), math.floor(pos.y + 0.5), math.floor(pos.z + 0.5) + worldedit.pos1[name] = pos + worldedit.mark_pos1(name) + worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos)) + end, +}) + +minetest.register_chatcommand("/pos2", { + params = "", + description = "Set WorldEdit region position 2 to the player's location", + privs = {worldedit=true}, + func = function(name, param) + local pos = minetest.get_player_by_name(name):getpos() + pos.x, pos.y, pos.z = math.floor(pos.x + 0.5), math.floor(pos.y + 0.5), math.floor(pos.z + 0.5) + worldedit.pos2[name] = pos + worldedit.mark_pos2(name) + worldedit.player_notify(name, "position 2 set to " .. minetest.pos_to_string(pos)) + end, +}) + +minetest.register_chatcommand("/p", { + params = "set/set1/set2/get", + description = "Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region", + privs = {worldedit=true}, + func = function(name, param) + if param == "set" then --set both WorldEdit positions + worldedit.set_pos[name] = "pos1" + worldedit.player_notify(name, "select positions by punching two nodes") + elseif param == "set1" then --set WorldEdit position 1 + worldedit.set_pos[name] = "pos1only" + worldedit.player_notify(name, "select position 1 by punching a node") + elseif param == "set2" then --set WorldEdit position 2 + worldedit.set_pos[name] = "pos2" + worldedit.player_notify(name, "select position 2 by punching a node") + elseif param == "get" then --display current WorldEdit positions + if worldedit.pos1[name] ~= nil then + worldedit.player_notify(name, "position 1: " .. minetest.pos_to_string(worldedit.pos1[name])) + else + worldedit.player_notify(name, "position 1 not set") + end + if worldedit.pos2[name] ~= nil then + worldedit.player_notify(name, "position 2: " .. minetest.pos_to_string(worldedit.pos2[name])) + else + worldedit.player_notify(name, "position 2 not set") + end + else + worldedit.player_notify(name, "unknown subcommand: " .. param) + end + end, +}) + +minetest.register_chatcommand("/fixedpos", { + params = "set1/set2 x y z", + description = "Set a WorldEdit region position to the position at (, , )", + privs = {worldedit=true}, + func = function(name, param) + local found, _, flag, x, y, z = param:find("^(set[12])%s+([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + local pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)} + if flag == "set1" then + worldedit.pos1[name] = pos + worldedit.mark_pos1(name) + worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos)) + else --flag == "set2" + worldedit.pos2[name] = pos + worldedit.mark_pos2(name) + worldedit.player_notify(name, "position 2 set to " .. minetest.pos_to_string(pos)) + end + end, +}) + +minetest.register_on_punchnode(function(pos, node, puncher) + local name = puncher:get_player_name() + if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position + if worldedit.set_pos[name] == "pos1" then --setting position 1 + worldedit.pos1[name] = pos + worldedit.mark_pos1(name) + worldedit.set_pos[name] = "pos2" --set position 2 on the next invocation + worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos)) + elseif worldedit.set_pos[name] == "pos1only" then --setting position 1 only + worldedit.pos1[name] = pos + worldedit.mark_pos1(name) + worldedit.set_pos[name] = nil --finished setting positions + worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos)) + elseif worldedit.set_pos[name] == "pos2" then --setting position 2 + worldedit.pos2[name] = pos + worldedit.mark_pos2(name) + worldedit.set_pos[name] = nil --finished setting positions + worldedit.player_notify(name, "position 2 set to " .. minetest.pos_to_string(pos)) + elseif worldedit.set_pos[name] == "prob" then --setting Minetest schematic node probabilities + worldedit.prob_pos[name] = pos + minetest.show_formspec(puncher:get_player_name(), "prob_val_enter", "field[text;;]") + end + end +end) + +minetest.register_chatcommand("/volume", { + params = "", + description = "Display the volume of the current WorldEdit region", + privs = {worldedit=true}, + func = function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if pos1 == nil or pos2 == nil then + worldedit.player_notify(name, "no region selected") + return nil + end + + local volume = worldedit.volume(pos1, pos2) + local abs = math.abs + worldedit.player_notify(name, "current region has a volume of " .. volume .. " nodes (" + .. abs(pos2.x - pos1.x) + 1 .. "*" + .. abs(pos2.y - pos1.y) + 1 .. "*" + .. abs(pos2.z - pos1.z) + 1 .. ")") + end, +}) + +local check_set = function(name, param) + local node = get_node(name, param) + if not node then return nil end + return check_region(name, param) +end + +minetest.register_chatcommand("/set", { + params = "", + description = "Set the current WorldEdit region to ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local node = get_node(name, param) + local count = worldedit.set(pos1, pos2, node) + worldedit.player_notify(name, count .. " nodes set") + end, check_set), +}) + +local check_replace = function(name, param) + local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local newsearchnode = worldedit.normalize_nodename(searchnode) + if not newsearchnode then + worldedit.player_notify(name, "invalid search node name: " .. searchnode) + return nil + end + local newreplacenode = worldedit.normalize_nodename(replacenode) + if not newreplacenode then + worldedit.player_notify(name, "invalid replace node name: " .. replacenode) + return nil + end + return check_region(name, param) +end + +minetest.register_chatcommand("/replace", { + params = " ", + description = "Replace all instances of with in the current WorldEdit region", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$") + local newsearchnode = worldedit.normalize_nodename(searchnode) + local newreplacenode = worldedit.normalize_nodename(replacenode) + local count = worldedit.replace(pos1, pos2, newsearchnode, newreplacenode) + worldedit.player_notify(name, count .. " nodes replaced") + end, check_replace), +}) + +minetest.register_chatcommand("/replaceinverse", { + params = " ", + description = "Replace all nodes other than with in the current WorldEdit region", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$") + local newsearchnode = worldedit.normalize_nodename(searchnode) + local newreplacenode = worldedit.normalize_nodename(replacenode) + local count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode) + worldedit.player_notify(name, count .. " nodes replaced") + end, check_replace), +}) + +local check_sphere = function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return math.ceil((4 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of sphere +end + +minetest.register_chatcommand("/hollowsphere", { + params = " ", + description = "Add hollow sphere centered at WorldEdit position 1 with radius , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + local node = get_node(name, nodename) + local count = worldedit.hollow_sphere(pos, tonumber(radius), node) + worldedit.player_notify(name, count .. " nodes added") + end, check_sphere), +}) + +minetest.register_chatcommand("/sphere", { + params = " ", + description = "Add sphere centered at WorldEdit position 1 with radius , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + local node = get_node(name, nodename) + local count = worldedit.sphere(pos, tonumber(radius), node) + worldedit.player_notify(name, count .. " nodes added") + end, check_sphere), +}) + +local check_dome = function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return math.ceil((2 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of dome +end + +minetest.register_chatcommand("/hollowdome", { + params = " ", + description = "Add hollow dome centered at WorldEdit position 1 with radius , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + local node = get_node(name, nodename) + local count = worldedit.hollow_dome(pos, tonumber(radius), node) + worldedit.player_notify(name, count .. " nodes added") + end, check_dome), +}) + +minetest.register_chatcommand("/dome", { + params = " ", + description = "Add dome centered at WorldEdit position 1 with radius , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + local node = get_node(name, nodename) + local count = worldedit.dome(pos, tonumber(radius), node) + worldedit.player_notify(name, count .. " nodes added") + end, check_dome), +}) + +local check_cylinder = function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return math.ceil(math.pi * (tonumber(radius) ^ 2) * tonumber(length)) +end + +minetest.register_chatcommand("/hollowcylinder", { + params = "x/y/z/? ", + description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length and radius , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + length = tonumber(length) + if axis == "?" then + axis, sign = worldedit.player_axis(name) + length = length * sign + end + local node = get_node(name, nodename) + local count = worldedit.hollow_cylinder(pos, axis, length, tonumber(radius), node) + worldedit.player_notify(name, count .. " nodes added") + end, check_cylinder), +}) + +minetest.register_chatcommand("/cylinder", { + params = "x/y/z/? ", + description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length and radius , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + length = tonumber(length) + if axis == "?" then + axis, sign = worldedit.player_axis(name) + length = length * sign + end + local node = get_node(name, nodename) + local count = worldedit.cylinder(pos, axis, length, tonumber(radius), node) + worldedit.player_notify(name, count .. " nodes added") + end, check_cylinder), +}) + +minetest.register_chatcommand("/pyramid", { + params = "x/y/z/? ", + description = "Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = get_position(name) + local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$") + height = tonumber(height) + if axis == "?" then + axis, sign = worldedit.player_axis(name) + height = height * sign + end + local node = get_node(name, nodename) + local count = worldedit.pyramid(pos, axis, height, node) + worldedit.player_notify(name, count .. " nodes added") + end, + function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + height = tonumber(height) + return math.ceil(((height * 2 + 1) ^ 2) * height / 3) + end), +}) + +minetest.register_chatcommand("/spiral", { + params = " ", + description = "Add spiral centered at WorldEdit position 1 with side length , height , space between walls , composed of ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + local node = get_node(name, nodename) + local count = worldedit.spiral(pos, tonumber(length), tonumber(height), tonumber(space), node) + worldedit.player_notify(name, count .. " nodes added") + end, + function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return check_region(name, param) + end), +}) + +minetest.register_chatcommand("/copy", { + params = "x/y/z/? ", + description = "Copy the current WorldEdit region along the x/y/z/? axis by nodes", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + amount = tonumber(amount) + if axis == "?" then + axis, sign = worldedit.player_axis(name) + amount = amount * sign + end + + local count = worldedit.copy(pos1, pos2, axis, amount) + worldedit.player_notify(name, count .. " nodes copied") + end, + function(name, param) + local volume = check_region(name, param) + return volume and volume * 2 or volume + end), +}) + +minetest.register_chatcommand("/move", { + params = "x/y/z/? ", + description = "Move the current WorldEdit region along the x/y/z/? axis by nodes", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + amount = tonumber(amount) + if axis == "?" then + axis, sign = worldedit.player_axis(name) + amount = amount * sign + end + + local count = worldedit.move(pos1, pos2, axis, amount) + + pos1[axis] = pos1[axis] + amount + pos2[axis] = pos2[axis] + amount + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + worldedit.player_notify(name, count .. " nodes moved") + end, check_region), +}) + +minetest.register_chatcommand("/stack", { + params = "x/y/z/? ", + description = "Stack the current WorldEdit region along the x/y/z/? axis times", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$") + repetitions = tonumber(repetitions) + if axis == "?" then + axis, sign = worldedit.player_axis(name) + repetitions = repetitions * sign + end + local count = worldedit.stack(pos1, pos2, axis, repetitions) + worldedit.player_notify(name, count .. " nodes stacked") + end, + function(name, param) + local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + end + local count = check_region(name, param) + if count then return (tonumber(repetitions) + 1) * count end + return nil + end), +}) + +minetest.register_chatcommand("/stretch", { + params = " ", + description = "Scale the current WorldEdit positions and region by a factor of , , along the X, Y, and Z axes, repectively, with position 1 as the origin", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$") + stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz) + local count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz) + + --reset markers to scaled positions + worldedit.pos1[name] = pos1 + worldedit.pos2[name] = pos2 + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + + worldedit.player_notify(name, count .. " nodes stretched") + end, + function(name, param) + local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz) + if stretchx == 0 or stretchy == 0 or stretchz == 0 then + worldedit.player_notify(name, "invalid scaling factors: " .. param) + end + local count = check_region(name, param) + if count then return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * count end + return nil + end), +}) + +minetest.register_chatcommand("/transpose", { + params = "x/y/z/? x/y/z/?", + description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$") + if axis1 == "?" then axis1 = worldedit.player_axis(name) end + if axis2 == "?" then axis2 = worldedit.player_axis(name) end + local count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2) + + --reset markers to transposed positions + worldedit.pos1[name] = pos1 + worldedit.pos2[name] = pos2 + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + + worldedit.player_notify(name, count .. " nodes transposed") + end, + function(name, param) + local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + if axis1 == axis2 then + worldedit.player_notify(name, "invalid usage: axes must be different") + return nil + end + return check_region(name, param) + end), +}) + +minetest.register_chatcommand("/flip", { + params = "x/y/z/?", + description = "Flip the current WorldEdit region along the x/y/z/? axis", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if param == "?" then param = worldedit.player_axis(name) end + local count = worldedit.flip(pos1, pos2, param) + worldedit.player_notify(name, count .. " nodes flipped") + end, + function(name, param) + if param ~= "x" and param ~= "y" and param ~= "z" and param ~= "?" then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + return check_region(name, param) + end), +}) + +minetest.register_chatcommand("/rotate", { + params = " ", + description = "Rotate the current WorldEdit region around the axis by angle (90 degree increment)", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$") + if axis == "?" then axis = worldedit.player_axis(name) end + local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle) + + --reset markers to rotated positions + worldedit.pos1[name] = pos1 + worldedit.pos2[name] = pos2 + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + + worldedit.player_notify(name, count .. " nodes rotated") + end, + function(name, param) + local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + if angle % 90 ~= 0 then + worldedit.player_notify(name, "invalid usage: angle must be multiple of 90") + return nil + end + return check_region(name, param) + end), +}) + +minetest.register_chatcommand("/orient", { + params = "", + description = "Rotate oriented nodes in the current WorldEdit region around the Y axis by angle (90 degree increment)", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, angle = param:find("^([+-]?%d+)$") + local count = worldedit.orient(pos1, pos2, angle) + worldedit.player_notify(name, count .. " nodes oriented") + end, + function(name, param) + local found, _, angle = param:find("^([+-]?%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + if angle % 90 ~= 0 then + worldedit.player_notify(name, "invalid usage: angle must be multiple of 90") + return nil + end + return check_region(name, param) + end), +}) + +minetest.register_chatcommand("/fixlight", { + params = "", + description = "Fix the lighting in the current WorldEdit region", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local count = worldedit.fixlight(pos1, pos2) + worldedit.player_notify(name, count .. " nodes updated") + end), +}) + +minetest.register_chatcommand("/hide", { + params = "", + description = "Hide all nodes in the current WorldEdit region non-destructively", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local count = worldedit.hide(pos1, pos2) + worldedit.player_notify(name, count .. " nodes hidden") + end), +}) + +minetest.register_chatcommand("/suppress", { + params = "", + description = "Suppress all in the current WorldEdit region non-destructively", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local node = get_node(name, param) + local count = worldedit.suppress(pos1, pos2, node) + worldedit.player_notify(name, count .. " nodes suppressed") + end, check_set), +}) + +minetest.register_chatcommand("/highlight", { + params = "", + description = "Highlight in the current WorldEdit region by hiding everything else non-destructively", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local node = get_node(name, param) + local count = worldedit.highlight(pos1, pos2, node) + worldedit.player_notify(name, count .. " nodes highlighted") + end, check_set), +}) + +minetest.register_chatcommand("/restore", { + params = "", + description = "Restores nodes hidden with WorldEdit in the current WorldEdit region", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local count = worldedit.restore(pos1, pos2) + worldedit.player_notify(name, count .. " nodes restored") + end), +}) + +minetest.register_chatcommand("/save", { + params = "", + description = "Save the current WorldEdit region to \"(world folder)/schems/.we\"", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if param == "" then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then + worldedit.player_notify(name, "invalid file name: " .. param) + return + end + + local result, count = worldedit.serialize(pos1, pos2) + + local path = minetest.get_worldpath() .. "/schems" + local filename = path .. "/" .. param .. ".we" + filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\") --escape any nasty characters + os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist + local file, err = io.open(filename, "wb") + if err ~= nil then + worldedit.player_notify(name, "could not save file to \"" .. filename .. "\"") + return + end + file:write(result) + file:flush() + file:close() + + worldedit.player_notify(name, count .. " nodes saved") + end), +}) + +minetest.register_chatcommand("/allocate", { + params = "", + description = "Set the region defined by nodes from \"(world folder)/schems/.we\" as the current WorldEdit region", + privs = {worldedit=true}, + func = function(name, param) + local pos = get_position(name) + if pos == nil then return end + + if param == "" then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then + worldedit.player_notify(name, "invalid file name: " .. param) + return + end + + local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we" + local file, err = io.open(filename, "rb") + if err ~= nil then + worldedit.player_notify(name, "could not open file \"" .. filename .. "\"") + return + end + local value = file:read("*a") + file:close() + + if worldedit.valueversion(value) == 0 then --unknown version + worldedit.player_notify(name, "invalid file: file is invalid or created with newer version of WorldEdit") + return + end + local nodepos1, nodepos2, count = worldedit.allocate(pos, value) + + worldedit.pos1[name] = nodepos1 + worldedit.mark_pos1(name) + worldedit.pos2[name] = nodepos2 + worldedit.mark_pos2(name) + + worldedit.player_notify(name, count .. " nodes allocated") + end, +}) + +minetest.register_chatcommand("/load", { + params = "", + description = "Load nodes from \"(world folder)/schems/[.we[m]]\" with position 1 of the current WorldEdit region as the origin", + privs = {worldedit=true}, + func = function(name, param) + local pos = get_position(name) + if pos == nil then return end + + if param == "" then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then + worldedit.player_notify(name, "invalid file name: " .. param) + return + end + + --find the file in the world path + local testpaths = { + minetest.get_worldpath() .. "/schems/" .. param, + minetest.get_worldpath() .. "/schems/" .. param .. ".we", + minetest.get_worldpath() .. "/schems/" .. param .. ".wem", + } + local file, err + for index, path in ipairs(testpaths) do + file, err = io.open(path, "rb") + if not err then + break + end + end + if err then + worldedit.player_notify(name, "could not open file \"" .. param .. "\"") + return + end + local value = file:read("*a") + file:close() + + if worldedit.valueversion(value) == 0 then --unknown version + worldedit.player_notify(name, "invalid file: file is invalid or created with newer version of WorldEdit") + return + end + + local count = worldedit.deserialize(pos, value) + + worldedit.player_notify(name, count .. " nodes loaded") + end, +}) + +minetest.register_chatcommand("/lua", { + params = "", + description = "Executes as a Lua chunk in the global namespace", + privs = {worldedit=true, server=true}, + func = function(name, param) + local admin = minetest.setting_get("name") + if not admin or not name == admin then + worldedit.player_notify(name, "this command can only be run by the server administrator") + return + end + local err = worldedit.lua(param) + if err then + worldedit.player_notify(name, "code error: " .. err) + else + worldedit.player_notify(name, "code successfully executed", false) + end + end, +}) + +minetest.register_chatcommand("/luatransform", { + params = "", + description = "Executes as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region", + privs = {worldedit=true, server=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local admin = minetest.setting_get("name") + if not admin or not name == admin then + worldedit.player_notify(name, "this command can only be run by the server administrator") + return + end + + local err = worldedit.luatransform(pos1, pos2, param) + if err then + worldedit.player_notify(name, "code error: " .. err, false) + else + worldedit.player_notify(name, "code successfully executed", false) + end + end), +}) + +minetest.register_chatcommand("/mtschemcreate", { + params = "", + description = "Save the current WorldEdit region using the Minetest Schematic format to \"(world folder)/schems/.mts\"", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if param == nil then + worldedit.player_notify(name, "No filename specified") + return + end + + local path = minetest.get_worldpath() .. "/schems" + local filename = path .. "/" .. param .. ".mts" + filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\") --escape any nasty characters + os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist + + local ret = minetest.create_schematic(pos1, pos2, worldedit.prob_list[name], filename) + if ret == nil then + worldedit.player_notify(name, "failed to create Minetest schematic", false) + else + worldedit.player_notify(name, "saved Minetest schematic to " .. param, false) + end + worldedit.prob_list[name] = {} + end), +}) + +minetest.register_chatcommand("/mtschemplace", { + params = "", + description = "Load nodes from \"(world folder)/schems/.mts\" with position 1 of the current WorldEdit region as the origin", + privs = {worldedit=true}, + func = function(name, param) + if param == nil then + worldedit.player_notify(name, "no filename specified") + return + end + + local pos = get_position(name) + if pos == nil then return end + + local path = minetest.get_worldpath() .. "/schems/" .. param .. ".mts" + if minetest.place_schematic(pos, path) == nil then + worldedit.player_notify(name, "failed to place Minetest schematic", false) + else + worldedit.player_notify(name, "placed Minetest schematic " .. param .. + " at " .. minetest.pos_to_string(pos), false) + end + end, +}) + +minetest.register_chatcommand("/mtschemprob", { + params = "start/finish/get", + description = "Begins node probability entry for Minetest schematics, gets the nodes that have probabilities set, or ends node probability entry", + privs = {worldedit=true}, + func = function(name, param) + if param == "start" then --start probability setting + worldedit.set_pos[name] = "prob" + worldedit.prob_list[name] = {} + worldedit.player_notify(name, "select Minetest schematic probability values by punching nodes") + elseif param == "finish" then --finish probability setting + worldedit.set_pos[name] = nil + worldedit.player_notify(name, "finished Minetest schematic probability selection") + elseif param == "get" then --get all nodes that had probabilities set on them + local text = "" + local problist = worldedit.prob_list[name] + if problist == nil then + return + end + for k,v in pairs(problist) do + local prob = math.floor(((v["prob"] / 256) * 100) * 100 + 0.5) / 100 + text = text .. minetest.pos_to_string(v["pos"]) .. ": " .. prob .. "% | " + end + worldedit.player_notify(name, "currently set node probabilities:") + worldedit.player_notify(name, text) + else + worldedit.player_notify(name, "unknown subcommand: " .. param) + end + end, +}) + +minetest.register_on_player_receive_fields( + function(player, formname, fields) + if (formname == "prob_val_enter") and (fields.text ~= "") then + local name = player:get_player_name() + local prob_entry = {pos=worldedit.prob_pos[name], prob=tonumber(fields.text)} + local index = table.getn(worldedit.prob_list[name]) + 1 + worldedit.prob_list[name][index] = prob_entry + end + end +) + +minetest.register_chatcommand("/clearobjects", { + params = "", + description = "Clears all objects within the WorldEdit region", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local count = worldedit.clearobjects(pos1, pos2) + worldedit.player_notify(name, count .. " objects cleared") + end), +}) diff --git a/mods/Minetest-WorldEdit/worldedit_commands/mark.lua b/mods/Minetest-WorldEdit/worldedit_commands/mark.lua new file mode 100644 index 0000000..e07e849 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_commands/mark.lua @@ -0,0 +1,161 @@ +worldedit.marker1 = {} +worldedit.marker2 = {} +worldedit.marker_region = {} + +--marks worldedit region position 1 +worldedit.mark_pos1 = function(name) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + + if pos1 ~= nil then + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos1) + end + if worldedit.marker1[name] ~= nil then --marker already exists + worldedit.marker1[name]:remove() --remove marker + worldedit.marker1[name] = nil + end + if pos1 ~= nil then + --add marker + worldedit.marker1[name] = minetest.add_entity(pos1, "worldedit:pos1") + if worldedit.marker1[name] ~= nil then + worldedit.marker1[name]:get_luaentity().name = name + end + end + worldedit.mark_region(name) +end + +--marks worldedit region position 2 +worldedit.mark_pos2 = function(name) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + + if pos2 ~= nil then + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos2, pos2) + end + if worldedit.marker2[name] ~= nil then --marker already exists + worldedit.marker2[name]:remove() --remove marker + worldedit.marker2[name] = nil + end + if pos2 ~= nil then + --add marker + worldedit.marker2[name] = minetest.add_entity(pos2, "worldedit:pos2") + if worldedit.marker2[name] ~= nil then + worldedit.marker2[name]:get_luaentity().name = name + end + end + worldedit.mark_region(name) +end + +worldedit.mark_region = function(name) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + + if worldedit.marker_region[name] ~= nil then --marker already exists + --wip: make the area stay loaded somehow + for _, entity in ipairs(worldedit.marker_region[name]) do + entity:remove() + end + worldedit.marker_region[name] = nil + end + if pos1 ~= nil and pos2 ~= nil then + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local thickness = 0.2 + local sizex, sizey, sizez = (1 + pos2.x - pos1.x) / 2, (1 + pos2.y - pos1.y) / 2, (1 + pos2.z - pos1.z) / 2 + + --make area stay loaded + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local markers = {} + + --XY plane markers + for _, z in ipairs({pos1.z - 0.5, pos2.z + 0.5}) do + local marker = minetest.add_entity({x=pos1.x + sizex - 0.5, y=pos1.y + sizey - 0.5, z=z}, "worldedit:region_cube") + marker:set_properties({ + visual_size={x=sizex * 2, y=sizey * 2}, + collisionbox = {-sizex, -sizey, -thickness, sizex, sizey, thickness}, + }) + marker:get_luaentity().name = name + table.insert(markers, marker) + end + + --YZ plane markers + for _, x in ipairs({pos1.x - 0.5, pos2.x + 0.5}) do + local marker = minetest.add_entity({x=x, y=pos1.y + sizey - 0.5, z=pos1.z + sizez - 0.5}, "worldedit:region_cube") + marker:set_properties({ + visual_size={x=sizez * 2, y=sizey * 2}, + collisionbox = {-thickness, -sizey, -sizez, thickness, sizey, sizez}, + }) + marker:setyaw(math.pi / 2) + marker:get_luaentity().name = name + table.insert(markers, marker) + end + + worldedit.marker_region[name] = markers + end +end + +minetest.register_entity(":worldedit:pos1", { + initial_properties = { + visual = "cube", + visual_size = {x=1.1, y=1.1}, + textures = {"worldedit_pos1.png", "worldedit_pos1.png", + "worldedit_pos1.png", "worldedit_pos1.png", + "worldedit_pos1.png", "worldedit_pos1.png"}, + collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55}, + physical = false, + }, + on_step = function(self, dtime) + if worldedit.marker1[self.name] == nil then + self.object:remove() + end + end, + on_punch = function(self, hitter) + self.object:remove() + worldedit.marker1[self.name] = nil + end, +}) + +minetest.register_entity(":worldedit:pos2", { + initial_properties = { + visual = "cube", + visual_size = {x=1.1, y=1.1}, + textures = {"worldedit_pos2.png", "worldedit_pos2.png", + "worldedit_pos2.png", "worldedit_pos2.png", + "worldedit_pos2.png", "worldedit_pos2.png"}, + collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55}, + physical = false, + }, + on_step = function(self, dtime) + if worldedit.marker2[self.name] == nil then + self.object:remove() + end + end, + on_punch = function(self, hitter) + self.object:remove() + worldedit.marker2[self.name] = nil + end, +}) + +minetest.register_entity(":worldedit:region_cube", { + initial_properties = { + visual = "upright_sprite", + visual_size = {x=1.1, y=1.1}, + textures = {"worldedit_cube.png"}, + visual_size = {x=10, y=10}, + physical = false, + }, + on_step = function(self, dtime) + if worldedit.marker_region[self.name] == nil then + self.object:remove() + return + end + end, + on_punch = function(self, hitter) + for _, entity in ipairs(worldedit.marker_region[self.name]) do + entity:remove() + end + worldedit.marker_region[self.name] = nil + end, +}) \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit_commands/safe.lua b/mods/Minetest-WorldEdit/worldedit_commands/safe.lua new file mode 100644 index 0000000..c6751c1 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_commands/safe.lua @@ -0,0 +1,65 @@ +local safe_region_callback = {} +local safe_region_param = {} + +check_region = function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] --obtain positions + if pos1 == nil or pos2 == nil then + worldedit.player_notify(name, "no region selected") + return nil + end + return worldedit.volume(pos1, pos2) +end + +--`callback` is a callback to run when the user confirms +--`nodes_needed` is a function accepting `param`, `pos1`, and `pos2` to calculate the number of nodes needed +safe_region = function(callback, nodes_needed) + --default node volume calculation + nodes_needed = nodes_needed or check_region + + return function(name, param) + --check if the operation applies to a safe number of nodes + local count = nodes_needed(name, param) + if count == nil then return end --invalid command + if count < 10000 then + return callback(name, param) + end + + --save callback to call later + safe_region_callback[name], safe_region_param[name] = callback, param + worldedit.player_notify(name, "WARNING: this operation could affect up to " .. count .. " nodes; type //y to continue or //n to cancel") + end +end + +minetest.register_chatcommand("/y", { + params = "", + description = "Confirm a pending operation", + func = function(name) + local callback, param = safe_region_callback[name], safe_region_param[name] + if not callback then + worldedit.player_notify(name, "no operation pending") + return + end + + --obtain positions + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if pos1 == nil or pos2 == nil then + worldedit.player_notify(name, "no region selected") + return + end + + safe_region_callback[name], safe_region_param[name] = nil, nil --reset pending operation + callback(name, param, pos1, pos2) + end, +}) + +minetest.register_chatcommand("/n", { + params = "", + description = "Confirm a pending operation", + func = function(name) + if not safe_region_callback[name] then + worldedit.player_notify(name, "no operation pending") + return + end + safe_region_callback[name], safe_region_param[name] = nil, nil + end, +}) diff --git a/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_cube.png b/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_cube.png new file mode 100644 index 0000000..fde36a8 Binary files /dev/null and b/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_cube.png differ diff --git a/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_pos1.png b/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_pos1.png new file mode 100644 index 0000000..4c304aa Binary files /dev/null and b/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_pos1.png differ diff --git a/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_pos2.png b/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_pos2.png new file mode 100644 index 0000000..1502f16 Binary files /dev/null and b/mods/Minetest-WorldEdit/worldedit_commands/textures/worldedit_pos2.png differ diff --git a/mods/Minetest-WorldEdit/worldedit_gui/depends.txt b/mods/Minetest-WorldEdit/worldedit_gui/depends.txt new file mode 100644 index 0000000..d603ac9 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_gui/depends.txt @@ -0,0 +1,5 @@ +worldedit +worldedit_commands +unified_inventory? +inventory_plus? +creative? \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit_gui/functionality.lua b/mods/Minetest-WorldEdit/worldedit_gui/functionality.lua new file mode 100644 index 0000000..f331d4d --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_gui/functionality.lua @@ -0,0 +1,657 @@ +--saved state for each player +local gui_nodename1 = {} --mapping of player names to node names (arbitrary strings may also appear as values) +local gui_nodename2 = {} --mapping of player names to node names (arbitrary strings may also appear as values) +local gui_axis1 = {} --mapping of player names to axes (one of 1, 2, 3, or 4, representing the axes in the `axis_indices` table below) +local gui_axis2 = {} --mapping of player names to axes (one of 1, 2, 3, or 4, representing the axes in the `axis_indices` table below) +local gui_distance1 = {} --mapping of player names to a distance (arbitrary strings may also appear as values) +local gui_distance2 = {} --mapping of player names to a distance (arbitrary strings may also appear as values) +local gui_distance3 = {} --mapping of player names to a distance (arbitrary strings may also appear as values) +local gui_count1 = {} --mapping of player names to a quantity (arbitrary strings may also appear as values) +local gui_count2 = {} --mapping of player names to a quantity (arbitrary strings may also appear as values) +local gui_count3 = {} --mapping of player names to a quantity (arbitrary strings may also appear as values) +local gui_angle = {} --mapping of player names to an angle (one of 90, 180, 270, representing the angle in degrees clockwise) +local gui_filename = {} --mapping of player names to file names (arbitrary strings may also appear as values) +local gui_formspec = {} --mapping of player names to formspecs +local gui_code = {} --mapping of player names to formspecs + +--set default values +setmetatable(gui_nodename1, {__index = function() return "Cobblestone" end}) +setmetatable(gui_nodename2, {__index = function() return "Stone" end}) +setmetatable(gui_axis1, {__index = function() return 4 end}) +setmetatable(gui_axis2, {__index = function() return 1 end}) +setmetatable(gui_distance1, {__index = function() return "10" end}) +setmetatable(gui_distance2, {__index = function() return "5" end}) +setmetatable(gui_distance3, {__index = function() return "2" end}) +setmetatable(gui_count1, {__index = function() return "3" end}) +setmetatable(gui_count2, {__index = function() return "6" end}) +setmetatable(gui_count3, {__index = function() return "4" end}) +setmetatable(gui_angle, {__index = function() return 90 end}) +setmetatable(gui_filename, {__index = function() return "building" end}) +setmetatable(gui_formspec, {__index = function() return "size[5,5]\nlabel[0,0;Hello, world!]" end}) +setmetatable(gui_code, {__index = function() return "minetest.chat_send_player(\"singleplayer\", \"Hello, world!\")" end}) + +local axis_indices = {["X axis"]=1, ["Y axis"]=2, ["Z axis"]=3, ["Look direction"]=4} +local axis_values = {"x", "y", "z", "?"} +setmetatable(axis_indices, {__index = function () return 4 end}) +setmetatable(axis_values, {__index = function () return "?" end}) + +local angle_indices = {["90 degrees"]=1, ["180 degrees"]=2, ["270 degrees"]=3} +local angle_values = {90, 180, 270} +setmetatable(angle_indices, {__index = function () return 1 end}) +setmetatable(angle_values, {__index = function () return 90 end}) + +--given multiple sets of privileges, produces a single set of privs that would have the same effect as requiring all of them at the same time +local combine_privs = function(...) + local result = {} + for i, privs in ipairs({...}) do + for name, value in pairs(privs) do + if result[name] ~= nil and result[name] ~= value then --the priv must be both true and false, which can never happen + return {__fake_priv_that_nobody_has__=true} --priviledge table that can never be satisfied + end + result[name] = value + end + end + return result +end + +worldedit.register_gui_function("worldedit_gui_about", { + name = "About", privs = minetest.chatcommands["/about"].privs, + on_select = function(name) + minetest.chatcommands["/about"].func(name, "") + end, +}) + +worldedit.register_gui_function("worldedit_gui_inspect", { + name = "Toggle Inspect", privs = minetest.chatcommands["/inspect"].privs, + on_select = function(name) + minetest.chatcommands["/inspect"].func(name, worldedit.inspect[name] and "disable" or "enable") + end, +}) + +worldedit.register_gui_function("worldedit_gui_region", { + name = "Get/Set Region", privs = combine_privs(minetest.chatcommands["/p"].privs, minetest.chatcommands["/pos1"].privs, minetest.chatcommands["/pos2"].privs, minetest.chatcommands["/reset"].privs, minetest.chatcommands["/mark"].privs, minetest.chatcommands["/unmark"].privs, minetest.chatcommands["/volume"].privs, minetest.chatcommands["/fixedpos"].privs), + get_formspec = function(name) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + return "size[9,7]" .. worldedit.get_formspec_header("worldedit_gui_region") .. + "button_exit[0,1;3,0.8;worldedit_gui_p_get;Get Positions]" .. + "button_exit[3,1;3,0.8;worldedit_gui_p_set1;Choose Position 1]" .. + "button_exit[6,1;3,0.8;worldedit_gui_p_set2;Choose Position 2]" .. + "button_exit[0,2;3,0.8;worldedit_gui_pos1;Position 1 Here]" .. + "button_exit[3,2;3,0.8;worldedit_gui_pos2;Position 2 Here]" .. + "button_exit[6,2;3,0.8;worldedit_gui_reset;Reset Region]" .. + "button_exit[0,3;3,0.8;worldedit_gui_mark;Mark Region]" .. + "button_exit[3,3;3,0.8;worldedit_gui_unmark;Unmark Region]" .. + "button_exit[6,3;3,0.8;worldedit_gui_volume;Region Volume]" .. + "label[0,4.7;Position 1]" .. + string.format("field[2,5;1.5,0.8;worldedit_gui_fixedpos_pos1x;X ;%s]", pos1 and pos1.x or "") .. + string.format("field[3.5,5;1.5,0.8;worldedit_gui_fixedpos_pos1y;Y ;%s]", pos1 and pos1.y or "") .. + string.format("field[5,5;1.5,0.8;worldedit_gui_fixedpos_pos1z;Z ;%s]", pos1 and pos1.z or "") .. + "button_exit[6.5,4.68;2.5,0.8;worldedit_gui_fixedpos_pos1_submit;Set Position 1]" .. + "label[0,6.2;Position 2]" .. + string.format("field[2,6.5;1.5,0.8;worldedit_gui_fixedpos_pos2x;X ;%s]", pos2 and pos2.x or "") .. + string.format("field[3.5,6.5;1.5,0.8;worldedit_gui_fixedpos_pos2y;Y ;%s]", pos2 and pos2.y or "") .. + string.format("field[5,6.5;1.5,0.8;worldedit_gui_fixedpos_pos2z;Z ;%s]", pos2 and pos2.z or "") .. + "button_exit[6.5,6.18;2.5,0.8;worldedit_gui_fixedpos_pos2_submit;Set Position 2]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_region", function(name, fields) + if fields.worldedit_gui_p_get then + minetest.chatcommands["/p"].func(name, "get") + return true + elseif fields.worldedit_gui_p_set1 then + minetest.chatcommands["/p"].func(name, "set1") + return true + elseif fields.worldedit_gui_p_set2 then + minetest.chatcommands["/p"].func(name, "set2") + return true + elseif fields.worldedit_gui_pos1 then + minetest.chatcommands["/pos1"].func(name, "") + worldedit.show_page(name, "worldedit_gui_region") + return true + elseif fields.worldedit_gui_pos2 then + minetest.chatcommands["/pos2"].func(name, "") + worldedit.show_page(name, "worldedit_gui_region") + return true + elseif fields.worldedit_gui_reset then + minetest.chatcommands["/reset"].func(name, "") + worldedit.show_page(name, "worldedit_gui_region") + return true + elseif fields.worldedit_gui_mark then + minetest.chatcommands["/mark"].func(name, "") + worldedit.show_page(name, "worldedit_gui_region") + return true + elseif fields.worldedit_gui_unmark then + minetest.chatcommands["/unmark"].func(name, "") + worldedit.show_page(name, "worldedit_gui_region") + return true + elseif fields.worldedit_gui_volume then + minetest.chatcommands["/volume"].func(name, "") + worldedit.show_page(name, "worldedit_gui_region") + return true + elseif fields.worldedit_gui_fixedpos_pos1_submit then + minetest.chatcommands["/fixedpos"].func(name, string.format("set1 %s %s %s", + tostring(fields.worldedit_gui_fixedpos_pos1x), + tostring(fields.worldedit_gui_fixedpos_pos1y), + tostring(fields.worldedit_gui_fixedpos_pos1z))) + worldedit.show_page(name, "worldedit_gui_region") + return true + elseif fields.worldedit_gui_fixedpos_pos2_submit then + minetest.chatcommands["/fixedpos"].func(name, string.format("set2 %s %s %s", + tostring(fields.worldedit_gui_fixedpos_pos2x), + tostring(fields.worldedit_gui_fixedpos_pos2y), + tostring(fields.worldedit_gui_fixedpos_pos2z))) + worldedit.show_page(name, "worldedit_gui_region") + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_set", { + name = "Set Nodes", privs = minetest.chatcommands["/set"].privs, + get_formspec = function(name) + local node = gui_nodename1[name] + local nodename = worldedit.normalize_nodename(node) + return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_set") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_set_node;Name;%s]", minetest.formspec_escape(node)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_set_search;Search]" .. + (nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + "button_exit[0,2.5;3,0.8;worldedit_gui_set_submit;Set Nodes]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_set", function(name, fields) + if fields.worldedit_gui_set_search or fields.worldedit_gui_set_submit then + gui_nodename1[name] = tostring(fields.worldedit_gui_set_node) + worldedit.show_page(name, "worldedit_gui_set") + if fields.worldedit_gui_set_submit then + minetest.chatcommands["/set"].func(name, gui_nodename1[name]) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_replace", { + name = "Replace Nodes", privs = combine_privs(minetest.chatcommands["/replace"].privs, minetest.chatcommands["/replaceinverse"].privs), + get_formspec = function(name) + local search, replace = gui_nodename1[name], gui_nodename2[name] + local search_nodename, replace_nodename = worldedit.normalize_nodename(search), worldedit.normalize_nodename(replace) + return "size[6.5,4]" .. worldedit.get_formspec_header("worldedit_gui_replace") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_replace_search;Name;%s]", minetest.formspec_escape(search)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_replace_search_search;Search]" .. + (search_nodename and string.format("item_image[5.5,1.1;1,1;%s]", search_nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + string.format("field[0.5,2.5;4,0.8;worldedit_gui_replace_replace;Name;%s]", minetest.formspec_escape(replace)) .. + "button[4,2.18;1.5,0.8;worldedit_gui_replace_replace_search;Search]" .. + (replace_nodename and string.format("item_image[5.5,2.1;1,1;%s]", replace_nodename) + or "image[5.5,2.1;1,1;unknown_node.png]") .. + "button_exit[0,3.5;3,0.8;worldedit_gui_replace_submit;Replace Nodes]" .. + "button_exit[3.5,3.5;3,0.8;worldedit_gui_replace_submit_inverse;Replace Inverse]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_replace", function(name, fields) + if fields.worldedit_gui_replace_search_search or fields.worldedit_gui_replace_replace_search + or fields.worldedit_gui_replace_submit or fields.worldedit_gui_replace_submit_inverse then + gui_nodename1[name] = tostring(fields.worldedit_gui_replace_search) + gui_nodename2[name] = tostring(fields.worldedit_gui_replace_replace) + worldedit.show_page(name, "worldedit_gui_replace") + if fields.worldedit_gui_replace_submit then + minetest.chatcommands["/replace"].func(name, string.format("%s %s", gui_nodename1[name], gui_nodename2[name])) + elseif fields.worldedit_gui_replace_submit_inverse then + minetest.chatcommands["/replaceinverse"].func(name, string.format("%s %s", gui_nodename1[name], gui_nodename2[name])) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_sphere_dome", { + name = "Sphere/Dome", privs = combine_privs(minetest.chatcommands["/hollowsphere"].privs, minetest.chatcommands["/sphere"].privs, minetest.chatcommands["/hollowdome"].privs, minetest.chatcommands["/dome"].privs), + get_formspec = function(name) + local node, radius = gui_nodename1[name], gui_distance2[name] + local nodename = worldedit.normalize_nodename(node) + return "size[6.5,5]" .. worldedit.get_formspec_header("worldedit_gui_sphere_dome") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_sphere_dome_node;Name;%s]", minetest.formspec_escape(node)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_sphere_dome_search;Search]" .. + (nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + string.format("field[0.5,2.5;4,0.8;worldedit_gui_sphere_dome_radius;Radius;%s]", minetest.formspec_escape(radius)) .. + "button_exit[0,3.5;3,0.8;worldedit_gui_sphere_dome_submit_hollow;Hollow Sphere]" .. + "button_exit[3.5,3.5;3,0.8;worldedit_gui_sphere_dome_submit_solid;Solid Sphere]" .. + "button_exit[0,4.5;3,0.8;worldedit_gui_sphere_dome_submit_hollow_dome;Hollow Dome]" .. + "button_exit[3.5,4.5;3,0.8;worldedit_gui_sphere_dome_submit_solid_dome;Solid Dome]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_sphere_dome", function(name, fields) + if fields.worldedit_gui_sphere_dome_search + or fields.worldedit_gui_sphere_dome_submit_hollow or fields.worldedit_gui_sphere_dome_submit_solid + or fields.worldedit_gui_sphere_dome_submit_hollow_dome or fields.worldedit_gui_sphere_dome_submit_solid_dome then + gui_nodename1[name] = tostring(fields.worldedit_gui_sphere_dome_node) + gui_distance2[name] = tostring(fields.worldedit_gui_sphere_dome_radius) + worldedit.show_page(name, "worldedit_gui_sphere_dome") + if fields.worldedit_gui_sphere_dome_submit_hollow then + minetest.chatcommands["/hollowsphere"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name])) + elseif fields.worldedit_gui_sphere_dome_submit_solid then + minetest.chatcommands["/sphere"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name])) + elseif fields.worldedit_gui_sphere_dome_submit_hollow_dome then + minetest.chatcommands["/hollowdome"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name])) + elseif fields.worldedit_gui_sphere_dome_submit_solid_dome then + minetest.chatcommands["/dome"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name])) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_cylinder", { + name = "Cylinder", privs = combine_privs(minetest.chatcommands["/hollowcylinder"].privs, minetest.chatcommands["/cylinder"].privs), + get_formspec = function(name) + local node, axis, length, radius = gui_nodename1[name], gui_axis1[name], gui_distance1[name], gui_distance2[name] + local nodename = worldedit.normalize_nodename(node) + return "size[6.5,5]" .. worldedit.get_formspec_header("worldedit_gui_cylinder") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_cylinder_node;Name;%s]", minetest.formspec_escape(node)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_cylinder_search;Search]" .. + (nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + string.format("field[0.5,2.5;4,0.8;worldedit_gui_cylinder_length;Length;%s]", minetest.formspec_escape(length)) .. + string.format("dropdown[4,2.18;2.5;worldedit_gui_cylinder_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) .. + string.format("field[0.5,3.5;4,0.8;worldedit_gui_cylinder_radius;Radius;%s]", minetest.formspec_escape(radius)) .. + "button_exit[0,4.5;3,0.8;worldedit_gui_cylinder_submit_hollow;Hollow Cylinder]" .. + "button_exit[3.5,4.5;3,0.8;worldedit_gui_cylinder_submit_solid;Solid Cylinder]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_cylinder", function(name, fields) + if fields.worldedit_gui_cylinder_search + or fields.worldedit_gui_cylinder_submit_hollow or fields.worldedit_gui_cylinder_submit_solid then + gui_nodename1[name] = tostring(fields.worldedit_gui_cylinder_node) + gui_axis1[name] = axis_indices[fields.worldedit_gui_cylinder_axis] + gui_distance1[name] = tostring(fields.worldedit_gui_cylinder_length) + gui_distance2[name] = tostring(fields.worldedit_gui_cylinder_radius) + worldedit.show_page(name, "worldedit_gui_cylinder") + if fields.worldedit_gui_cylinder_submit_hollow then + minetest.chatcommands["/hollowcylinder"].func(name, string.format("%s %s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_distance2[name], gui_nodename1[name])) + elseif fields.worldedit_gui_cylinder_submit_solid then + minetest.chatcommands["/cylinder"].func(name, string.format("%s %s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_distance2[name], gui_nodename1[name])) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_pyramid", { + name = "Pyramid", privs = minetest.chatcommands["/pyramid"].privs, + get_formspec = function(name) + local node, axis, length = gui_nodename1[name], gui_axis1[name], gui_distance1[name] + local nodename = worldedit.normalize_nodename(node) + return "size[6.5,4]" .. worldedit.get_formspec_header("worldedit_gui_pyramid") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_pyramid_node;Name;%s]", minetest.formspec_escape(node)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_pyramid_search;Search]" .. + (nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + string.format("field[0.5,2.5;4,0.8;worldedit_gui_pyramid_length;Length;%s]", minetest.formspec_escape(length)) .. + string.format("dropdown[4,2.18;2.5;worldedit_gui_pyramid_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) .. + "button_exit[0,3.5;3,0.8;worldedit_gui_pyramid_submit;Pyramid]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_pyramid", function(name, fields) + if fields.worldedit_gui_pyramid_search or fields.worldedit_gui_pyramid_submit then + gui_nodename1[name] = tostring(fields.worldedit_gui_pyramid_node) + gui_axis1[name] = axis_indices[fields.worldedit_gui_pyramid_axis] + gui_distance1[name] = tostring(fields.worldedit_gui_pyramid_length) + worldedit.show_page(name, "worldedit_gui_pyramid") + if fields.worldedit_gui_pyramid_submit then + minetest.chatcommands["/pyramid"].func(name, string.format("%s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_nodename1[name])) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_spiral", { + name = "Spiral", privs = minetest.chatcommands["/spiral"].privs, + get_formspec = function(name) + local node, length, height, space = gui_nodename1[name], gui_distance1[name], gui_distance2[name], gui_distance3[name] + local nodename = worldedit.normalize_nodename(node) + return "size[6.5,6]" .. worldedit.get_formspec_header("worldedit_gui_spiral") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_spiral_node;Name;%s]", minetest.formspec_escape(node)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_spiral_search;Search]" .. + (nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + string.format("field[0.5,2.5;4,0.8;worldedit_gui_spiral_length;Side Length;%s]", minetest.formspec_escape(length)) .. + string.format("field[0.5,3.5;4,0.8;worldedit_gui_spiral_height;Height;%s]", minetest.formspec_escape(height)) .. + string.format("field[0.5,4.5;4,0.8;worldedit_gui_spiral_space;Wall Spacing;%s]", minetest.formspec_escape(space)) .. + "button_exit[0,5.5;3,0.8;worldedit_gui_spiral_submit;Spiral]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_spiral", function(name, fields) + if fields.worldedit_gui_spiral_search or fields.worldedit_gui_spiral_submit then + gui_nodename1[name] = fields.worldedit_gui_spiral_node + gui_distance1[name] = tostring(fields.worldedit_gui_spiral_length) + gui_distance2[name] = tostring(fields.worldedit_gui_spiral_height) + gui_distance3[name] = tostring(fields.worldedit_gui_spiral_space) + worldedit.show_page(name, "worldedit_gui_spiral") + if fields.worldedit_gui_spiral_submit then + minetest.chatcommands["/spiral"].func(name, string.format("%s %s %s %s", gui_distance1[name], gui_distance2[name], gui_distance3[name], gui_nodename1[name])) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_copy_move", { + name = "Copy/Move", privs = combine_privs(minetest.chatcommands["/copy"].privs, minetest.chatcommands["/move"].privs), + get_formspec = function(name) + local axis = gui_axis1[name] or 4 + local amount = gui_distance1[name] or "10" + return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_copy_move") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_copy_move_amount;Amount;%s]", minetest.formspec_escape(amount)) .. + string.format("dropdown[4,1.18;2.5;worldedit_gui_copy_move_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) .. + "button_exit[0,2.5;3,0.8;worldedit_gui_copy_move_copy;Copy Region]" .. + "button_exit[3.5,2.5;3,0.8;worldedit_gui_copy_move_move;Move Region]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_copy_move", function(name, fields) + if fields.worldedit_gui_copy_move_copy or fields.worldedit_gui_copy_move_move then + gui_axis1[name] = axis_indices[fields.worldedit_gui_cylinder_axis] or 4 + gui_distance1[name] = tostring(fields.worldedit_gui_copy_move_amount) + worldedit.show_page(name, "worldedit_gui_copy_move") + if fields.worldedit_gui_copy_move_copy then + minetest.chatcommands["/copy"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], gui_distance1[name])) + else --fields.worldedit_gui_copy_move_move + minetest.chatcommands["/move"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], gui_distance1[name])) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_stack", { + name = "Stack", privs = minetest.chatcommands["/stack"].privs, + get_formspec = function(name) + local axis, count = gui_axis1[name], gui_count1[name] + return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_stack") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_stack_count;Count;%s]", minetest.formspec_escape(count)) .. + string.format("dropdown[4,1.18;2.5;worldedit_gui_stack_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) .. + "button_exit[0,2.5;3,0.8;worldedit_gui_stack_submit;Stack]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_stack", function(name, fields) + if fields.worldedit_gui_stack_submit then + gui_axis1[name] = axis_indices[fields.worldedit_gui_stack_axis] + gui_count1[name] = tostring(fields.worldedit_gui_stack_count) + worldedit.show_page(name, "worldedit_gui_stack") + minetest.chatcommands["/stack"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], gui_count1[name])) + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_stretch", { + name = "Stretch", privs = minetest.chatcommands["/stretch"].privs, + get_formspec = function(name) + local stretchx, stretchy, stretchz = gui_count1[name], gui_count2[name], gui_count3[name] + return "size[5,5]" .. worldedit.get_formspec_header("worldedit_gui_stretch") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_stretch_x;Stretch X;%s]", minetest.formspec_escape(stretchx)) .. + string.format("field[0.5,2.5;4,0.8;worldedit_gui_stretch_y;Stretch Y;%s]", minetest.formspec_escape(stretchy)) .. + string.format("field[0.5,3.5;4,0.8;worldedit_gui_stretch_z;Stretch Z;%s]", minetest.formspec_escape(stretchz)) .. + "button_exit[0,4.5;3,0.8;worldedit_gui_stretch_submit;Stretch]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_stretch", function(name, fields) + if fields.worldedit_gui_stretch_submit then + gui_count1[name] = tostring(fields.worldedit_gui_stretch_x) + gui_count2[name] = tostring(fields.worldedit_gui_stretch_y) + gui_count3[name] = tostring(fields.worldedit_gui_stretch_z) + worldedit.show_page(name, "worldedit_gui_stretch") + minetest.chatcommands["/stretch"].func(name, string.format("%s %s %s", gui_count1[name], gui_count2[name], gui_count3[name])) + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_transpose", { + name = "Transpose", privs = minetest.chatcommands["/transpose"].privs, + get_formspec = function(name) + local axis1, axis2 = gui_axis1[name], gui_axis2[name] + return "size[5.5,3]" .. worldedit.get_formspec_header("worldedit_gui_transpose") .. + string.format("dropdown[0,1;2.5;worldedit_gui_transpose_axis1;X axis,Y axis,Z axis,Look direction;%d]", axis1) .. + string.format("dropdown[3,1;2.5;worldedit_gui_transpose_axis2;X axis,Y axis,Z axis,Look direction;%d]", axis2) .. + "button_exit[0,2.5;3,0.8;worldedit_gui_transpose_submit;Transpose]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_transpose", function(name, fields) + if fields.worldedit_gui_transpose_submit then + gui_axis1[name] = axis_indices[fields.worldedit_gui_transpose_axis1] + gui_axis2[name] = axis_indices[fields.worldedit_gui_transpose_axis2] + worldedit.show_page(name, "worldedit_gui_transpose") + minetest.chatcommands["/transpose"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], axis_values[gui_axis2[name]])) + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_flip", { + name = "Flip", privs = minetest.chatcommands["/flip"].privs, + get_formspec = function(name) + local axis = gui_axis2[name] + return "size[5,3]" .. worldedit.get_formspec_header("worldedit_gui_flip") .. + string.format("dropdown[0,1;2.5;worldedit_gui_flip_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) .. + "button_exit[0,2.5;3,0.8;worldedit_gui_flip_submit;Flip]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_flip", function(name, fields) + if fields.worldedit_gui_flip_submit then + gui_axis2[name] = axis_indices[fields.worldedit_gui_flip_axis] + worldedit.show_page(name, "worldedit_gui_flip") + minetest.chatcommands["/flip"].func(name, axis_values[gui_axis2[name]]) + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_rotate", { + name = "Rotate", privs = minetest.chatcommands["/rotate"].privs, + get_formspec = function(name) + local axis, angle = gui_axis1[name], gui_angle[name] + return "size[5.5,3]" .. worldedit.get_formspec_header("worldedit_gui_rotate") .. + string.format("dropdown[0,1;2.5;worldedit_gui_rotate_angle;90 degrees,180 degrees,270 degrees;%s]", angle) .. + string.format("dropdown[3,1;2.5;worldedit_gui_rotate_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) .. + "button_exit[0,2.5;3,0.8;worldedit_gui_rotate_submit;Rotate]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_rotate", function(name, fields) + if fields.worldedit_gui_rotate_submit then + gui_axis1[name] = axis_indices[fields.worldedit_gui_rotate_axis] + gui_angle[name] = angle_indices[fields.worldedit_gui_rotate_angle] + worldedit.show_page(name, "worldedit_gui_rotate") + minetest.chatcommands["/rotate"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], angle_values[gui_angle[name]])) + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_orient", { + name = "Orient", privs = minetest.chatcommands["/orient"].privs, + get_formspec = function(name) + local angle = gui_angle[name] + return "size[5,3]" .. worldedit.get_formspec_header("worldedit_gui_orient") .. + string.format("dropdown[0,1;2.5;worldedit_gui_rotate_angle;90 degrees,180 degrees,270 degrees;%s]", angle) .. + "button_exit[0,2.5;3,0.8;worldedit_gui_orient_submit;Orient]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_orient", function(name, fields) + if fields.worldedit_gui_orient_submit then + gui_angle[name] = angle_indices[fields.worldedit_gui_orient_angle] + worldedit.show_page(name, "worldedit_gui_orient") + minetest.chatcommands["/orient"].func(name, angle_values[gui_angle[name]]) + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_fixlight", { + name = "Fix Lighting", privs = minetest.chatcommands["/fixlight"].privs, + on_select = function(name) + minetest.chatcommands["/fixlight"].func(name, "") + end, +}) + +worldedit.register_gui_function("worldedit_gui_hide", { + name = "Hide Region", privs = minetest.chatcommands["/hide"].privs, + on_select = function(name) + minetest.chatcommands["/hide"].func(name, "") + end, +}) + +worldedit.register_gui_function("worldedit_gui_suppress", { + name = "Suppress Nodes", privs = minetest.chatcommands["/suppress"].privs, + get_formspec = function(name) + local node = gui_nodename1[name] + local nodename = worldedit.normalize_nodename(node) + return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_suppress") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_suppress_node;Name;%s]", minetest.formspec_escape(node)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_suppress_search;Search]" .. + (nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + "button_exit[0,2.5;3,0.8;worldedit_gui_suppress_submit;Suppress Nodes]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_suppress", function(name, fields) + if fields.worldedit_gui_suppress_search or fields.worldedit_gui_suppress_submit then + gui_nodename1[name] = tostring(fields.worldedit_gui_suppress_node) + worldedit.show_page(name, "worldedit_gui_suppress") + if fields.worldedit_gui_suppress_submit then + minetest.chatcommands["/suppress"].func(name, gui_nodename1[name]) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_highlight", { + name = "Highlight Nodes", privs = minetest.chatcommands["/highlight"].privs, + get_formspec = function(name) + local node = gui_nodename1[name] + local nodename = worldedit.normalize_nodename(node) + return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_highlight") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_highlight_node;Name;%s]", minetest.formspec_escape(node)) .. + "button[4,1.18;1.5,0.8;worldedit_gui_highlight_search;Search]" .. + (nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename) + or "image[5.5,1.1;1,1;unknown_node.png]") .. + "button_exit[0,2.5;3,0.8;worldedit_gui_highlight_submit;Highlight Nodes]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_highlight", function(name, fields) + if fields.worldedit_gui_highlight_search or fields.worldedit_gui_highlight_submit then + gui_nodename1[name] = tostring(fields.worldedit_gui_highlight_node) + worldedit.show_page(name, "worldedit_gui_highlight") + if fields.worldedit_gui_highlight_submit then + minetest.chatcommands["/highlight"].func(name, gui_nodename1[name]) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_restore", { + name = "Restore Region", privs = minetest.chatcommands["/restore"].privs, + on_select = function(name) + minetest.chatcommands["/restore"].func(name, "") + end, +}) + +worldedit.register_gui_function("worldedit_gui_save_load", { + name = "Save/Load", privs = combine_privs(minetest.chatcommands["/save"].privs, minetest.chatcommands["/allocate"].privs, minetest.chatcommands["/load"].privs), + get_formspec = function(name) + local filename = gui_filename[name] + return "size[6,4]" .. worldedit.get_formspec_header("worldedit_gui_save_load") .. + string.format("field[0.5,1.5;4,0.8;worldedit_gui_save_filename;Filename;%s]", minetest.formspec_escape(filename)) .. + "button_exit[0,2.5;3,0.8;worldedit_gui_save_load_submit_save;Save]" .. + "button_exit[3,2.5;3,0.8;worldedit_gui_save_load_submit_allocate;Allocate]" .. + "button_exit[0,3.5;3,0.8;worldedit_gui_save_load_submit_load;Load]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_save", function(name, fields) + if fields.worldedit_gui_save_load_submit_save or worldedit_gui_save_load_submit_allocate or worldedit_gui_save_load_submit_load then + gui_filename[name] = tostring(fields.worldedit_gui_save_axis) + worldedit.show_page(name, "worldedit_gui_save_load") + if fields.worldedit_gui_save_load_submit_save then + minetest.chatcommands["/save"].func(name, gui_filename[name]) + elseif fields.worldedit_gui_save_load_submit_allocate then + minetest.chatcommands["/allocate"].func(name, gui_filename[name]) + else --fields.worldedit_gui_save_load_submit_load + minetest.chatcommands["/load"].func(name, gui_filename[name]) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_lua", { + name = "Run Lua", + get_formspec = function(name) + local code = gui_code[name] + return "size[8,6.5]" .. worldedit.get_formspec_header("worldedit_gui_lua") .. + string.format("textarea[0.5,1;7.5,5.5;worldedit_gui_lua_code;Lua Code;%s]", minetest.formspec_escape(code)) .. + "button_exit[0,6;3,0.8;worldedit_gui_lua_run;Run Lua]" .. + "button_exit[5,6;3,0.8;worldedit_gui_lua_transform;Lua Transform]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_lua", function(name, fields) + if fields.worldedit_gui_lua_run or fields.worldedit_gui_lua_transform then + gui_code[name] = fields.worldedit_gui_lua_value + worldedit.show_page(name, "worldedit_gui_lua") + if fields.worldedit_gui_lua_run then + minetest.chatcommands["/lua"].func(name, gui_code[name]) + else --fields.worldedit_gui_lua_transform + minetest.chatcommands["/luatransform"].func(name, gui_code[name]) + end + return true + end + return false +end) + +worldedit.register_gui_function("worldedit_gui_clearobjects", { + name = "Clear Objects", privs = minetest.chatcommands["/clearobjects"].privs, + on_select = function(name) + minetest.chatcommands["/clearobjects"].func(name, "") + end, +}) + +worldedit.register_gui_function("worldedit_gui_formspec_tester", { + name = "Formspec Tester", + get_formspec = function(name) + local value = gui_formspec[name] + return "size[8,6.5]" .. worldedit.get_formspec_header("worldedit_gui_formspec_tester") .. + string.format("textarea[0.5,1;7.5,5.5;worldedit_gui_formspec_tester_value;Formspec Code;%s]", minetest.formspec_escape(value)) .. + "button_exit[0,6;3,0.8;worldedit_gui_formspec_tester_show;Show Formspec]" + end, +}) + +worldedit.register_gui_handler("worldedit_gui_formspec_tester", function(name, fields) + if fields.worldedit_gui_formspec_tester_show then + gui_formspec[name] = fields.worldedit_gui_formspec_tester_value or "" + worldedit.show_page(name, "worldedit_gui_formspec_tester") + minetest.show_formspec(name, "worldedit:formspec_tester", gui_formspec[name]) + return true + end + return false +end) diff --git a/mods/Minetest-WorldEdit/worldedit_gui/init.lua b/mods/Minetest-WorldEdit/worldedit_gui/init.lua new file mode 100644 index 0000000..b1ebc72 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_gui/init.lua @@ -0,0 +1,247 @@ +worldedit = worldedit or {} + +--[[ +Example: + + worldedit.register_gui_function("worldedit_gui_hollow_cylinder", { + name = "Make Hollow Cylinder", + privs = {worldedit=true}, + get_formspec = function(name) return "some formspec here" end, + on_select = function(name) print(name .. " clicked the button!") end, + }) + +Use `nil` for the `options` parameter to unregister the function associated with the given identifier. + +Use `nil` for the `get_formspec` field to denote that the function does not have its own screen. + +Use `nil` for the `privs` field to denote that no special privileges are required to use the function. + +If the identifier is already registered to another function, it will be replaced by the new one. + +The `on_select` function must not call `worldedit.show_page` +]] + +worldedit.pages = {} --mapping of identifiers to options +local identifiers = {} --ordered list of identifiers +worldedit.register_gui_function = function(identifier, options) + worldedit.pages[identifier] = options + table.insert(identifiers, identifier) +end + +--[[ +Example: + + worldedit.register_gui_handler("worldedit_gui_hollow_cylinder", function(name, fields) + print(minetest.serialize(fields)) + end) +]] + +worldedit.register_gui_handler = function(identifier, handler) + minetest.register_on_player_receive_fields(function(player, formname, fields) + --ensure the form is not being exited since this is a duplicate message + if fields.quit then + return false + end + + local name = player:get_player_name() + + --ensure the player has permission to perform the action + local entry = worldedit.pages[identifier] + if entry and minetest.check_player_privs(name, entry.privs or {}) then + return handler(name, fields) + end + return false + end) +end + +worldedit.get_formspec_header = function(identifier) + local entry = worldedit.pages[identifier] or {} + return "button[0,0;2,0.5;worldedit_gui;Back]" .. + string.format("label[2,0;WorldEdit GUI > %s]", entry.name or "") +end + +local get_formspec = function(name, identifier) + if worldedit.pages[identifier] then + return worldedit.pages[identifier].get_formspec(name) + end + return worldedit.pages["worldedit_gui"].get_formspec(name) --default to showing main page if an unknown page is given +end + +--implement worldedit.show_page(name, page) in different ways depending on the available APIs +if unified_inventory then --unified inventory installed + local old_func = worldedit.register_gui_function + worldedit.register_gui_function = function(identifier, options) + old_func(identifier, options) + unified_inventory.register_page(identifier, {get_formspec=function(player) return {formspec=options.get_formspec(player:get_player_name())} end}) + end + + unified_inventory.register_button("worldedit_gui", { + type = "image", + image = "inventory_plus_worldedit_gui.png", + }) + + minetest.register_on_player_receive_fields(function(player, formname, fields) + local name = player:get_player_name() + if fields.worldedit_gui then --main page + worldedit.show_page(name, "worldedit_gui") + return true + elseif fields.worldedit_gui_exit then --return to original page + local player = minetest.get_player_by_name(name) + if player then + unified_inventory.set_inventory_formspec(player, "craft") + end + return true + end + return false + end) + + worldedit.show_page = function(name, page) + local player = minetest.get_player_by_name(name) + if player then + player:set_inventory_formspec(get_formspec(name, page)) + end + end +elseif inventory_plus then --inventory++ installed + minetest.register_on_joinplayer(function(player) + inventory_plus.register_button(player, "worldedit_gui", "WorldEdit") + end) + + --show the form when the button is pressed and hide it when done + local gui_player_formspecs = {} + minetest.register_on_player_receive_fields(function(player, formname, fields) + local name = player:get_player_name() + if fields.worldedit_gui then --main page + gui_player_formspecs[name] = player:get_inventory_formspec() + worldedit.show_page(name, "worldedit_gui") + return true + elseif fields.worldedit_gui_exit then --return to original page + if gui_player_formspecs[name] then + inventory_plus.set_inventory_formspec(player, gui_player_formspecs[name]) + end + return true + end + return false + end) + + worldedit.show_page = function(name, page) + local player = minetest.get_player_by_name(name) + if player then + inventory_plus.set_inventory_formspec(player, get_formspec(name, page)) + end + end +else --fallback button + local player_formspecs = {} + + local update_main_formspec = function(name) + local formspec = player_formspecs[name] + if not formspec then + return + end + local player = minetest.get_player_by_name(name) + if not player then --this is in case the player signs off while the media is loading + return + end + if (minetest.check_player_privs(name, {creative=true}) or minetest.setting_getbool("creative_mode")) and creative_inventory then --creative_inventory is active, add button to modified formspec + formspec = player:get_inventory_formspec() .. "image_button[6,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" + else + formspec = formspec .. "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" + end + player:set_inventory_formspec(formspec) + end + + minetest.register_on_joinplayer(function(player) + local name = player:get_player_name() + minetest.after(1, function() + if minetest.get_player_by_name(name) then --ensure the player is still signed in + player_formspecs[name] = player:get_inventory_formspec() + minetest.after(0.01, function() + update_main_formspec(name) + end) + end + end) + end) + + minetest.register_on_leaveplayer(function(player) + player_formspecs[player:get_player_name()] = nil + end) + + local gui_player_formspecs = {} + minetest.register_on_player_receive_fields(function(player, formname, fields) + local name = player:get_player_name() + if fields.worldedit_gui then --main page + gui_player_formspecs[name] = player:get_inventory_formspec() + worldedit.show_page(name, "worldedit_gui") + return true + elseif fields.worldedit_gui_exit then --return to original page + if gui_player_formspecs[name] then + player:set_inventory_formspec(gui_player_formspecs[name]) + end + return true + else --deal with creative_inventory setting the formspec on every single message + minetest.after(0.01,function() + update_main_formspec(name) + end) + return false --continue processing in creative inventory + end + end) + + worldedit.show_page = function(name, page) + local player = minetest.get_player_by_name(name) + if player then + player:set_inventory_formspec(get_formspec(name, page)) + end + end +end + +worldedit.register_gui_function("worldedit_gui", { + name = "WorldEdit GUI", + get_formspec = function(name) + --create a form with all the buttons arranged in a grid + local buttons, x, y, index = {}, 0, 1, 0 + local width, height = 3, 0.8 + local columns = 5 + for i, identifier in pairs(identifiers) do + if identifier ~= "worldedit_gui" then + local entry = worldedit.pages[identifier] + table.insert(buttons, string.format((entry.get_formspec and "button" or "button_exit") .. + "[%g,%g;%g,%g;%s;%s]", x, y, width, height, identifier, minetest.formspec_escape(entry.name))) + + index, x = index + 1, x + width + if index == columns then --row is full + x, y = 0, y + height + index = 0 + end + end + end + if index == 0 then --empty row + y = y - height + end + return string.format("size[%g,%g]", math.max(columns * width, 5), math.max(y + 0.5, 3)) .. + "button[0,0;2,0.5;worldedit_gui_exit;Back]" .. + "label[2,0;WorldEdit GUI]" .. + table.concat(buttons) + end, +}) + +worldedit.register_gui_handler("worldedit_gui", function(name, fields) + for identifier, entry in pairs(worldedit.pages) do --check for WorldEdit GUI main formspec button selection + if fields[identifier] and identifier ~= "worldedit_gui" then + --ensure player has permission to perform action + local has_privs, missing_privs = minetest.check_player_privs(name, entry.privs or {}) + if not has_privs then + worldedit.player_notify(name, "you are not allowed to use this function (missing privileges: " .. table.concat(missing_privs, ", ") .. ")") + return false + end + if entry.on_select then + entry.on_select(name) + end + if entry.get_formspec then + worldedit.show_page(name, identifier) + end + return true + end + end + return false +end) + +dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/functionality.lua") diff --git a/mods/Minetest-WorldEdit/worldedit_gui/textures/inventory_plus_worldedit_gui.png b/mods/Minetest-WorldEdit/worldedit_gui/textures/inventory_plus_worldedit_gui.png new file mode 100644 index 0000000..fbc1abc Binary files /dev/null and b/mods/Minetest-WorldEdit/worldedit_gui/textures/inventory_plus_worldedit_gui.png differ diff --git a/mods/Minetest-WorldEdit/worldedit_infinity/init.lua b/mods/Minetest-WorldEdit/worldedit_infinity/init.lua new file mode 100644 index 0000000..be79101 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_infinity/init.lua @@ -0,0 +1,103 @@ +worldedit = worldedit or {} +local minetest = minetest --local copy of global + +local get_pointed = function(pos, nearest, distance) + if distance > 100 then + return false + end + + --check for collision with node + local nodename = minetest.get_node(pos).name + if nodename ~= "air" + and nodename ~= "default:water_source" + and nodename ~= "default:water_flowing" then + if nodename ~= "ignore" then + return nearest + end + return false + end +end + +local use = function(itemstack, user, pointed_thing) + if pointed_thing.type == "nothing" then --pointing at nothing + local placepos = worldedit.raytrace(user:getpos(), user:get_look_dir(), get_pointed) + if placepos then --extended reach + pointed_thing.type = "node" + pointed_thing.under = nil --wip + pointed_thing.above = nil --wip + end + end + return minetest.item_place_node(itemstack, user, pointed_thing) +end +-- + +worldedit.raytrace = function(pos, dir, callback) + local base = {x=math.floor(pos.x), y=math.floor(pos.y), z=math.floor(pos.z)} + local stepx, stepy, stepz = 0, 0, 0 + local componentx, componenty, componentz = 0, 0, 0 + local intersectx, intersecty, intersectz = 0, 0, 0 + + if dir.x == 0 then + intersectx = math.huge + elseif dir.x > 0 then + stepx = 1 + componentx = 1 / dir.x + intersectx = ((base.x - pos.x) + 1) * componentx + else + stepx = -1 + componentx = 1 / -dir.x + intersectx = (pos.x - base.x) * componentx + end + if dir.y == 0 then + intersecty = math.huge + elseif dir.y > 0 then + stepy = 1 + componenty = 1 / dir.y + intersecty = ((base.y - pos.y) + 1) * componenty + else + stepy = -1 + componenty = 1 / -dir.y + intersecty = (pos.y - base.y) * componenty + end + if dir.z == 0 then + intersectz = math.huge + elseif dir.z > 0 then + stepz = 1 + componentz = 1 / dir.z + intersectz = ((base.z - pos.z) + 1) * componentz + else + stepz = -1 + componentz = 1 / -dir.z + intersectz = (pos.z - base.z) * componentz + end + + local distance = 0 + local nearest = {x=base.x, y=base.y, z=base.z} + while true do + local values = {callback(base, nearest, distance)} + if #values > 0 then + return unpack(values) + end + + nearest.x, nearest.y, nearest.z = base.x, base.y, base.z + if intersectx < intersecty then + if intersectx < intersectz then + base.x = base.x + stepx + distance = intersectx + intersectx = intersectx + componentx + else + base.z = base.z + stepz + distance = intersectz + intersectz = intersectz + componentz + end + elseif intersecty < intersectz then + base.y = base.y + stepy + distance = intersecty + intersecty = intersecty + componenty + else + base.z = base.z + stepz + distance = intersectz + intersectz = intersectz + componentz + end + end +end \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit_limited/depends.txt b/mods/Minetest-WorldEdit/worldedit_limited/depends.txt new file mode 100644 index 0000000..74054c6 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_limited/depends.txt @@ -0,0 +1 @@ +worldedit diff --git a/mods/Minetest-WorldEdit/worldedit_limited/init.lua b/mods/Minetest-WorldEdit/worldedit_limited/init.lua new file mode 100644 index 0000000..801e19c --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_limited/init.lua @@ -0,0 +1,120 @@ +do return end +do + local MAX_VOLUME = 30 * 30 * 30 + + local we = worldedit + local volume = we.volume + local safewrap = function(func) + return function(pos1, pos2, ...) + if validbox(pos1, pos2) then + return func(pos1, pos2, ...) + end + return 0, pos1, pos2 + end + end + + local validbox = function(pos1, pos2) + tpos1, tpos2 = we.sort_pos(pos1, pos2) + + if volume(tpos1, tpos2) > MAX_VOLUME then + return false + end + + --check for ownership of area if ownership mod is installed + if owner_defs then + local inside = false + for _, def in pairs(owner_defs) do + --sort positions + local tdef = {x1=def.x1, x2 = def.x2, y1=def.y1, y2=def.y2, z1=def.z1, z2=def.z2} + if tdef.x1 > tdef.x2 then + tdef.x1, tdef.x2 = tdef.x2, tdef.x1 + end + if tdef.y1 > tdef.y2 then + tdef.y1, tdef.y2 = tdef.y2, tdef.y1 + end + if tdef.z1 > tdef.z2 then + tdef.z1, tdef.z2 = tdef.z2, tdef.z1 + end + + --check ownership + if tpos1.x >= tdef.x1 and tpos1.x <= tdef.x2 + and tpos2.x >= tdef.x1 and tpos2.x <= tdef.x2 + and tpos1.y >= tdef.y1 and tpos1.y <= tdef.y2 + and tpos2.y >= tdef.y1 and tpos2.y <= tdef.y2 + and tpos1.z >= tdef.z1 and tpos1.z <= tdef.z2 + and tpos2.z >= tdef.z1 and tpos2.z <= tdef.z2 + and name == def.owner then --wip: name isn't available here + inside = true + break + end + end + if not inside then + return false + end + end + + return true + end + + worldedit = { + sort_pos = we.sort_pos, + + set = safewrap(we.set), + replace = safewrap(we.replace), + replaceinverse = safewrap(we.replaceinverse), + copy = function(pos1, pos2, axis, amount) + tpos1, tpos2 = we.sort_pos(pos1, pos2) + tpos1[axis] = tpos1[axis] + amount + tpos2[axis] = tpos2[axis] + amount + if validbox(pos1, pos2) and validbox(tpos1, tpos2) then + we.copy(pos1, pos2, axis, amount) + else + return 0 + end + end, + move = function(pos1, pos2, axis, amount) + tpos1, tpos2 = we.sort_pos(pos1, pos2) + tpos1[axis] = tpos1[axis] + amount + tpos2[axis] = tpos2[axis] + amount + if validbox(pos1, pos2) and validbox(tpos1, tpos2) then + we.move(pos1, pos2, axis, amount) + else + return 0 + end + end, + stack = function(pos1, pos2, axis, count) + tpos1, tpos2 = we.sort_pos(pos1, pos2) + local length = (tpos2[axis] - tpos1[axis] + 1) * count + if count < 0 then + tpos1[axis] = tpos1[axis] + length + else + tpos2[axis] = tpos2[axis] + length + end + if validbox(tpos1, tpos2) then + we.stack(pos1, pos2, axis, amount) + else + return 0 + end + end, + --wip: add transpose, rotate safely + flip = safewrap(we.flip), + orient = safewrap(we.orient), + fixlight = safewrap(we.fixlight), + --wip: add primitives here + volume = we.volume, + hide = safewrap(we.hide), + suppress = safewrap(we.suppress), + highlight = safewrap(we.highlight), + restore = safewrap(we.restore), + serialize = safewrap(we.serialize), + allocate = we.allocate, + deserialize = function(originpos, value) + local tpos1, tpos2 = we.allocate(originpos, value) + if validbox(tpos1, tpos2) then + we.deserialize(originpos, value) + else + return 0 + end + end, + } +end \ No newline at end of file diff --git a/mods/Minetest-WorldEdit/worldedit_shortcommands/depends.txt b/mods/Minetest-WorldEdit/worldedit_shortcommands/depends.txt new file mode 100644 index 0000000..de1cb6c --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_shortcommands/depends.txt @@ -0,0 +1 @@ +worldedit_commands diff --git a/mods/Minetest-WorldEdit/worldedit_shortcommands/init.lua b/mods/Minetest-WorldEdit/worldedit_shortcommands/init.lua new file mode 100644 index 0000000..a3cbb67 --- /dev/null +++ b/mods/Minetest-WorldEdit/worldedit_shortcommands/init.lua @@ -0,0 +1,50 @@ +--provides shorter names for the commands in `worldedit_commands` + +--returns true if command could not be aliased, false otherwise +worldedit.alias_chatcommand = function(alias, original_command) + if not minetest.chatcommands[original_command] then + minetest.log("error", "worldedit_shortcommands: original command " .. original_command .. " does not exist") + return true + end + if minetest.chatcommands[alias] then + minetest.log("error", "worldedit_shortcommands: alias " .. alias .. " already exists") + return true + end + minetest.register_chatcommand(alias, minetest.chatcommands[original_command]) + return false +end + +worldedit.alias_chatcommand("/i", "/inspect") +worldedit.alias_chatcommand("/rst", "/reset") +worldedit.alias_chatcommand("/mk", "/mark") +worldedit.alias_chatcommand("/umk", "/unmark") +worldedit.alias_chatcommand("/1", "/pos1") +worldedit.alias_chatcommand("/2", "/pos2") +worldedit.alias_chatcommand("/fp", "/fixedpos") +worldedit.alias_chatcommand("/v", "/volume") +worldedit.alias_chatcommand("/s", "/set") +worldedit.alias_chatcommand("/r", "/replace") +worldedit.alias_chatcommand("/ri", "/replaceinverse") +worldedit.alias_chatcommand("/hspr", "/hollowsphere") +worldedit.alias_chatcommand("/spr", "/sphere") +worldedit.alias_chatcommand("/hdo", "/hollowdome") +worldedit.alias_chatcommand("/do", "/dome") +worldedit.alias_chatcommand("/hcyl", "/hollowcylinder") +worldedit.alias_chatcommand("/cyl", "/cylinder") +worldedit.alias_chatcommand("/pyr", "/pyramid") +worldedit.alias_chatcommand("/spl", "/spiral") +worldedit.alias_chatcommand("/m", "/move") +worldedit.alias_chatcommand("/c", "/copy") +worldedit.alias_chatcommand("/stk", "/stack") +worldedit.alias_chatcommand("/sch", "/stretch") +worldedit.alias_chatcommand("/tps", "/transpose") +worldedit.alias_chatcommand("/fl", "/flip") +worldedit.alias_chatcommand("/rot", "/rotate") +worldedit.alias_chatcommand("/ort", "/orient") +worldedit.alias_chatcommand("/hi", "/hide") +worldedit.alias_chatcommand("/sup", "/suppress") +worldedit.alias_chatcommand("/hlt", "/highlight") +worldedit.alias_chatcommand("/rsr", "/restore") +worldedit.alias_chatcommand("/l", "/lua") +worldedit.alias_chatcommand("/lt", "/luatransform") +worldedit.alias_chatcommand("/clro", "/clearobjects") \ No newline at end of file diff --git a/mods/carpet/init.lua b/mods/carpet/init.lua new file mode 100644 index 0000000..b0150c3 --- /dev/null +++ b/mods/carpet/init.lua @@ -0,0 +1,267 @@ +-- Carpet Mod! +-- By Jordan Snelling 2012 +-- License LGPL +-- This mod adds carpets into Minetest. + +minetest.register_node("carpet:red", { + description = "Red Carpet", + drawtype = "raillike", + tiles = {"carpet_red_out.png"}, + inventory_image = "carpet_red_out.png", + wield_image = "carpet_red_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:orange", { + description = "Orange Carpet", + drawtype = "raillike", + tiles = {"carpet_orange_out.png"}, + inventory_image = "carpet_orange_out.png", + wield_image = "carpet_orange_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:yellow", { + description = "Yellow Carpet", + drawtype = "raillike", + tiles = {"carpet_yellow_out.png"}, + inventory_image = "carpet_yellow_out.png", + wield_image = "carpet_yellow_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:green", { + description = "Green Carpet", + drawtype = "raillike", + tiles = {"carpet_green_out.png"}, + inventory_image = "carpet_green_out.png", + wield_image = "carpet_green_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:cyan", { + description = "Cyan Carpet", + drawtype = "raillike", + tiles = {"carpet_cyan_out.png"}, + inventory_image = "carpet_cyan_out.png", + wield_image = "carpet_cyan_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:blue", { + description = "Blue Carpet", + drawtype = "raillike", + tiles = {"carpet_blue_out.png"}, + inventory_image = "carpet_blue_out.png", + wield_image = "carpet_blue_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:pink", { + description = "Pink Carpet", + drawtype = "raillike", + tiles = {"carpet_pink_out.png"}, + inventory_image = "carpet_pink_out.png", + wield_image = "carpet_pink_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + + +minetest.register_node("carpet:black", { + description = "Black Carpet", + drawtype = "raillike", + tiles = {"carpet_black_out.png"}, + inventory_image = "carpet_black_out.png", + wield_image = "carpet_black_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:magenta", { + description = "Magenta Carpet", + drawtype = "raillike", + tiles = {"carpet_magenta_out.png"}, + inventory_image = "carpet_magenta_out.png", + wield_image = "carpet_magenta_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +minetest.register_node("carpet:white", { + description = "White Carpet", + drawtype = "raillike", + tiles = {"carpet_white_out.png"}, + inventory_image = "carpet_white_out.png", + wield_image = "carpet_white_out.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + buildable_to = true, + selection_box = { + type = "fixed", + + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {dig_immediate=2}, +}) + +-- Crafing + +minetest.register_craft({ + output = 'carpet:red 64', + recipe = { + {'wool:red', 'wool:red', 'wool:red'}, + {'wool:red', 'wool:red', 'wool:red'}, + } +}) + +minetest.register_craft({ + output = 'carpet:orange 64', + recipe = { + {'wool:orange', 'wool:orange', 'wool:orange'}, + {'wool:orange', 'wool:orange', 'wool:orange'}, + } +}) + +minetest.register_craft({ + output = 'carpetyellow 64', + recipe = { + {'wool:yellow', 'wool:yellow', 'wool:yellow'}, + {'wool:yellow', 'wool:yellow', 'wool:yellow'}, + } +}) + +minetest.register_craft({ + output = 'carpet:green 64', + recipe = { + {'wool:green', 'wool:green', 'wool:green'}, + {'wool:green', 'wool:green', 'wool:green'}, + } +}) + +minetest.register_craft({ + output = 'carpet:cyan 64', + recipe = { + {'wool:cyan', 'wool:cyan', 'wool:cyan'}, + {'wool:cyan', 'wool:cyan', 'wool:cyan'}, + } +}) + +minetest.register_craft({ + output = 'carpet:blue 64', + recipe = { + {'wool:blue', 'wool:blue', 'wool:blue'}, + {'wool:blue', 'wool:blue', 'wool:blue'}, + } +}) + +minetest.register_craft({ + output = 'carpet:pink 64', + recipe = { + {'wool:pink', 'wool:pink', 'wool:pink'}, + {'wool:pink', 'wool:pink', 'wool:pink'}, + } +}) + +minetest.register_craft({ + output = 'carpet:magenta 64', + recipe = { + {'wool:magenta', 'wool:megenta', 'wool:magenta'}, + {'wool:magenta', 'wool:magenta', 'wool:magenta'}, + } +}) + +minetest.register_craft({ + output = 'carpet:white 64', + recipe = { + {'wool:white', 'wool:white', 'wool:white'}, + {'wool:white', 'wool:white', 'wool:white'}, + } +}) + +minetest.register_craft({ + output = 'carpet:black 64', + recipe = { + {'wool:black', 'wool:black', 'wool:black'}, + {'wool:black', 'wool:black', 'wool:black'}, + } +}) diff --git a/mods/carpet/textures/.directory b/mods/carpet/textures/.directory new file mode 100644 index 0000000..016a53c --- /dev/null +++ b/mods/carpet/textures/.directory @@ -0,0 +1,4 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2014,5,12,13,13,14 +Version=3 diff --git a/mods/carpet/textures/carpet_black_out.png b/mods/carpet/textures/carpet_black_out.png new file mode 100644 index 0000000..4a81d8c Binary files /dev/null and b/mods/carpet/textures/carpet_black_out.png differ diff --git a/mods/carpet/textures/carpet_blue_out.png b/mods/carpet/textures/carpet_blue_out.png new file mode 100644 index 0000000..9d9eb27 Binary files /dev/null and b/mods/carpet/textures/carpet_blue_out.png differ diff --git a/mods/carpet/textures/carpet_cyan_out.png b/mods/carpet/textures/carpet_cyan_out.png new file mode 100644 index 0000000..b8884fb Binary files /dev/null and b/mods/carpet/textures/carpet_cyan_out.png differ diff --git a/mods/carpet/textures/carpet_green_out.png b/mods/carpet/textures/carpet_green_out.png new file mode 100644 index 0000000..d50a3e1 Binary files /dev/null and b/mods/carpet/textures/carpet_green_out.png differ diff --git a/mods/carpet/textures/carpet_magenta_out.png b/mods/carpet/textures/carpet_magenta_out.png new file mode 100644 index 0000000..cbb1d67 Binary files /dev/null and b/mods/carpet/textures/carpet_magenta_out.png differ diff --git a/mods/carpet/textures/carpet_orange_out.png b/mods/carpet/textures/carpet_orange_out.png new file mode 100644 index 0000000..296f476 Binary files /dev/null and b/mods/carpet/textures/carpet_orange_out.png differ diff --git a/mods/carpet/textures/carpet_pink_out.png b/mods/carpet/textures/carpet_pink_out.png new file mode 100644 index 0000000..ba3efd4 Binary files /dev/null and b/mods/carpet/textures/carpet_pink_out.png differ diff --git a/mods/carpet/textures/carpet_red_out.png b/mods/carpet/textures/carpet_red_out.png new file mode 100644 index 0000000..acebe98 Binary files /dev/null and b/mods/carpet/textures/carpet_red_out.png differ diff --git a/mods/carpet/textures/carpet_white_out.png b/mods/carpet/textures/carpet_white_out.png new file mode 100644 index 0000000..3f550a0 Binary files /dev/null and b/mods/carpet/textures/carpet_white_out.png differ diff --git a/mods/carpet/textures/carpet_yellow_out.png b/mods/carpet/textures/carpet_yellow_out.png new file mode 100644 index 0000000..33227a1 Binary files /dev/null and b/mods/carpet/textures/carpet_yellow_out.png differ diff --git a/mods/carts/README.txt b/mods/carts/README.txt new file mode 100644 index 0000000..58673ce --- /dev/null +++ b/mods/carts/README.txt @@ -0,0 +1,25 @@ +Minetest 0.4 mod: carts +======================= +by PilzAdam + +License of source code: +----------------------- +WTFPL + +License of media (textures, sounds and models): +----------------------------------------------- +CC-0 + +Authors of media files: +----------------------- +kddekadenz: + cart_bottom.png + cart_side.png + cart_top.png + +Zeg9: + cart.x + cart.png + +rarkenin: + cart_rail_*.png diff --git a/mods/carts/depends.txt b/mods/carts/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/mods/carts/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/carts/functions.lua b/mods/carts/functions.lua new file mode 100644 index 0000000..73df96b --- /dev/null +++ b/mods/carts/functions.lua @@ -0,0 +1,62 @@ + +-- +-- Helper functions +-- + +cart_func = {} + +dofile(minetest.get_modpath("carts").."/voxelgetter.lua") + +function cart_func:get_sign(z) + if z == 0 then + return 0 + else + return z/math.abs(z) + end +end + +-- Returns the velocity as a unit vector +-- The smaller part of the vector will be turned to 0 +function cart_func:velocity_to_dir(v) + if math.abs(v.x) > math.abs(v.z) then + return {x=cart_func:get_sign(v.x), y=cart_func:get_sign(v.y), z=0} + else + return {x=0, y=cart_func:get_sign(v.y), z=cart_func:get_sign(v.z)} + end +end + +function cart_func:is_rail(p) + local nn = minetest.env:get_node(p).name + if nn=="ignore" then + print("oops") + nn=cart_func:get_content_voxel(p) + end + return minetest.get_item_group(nn, "rail") ~= 0 +end + +function cart_func:is_int(z) + z = math.abs(z) + return math.abs(math.floor(z+0.5)-z) <= 0.1 +end + +cart_func.v3 = {} + +function cart_func.v3:add(v1, v2) + return {x=v1.x+v2.x, y=v1.y+v2.y, z=v1.z+v2.z} +end + +function cart_func.v3:copy(v) + return {x=v.x, y=v.y, z=v.z} +end + +function cart_func.v3:round(v) + return { + x = math.floor(v.x+0.5), + y = math.floor(v.y+0.5), + z = math.floor(v.z+0.5), + } +end + +function cart_func.v3:equal(v1, v2) + return v1.x == v2.x and v1.y == v2.y and v1.z == v2.z +end diff --git a/mods/carts/init.lua b/mods/carts/init.lua new file mode 100644 index 0000000..03bc1a3 --- /dev/null +++ b/mods/carts/init.lua @@ -0,0 +1,595 @@ + +dofile(minetest.get_modpath("carts").."/functions.lua") + +-- +-- Cart entity +-- + +local cart = { + physical = false, + collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, + visual = "mesh", + mesh = "cart.x", + visual_size = {x=1, y=1}, + textures = {"cart.png"}, + + driver = nil, + velocity = {x=0, y=0, z=0}, + old_pos = nil, + old_velocity = nil, + pre_stop_dir = nil, + MAX_V = 8, -- Limit of the velocity +} + +function cart:on_rightclick(clicker) + if not clicker or not clicker:is_player() then + return + end + if self.driver and clicker == self.driver then + self.driver = nil + clicker:set_detach() + elseif not self.driver then + self.driver = clicker + clicker:set_attach(self.object, "", {x=0,y=5,z=0}, {x=0,y=0,z=0}) + end +end + +function cart:on_activate(staticdata, dtime_s) + self.object:set_armor_groups({immortal=1}) + if staticdata then + local tmp = minetest.deserialize(staticdata) + if tmp then + self.velocity = tmp.velocity + end + if tmp and tmp.pre_stop_dir then + self.pre_stop_dir = tmp.pre_stop_dir + end + end + self.old_pos = self.object:getpos() + self.old_velocity = self.velocity +end + +function cart:get_staticdata() + return minetest.serialize({ + velocity = self.velocity, + pre_stop_dir = self.pre_stop_dir, + }) +end + +-- Remove the cart if holding a tool or accelerate it +function cart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) + if not puncher or not puncher:is_player() then + return + end + + if puncher:get_player_control().sneak then + self.object:remove() + local inv = puncher:get_inventory() + if minetest.setting_getbool("creative_mode") then + if not inv:contains_item("main", "carts:cart") then + inv:add_item("main", "carts:cart") + end + else + inv:add_item("main", "carts:cart") + end + return + end + + if puncher == self.driver then + return + end + + local d = cart_func:velocity_to_dir(direction) + local s = self.velocity + if time_from_last_punch > tool_capabilities.full_punch_interval then + time_from_last_punch = tool_capabilities.full_punch_interval + end + local f = 4*(time_from_last_punch/tool_capabilities.full_punch_interval) + local v = {x=s.x+d.x*f, y=s.y, z=s.z+d.z*f} + if math.abs(v.x) < 6 and math.abs(v.z) < 6 then + self.velocity = v + else + if math.abs(self.velocity.x) < 6 and math.abs(v.x) >= 6 then + self.velocity.x = 6*cart_func:get_sign(self.velocity.x) + end + if math.abs(self.velocity.z) < 6 and math.abs(v.z) >= 6 then + self.velocity.z = 6*cart_func:get_sign(self.velocity.z) + end + end +end + +-- Returns the direction as a unit vector +function cart:get_rail_direction(pos, dir) + local d = cart_func.v3:copy(dir) + + -- Check front + d.y = 0 + local p = cart_func.v3:add(cart_func.v3:copy(pos), d) + if cart_func:is_rail(p) then + return d + end + + -- Check downhill + d.y = -1 + p = cart_func.v3:add(cart_func.v3:copy(pos), d) + if cart_func:is_rail(p) then + return d + end + + -- Check uphill + d.y = 1 + p = cart_func.v3:add(cart_func.v3:copy(pos), d) + if cart_func:is_rail(p) then + return d + end + d.y = 0 + + -- Check left and right + local view_dir + local other_dir + local a + + if d.x == 0 and d.z ~= 0 then + view_dir = "z" + other_dir = "x" + if d.z < 0 then + a = {1, -1} + else + a = {-1, 1} + end + elseif d.z == 0 and d.x ~= 0 then + view_dir = "x" + other_dir = "z" + if d.x > 0 then + a = {1, -1} + else + a = {-1, 1} + end + else + return {x=0, y=0, z=0} + end + + d[view_dir] = 0 + d[other_dir] = a[1] + p = cart_func.v3:add(cart_func.v3:copy(pos), d) + if cart_func:is_rail(p) then + return d + end + d.y = -1 + p = cart_func.v3:add(cart_func.v3:copy(pos), d) + if cart_func:is_rail(p) then + return d + end + d.y = 0 + d[other_dir] = a[2] + p = cart_func.v3:add(cart_func.v3:copy(pos), d) + if cart_func:is_rail(p) then + return d + end + d.y = -1 + p = cart_func.v3:add(cart_func.v3:copy(pos), d) + if cart_func:is_rail(p) then + return d + end + d.y = 0 + + return {x=0, y=0, z=0} +end + +function cart:calc_rail_direction(pos, vel) + local velocity = cart_func.v3:copy(vel) + local p = cart_func.v3:copy(pos) + if cart_func:is_int(p.x) and cart_func:is_int(p.z) then + + local dir = cart_func:velocity_to_dir(velocity) + local dir_old = cart_func.v3:copy(dir) + + dir = self:get_rail_direction(cart_func.v3:round(p), dir) + + local v = math.max(math.abs(velocity.x), math.abs(velocity.z)) + velocity = { + x = v * dir.x, + y = v * dir.y, + z = v * dir.z, + } + + if cart_func.v3:equal(velocity, {x=0, y=0, z=0}) then + + -- First try this HACK + -- Move the cart on the rail if above or under it + if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=1, z=0})) and vel.y >= 0 then + p = cart_func.v3:add(p, {x=0, y=1, z=0}) + return self:calc_rail_direction(p, vel) + end + if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=-1, z=0})) and vel.y <= 0 then + p = cart_func.v3:add(p, {x=0, y=-1, z=0}) + return self:calc_rail_direction(p, vel) + end + -- Now the HACK gets really dirty + if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=2, z=0})) and vel.y >= 0 then + p = cart_func.v3:add(p, {x=0, y=1, z=0}) + return self:calc_rail_direction(p, vel) + end + if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=-2, z=0})) and vel.y <= 0 then + p = cart_func.v3:add(p, {x=0, y=-1, z=0}) + return self:calc_rail_direction(p, vel) + end + + return {x=0, y=0, z=0}, p + end + + if not cart_func.v3:equal(dir, dir_old) then + return velocity, cart_func.v3:round(p) + end + + end + return velocity, p +end + +function cart:on_step(dtime) + + local pos = self.object:getpos() + local dir = cart_func:velocity_to_dir(self.velocity) + + if not cart_func.v3:equal(self.velocity, {x=0,y=0,z=0}) then + self.pre_stop_dir = cart_func:velocity_to_dir(self.velocity) + end + + -- Stop the cart if the velocity is nearly 0 + -- Only if on a flat railway + if dir.y == 0 then + if math.abs(self.velocity.x) < 0.1 and math.abs(self.velocity.z) < 0.1 then + -- Start the cart if powered from mesecons + local a = tonumber(minetest.env:get_meta(pos):get_string("cart_acceleration")) + if a and a ~= 0 then + if self.pre_stop_dir and cart_func.v3:equal(self:get_rail_direction(self.object:getpos(), self.pre_stop_dir), self.pre_stop_dir) then + self.velocity = { + x = self.pre_stop_dir.x * 0.2, + y = self.pre_stop_dir.y * 0.2, + z = self.pre_stop_dir.z * 0.2, + } + self.old_velocity = self.velocity + return + end + for _,y in ipairs({0,-1,1}) do + for _,z in ipairs({1,-1}) do + if cart_func.v3:equal(self:get_rail_direction(self.object:getpos(), {x=0, y=y, z=z}), {x=0, y=y, z=z}) then + self.velocity = { + x = 0, + y = 0.2*y, + z = 0.2*z, + } + self.old_velocity = self.velocity + return + end + end + for _,x in ipairs({1,-1}) do + if cart_func.v3:equal(self:get_rail_direction(self.object:getpos(), {x=x, y=y, z=0}), {x=x, y=y, z=0}) then + self.velocity = { + x = 0.2*x, + y = 0.2*y, + z = 0, + } + self.old_velocity = self.velocity + return + end + end + end + end + + self.velocity = {x=0, y=0, z=0} + self.object:setvelocity(self.velocity) + self.old_velocity = self.velocity + self.old_pos = self.object:getpos() + return + end + end + + -- + -- Set the new moving direction + -- + + -- Recalcualte the rails that are passed since the last server step + local old_dir = cart_func:velocity_to_dir(self.old_velocity) + if old_dir.x ~= 0 then + local sign = cart_func:get_sign(pos.x-self.old_pos.x) + while true do + if sign ~= cart_func:get_sign(pos.x-self.old_pos.x) or pos.x == self.old_pos.x then + break + end + self.old_pos.x = self.old_pos.x + cart_func:get_sign(pos.x-self.old_pos.x)*0.1 + self.old_pos.y = self.old_pos.y + cart_func:get_sign(pos.x-self.old_pos.x)*0.1*old_dir.y + self.old_velocity, self.old_pos = self:calc_rail_direction(self.old_pos, self.old_velocity) + old_dir = cart_func:velocity_to_dir(self.old_velocity) + if not cart_func.v3:equal(cart_func:velocity_to_dir(self.old_velocity), dir) then + self.velocity = self.old_velocity + pos = self.old_pos + self.object:setpos(self.old_pos) + break + end + end + elseif old_dir.z ~= 0 then + local sign = cart_func:get_sign(pos.z-self.old_pos.z) + while true do + if sign ~= cart_func:get_sign(pos.z-self.old_pos.z) or pos.z == self.old_pos.z then + break + end + self.old_pos.z = self.old_pos.z + cart_func:get_sign(pos.z-self.old_pos.z)*0.1 + self.old_pos.y = self.old_pos.y + cart_func:get_sign(pos.z-self.old_pos.z)*0.1*old_dir.y + self.old_velocity, self.old_pos = self:calc_rail_direction(self.old_pos, self.old_velocity) + old_dir = cart_func:velocity_to_dir(self.old_velocity) + if not cart_func.v3:equal(cart_func:velocity_to_dir(self.old_velocity), dir) then + self.velocity = self.old_velocity + pos = self.old_pos + self.object:setpos(self.old_pos) + break + end + end + end + + -- Calculate the new step + self.velocity, pos = self:calc_rail_direction(pos, self.velocity) + self.object:setpos(pos) + dir = cart_func:velocity_to_dir(self.velocity) + + -- Accelerate or decelerate the cart according to the pitch and acceleration of the rail node + local a = tonumber(minetest.env:get_meta(pos):get_string("cart_acceleration")) + if not a then + a = 0 + end + if self.velocity.y < 0 then + self.velocity = { + x = self.velocity.x + (a+0.13)*cart_func:get_sign(self.velocity.x), + y = self.velocity.y + (a+0.13)*cart_func:get_sign(self.velocity.y), + z = self.velocity.z + (a+0.13)*cart_func:get_sign(self.velocity.z), + } + elseif self.velocity.y > 0 then + self.velocity = { + x = self.velocity.x + (a-0.1)*cart_func:get_sign(self.velocity.x), + y = self.velocity.y + (a-0.1)*cart_func:get_sign(self.velocity.y), + z = self.velocity.z + (a-0.1)*cart_func:get_sign(self.velocity.z), + } + else + self.velocity = { + x = self.velocity.x + (a-0.03)*cart_func:get_sign(self.velocity.x), + y = self.velocity.y + (a-0.03)*cart_func:get_sign(self.velocity.y), + z = self.velocity.z + (a-0.03)*cart_func:get_sign(self.velocity.z), + } + + -- Place the cart exactly on top of the rail + if cart_func:is_rail(cart_func.v3:round(pos)) then + self.object:setpos({x=pos.x, y=math.floor(pos.y+0.5), z=pos.z}) + pos = self.object:getpos() + end + end + + -- Dont switch moving direction + -- Only if on flat railway + if dir.y == 0 then + if cart_func:get_sign(dir.x) ~= cart_func:get_sign(self.velocity.x) then + self.velocity.x = 0 + end + if cart_func:get_sign(dir.y) ~= cart_func:get_sign(self.velocity.y) then + self.velocity.y = 0 + end + if cart_func:get_sign(dir.z) ~= cart_func:get_sign(self.velocity.z) then + self.velocity.z = 0 + end + end + + -- Allow only one moving direction (multiply the other one with 0) + dir = cart_func:velocity_to_dir(self.velocity) + self.velocity = { + x = math.abs(self.velocity.x) * dir.x, + y = self.velocity.y, + z = math.abs(self.velocity.z) * dir.z, + } + + -- Move cart exactly on the rail + if dir.x ~= 0 and not cart_func:is_int(pos.z) then + pos.z = math.floor(0.5+pos.z) + self.object:setpos(pos) + elseif dir.z ~= 0 and not cart_func:is_int(pos.x) then + pos.x = math.floor(0.5+pos.x) + self.object:setpos(pos) + end + + -- Limit the velocity + if math.abs(self.velocity.x) > self.MAX_V then + self.velocity.x = self.MAX_V*cart_func:get_sign(self.velocity.x) + end + if math.abs(self.velocity.y) > self.MAX_V then + self.velocity.y = self.MAX_V*cart_func:get_sign(self.velocity.y) + end + if math.abs(self.velocity.z) > self.MAX_V then + self.velocity.z = self.MAX_V*cart_func:get_sign(self.velocity.z) + end + + self.object:setvelocity(self.velocity) + + self.old_pos = self.object:getpos() + self.old_velocity = cart_func.v3:copy(self.velocity) + + if dir.x < 0 then + self.object:setyaw(math.pi/2) + elseif dir.x > 0 then + self.object:setyaw(3*math.pi/2) + elseif dir.z < 0 then + self.object:setyaw(math.pi) + elseif dir.z > 0 then + self.object:setyaw(0) + end + + if dir.y == -1 then + self.object:set_animation({x=1, y=1}, 1, 0) + elseif dir.y == 1 then + self.object:set_animation({x=2, y=2}, 1, 0) + else + self.object:set_animation({x=0, y=0}, 1, 0) + end + +end + +minetest.register_entity("carts:cart", cart) + + +minetest.register_craftitem("carts:cart", { + description = "Minecart", + inventory_image = minetest.inventorycube("cart_top.png", "cart_side.png", "cart_side.png"), + wield_image = "cart_side.png", + + on_place = function(itemstack, placer, pointed_thing) + if not pointed_thing.type == "node" then + return + end + if cart_func:is_rail(pointed_thing.under) then + minetest.env:add_entity(pointed_thing.under, "carts:cart") + if not minetest.setting_getbool("creative_mode") then + itemstack:take_item() + end + return itemstack + elseif cart_func:is_rail(pointed_thing.above) then + minetest.env:add_entity(pointed_thing.above, "carts:cart") + if not minetest.setting_getbool("creative_mode") then + itemstack:take_item() + end + return itemstack + end + end, +}) + +minetest.register_craft({ + output = "carts:cart", + recipe = { + {"", "", ""}, + {"default:steel_ingot", "", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + }, +}) + +-- +-- Mesecon support +-- + +minetest.register_node(":default:rail", { + description = "Rail", + drawtype = "raillike", + tiles = {"default_rail.png", "default_rail_curved.png", "default_rail_t_junction.png", "default_rail_crossing.png"}, + inventory_image = "default_rail.png", + wield_image = "default_rail.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + selection_box = { + type = "fixed", + -- but how to specify the dimensions for curved and sideways rails? + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {bendy=2,snappy=1,dig_immediate=2,attached_node=1,rail=1,connect_to_raillike=1}, +}) + +minetest.register_node("carts:powerrail", { + description = "Powered Rail", + drawtype = "raillike", + tiles = {"carts_rail_pwr.png", "carts_rail_curved_pwr.png", "carts_rail_t_junction_pwr.png", "carts_rail_crossing_pwr.png"}, + inventory_image = "carts_rail_pwr.png", + wield_image = "carts_rail_pwr.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + selection_box = { + type = "fixed", + -- but how to specify the dimensions for curved and sideways rails? + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {bendy=2,snappy=1,dig_immediate=2,attached_node=1,rail=1,connect_to_raillike=1}, + + after_place_node = function(pos, placer, itemstack) + if not mesecon then + minetest.env:get_meta(pos):set_string("cart_acceleration", "0.5") + end + end, + + mesecons = { + effector = { + action_on = function(pos, node) + minetest.env:get_meta(pos):set_string("cart_acceleration", "0.5") + end, + + action_off = function(pos, node) + minetest.env:get_meta(pos):set_string("cart_acceleration", "0") + end, + }, + }, +}) + +minetest.register_node("carts:brakerail", { + description = "Brake Rail", + drawtype = "raillike", + tiles = {"carts_rail_brk.png", "carts_rail_curved_brk.png", "carts_rail_t_junction_brk.png", "carts_rail_crossing_brk.png"}, + inventory_image = "carts_rail_brk.png", + wield_image = "carts_rail_brk.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + selection_box = { + type = "fixed", + -- but how to specify the dimensions for curved and sideways rails? + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {bendy=2,snappy=1,dig_immediate=2,attached_node=1,rail=1,connect_to_raillike=1}, + + after_place_node = function(pos, placer, itemstack) + if not mesecon then + minetest.env:get_meta(pos):set_string("cart_acceleration", "-0.2") + end + end, + + mesecons = { + effector = { + action_on = function(pos, node) + minetest.env:get_meta(pos):set_string("cart_acceleration", "-0.2") + end, + + action_off = function(pos, node) + minetest.env:get_meta(pos):set_string("cart_acceleration", "0") + end, + }, + }, +}) + +minetest.register_craft({ + output = "carts:powerrail 2", + recipe = { + {"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"}, + {"default:steel_ingot", "default:stick", "default:steel_ingot"}, + {"default:steel_ingot", "", "default:steel_ingot"}, + } +}) + +minetest.register_craft({ + output = "carts:powerrail 2", + recipe = { + {"default:steel_ingot", "", "default:steel_ingot"}, + {"default:steel_ingot", "default:stick", "default:steel_ingot"}, + {"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"}, + } +}) + +minetest.register_craft({ + output = "carts:brakerail 2", + recipe = { + {"default:steel_ingot", "default:coal_lump", "default:steel_ingot"}, + {"default:steel_ingot", "default:stick", "default:steel_ingot"}, + {"default:steel_ingot", "", "default:steel_ingot"}, + } +}) + +minetest.register_craft({ + output = "carts:brakerail 2", + recipe = { + {"default:steel_ingot", "", "default:steel_ingot"}, + {"default:steel_ingot", "default:stick", "default:steel_ingot"}, + {"default:steel_ingot", "default:coal_lump", "default:steel_ingot"}, + } +}) diff --git a/mods/carts/models/cart.png b/mods/carts/models/cart.png new file mode 100644 index 0000000..1f9f568 Binary files /dev/null and b/mods/carts/models/cart.png differ diff --git a/mods/carts/models/cart.x b/mods/carts/models/cart.x new file mode 100644 index 0000000..3325aaf --- /dev/null +++ b/mods/carts/models/cart.x @@ -0,0 +1,339 @@ +xof 0303txt 0032 + +Frame Root { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000, 1.000000,-0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 1.000000;; + } + Frame Cube { + FrameTransformMatrix { + 5.000000, 0.000000,-0.000000, 0.000000, + -0.000000, 3.535534, 3.535534, 0.000000, + 0.000000,-3.535534, 3.535534, 0.000000, + 0.000000,-3.000000, 3.000000, 1.000000;; + } + Mesh { //Cube_001 Mesh + 72; + -1.000000; 1.000000;-1.000000;, + -1.000000;-1.000000;-1.000000;, + 1.000000;-1.000000;-1.000000;, + 1.000000; 1.000000;-1.000000;, + -0.833334;-1.000000; 1.000000;, + -1.000000;-1.000000; 1.000000;, + -1.000000;-0.833333; 1.000000;, + -0.833334;-0.833333; 1.000000;, + -1.000000;-1.000000;-1.000000;, + -1.000000;-1.000000; 1.000000;, + 0.999999;-1.000001; 1.000000;, + 1.000000;-1.000000;-1.000000;, + 0.999999;-1.000001; 1.000000;, + 0.833332;-1.000000; 1.000000;, + 0.833333;-0.833334; 1.000000;, + 1.000000;-0.833334; 1.000000;, + 0.833332;-1.000000; 1.000000;, + -0.833334;-1.000000; 1.000000;, + -0.833334;-0.833333; 1.000000;, + 0.833333;-0.833334; 1.000000;, + 1.000000; 0.833333; 1.000000;, + 0.833334; 0.833333; 1.000000;, + 0.833334; 1.000000; 1.000000;, + 1.000000; 0.999999; 1.000000;, + 1.000000;-0.833334; 1.000000;, + 0.833333;-0.833334; 1.000000;, + 0.833334; 0.833333; 1.000000;, + 1.000000; 0.833333; 1.000000;, + 0.833334; 0.833333; 1.000000;, + -0.833333; 0.833333; 1.000000;, + -0.833333; 1.000000; 1.000000;, + 0.833334; 1.000000; 1.000000;, + 0.833334; 0.833333;-0.800000;, + -0.833333; 0.833333;-0.800000;, + -0.833333; 0.833333; 1.000000;, + 0.833334; 0.833333; 1.000000;, + -0.833333; 0.833333; 1.000000;, + -1.000000; 0.833333; 1.000000;, + -1.000000; 1.000000; 1.000000;, + -0.833333; 1.000000; 1.000000;, + -0.833334;-0.833333; 1.000000;, + -1.000000;-0.833333; 1.000000;, + -1.000000; 0.833333; 1.000000;, + -0.833333; 0.833333; 1.000000;, + 0.833333;-0.833334;-0.800000;, + -0.833334;-0.833333;-0.800000;, + -0.833333; 0.833333;-0.800000;, + 0.833334; 0.833333;-0.800000;, + -0.833333; 0.833333;-0.800000;, + -0.833334;-0.833333;-0.800000;, + -0.833334;-0.833333; 1.000000;, + -0.833333; 0.833333; 1.000000;, + -0.833334;-0.833333;-0.800000;, + 0.833333;-0.833334;-0.800000;, + 0.833333;-0.833334; 1.000000;, + -0.833334;-0.833333; 1.000000;, + 0.833333;-0.833334;-0.800000;, + 0.833334; 0.833333;-0.800000;, + 0.833334; 0.833333; 1.000000;, + 0.833333;-0.833334; 1.000000;, + -1.000000; 1.000000;-1.000000;, + -1.000000; 1.000000; 1.000000;, + -1.000000;-1.000000; 1.000000;, + -1.000000;-1.000000;-1.000000;, + -1.000000; 1.000000; 1.000000;, + -1.000000; 1.000000;-1.000000;, + 1.000000; 1.000000;-1.000000;, + 1.000000; 0.999999; 1.000000;, + 1.000000;-1.000000;-1.000000;, + 0.999999;-1.000001; 1.000000;, + 1.000000; 0.999999; 1.000000;, + 1.000000; 1.000000;-1.000000;; + 18; + 4;0;1;2;3;, + 4;4;5;6;7;, + 4;8;9;10;11;, + 4;12;13;14;15;, + 4;16;17;18;19;, + 4;20;21;22;23;, + 4;24;25;26;27;, + 4;28;29;30;31;, + 4;32;33;34;35;, + 4;36;37;38;39;, + 4;40;41;42;43;, + 4;44;45;46;47;, + 4;48;49;50;51;, + 4;52;53;54;55;, + 4;56;57;58;59;, + 4;60;61;62;63;, + 4;64;65;66;67;, + 4;68;69;70;71;; + MeshNormals { //Cube_001 Normals + 72; + 0.000000; 0.000000;-1.000000;, + 0.000000; 0.000000;-1.000000;, + 0.000000; 0.000000;-1.000000;, + 0.000000; 0.000000;-1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + -0.000000;-1.000000;-0.000000;, + -0.000000;-1.000000;-0.000000;, + -0.000000;-1.000000;-0.000000;, + -0.000000;-1.000000;-0.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + -0.000000;-1.000000; 0.000000;, + -0.000000;-1.000000; 0.000000;, + -0.000000;-1.000000; 0.000000;, + -0.000000;-1.000000; 0.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 1.000000;-0.000000; 0.000000;, + 1.000000;-0.000000; 0.000000;, + 1.000000;-0.000000; 0.000000;, + 1.000000;-0.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + -1.000000; 0.000000; 0.000000;, + -1.000000; 0.000000; 0.000000;, + -1.000000; 0.000000; 0.000000;, + -1.000000; 0.000000; 0.000000;, + -1.000000; 0.000000;-0.000000;, + -1.000000; 0.000000;-0.000000;, + -1.000000; 0.000000;-0.000000;, + -1.000000; 0.000000;-0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 1.000000;-0.000000; 0.000000;, + 1.000000;-0.000000; 0.000000;, + 1.000000;-0.000000; 0.000000;, + 1.000000;-0.000000; 0.000000;; + 18; + 4;0;1;2;3;, + 4;4;5;6;7;, + 4;8;9;10;11;, + 4;12;13;14;15;, + 4;16;17;18;19;, + 4;20;21;22;23;, + 4;24;25;26;27;, + 4;28;29;30;31;, + 4;32;33;34;35;, + 4;36;37;38;39;, + 4;40;41;42;43;, + 4;44;45;46;47;, + 4;48;49;50;51;, + 4;52;53;54;55;, + 4;56;57;58;59;, + 4;60;61;62;63;, + 4;64;65;66;67;, + 4;68;69;70;71;; + } //End of Cube_001 Normals + MeshMaterialList { //Cube_001 Material List + 1; + 18; + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0;; + Material Material { + 0.640000; 0.640000; 0.640000; 1.000000;; + 96.078431; + 0.500000; 0.500000; 0.500000;; + 0.000000; 0.000000; 0.000000;; + TextureFilename {"cart.png";} + } + } //End of Cube_001 Material List + MeshTextureCoords { //Cube_001 UV Coordinates + 72; + 0.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 1.000000;, + 0.000000; 1.000000;, + 0.031250; 0.500000;, + -0.000000; 0.500000;, + -0.000000; 0.468750;, + 0.031250; 0.468750;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 1.000000; 0.000000;, + 1.000000; 0.500000;, + 0.468750; 0.468750;, + 0.500000; 0.468750;, + 0.500000; 0.500000;, + 0.468750; 0.500000;, + 0.031250; 0.468750;, + 0.468750; 0.468750;, + 0.468750; 0.500000;, + 0.031250; 0.500000;, + 0.468750; 0.000000;, + 0.500000; 0.000000;, + 0.500000; 0.031250;, + 0.468750; 0.031250;, + 0.468750; 0.031250;, + 0.500000; 0.031250;, + 0.500000; 0.468750;, + 0.468750; 0.468750;, + 0.468750; 0.031250;, + 0.031250; 0.031250;, + 0.031250; 0.000000;, + 0.468750; 0.000000;, + 1.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 1.000000; 0.000000;, + 0.031250; 0.031250;, + 0.000000; 0.031250;, + 0.000000; 0.000000;, + 0.031250; 0.000000;, + 0.031250; 0.468750;, + -0.000000; 0.468750;, + 0.000000; 0.031250;, + 0.031250; 0.031250;, + 0.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 1.000000;, + 0.000000; 1.000000;, + 1.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 1.000000; 0.000000;, + 1.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 1.000000; 0.000000;, + 1.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 1.000000; 0.000000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 1.000000; 0.000000;, + 1.000000; 0.500000;, + 1.000000; 0.000000;, + 1.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 1.000000; 0.000000;, + 1.000000; 0.500000;; + } //End of Cube_001 UV Coordinates + } //End of Cube_001 Mesh + } //End of Cube +} //End of Root Frame +AnimationSet { + Animation { + {Cube} + AnimationKey { //Position + 2; + 4; + 0;3; 0.000000, 0.000000, 0.000000;;, + 1;3; 0.000000, 3.000000, 3.000000;;, + 2;3; 0.000000,-3.000000, 3.000000;;, + 3;3; 0.000000,-3.000000, 3.000000;;; + } + AnimationKey { //Rotation + 0; + 4; + 0;4; -1.000000, 0.000000, 0.000000, 0.000000;;, + 1;4; -0.923880,-0.382683,-0.000000, 0.000000;;, + 2;4; -0.923880, 0.382683, 0.000000, 0.000000;;, + 3;4; -0.923880, 0.382683, 0.000000, 0.000000;;; + } + AnimationKey { //Scale + 1; + 4; + 0;3; 5.000000, 5.000000, 5.000000;;, + 1;3; 5.000000, 5.000000, 5.000000;;, + 2;3; 5.000000, 5.000000, 5.000000;;, + 3;3; 5.000000, 5.000000, 5.000000;;; + } + } +} //End of AnimationSet diff --git a/mods/carts/textures/cart_bottom.png b/mods/carts/textures/cart_bottom.png new file mode 100644 index 0000000..f84b1ae Binary files /dev/null and b/mods/carts/textures/cart_bottom.png differ diff --git a/mods/carts/textures/cart_side.png b/mods/carts/textures/cart_side.png new file mode 100644 index 0000000..79f6c32 Binary files /dev/null and b/mods/carts/textures/cart_side.png differ diff --git a/mods/carts/textures/cart_top.png b/mods/carts/textures/cart_top.png new file mode 100644 index 0000000..8140fc7 Binary files /dev/null and b/mods/carts/textures/cart_top.png differ diff --git a/mods/carts/textures/carts_rail_brk.png b/mods/carts/textures/carts_rail_brk.png new file mode 100644 index 0000000..f3e0ff9 Binary files /dev/null and b/mods/carts/textures/carts_rail_brk.png differ diff --git a/mods/carts/textures/carts_rail_crossing_brk.png b/mods/carts/textures/carts_rail_crossing_brk.png new file mode 100644 index 0000000..3ace508 Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing_brk.png differ diff --git a/mods/carts/textures/carts_rail_crossing_pwr.png b/mods/carts/textures/carts_rail_crossing_pwr.png new file mode 100644 index 0000000..d63f133 Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing_pwr.png differ diff --git a/mods/carts/textures/carts_rail_curved_brk.png b/mods/carts/textures/carts_rail_curved_brk.png new file mode 100644 index 0000000..5a84918 Binary files /dev/null and b/mods/carts/textures/carts_rail_curved_brk.png differ diff --git a/mods/carts/textures/carts_rail_curved_pwr.png b/mods/carts/textures/carts_rail_curved_pwr.png new file mode 100644 index 0000000..e2ac67a Binary files /dev/null and b/mods/carts/textures/carts_rail_curved_pwr.png differ diff --git a/mods/carts/textures/carts_rail_pwr.png b/mods/carts/textures/carts_rail_pwr.png new file mode 100644 index 0000000..95f33f6 Binary files /dev/null and b/mods/carts/textures/carts_rail_pwr.png differ diff --git a/mods/carts/textures/carts_rail_t_junction_brk.png b/mods/carts/textures/carts_rail_t_junction_brk.png new file mode 100644 index 0000000..0c2c1cb Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction_brk.png differ diff --git a/mods/carts/textures/carts_rail_t_junction_pwr.png b/mods/carts/textures/carts_rail_t_junction_pwr.png new file mode 100644 index 0000000..7f97fc7 Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction_pwr.png differ diff --git a/mods/carts/voxelgetter.lua b/mods/carts/voxelgetter.lua new file mode 100644 index 0000000..df7c7f8 --- /dev/null +++ b/mods/carts/voxelgetter.lua @@ -0,0 +1,16 @@ +function cart_func:get_content_voxel(pos) + local t1 = os.clock() + local vm = minetest.get_voxel_manip() + local pos1, pos2 = vm:read_from_map(vector.add(pos, {x=-1,y=-1,z=-1}),vector.add(pos, {x=1,y=1,z=1})) + local a = VoxelArea:new{ + MinEdge=pos1, + MaxEdge=pos2, + } + + local data = vm:get_data() + local vi = a:indexp(pos) + local railid = data[vi] + local real_name = minetest.get_name_from_content_id(railid) + print(string.format("voxel-ing rail: elapsed time: %.2fms", (os.clock() - t1) * 1000)) + return real_name +end diff --git a/mods/clock/init.lua b/mods/clock/init.lua index 0fca778..2f29a0e 100644 --- a/mods/clock/init.lua +++ b/mods/clock/init.lua @@ -10,7 +10,7 @@ minetest.register_globalstep(function(dtime) return false end if has_clock(player) then - local time = math.floor(16 * (minetest.get_timeofday() + .5) % 16 + 1) + local time = math.floor((64 * (minetest.get_timeofday() + .5)) % 64 + 1) for j,stack in ipairs(player:get_inventory():get_list("main")) do if minetest.get_item_group(stack:get_name(), "clock") ~= 0 and @@ -23,22 +23,70 @@ minetest.register_globalstep(function(dtime) end) local images = { - "w1.png", - "w2.png", - "w3.png", - "w4.png", - "w5.png", - "w6.png", - "w7.png", - "w8.png", - "w9.png", - "w10.png", - "w11.png", - "w12.png", - "w13.png", - "w14.png", - "w15.png", - "w16.png", + "w0.png", + "w1.png", + "w2.png", + "w3.png", + "w4.png", + "w5.png", + "w6.png", + "w7.png", + "w8.png", + "w9.png", + "w10.png", + "w11.png", + "w12.png", + "w13.png", + "w14.png", + "w15.png", + "w16.png", + "w17.png", + "w18.png", + "w19.png", + "w20.png", + "w21.png", + "w22.png", + "w23.png", + "w24.png", + "w25.png", + "w26.png", + "w27.png", + "w28.png", + "w29.png", + "w30.png", + "w31.png", + "w32.png", + "w33.png", + "w34.png", + "w35.png", + "w36.png", + "w37.png", + "w38.png", + "w39.png", + "w40.png", + "w41.png", + "w42.png", + "w43.png", + "w44.png", + "w45.png", + "w46.png", + "w47.png", + "w48.png", + "w49.png", + "w50.png", + "w51.png", + "w52.png", + "w53.png", + "w54.png", + "w55.png", + "w56.png", + "w57.png", + "w58.png", + "w59.png", + "w60.png", + "w61.png", + "w62.png", + "w63.png", } local i diff --git a/mods/clock/textures/w0.png b/mods/clock/textures/w0.png new file mode 100644 index 0000000..dbbda19 Binary files /dev/null and b/mods/clock/textures/w0.png differ diff --git a/mods/clock/textures/w1.png b/mods/clock/textures/w1.png index ab3b879..32e299a 100644 Binary files a/mods/clock/textures/w1.png and b/mods/clock/textures/w1.png differ diff --git a/mods/clock/textures/w10.png b/mods/clock/textures/w10.png index e9244e3..b52b8a8 100644 Binary files a/mods/clock/textures/w10.png and b/mods/clock/textures/w10.png differ diff --git a/mods/clock/textures/w11.png b/mods/clock/textures/w11.png index 22caa29..4f986f7 100644 Binary files a/mods/clock/textures/w11.png and b/mods/clock/textures/w11.png differ diff --git a/mods/clock/textures/w12.png b/mods/clock/textures/w12.png index fbe763e..ae965c7 100644 Binary files a/mods/clock/textures/w12.png and b/mods/clock/textures/w12.png differ diff --git a/mods/clock/textures/w13.png b/mods/clock/textures/w13.png index 999ab1c..7328dc1 100644 Binary files a/mods/clock/textures/w13.png and b/mods/clock/textures/w13.png differ diff --git a/mods/clock/textures/w14.png b/mods/clock/textures/w14.png index 2c89dcb..fac389b 100644 Binary files a/mods/clock/textures/w14.png and b/mods/clock/textures/w14.png differ diff --git a/mods/clock/textures/w15.png b/mods/clock/textures/w15.png index 9600632..4fb5ac1 100644 Binary files a/mods/clock/textures/w15.png and b/mods/clock/textures/w15.png differ diff --git a/mods/clock/textures/w16.png b/mods/clock/textures/w16.png index 1d3c52f..faca1f7 100644 Binary files a/mods/clock/textures/w16.png and b/mods/clock/textures/w16.png differ diff --git a/mods/clock/textures/w17.png b/mods/clock/textures/w17.png new file mode 100644 index 0000000..e00e6fe Binary files /dev/null and b/mods/clock/textures/w17.png differ diff --git a/mods/clock/textures/w18.png b/mods/clock/textures/w18.png new file mode 100644 index 0000000..528e478 Binary files /dev/null and b/mods/clock/textures/w18.png differ diff --git a/mods/clock/textures/w19.png b/mods/clock/textures/w19.png new file mode 100644 index 0000000..b204d14 Binary files /dev/null and b/mods/clock/textures/w19.png differ diff --git a/mods/clock/textures/w2.png b/mods/clock/textures/w2.png index a5ac555..0bc81b6 100644 Binary files a/mods/clock/textures/w2.png and b/mods/clock/textures/w2.png differ diff --git a/mods/clock/textures/w20.png b/mods/clock/textures/w20.png new file mode 100644 index 0000000..9035a75 Binary files /dev/null and b/mods/clock/textures/w20.png differ diff --git a/mods/clock/textures/w21.png b/mods/clock/textures/w21.png new file mode 100644 index 0000000..cf1b442 Binary files /dev/null and b/mods/clock/textures/w21.png differ diff --git a/mods/clock/textures/w22.png b/mods/clock/textures/w22.png new file mode 100644 index 0000000..e6ffe64 Binary files /dev/null and b/mods/clock/textures/w22.png differ diff --git a/mods/clock/textures/w23.png b/mods/clock/textures/w23.png new file mode 100644 index 0000000..4dffc56 Binary files /dev/null and b/mods/clock/textures/w23.png differ diff --git a/mods/clock/textures/w24.png b/mods/clock/textures/w24.png new file mode 100644 index 0000000..dcff127 Binary files /dev/null and b/mods/clock/textures/w24.png differ diff --git a/mods/clock/textures/w25.png b/mods/clock/textures/w25.png new file mode 100644 index 0000000..5d09072 Binary files /dev/null and b/mods/clock/textures/w25.png differ diff --git a/mods/clock/textures/w26.png b/mods/clock/textures/w26.png new file mode 100644 index 0000000..b35bb99 Binary files /dev/null and b/mods/clock/textures/w26.png differ diff --git a/mods/clock/textures/w27.png b/mods/clock/textures/w27.png new file mode 100644 index 0000000..6b0f616 Binary files /dev/null and b/mods/clock/textures/w27.png differ diff --git a/mods/clock/textures/w28.png b/mods/clock/textures/w28.png new file mode 100644 index 0000000..b6764dc Binary files /dev/null and b/mods/clock/textures/w28.png differ diff --git a/mods/clock/textures/w29.png b/mods/clock/textures/w29.png new file mode 100644 index 0000000..3947e60 Binary files /dev/null and b/mods/clock/textures/w29.png differ diff --git a/mods/clock/textures/w3.png b/mods/clock/textures/w3.png index c63014d..c8e73a7 100644 Binary files a/mods/clock/textures/w3.png and b/mods/clock/textures/w3.png differ diff --git a/mods/clock/textures/w30.png b/mods/clock/textures/w30.png new file mode 100644 index 0000000..8a23bb4 Binary files /dev/null and b/mods/clock/textures/w30.png differ diff --git a/mods/clock/textures/w31.png b/mods/clock/textures/w31.png new file mode 100644 index 0000000..a631d28 Binary files /dev/null and b/mods/clock/textures/w31.png differ diff --git a/mods/clock/textures/w32.png b/mods/clock/textures/w32.png new file mode 100644 index 0000000..1c3ff8c Binary files /dev/null and b/mods/clock/textures/w32.png differ diff --git a/mods/clock/textures/w33.png b/mods/clock/textures/w33.png new file mode 100644 index 0000000..afcd250 Binary files /dev/null and b/mods/clock/textures/w33.png differ diff --git a/mods/clock/textures/w34.png b/mods/clock/textures/w34.png new file mode 100644 index 0000000..ad60363 Binary files /dev/null and b/mods/clock/textures/w34.png differ diff --git a/mods/clock/textures/w35.png b/mods/clock/textures/w35.png new file mode 100644 index 0000000..4fe44aa Binary files /dev/null and b/mods/clock/textures/w35.png differ diff --git a/mods/clock/textures/w36.png b/mods/clock/textures/w36.png new file mode 100644 index 0000000..f6da86f Binary files /dev/null and b/mods/clock/textures/w36.png differ diff --git a/mods/clock/textures/w37.png b/mods/clock/textures/w37.png new file mode 100644 index 0000000..ad797cc Binary files /dev/null and b/mods/clock/textures/w37.png differ diff --git a/mods/clock/textures/w38.png b/mods/clock/textures/w38.png new file mode 100644 index 0000000..531f8f5 Binary files /dev/null and b/mods/clock/textures/w38.png differ diff --git a/mods/clock/textures/w39.png b/mods/clock/textures/w39.png new file mode 100644 index 0000000..fe0cf9d Binary files /dev/null and b/mods/clock/textures/w39.png differ diff --git a/mods/clock/textures/w4.png b/mods/clock/textures/w4.png index b931742..78acc6d 100644 Binary files a/mods/clock/textures/w4.png and b/mods/clock/textures/w4.png differ diff --git a/mods/clock/textures/w40.png b/mods/clock/textures/w40.png new file mode 100644 index 0000000..cd9939b Binary files /dev/null and b/mods/clock/textures/w40.png differ diff --git a/mods/clock/textures/w41.png b/mods/clock/textures/w41.png new file mode 100644 index 0000000..479e847 Binary files /dev/null and b/mods/clock/textures/w41.png differ diff --git a/mods/clock/textures/w42.png b/mods/clock/textures/w42.png new file mode 100644 index 0000000..46369e1 Binary files /dev/null and b/mods/clock/textures/w42.png differ diff --git a/mods/clock/textures/w43.png b/mods/clock/textures/w43.png new file mode 100644 index 0000000..c42dbc8 Binary files /dev/null and b/mods/clock/textures/w43.png differ diff --git a/mods/clock/textures/w44.png b/mods/clock/textures/w44.png new file mode 100644 index 0000000..f64be2b Binary files /dev/null and b/mods/clock/textures/w44.png differ diff --git a/mods/clock/textures/w45.png b/mods/clock/textures/w45.png new file mode 100644 index 0000000..0c2ed91 Binary files /dev/null and b/mods/clock/textures/w45.png differ diff --git a/mods/clock/textures/w46.png b/mods/clock/textures/w46.png new file mode 100644 index 0000000..81dcd84 Binary files /dev/null and b/mods/clock/textures/w46.png differ diff --git a/mods/clock/textures/w47.png b/mods/clock/textures/w47.png new file mode 100644 index 0000000..2fd7ba4 Binary files /dev/null and b/mods/clock/textures/w47.png differ diff --git a/mods/clock/textures/w48.png b/mods/clock/textures/w48.png new file mode 100644 index 0000000..03ce821 Binary files /dev/null and b/mods/clock/textures/w48.png differ diff --git a/mods/clock/textures/w49.png b/mods/clock/textures/w49.png new file mode 100644 index 0000000..e8b0fca Binary files /dev/null and b/mods/clock/textures/w49.png differ diff --git a/mods/clock/textures/w5.png b/mods/clock/textures/w5.png index 879e951..46cac74 100644 Binary files a/mods/clock/textures/w5.png and b/mods/clock/textures/w5.png differ diff --git a/mods/clock/textures/w50.png b/mods/clock/textures/w50.png new file mode 100644 index 0000000..506c3ae Binary files /dev/null and b/mods/clock/textures/w50.png differ diff --git a/mods/clock/textures/w51.png b/mods/clock/textures/w51.png new file mode 100644 index 0000000..bd08cd8 Binary files /dev/null and b/mods/clock/textures/w51.png differ diff --git a/mods/clock/textures/w52.png b/mods/clock/textures/w52.png new file mode 100644 index 0000000..badb472 Binary files /dev/null and b/mods/clock/textures/w52.png differ diff --git a/mods/clock/textures/w53.png b/mods/clock/textures/w53.png new file mode 100644 index 0000000..a68d00b Binary files /dev/null and b/mods/clock/textures/w53.png differ diff --git a/mods/clock/textures/w54.png b/mods/clock/textures/w54.png new file mode 100644 index 0000000..61ed3fa Binary files /dev/null and b/mods/clock/textures/w54.png differ diff --git a/mods/clock/textures/w55.png b/mods/clock/textures/w55.png new file mode 100644 index 0000000..864c95d Binary files /dev/null and b/mods/clock/textures/w55.png differ diff --git a/mods/clock/textures/w56.png b/mods/clock/textures/w56.png new file mode 100644 index 0000000..f966996 Binary files /dev/null and b/mods/clock/textures/w56.png differ diff --git a/mods/clock/textures/w57.png b/mods/clock/textures/w57.png new file mode 100644 index 0000000..1f425be Binary files /dev/null and b/mods/clock/textures/w57.png differ diff --git a/mods/clock/textures/w58.png b/mods/clock/textures/w58.png new file mode 100644 index 0000000..9628a4c Binary files /dev/null and b/mods/clock/textures/w58.png differ diff --git a/mods/clock/textures/w59.png b/mods/clock/textures/w59.png new file mode 100644 index 0000000..e481787 Binary files /dev/null and b/mods/clock/textures/w59.png differ diff --git a/mods/clock/textures/w6.png b/mods/clock/textures/w6.png index f0de51f..9d0eaf9 100644 Binary files a/mods/clock/textures/w6.png and b/mods/clock/textures/w6.png differ diff --git a/mods/clock/textures/w60.png b/mods/clock/textures/w60.png new file mode 100644 index 0000000..bb8ad2f Binary files /dev/null and b/mods/clock/textures/w60.png differ diff --git a/mods/clock/textures/w61.png b/mods/clock/textures/w61.png new file mode 100644 index 0000000..b837b14 Binary files /dev/null and b/mods/clock/textures/w61.png differ diff --git a/mods/clock/textures/w62.png b/mods/clock/textures/w62.png new file mode 100644 index 0000000..b773104 Binary files /dev/null and b/mods/clock/textures/w62.png differ diff --git a/mods/clock/textures/w63.png b/mods/clock/textures/w63.png new file mode 100644 index 0000000..bc71f1d Binary files /dev/null and b/mods/clock/textures/w63.png differ diff --git a/mods/clock/textures/w7.png b/mods/clock/textures/w7.png index 65f0fb7..892a5d1 100644 Binary files a/mods/clock/textures/w7.png and b/mods/clock/textures/w7.png differ diff --git a/mods/clock/textures/w8.png b/mods/clock/textures/w8.png index b702fff..409f81e 100644 Binary files a/mods/clock/textures/w8.png and b/mods/clock/textures/w8.png differ diff --git a/mods/clock/textures/w9.png b/mods/clock/textures/w9.png index 780d381..1299e2a 100644 Binary files a/mods/clock/textures/w9.png and b/mods/clock/textures/w9.png differ diff --git a/mods/compass/init.lua b/mods/compass/init.lua index 1dc603b..7138296 100644 --- a/mods/compass/init.lua +++ b/mods/compass/init.lua @@ -22,7 +22,7 @@ minetest.register_globalstep(function(dtime) if angle_north < 0 then angle_north = angle_north + 360 end local angle_dir = 90 - math.deg(dir) local angle_relative = (angle_north - angle_dir) % 360 - local compass_image = math.floor((angle_relative/30) + 0.5)%12 + local compass_image = math.floor((angle_relative/11.25) + 16.5) % 32 for j,stack in ipairs(player:get_inventory():get_list("main")) do if minetest.get_item_group(stack:get_name(), "compass") ~= 0 and @@ -35,18 +35,38 @@ minetest.register_globalstep(function(dtime) end) local images = { - "compass_0.png", - "compass_1.png", - "compass_2.png", - "compass_3.png", - "compass_4.png", - "compass_5.png", - "compass_6.png", - "compass_7.png", - "compass_8.png", - "compass_9.png", - "compass_10.png", - "compass_11.png", + "compass_0.png", + "compass_1.png", + "compass_2.png", + "compass_3.png", + "compass_4.png", + "compass_5.png", + "compass_6.png", + "compass_7.png", + "compass_8.png", + "compass_9.png", + "compass_10.png", + "compass_11.png", + "compass_12.png", + "compass_13.png", + "compass_14.png", + "compass_15.png", + "compass_16.png", + "compass_17.png", + "compass_18.png", + "compass_19.png", + "compass_20.png", + "compass_21.png", + "compass_22.png", + "compass_23.png", + "compass_24.png", + "compass_25.png", + "compass_26.png", + "compass_27.png", + "compass_28.png", + "compass_29.png", + "compass_30.png", + "compass_31.png", } local i diff --git a/mods/compass/textures/compass_0.png b/mods/compass/textures/compass_0.png index dae681b..a989d09 100644 Binary files a/mods/compass/textures/compass_0.png and b/mods/compass/textures/compass_0.png differ diff --git a/mods/compass/textures/compass_1.png b/mods/compass/textures/compass_1.png index 57abb60..c0563d0 100644 Binary files a/mods/compass/textures/compass_1.png and b/mods/compass/textures/compass_1.png differ diff --git a/mods/compass/textures/compass_10.png b/mods/compass/textures/compass_10.png index 9388e92..6cf3cc2 100644 Binary files a/mods/compass/textures/compass_10.png and b/mods/compass/textures/compass_10.png differ diff --git a/mods/compass/textures/compass_11.png b/mods/compass/textures/compass_11.png index b6034e5..4dab515 100644 Binary files a/mods/compass/textures/compass_11.png and b/mods/compass/textures/compass_11.png differ diff --git a/mods/compass/textures/compass_12.png b/mods/compass/textures/compass_12.png new file mode 100644 index 0000000..c208f1a Binary files /dev/null and b/mods/compass/textures/compass_12.png differ diff --git a/mods/compass/textures/compass_13.png b/mods/compass/textures/compass_13.png new file mode 100644 index 0000000..b9a5502 Binary files /dev/null and b/mods/compass/textures/compass_13.png differ diff --git a/mods/compass/textures/compass_14.png b/mods/compass/textures/compass_14.png new file mode 100644 index 0000000..498775c Binary files /dev/null and b/mods/compass/textures/compass_14.png differ diff --git a/mods/compass/textures/compass_15.png b/mods/compass/textures/compass_15.png new file mode 100644 index 0000000..befcd39 Binary files /dev/null and b/mods/compass/textures/compass_15.png differ diff --git a/mods/compass/textures/compass_16.png b/mods/compass/textures/compass_16.png new file mode 100644 index 0000000..4afc7ca Binary files /dev/null and b/mods/compass/textures/compass_16.png differ diff --git a/mods/compass/textures/compass_17.png b/mods/compass/textures/compass_17.png new file mode 100644 index 0000000..e99b912 Binary files /dev/null and b/mods/compass/textures/compass_17.png differ diff --git a/mods/compass/textures/compass_18.png b/mods/compass/textures/compass_18.png new file mode 100644 index 0000000..0947445 Binary files /dev/null and b/mods/compass/textures/compass_18.png differ diff --git a/mods/compass/textures/compass_19.png b/mods/compass/textures/compass_19.png new file mode 100644 index 0000000..ee5541c Binary files /dev/null and b/mods/compass/textures/compass_19.png differ diff --git a/mods/compass/textures/compass_2.png b/mods/compass/textures/compass_2.png index 8f6f005..e7547a4 100644 Binary files a/mods/compass/textures/compass_2.png and b/mods/compass/textures/compass_2.png differ diff --git a/mods/compass/textures/compass_20.png b/mods/compass/textures/compass_20.png new file mode 100644 index 0000000..ba55096 Binary files /dev/null and b/mods/compass/textures/compass_20.png differ diff --git a/mods/compass/textures/compass_21.png b/mods/compass/textures/compass_21.png new file mode 100644 index 0000000..01d3cda Binary files /dev/null and b/mods/compass/textures/compass_21.png differ diff --git a/mods/compass/textures/compass_22.png b/mods/compass/textures/compass_22.png new file mode 100644 index 0000000..32d3973 Binary files /dev/null and b/mods/compass/textures/compass_22.png differ diff --git a/mods/compass/textures/compass_23.png b/mods/compass/textures/compass_23.png new file mode 100644 index 0000000..a9f1f55 Binary files /dev/null and b/mods/compass/textures/compass_23.png differ diff --git a/mods/compass/textures/compass_24.png b/mods/compass/textures/compass_24.png new file mode 100644 index 0000000..20e7ad7 Binary files /dev/null and b/mods/compass/textures/compass_24.png differ diff --git a/mods/compass/textures/compass_25.png b/mods/compass/textures/compass_25.png new file mode 100644 index 0000000..81dba46 Binary files /dev/null and b/mods/compass/textures/compass_25.png differ diff --git a/mods/compass/textures/compass_26.png b/mods/compass/textures/compass_26.png new file mode 100644 index 0000000..a007307 Binary files /dev/null and b/mods/compass/textures/compass_26.png differ diff --git a/mods/compass/textures/compass_27.png b/mods/compass/textures/compass_27.png new file mode 100644 index 0000000..7109dd9 Binary files /dev/null and b/mods/compass/textures/compass_27.png differ diff --git a/mods/compass/textures/compass_28.png b/mods/compass/textures/compass_28.png new file mode 100644 index 0000000..21220d3 Binary files /dev/null and b/mods/compass/textures/compass_28.png differ diff --git a/mods/compass/textures/compass_29.png b/mods/compass/textures/compass_29.png new file mode 100644 index 0000000..1c21ee0 Binary files /dev/null and b/mods/compass/textures/compass_29.png differ diff --git a/mods/compass/textures/compass_3.png b/mods/compass/textures/compass_3.png index 60d4a78..500c39e 100644 Binary files a/mods/compass/textures/compass_3.png and b/mods/compass/textures/compass_3.png differ diff --git a/mods/compass/textures/compass_30.png b/mods/compass/textures/compass_30.png new file mode 100644 index 0000000..43ec693 Binary files /dev/null and b/mods/compass/textures/compass_30.png differ diff --git a/mods/compass/textures/compass_31.png b/mods/compass/textures/compass_31.png new file mode 100644 index 0000000..473ede0 Binary files /dev/null and b/mods/compass/textures/compass_31.png differ diff --git a/mods/compass/textures/compass_4.png b/mods/compass/textures/compass_4.png index 4e53124..255dc8e 100644 Binary files a/mods/compass/textures/compass_4.png and b/mods/compass/textures/compass_4.png differ diff --git a/mods/compass/textures/compass_5.png b/mods/compass/textures/compass_5.png index adb37ee..812738f 100644 Binary files a/mods/compass/textures/compass_5.png and b/mods/compass/textures/compass_5.png differ diff --git a/mods/compass/textures/compass_6.png b/mods/compass/textures/compass_6.png index d081758..776a55b 100644 Binary files a/mods/compass/textures/compass_6.png and b/mods/compass/textures/compass_6.png differ diff --git a/mods/compass/textures/compass_7.png b/mods/compass/textures/compass_7.png index 6794a83..38ae287 100644 Binary files a/mods/compass/textures/compass_7.png and b/mods/compass/textures/compass_7.png differ diff --git a/mods/compass/textures/compass_8.png b/mods/compass/textures/compass_8.png index cc551df..8596026 100644 Binary files a/mods/compass/textures/compass_8.png and b/mods/compass/textures/compass_8.png differ diff --git a/mods/compass/textures/compass_9.png b/mods/compass/textures/compass_9.png index c44fceb..74d85f8 100644 Binary files a/mods/compass/textures/compass_9.png and b/mods/compass/textures/compass_9.png differ diff --git a/mods/fake_fire/depends.txt b/mods/fake_fire/depends.txt new file mode 100644 index 0000000..562cf63 --- /dev/null +++ b/mods/fake_fire/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/fake_fire/init.lua b/mods/fake_fire/init.lua new file mode 100644 index 0000000..e29c98c --- /dev/null +++ b/mods/fake_fire/init.lua @@ -0,0 +1,127 @@ +minetest.register_node("fake_fire:fake_fire", { + description = "fake_fire", + tiles = { + {name="fake_fire_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=1.5}}, + }, + paramtype = "light", + is_ground_content = true, + inventory_image = 'fake_fire.png', + wield_image = { + {name="fake_fire_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=1.5}}, + }, + drawtype = "plantlike", + light_source = 14, + drop = '', + damage_per_second = 2*0.5, + groups = {dig_immediate=3,attached_node=1}, + paramtype = "light", + walkable = false, + sounds = minetest.sound_play("fire_small", {pos=cp, loop=true}), + on_punch = function (pos,node,puncher) + minetest.sound_play("fire_extinguish", + {pos = pos, gain = 1.0, max_hear_distance = 20,}) +end +}) + minetest.register_craftitem("fake_fire:old_flint_and_steel", { + description = "Never ending flint and steel", + inventory_image = "flint_and_steel.png", + stack_max = 1, + liquids_pointable = false, + on_use = function(itemstack, user, pointed_thing) + n = minetest.env:get_node(pointed_thing) + if pointed_thing.type == "node" then + minetest.env:add_node(pointed_thing.above, {name="fake_fire:fake_fire"}) + minetest.sound_play("", + {gain = 1.0, max_hear_distance = 20,}) + end + end, +}) + +-- new code -- + +-- found then changed to my likeing from flint mod -- +local function get_nodedef_field(nodename, fieldname) + if not minetest.registered_nodes[nodename] then + return nil + end + return minetest.registered_nodes[nodename][fieldname] +end + +local function set_fake_fire(pointed_thing) + local n = minetest.env:get_node(pointed_thing.above) + if n.name ~= "" and n.name == "air" then + minetest.env:set_node(pointed_thing.above, {name="fake_fire:fake_fire"}) + end +end + +-- the flint and steel -- + +minetest.register_tool("fake_fire:flint_and_steel", { + description = "Flint and steel", + inventory_image = "flint_and_steel.png", + liquids_pointable = false, + stack_max = 1, + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=0, + groupcaps={ + flamable = {uses=65, maxlevel=1}, + } + }, + on_use = function(itemstack, user, pointed_thing) + if pointed_thing.type == "node" then + set_fake_fire(pointed_thing) + minetest.sound_play("", + {gain = 1.0, max_hear_distance = 2,}) + itemstack:add_wear(65535/65) + return itemstack + end + end, + +}) + +-- water and lava puts out fake fire -- +minetest.register_abm({ +nodenames = {"fake_fire:fake_fire"}, +interval = 1, +chance = 1, +action = function(pos, node) +if minetest.env:find_node_near(pos, 1, {"default:water_source", "default:water_flowing","default:lava_source","default:lava_flowing"}) then + minetest.sound_play("fire_extinguish", + {gain = 1.0, max_hear_distance = 20,}) +node.name = "air" +minetest.env:set_node(pos, node) +end +end, +}) + +minetest.register_craftitem("fake_fire:flint", { + description = "flint", + inventory_image = "flint.png", + stack_max = 99, + liquids_pointable = false, +}) + +minetest.register_craft({ + output = '"fake_fire:flint_and_steel" 1', + recipe = { + {"fake_fire:flint", ""}, + {"", "default:steel_ingot"}, + } +}) + +minetest.register_craft({ + output = '"fake_fire:flint" 1', + recipe = { + {"default:gravel"}, + } +}) + + +-- Thanks- + +-- Many thanks for addi for his help in coding. -- + +-- Many thanks for the players on the King Arthur's land server for giving -- +-- me support, ideas and allowing me to add the mod to the server itself. -- + diff --git a/mods/fake_fire/sounds/fire_extinguish.ogg b/mods/fake_fire/sounds/fire_extinguish.ogg new file mode 100644 index 0000000..38c56d6 Binary files /dev/null and b/mods/fake_fire/sounds/fire_extinguish.ogg differ diff --git a/mods/fake_fire/sounds/fire_ignite.ogg b/mods/fake_fire/sounds/fire_ignite.ogg new file mode 100644 index 0000000..9063eeb Binary files /dev/null and b/mods/fake_fire/sounds/fire_ignite.ogg differ diff --git a/mods/fake_fire/sounds/fire_small.ogg b/mods/fake_fire/sounds/fire_small.ogg new file mode 100644 index 0000000..5aac595 Binary files /dev/null and b/mods/fake_fire/sounds/fire_small.ogg differ diff --git a/mods/fake_fire/textures/fake_fire.png b/mods/fake_fire/textures/fake_fire.png new file mode 100644 index 0000000..a5c2afd Binary files /dev/null and b/mods/fake_fire/textures/fake_fire.png differ diff --git a/mods/fake_fire/textures/fake_fire_animated.png b/mods/fake_fire/textures/fake_fire_animated.png new file mode 100644 index 0000000..d419ae2 Binary files /dev/null and b/mods/fake_fire/textures/fake_fire_animated.png differ diff --git a/mods/fake_fire/textures/fake_fire_animated_old.png b/mods/fake_fire/textures/fake_fire_animated_old.png new file mode 100644 index 0000000..20abe23 Binary files /dev/null and b/mods/fake_fire/textures/fake_fire_animated_old.png differ diff --git a/mods/fake_fire/textures/flint.png b/mods/fake_fire/textures/flint.png new file mode 100644 index 0000000..f53881d Binary files /dev/null and b/mods/fake_fire/textures/flint.png differ diff --git a/mods/fake_fire/textures/flint_and_steel.png b/mods/fake_fire/textures/flint_and_steel.png new file mode 100644 index 0000000..1fc4f92 Binary files /dev/null and b/mods/fake_fire/textures/flint_and_steel.png differ diff --git a/mods/farming_plus/README.txt b/mods/farming_plus/README.txt new file mode 100644 index 0000000..c7c6751 --- /dev/null +++ b/mods/farming_plus/README.txt @@ -0,0 +1,23 @@ +===FARMING_PLUS MOD for MINETEST=== +by PilzAdam + +License: +Sourcecode: WTFPL (see below) +Graphics: WTFPL (see below) + +See also: +http://minetest.net/ + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/mods/farming_plus/bananas.lua b/mods/farming_plus/bananas.lua new file mode 100644 index 0000000..c5184a2 --- /dev/null +++ b/mods/farming_plus/bananas.lua @@ -0,0 +1,71 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_node("farming_plus:banana_sapling", { + description = S("Banana Tree Sapling"), + drawtype = "plantlike", + tiles = {"farming_banana_sapling.png"}, + inventory_image = "farming_banana_sapling.png", + wield_image = "farming_banana_sapling.png", + paramtype = "light", + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3} + }, + groups = {dig_immediate=3,flammable=2}, + sounds = default.node_sound_defaults(), +}) + +minetest.register_node("farming_plus:banana_leaves", { + drawtype = "allfaces_optional", + tiles = {"farming_banana_leaves.png"}, + paramtype = "light", + groups = {snappy=3, leafdecay=3, flammable=2, not_in_creative_inventory=1}, + drop = { + max_items = 1, + items = { + { + items = {'farming_plus:banana_sapling'}, + rarity = 20, + }, + } + }, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_abm({ + nodenames = {"farming_plus:banana_sapling"}, + interval = 60, + chance = 20, + action = function(pos, node) + farming.generate_tree(pos, "default:tree", "farming_plus:banana_leaves", {"default:dirt", "default:dirt_with_grass"}, {["farming_plus:banana"]=20}) + end +}) + +minetest.register_on_generated(function(minp, maxp, blockseed) + if math.random(1, 100) > 5 then + return + end + local tmp = {x=(maxp.x-minp.x)/2+minp.x, y=(maxp.y-minp.y)/2+minp.y, z=(maxp.z-minp.z)/2+minp.z} + local pos = minetest.find_node_near(tmp, maxp.x-minp.x, {"default:dirt_with_grass"}) + if pos ~= nil then + farming.generate_tree({x=pos.x, y=pos.y+1, z=pos.z}, "default:tree", "farming_plus:banana_leaves", {"default:dirt", "default:dirt_with_grass"}, {["farming_plus:banana"]=10}) + end +end) + +minetest.register_node("farming_plus:banana", { + description = S("Banana"), + tiles = {"farming_banana.png"}, + inventory_image = "farming_banana.png", + wield_image = "farming_banana.png", + drawtype = "torchlike", + paramtype = "light", + sunlight_propagates = true, + walkable = false, + groups = {fleshy=3,dig_immediate=3,flammable=2,leafdecay=3,leafdecay_drop=1}, + sounds = default.node_sound_defaults(), + + on_use = minetest.item_eat(6), +}) diff --git a/mods/farming_plus/carrots.lua b/mods/farming_plus/carrots.lua new file mode 100644 index 0000000..7f55644 --- /dev/null +++ b/mods/farming_plus/carrots.lua @@ -0,0 +1,87 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_craftitem("farming_plus:carrot_seed", { + description = S("Carrot Seeds"), + inventory_image = "farming_carrot_seed.png", + on_place = function(itemstack, placer, pointed_thing) + return farming.place_seed(itemstack, placer, pointed_thing, "farming_plus:carrot_1") + end +}) + +minetest.register_node("farming_plus:carrot_1", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_carrot_1.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+3/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:carrot_2", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_carrot_2.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+5/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:carrot_3", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_carrot_3.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+12/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:carrot", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + tiles = {"farming_carrot_4.png"}, + drop = { + max_items = 6, + items = { + { items = {'farming_plus:carrot_seed'} }, + { items = {'farming_plus:carrot_seed'}, rarity = 2}, + { items = {'farming_plus:carrot_seed'}, rarity = 5}, + { items = {'farming_plus:carrot_item'} }, + { items = {'farming_plus:carrot_item'}, rarity = 2 }, + { items = {'farming_plus:carrot_item'}, rarity = 5 } + } + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_craftitem("farming_plus:carrot_item", { + description = S("Carrot"), + inventory_image = "farming_carrot.png", + on_use = minetest.item_eat(3), +}) + +farming.add_plant("farming_plus:carrot", {"farming_plus:carrot_1", "farming_plus:carrot_2", "farming_plus:carrot_3"}, 50, 20) diff --git a/mods/farming_plus/cocoa.lua b/mods/farming_plus/cocoa.lua new file mode 100644 index 0000000..42a7705 --- /dev/null +++ b/mods/farming_plus/cocoa.lua @@ -0,0 +1,81 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_node("farming_plus:cocoa_sapling", { + description = S("Cocoa Tree Sapling"), + drawtype = "plantlike", + tiles = {"farming_cocoa_sapling.png"}, + inventory_image = "farming_cocoa_sapling.png", + wield_image = "farming_cocoa_sapling.png", + paramtype = "light", + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3} + }, + groups = {dig_immediate=3,flammable=2}, + sounds = default.node_sound_defaults(), +}) + +minetest.register_node("farming_plus:cocoa_leaves", { + drawtype = "allfaces_optional", + tiles = {"farming_banana_leaves.png"}, + paramtype = "light", + groups = {snappy=3, leafdecay=3, flammable=2, not_in_creative_inventory=1}, + drop = { + max_items = 1, + items = { + { + items = {'farming_plus:cocoa_sapling'}, + rarity = 20, + }, + } + }, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_abm({ + nodenames = {"farming_plus:cocoa_sapling"}, + interval = 60, + chance = 20, + action = function(pos, node) + farming.generate_tree(pos, "default:tree", "farming_plus:cocoa_leaves", {"default:sand", "default:desert_sand"}, {["farming_plus:cocoa"]=20}) + end +}) + +minetest.register_on_generated(function(minp, maxp, blockseed) + if math.random(1, 100) > 5 then + return + end + local tmp = {x=(maxp.x-minp.x)/2+minp.x, y=(maxp.y-minp.y)/2+minp.y, z=(maxp.z-minp.z)/2+minp.z} + local pos = minetest.find_node_near(tmp, maxp.x-minp.x, {"default:desert_sand"}) + if pos ~= nil then + farming.generate_tree({x=pos.x, y=pos.y+1, z=pos.z}, "default:tree", "farming_plus:cocoa_leaves", {"default:sand", "default:desert_sand"}, {["farming_plus:cocoa"]=20}) + end +end) + +minetest.register_node("farming_plus:cocoa", { + description = S("Cocoa"), + tiles = {"farming_cocoa.png"}, + visual_scale = 0.5, + inventory_image = "farming_cocoa.png", + wield_image = "farming_cocoa.png", + drawtype = "torchlike", + paramtype = "light", + sunlight_propagates = true, + walkable = false, + groups = {fleshy=3,dig_immediate=3,flammable=2,leafdecay=3,leafdecay_drop=1}, + sounds = default.node_sound_defaults(), +}) + +minetest.register_craftitem("farming_plus:cocoa_bean", { + description = "Cocoa Bean", + inventory_image = "farming_cocoa_bean.png", +}) + +minetest.register_craft({ + output = "farming_plus:cocoa_bean 10", + type = "shapeless", + recipe = {"farming_plus:cocoa"}, +}) diff --git a/mods/farming_plus/depends.txt b/mods/farming_plus/depends.txt new file mode 100644 index 0000000..657056a --- /dev/null +++ b/mods/farming_plus/depends.txt @@ -0,0 +1,3 @@ +default +farming +intllib? diff --git a/mods/farming_plus/init.lua b/mods/farming_plus/init.lua new file mode 100644 index 0000000..4f949e7 --- /dev/null +++ b/mods/farming_plus/init.lua @@ -0,0 +1,324 @@ +farming.registered_plants = {} + +-- Boilerplate to support localized strings if intllib mod is installed. +if (minetest.get_modpath("intllib")) then + dofile(minetest.get_modpath("intllib").."/intllib.lua") + farming.S = intllib.Getter(minetest.get_current_modname()) +else + farming.S = function ( s ) return s end +end + +function farming.add_plant(full_grown, names, interval, chance) + minetest.register_abm({ + nodenames = names, + interval = interval, + chance = chance, + action = function(pos, node) + pos.y = pos.y-1 + if minetest.get_node(pos).name ~= "farming:soil_wet" then + return + end + pos.y = pos.y+1 + if not minetest.get_node_light(pos) then + return + end + if minetest.get_node_light(pos) < 8 then + return + end + local step = nil + for i,name in ipairs(names) do + if name == node.name then + step = i + break + end + end + if step == nil then + return + end + local new_node = {name=names[step+1]} + if new_node.name == nil then + new_node.name = full_grown + end + minetest.set_node(pos, new_node) + end + }) + + table.insert(farming.registered_plants, { + full_grown = full_grown, + names = names, + interval = interval, + chance = chance, + }) +end + +function farming.generate_tree(pos, trunk, leaves, underground, replacements) + pos.y = pos.y-1 + local nodename = minetest.get_node(pos).name + local ret = true + for _,name in ipairs(underground) do + if nodename == name then + ret = false + break + end + end + pos.y = pos.y+1 + if not minetest.get_node_light(pos) then + return + end + if ret or minetest.get_node_light(pos) < 8 then + return + end + + node = {name = ""} + for dy=1,4 do + pos.y = pos.y+dy + if minetest.get_node(pos).name ~= "air" then + return + end + pos.y = pos.y-dy + end + node.name = trunk + for dy=0,4 do + pos.y = pos.y+dy + minetest.set_node(pos, node) + pos.y = pos.y-dy + end + + if not replacements then + replacements = {} + end + + node.name = leaves + pos.y = pos.y+3 + for dx=-2,2 do + for dz=-2,2 do + for dy=0,3 do + pos.x = pos.x+dx + pos.y = pos.y+dy + pos.z = pos.z+dz + + if dx == 0 and dz == 0 and dy==3 then + if minetest.get_node(pos).name == "air" and math.random(1, 5) <= 4 then + minetest.set_node(pos, node) + for name,rarity in pairs(replacements) do + if math.random(1, rarity) == 1 then + minetest.set_node(pos, {name=name}) + end + end + end + elseif dx == 0 and dz == 0 and dy==4 then + if minetest.get_node(pos).name == "air" and math.random(1, 5) <= 4 then + minetest.set_node(pos, node) + for name,rarity in pairs(replacements) do + if math.random(1, rarity) == 1 then + minetest.set_node(pos, {name=name}) + end + end + end + elseif math.abs(dx) ~= 2 and math.abs(dz) ~= 2 then + if minetest.get_node(pos).name == "air" then + minetest.set_node(pos, node) + for name,rarity in pairs(replacements) do + if math.random(1, rarity) == 1 then + minetest.set_node(pos, {name=name}) + end + end + end + else + if math.abs(dx) ~= 2 or math.abs(dz) ~= 2 then + if minetest.get_node(pos).name == "air" and math.random(1, 5) <= 4 then + minetest.set_node(pos, node) + for name,rarity in pairs(replacements) do + if math.random(1, rarity) == 1 then + minetest.set_node(pos, {name=name}) + end + end + end + end + end + + pos.x = pos.x-dx + pos.y = pos.y-dy + pos.z = pos.z-dz + end + end + end +end + +farming.seeds = { + ["farming:pumpkin_seed"]=60, + ["farming_plus:strawberry_seed"]=30, + ["farming_plus:rhubarb_seed"]=30, + ["farming_plus:potatoe_seed"]=30, + ["farming_plus:tomato_seed"]=30, + ["farming_plus:orange_seed"]=30, + ["farming_plus:carrot_seed"]=30, +} + + +-- ========= GENERATE PLANTS IN THE MAP ========= +minetest.register_on_generated(function(minp, maxp, seed) + if maxp.y >= 2 and minp.y <= 0 then + -- Generate plants (code from flowers) + local perlin1 = minetest.get_perlin(974, 3, 0.6, 100) + -- Assume X and Z lengths are equal + local divlen = 16 + local divs = (maxp.x-minp.x)/divlen+1; + for divx=0,divs-1 do + for divz=0,divs-1 do + local x0 = minp.x + math.floor((divx+0)*divlen) + local z0 = minp.z + math.floor((divz+0)*divlen) + local x1 = minp.x + math.floor((divx+1)*divlen) + local z1 = minp.z + math.floor((divz+1)*divlen) + -- Determine flowers amount from perlin noise + local grass_amount = math.floor(perlin1:get2d({x=x0, y=z0}) ^ 3 * 9) + -- Find random positions for flowers based on this random + local pr = PseudoRandom(seed+456) + for i=0,grass_amount do + local x = pr:next(x0, x1) + local z = pr:next(z0, z1) + -- Find ground level (0...15) + local ground_y = nil + for y=30,0,-1 do + if minetest.get_node({x=x,y=y,z=z}).name ~= "air" then + ground_y = y + break + end + end + + if ground_y then + local p = {x=x,y=ground_y+1,z=z} + local nn = minetest.get_node(p).name + -- Check if the node can be replaced + if minetest.registered_nodes[nn] and + minetest.registered_nodes[nn].buildable_to then + nn = minetest.get_node({x=x,y=ground_y,z=z}).name + if nn == "default:dirt_with_grass" then + --local plant_choice = pr:next(1, #farming.registered_plants) + local plant_choice = math.floor(perlin1:get2d({x=x,y=z})*(#farming.registered_plants)) + local plant = farming.registered_plants[plant_choice] + if plant then + minetest.set_node(p, {name=plant.full_grown}) + end + end + end + end + + end + end + end + end +end) + +function farming.place_seed(itemstack, placer, pointed_thing, plantname) + + -- Call on_rightclick if the pointed node defines it + if pointed_thing.type == "node" and placer and + not placer:get_player_control().sneak then + local n = minetest.get_node(pointed_thing.under) + local nn = n.name + if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then + return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n, + placer, itemstack, pointed_thing) or itemstack, false + end + end + + local pt = pointed_thing + -- check if pointing at a node + if not pt then + return + end + if pt.type ~= "node" then + return + end + + local under = minetest.get_node(pt.under) + local above = minetest.get_node(pt.above) + + -- return if any of the nodes is not registered + if not minetest.registered_nodes[under.name] then + return + end + if not minetest.registered_nodes[above.name] then + return + end + + -- check if pointing at the top of the node + if pt.above.y ~= pt.under.y+1 then + return + end + + -- check if you can replace the node above the pointed node + if not minetest.registered_nodes[above.name].buildable_to then + return + end + + -- check if pointing at soil + if minetest.get_item_group(under.name, "soil") < 2 then + return + end + + -- add the node and remove 1 item from the itemstack + minetest.add_node(pt.above, {name=plantname, param2 = 1}) + if not minetest.setting_getbool("creative_mode") then + itemstack:take_item() + end + return itemstack +end + +-- ========= ALIASES FOR FARMING MOD BY SAPIER ========= +-- potatoe -> potatoe +minetest.register_alias("farming:potatoe_node", "farming_plus:potatoe") +--minetest.register_alias("farming:potatoe", "farming:potatoe_item") cant do this +minetest.register_alias("farming:potatoe_straw", "farming_plus:potatoe") +minetest.register_alias("farming:seed_potatoe", "farming_plus:potatoe_seed") +for lvl = 1, 6, 1 do + minetest.register_entity(":farming:potatoe_lvl"..lvl, { + on_activate = function(self, staticdata) + minetest.set_node(self.object:getpos(), {name="farming_plus:potatoe_1"}) + end + }) +end + + +minetest.register_alias("farming:cotton", "farming:cotton_3") +minetest.register_alias("farming:wheat_harvested", "farming:wheat") +minetest.register_alias("farming:dough", "farming:flour") +minetest.register_abm({ + nodenames = {"farming:wheat"}, + interval = 1, + chance = 1, + action = function(pos) + minetest.set_node(pos, {name="farming:wheat_8"}) + end, +}) + +-- ========= STRAWBERRIES ========= +dofile(minetest.get_modpath("farming_plus").."/strawberries.lua") + +-- ========= RHUBARB ========= +dofile(minetest.get_modpath("farming_plus").."/rhubarb.lua") + +-- ========= POTATOES ========= +dofile(minetest.get_modpath("farming_plus").."/potatoes.lua") + +-- ========= TOMATOES ========= +dofile(minetest.get_modpath("farming_plus").."/tomatoes.lua") + +-- ========= ORANGES ========= +dofile(minetest.get_modpath("farming_plus").."/oranges.lua") + +-- ========= BANANAS ========= +dofile(minetest.get_modpath("farming_plus").."/bananas.lua") + +-- ========= CARROTS ========= +dofile(minetest.get_modpath("farming_plus").."/carrots.lua") + +-- ========= COCOA ========= +dofile(minetest.get_modpath("farming_plus").."/cocoa.lua") + +-- ========= PUMPKIN ========= +dofile(minetest.get_modpath("farming_plus").."/pumpkin.lua") + +-- ========= WEED ========= +dofile(minetest.get_modpath("farming_plus").."/weed.lua") diff --git a/mods/farming_plus/locale/de.txt b/mods/farming_plus/locale/de.txt new file mode 100644 index 0000000..8caedde --- /dev/null +++ b/mods/farming_plus/locale/de.txt @@ -0,0 +1,50 @@ +# Translation by Xanthin + +### bananas.lua ### +Banana Tree Sapling = Bananenbaumsetzling +Banana = Banane + +### carrots.lua ### +Carrot Seeds = Karottensamen +Carrot = Karotte + +### cocoa.lua ### +Cocoa Tree Sapling = Kakaobaumsetzling +Cocoa = Kakao +Cocoa Bean = Kakaobohne + +### oranges.lua ### +Orange Seeds = Orangensamen +Orange = Orange + +### potatoes.lua ### +Potato Seeds = Kartoffelsamen +Potato = Kartoffel + +### pumpkin.lua ### +Pumpkin Seed = Kuerbissamen +Pumpkin = Kuerbis +Pumpkin Face = Kuerbislaterne +Pumpkin Face With Light = Leuchtende Kuerbislaterne +Big Pumpkin = Riesen-Kuerbis +Scarecrow = Vogelscheuche +Scarecrow With Light = Leuchtende Vogelscheuche +Pumpkin Bread = Kuerbisbrot +Pumpkin Flour = Kuerbismehl + +### rhubarb.lua ### +Rhubarb Seeds = Rhabarbersamen +Rhubarb = Rhabarber + +### strawberries.lua ### +Strawberry Seeds = Erdbeersamen +Strawberry = Erdbeere + +### tomatoes.lua ### +Tomato Seeds = Tomatensamen +Tomato = Tomate + +### init.lua ### + +### weed.lua ### +Weed = Unkraut diff --git a/mods/farming_plus/locale/template.txt b/mods/farming_plus/locale/template.txt new file mode 100644 index 0000000..9926004 --- /dev/null +++ b/mods/farming_plus/locale/template.txt @@ -0,0 +1,51 @@ +# Template + +### bananas.lua ### +Banana Tree Sapling = +Banana = + +### carrots.lua ### +Carrot Seeds = +Carrot = + +### cocoa.lua ### +Cocoa Tree Sapling = +Cocoa = +Cocoa Bean = + +### oranges.lua ### +Orange Seeds = +Orange = + +### potatoes.lua ### +Potato Seeds = +Potato = + +### pumpkin.lua ### +Pumpkin Seed = +Pumpkin = +Pumpkin Face = +Pumpkin Face With Light = +Big Pumpkin = +Scarecrow = +Scarecrow With Light = +Pumpkin Bread = +Pumpkin Flour = + +### rhubarb.lua ### +Rhubarb Seeds = +Rhubarb = + +### strawberries.lua ### +Strawberry Seeds = +Strawberry = + +### tomatoes.lua ### +Tomato Seeds = +Tomato = + +### init.lua ### + +### weed.lua ### +Weed = + diff --git a/mods/farming_plus/oranges.lua b/mods/farming_plus/oranges.lua new file mode 100644 index 0000000..685ebb3 --- /dev/null +++ b/mods/farming_plus/oranges.lua @@ -0,0 +1,87 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_craftitem("farming_plus:orange_seed", { + description = S("Orange Seeds"), + inventory_image = "farming_orange_seed.png", + on_place = function(itemstack, placer, pointed_thing) + return farming.place_seed(itemstack, placer, pointed_thing, "farming_plus:orange_1") + end +}) + +minetest.register_node("farming_plus:orange_1", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_orange_1.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+3/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:orange_2", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_orange_2.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+8/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:orange_3", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_orange_3.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+14/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:orange", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + tiles = {"farming_orange_4.png"}, + drop = { + max_items = 6, + items = { + { items = {'farming_plus:orange_seed'} }, + { items = {'farming_plus:orange_seed'}, rarity = 2}, + { items = {'farming_plus:orange_seed'}, rarity = 5}, + { items = {'farming_plus:orange_item'} }, + { items = {'farming_plus:orange_item'}, rarity = 2 }, + { items = {'farming_plus:orange_item'}, rarity = 5 } + } + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_craftitem("farming_plus:orange_item", { + description = S("Orange"), + inventory_image = "farming_orange.png", + on_use = minetest.item_eat(4), +}) + +farming.add_plant("farming_plus:orange", {"farming_plus:orange_1", "farming_plus:orange_2", "farming_plus:orange_3"}, 50, 20) diff --git a/mods/farming_plus/potatoes.lua b/mods/farming_plus/potatoes.lua new file mode 100644 index 0000000..794c021 --- /dev/null +++ b/mods/farming_plus/potatoes.lua @@ -0,0 +1,77 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_craftitem("farming_plus:potato_seed", { + description = ("Potato Seeds"), + inventory_image = "farming_potato_seed.png", + on_place = function(itemstack, placer, pointed_thing) + return farming.place_seed(itemstack, placer, pointed_thing, "farming_plus:potato_1") + end +}) + +minetest.register_node("farming_plus:potato_1", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_potato_1.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+6/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:potato_2", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_potato_2.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+9/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:potato", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + tiles = {"farming_potato_3.png"}, + drop = { + max_items = 6, + items = { + { items = {'farming_plus:potato_seed'} }, + { items = {'farming_plus:potato_seed'}, rarity = 2}, + { items = {'farming_plus:potato_seed'}, rarity = 5}, + { items = {'farming_plus:potato_item'} }, + { items = {'farming_plus:potato_item'}, rarity = 2 }, + { items = {'farming_plus:potato_item'}, rarity = 5 } + } + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_craftitem("farming_plus:potato_item", { + description = S("Potato"), + inventory_image = "farming_potato.png", +}) + +farming.add_plant("farming_plus:potato", {"farming_plus:potato_1", "farming_plus:potato_2"}, 50, 20) + +minetest.register_alias("farming_plus:potatoe_item", "farming_plus:potato_item") +minetest.register_alias("farming_plus:potatoe_seed", "farming_plus:potato_seed") +minetest.register_alias("farming_plus:potatoe", "farming_plus:potato") +minetest.register_alias("farming_plus:potatoe_1", "farming_plus:potato_1") +minetest.register_alias("farming_plus:potatoe_2", "farming_plus:potato_2") + diff --git a/mods/farming_plus/pumpkin.lua b/mods/farming_plus/pumpkin.lua new file mode 100644 index 0000000..4a68b99 --- /dev/null +++ b/mods/farming_plus/pumpkin.lua @@ -0,0 +1,480 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_craftitem(":farming:pumpkin_seed", { + description = S("Pumpkin Seed"), + inventory_image = "farming_pumpkin_seed.png", + on_place = function(itemstack, placer, pointed_thing) + return farming.place_seed(itemstack, placer, pointed_thing, "farming:pumpkin_1") + end +}) + +minetest.register_node(":farming:pumpkin_1", { + paramtype = "light", + sunlight_propagates = true, + drawtype = "nodebox", + drop = "", + tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png"}, + node_box = { + type = "fixed", + fixed = { + {-0.2, -0.5, -0.2, 0.2, -0.1, 0.2} + }, + }, + selection_box = { + type = "fixed", + fixed = { + {-0.2, -0.5, -0.2, 0.2, -0.1, 0.2} + }, + }, + groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2, not_in_creative_inventory=1, plant=1}, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_node(":farming:pumpkin_2", { + paramtype = "light", + sunlight_propagates = true, + drawtype = "nodebox", + drop = "", + tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png"}, + node_box = { + type = "fixed", + fixed = { + {-0.35, -0.5, -0.35, 0.35, 0.2, 0.35} + }, + }, + selection_box = { + type = "fixed", + fixed = { + {-0.35, -0.5, -0.35, 0.35, 0.2, 0.35} + }, + }, + groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2, not_in_creative_inventory=1, plant=1}, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_node(":farming:pumpkin", { + description = S("Pumpkin"), + paramtype2 = "facedir", + tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png"}, + groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2, plant=1}, + sounds = default.node_sound_wood_defaults(), + + on_punch = function(pos, node, puncher) + local tool = puncher:get_wielded_item():get_name() + if tool and string.match(tool, "sword") then + node.name = "farming:pumpkin_face" + minetest.set_node(pos, node) + puncher:get_inventory():add_item("main", ItemStack("farming:pumpkin_seed")) + if math.random(1, 5) == 1 then + puncher:get_inventory():add_item("main", ItemStack("farming:pumpkin_seed")) + end + end + end +}) + +farming.add_plant("farming:pumpkin", {"farming:pumpkin_1", "farming:pumpkin_2"}, 80, 20) + +minetest.register_node(":farming:pumpkin_face", { + description = S("Pumpkin Face"), + paramtype2 = "facedir", + tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_face.png"}, + groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2, plant=1}, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_node(":farming:pumpkin_face_light", { + description = S("Pumpkin Face With Light"), + paramtype2 = "facedir", + light_source = LIGHT_MAX-2, + tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_face_light.png"}, + groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2}, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_craft({ + type = "shapeless", + output = "farming:pumpkin_face_light", + recipe = {"farming:pumpkin_face", "default:torch"} +}) + +-- ========= BIG PUMPKIN ========= +minetest.register_node(":farming:big_pumpkin", { + description = S("Big Pumpkin"), + paramtype2 = "facedir", + tiles = {"farming_pumpkin_big_side.png"}, + selection_box = { + type = "fixed", + fixed = { + {-1, -0.5, -1, 1, 1.5, 1} + } + }, + groups = {choppy=1, oddly_breakable_by_hand=1, flammable=2}, + sounds = default.node_sound_wood_defaults(), + + after_place_node = function(pos, placer) + for dx=-1,1 do + for dy=0,1 do + for dz=-1,1 do + pos.x = pos.x+dx + pos.y = pos.y+dy + pos.z = pos.z+dz + if dx ~= 0 or dy ~= 0 or dz ~= 0 then + if minetest.get_node(pos).name ~= "air" then + pos.x = pos.x-dx + pos.y = pos.y-dy + pos.z = pos.z-dz + minetest.remove_node(pos) + minetest.after(0.1, function(placer) + local inv = placer:get_inventory() + local index = placer:get_wield_index() + inv:set_stack("main", index, ItemStack("farming:big_pumpkin")) + end, placer) + return + end + end + pos.x = pos.x-dx + pos.y = pos.y-dy + pos.z = pos.z-dz + end + end + end + for dy=0,1 do + pos.y = pos.y+dy + pos.z = pos.z+1 + minetest.set_node(pos, {name="farming:big_pumpkin_side", param2=2}) + pos.x = pos.x-1 + minetest.set_node(pos, {name="farming:big_pumpkin_corner", param2=2}) + pos.x = pos.x+1 + pos.z = pos.z-2 + minetest.set_node(pos, {name="farming:big_pumpkin_side", param2=4}) + pos.x = pos.x+1 + minetest.set_node(pos, {name="farming:big_pumpkin_corner", param2=4}) + pos.z = pos.z+1 + minetest.set_node(pos, {name="farming:big_pumpkin_side", param2=3}) + pos.z = pos.z+1 + minetest.set_node(pos, {name="farming:big_pumpkin_corner", param2=3}) + pos.z = pos.z-1 + pos.x = pos.x-2 + minetest.set_node(pos, {name="farming:big_pumpkin_side", param2=1}) + pos.z = pos.z-1 + minetest.set_node(pos, {name="farming:big_pumpkin_corner", param2=1}) + pos.z = pos.z+1 + pos.x = pos.x+1 + pos.y = pos.y-dy + end + pos.y = pos.y+1 + minetest.set_node(pos, {name="farming:big_pumpkin_top"}) + end, + + after_destruct = function(pos, oldnode) + for dx=-1,1 do + for dy=0,1 do + for dz=-1,1 do + pos.x = pos.x+dx + pos.y = pos.y+dy + pos.z = pos.z+dz + local name = minetest.get_node(pos).name + if string.find(name, "farming:big_pumpkin") then + minetest.remove_node(pos) + end + pos.x = pos.x-dx + pos.y = pos.y-dy + pos.z = pos.z-dz + end + end + end + end +}) + +minetest.register_node(":farming:big_pumpkin_side", { + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + tiles = {"farming_pumpkin_big_top_side.png", "farming_pumpkin_big_side.png"}, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, 0, 0.5, 0.5, 0.5} + } + }, + selection_box = { + type = "fixed", + fixed = { + {0, 0, 0, 0, 0, 0} + } + }, + groups = {not_in_creative_inventory=1}, +}) +minetest.register_node(":farming:big_pumpkin_corner", { + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + tiles = {"farming_pumpkin_big_top_corner.png", "farming_pumpkin_big_side.png"}, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, 0, 0, 0.5, 0.5} + } + }, + selection_box = { + type = "fixed", + fixed = { + {0, 0, 0, 0, 0, 0} + } + }, + groups = {not_in_creative_inventory=1}, +}) + +minetest.register_node(":farming:big_pumpkin_top", { + paramtype = "light", + sunlight_propagates = true, + tiles = {"farming_pumpkin_big_top.png"}, + selection_box = { + type = "fixed", + fixed = { + {0, 0, 0, 0, 0, 0} + } + }, + groups = {not_in_creative_inventory=1}, +}) + +minetest.register_craft({ + type = "shapeless", + output = "farming:big_pumpkin", + recipe = {"bucket:bucket_water", "farming:pumpkin"}, + replacements = { + {"bucket:bucket_water", "bucket:bucket_empty"} + } +}) + +-- ========= SCARECROW ========= +local box1 = { + {-1, -8, -1, 1, 8, 1}, +} + +local box2 = { + {-1, -8, -1, 1, 8, 1}, + {-12, -8, -1, 12, -7, 1}, + {-5, -2, -5, 5, 8, 5} +} + +for j,list in ipairs(box1) do + for i,int in ipairs(list) do + list[i] = int/16 + end + box1[j] = list +end + +for j,list in ipairs(box2) do + for i,int in ipairs(list) do + list[i] = int/16 + end + box2[j] = list +end + +minetest.register_node(":farming:scarecrow", { + description = S("Scarecrow"), + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + tiles = {"farming_scarecrow_top.png", "farming_scarecrow_top.png", "farming_scarecrow_side.png", "farming_scarecrow_side.png", "farming_scarecrow_side.png", "farming_scarecrow_front.png"}, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = box2 + }, + selection_box = { + type = "fixed", + fixed = { + {-12/16, -1.5, -0.5, 12/16, 0.5, 0.5} + } + }, + groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2}, + + after_place_node = function(pos, placer) + local node = minetest.get_node(pos) + local param2 = node.param2 + pos.y = pos.y+1 + if minetest.get_node(pos).name ~= "air" then + pos.y = pos.y-1 + minetest.remove_node(pos) + minetest.after(0.1, function(placer) + local inv = placer:get_inventory() + local index = placer:get_wield_index() + inv:set_stack("main", index, ItemStack("farming:scarecrow")) + end, placer) + return + end + minetest.set_node(pos, node) + pos.y = pos.y-1 + node.name = "farming:scarecrow_bottom" + minetest.set_node(pos, node) + end, + + after_destruct = function(pos, oldnode) + pos.y = pos.y-1 + if minetest.get_node(pos).name == "farming:scarecrow_bottom" then + minetest.remove_node(pos) + end + end +}) + +minetest.register_node(":farming:scarecrow_bottom", { + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + tiles = {"default_wood.png"}, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = box1 + }, + groups = {not_in_creative_inventory=1}, + selection_box = { + type = "fixed", + fixed = { + {0, 0, 0, 0, 0, 0} + } + } +}) + +minetest.register_craft({ + output = "farming:scarecrow", + recipe = { + {"", "farming:pumpkin_face", "",}, + {"default:stick", "default:stick", "default:stick",}, + {"", "default:stick", "",} + } +}) + +minetest.register_node(":farming:scarecrow_light", { + description = S("Scarecrow With light"), + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + light_source = LIGHT_MAX-2, + tiles = {"farming_scarecrow_top.png", "farming_scarecrow_top.png", "farming_scarecrow_side.png", "farming_scarecrow_side.png", "farming_scarecrow_side.png", "farming_scarecrow_front_light.png"}, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = box2 + }, + selection_box = { + type = "fixed", + fixed = { + {-12/16, -1.5, -0.5, 12/16, 0.5, 0.5} + } + }, + groups = {choppy=2, oddly_breakable_by_hand=2, flammable=2}, + + after_place_node = function(pos, placer) + local node = minetest.get_node(pos) + local param2 = node.param2 + pos.y = pos.y+1 + if minetest.get_node(pos).name ~= "air" then + pos.y = pos.y-1 + minetest.remove_node(pos) + minetest.after(0.1, function(placer) + local inv = placer:get_inventory() + local index = placer:get_wield_index() + inv:set_stack("main", index, ItemStack("farming:scarecrow_light")) + end, placer) + return + end + minetest.set_node(pos, node) + pos.y = pos.y-1 + node.name = "farming:scarecrow_bottom" + minetest.set_node(pos, node) + end, + + after_destruct = function(pos, oldnode) + pos.y = pos.y-1 + if minetest.get_node(pos).name == "farming:scarecrow_bottom" then + minetest.remove_node(pos) + end + end +}) + +minetest.register_craft({ + output = "farming:scarecrow_light", + recipe = { + {"", "farming:pumpkin_face_light", "",}, + {"default:stick", "default:stick", "default:stick",}, + {"", "default:stick", "",} + } +}) + +--=============== +minetest.register_craftitem(":farming:pumpkin_bread", { + description = S("Pumpkin Bread"), + inventory_image = "farming_bread_pumpkin.png", + stack_max = 1, + on_use = minetest.item_eat(8) +}) + +minetest.register_craftitem(":farming:pumpkin_flour", { + description = "Pumpkin Flour", + inventory_image = "farming_cake_mix_pumpkin.png", +}) +minetest.register_alias("farming:pumpkin_cake_mix", "farming:pumpkin_flour") + +minetest.register_craft({ + output = "farming:pumpkin_flour", + type = "shapeless", + recipe = {"farming:flour", "farming:pumpkin"} +}) + +minetest.register_craft({ + type = "cooking", + output = "farming:pumpkin_bread", + recipe = "farming:pumpkin_flour", + cooktime = 10 +}) + + +-- ========= FUEL ========= +minetest.register_craft({ + type = "fuel", + recipe = "farming:pumpkin_seed", + burntime = 1 +}) + +minetest.register_craft({ + type = "fuel", + recipe = "farming:pumpkin", + burntime = 5 +}) + +minetest.register_craft({ + type = "fuel", + recipe = "farming:pumpkin_face", + burntime = 5 +}) + +minetest.register_craft({ + type = "fuel", + recipe = "farming:pumpkin_face_light", + burntime = 7 +}) + +minetest.register_craft({ + type = "fuel", + recipe = "farming:big_pumpkin", + burntime = 10 +}) + +minetest.register_craft({ + type = "fuel", + recipe = "farming:scarecrow", + burntime = 5 +}) + +minetest.register_craft({ + type = "fuel", + recipe = "farming:scarecrow_light", + burntime = 5 +}) diff --git a/mods/farming_plus/rhubarb.lua b/mods/farming_plus/rhubarb.lua new file mode 100644 index 0000000..43c5baa --- /dev/null +++ b/mods/farming_plus/rhubarb.lua @@ -0,0 +1,70 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_craftitem("farming_plus:rhubarb_seed", { + description = S("Rhubarb Seeds"), + inventory_image = "farming_rhubarb_seed.png", + on_place = function(itemstack, placer, pointed_thing) + return farming.place_seed(itemstack, placer, pointed_thing, "farming_plus:rhubarb_1") + end +}) + +minetest.register_node("farming_plus:rhubarb_1", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_rhubarb_1.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+5/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:rhubarb_2", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_rhubarb_2.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+11/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:rhubarb", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + tiles = {"farming_rhubarb_3.png"}, + drop = { + max_items = 6, + items = { + { items = {'farming_plus:rhubarb_seed'} }, + { items = {'farming_plus:rhubarb_seed'}, rarity = 2}, + { items = {'farming_plus:rhubarb_seed'}, rarity = 5}, + { items = {'farming_plus:rhubarb_item'} }, + { items = {'farming_plus:rhubarb_item'}, rarity = 2 }, + { items = {'farming_plus:rhubarb_item'}, rarity = 5 } + } + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_craftitem("farming_plus:rhubarb_item", { + description = S("Rhubarb"), + inventory_image = "farming_rhubarb.png", +}) + +farming.add_plant("farming_plus:rhubarb", {"farming_plus:rhubarb_1", "farming_plus:rhubarb_2"}, 50, 20) diff --git a/mods/farming_plus/strawberries.lua b/mods/farming_plus/strawberries.lua new file mode 100644 index 0000000..3c5ef7b --- /dev/null +++ b/mods/farming_plus/strawberries.lua @@ -0,0 +1,87 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_craftitem("farming_plus:strawberry_seed", { + description = S("Strawberry Seeds"), + inventory_image = "farming_strawberry_seed.png", + on_place = function(itemstack, placer, pointed_thing) + return farming.place_seed(itemstack, placer, pointed_thing, "farming_plus:strawberry_1") + end +}) + +minetest.register_node("farming_plus:strawberry_1", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_strawberry_1.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+9/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:strawberry_2", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_strawberry_2.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+12/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:strawberry_3", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_strawberry_3.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+14/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:strawberry", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + tiles = {"farming_strawberry_4.png"}, + drop = { + max_items = 6, + items = { + { items = {'farming_plus:strawberry_seed'} }, + { items = {'farming_plus:strawberry_seed'}, rarity = 2}, + { items = {'farming_plus:strawberry_seed'}, rarity = 5}, + { items = {'farming_plus:strawberry_item'} }, + { items = {'farming_plus:strawberry_item'}, rarity = 2 }, + { items = {'farming_plus:strawberry_item'}, rarity = 5 } + } + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_craftitem("farming_plus:strawberry_item", { + description = S("Strawberry"), + inventory_image = "farming_strawberry.png", + on_use = minetest.item_eat(2), +}) + +farming.add_plant("farming_plus:strawberry", {"farming_plus:strawberry_1", "farming_plus:strawberry_2", "farming_plus:strawberry_3"}, 50, 20) diff --git a/mods/farming_plus/textures/farming_banana.png b/mods/farming_plus/textures/farming_banana.png new file mode 100644 index 0000000..f775e14 Binary files /dev/null and b/mods/farming_plus/textures/farming_banana.png differ diff --git a/mods/farming_plus/textures/farming_banana_leaves.png b/mods/farming_plus/textures/farming_banana_leaves.png new file mode 100644 index 0000000..cf8eecb Binary files /dev/null and b/mods/farming_plus/textures/farming_banana_leaves.png differ diff --git a/mods/farming_plus/textures/farming_banana_sapling.png b/mods/farming_plus/textures/farming_banana_sapling.png new file mode 100644 index 0000000..821c64f Binary files /dev/null and b/mods/farming_plus/textures/farming_banana_sapling.png differ diff --git a/mods/farming_plus/textures/farming_bread_pumpkin.png b/mods/farming_plus/textures/farming_bread_pumpkin.png new file mode 100644 index 0000000..13a0adf Binary files /dev/null and b/mods/farming_plus/textures/farming_bread_pumpkin.png differ diff --git a/mods/farming_plus/textures/farming_cake_mix_pumpkin.png b/mods/farming_plus/textures/farming_cake_mix_pumpkin.png new file mode 100644 index 0000000..171e486 Binary files /dev/null and b/mods/farming_plus/textures/farming_cake_mix_pumpkin.png differ diff --git a/mods/farming_plus/textures/farming_carrot.png b/mods/farming_plus/textures/farming_carrot.png new file mode 100644 index 0000000..81cee6c Binary files /dev/null and b/mods/farming_plus/textures/farming_carrot.png differ diff --git a/mods/farming_plus/textures/farming_carrot_1.png b/mods/farming_plus/textures/farming_carrot_1.png new file mode 100644 index 0000000..f1596f5 Binary files /dev/null and b/mods/farming_plus/textures/farming_carrot_1.png differ diff --git a/mods/farming_plus/textures/farming_carrot_2.png b/mods/farming_plus/textures/farming_carrot_2.png new file mode 100644 index 0000000..e0a7116 Binary files /dev/null and b/mods/farming_plus/textures/farming_carrot_2.png differ diff --git a/mods/farming_plus/textures/farming_carrot_3.png b/mods/farming_plus/textures/farming_carrot_3.png new file mode 100644 index 0000000..7eb2070 Binary files /dev/null and b/mods/farming_plus/textures/farming_carrot_3.png differ diff --git a/mods/farming_plus/textures/farming_carrot_4.png b/mods/farming_plus/textures/farming_carrot_4.png new file mode 100644 index 0000000..6eca727 Binary files /dev/null and b/mods/farming_plus/textures/farming_carrot_4.png differ diff --git a/mods/farming_plus/textures/farming_carrot_seed.png b/mods/farming_plus/textures/farming_carrot_seed.png new file mode 100644 index 0000000..69bc450 Binary files /dev/null and b/mods/farming_plus/textures/farming_carrot_seed.png differ diff --git a/mods/farming_plus/textures/farming_cocoa.png b/mods/farming_plus/textures/farming_cocoa.png new file mode 100644 index 0000000..bce3db6 Binary files /dev/null and b/mods/farming_plus/textures/farming_cocoa.png differ diff --git a/mods/farming_plus/textures/farming_cocoa_bean.png b/mods/farming_plus/textures/farming_cocoa_bean.png new file mode 100644 index 0000000..4ad6b35 Binary files /dev/null and b/mods/farming_plus/textures/farming_cocoa_bean.png differ diff --git a/mods/farming_plus/textures/farming_cocoa_sapling.png b/mods/farming_plus/textures/farming_cocoa_sapling.png new file mode 100644 index 0000000..73c588f Binary files /dev/null and b/mods/farming_plus/textures/farming_cocoa_sapling.png differ diff --git a/mods/farming_plus/textures/farming_orange.png b/mods/farming_plus/textures/farming_orange.png new file mode 100644 index 0000000..4c5e045 Binary files /dev/null and b/mods/farming_plus/textures/farming_orange.png differ diff --git a/mods/farming_plus/textures/farming_orange_1.png b/mods/farming_plus/textures/farming_orange_1.png new file mode 100644 index 0000000..5a2aaa2 Binary files /dev/null and b/mods/farming_plus/textures/farming_orange_1.png differ diff --git a/mods/farming_plus/textures/farming_orange_2.png b/mods/farming_plus/textures/farming_orange_2.png new file mode 100644 index 0000000..3de4623 Binary files /dev/null and b/mods/farming_plus/textures/farming_orange_2.png differ diff --git a/mods/farming_plus/textures/farming_orange_3.png b/mods/farming_plus/textures/farming_orange_3.png new file mode 100644 index 0000000..851cd67 Binary files /dev/null and b/mods/farming_plus/textures/farming_orange_3.png differ diff --git a/mods/farming_plus/textures/farming_orange_4.png b/mods/farming_plus/textures/farming_orange_4.png new file mode 100644 index 0000000..accb7b7 Binary files /dev/null and b/mods/farming_plus/textures/farming_orange_4.png differ diff --git a/mods/farming_plus/textures/farming_orange_seed.png b/mods/farming_plus/textures/farming_orange_seed.png new file mode 100644 index 0000000..3873bad Binary files /dev/null and b/mods/farming_plus/textures/farming_orange_seed.png differ diff --git a/mods/farming_plus/textures/farming_potato.png b/mods/farming_plus/textures/farming_potato.png new file mode 100644 index 0000000..8768af8 Binary files /dev/null and b/mods/farming_plus/textures/farming_potato.png differ diff --git a/mods/farming_plus/textures/farming_potato_1.png b/mods/farming_plus/textures/farming_potato_1.png new file mode 100644 index 0000000..75a3cdf Binary files /dev/null and b/mods/farming_plus/textures/farming_potato_1.png differ diff --git a/mods/farming_plus/textures/farming_potato_2.png b/mods/farming_plus/textures/farming_potato_2.png new file mode 100644 index 0000000..8b7ccd4 Binary files /dev/null and b/mods/farming_plus/textures/farming_potato_2.png differ diff --git a/mods/farming_plus/textures/farming_potato_3.png b/mods/farming_plus/textures/farming_potato_3.png new file mode 100644 index 0000000..cc29ef3 Binary files /dev/null and b/mods/farming_plus/textures/farming_potato_3.png differ diff --git a/mods/farming_plus/textures/farming_potato_seed.png b/mods/farming_plus/textures/farming_potato_seed.png new file mode 100644 index 0000000..74e440d Binary files /dev/null and b/mods/farming_plus/textures/farming_potato_seed.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_big_side.png b/mods/farming_plus/textures/farming_pumpkin_big_side.png new file mode 100644 index 0000000..2651380 Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_big_side.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_big_top.png b/mods/farming_plus/textures/farming_pumpkin_big_top.png new file mode 100644 index 0000000..581accc Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_big_top.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_big_top_corner.png b/mods/farming_plus/textures/farming_pumpkin_big_top_corner.png new file mode 100644 index 0000000..ab1de28 Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_big_top_corner.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_big_top_side.png b/mods/farming_plus/textures/farming_pumpkin_big_top_side.png new file mode 100644 index 0000000..e2eb1a7 Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_big_top_side.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_face.png b/mods/farming_plus/textures/farming_pumpkin_face.png new file mode 100644 index 0000000..1a0b34a Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_face.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_face_light.png b/mods/farming_plus/textures/farming_pumpkin_face_light.png new file mode 100644 index 0000000..85246eb Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_face_light.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_seed.png b/mods/farming_plus/textures/farming_pumpkin_seed.png new file mode 100644 index 0000000..6933bc3 Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_seed.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_side.png b/mods/farming_plus/textures/farming_pumpkin_side.png new file mode 100644 index 0000000..2d2210e Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_side.png differ diff --git a/mods/farming_plus/textures/farming_pumpkin_top.png b/mods/farming_plus/textures/farming_pumpkin_top.png new file mode 100644 index 0000000..d3c6c11 Binary files /dev/null and b/mods/farming_plus/textures/farming_pumpkin_top.png differ diff --git a/mods/farming_plus/textures/farming_rhubarb.png b/mods/farming_plus/textures/farming_rhubarb.png new file mode 100644 index 0000000..849f61b Binary files /dev/null and b/mods/farming_plus/textures/farming_rhubarb.png differ diff --git a/mods/farming_plus/textures/farming_rhubarb_1.png b/mods/farming_plus/textures/farming_rhubarb_1.png new file mode 100644 index 0000000..706d8cf Binary files /dev/null and b/mods/farming_plus/textures/farming_rhubarb_1.png differ diff --git a/mods/farming_plus/textures/farming_rhubarb_2.png b/mods/farming_plus/textures/farming_rhubarb_2.png new file mode 100644 index 0000000..2aadf5f Binary files /dev/null and b/mods/farming_plus/textures/farming_rhubarb_2.png differ diff --git a/mods/farming_plus/textures/farming_rhubarb_3.png b/mods/farming_plus/textures/farming_rhubarb_3.png new file mode 100644 index 0000000..833f65b Binary files /dev/null and b/mods/farming_plus/textures/farming_rhubarb_3.png differ diff --git a/mods/farming_plus/textures/farming_rhubarb_seed.png b/mods/farming_plus/textures/farming_rhubarb_seed.png new file mode 100644 index 0000000..c16527d Binary files /dev/null and b/mods/farming_plus/textures/farming_rhubarb_seed.png differ diff --git a/mods/farming_plus/textures/farming_scarecrow_front.png b/mods/farming_plus/textures/farming_scarecrow_front.png new file mode 100644 index 0000000..364738f Binary files /dev/null and b/mods/farming_plus/textures/farming_scarecrow_front.png differ diff --git a/mods/farming_plus/textures/farming_scarecrow_front_light.png b/mods/farming_plus/textures/farming_scarecrow_front_light.png new file mode 100644 index 0000000..b4b3cf2 Binary files /dev/null and b/mods/farming_plus/textures/farming_scarecrow_front_light.png differ diff --git a/mods/farming_plus/textures/farming_scarecrow_side.png b/mods/farming_plus/textures/farming_scarecrow_side.png new file mode 100644 index 0000000..e22e84b Binary files /dev/null and b/mods/farming_plus/textures/farming_scarecrow_side.png differ diff --git a/mods/farming_plus/textures/farming_scarecrow_top.png b/mods/farming_plus/textures/farming_scarecrow_top.png new file mode 100644 index 0000000..3a4addc Binary files /dev/null and b/mods/farming_plus/textures/farming_scarecrow_top.png differ diff --git a/mods/farming_plus/textures/farming_strawberry.png b/mods/farming_plus/textures/farming_strawberry.png new file mode 100644 index 0000000..0a80f45 Binary files /dev/null and b/mods/farming_plus/textures/farming_strawberry.png differ diff --git a/mods/farming_plus/textures/farming_strawberry_1.png b/mods/farming_plus/textures/farming_strawberry_1.png new file mode 100644 index 0000000..ff238f6 Binary files /dev/null and b/mods/farming_plus/textures/farming_strawberry_1.png differ diff --git a/mods/farming_plus/textures/farming_strawberry_2.png b/mods/farming_plus/textures/farming_strawberry_2.png new file mode 100644 index 0000000..2912eb5 Binary files /dev/null and b/mods/farming_plus/textures/farming_strawberry_2.png differ diff --git a/mods/farming_plus/textures/farming_strawberry_3.png b/mods/farming_plus/textures/farming_strawberry_3.png new file mode 100644 index 0000000..ca77389 Binary files /dev/null and b/mods/farming_plus/textures/farming_strawberry_3.png differ diff --git a/mods/farming_plus/textures/farming_strawberry_4.png b/mods/farming_plus/textures/farming_strawberry_4.png new file mode 100644 index 0000000..12c6a49 Binary files /dev/null and b/mods/farming_plus/textures/farming_strawberry_4.png differ diff --git a/mods/farming_plus/textures/farming_strawberry_seed.png b/mods/farming_plus/textures/farming_strawberry_seed.png new file mode 100644 index 0000000..08c958d Binary files /dev/null and b/mods/farming_plus/textures/farming_strawberry_seed.png differ diff --git a/mods/farming_plus/textures/farming_tomato.png b/mods/farming_plus/textures/farming_tomato.png new file mode 100644 index 0000000..b112d48 Binary files /dev/null and b/mods/farming_plus/textures/farming_tomato.png differ diff --git a/mods/farming_plus/textures/farming_tomato_1.png b/mods/farming_plus/textures/farming_tomato_1.png new file mode 100644 index 0000000..2e7c425 Binary files /dev/null and b/mods/farming_plus/textures/farming_tomato_1.png differ diff --git a/mods/farming_plus/textures/farming_tomato_2.png b/mods/farming_plus/textures/farming_tomato_2.png new file mode 100644 index 0000000..6f6a451 Binary files /dev/null and b/mods/farming_plus/textures/farming_tomato_2.png differ diff --git a/mods/farming_plus/textures/farming_tomato_3.png b/mods/farming_plus/textures/farming_tomato_3.png new file mode 100644 index 0000000..e01b60b Binary files /dev/null and b/mods/farming_plus/textures/farming_tomato_3.png differ diff --git a/mods/farming_plus/textures/farming_tomato_4.png b/mods/farming_plus/textures/farming_tomato_4.png new file mode 100644 index 0000000..e2f5db4 Binary files /dev/null and b/mods/farming_plus/textures/farming_tomato_4.png differ diff --git a/mods/farming_plus/textures/farming_tomato_seed.png b/mods/farming_plus/textures/farming_tomato_seed.png new file mode 100644 index 0000000..dbef76e Binary files /dev/null and b/mods/farming_plus/textures/farming_tomato_seed.png differ diff --git a/mods/farming_plus/textures/farming_weed.png b/mods/farming_plus/textures/farming_weed.png new file mode 100644 index 0000000..4667287 Binary files /dev/null and b/mods/farming_plus/textures/farming_weed.png differ diff --git a/mods/farming_plus/tomatoes.lua b/mods/farming_plus/tomatoes.lua new file mode 100644 index 0000000..5926dcf --- /dev/null +++ b/mods/farming_plus/tomatoes.lua @@ -0,0 +1,87 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_craftitem("farming_plus:tomato_seed", { + description = S("Tomato Seeds"), + inventory_image = "farming_tomato_seed.png", + on_place = function(itemstack, placer, pointed_thing) + return farming.place_seed(itemstack, placer, pointed_thing, "farming_plus:tomato_1") + end +}) + +minetest.register_node("farming_plus:tomato_1", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_tomato_1.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+5/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:tomato_2", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_tomato_2.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+8/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:tomato_3", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + drop = "", + tiles = {"farming_tomato_3.png"}, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+13/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("farming_plus:tomato", { + paramtype = "light", + walkable = false, + drawtype = "plantlike", + tiles = {"farming_tomato_4.png"}, + drop = { + max_items = 6, + items = { + { items = {'farming_plus:tomato_seed'} }, + { items = {'farming_plus:tomato_seed'}, rarity = 2}, + { items = {'farming_plus:tomato_seed'}, rarity = 5}, + { items = {'farming_plus:tomato_item'} }, + { items = {'farming_plus:tomato_item'}, rarity = 2 }, + { items = {'farming_plus:tomato_item'}, rarity = 5 } + } + }, + groups = {snappy=3, flammable=2, not_in_creative_inventory=1,plant=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_craftitem("farming_plus:tomato_item", { + description = S("Tomato"), + inventory_image = "farming_tomato.png", + on_use = minetest.item_eat(4), +}) + +farming.add_plant("farming_plus:tomato", {"farming_plus:tomato_1", "farming_plus:tomato_2", "farming_plus:tomato_3"}, 50, 20) diff --git a/mods/farming_plus/weed.lua b/mods/farming_plus/weed.lua new file mode 100644 index 0000000..b117870 --- /dev/null +++ b/mods/farming_plus/weed.lua @@ -0,0 +1,44 @@ +-- main `S` code in init.lua +local S +S = farming.S + +minetest.register_node(":farming:weed", { + description = S("Weed"), + paramtype = "light", + sunlight_propagates = true, + walkable = false, + drawtype = "plantlike", + tiles = {"farming_weed.png"}, + inventory_image = "farming_weed.png", + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+4/16, 0.5} + }, + }, + groups = {snappy=3, flammable=2,plant=1}, + sounds = default.node_sound_leaves_defaults() +}) + +minetest.register_abm({ + nodenames = {"farming:soil_wet", "farming:soil"}, + interval = 50, + chance = 10, + action = function(pos, node) + if minetest.find_node_near(pos, 4, {"farming:scarecrow", "farming:scarecrow_light"}) ~= nil then + return + end + pos.y = pos.y+1 + if minetest.get_node(pos).name == "air" then + node.name = "farming:weed" + minetest.set_node(pos, node) + end + end +}) + +-- ========= FUEL ========= +minetest.register_craft({ + type = "fuel", + recipe = "farming:weed", + burntime = 1 +}) diff --git a/mods/fertiliser/LICENSE b/mods/fertiliser/LICENSE new file mode 100644 index 0000000..e06d208 --- /dev/null +++ b/mods/fertiliser/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/mods/fertiliser/README.md b/mods/fertiliser/README.md new file mode 100644 index 0000000..807f58d --- /dev/null +++ b/mods/fertiliser/README.md @@ -0,0 +1,4 @@ +minetest-fertiliser +=================== + +Fertiliser mod for minetest diff --git a/mods/fertiliser/depends.txt b/mods/fertiliser/depends.txt new file mode 100644 index 0000000..dd6b842 --- /dev/null +++ b/mods/fertiliser/depends.txt @@ -0,0 +1,4 @@ +default + +farming +farming_plus \ No newline at end of file diff --git a/mods/fertiliser/init.lua b/mods/fertiliser/init.lua new file mode 100644 index 0000000..717aeaa --- /dev/null +++ b/mods/fertiliser/init.lua @@ -0,0 +1,199 @@ +fertiliser = {} +fertiliser.grows = { + stdtree = function(pos, def) + if farming~=nil and farming.generate_tree~=nil then + farming:generate_tree(pos, def[4][1], def[4][2], def[4][3], def[4][4]) + end + end, + jungletree = function(pos, def) +-- farming:generate_tree(pos, def[4][1], def[4][2], def[4][3], def[4][4]) + local nu = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name + local is_soil = minetest.get_item_group(nu, "soil") + if is_soil == 0 then + return + end + + print("[fertiliser] spawned "..node.name.." tree") + local vm = minetest.get_voxel_manip() + local minp, maxp = vm:read_from_map({x=pos.x-16, y=pos.y, z=pos.z-16}, {x=pos.x+16, y=pos.y+16, z=pos.z+16}) + local a = VoxelArea:new{MinEdge=minp, MaxEdge=maxp} + local data = vm:get_data() + default.grow_jungletree(data, a, pos, math.random(1,100000)) + vm:set_data(data) + vm:write_to_map(data) + vm:update_map() + end, + moretrees = function(pos, def) + local node = minetest.get_node(pos) + print("[fertiliser] spawned "..node.name.." tree") + plantslib.growing[def[1]](pos, node, nil, nil) + end, + clone = function(pos, def) + local node = minetest.get_node(pos) + + while minetest.get_node(pos).name == node.name do + pos.y = pos.y + 1 + end + + if minetest.get_node(pos).name=="air" then + minetest.set_node(pos, node) + return true + end + return false + end, +} +fertiliser.saplings = { + { + "default:sapling", -- name + 5, -- chance + fertiliser.grows.stdtree, + { + "default:tree", + "default:leaves", + {"default:dirt", "default:dirt_with_grass"}, + {}, + }, + }, + { + "default:junglesapling", -- name + 5, -- chance + fertiliser.grows.jungletree, + { + "default:tree", + "default:leaves", + {"default:dirt", "default:dirt_with_grass"}, + {}, + }, + }, + { + "farming_plus:banana_sapling", + 5, + fertiliser.grows.stdtree, + { + "default:tree", + "farming_plus:banana_leaves", + {"default:dirt", "default:dirt_with_grass"}, + {["farming_plus:banana"]=20}, + }, + }, + { + "farming_plus:cocoa_sapling", + 5, + fertiliser.grows.stdtree, + { + "default:tree", + "farming_plus:cocoa_leaves", + {"default:sand", "default:desert_sand"}, + {["farming_plus:cocoa"]=20}, + }, + }, + { + "default:cactus", + 1, + fertiliser.grows.clone, + }, + { + "default:papyrus", + 1, + fertiliser.grows.clone, + }, +} + +minetest.after(0, function() + + local register = function(val) + for i = 1, #val.names do + local name = val.names[i] + fertiliser.saplings[#fertiliser.saplings + 1] = { + name, + 1, + function(pos, def) + minetest.set_node(pos, {name = (val.names[i+1] or val.full_grown)}) + end, + } + end + end + + if farming.registered_plants~=nil then + for _, val in ipairs(farming.registered_plants) do + register(val) + end + end + + local names = {"farming:wheat_1", + "farming:wheat_2", + "farming:wheat_3", + "farming:wheat_4", + "farming:wheat_5", + "farming:wheat_6", + "farming:wheat_7"} + + register( { + full_grown = "farming:wheat_8", + names = names + }) + + names = { "farming:cotton_1", + "farming:cotton_2", + "farming:cotton_3", + "farming:cotton_4", + "farming:cotton_5", + "farming:cotton_6", + "farming:cotton_7"} + + register( { + full_grown = "farming:cotton_8", + names = names + }) +end) + +minetest.register_craftitem("fertiliser:fertiliser", { + description = "Fertiliser", + inventory_image = "fertiliser_fertiliser.png", + on_use = function(itemstack, user, pointed_thing) + if pointed_thing.type=="node" then + local pos = pointed_thing.under + local node = minetest.get_node(pos) + for i=1, #fertiliser.saplings do + local def = fertiliser.saplings[i] + if node.name==def[1] then + local res + if math.random(def[2])==1 then + res = def[3](pos, def) + end + if res~=false then itemstack:take_item() end + end + end + end + return itemstack + end, +}) + +minetest.register_craft({ + output = 'fertiliser:fertiliser 9', + recipe = { + {'default:dirt', 'default:dirt', 'default:dirt'}, + {'default:dirt', 'bones:single_bone', 'default:dirt'}, + {'default:dirt', 'default:dirt', 'default:dirt'}, + }, +}) + +minetest.register_craft({ + output = 'bones:bones', + recipe = { + {'bones:single_bone', 'bones:single_bone', 'bones:single_bone'}, + {'bones:single_bone', 'bones:single_bone', 'bones:single_bone'}, + {'bones:single_bone', 'bones:single_bone', 'bones:single_bone'}, + }, +}) + +minetest.register_craft({ + type = 'shapeless', + output = 'bones:single_bone 9', + recipe = {'bones:bones'}, +}) + +minetest.register_craftitem(":bones:single_bone", { + description = "Single Bone", + inventory_image = "fertiliser_bone.png", +}) diff --git a/mods/fertiliser/textures/.directory b/mods/fertiliser/textures/.directory new file mode 100644 index 0000000..a8fa508 --- /dev/null +++ b/mods/fertiliser/textures/.directory @@ -0,0 +1,4 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2014,7,26,16,14,12 +Version=3 diff --git a/mods/fertiliser/textures/fertiliser_bone.png b/mods/fertiliser/textures/fertiliser_bone.png new file mode 100644 index 0000000..3d73f35 Binary files /dev/null and b/mods/fertiliser/textures/fertiliser_bone.png differ diff --git a/mods/fertiliser/textures/fertiliser_fertiliser.png b/mods/fertiliser/textures/fertiliser_fertiliser.png new file mode 100644 index 0000000..c278899 Binary files /dev/null and b/mods/fertiliser/textures/fertiliser_fertiliser.png differ diff --git a/mods/gate/README.txt b/mods/gate/README.txt new file mode 100644 index 0000000..bf63a19 --- /dev/null +++ b/mods/gate/README.txt @@ -0,0 +1,28 @@ +Minetest mod "Simple Fencegate" +=============================== +by BlockMen (c) 2014 + +Version: 1.0 + +About +~~~~~ +This mod adds a fence gate to Minetest, perserving the fence style of Minetest. +Also it makes jumping over fence impossible and fixes the collision box (not like a full block anymore). + +You can place the fence gates ONLY between to fence posts. + +Crafting: + +stick wood stick +stick wood stick + + + + +License of source code, textures: WTFPL + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. diff --git a/mods/gate/depends.txt b/mods/gate/depends.txt new file mode 100644 index 0000000..331d858 --- /dev/null +++ b/mods/gate/depends.txt @@ -0,0 +1 @@ +default \ No newline at end of file diff --git a/mods/gate/init.lua b/mods/gate/init.lua new file mode 100644 index 0000000..42a50f9 --- /dev/null +++ b/mods/gate/init.lua @@ -0,0 +1,130 @@ +local nb_gap = { + {-1, 0.1875, -0.0625, -0.5, 0.3125, 0.0625}, + {-1, -0.1875, -0.0625, -0.5, -0.3125, 0.0625}, + {0.5, 0.1875, -0.0625, 1, 0.3125, 0.0625}, + {0.5, -0.1875, -0.0625, 1, -0.3125, 0.0625} + } + +local nb_pil = { + {0.5, -0.5, -0.09375, 0.5625, 0.5, 0.09375}, + {-0.5625, -0.5, -0.09375, -0.5, 0.5, 0.09375}, + {-0.5, -0.3125, -0.0625, -0.375, 0.3125, 0.0625}, + {0.375, -0.3125, -0.0625, 0.5, 0.3125, 0.0625} + } + +local function can_place(pos, n0) + if not n0 or n0.name ~= "gate:fencegate" then + return + end + local p1 = {x = pos.x, y = pos.y, z = pos.z} + local p2 = {x = pos.x, y = pos.y, z = pos.z} + if n0.param2 == 1 or n0.param2 == 3 then + p1.z = p1.z - 1 + p2.z = p2.z + 1 + else + p1.x = p1.x - 1 + p2.x = p2.x + 1 + end + local n1 = minetest.get_node_or_nil(p1) + local n2 = minetest.get_node_or_nil(p2) + + if n1 and n1.name == "default:fence_wood" and n2 and + n2.name == "default:fence_wood" then + return false + end + minetest.remove_node(pos) + return true +end + +local function gate_rightclick(pos, node) + if node.name == "gate:fencegate" then + minetest.sound_play("door_open", {gain = 0.3, max_hear_distance = 10}) + minetest.set_node(pos, {name="gate:fencegate_open", param2=node.param2}) + else + minetest.sound_play("door_close", {gain = 0.3, max_hear_distance = 10}) + minetest.set_node(pos, {name="gate:fencegate", param2=node.param2}) + end +end + +local wood_rotated = "default_wood.png^[transformR90" + +minetest.register_node("gate:fencegate_open", { + tiles = {"default_wood.png", "default_wood.png", wood_rotated, + wood_rotated, wood_rotated, wood_rotated}, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + walkable = true, + groups = {snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 2, not_in_inventory = 1}, + drop = 'gate:fencegate', + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.3125, 0.4375, -0.375, 0.3125, 0.5}, + {0.375, -0.3125, 0.4375, 0.5, 0.3125, 0.5}, + {-0.5, 0.1875, 0.0625, -0.375, 0.3125, 0.4375}, + {-0.5, -0.1875, 0.0625, -0.375, -0.3125, 0.4375}, + {0.375, 0.1875, 0.0625, 0.5, 0.3125, 0.4375}, + {0.375, -0.1875, 0.0625, 0.5, -0.3125, 0.4375}, + nb_pil[1], nb_pil[2], + nb_pil[3], nb_pil[4], + nb_gap[1], nb_gap[2], + nb_gap[3], nb_gap[4], + } + }, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.3125, -0.0625, -0.375, 0.3125, 0.5}, + {0.375, -0.3125, -0.0625, 0.5, 0.3125, 0.5}, + } + }, + on_rightclick = gate_rightclick, +}) + +minetest.register_node("gate:fencegate", { + description = "Wooden fence gate", + tiles = {"default_wood.png", "default_wood.png", wood_rotated, + wood_rotated, wood_rotated, wood_rotated}, + inventory_image = "gate_fencegate.png", + wield_image = "gate_fencegate.png", + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + walkable = true, + groups = {snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 2}, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + nb_pil[1], nb_pil[2], + nb_pil[3], nb_pil[4], + {-0.0625, -0.3125, -0.0625, 0.0625, 0.3125, 0.0625}, + {-1, 0.1875, -0.0625, 1, 0.3125, 0.0625}, + {-1, -0.1875, -0.0625, 1, -0.3125, 0.0625}, + } + }, + selection_box = { + type = "fixed", + fixed = {{-0.5, -0.3125, -0.0625, 0.5, 0.3125, 0.0625}} + }, + on_rightclick = gate_rightclick, +}) + +minetest.override_item("default:fence_wood", {node_box = { + type = "fixed", + fixed = { + {-0.2, -0.5, -0.2, 0.2, 1.0, 0.2}, + }, + }}) + + -- minetest.register_on_placenode(can_place) + +minetest.register_craft({ + output = 'gate:fencegate', + recipe = { + {'default:stick', 'group:wood', 'default:stick'}, + {'default:stick', 'group:wood', 'default:stick'}, + } +}) diff --git a/mods/gate/textures/gate_fencegate.png b/mods/gate/textures/gate_fencegate.png new file mode 100644 index 0000000..2e62a5b Binary files /dev/null and b/mods/gate/textures/gate_fencegate.png differ diff --git a/mods/itemframes/depends.txt b/mods/itemframes/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/mods/itemframes/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/itemframes/init.lua b/mods/itemframes/init.lua new file mode 100644 index 0000000..f5c8ce0 --- /dev/null +++ b/mods/itemframes/init.lua @@ -0,0 +1,216 @@ +local tmp = {} + +minetest.register_entity("itemframes:item",{ + hp_max = 1, + visual="wielditem", + visual_size={x=.33,y=.33}, + collisionbox = {0,0,0,0,0,0}, + physical=false, + textures={"air"}, + on_activate = function(self, staticdata) + if tmp.nodename ~= nil and tmp.texture ~= nil then + self.nodename = tmp.nodename + tmp.nodename = nil + self.texture = tmp.texture + tmp.texture = nil + else + if staticdata ~= nil and staticdata ~= "" then + local data = staticdata:split(';') + if data and data[1] and data[2] then + self.nodename = data[1] + self.texture = data[2] + end + end + end + if self.texture ~= nil then + self.object:set_properties({textures={self.texture}}) + end + if self.nodename == "itemframes:pedestal" then + self.object:set_properties({automatic_rotate=1}) + end + end, + get_staticdata = function(self) + if self.nodename ~= nil and self.texture ~= nil then + return self.nodename .. ';' .. self.texture + end + return "" + end, +}) + + +local facedir = {} +facedir[0] = {x=0,y=0,z=1} +facedir[1] = {x=1,y=0,z=0} +facedir[2] = {x=0,y=0,z=-1} +facedir[3] = {x=-1,y=0,z=0} + +local remove_item = function(pos, node) + local objs = nil + if node.name == "itemframes:frame" then + objs = minetest.env:get_objects_inside_radius(pos, .5) + elseif node.name == "itemframes:pedestal" then + objs = minetest.env:get_objects_inside_radius({x=pos.x,y=pos.y+1,z=pos.z}, .5) + end + if objs then + for _, obj in ipairs(objs) do + if obj and obj:get_luaentity() and obj:get_luaentity().name == "itemframes:item" then + obj:remove() + end + end + end +end + +local update_item = function(pos, node) + remove_item(pos, node) + local meta = minetest.env:get_meta(pos) + if meta:get_string("item") ~= "" then + if node.name == "itemframes:frame" then + local posad = facedir[node.param2] + if not posad then return end + pos.x = pos.x + posad.x*6.5/16 + pos.y = pos.y + posad.y*6.5/16 + pos.z = pos.z + posad.z*6.5/16 + elseif node.name == "itemframes:pedestal" then + pos.y = pos.y + 12/16+.33 + end + tmp.nodename = node.name + tmp.texture = ItemStack(meta:get_string("item")):get_name() + local e = minetest.env:add_entity(pos,"itemframes:item") + if node.name == "itemframes:frame" then + local yaw = math.pi*2 - node.param2 * math.pi/2 + e:setyaw(yaw) + end + end +end + +local drop_item = function(pos, node) + local meta = minetest.env:get_meta(pos) + if meta:get_string("item") ~= "" then + if node.name == "itemframes:frame" then + minetest.env:add_item(pos, meta:get_string("item")) + elseif node.name == "itemframes:pedestal" then + minetest.env:add_item({x=pos.x,y=pos.y+1,z=pos.z}, meta:get_string("item")) + end + meta:set_string("item","") + end + remove_item(pos, node) +end + +minetest.register_node("itemframes:frame",{ + description = "Item frame", + drawtype = "nodebox", + node_box = { type = "fixed", fixed = {-0.5, -0.5, 7/16, 0.5, 0.5, 0.5} }, + selection_box = { type = "fixed", fixed = {-0.5, -0.5, 7/16, 0.5, 0.5, 0.5} }, + tiles = {"itemframes_frame.png"}, + inventory_image = "itemframes_frame.png", + wield_image = "itemframes_frame.png", + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + groups = { choppy=2,dig_immediate=2 }, + legacy_wallmounted = true, + sounds = default.node_sound_defaults(), + after_place_node = function(pos, placer, itemstack) + local meta = minetest.env:get_meta(pos) + meta:set_string("owner",placer:get_player_name()) + meta:set_string("infotext","Item frame (owned by "..placer:get_player_name()..")") + end, + on_rightclick = function(pos, node, clicker, itemstack) + if not itemstack then return end + local meta = minetest.env:get_meta(pos) + if clicker:get_player_name() == meta:get_string("owner") then + drop_item(pos,node) + local s = itemstack:take_item() + meta:set_string("item",s:to_string()) + update_item(pos,node) + end + return itemstack + end, + on_punch = function(pos,node,puncher) + local meta = minetest.env:get_meta(pos) + if puncher:get_player_name() == meta:get_string("owner") then + drop_item(pos, node) + end + end, + can_dig = function(pos,player) + + local meta = minetest.env:get_meta(pos) + return player:get_player_name() == meta:get_string("owner") + end, +}) + + +minetest.register_node("itemframes:pedestal",{ + description = "Pedestal", + drawtype = "nodebox", + node_box = { type = "fixed", fixed = { + {-7/16, -8/16, -7/16, 7/16, -7/16, 7/16}, -- bottom plate + {-6/16, -7/16, -6/16, 6/16, -6/16, 6/16}, -- bottom plate (upper) + {-0.25, -6/16, -0.25, 0.25, 11/16, 0.25}, -- pillar + {-7/16, 11/16, -7/16, 7/16, 12/16, 7/16}, -- top plate + } }, + --selection_box = { type = "fixed", fixed = {-7/16, -0.5, -7/16, 7/16, 12/16, 7/16} }, + tiles = {"itemframes_pedestal.png"}, + paramtype = "light", + groups = { cracky=3 }, + sounds = default.node_sound_defaults(), + after_place_node = function(pos, placer, itemstack) + local meta = minetest.env:get_meta(pos) + meta:set_string("owner",placer:get_player_name()) + meta:set_string("infotext","Pedestal (owned by "..placer:get_player_name()..")") + end, + on_rightclick = function(pos, node, clicker, itemstack) + if not itemstack then return end + local meta = minetest.env:get_meta(pos) + if clicker:get_player_name() == meta:get_string("owner") then + drop_item(pos,node) + local s = itemstack:take_item() + meta:set_string("item",s:to_string()) + update_item(pos,node) + end + return itemstack + end, + on_punch = function(pos,node,puncher) + local meta = minetest.env:get_meta(pos) + if puncher:get_player_name() == meta:get_string("owner") then + drop_item(pos,node) + end + end, + can_dig = function(pos,player) + + local meta = minetest.env:get_meta(pos) + return player:get_player_name() == meta:get_string("owner") + end, +}) + +-- automatically restore entities lost from frames/pedestals +-- due to /clearobjects or similar + +minetest.register_abm({ + nodenames = { "itemframes:frame", "itemframes:pedestal" }, + interval = 15, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + if #minetest.get_objects_inside_radius(pos, 0.5) > 0 then return end + update_item(pos, node) + end +}) + +-- crafts + +minetest.register_craft({ + output = 'itemframes:frame', + recipe = { + {'default:stick', 'default:stick', 'default:stick'}, + {'default:stick', 'default:paper', 'default:stick'}, + {'default:stick', 'default:stick', 'default:stick'}, + } +}) +minetest.register_craft({ + output = 'itemframes:pedestal', + recipe = { + {'default:stone', 'default:stone', 'default:stone'}, + {'', 'default:stone', ''}, + {'default:stone', 'default:stone', 'default:stone'}, + } +}) diff --git a/mods/itemframes/textures/itemframes_frame.png b/mods/itemframes/textures/itemframes_frame.png new file mode 100644 index 0000000..b364875 Binary files /dev/null and b/mods/itemframes/textures/itemframes_frame.png differ diff --git a/mods/itemframes/textures/itemframes_pedestal.png b/mods/itemframes/textures/itemframes_pedestal.png new file mode 100644 index 0000000..e39abd3 Binary files /dev/null and b/mods/itemframes/textures/itemframes_pedestal.png differ diff --git a/mods/mapfix/depends.txt b/mods/mapfix/depends.txt new file mode 100644 index 0000000..e69de29 diff --git a/mods/mapfix/init.lua b/mods/mapfix/init.lua new file mode 100644 index 0000000..77ce155 --- /dev/null +++ b/mods/mapfix/init.lua @@ -0,0 +1,19 @@ +minetest.register_chatcommand("mapfix", { + params = "", + description = "Recalculate the flowing liquids of a chunk", + func = function(name, param) + local pos = minetest.get_player_by_name(name):getpos() + local size = tonumber(param) or 40 + if size > 50 and not minetest.check_player_privs(name, {server=true}) then + return false, "You need the server privilege to exceed the radius of 50 blocks" + end + local minp, maxp = {x = math.floor(pos.x - size), y = math.floor(pos.y - size), z = math.floor(pos.z - size)}, {x = math.ceil(pos.x + size), y = math.ceil(pos.y + size), z = math.ceil(pos.z + size)} + local vm = minetest.get_voxel_manip() + vm:read_from_map(minp, maxp) + vm:calc_lighting() + vm:update_liquids() + vm:write_to_map() + vm:update_map() + return true, "Done." + end, +}) diff --git a/mods/minetest-mod-mesecons/LICENSE.txt b/mods/minetest-mod-mesecons/LICENSE.txt new file mode 100644 index 0000000..0d2fd18 --- /dev/null +++ b/mods/minetest-mod-mesecons/LICENSE.txt @@ -0,0 +1,532 @@ +The LGPLv3 applies to all code in this project. +The CC-BY-SA-3.0 license applies to textures and any other content in this project which is not source code. + +================================================================= + +GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + 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. + +================================================================= + +Creative Commons Legal Code + +Attribution-ShareAlike 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined below) for the purposes of this + License. + c. "Creative Commons Compatible License" means a license that is listed + at http://creativecommons.org/compatiblelicenses that has been + approved by Creative Commons as being essentially equivalent to this + License, including, at a minimum, because that license: (i) contains + terms that have the same purpose, meaning and effect as the License + Elements of this License; and, (ii) explicitly permits the relicensing + of adaptations of works made available under that license under this + License or a Creative Commons jurisdiction license with the same + License Elements as this License. + d. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + e. "License Elements" means the following high-level license attributes + as selected by Licensor and indicated in the title of this License: + Attribution, ShareAlike. + f. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + g. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + h. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + i. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + j. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + k. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(c), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(c), as requested. + b. You may Distribute or Publicly Perform an Adaptation only under the + terms of: (i) this License; (ii) a later version of this License with + the same License Elements as this License; (iii) a Creative Commons + jurisdiction license (either this or a later license version) that + contains the same License Elements as this License (e.g., + Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible + License. If you license the Adaptation under one of the licenses + mentioned in (iv), you must comply with the terms of that license. If + you license the Adaptation under the terms of any of the licenses + mentioned in (i), (ii) or (iii) (the "Applicable License"), you must + comply with the terms of the Applicable License generally and the + following provisions: (I) You must include a copy of, or the URI for, + the Applicable License with every copy of each Adaptation You + Distribute or Publicly Perform; (II) You may not offer or impose any + terms on the Adaptation that restrict the terms of the Applicable + License or the ability of the recipient of the Adaptation to exercise + the rights granted to that recipient under the terms of the Applicable + License; (III) You must keep intact all notices that refer to the + Applicable License and to the disclaimer of warranties with every copy + of the Work as included in the Adaptation You Distribute or Publicly + Perform; (IV) when You Distribute or Publicly Perform the Adaptation, + You may not impose any effective technological measures on the + Adaptation that restrict the ability of a recipient of the Adaptation + from You to exercise the rights granted to that recipient under the + terms of the Applicable License. This Section 4(b) applies to the + Adaptation as incorporated in a Collection, but this does not require + the Collection apart from the Adaptation itself to be made subject to + the terms of the Applicable License. + c. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Ssection 3(b), in the case of an + Adaptation, a credit identifying the use of the Work in the Adaptation + (e.g., "French translation of the Work by Original Author," or + "Screenplay based on original Work by Original Author"). The credit + required by this Section 4(c) may be implemented in any reasonable + manner; provided, however, that in the case of a Adaptation or + Collection, at a minimum such credit will appear, if a credit for all + contributing authors of the Adaptation or Collection appears, then as + part of these credits and in a manner at least as prominent as the + credits for the other contributing authors. For the avoidance of + doubt, You may only use the credit required by this Section for the + purpose of attribution in the manner set out above and, by exercising + Your rights under this License, You may not implicitly or explicitly + assert or imply any connection with, sponsorship or endorsement by the + Original Author, Licensor and/or Attribution Parties, as appropriate, + of You or Your use of the Work, without the separate, express prior + written permission of the Original Author, Licensor and/or Attribution + Parties. + d. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of the License. + + Creative Commons may be contacted at http://creativecommons.org/. diff --git a/mods/minetest-mod-mesecons/README.md b/mods/minetest-mod-mesecons/README.md new file mode 100644 index 0000000..5de72c7 --- /dev/null +++ b/mods/minetest-mod-mesecons/README.md @@ -0,0 +1,78 @@ + ######################################################################## + ## __ __ _____ _____ _____ _____ _____ _ _ _____ ## + ## | \ / | | ___| | ___| | ___| | ___| | _ | | \ | | | ___| ## + ## | \/ | | |___ | |___ | |___ | | | | | | | \| | | |___ ## + ## | |\__/| | | ___| |___ | | ___| | | | | | | | | |___ | ## + ## | | | | | |___ ___| | | |___ | |___ | |_| | | |\ | ___| | ## + ## |_| |_| |_____| |_____| |_____| |_____| |_____| |_| \_| |_____| ## + ## ## + ######################################################################## + +MESECONS by Jeija and contributors + +Mezzee-what? +------------ +[Mesecons](http://mesecons.net/)! They're yellow, they're conductive, and they'll add a whole new dimension to Minetest's gameplay. + +Mesecons is a mod for [Minetest](http://minetest.net/) that implements a ton of items related to digital circuitry, such as wires, buttons, lights, and even programmable controllers. Among other things, there are also pistons, solar panels, pressure plates, and note blocks. + +Mesecons has a similar goal to Redstone in Minecraft, but works in its own way, with different rules and mechanics. + +OK, I want in. +-------------- +Go get it! + +[DOWNLOADS PAGE](http://mesecons.net/downloads.php) + +Now go ahead and install it like any other Minetest mod. Don't know how? Check out [the wonderful page about it](http://wiki.minetest.com/wiki/Mods) over at the Minetest Wiki. For your convenience, here's a quick summary: + +1. If Mesecons is still in a ZIP file, extract the folder inside to somewhere on the computer. +2. Make sure that when you open the folder, you can directly find `README.md` in the listing. If you just see another folder, move that folder up one level and delete the old one. +3. Open up the Minetest mods folder - usually `/mods/`. If you see the `minetest` or folder inside of that, that is your mod folder instead. +4. Copy the Mesecons folder into the mods folder. + +Don't like some parts of Mesecons? Open up the Mesecons folder and delete the subfolder containing the mod you don't want. If you didn't want movestones, for example, all you have to do is delete the `mesecons_movestones` folder and they will no longer be available. + +There are no dependencies - it will work right after installing! + +How do I use this thing? +------------------------ +How about a [quick overview video](https://www.youtube.com/watch?v=6kmeQj6iW5k)? + +Or maybe a [comprehensive reference](http://mesecons.net/items.php) is your style? + +An overview for the very newest of new beginners? How does [this one](http://uberi.mesecons.net/projects/MeseconsBasics/index.html) look? + +Want to get more into building? Why not check out the [Mesecons Laboratory](http://uberi.mesecons.net/), a website dedicated to advanced Mesecons builders? + +Want to contribute to Mesecons itself? Check out the [source code](https://github.com/Jeija/minetest-mod-mesecons)! + +Who wrote it anyways? +--------------------- +These awesome people made Mesecons possible! + +| Contributor | Contribution | +| --------------- | -------------------------------- | +| Jat15 | Various tweaks. | +| Jeija | **Main developer! Everything.** | +| Jordach | Noteblock sounds. | +| khonkhortistan | Code, recipes, textures. | +| Kotolegokot | Nodeboxes for items. | +| minerd247 | Textures. | +| Nore/Novatux | Code. | +| RealBadAngel | Fixes, improvements. | +| sfan5 | Code, recipes, textures. | +| suzenako | Piston sounds. | +| Uberi/Temperest | Code, textures, documentation. | +| VanessaE | Code, recipes, textures, design. | +| Whiskers75 | Logic gates implementation. | + +There are also a whole bunch of other people helping with everything from code to testing and feedback. Mesecons would also not be possible without their help! + +Alright, how can I use it? +-------------------------- +All textures in this project are licensed under the CC-BY-SA 3.0 (Creative Commons Attribution-ShareAlike 3.0 Generic). That means you can distribute and remix them as much as you want to, under the condition that you give credit to the authors and the project, and that if you remix and release them, they must be under the same or similar license to this one. + +All code in this project is licensed under the LGPL version 3 or later. That means you have unlimited freedom to distribute and modify the work however you see fit, provided that if you decide to distribute it or any modified versions of it, you must also use the same license. The LGPL also grants the additional freedom to write extensions for the software and distribute them without the extensions being subject to the terms of the LGPL, although the software itself retains its license. + +No warranty is provided, express or implied, for any part of the project. diff --git a/mods/minetest-mod-mesecons/mesecons/VERSION b/mods/minetest-mod-mesecons/mesecons/VERSION new file mode 100644 index 0000000..75b9e03 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/VERSION @@ -0,0 +1 @@ +0.41 DEV diff --git a/mods/minetest-mod-mesecons/mesecons/actionqueue.lua b/mods/minetest-mod-mesecons/mesecons/actionqueue.lua new file mode 100644 index 0000000..fa4079f --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/actionqueue.lua @@ -0,0 +1,118 @@ +mesecon.queue.actions={} -- contains all ActionQueue actions + +function mesecon.queue:add_function(name, func) + mesecon.queue.funcs[name] = func +end + +-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten +-- use overwritecheck nil to never overwrite, but just add the event to the queue +-- priority specifies the order actions are executed within one globalstep, highest first +-- should be between 0 and 1 +function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority) + -- Create Action Table: + time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution + priority = priority or 1 + local action = { pos=mesecon.tablecopy(pos), + func=func, + params=mesecon.tablecopy(params or {}), + time=time, + owcheck=(overwritecheck and mesecon.tablecopy(overwritecheck)) or nil, + priority=priority} + + local toremove = nil + -- Otherwise, add the action to the queue + if overwritecheck then -- check if old action has to be overwritten / removed: + for i, ac in ipairs(mesecon.queue.actions) do + if(mesecon.cmpPos(pos, ac.pos) + and mesecon.cmpAny(overwritecheck, ac.owcheck)) then + toremove = i + break + end + end + end + + if (toremove ~= nil) then + table.remove(mesecon.queue.actions, toremove) + end + + table.insert(mesecon.queue.actions, action) +end + +-- execute the stored functions on a globalstep +-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function +-- this makes sure that resuming mesecons circuits when restarting minetest works fine +-- However, even that does not work in some cases, that's why we delay the time the globalsteps +-- start to be execute by 5 seconds +local get_highest_priority = function (actions) + local highestp = -1 + local highesti + for i, ac in ipairs(actions) do + if ac.priority > highestp then + highestp = ac.priority + highesti = i + end + end + + return highesti +end + +local m_time = 0 +local resumetime = mesecon.setting("resumetime", 4) +minetest.register_globalstep(function (dtime) + m_time = m_time + dtime + -- don't even try if server has not been running for XY seconds; resumetime = time to wait + -- after starting the server before processing the ActionQueue, don't set this too low + if (m_time < resumetime) then return end + local actions = mesecon.tablecopy(mesecon.queue.actions) + local actions_now={} + + mesecon.queue.actions = {} + + -- sort actions into two categories: + -- those toexecute now (actions_now) and those to execute later (mesecon.queue.actions) + for i, ac in ipairs(actions) do + if ac.time > 0 then + ac.time = ac.time - dtime -- executed later + table.insert(mesecon.queue.actions, ac) + else + table.insert(actions_now, ac) + end + end + + while(#actions_now > 0) do -- execute highest priorities first, until all are executed + local hp = get_highest_priority(actions_now) + mesecon.queue:execute(actions_now[hp]) + table.remove(actions_now, hp) + end +end) + +function mesecon.queue:execute(action) + mesecon.queue.funcs[action.func](action.pos, unpack(action.params)) +end + + +-- Store and read the ActionQueue to / from a file +-- so that upcoming actions are remembered when the game +-- is restarted + +local wpath = minetest.get_worldpath() +local function file2table(filename) + local f = io.open(filename, "r") + if f==nil then return {} end + local t = f:read("*all") + f:close() + if t=="" or t==nil then return {} end + return minetest.deserialize(t) +end + +local function table2file(filename, table) + local f = io.open(filename, "w") + f:write(minetest.serialize(table)) + f:close() +end + +mesecon.queue.actions = file2table(wpath.."/mesecon_actionqueue") + +minetest.register_on_shutdown(function() + mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions) +end) diff --git a/mods/minetest-mod-mesecons/mesecons/depends.txt b/mods/minetest-mod-mesecons/mesecons/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/minetest-mod-mesecons/mesecons/init.lua b/mods/minetest-mod-mesecons/mesecons/init.lua new file mode 100644 index 0000000..096e509 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/init.lua @@ -0,0 +1,139 @@ +-- |\ /| ____ ____ ____ _____ ____ _____ +-- | \ / | | | | | | | |\ | | +-- | \/ | |___ ____ |___ | | | | \ | |____ +-- | | | | | | | | | \ | | +-- | | |___ ____| |___ |____ |____| | \| ____| +-- by Jeija, Uberi (Temperest), sfan5, VanessaE +-- +-- +-- +-- This mod adds mesecons[=minecraft redstone] and different receptors/effectors to minetest. +-- See the documentation on the forum for additional information, especially about crafting +-- +-- +-- For developer documentation see the Developers' section on mesecons.TK +-- +-- +-- +--Quick draft for the mesecons array in the node's definition +--mesecons = +--{ +-- receptor = +-- { +-- state = mesecon.state.on/off +-- rules = rules/get_rules +-- }, +-- effector = +-- { +-- action_on = function +-- action_off = function +-- action_change = function +-- rules = rules/get_rules +-- }, +-- conductor = +-- { +-- state = mesecon.state.on/off +-- offstate = opposite state (for state = on only) +-- onstate = opposite state (for state = off only) +-- rules = rules/get_rules +-- } +--} + +-- PUBLIC VARIABLES +mesecon={} -- contains all functions and all global variables +mesecon.queue={} -- contains the ActionQueue +mesecon.queue.funcs={} -- contains all ActionQueue functions + +-- Settings +dofile(minetest.get_modpath("mesecons").."/settings.lua") + +-- Utilities like comparing positions, +-- adding positions and rules, +-- mostly things that make the source look cleaner +dofile(minetest.get_modpath("mesecons").."/util.lua"); + +-- Presets (eg default rules) +dofile(minetest.get_modpath("mesecons").."/presets.lua"); + +-- The ActionQueue +-- Saves all the actions that have to be execute in the future +dofile(minetest.get_modpath("mesecons").."/actionqueue.lua"); + +-- Internal stuff +-- This is the most important file +-- it handles signal transmission and basically everything else +-- It is also responsible for managing the nodedef things, +-- like calling action_on/off/change +dofile(minetest.get_modpath("mesecons").."/internal.lua"); + +-- API +-- these are the only functions you need to remember + +mesecon.queue:add_function("receptor_on", function (pos, rules) + rules = rules or mesecon.rules.default + + -- if area (any of the rule targets) is not loaded, keep trying and call this again later + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) + -- if area is not loaded, keep trying + if minetest.get_node_or_nil(np) == nil then + mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) + return + end + end + + -- execute action + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) + local rulenames = mesecon.rules_link_rule_all(pos, rule) + for _, rulename in ipairs(rulenames) do + mesecon.turnon(np, rulename) + end + end +end) + +function mesecon.receptor_on(pos, rules) + mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) +end + +mesecon.queue:add_function("receptor_off", function (pos, rules) + rules = rules or mesecon.rules.default + + -- if area (any of the rule targets) is not loaded, keep trying and call this again later + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) + if minetest.get_node_or_nil(np) == nil then + mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) + return + end + end + + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) + local rulenames = mesecon.rules_link_rule_all(pos, rule) + for _, rulename in ipairs(rulenames) do + if not mesecon.connected_to_receptor(np, mesecon.invertRule(rule)) then + mesecon.turnoff(np, rulename) + else + mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2) + end + end + end +end) + +function mesecon.receptor_off(pos, rules) + mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) +end + + +print("[OK] Mesecons") + +-- Deprecated stuff +-- To be removed in future releases +dofile(minetest.get_modpath("mesecons").."/legacy.lua"); + +--The actual wires +dofile(minetest.get_modpath("mesecons").."/wires.lua"); + +--Services like turnoff receptor on dignode and so on +dofile(minetest.get_modpath("mesecons").."/services.lua"); diff --git a/mods/minetest-mod-mesecons/mesecons/internal.lua b/mods/minetest-mod-mesecons/mesecons/internal.lua new file mode 100644 index 0000000..d62df1f --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/internal.lua @@ -0,0 +1,652 @@ +-- Internal.lua - The core of mesecons +-- +-- For more practical developer resources see http://mesecons.net/developers.php +-- +-- Function overview +-- mesecon.get_effector(nodename) --> Returns the mesecons.effector -specifictation in the nodedef by the nodename +-- mesecon.get_receptor(nodename) --> Returns the mesecons.receptor -specifictation in the nodedef by the nodename +-- mesecon.get_conductor(nodename) --> Returns the mesecons.conductor-specifictation in the nodedef by the nodename +-- mesecon.get_any_inputrules (node) --> Returns the rules of a node if it is a conductor or an effector +-- mesecon.get_any_outputrules (node) --> Returns the rules of a node if it is a conductor or a receptor + +-- RECEPTORS +-- mesecon.is_receptor(nodename) --> Returns true if nodename is a receptor +-- mesecon.is_receptor_on(nodename --> Returns true if nodename is an receptor with state = mesecon.state.on +-- mesecon.is_receptor_off(nodename) --> Returns true if nodename is an receptor with state = mesecon.state.off +-- mesecon.receptor_get_rules(node) --> Returns the rules of the receptor (mesecon.rules.default if none specified) + +-- EFFECTORS +-- mesecon.is_effector(nodename) --> Returns true if nodename is an effector +-- mesecon.is_effector_on(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_off +-- mesecon.is_effector_off(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_on +-- mesecon.effector_get_rules(node) --> Returns the input rules of the effector (mesecon.rules.default if none specified) + +-- SIGNALS +-- mesecon.activate(pos, node, depth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher depths are executed later +-- mesecon.deactivate(pos, node, depth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), higher depths are executed later +-- mesecon.changesignal(pos, node, rulename, newstate, depth) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change), higher depths are executed later + +-- CONDUCTORS +-- mesecon.is_conductor(nodename) --> Returns true if nodename is a conductor +-- mesecon.is_conductor_on(node --> Returns true if node is a conductor with state = mesecon.state.on +-- mesecon.is_conductor_off(node) --> Returns true if node is a conductor with state = mesecon.state.off +-- mesecon.get_conductor_on(node_off) --> Returns the onstate nodename of the conductor +-- mesecon.get_conductor_off(node_on) --> Returns the offstate nodename of the conductor +-- mesecon.conductor_get_rules(node) --> Returns the input+output rules of a conductor (mesecon.rules.default if none specified) + +-- HIGH-LEVEL Internals +-- mesecon.is_power_on(pos) --> Returns true if pos emits power in any way +-- mesecon.is_power_off(pos) --> Returns true if pos does not emit power in any way +-- mesecon.turnon(pos, link) --> link is the input rule that caused calling turnon, turns on every connected node, iterative +-- mesecon.turnoff(pos, link) --> link is the input rule that caused calling turnoff, turns off every connected node, iterative +-- mesecon.connected_to_receptor(pos, link) --> Returns true if pos is connected to a receptor directly or via conductors, iterative +-- mesecon.rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect) +-- mesecon.rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon.rules_link but also returns true if output and input are swapped +-- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor + +-- RULES ROTATION helpers +-- mesecon.rotate_rules_right(rules) +-- mesecon.rotate_rules_left(rules) +-- mesecon.rotate_rules_up(rules) +-- mesecon.rotate_rules_down(rules) +-- These functions return rules that have been rotated in the specific direction + +-- General +function mesecon.get_effector(nodename) + if minetest.registered_nodes[nodename] + and minetest.registered_nodes[nodename].mesecons + and minetest.registered_nodes[nodename].mesecons.effector then + return minetest.registered_nodes[nodename].mesecons.effector + end +end + +function mesecon.get_receptor(nodename) + if minetest.registered_nodes[nodename] + and minetest.registered_nodes[nodename].mesecons + and minetest.registered_nodes[nodename].mesecons.receptor then + return minetest.registered_nodes[nodename].mesecons.receptor + end +end + +function mesecon.get_conductor(nodename) + if minetest.registered_nodes[nodename] + and minetest.registered_nodes[nodename].mesecons + and minetest.registered_nodes[nodename].mesecons.conductor then + return minetest.registered_nodes[nodename].mesecons.conductor + end +end + +function mesecon.get_any_outputrules (node) + if mesecon.is_conductor(node.name) then + return mesecon.conductor_get_rules(node) + elseif mesecon.is_receptor(node.name) then + return mesecon.receptor_get_rules(node) + end +end + +function mesecon.get_any_inputrules (node) + if mesecon.is_conductor(node.name) then + return mesecon.conductor_get_rules(node) + elseif mesecon.is_effector(node.name) then + return mesecon.effector_get_rules(node) + end +end + +function mesecon.get_any_rules (node) + return mesecon.mergetable(mesecon.get_any_inputrules(node) or {}, + mesecon.get_any_outputrules(node) or {}) +end + +-- Receptors +-- Nodes that can power mesecons +function mesecon.is_receptor_on(nodename) + local receptor = mesecon.get_receptor(nodename) + if receptor and receptor.state == mesecon.state.on then + return true + end + return false +end + +function mesecon.is_receptor_off(nodename) + local receptor = mesecon.get_receptor(nodename) + if receptor and receptor.state == mesecon.state.off then + return true + end + return false +end + +function mesecon.is_receptor(nodename) + local receptor = mesecon.get_receptor(nodename) + if receptor then + return true + end + return false +end + +function mesecon.receptor_get_rules(node) + local receptor = mesecon.get_receptor(node.name) + if receptor then + local rules = receptor.rules + if type(rules) == 'function' then + return rules(node) + elseif rules then + return rules + end + end + + return mesecon.rules.default +end + +-- Effectors +-- Nodes that can be powered by mesecons +function mesecon.is_effector_on(nodename) + local effector = mesecon.get_effector(nodename) + if effector and effector.action_off then + return true + end + return false +end + +function mesecon.is_effector_off(nodename) + local effector = mesecon.get_effector(nodename) + if effector and effector.action_on then + return true + end + return false +end + +function mesecon.is_effector(nodename) + local effector = mesecon.get_effector(nodename) + if effector then + return true + end + return false +end + +function mesecon.effector_get_rules(node) + local effector = mesecon.get_effector(node.name) + if effector then + local rules = effector.rules + if type(rules) == 'function' then + return rules(node) + elseif rules then + return rules + end + end + return mesecon.rules.default +end + +-- ####################### +-- # Signals (effectors) # +-- ####################### + +-- Activation: +mesecon.queue:add_function("activate", function (pos, rulename) + local node = minetest.get_node(pos) + local effector = mesecon.get_effector(node.name) + + if effector and effector.action_on then + effector.action_on(pos, node, rulename) + end +end) + +function mesecon.activate(pos, node, rulename, depth) + if rulename == nil then + for _,rule in ipairs(mesecon.effector_get_rules(node)) do + mesecon.activate(pos, node, rule, depth + 1) + end + return + end + mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / depth) +end + + +-- Deactivation +mesecon.queue:add_function("deactivate", function (pos, rulename) + local node = minetest.get_node(pos) + local effector = mesecon.get_effector(node.name) + + if effector and effector.action_off then + effector.action_off(pos, node, rulename) + end +end) + +function mesecon.deactivate(pos, node, rulename, depth) + if rulename == nil then + for _,rule in ipairs(mesecon.effector_get_rules(node)) do + mesecon.deactivate(pos, node, rule, depth + 1) + end + return + end + mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / depth) +end + + +-- Change +mesecon.queue:add_function("change", function (pos, rulename, changetype) + local node = minetest.get_node(pos) + local effector = mesecon.get_effector(node.name) + + if effector and effector.action_change then + effector.action_change(pos, node, rulename, changetype) + end +end) + +function mesecon.changesignal(pos, node, rulename, newstate, depth) + if rulename == nil then + for _,rule in ipairs(mesecon.effector_get_rules(node)) do + mesecon.changesignal(pos, node, rule, newstate, depth + 1) + end + return + end + + -- Include "change" in overwritecheck so that it cannot be overwritten + -- by "active" / "deactivate" that will be called upon the node at the same time. + local overwritecheck = {"change", rulename} + mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, overwritecheck, 1 / depth) +end + +-- Conductors + +function mesecon.is_conductor_on(node, rulename) + local conductor = mesecon.get_conductor(node.name) + if conductor then + if conductor.state then + return conductor.state == mesecon.state.on + end + if conductor.states then + if not rulename then + return mesecon.getstate(node.name, conductor.states) ~= 1 + end + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node)) + local binstate = mesecon.getbinstate(node.name, conductor.states) + return mesecon.get_bit(binstate, bit) + end + end + return false +end + +function mesecon.is_conductor_off(node, rulename) + local conductor = mesecon.get_conductor(node.name) + if conductor then + if conductor.state then + return conductor.state == mesecon.state.off + end + if conductor.states then + if not rulename then + return mesecon.getstate(node.name, conductor.states) == 1 + end + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node)) + local binstate = mesecon.getbinstate(node.name, conductor.states) + return not mesecon.get_bit(binstate, bit) + end + end + return false +end + +function mesecon.is_conductor(nodename) + local conductor = mesecon.get_conductor(nodename) + if conductor then + return true + end + return false +end + +function mesecon.get_conductor_on(node_off, rulename) + local conductor = mesecon.get_conductor(node_off.name) + if conductor then + if conductor.onstate then + return conductor.onstate + end + if conductor.states then + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node_off)) + local binstate = mesecon.getbinstate(node_off.name, conductor.states) + binstate = mesecon.set_bit(binstate, bit, "1") + return conductor.states[tonumber(binstate,2)+1] + end + end + return offstate +end + +function mesecon.get_conductor_off(node_on, rulename) + local conductor = mesecon.get_conductor(node_on.name) + if conductor then + if conductor.offstate then + return conductor.offstate + end + if conductor.states then + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node_on)) + local binstate = mesecon.getbinstate(node_on.name, conductor.states) + binstate = mesecon.set_bit(binstate, bit, "0") + return conductor.states[tonumber(binstate,2)+1] + end + end + return onstate +end + +function mesecon.conductor_get_rules(node) + local conductor = mesecon.get_conductor(node.name) + if conductor then + local rules = conductor.rules + if type(rules) == 'function' then + return rules(node) + elseif rules then + return rules + end + end + return mesecon.rules.default +end + +-- some more general high-level stuff + +function mesecon.is_power_on(pos, rulename) + local node = minetest.get_node(pos) + if mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name) then + return true + end + return false +end + +function mesecon.is_power_off(pos, rulename) + local node = minetest.get_node(pos) + if mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name) then + return true + end + return false +end + +function mesecon.turnon(pos, link) + local frontiers = {{pos = pos, link = link}} + + local depth = 1 + while frontiers[depth] do + local f = frontiers[depth] + local node = minetest.get_node_or_nil(f.pos) + + -- area not loaded, postpone action + if not node then + mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true) + elseif mesecon.is_conductor_off(node, f.link) then + local rules = mesecon.conductor_get_rules(node) + + minetest.swap_node(f.pos, {name = mesecon.get_conductor_on(node, f.link), + param2 = node.param2}) + + -- call turnon on neighbors: normal rules + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = mesecon.addPosRule(f.pos, r) + + -- area not loaded, postpone action + if not minetest.get_node_or_nil(np) then + mesecon.queue:add_action(np, "turnon", {rulename}, + nil, true) + else + local links = mesecon.rules_link_rule_all(f.pos, r) + for _, l in ipairs(links) do + table.insert(frontiers, {pos = np, link = l}) + end + end + end + elseif mesecon.is_effector(node.name) then + mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth) + if mesecon.is_effector_off(node.name) then + mesecon.activate(f.pos, node, f.link, depth) + end + end + depth = depth + 1 + end +end + +mesecon.queue:add_function("turnon", function (pos, rulename, recdepth) + mesecon.turnon(pos, rulename, recdepth) +end) + +function mesecon.turnoff(pos, link) + local frontiers = {{pos = pos, link = link}} + + local depth = 1 + while frontiers[depth] do + local f = frontiers[depth] + local node = minetest.get_node_or_nil(f.pos) + + -- area not loaded, postpone action + if not node then + mesecon.queue:add_action(f.pos, "turnoff", {link}, nil, true) + elseif mesecon.is_conductor_on(node, f.link) then + local rules = mesecon.conductor_get_rules(node) + + minetest.swap_node(f.pos, {name = mesecon.get_conductor_off(node, f.link), + param2 = node.param2}) + + -- call turnoff on neighbors: normal rules + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = mesecon.addPosRule(f.pos, r) + + -- area not loaded, postpone action + if not minetest.get_node_or_nil(np) then + mesecon.queue:add_action(np, "turnoff", {rulename}, + nil, true) + else + local links = mesecon.rules_link_rule_all(f.pos, r) + for _, l in ipairs(links) do + table.insert(frontiers, {pos = np, link = l}) + end + end + end + elseif mesecon.is_effector(node.name) then + mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth) + if mesecon.is_effector_on(node.name) and not mesecon.is_powered(f.pos) then + mesecon.deactivate(f.pos, node, f.link, depth) + end + end + depth = depth + 1 + end +end + +mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth) + mesecon.turnoff(pos, rulename, recdepth) +end) + + +function mesecon.connected_to_receptor(pos, link) + local node = minetest.get_node(pos) + + -- Check if conductors around are connected + local rules = mesecon.get_any_inputrules(node) + if not rules then return false end + + for _, rule in ipairs(mesecon.rule2meta(link, rules)) do + local links = mesecon.rules_link_rule_all_inverted(pos, rule) + for _, l in ipairs(links) do + local np = mesecon.addPosRule(pos, l) + if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then + return true + end + end + end + + return false +end + +function mesecon.find_receptor_on(pos, link) + local frontiers = {{pos = pos, link = link}} + local checked = {} + + -- List of positions that have been searched for onstate receptors + local depth = 1 + while frontiers[depth] do + local f = frontiers[depth] + local node = minetest.get_node_or_nil(f.pos) + + if not node then return false end + if mesecon.is_receptor_on(node.name) then return true end + if mesecon.is_conductor_on(node, f.link) then + local rules = mesecon.conductor_get_rules(node) + + -- call turnoff on neighbors: normal rules + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = mesecon.addPosRule(f.pos, r) + + local links = mesecon.rules_link_rule_all_inverted(f.pos, r) + for _, l in ipairs(links) do + local checkedstring = np.x..np.y..np.z..l.x..l.y..l.z + if not checked[checkedstring] then + table.insert(frontiers, {pos = np, link = l}) + checked[checkedstring] = true + end + end + end + + end + depth = depth + 1 + end +end + +function mesecon.rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule + local outputnode = minetest.get_node(output) + local inputnode = minetest.get_node(input) + local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode) + local inputrules = mesecon.get_any_inputrules (inputnode) + if not outputrules or not inputrules then + return + end + + for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do + -- Check if output sends to input + if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then + for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do + -- Check if input accepts from output + if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then + return true, inputrule + end + end + end + end + return false +end + +function mesecon.rules_link_rule_all(output, rule) + local input = mesecon.addPosRule(output, rule) + local inputnode = minetest.get_node(input) + local inputrules = mesecon.get_any_inputrules (inputnode) + if not inputrules then + return {} + end + local rules = {} + + for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do + -- Check if input accepts from output + if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then + table.insert(rules, inputrule) + end + end + return rules +end + +function mesecon.rules_link_rule_all_inverted(input, rule) + --local irule = mesecon.invertRule(rule) + local output = mesecon.addPosRule(input, rule) + local outputnode = minetest.get_node(output) + local outputrules = mesecon.get_any_outputrules (outputnode) + if not outputrules then + return {} + end + local rules = {} + + for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do + if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then + table.insert(rules, mesecon.invertRule(outputrule)) + end + end + return rules +end + +function mesecon.rules_link_anydir(pos1, pos2) + return mesecon.rules_link(pos1, pos2) or mesecon.rules_link(pos2, pos1) +end + +function mesecon.is_powered(pos, rule) + local node = minetest.get_node(pos) + local rules = mesecon.get_any_inputrules(node) + if not rules then return false end + + -- List of nodes that send out power to pos + local sourcepos = {} + + if not rule then + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule) + for _, rname in ipairs(rulenames) do + local np = mesecon.addPosRule(pos, rname) + local nn = minetest.get_node(np) + if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname)) + or mesecon.is_receptor_on (nn.name)) then + table.insert(sourcepos, np) + end + end + end + else + local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule) + for _, rname in ipairs(rulenames) do + local np = mesecon.addPosRule(pos, rname) + local nn = minetest.get_node(np) + if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname)) + or mesecon.is_receptor_on (nn.name)) then + table.insert(sourcepos, np) + end + end + end + + -- Return FALSE if not powered, return list of sources if is powered + if (#sourcepos == 0) then return false + else return sourcepos end +end + +--Rules rotation Functions: +function mesecon.rotate_rules_right(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = -rule.z, + y = rule.y, + z = rule.x, + name = rule.name}) + end + return nr +end + +function mesecon.rotate_rules_left(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = rule.z, + y = rule.y, + z = -rule.x, + name = rule.name}) + end + return nr +end + +function mesecon.rotate_rules_down(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = -rule.y, + y = rule.x, + z = rule.z, + name = rule.name}) + end + return nr +end + +function mesecon.rotate_rules_up(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = rule.y, + y = -rule.x, + z = rule.z, + name = rule.name}) + end + return nr +end diff --git a/mods/minetest-mod-mesecons/mesecons/legacy.lua b/mods/minetest-mod-mesecons/mesecons/legacy.lua new file mode 100644 index 0000000..6d8ccca --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/legacy.lua @@ -0,0 +1,30 @@ +-- Ugly hack to prevent breaking compatibility with other mods +-- Just remove the following two functions to delete the hack, to be done when other mods have updated +function mesecon.receptor_on(self, pos, rules) + if (self.receptor_on) then + print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.") + print("[Mesecons] If you are the programmer of this mod, please update it ") + print("[Mesecons] to use mesecon.receptor_on instead. mesecon:* is deprecated") + print("[Mesecons] Otherwise, please make sure you're running the latest version") + print("[Mesecons] of that mod and inform the mod creator.") + else + rules = pos + pos = self + end + mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) +end + +function mesecon.receptor_off(self, pos, rules) + if (self.receptor_off) then + print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.") + print("[Mesecons] If you are the programmer of this mod, please update it ") + print("[Mesecons] to use mesecon.receptor_off instead. mesecon:* is deprecated") + print("[Mesecons] Otherwise, please make sure you're running the latest version") + print("[Mesecons] of that mod and inform the mod creator.") + else + rules = pos + pos = self + end + mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) +end + diff --git a/mods/minetest-mod-mesecons/mesecons/oldwires.lua b/mods/minetest-mod-mesecons/mesecons/oldwires.lua new file mode 100644 index 0000000..9e54b1b --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/oldwires.lua @@ -0,0 +1,38 @@ +minetest.register_node("mesecons:mesecon_off", { + drawtype = "raillike", + tiles = {"jeija_mesecon_off.png", "jeija_mesecon_curved_off.png", "jeija_mesecon_t_junction_off.png", "jeija_mesecon_crossing_off.png"}, + inventory_image = "jeija_mesecon_off.png", + wield_image = "jeija_mesecon_off.png", + paramtype = "light", + is_ground_content = true, + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}, + }, + groups = {dig_immediate=3, mesecon=1, mesecon_conductor_craftable=1}, + description="Mesecons", + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "mesecons:mesecon_on" + }} +}) + +minetest.register_node("mesecons:mesecon_on", { + drawtype = "raillike", + tiles = {"jeija_mesecon_on.png", "jeija_mesecon_curved_on.png", "jeija_mesecon_t_junction_on.png", "jeija_mesecon_crossing_on.png"}, + paramtype = "light", + is_ground_content = true, + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}, + }, + groups = {dig_immediate=3, not_in_creaive_inventory=1, mesecon=1}, + drop = "mesecons:mesecon_off 1", + light_source = LIGHT_MAX-11, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "mesecons:mesecon_off" + }} +}) diff --git a/mods/minetest-mod-mesecons/mesecons/presets.lua b/mods/minetest-mod-mesecons/mesecons/presets.lua new file mode 100644 index 0000000..ea4bd65 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/presets.lua @@ -0,0 +1,47 @@ +mesecon.rules = {} +mesecon.state = {} + +mesecon.rules.default = +{{x=0, y=0, z=-1}, + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=1, y=1, z=0}, + {x=1, y=-1, z=0}, + {x=-1, y=1, z=0}, + {x=-1, y=-1, z=0}, + {x=0, y=1, z=1}, + {x=0, y=-1, z=1}, + {x=0, y=1, z=-1}, + {x=0, y=-1, z=-1}} + +mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.default, {{x=0, y=-2, z=0}}) + +mesecon.rules.buttonlike = +{{x = 1, y = 0, z = 0}, + {x = 1, y = 1, z = 0}, + {x = 1, y =-1, z = 0}, + {x = 1, y =-1, z = 1}, + {x = 1, y =-1, z =-1}, + {x = 2, y = 0, z = 0}} + +mesecon.rules.flat = +{{x = 1, y = 0, z = 0}, + {x =-1, y = 0, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 0, y = 0, z =-1}} + +mesecon.rules.buttonlike_get = function(node) + local rules = mesecon.rules.buttonlike + if node.param2 == 2 then + rules=mesecon.rotate_rules_left(rules) + elseif node.param2 == 3 then + rules=mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) + elseif node.param2 == 0 then + rules=mesecon.rotate_rules_right(rules) + end + return rules +end + +mesecon.state.on = "on" +mesecon.state.off = "off" diff --git a/mods/minetest-mod-mesecons/mesecons/services.lua b/mods/minetest-mod-mesecons/mesecons/services.lua new file mode 100644 index 0000000..215fb31 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/services.lua @@ -0,0 +1,100 @@ +-- Dig and place services + +mesecon.on_placenode = function (pos, node) + mesecon.update_autoconnect(pos, node) + + -- Receptors: Send on signal when active + if mesecon.is_receptor_on(node.name) then + mesecon.receptor_on(pos, mesecon.receptor_get_rules(node)) + end + + -- Conductors: Send turnon signal when powered or replace by respective offstate conductor + -- if placed conductor is an onstate one + if mesecon.is_conductor(node.name) then + local sources = mesecon.is_powered(pos) + if sources then + -- also call receptor_on if itself is powered already, so that neighboring + -- conductors will be activated (when pushing an on-conductor with a piston) + for _, s in ipairs(sources) do + local rule = {x = pos.x - s.x, y = pos.y - s.y, z = pos.z - s.z} + mesecon.turnon(pos, rule) + end + --mesecon.receptor_on (pos, mesecon.conductor_get_rules(node)) + elseif mesecon.is_conductor_on(node) then + minetest.swap_node(pos, {name = mesecon.get_conductor_off(node)}) + end + end + + -- Effectors: Send changesignal and activate or deactivate + if mesecon.is_effector(node.name) then + local powered_rules = {} + local unpowered_rules = {} + + -- for each input rule, check if powered + for _, r in ipairs(mesecon.effector_get_rules(node)) do + local powered = mesecon.is_powered(pos, r) + if powered then table.insert(powered_rules, r) + else table.insert(unpowered_rules, r) end + + local state = powered and mesecon.state.on or mesecon.state.off + mesecon.changesignal(pos, node, r, state, 1) + end + + if (#powered_rules > 0) then + for _, r in ipairs(powered_rules) do + mesecon.activate(pos, node, r, 1) + end + else + for _, r in ipairs(unpowered_rules) do + mesecon.deactivate(pos, node, r, 1) + end + end + end +end + +mesecon.on_dignode = function (pos, node) + if mesecon.is_conductor_on(node) then + mesecon.receptor_off(pos, mesecon.conductor_get_rules(node)) + elseif mesecon.is_receptor_on(node.name) then + mesecon.receptor_off(pos, mesecon.receptor_get_rules(node)) + end + mesecon.queue:add_action(pos, "update_autoconnect", {node}) +end + +mesecon.queue:add_function("update_autoconnect", mesecon.update_autoconnect) + +minetest.register_on_placenode(mesecon.on_placenode) +minetest.register_on_dignode(mesecon.on_dignode) + +-- Overheating service for fast circuits + +-- returns true if heat is too high +mesecon.do_overheat = function(pos) + local meta = minetest.get_meta(pos) + local heat = meta:get_int("heat") or 0 + + heat = heat + 1 + meta:set_int("heat", heat) + + if heat < mesecon.setting("overheat_max", 20) then + mesecon.queue:add_action(pos, "cooldown", {}, 1, nil, 0) + else + return true + end + + return false +end + + +mesecon.queue:add_function("cooldown", function (pos) + if minetest.get_item_group(minetest.get_node(pos).name, "overheat") == 0 then + return -- node has been moved, this one does not use overheating - ignore + end + + local meta = minetest.get_meta(pos) + local heat = meta:get_int("heat") + + if (heat > 0) then + meta:set_int("heat", heat - 1) + end +end) diff --git a/mods/minetest-mod-mesecons/mesecons/settings.lua b/mods/minetest-mod-mesecons/mesecons/settings.lua new file mode 100644 index 0000000..164cb57 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/settings.lua @@ -0,0 +1,10 @@ +-- SETTINGS +function mesecon.setting(setting, default) + if type(default) == "bool" then + return minetest.setting_getbool("mesecon."..setting) or default + elseif type(default) == "string" then + return minetest.setting_get("mesecon."..setting) or default + elseif type(default) == "number" then + return tonumber(minetest.setting_get("mesecon."..setting) or default) + end +end diff --git a/mods/minetest-mod-mesecons/mesecons/textures/jeija_fiber.png b/mods/minetest-mod-mesecons/mesecons/textures/jeija_fiber.png new file mode 100644 index 0000000..e8c7b08 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/jeija_fiber.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/jeija_glue.png b/mods/minetest-mod-mesecons/mesecons/textures/jeija_glue.png new file mode 100644 index 0000000..2f351d1 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/jeija_glue.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_off.png b/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_off.png new file mode 100644 index 0000000..2a75ef3 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_on.png b/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_on.png new file mode 100644 index 0000000..9df3450 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_side.png b/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_side.png new file mode 100644 index 0000000..fb5db33 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/jeija_mesecon_switch_side.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/jeija_silicon.png b/mods/minetest-mod-mesecons/mesecons/textures/jeija_silicon.png new file mode 100644 index 0000000..a7b0d52 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/jeija_silicon.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_inv.png b/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_inv.png new file mode 100644 index 0000000..a3930cb Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_inv.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_off.png b/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_off.png new file mode 100644 index 0000000..58164fa Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_on.png b/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_on.png new file mode 100644 index 0000000..98a86c8 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons/textures/mesecons_wire_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons/util.lua b/mods/minetest-mod-mesecons/mesecons/util.lua new file mode 100644 index 0000000..ab2f32c --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/util.lua @@ -0,0 +1,211 @@ +function mesecon.move_node(pos, newpos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos):to_table() + minetest.remove_node(pos) + minetest.add_node(newpos, node) + minetest.get_meta(pos):from_table(meta) +end + +function mesecon.flattenrules(allrules) +--[[ + { + { + {xyz}, + {xyz}, + }, + { + {xyz}, + {xyz}, + }, + } +--]] + if allrules[1] and + allrules[1].x then + return allrules + end + + local shallowrules = {} + for _, metarule in ipairs( allrules) do + for _, rule in ipairs(metarule ) do + table.insert(shallowrules, rule) + end + end + return shallowrules +--[[ + { + {xyz}, + {xyz}, + {xyz}, + {xyz}, + } +--]] +end + +function mesecon.rule2bit(findrule, allrules) + --get the bit of the metarule the rule is in, or bit 1 + if (allrules[1] and + allrules[1].x) or + not findrule then + return 1 + end + for m,metarule in ipairs( allrules) do + for _, rule in ipairs(metarule ) do + if mesecon.cmpPos(findrule, rule) then + return m + end + end + end +end + +function mesecon.rule2metaindex(findrule, allrules) + --get the metarule the rule is in, or allrules + if allrules[1].x then + return nil + end + + if not(findrule) then + return mesecon.flattenrules(allrules) + end + + for m, metarule in ipairs( allrules) do + for _, rule in ipairs(metarule ) do + if mesecon.cmpPos(findrule, rule) then + return m + end + end + end +end + +function mesecon.rule2meta(findrule, allrules) + if #allrules == 0 then return {} end + + local index = mesecon.rule2metaindex(findrule, allrules) + if index == nil then + if allrules[1].x then + return allrules + else + return {} + end + end + return allrules[index] +end + +function mesecon.dec2bin(n) + local x, y = math.floor(n / 2), n % 2 + if (n > 1) then + return mesecon.dec2bin(x)..y + else + return ""..y + end +end + +function mesecon.getstate(nodename, states) + for state, name in ipairs(states) do + if name == nodename then + return state + end + end + error(nodename.." doesn't mention itself in "..dump(states)) +end + +function mesecon.getbinstate(nodename, states) + return mesecon.dec2bin(mesecon.getstate(nodename, states)-1) +end + +function mesecon.get_bit(binary,bit) + bit = bit or 1 + local c = binary:len()-(bit-1) + return binary:sub(c,c) == "1" +end + +function mesecon.set_bit(binary,bit,value) + if value == "1" then + if not mesecon.get_bit(binary,bit) then + return mesecon.dec2bin(tonumber(binary,2)+math.pow(2,bit-1)) + end + elseif value == "0" then + if mesecon.get_bit(binary,bit) then + return mesecon.dec2bin(tonumber(binary,2)-math.pow(2,bit-1)) + end + end + return binary + +end + +function mesecon.invertRule(r) + return {x = -r.x, y = -r.y, z = -r.z} +end + +function mesecon.addPosRule(p, r) + return {x = p.x + r.x, y = p.y + r.y, z = p.z + r.z} +end + +function mesecon.cmpPos(p1, p2) + return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z) +end + +function mesecon.tablecopy(table) -- deep table copy + if type(table) ~= "table" then return table end -- no need to copy + local newtable = {} + + for idx, item in pairs(table) do + if type(item) == "table" then + newtable[idx] = mesecon.tablecopy(item) + else + newtable[idx] = item + end + end + + return newtable +end + +function mesecon.cmpAny(t1, t2) + if type(t1) ~= type(t2) then return false end + if type(t1) ~= "table" and type(t2) ~= "table" then return t1 == t2 end + + for i, e in pairs(t1) do + if not mesecon.cmpAny(e, t2[i]) then return false end + end + + return true +end + +-- does not overwrite values; number keys (ipairs) are appended, not overwritten +function mesecon.mergetable(source, dest) + local rval = mesecon.tablecopy(dest) + + for k, v in pairs(source) do + rval[k] = dest[k] or mesecon.tablecopy(v) + end + for i, v in ipairs(source) do + table.insert(rval, mesecon.tablecopy(v)) + end + + return rval +end + +function mesecon.register_node(name, spec_common, spec_off, spec_on) + spec_common.drop = spec_common.drop or name .. "_off" + spec_common.__mesecon_basename = name + spec_on.__mesecon_state = "on" + spec_off.__mesecon_state = "off" + + spec_on = mesecon.mergetable(spec_common, spec_on); + spec_off = mesecon.mergetable(spec_common, spec_off); + + minetest.register_node(name .. "_on", spec_on) + minetest.register_node(name .. "_off", spec_off) +end + +-- swap onstate and offstate nodes, returns new state +function mesecon.flipstate(pos, node) + local nodedef = minetest.registered_nodes[node.name] + local newstate + if (nodedef.__mesecon_state == "on") then newstate = "off" end + if (nodedef.__mesecon_state == "off") then newstate = "on" end + + minetest.swap_node(pos, {name = nodedef.__mesecon_basename .. "_" .. newstate, + param2 = node.param2}) + + return newstate +end diff --git a/mods/minetest-mod-mesecons/mesecons/wires.lua b/mods/minetest-mod-mesecons/mesecons/wires.lua new file mode 100644 index 0000000..40c8541 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons/wires.lua @@ -0,0 +1,250 @@ +-- naming scheme: wire:(xp)(zp)(xm)(zm)(xpyp)(zpyp)(xmyp)(zmyp)_on/off +-- where x= x direction, z= z direction, y= y direction, p = +1, m = -1, e.g. xpym = {x=1, y=-1, z=0} +-- The (xp)/(zpyp)/.. statements shall be replaced by either 0 or 1 +-- Where 0 means the wire has no visual connection to that direction and +-- 1 means that the wire visually connects to that other node. + +-- ####################### +-- ## Update wire looks ## +-- ####################### + +-- self_pos = pos of any mesecon node, from_pos = pos of conductor to getconnect for +local wire_getconnect = function (from_pos, self_pos) + local node = minetest.get_node(self_pos) + if minetest.registered_nodes[node.name] + and minetest.registered_nodes[node.name].mesecons then + -- rules of node to possibly connect to + local rules = {} + if (minetest.registered_nodes[node.name].mesecon_wire) then + rules = mesecon.rules.default + else + rules = mesecon.get_any_rules(node) + end + + for _, r in ipairs(mesecon.flattenrules(rules)) do + if (mesecon.cmpPos(mesecon.addPosRule(self_pos, r), from_pos)) then + return true + end + end + end + return false +end + +-- Update this node +local wire_updateconnect = function (pos) + local connections = {} + + for _, r in ipairs(mesecon.rules.default) do + if wire_getconnect(pos, mesecon.addPosRule(pos, r)) then + table.insert(connections, r) + end + end + + local nid = {} + for _, vec in ipairs(connections) do + -- flat component + if vec.x == 1 then nid[0] = "1" end + if vec.z == 1 then nid[1] = "1" end + if vec.x == -1 then nid[2] = "1" end + if vec.z == -1 then nid[3] = "1" end + + -- slopy component + if vec.y == 1 then + if vec.x == 1 then nid[4] = "1" end + if vec.z == 1 then nid[5] = "1" end + if vec.x == -1 then nid[6] = "1" end + if vec.z == -1 then nid[7] = "1" end + end + end + + local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0") + ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0") + + local state_suffix = string.find(minetest.get_node(pos).name, "_off") and "_off" or "_on" + minetest.set_node(pos, {name = "mesecons:wire_"..nodeid..state_suffix}) +end + +local update_on_place_dig = function (pos, node) + -- Update placed node (get_node again as it may have been dug) + local nn = minetest.get_node(pos) + if (minetest.registered_nodes[nn.name]) + and (minetest.registered_nodes[nn.name].mesecon_wire) then + wire_updateconnect(pos) + end + + -- Update nodes around it + local rules = {} + if minetest.registered_nodes[node.name] + and minetest.registered_nodes[node.name].mesecon_wire then + rules = mesecon.rules.default + else + rules = mesecon.get_any_rules(node) + end + if (not rules) then return end + + for _, r in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, r) + if minetest.registered_nodes[minetest.get_node(np).name] + and minetest.registered_nodes[minetest.get_node(np).name].mesecon_wire then + wire_updateconnect(np) + end + end +end + +function mesecon.update_autoconnect(pos, node) + if (not node) then node = minetest.get_node(pos) end + update_on_place_dig(pos, node) +end + +-- ############################ +-- ## Wire node registration ## +-- ############################ +-- Nodeboxes: +local box_center = {-1/16, -.5, -1/16, 1/16, -.5+1/16, 1/16} +local box_bump1 = { -2/16, -8/16, -2/16, 2/16, -13/32, 2/16 } + +local nbox_nid = +{ + [0] = {1/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}, -- x positive + [1] = {-1/16, -.5, 1/16, 1/16, -.5+1/16, 8/16}, -- z positive + [2] = {-8/16, -.5, -1/16, -1/16, -.5+1/16, 1/16}, -- x negative + [3] = {-1/16, -.5, -8/16, 1/16, -.5+1/16, -1/16}, -- z negative + + [4] = {.5-1/16, -.5+1/16, -1/16, .5, .4999+1/16, 1/16}, -- x positive up + [5] = {-1/16, -.5+1/16, .5-1/16, 1/16, .4999+1/16, .5}, -- z positive up + [6] = {-.5, -.5+1/16, -1/16, -.5+1/16, .4999+1/16, 1/16}, -- x negative up + [7] = {-1/16, -.5+1/16, -.5, 1/16, .4999+1/16, -.5+1/16} -- z negative up +} + +local tiles_off = { "mesecons_wire_off.png" } +local tiles_on = { "mesecons_wire_on.png" } + +local selectionbox = +{ + type = "fixed", + fixed = {-.5, -.5, -.5, .5, -.5+4/16, .5} +} + +-- go to the next nodeid (ex.: 01000011 --> 01000100) +local nid_inc = function() end +nid_inc = function (nid) + local i = 0 + while nid[i-1] ~= 1 do + nid[i] = (nid[i] ~= 1) and 1 or 0 + i = i + 1 + end + + -- BUT: Skip impossible nodeids: + if ((nid[0] == 0 and nid[4] == 1) or (nid[1] == 0 and nid[5] == 1) + or (nid[2] == 0 and nid[6] == 1) or (nid[3] == 0 and nid[7] == 1)) then + return nid_inc(nid) + end + + return i <= 8 +end + +register_wires = function() + local nid = {} + while true do + -- Create group specifiction and nodeid string (see note above for details) + local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0") + ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0") + + -- Calculate nodebox + local nodebox = {type = "fixed", fixed={box_center}} + for i=0,7 do + if nid[i] == 1 then + table.insert(nodebox.fixed, nbox_nid[i]) + end + end + + -- Add bump to nodebox if curved + if (nid[0] == 1 and nid[1] == 1) or (nid[1] == 1 and nid[2] == 1) + or (nid[2] == 1 and nid[3] == 1) or (nid[3] == 1 and nid[0] == 1) then + table.insert(nodebox.fixed, box_bump1) + end + + -- If nothing to connect to, still make a nodebox of a straight wire + if nodeid == "00000000" then + nodebox.fixed = {-8/16, -.5, -1/16, 8/16, -.5+1/16, 1/16} + end + + local rules = {} + if (nid[0] == 1) then table.insert(rules, vector.new( 1, 0, 0)) end + if (nid[1] == 1) then table.insert(rules, vector.new( 0, 0, 1)) end + if (nid[2] == 1) then table.insert(rules, vector.new(-1, 0, 0)) end + if (nid[3] == 1) then table.insert(rules, vector.new( 0, 0, -1)) end + + if (nid[0] == 1) then table.insert(rules, vector.new( 1, -1, 0)) end + if (nid[1] == 1) then table.insert(rules, vector.new( 0, -1, 1)) end + if (nid[2] == 1) then table.insert(rules, vector.new(-1, -1, 0)) end + if (nid[3] == 1) then table.insert(rules, vector.new( 0, -1, -1)) end + + if (nid[4] == 1) then table.insert(rules, vector.new( 1, 1, 0)) end + if (nid[5] == 1) then table.insert(rules, vector.new( 0, 1, 1)) end + if (nid[6] == 1) then table.insert(rules, vector.new(-1, 1, 0)) end + if (nid[7] == 1) then table.insert(rules, vector.new( 0, 1, -1)) end + + local meseconspec_off = { conductor = { + rules = rules, + state = mesecon.state.off, + onstate = "mesecons:wire_"..nodeid.."_on" + }} + + local meseconspec_on = { conductor = { + rules = rules, + state = mesecon.state.on, + offstate = "mesecons:wire_"..nodeid.."_off" + }} + + local groups_on = {dig_immediate = 3, mesecon_conductor_craftable = 1, + not_in_creative_inventory = 1} + local groups_off = {dig_immediate = 3, mesecon_conductor_craftable = 1} + if nodeid ~= "00000000" then + groups_off["not_in_creative_inventory"] = 1 + end + + mesecon.register_node("mesecons:wire_"..nodeid, { + description = "Mesecon", + drawtype = "nodebox", + inventory_image = "mesecons_wire_inv.png", + wield_image = "mesecons_wire_inv.png", + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + selection_box = selectionbox, + node_box = nodebox, + walkable = false, + drop = "mesecons:wire_00000000_off", + mesecon_wire = true + }, {tiles = tiles_off, mesecons = meseconspec_off, groups = groups_off}, + {tiles = tiles_on, mesecons = meseconspec_on, groups = groups_on}) + + if (nid_inc(nid) == false) then return end + end +end +register_wires() + +-- ############## +-- ## Crafting ## +-- ############## +minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 2", + recipe = "default:mese_crystal_fragment", + cooktime = 3, +}) + +minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 18", + recipe = "default:mese_crystal", + cooktime = 15, +}) + +minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 162", + recipe = "default:mese", + cooktime = 30, +}) diff --git a/mods/minetest-mod-mesecons/mesecons_alias/depends.txt b/mods/minetest-mod-mesecons/mesecons_alias/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_alias/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_alias/init.lua b/mods/minetest-mod-mesecons/mesecons_alias/init.lua new file mode 100644 index 0000000..395c368 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_alias/init.lua @@ -0,0 +1,38 @@ +-- This file registers aliases for the /give /giveme commands. + +minetest.register_alias("mesecons:removestone", "mesecons_random:removestone") +minetest.register_alias("mesecons:power_plant", "mesecons_powerplant:power_plant") +minetest.register_alias("mesecons:powerplant", "mesecons_powerplant:power_plant") +minetest.register_alias("mesecons:meselamp", "mesecons_lamp:lamp_off") +minetest.register_alias("mesecons:mesecon", "mesecons:wire_00000000_off") +minetest.register_alias("mesecons:object_detector", "mesecons_detector:object_detector_off") +minetest.register_alias("mesecons:wireless_inverter", "mesecons_wireless:wireless_inverter_on") +minetest.register_alias("mesecons:wireless_receiver", "mesecons_wireless:wireless_receiver_off") +minetest.register_alias("mesecons:wireless_transmitter", "mesecons_wireless:wireless_transmitter_off") +minetest.register_alias("mesecons:switch", "mesecons_switch:mesecon_switch_off") +minetest.register_alias("mesecons:button", "mesecons_button:button_off") +minetest.register_alias("mesecons:piston", "mesecons_pistons:piston_normal_off") +minetest.register_alias("mesecons:blinky_plant", "mesecons_blinkyplant:blinky_plant_off") +minetest.register_alias("mesecons:mesecon_torch", "mesecons_torch:mesecon_torch_on") +minetest.register_alias("mesecons:torch", "mesecons_torch:mesecon_torch_on") +minetest.register_alias("mesecons:hydro_turbine", "mesecons_hydroturbine:hydro_turbine_off") +minetest.register_alias("mesecons:pressure_plate_stone", "mesecons_pressureplates:pressure_plate_stone_off") +minetest.register_alias("mesecons:pressure_plate_wood", "mesecons_pressureplates:pressure_plate_wood_off") +minetest.register_alias("mesecons:mesecon_socket", "mesecons_temperest:mesecon_socket_off") +minetest.register_alias("mesecons:mesecon_inverter", "mesecons_temperest:mesecon_inverter_on") +minetest.register_alias("mesecons:movestone", "mesecons_movestones:movestone") +minetest.register_alias("mesecons:sticky_movestone", "mesecons_movestones:sticky_movestone") +minetest.register_alias("mesecons:noteblock", "mesecons_noteblock:noteblock") +minetest.register_alias("mesecons:microcontroller", "mesecons_microcontroller:microcontroller0000") +minetest.register_alias("mesecons:delayer", "mesecons_delayer:delayer_off_1") +minetest.register_alias("mesecons:solarpanel", "mesecons_solarpanel:solar_panel_off") + + +--Backwards compatibility +minetest.register_alias("mesecons:mesecon_off", "mesecons:wire_00000000_off") +minetest.register_alias("mesecons_pistons:piston_sticky", "mesecons_pistons:piston_sticky_on") +minetest.register_alias("mesecons_pistons:piston_normal", "mesecons_pistons:piston_normal_on") +minetest.register_alias("mesecons_pistons:piston_up_normal", "mesecons_pistons:piston_up_normal_on") +minetest.register_alias("mesecons_pistons:piston_down_normal", "mesecons_pistons:piston_down_normal_on") +minetest.register_alias("mesecons_pistons:piston_up_sticky", "mesecons_pistons:piston_up_sticky_on") +minetest.register_alias("mesecons_pistons:piston_down_sticky", "mesecons_pistons:piston_down_sticky_on") diff --git a/mods/minetest-mod-mesecons/mesecons_blinkyplant/depends.txt b/mods/minetest-mod-mesecons/mesecons_blinkyplant/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_blinkyplant/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_blinkyplant/init.lua b/mods/minetest-mod-mesecons/mesecons_blinkyplant/init.lua new file mode 100644 index 0000000..8d2aa6e --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_blinkyplant/init.lua @@ -0,0 +1,51 @@ +-- The BLINKY_PLANT + +local toggle_timer = function (pos) + local timer = minetest.get_node_timer(pos) + if timer:is_started() then + timer:stop() + else + timer:start(mesecon.setting("blinky_plant_interval", 3)) + end +end + +local on_timer = function (pos) + local node = minetest.get_node(pos) + if(mesecon.flipstate(pos, node) == "on") then + mesecon.receptor_on(pos) + else + mesecon.receptor_off(pos) + end + toggle_timer(pos) +end + +mesecon.register_node("mesecons_blinkyplant:blinky_plant", { + description="Blinky Plant", + drawtype = "plantlike", + inventory_image = "jeija_blinky_plant_off.png", + paramtype = "light", + walkable = false, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, + }, + on_timer = on_timer, + on_rightclick = toggle_timer, + on_construct = toggle_timer +},{ + tiles = {"jeija_blinky_plant_off.png"}, + groups = {dig_immediate=3}, + mesecons = {receptor = { state = mesecon.state.off }} +},{ + tiles = {"jeija_blinky_plant_on.png"}, + groups = {dig_immediate=3, not_in_creative_inventory=1}, + mesecons = {receptor = { state = mesecon.state.on }} +}) + +minetest.register_craft({ + output = "mesecons_blinkyplant:blinky_plant_off 1", + recipe = { {"","group:mesecon_conductor_craftable",""}, + {"","group:mesecon_conductor_craftable",""}, + {"group:sapling","group:sapling","group:sapling"}} +}) diff --git a/mods/minetest-mod-mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_off.png b/mods/minetest-mod-mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_off.png new file mode 100644 index 0000000..4f507da Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_on.png b/mods/minetest-mod-mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_on.png new file mode 100644 index 0000000..f77a134 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_button/depends.txt b/mods/minetest-mod-mesecons/mesecons_button/depends.txt new file mode 100644 index 0000000..19c798c --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_button/depends.txt @@ -0,0 +1,2 @@ +mesecons +mesecons_receiver diff --git a/mods/minetest-mod-mesecons/mesecons_button/init.lua b/mods/minetest-mod-mesecons/mesecons_button/init.lua new file mode 100644 index 0000000..f147d8f --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_button/init.lua @@ -0,0 +1,98 @@ +-- WALL BUTTON +-- A button that when pressed emits power for 1 second +-- and then turns off again + +mesecon.button_turnoff = function (pos) + local node = minetest.get_node(pos) + if node.name=="mesecons_button:button_on" then --has not been dug + minetest.swap_node(pos, {name = "mesecons_button:button_off", param2=node.param2}) + minetest.sound_play("mesecons_button_pop", {pos=pos}) + local rules = mesecon.rules.buttonlike_get(node) + mesecon.receptor_off(pos, rules) + end +end + +minetest.register_node("mesecons_button:button_off", { + drawtype = "nodebox", + tiles = { + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_off.png" + }, + paramtype = "light", + paramtype2 = "facedir", + legacy_wallmounted = true, + walkable = false, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 } + }, + node_box = { + type = "fixed", + fixed = { + { -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the thin plate behind the button + { -4/16, -2/16, 4/16, 4/16, 2/16, 6/16 } -- the button itself + } + }, + groups = {dig_immediate=2, mesecon_needs_receiver = 1}, + description = "Button", + on_punch = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2}) + mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) + minetest.sound_play("mesecons_button_push", {pos=pos}) + minetest.after(1, mesecon.button_turnoff, pos) + end, + sounds = default.node_sound_stone_defaults(), + mesecons = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.buttonlike_get + }} +}) + +minetest.register_node("mesecons_button:button_on", { + drawtype = "nodebox", + tiles = { + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_on.png" + }, + paramtype = "light", + paramtype2 = "facedir", + legacy_wallmounted = true, + walkable = false, + light_source = LIGHT_MAX-7, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 } + }, + node_box = { + type = "fixed", + fixed = { + { -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, + { -4/16, -2/16, 11/32, 4/16, 2/16, 6/16 } + } + }, + groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon_needs_receiver = 1}, + drop = 'mesecons_button:button_off', + description = "Button", + sounds = default.node_sound_stone_defaults(), + mesecons = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.buttonlike_get + }} +}) + +minetest.register_craft({ + output = "mesecons_button:button_off 2", + recipe = { + {"group:mesecon_conductor_craftable","default:stone"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_button/sounds/mesecons_button_pop.ogg b/mods/minetest-mod-mesecons/mesecons_button/sounds/mesecons_button_pop.ogg new file mode 100644 index 0000000..9d56bb8 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_button/sounds/mesecons_button_pop.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_button/sounds/mesecons_button_push.ogg b/mods/minetest-mod-mesecons/mesecons_button/sounds/mesecons_button_push.ogg new file mode 100644 index 0000000..53d45c1 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_button/sounds/mesecons_button_push.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_off.png b/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_off.png new file mode 100644 index 0000000..0e3ff25 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_on.png b/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_on.png new file mode 100644 index 0000000..1d97464 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_sides.png b/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_sides.png new file mode 100644 index 0000000..9b79b57 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_button/textures/jeija_wall_button_sides.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_commandblock/depends.txt b/mods/minetest-mod-mesecons/mesecons_commandblock/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_commandblock/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_commandblock/init.lua b/mods/minetest-mod-mesecons/mesecons_commandblock/init.lua new file mode 100644 index 0000000..8fd23f6 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_commandblock/init.lua @@ -0,0 +1,195 @@ +minetest.register_chatcommand("say", { + params = "", + description = "Say as the server", + privs = {server=true}, + func = function(name, param) + minetest.chat_send_all(name .. ": " .. param) + end +}) + +minetest.register_chatcommand("tell", { + params = " ", + description = "Say to privately", + func = function(name, param) + local found, _, target, message = param:find("^([^%s]+)%s+(.*)$") + if found == nil then + minetest.chat_send_player(name, "Invalid usage: " .. param) + return + end + if not minetest.get_player_by_name(target) then + minetest.chat_send_player(name, "Invalid target: " .. target) + end + minetest.chat_send_player(target, name .. " whispers: " .. message, false) + end +}) + +minetest.register_chatcommand("hp", { + params = " ", + description = "Set health of to hitpoints", + privs = {ban=true}, + func = function(name, param) + local found, _, target, value = param:find("^([^%s]+)%s+(%d+)$") + if found == nil then + minetest.chat_send_player(name, "Invalid usage: " .. param) + return + end + local player = minetest.get_player_by_name(target) + if player then + player:set_hp(value) + else + minetest.chat_send_player(name, "Invalid target: " .. target) + end + end +}) + +local function initialize_data(meta) + local commands = meta:get_string("commands") + meta:set_string("formspec", + "invsize[9,5;]" .. + "textarea[0.5,0.5;8.5,4;commands;Commands;"..commands.."]" .. + "label[1,3.8;@nearest, @farthest, and @random are replaced by the respective player names]" .. + "button_exit[3.3,4.5;2,1;submit;Submit]") + local owner = meta:get_string("owner") + if owner == "" then + owner = "not owned" + else + owner = "owned by " .. owner + end + meta:set_string("infotext", "Command Block\n" .. + "(" .. owner .. ")\n" .. + "Commands: "..commands) +end + +local function construct(pos) + local meta = minetest.get_meta(pos) + + meta:set_string("commands", "tell @nearest Commandblock unconfigured") + + meta:set_string("owner", "") + + initialize_data(meta) +end + +local function after_place(pos, placer) + if placer then + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + initialize_data(meta) + end +end + +local function receive_fields(pos, formname, fields, sender) + if not fields.submit then + return + end + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + if owner ~= "" and sender:get_player_name() ~= owner then + return + end + meta:set_string("commands", fields.commands) + + initialize_data(meta) +end + +local function resolve_commands(commands, pos) + local nearest, farthest = nil, nil + local min_distance, max_distance = math.huge, -1 + local players = minetest.get_connected_players() + for index, player in pairs(players) do + local distance = vector.distance(pos, player:getpos()) + if distance < min_distance then + min_distance = distance + nearest = player:get_player_name() + end + if distance > max_distance then + max_distance = distance + farthest = player:get_player_name() + end + end + local random = players[math.random(#players)]:get_player_name() + commands = commands:gsub("@nearest", nearest) + commands = commands:gsub("@farthest", farthest) + commands = commands:gsub("@random", random) + return commands +end + +local function commandblock_action_on(pos, node) + if node.name ~= "mesecons_commandblock:commandblock_off" then + return + end + + minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"}) + + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + if owner == "" then + return + end + + local commands = resolve_commands(meta:get_string("commands"), pos) + for _, command in pairs(commands:split("\n")) do + local pos = command:find(" ") + local cmd, param = command, "" + if pos then + cmd = command:sub(1, pos - 1) + param = command:sub(pos + 1) + end + local cmddef = minetest.chatcommands[cmd] + if not cmddef then + minetest.chat_send_player(owner, "The command "..cmd.." does not exist") + return + end + local has_privs, missing_privs = minetest.check_player_privs(owner, cmddef.privs) + if not has_privs then + minetest.chat_send_player(owner, "You don't have permission " + .."to run "..cmd + .." (missing privileges: " + ..table.concat(missing_privs, ", ")..")") + return + end + cmddef.func(owner, param) + end +end + +local function commandblock_action_off(pos, node) + if node.name == "mesecons_commandblock:commandblock_on" then + minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_off"}) + end +end + +local function can_dig(pos, player) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + return owner == "" or owner == player:get_player_name() +end + +minetest.register_node("mesecons_commandblock:commandblock_off", { + description = "Command Block", + tiles = {"jeija_commandblock_off.png"}, + inventory_image = minetest.inventorycube("jeija_commandblock_off.png"), + groups = {cracky=2, mesecon_effector_off=1}, + on_construct = construct, + after_place_node = after_place, + on_receive_fields = receive_fields, + can_dig = can_dig, + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + action_on = commandblock_action_on + }} +}) + +minetest.register_node("mesecons_commandblock:commandblock_on", { + tiles = {"jeija_commandblock_on.png"}, + groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1}, + light_source = 10, + drop = "mesecons_commandblock:commandblock_off", + on_construct = construct, + after_place_node = after_place, + on_receive_fields = receive_fields, + can_dig = can_dig, + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + action_off = commandblock_action_off + }} +}) diff --git a/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_close_window.png b/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_close_window.png new file mode 100644 index 0000000..5c27c6c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_close_window.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_commandblock_off.png b/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_commandblock_off.png new file mode 100644 index 0000000..c05b616 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_commandblock_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_commandblock_on.png b/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_commandblock_on.png new file mode 100644 index 0000000..7fc35b6 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_commandblock/textures/jeija_commandblock_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_compatibility/depends.txt b/mods/minetest-mod-mesecons/mesecons_compatibility/depends.txt new file mode 100644 index 0000000..ed2fcd8 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_compatibility/depends.txt @@ -0,0 +1,2 @@ +mesecons +doors diff --git a/mods/minetest-mod-mesecons/mesecons_compatibility/init.lua b/mods/minetest-mod-mesecons/mesecons_compatibility/init.lua new file mode 100644 index 0000000..eebd740 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_compatibility/init.lua @@ -0,0 +1,191 @@ +doors = {} + +-- Registers a door - REDEFINITION ONLY | DOORS MOD MUST HAVE BEEN LOADED BEFORE +-- name: The name of the door +-- def: a table with the folowing fields: +-- description +-- inventory_image +-- groups +-- tiles_bottom: the tiles of the bottom part of the door {front, side} +-- tiles_top: the tiles of the bottom part of the door {front, side} +-- If the following fields are not defined the default values are used +-- node_box_bottom +-- node_box_top +-- selection_box_bottom +-- selection_box_top +-- only_placer_can_open: if true only the player who placed the door can +-- open it +local function is_right(pos) + local r1 = minetest.get_node({x=pos.x-1, y=pos.y, z=pos.z}) + local r2 = minetest.get_node({x=pos.x, y=pos.y, z=pos.z-1}) + if string.find(r1.name, "door_") or string.find(r2.name, "door_") then + if string.find(r1.name, "_1") or string.find(r2.name, "_1") then + return true + else + return false + end + end +end + +function doors:register_door(name, def) + def.groups.not_in_creative_inventory = 1 + + local box = {{-0.5, -0.5, -0.5, 0.5, 0.5, -0.5+1.5/16}} + + if not def.node_box_bottom then + def.node_box_bottom = box + end + if not def.node_box_top then + def.node_box_top = box + end + if not def.selection_box_bottom then + def.selection_box_bottom= box + end + if not def.selection_box_top then + def.selection_box_top = box + end + + local tt = def.tiles_top + local tb = def.tiles_bottom + + local function after_dig_node(pos, name) + if minetest.get_node(pos).name == name then + minetest.remove_node(pos) + end + end + + local function on_rightclick(pos, dir, check_name, replace, replace_dir, params) + pos.y = pos.y+dir + if not minetest.get_node(pos).name == check_name then + return + end + local p2 = minetest.get_node(pos).param2 + p2 = params[p2+1] + + local meta = minetest.get_meta(pos):to_table() + minetest.set_node(pos, {name=replace_dir, param2=p2}) + minetest.get_meta(pos):from_table(meta) + + pos.y = pos.y-dir + meta = minetest.get_meta(pos):to_table() + minetest.set_node(pos, {name=replace, param2=p2}) + minetest.get_meta(pos):from_table(meta) + + local snd_1 = "_close" + local snd_2 = "_open" + if params[1] == 3 then + snd_1 = "_open" + snd_2 = "_close" + end + + if is_right(pos) then + minetest.sound_play("door"..snd_1, {pos = pos, gain = 0.3, max_hear_distance = 10}) + else + minetest.sound_play("door"..snd_2, {pos = pos, gain = 0.3, max_hear_distance = 10}) + end + end + + local function on_mesecons_signal_open (pos, node) + on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0}) + end + + local function on_mesecons_signal_close (pos, node) + on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2}) + end + + local function check_player_priv(pos, player) + if not def.only_placer_can_open then + return true + end + local meta = minetest.get_meta(pos) + local pn = player:get_player_name() + return meta:get_string("doors_owner") == pn + end + + minetest.register_node(":"..name.."_b_1", { + tiles = {tb[2], tb[2], tb[2], tb[2], tb[1], tb[1].."^[transformfx"}, + paramtype = "light", + paramtype2 = "facedir", + drop = name, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = def.node_box_bottom + }, + selection_box = { + type = "fixed", + fixed = def.selection_box_bottom + }, + groups = def.groups, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + pos.y = pos.y+1 + after_dig_node(pos, name.."_t_1") + end, + + on_rightclick = function(pos, node, puncher) + if check_player_priv(pos, puncher) then + on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0}) + end + end, + + mesecons = {effector = { + action_on = on_mesecons_signal_open + }}, + + can_dig = check_player_priv, + }) + + minetest.register_node(":"..name.."_b_2", { + tiles = {tb[2], tb[2], tb[2], tb[2], tb[1].."^[transformfx", tb[1]}, + paramtype = "light", + paramtype2 = "facedir", + drop = name, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = def.node_box_bottom + }, + selection_box = { + type = "fixed", + fixed = def.selection_box_bottom + }, + groups = def.groups, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + pos.y = pos.y+1 + after_dig_node(pos, name.."_t_2") + end, + + on_rightclick = function(pos, node, puncher) + if check_player_priv(pos, puncher) then + on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2}) + end + end, + + mesecons = {effector = { + action_off = on_mesecons_signal_close + }}, + + can_dig = check_player_priv, + }) +end + +doors:register_door("doors:door_wood", { + description = "Wooden Door", + inventory_image = "doors_wood.png", + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=2,door=1}, + tiles_bottom = {"doors_wood_b.png", "doors_brown.png"}, + tiles_top = {"doors_wood_a.png", "doors_brown.png"}, + sounds = default.node_sound_wood_defaults(), +}) + +doors:register_door("doors:door_steel", { + description = "Steel Door", + inventory_image = "doors_steel.png", + groups = {snappy=1,bendy=2,cracky=1,melty=2,level=2,door=1}, + tiles_bottom = {"doors_steel_b.png", "doors_grey.png"}, + tiles_top = {"doors_steel_a.png", "doors_grey.png"}, + only_placer_can_open = true, + sounds = default.node_sound_stone_defaults(), +}) diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/depends.txt b/mods/minetest-mod-mesecons/mesecons_delayer/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_delayer/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/init.lua b/mods/minetest-mod-mesecons/mesecons_delayer/init.lua new file mode 100644 index 0000000..ba4067f --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_delayer/init.lua @@ -0,0 +1,179 @@ +-- Function that get the input/output rules of the delayer +local delayer_get_output_rules = function(node) + local rules = {{x = 0, y = 0, z = 1}} + for i = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local delayer_get_input_rules = function(node) + local rules = {{x = 0, y = 0, z = -1}} + for i = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +-- Functions that are called after the delay time + +local delayer_activate = function(pos, node) + local def = minetest.registered_nodes[node.name] + local time = def.delayer_time + minetest.swap_node(pos, {name = def.delayer_onstate, param2=node.param2}) + mesecon.queue:add_action(pos, "receptor_on", {delayer_get_output_rules(node)}, time, nil) +end + +local delayer_deactivate = function(pos, node) + local def = minetest.registered_nodes[node.name] + local time = def.delayer_time + minetest.swap_node(pos, {name = def.delayer_offstate, param2=node.param2}) + mesecon.queue:add_action(pos, "receptor_off", {delayer_get_output_rules(node)}, time, nil) +end + +-- Register the 2 (states) x 4 (delay times) delayers + +for i = 1, 4 do +local groups = {} +if i == 1 then + groups = {bendy=2,snappy=1,dig_immediate=2} +else + groups = {bendy=2,snappy=1,dig_immediate=2, not_in_creative_inventory=1} +end + +local delaytime +if i == 1 then delaytime = 0.1 +elseif i == 2 then delaytime = 0.3 +elseif i == 3 then delaytime = 0.5 +elseif i == 4 then delaytime = 1.0 end + +boxes = {{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab + + { -2/16, -7/16, -4/16, 2/16, -26/64, -3/16 }, -- the jeweled "on" indicator + { -3/16, -7/16, -3/16, 3/16, -26/64, -2/16 }, + { -4/16, -7/16, -2/16, 4/16, -26/64, 2/16 }, + { -3/16, -7/16, 2/16, 3/16, -26/64, 3/16 }, + { -2/16, -7/16, 3/16, 2/16, -26/64, 4/16 }, + + { -6/16, -7/16, -6/16, -4/16, -27/64, -4/16 }, -- the timer indicator + { -8/16, -8/16, -1/16, -6/16, -7/16, 1/16 }, -- the two wire stubs + { 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }} + +minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), { + description = "Delayer", + drawtype = "nodebox", + tiles = { + "mesecons_delayer_off_"..tostring(i)..".png", + "mesecons_delayer_bottom.png", + "mesecons_delayer_ends_off.png", + "mesecons_delayer_ends_off.png", + "mesecons_delayer_sides_off.png", + "mesecons_delayer_sides_off.png" + }, + inventory_image = "mesecons_delayer_off_1.png", + wield_image = "mesecons_delayer_off_1.png", + walkable = true, + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, + }, + node_box = { + type = "fixed", + fixed = boxes + }, + groups = groups, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + is_ground_content = true, + drop = 'mesecons_delayer:delayer_off_1', + on_punch = function (pos, node) + if node.name=="mesecons_delayer:delayer_off_1" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_2", param2=node.param2}) + elseif node.name=="mesecons_delayer:delayer_off_2" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_3", param2=node.param2}) + elseif node.name=="mesecons_delayer:delayer_off_3" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_4", param2=node.param2}) + elseif node.name=="mesecons_delayer:delayer_off_4" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_1", param2=node.param2}) + end + end, + delayer_time = delaytime, + delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i), + sounds = default.node_sound_stone_defaults(), + mesecons = { + receptor = + { + state = mesecon.state.off, + rules = delayer_get_output_rules + }, + effector = + { + rules = delayer_get_input_rules, + action_on = delayer_activate + } + } +}) + + +minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), { + description = "You hacker you", + drawtype = "nodebox", + tiles = { + "mesecons_delayer_on_"..tostring(i)..".png", + "mesecons_delayer_bottom.png", + "mesecons_delayer_ends_on.png", + "mesecons_delayer_ends_on.png", + "mesecons_delayer_sides_on.png", + "mesecons_delayer_sides_on.png" + }, + walkable = true, + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, + }, + node_box = { + type = "fixed", + fixed = boxes + }, + groups = {bendy = 2, snappy = 1, dig_immediate = 2, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + is_ground_content = true, + drop = 'mesecons_delayer:delayer_off_1', + on_punch = function (pos, node) + if node.name=="mesecons_delayer:delayer_on_1" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_2", param2=node.param2}) + elseif node.name=="mesecons_delayer:delayer_on_2" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_3", param2=node.param2}) + elseif node.name=="mesecons_delayer:delayer_on_3" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_4", param2=node.param2}) + elseif node.name=="mesecons_delayer:delayer_on_4" then + minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_1", param2=node.param2}) + end + end, + delayer_time = delaytime, + delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i), + mesecons = { + receptor = + { + state = mesecon.state.on, + rules = delayer_get_output_rules + }, + effector = + { + rules = delayer_get_input_rules, + action_off = delayer_deactivate + } + } +}) +end + +minetest.register_craft({ + output = "mesecons_delayer:delayer_off_1", + recipe = { + {"mesecons_torch:mesecon_torch_on", "group:mesecon_conductor_craftable", "mesecons_torch:mesecon_torch_on"}, + {"default:cobble","default:cobble", "default:cobble"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_bottom.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_bottom.png new file mode 100644 index 0000000..2e49d31 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_bottom.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_ends_off.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_ends_off.png new file mode 100644 index 0000000..0242deb Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_ends_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_ends_on.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_ends_on.png new file mode 100644 index 0000000..19ae0cb Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_ends_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_1.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_1.png new file mode 100644 index 0000000..7372b37 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_1.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_2.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_2.png new file mode 100644 index 0000000..e34f0ac Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_2.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_3.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_3.png new file mode 100644 index 0000000..091adbc Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_3.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_4.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_4.png new file mode 100644 index 0000000..7ecc9b6 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_off_4.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_1.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_1.png new file mode 100644 index 0000000..61f52f2 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_1.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_2.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_2.png new file mode 100644 index 0000000..7bd363f Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_2.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_3.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_3.png new file mode 100644 index 0000000..b93f725 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_3.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_4.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_4.png new file mode 100644 index 0000000..ca90a1e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_on_4.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_sides_off.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_sides_off.png new file mode 100644 index 0000000..79f3d59 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_sides_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_sides_on.png b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_sides_on.png new file mode 100644 index 0000000..1c8edaa Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_delayer/textures/mesecons_delayer_sides_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_detector/depends.txt b/mods/minetest-mod-mesecons/mesecons_detector/depends.txt new file mode 100644 index 0000000..bc7b062 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_detector/depends.txt @@ -0,0 +1,2 @@ +mesecons +mesecons_materials diff --git a/mods/minetest-mod-mesecons/mesecons_detector/init.lua b/mods/minetest-mod-mesecons/mesecons_detector/init.lua new file mode 100644 index 0000000..1a8595d --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_detector/init.lua @@ -0,0 +1,268 @@ +local GET_COMMAND = "GET" + +-- Object detector +-- Detects players in a certain radius +-- The radius can be specified in mesecons/settings.lua + +local object_detector_make_formspec = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", "size[9,2.5]" .. + "field[0.3, 0;9,2;scanname;Name of player to scan for (empty for any):;${scanname}]".. + "field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. + "button_exit[7,0.75;2,3;;Save]") +end + +local object_detector_on_receive_fields = function(pos, formname, fields) + if not fields.scanname or not fields.digiline_channel then return end; + + local meta = minetest.get_meta(pos) + meta:set_string("scanname", fields.scanname) + meta:set_string("digiline_channel", fields.digiline_channel) + object_detector_make_formspec(pos) +end + +-- returns true if player was found, false if not +local object_detector_scan = function (pos) + local objs = minetest.get_objects_inside_radius(pos, mesecon.setting("detector_radius", 6)) + for k, obj in pairs(objs) do + local isname = obj:get_player_name() -- "" is returned if it is not a player; "" ~= nil! + local scanname = minetest.get_meta(pos):get_string("scanname") + if (isname == scanname and isname ~= "") or (isname ~= "" and scanname == "") then -- player with scanname found or not scanname specified + return true + end + end + return false +end + +-- set player name when receiving a digiline signal on a specific channel +local object_detector_digiline = { + effector = { + action = function (pos, node, channel, msg) + local meta = minetest.get_meta(pos) + local active_channel = meta:get_string("digiline_channel") + if channel == active_channel then + meta:set_string("scanname", msg) + object_detector_make_formspec(pos) + end + end, + } +} + +minetest.register_node("mesecons_detector:object_detector_off", { + tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3}, + description="Player Detector", + mesecons = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = default.node_sound_stone_defaults(), + digiline = object_detector_digiline +}) + +minetest.register_node("mesecons_detector:object_detector_on", { + tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3,not_in_creative_inventory=1}, + drop = 'mesecons_detector:object_detector_off', + mesecons = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = default.node_sound_stone_defaults(), + digiline = object_detector_digiline +}) + +minetest.register_craft({ + output = 'mesecons_detector:object_detector_off', + recipe = { + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + {"default:steel_ingot", "mesecons_luacontroller:luacontroller0000", "default:steel_ingot"}, + {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"}, + } +}) + +minetest.register_abm( + {nodenames = {"mesecons_detector:object_detector_off"}, + interval = 1.0, + chance = 1, + action = function(pos) + if object_detector_scan(pos) then + minetest.swap_node(pos, {name = "mesecons_detector:object_detector_on"}) + mesecon.receptor_on(pos, mesecon.rules.pplate) + end + end, +}) + +minetest.register_abm( + {nodenames = {"mesecons_detector:object_detector_on"}, + interval = 1.0, + chance = 1, + action = function(pos) + if not object_detector_scan(pos) then + minetest.swap_node(pos, {name = "mesecons_detector:object_detector_off"}) + mesecon.receptor_off(pos, mesecon.rules.pplate) + end + end, +}) + +-- Node detector +-- Detects the node in front of it + +local node_detector_make_formspec = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", "size[9,2.5]" .. + "field[0.3, 0;9,2;scanname;Name of node to scan for (empty for any):;${scanname}]".. + "field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. + "button_exit[7,0.75;2,3;;Save]") +end + +local node_detector_on_receive_fields = function(pos, formname, fields) + if not fields.scanname or not fields.digiline_channel then return end; + + local meta = minetest.get_meta(pos) + meta:set_string("scanname", fields.scanname) + meta:set_string("digiline_channel", fields.digiline_channel) + node_detector_make_formspec(pos) +end + +-- returns true if player was found, false if not +local node_detector_scan = function (pos) + local node = minetest.get_node(pos) + local frontpos = vector.subtract(pos, minetest.facedir_to_dir(node.param2)) + local frontnode = minetest.get_node(frontpos) + local meta = minetest.get_meta(pos) + return (frontnode.name == meta:get_string("scanname")) or + (frontnode.name ~= "air" and frontnode.name ~= "ignore" and meta:get_string("scanname") == "") +end + +-- set player name when receiving a digiline signal on a specific channel +local node_detector_digiline = { + effector = { + action = function (pos, node, channel, msg) + local meta = minetest.get_meta(pos) + local active_channel = meta:get_string("digiline_channel") + if channel == active_channel then + if msg == GET_COMMAND then + local frontpos = vector.subtract(pos, minetest.facedir_to_dir(node.param2)) + local name = minetest.get_node(frontpos).name + digiline:receptor_send(pos, digiline.rules.default, channel, name) + else + meta:set_string("scanname", msg) + node_detector_make_formspec(pos) + end + end + end, + }, + receptor = {} +} + +minetest.register_node("mesecons_detector:node_detector_off", { + tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_off.png"}, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + groups = {cracky=3}, + description="Node Detector", + mesecons = {receptor = { + state = mesecon.state.off + }}, + on_construct = node_detector_make_formspec, + on_receive_fields = node_detector_on_receive_fields, + after_place_node = function (pos, placer) + local placer_pos = placer:getpos() + + --correct for the player's height + if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end + + --correct for 6d facedir + if placer_pos then + local dir = { + x = pos.x - placer_pos.x, + y = pos.y - placer_pos.y, + z = pos.z - placer_pos.z + } + local node = minetest.get_node(pos) + node.param2 = minetest.dir_to_facedir(dir, true) + minetest.set_node(pos, node) + minetest.log("action", "real (6d) facedir: " .. node.param2) + end + end, + sounds = default.node_sound_stone_defaults(), + digiline = node_detector_digiline +}) + +minetest.register_node("mesecons_detector:node_detector_on", { + tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_on.png"}, + paramtype = "light", + paramtype2 = "facedir", + walkable = true, + groups = {cracky=3,not_in_creative_inventory=1}, + drop = 'mesecons_detector:node_detector_off', + mesecons = {receptor = { + state = mesecon.state.on + }}, + on_construct = node_detector_make_formspec, + on_receive_fields = node_detector_on_receive_fields, + after_place_node = function (pos, placer) + local placer_pos = placer:getpos() + + --correct for the player's height + if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end + + --correct for 6d facedir + if placer_pos then + local dir = { + x = pos.x - placer_pos.x, + y = pos.y - placer_pos.y, + z = pos.z - placer_pos.z + } + local node = minetest.get_node(pos) + node.param2 = minetest.dir_to_facedir(dir, true) + minetest.set_node(pos, node) + minetest.log("action", "real (6d) facedir: " .. node.param2) + end + end, + sounds = default.node_sound_stone_defaults(), + digiline = node_detector_digiline +}) + +minetest.register_craft({ + output = 'mesecons_detector:node_detector_off', + recipe = { + {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"}, + {"default:steel_ingot", "mesecons_luacontroller:luacontroller0000", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + } +}) + +minetest.register_abm( + {nodenames = {"mesecons_detector:node_detector_off"}, + interval = 1.0, + chance = 1, + action = function(pos, node) + if node_detector_scan(pos) then + minetest.swap_node(pos, {name = "mesecons_detector:node_detector_on", param2 = node.param2}) + mesecon.receptor_on(pos) + end + end, +}) + +minetest.register_abm( + {nodenames = {"mesecons_detector:node_detector_on"}, + interval = 1.0, + chance = 1, + action = function(pos, node) + if not node_detector_scan(pos) then + minetest.swap_node(pos, {name = "mesecons_detector:node_detector_off", param2 = node.param2}) + mesecon.receptor_off(pos) + end + end, +}) diff --git a/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_node_detector_off.png b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_node_detector_off.png new file mode 100644 index 0000000..6d130ad Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_node_detector_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_node_detector_on.png b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_node_detector_on.png new file mode 100644 index 0000000..926a9d1 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_node_detector_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_object_detector_off.png b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_object_detector_off.png new file mode 100644 index 0000000..825d78f Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_object_detector_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_object_detector_on.png b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_object_detector_on.png new file mode 100644 index 0000000..96f8ba3 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_detector/textures/jeija_object_detector_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_extrawires/corner.lua b/mods/minetest-mod-mesecons/mesecons_extrawires/corner.lua new file mode 100644 index 0000000..003275a --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_extrawires/corner.lua @@ -0,0 +1,83 @@ +local corner_nodebox = { + type = "fixed", + fixed = {{ -16/32-0.001, -17/32, -3/32, 0, -13/32, 3/32 }, + { -3/32, -17/32, -16/32+0.001, 3/32, -13/32, 3/32}} +} + +local corner_selectionbox = { + type = "fixed", + fixed = { -16/32-0.001, -18/32, -16/32, 5/32, -12/32, 5/32 }, +} + +local corner_get_rules = function (node) + local rules = + {{x = 1, y = 0, z = 0}, + {x = 0, y = 0, z = -1}} + + for i = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + + return rules +end + +minetest.register_node("mesecons_extrawires:corner_on", { + drawtype = "nodebox", + tiles = { + "jeija_insulated_wire_curved_tb_on.png", + "jeija_insulated_wire_curved_tb_on.png^[transformR270", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png" + }, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + sunlight_propagates = true, + selection_box = corner_selectionbox, + node_box = corner_nodebox, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_extrawires:corner_off", + mesecons = {conductor = + { + state = mesecon.state.on, + rules = corner_get_rules, + offstate = "mesecons_extrawires:corner_off" + }} +}) + +minetest.register_node("mesecons_extrawires:corner_off", { + drawtype = "nodebox", + description = "Mesecon Corner", + tiles = { + "jeija_insulated_wire_curved_tb_off.png", + "jeija_insulated_wire_curved_tb_off.png^[transformR270", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png" + }, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + sunlight_propagates = true, + selection_box = corner_selectionbox, + node_box = corner_nodebox, + groups = {dig_immediate = 3}, + mesecons = {conductor = + { + state = mesecon.state.off, + rules = corner_get_rules, + onstate = "mesecons_extrawires:corner_on" + }} +}) + +minetest.register_craft({ + output = "mesecons_extrawires:corner_off 3", + recipe = { + {"", "", ""}, + {"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", ""}, + {"", "mesecons_insulated:insulated_off", ""}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_extrawires/crossover.lua b/mods/minetest-mod-mesecons/mesecons_extrawires/crossover.lua new file mode 100644 index 0000000..93b9638 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_extrawires/crossover.lua @@ -0,0 +1,176 @@ +function crossover_get_rules(node) + return { + {--first wire + {x=-1,y=0,z=0}, + {x=1,y=0,z=0}, + }, + {--second wire + {x=0,y=0,z=-1}, + {x=0,y=0,z=1}, + }, + } +end + +local crossover_states = { + "mesecons_extrawires:crossover_off", + "mesecons_extrawires:crossover_01", + "mesecons_extrawires:crossover_10", + "mesecons_extrawires:crossover_on", +} + +minetest.register_node("mesecons_extrawires:crossover_off", { + description = "Insulated Crossover", + drawtype = "nodebox", + tiles = { + "jeija_insulated_wire_crossing_tb_off.png", + "jeija_insulated_wire_crossing_tb_off.png", + "jeija_insulated_wire_ends_off.png" + }, + paramtype = "light", + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, + node_box = { + type = "fixed", + fixed = { + { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }, + { -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 }, + { -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 }, + { -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 }, + { -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 }, + { -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 }, + }, + }, + groups = {dig_immediate=3, mesecon=3, mesecon_conductor_craftable=1}, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_get_rules(), + } + }, +}) + +minetest.register_node("mesecons_extrawires:crossover_01", { + description = "You hacker you!", + drop = "mesecons_extrawires:crossover_off", + drawtype = "nodebox", + tiles = { + "jeija_insulated_wire_crossing_tb_01.png", + "jeija_insulated_wire_crossing_tb_01.png", + "jeija_insulated_wire_ends_01x.png", + "jeija_insulated_wire_ends_01x.png", + "jeija_insulated_wire_ends_01z.png", + "jeija_insulated_wire_ends_01z.png" + }, + paramtype = "light", + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, + node_box = { + type = "fixed", + fixed = { + { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }, + { -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 }, + { -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 }, + { -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 }, + { -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 }, + { -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 }, + }, + }, + groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_get_rules(), + } + }, +}) + +minetest.register_node("mesecons_extrawires:crossover_10", { + description = "You hacker you!", + drop = "mesecons_extrawires:crossover_off", + drawtype = "nodebox", + tiles = { + "jeija_insulated_wire_crossing_tb_10.png", + "jeija_insulated_wire_crossing_tb_10.png", + "jeija_insulated_wire_ends_10x.png", + "jeija_insulated_wire_ends_10x.png", + "jeija_insulated_wire_ends_10z.png", + "jeija_insulated_wire_ends_10z.png" + }, + paramtype = "light", + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, + node_box = { + type = "fixed", + fixed = { + { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }, + { -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 }, + { -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 }, + { -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 }, + { -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 }, + { -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 }, + }, + }, + groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_get_rules(), + } + }, +}) + +minetest.register_node("mesecons_extrawires:crossover_on", { + description = "You hacker you!", + drop = "mesecons_extrawires:crossover_off", + drawtype = "nodebox", + tiles = { + "jeija_insulated_wire_crossing_tb_on.png", + "jeija_insulated_wire_crossing_tb_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_ends_on.png" + }, + paramtype = "light", + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, + node_box = { + type = "fixed", + fixed = { + { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }, + { -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 }, + { -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 }, + { -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 }, + { -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 }, + { -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 }, + }, + }, + groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_get_rules(), + } + }, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_extrawires:crossover_off", + recipe = { + "mesecons_insulated:insulated_off", + "mesecons_insulated:insulated_off", + }, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_insulated:insulated_off 2", + recipe = { + "mesecons_extrawires:crossover_off", + }, +}) diff --git a/mods/minetest-mod-mesecons/mesecons_extrawires/depends.txt b/mods/minetest-mod-mesecons/mesecons_extrawires/depends.txt new file mode 100644 index 0000000..aca967d --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_extrawires/depends.txt @@ -0,0 +1,2 @@ +default +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_extrawires/init.lua b/mods/minetest-mod-mesecons/mesecons_extrawires/init.lua new file mode 100644 index 0000000..b22f2e5 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_extrawires/init.lua @@ -0,0 +1,5 @@ +dofile(minetest.get_modpath("mesecons_extrawires").."/crossover.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/tjunction.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/corner.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/vertical.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/mesewire.lua"); diff --git a/mods/minetest-mod-mesecons/mesecons_extrawires/mesewire.lua b/mods/minetest-mod-mesecons/mesecons_extrawires/mesewire.lua new file mode 100644 index 0000000..150178c --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_extrawires/mesewire.lua @@ -0,0 +1,30 @@ +local mesewire_rules = +{ + {x = 1, y = 0, z = 0}, + {x =-1, y = 0, z = 0}, + {x = 0, y = 1, z = 0}, + {x = 0, y =-1, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 0, y = 0, z =-1}, +} + +minetest.override_item("default:mese", { + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:mese_powered", + rules = mesewire_rules + }} +}) + +minetest.register_node("mesecons_extrawires:mese_powered", { + tiles = {minetest.registered_nodes["default:mese"].tiles[1].."^[brighten"}, + is_ground_content = true, + groups = {cracky=1, not_in_creative_inventory = 1}, + sounds = default.node_sound_stone_defaults(), + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "default:mese", + rules = mesewire_rules + }}, + drop = "default:mese" +}) diff --git a/mods/minetest-mod-mesecons/mesecons_extrawires/tjunction.lua b/mods/minetest-mod-mesecons/mesecons_extrawires/tjunction.lua new file mode 100644 index 0000000..680dc99 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_extrawires/tjunction.lua @@ -0,0 +1,84 @@ +local tjunction_nodebox = { + type = "fixed", + fixed = {{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }, + { -3/32, -17/32, -16/32+0.001, 3/32, -13/32, -3/32},} +} + +local tjunction_selectionbox = { + type = "fixed", + fixed = { -16/32-0.001, -18/32, -16/32, 16/32+0.001, -12/32, 7/32 }, +} + +local tjunction_get_rules = function (node) + local rules = + {{x = 0, y = 0, z = 1}, + {x = 1, y = 0, z = 0}, + {x = 0, y = 0, z = -1}} + + for i = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + + return rules +end + +minetest.register_node("mesecons_extrawires:tjunction_on", { + drawtype = "nodebox", + tiles = { + "jeija_insulated_wire_tjunction_tb_on.png", + "jeija_insulated_wire_tjunction_tb_on.png^[transformR180", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png" + }, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + sunlight_propagates = true, + selection_box = tjunction_selectionbox, + node_box = tjunction_nodebox, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_extrawires:tjunction_off", + mesecons = {conductor = + { + state = mesecon.state.on, + rules = tjunction_get_rules, + offstate = "mesecons_extrawires:tjunction_off" + }} +}) + +minetest.register_node("mesecons_extrawires:tjunction_off", { + drawtype = "nodebox", + description = "T-junction", + tiles = { + "jeija_insulated_wire_tjunction_tb_off.png", + "jeija_insulated_wire_tjunction_tb_off.png^[transformR180", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png" + }, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + sunlight_propagates = true, + selection_box = tjunction_selectionbox, + node_box = tjunction_nodebox, + groups = {dig_immediate = 3, mesecon_conductor_craftable=1}, + mesecons = {conductor = + { + state = mesecon.state.off, + rules = tjunction_get_rules, + onstate = "mesecons_extrawires:tjunction_on" + }} +}) + +minetest.register_craft({ + output = "mesecons_extrawires:tjunction_off 3", + recipe = { + {"", "", ""}, + {"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"}, + {"", "mesecons_insulated:insulated_off", ""}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_extrawires/vertical.lua b/mods/minetest-mod-mesecons/mesecons_extrawires/vertical.lua new file mode 100644 index 0000000..cac2ae2 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_extrawires/vertical.lua @@ -0,0 +1,183 @@ +local vertical_box = { + type = "fixed", + fixed = {-1/16, -8/16, -1/16, 1/16, 8/16, 1/16} +} + +local top_box = { + type = "fixed", + fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}} +} + +local bottom_box = { + type = "fixed", + fixed = { + {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, + {-1/16, -7/16, -1/16, 1/16, 8/16, 1/16}, + } +} + +local vertical_rules = { + {x=0, y=1, z=0}, + {x=0, y=-1, z=0} +} + +local top_rules = { + {x=1,y=0, z=0}, + {x=-1,y=0, z=0}, + {x=0,y=0, z=1}, + {x=0,y=0, z=-1}, + {x=0,y=-1, z=0} +} + +local bottom_rules = { + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=0, y=0, z=-1}, + {x=0, y=1, z=0}, + {x=0, y=2, z=0} -- receive power from pressure plate / detector / ... 2 nodes above +} + +local vertical_updatepos = function (pos) + local node = minetest.get_node(pos) + if minetest.registered_nodes[node.name] + and minetest.registered_nodes[node.name].is_vertical_conductor then + local node_above = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[1])) + local node_below = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[2])) + local namestate = minetest.registered_nodes[node.name].vertical_conductor_state + + local above = minetest.registered_nodes[node_above.name] + and minetest.registered_nodes[node_above.name].is_vertical_conductor + local below = minetest.registered_nodes[node_below.name] + and minetest.registered_nodes[node_below.name].is_vertical_conductor + + local basename = "mesecons_extrawires:vertical_" + if above and below then -- above and below: vertical mesecon + minetest.add_node(pos, {name = basename .. namestate}) + elseif above and not below then -- above only: bottom + minetest.add_node(pos, {name = basename .. "bottom_" .. namestate}) + elseif not above and below then -- below only: top + minetest.add_node(pos, {name = basename .. "top_" .. namestate}) + else -- no vertical wire above, no vertical wire below: use bottom + minetest.add_node(pos, {name = basename .. "bottom_" .. namestate}) + end + mesecon.update_autoconnect(pos) + end +end + +local vertical_update = function (pos, node) + vertical_updatepos(pos) -- this one + vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[1])) -- above + vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[2])) -- below +end + +-- Vertical wire +mesecon.register_node("mesecons_extrawires:vertical", { + description = "Vertical mesecon", + drawtype = "nodebox", + walkable = false, + paramtype = "light", + sunlight_propagates = true, + selection_box = vertical_box, + node_box = vertical_box, + is_vertical_conductor = true, + drop = "mesecons_extrawires:vertical_off", + after_place_node = vertical_update, + after_dig_node = vertical_update +},{ + tiles = {"mesecons_wire_off.png"}, + groups = {dig_immediate=3}, + vertical_conductor_state = "off", + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:vertical_on", + rules = vertical_rules, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + groups = {dig_immediate=3, not_in_creative_inventory=1}, + vertical_conductor_state = "on", + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_off", + rules = vertical_rules, + }} +}) + +-- Vertical wire top +mesecon.register_node("mesecons_extrawires:vertical_top", { + description = "Vertical mesecon", + drawtype = "nodebox", + walkable = false, + paramtype = "light", + sunlight_propagates = true, + groups = {dig_immediate=3, not_in_creative_inventory=1}, + selection_box = top_box, + node_box = top_box, + is_vertical_conductor = true, + drop = "mesecons_extrawires:vertical_off", + after_place_node = vertical_update, + after_dig_node = vertical_update +},{ + tiles = {"mesecons_wire_off.png"}, + vertical_conductor_state = "off", + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:vertical_top_on", + rules = top_rules, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + vertical_conductor_state = "on", + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_top_off", + rules = top_rules, + }} +}) + +-- Vertical wire bottom +mesecon.register_node("mesecons_extrawires:vertical_bottom", { + description = "Vertical mesecon", + drawtype = "nodebox", + walkable = false, + paramtype = "light", + sunlight_propagates = true, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + selection_box = bottom_box, + node_box = bottom_box, + is_vertical_conductor = true, + drop = "mesecons_extrawires:vertical_off", + after_place_node = vertical_update, + after_dig_node = vertical_update +},{ + tiles = {"mesecons_wire_off.png"}, + vertical_conductor_state = "off", + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:vertical_bottom_on", + rules = bottom_rules, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + vertical_conductor_state = "on", + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_bottom_off", + rules = bottom_rules, + }} +}) + +minetest.register_craft({ + output = "mesecons_extrawires:vertical_off 3", + recipe = { + {"mesecons:wire_00000000_off"}, + {"mesecons:wire_00000000_off"}, + {"mesecons:wire_00000000_off"} + } +}) + +minetest.register_craft({ + output = "mesecons:wire_00000000_off", + recipe = {{"mesecons_extrawires:vertical_off"}} +}) diff --git a/mods/minetest-mod-mesecons/mesecons_gates/depends.txt b/mods/minetest-mod-mesecons/mesecons_gates/depends.txt new file mode 100644 index 0000000..f3e0392 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_gates/depends.txt @@ -0,0 +1,6 @@ +mesecons +mesecons_microcontroller +mesecons_delayer + +mesecons_torch +mesecons_materials diff --git a/mods/minetest-mod-mesecons/mesecons_gates/init.lua b/mods/minetest-mod-mesecons/mesecons_gates/init.lua new file mode 100644 index 0000000..78a3e83 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_gates/init.lua @@ -0,0 +1,124 @@ +local nodebox = { + type = "fixed", + fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }}, +} + +local function gate_rotate_rules(node, rules) + for rotations = 0, node.param2 - 1 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local function gate_get_output_rules(node) + return gate_rotate_rules(node, {{x=1, y=0, z=0}}) +end + +local function gate_get_input_rules_oneinput(node) + return gate_rotate_rules(node, {{x=-1, y=0, z=0}}) +end + +local function gate_get_input_rules_twoinputs(node) + return gate_rotate_rules(node, {{x=0, y=0, z=1, name="input1"}, + {x=0, y=0, z=-1, name="input2"}}) +end + +local function set_gate(pos, node, state) + local gate = minetest.registered_nodes[node.name] + + if mesecon.do_overheat(pos) then + minetest.remove_node(pos) + mesecon.receptor_off(pos, gate_get_output_rules(node)) + minetest.add_item(pos, gate.drop) + elseif state then + minetest.swap_node(pos, {name = gate.onstate, param2=node.param2}) + mesecon.receptor_on(pos, gate_get_output_rules(node)) + else + minetest.swap_node(pos, {name = gate.offstate, param2=node.param2}) + mesecon.receptor_off(pos, gate_get_output_rules(node)) + end +end + +local function update_gate(pos, node, link, newstate) + local gate = minetest.registered_nodes[node.name] + + if gate.inputnumber == 1 then + set_gate(pos, node, gate.assess(newstate == "on")) + elseif gate.inputnumber == 2 then + local meta = minetest.get_meta(pos) + meta:set_int(link.name, newstate == "on" and 1 or 0) + + local val1 = meta:get_int("input1") == 1 + local val2 = meta:get_int("input2") == 1 + set_gate(pos, node, gate.assess(val1, val2)) + end +end + +function register_gate(name, inputnumber, assess, recipe) + local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or + gate_get_input_rules_oneinput + local description = "Mesecons Logic Gate: "..name + + local basename = "mesecons_gates:"..name + mesecon.register_node(basename, { + description = description, + inventory_image = "jeija_gate_off.png^jeija_gate_"..name..".png", + paramtype = "light", + paramtype2 = "facedir", + drawtype = "nodebox", + drop = basename.."_off", + selection_box = nodebox, + node_box = nodebox, + walkable = true, + sounds = default.node_sound_stone_defaults(), + assess = assess, + onstate = basename.."_on", + offstate = basename.."_off", + inputnumber = inputnumber + },{ + tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^".. + "jeija_gate_"..name..".png"}, + groups = {dig_immediate = 2, overheat = 1}, + mesecons = { receptor = { + state = "off", + rules = gate_get_output_rules + }, effector = { + rules = get_inputrules, + action_change = update_gate + }} + },{ + tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^".. + "jeija_gate_"..name..".png"}, + groups = {dig_immediate = 2, not_in_creative_inventory = 1, overheat = 1}, + mesecons = { receptor = { + state = "on", + rules = gate_get_output_rules + }, effector = { + rules = get_inputrules, + action_change = update_gate + }} + }) + + minetest.register_craft({output = basename.."_off", recipe = recipe}) +end + +register_gate("diode", 1, function (input) return input end, + {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons_torch:mesecon_torch_on"}}) + +register_gate("not", 1, function (input) return not input end, + {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons:mesecon"}}) + +register_gate("and", 2, function (val1, val2) return val1 and val2 end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons:mesecon"}, + {"mesecons:mesecon", "", ""}}) + +register_gate("nand", 2, function (val1, val2) return not (val1 and val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons_torch:mesecon_torch_on"}, + {"mesecons:mesecon", "", ""}}) + +register_gate("xor", 2, function (val1, val2) return (val1 or val2) and not (val1 and val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons_materials:silicon"}, + {"mesecons:mesecon", "", ""}}) diff --git a/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_and.png b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_and.png new file mode 100644 index 0000000..0ddc043 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_and.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_diode.png b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_diode.png new file mode 100644 index 0000000..ffa403f Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_diode.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_nand.png b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_nand.png new file mode 100644 index 0000000..0e4294e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_nand.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_not.png b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_not.png new file mode 100644 index 0000000..939fb76 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_not.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_off.png b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_off.png new file mode 100644 index 0000000..44017b0 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_on.png b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_on.png new file mode 100644 index 0000000..47028a8 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_xor.png b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_xor.png new file mode 100644 index 0000000..afbd6ab Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_gates/textures/jeija_gate_xor.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_hydroturbine/depends.txt b/mods/minetest-mod-mesecons/mesecons_hydroturbine/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_hydroturbine/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_hydroturbine/init.lua b/mods/minetest-mod-mesecons/mesecons_hydroturbine/init.lua new file mode 100644 index 0000000..36bd498 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_hydroturbine/init.lua @@ -0,0 +1,96 @@ +-- HYDRO_TURBINE +-- Water turbine: +-- Active if flowing >water< above it +-- (does not work with other liquids) + +minetest.register_node("mesecons_hydroturbine:hydro_turbine_off", { + drawtype = "nodebox", + tiles = {"jeija_hydro_turbine_off.png"}, + groups = {dig_immediate=2}, + description="Water Turbine", + paramtype = "light", + selection_box = { + type = "fixed", + fixed = {{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + {-0.15, 0.5, -0.15, 0.15, 1.45, 0.15}, + {-0.45, 1.15, -0.1, 0.45, 1.45, 0.1}, + {-0.1, 1.15, -0.45, 0.1, 1.45, 0.45}}, + }, + node_box = { + type = "fixed", + fixed = {{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + {-0.15, 0.5, -0.15, 0.15, 1.45, 0.15}, + {-0.45, 1.15, -0.1, 0.45, 1.45, 0.1}, + {-0.1, 1.15, -0.45, 0.1, 1.45, 0.45}}, + }, + sounds = default.node_sound_stone_defaults(), + mesecons = {receptor = { + state = mesecon.state.off + }} +}) + +minetest.register_node("mesecons_hydroturbine:hydro_turbine_on", { + drawtype = "nodebox", + tiles = {"jeija_hydro_turbine_on.png"}, + drop = "mesecons_hydroturbine:hydro_turbine_off 1", + groups = {dig_immediate=2,not_in_creative_inventory=1}, + description="Water Turbine", + paramtype = "light", + selection_box = { + type = "fixed", + fixed = {{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + {-0.15, 0.5, -0.15, 0.15, 1.45, 0.15}, + {-0.5, 1.15, -0.1, 0.5, 1.45, 0.1}, + {-0.1, 1.15, -0.5, 0.1, 1.45, 0.5}}, + }, + node_box = { + type = "fixed", + fixed = {{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + {-0.15, 0.5, -0.15, 0.15, 1.45, 0.15}, + {-0.5, 1.15, -0.1, 0.5, 1.45, 0.1}, + {-0.1, 1.15, -0.5, 0.1, 1.45, 0.5}}, + }, + sounds = default.node_sound_stone_defaults(), + mesecons = {receptor = { + state = mesecon.state.on + }} +}) + + +minetest.register_abm({ +nodenames = {"mesecons_hydroturbine:hydro_turbine_off"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local waterpos={x=pos.x, y=pos.y+1, z=pos.z} + if minetest.get_node(waterpos).name=="default:water_flowing" then + minetest.add_node(pos, {name="mesecons_hydroturbine:hydro_turbine_on"}) + nodeupdate(pos) + mesecon.receptor_on(pos) + end + end, +}) + +minetest.register_abm({ +nodenames = {"mesecons_hydroturbine:hydro_turbine_on"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local waterpos={x=pos.x, y=pos.y+1, z=pos.z} + if minetest.get_node(waterpos).name~="default:water_flowing" then + minetest.add_node(pos, {name="mesecons_hydroturbine:hydro_turbine_off"}) + nodeupdate(pos) + mesecon.receptor_off(pos) + end + end, +}) + +minetest.register_craft({ + output = "mesecons_hydroturbine:hydro_turbine_off 2", + recipe = { + {"","default:stick", ""}, + {"default:stick", "default:steel_ingot", "default:stick"}, + {"","default:stick", ""}, + } +}) + diff --git a/mods/minetest-mod-mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_off.png b/mods/minetest-mod-mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_off.png new file mode 100644 index 0000000..5ca1a12 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_on.png b/mods/minetest-mod-mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_on.png new file mode 100644 index 0000000..28eb0c9 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/depends.txt b/mods/minetest-mod-mesecons/mesecons_insulated/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_insulated/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/init.lua b/mods/minetest-mod-mesecons/mesecons_insulated/init.lua new file mode 100644 index 0000000..c6fc05e --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_insulated/init.lua @@ -0,0 +1,80 @@ +function insulated_wire_get_rules(node) + local rules = {{x = 1, y = 0, z = 0}, + {x =-1, y = 0, z = 0}} + if node.param2 == 1 or node.param2 == 3 then + return mesecon.rotate_rules_right(rules) + end + return rules +end + +minetest.register_node("mesecons_insulated:insulated_on", { + drawtype = "nodebox", + description = "Insulated Mesecon", + tiles = { + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_sides_on.png" + }, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -16/32-0.001, -18/32, -7/32, 16/32+0.001, -12/32, 7/32 } + }, + node_box = { + type = "fixed", + fixed = { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 } + }, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_insulated:insulated_off", + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_insulated:insulated_off", + rules = insulated_wire_get_rules + }} +}) + +minetest.register_node("mesecons_insulated:insulated_off", { + drawtype = "nodebox", + description = "Insulated Mesecon", + tiles = { + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_sides_off.png" + }, + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -16/32-0.001, -18/32, -7/32, 16/32+0.001, -12/32, 7/32 } + }, + node_box = { + type = "fixed", + fixed = { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 } + }, + groups = {dig_immediate = 3}, + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_insulated:insulated_on", + rules = insulated_wire_get_rules + }} +}) + +minetest.register_craft({ + output = "mesecons_insulated:insulated_off 3", + recipe = { + {"mesecons_materials:fiber", "mesecons_materials:fiber", "mesecons_materials:fiber"}, + {"mesecons:wire_00000000_off", "mesecons:wire_00000000_off", "mesecons:wire_00000000_off"}, + {"mesecons_materials:fiber", "mesecons_materials:fiber", "mesecons_materials:fiber"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_01.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_01.png new file mode 100644 index 0000000..d872b2b Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_01.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_10.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_10.png new file mode 100644 index 0000000..ae06dea Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_10.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_off.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_off.png new file mode 100644 index 0000000..41b5ff4 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_on.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_on.png new file mode 100644 index 0000000..154288b Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_crossing_tb_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_curved_tb_off.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_curved_tb_off.png new file mode 100644 index 0000000..85ca90b Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_curved_tb_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_curved_tb_on.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_curved_tb_on.png new file mode 100644 index 0000000..772d9a6 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_curved_tb_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_01x.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_01x.png new file mode 100644 index 0000000..b742152 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_01x.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_01z.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_01z.png new file mode 100644 index 0000000..497a467 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_01z.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_10x.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_10x.png new file mode 100644 index 0000000..d407cff Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_10x.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_10z.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_10z.png new file mode 100644 index 0000000..830d390 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_10z.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_off.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_off.png new file mode 100644 index 0000000..89a8385 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_on.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_on.png new file mode 100644 index 0000000..75cf435 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_off.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_off.png new file mode 100644 index 0000000..db33f14 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_on.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_on.png new file mode 100644 index 0000000..f76e9a8 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_off.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_off.png new file mode 100644 index 0000000..a897b29 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_on.png b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_on.png new file mode 100644 index 0000000..8fc312b Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lamp/depends.txt b/mods/minetest-mod-mesecons/mesecons_lamp/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_lamp/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_lamp/init.lua b/mods/minetest-mod-mesecons/mesecons_lamp/init.lua new file mode 100644 index 0000000..6cdae2d --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_lamp/init.lua @@ -0,0 +1,61 @@ +-- MESELAMPS +-- A lamp is "is an electrical device used to create artificial light" (wikipedia) +-- guess what? + +mesecon_lamp_box = { + type = "wallmounted", + wall_top = {-0.3125,0.375,-0.3125,0.3125,0.5,0.3125}, + wall_bottom = {-0.3125,-0.5,-0.3125,0.3125,-0.375,0.3125}, + wall_side = {-0.375,-0.3125,-0.3125,-0.5,0.3125,0.3125}, +} + +minetest.register_node("mesecons_lamp:lamp_on", { + drawtype = "nodebox", + tiles = {"jeija_meselamp_on.png"}, + paramtype = "light", + paramtype2 = "wallmounted", + legacy_wallmounted = true, + sunlight_propagates = true, + walkable = true, + light_source = LIGHT_MAX, + node_box = mesecon_lamp_box, + selection_box = mesecon_lamp_box, + groups = {dig_immediate=3,not_in_creative_inventory=1, mesecon_effector_on = 1}, + drop="mesecons_lamp:lamp_off 1", + sounds = default.node_sound_glass_defaults(), + mesecons = {effector = { + action_off = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lamp:lamp_off", param2 = node.param2}) + end + }} +}) + +minetest.register_node("mesecons_lamp:lamp_off", { + drawtype = "nodebox", + tiles = {"jeija_meselamp_off.png"}, + inventory_image = "jeija_meselamp.png", + wield_image = "jeija_meselamp.png", + paramtype = "light", + paramtype2 = "wallmounted", + sunlight_propagates = true, + walkable = true, + node_box = mesecon_lamp_box, + selection_box = mesecon_lamp_box, + groups = {dig_immediate=3, mesecon_receptor_off = 1, mesecon_effector_off = 1}, + description="Meselamp", + sounds = default.node_sound_glass_defaults(), + mesecons = {effector = { + action_on = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lamp:lamp_on", param2 = node.param2}) + end + }} +}) + +minetest.register_craft({ + output = "mesecons_lamp:lamp_off 1", + recipe = { + {"", "default:glass", ""}, + {"group:mesecon_conductor_craftable", "default:steel_ingot", "group:mesecon_conductor_craftable"}, + {"", "default:glass", ""}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp.png b/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp.png new file mode 100644 index 0000000..5456ee9 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp_off.png b/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp_off.png new file mode 100644 index 0000000..67bd7fd Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp_on.png b/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp_on.png new file mode 100644 index 0000000..2316e00 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lamp/textures/jeija_meselamp_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/depends.txt b/mods/minetest-mod-mesecons/mesecons_lightstone/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_lightstone/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/init.lua b/mods/minetest-mod-mesecons/mesecons_lightstone/init.lua new file mode 100644 index 0000000..5ed8f15 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_lightstone/init.lua @@ -0,0 +1,60 @@ +local lightstone_rules = { + {x=0, y=0, z=-1}, + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=1, y=1, z=0}, + {x=1, y=-1, z=0}, + {x=-1, y=1, z=0}, + {x=-1, y=-1, z=0}, + {x=0, y=1, z=1}, + {x=0, y=-1, z=1}, + {x=0, y=1, z=-1}, + {x=0, y=-1, z=-1}, + {x=0, y=-1, z=0}, +} + +function mesecon.lightstone_add(name, base_item, texture_off, texture_on) + minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_off", { + tiles = {texture_off}, + groups = {cracky=2, mesecon_effector_off = 1, mesecon = 2}, + description=name.." Lightstone", + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + rules = lightstone_rules, + action_on = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_on", param2 = node.param2}) + end, + }} + }) + minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_on", { + tiles = {texture_on}, + groups = {cracky=2,not_in_creative_inventory=1, mesecon = 2}, + drop = "mesecons_lightstone:lightstone_" .. name .. "_off", + light_source = LIGHT_MAX-2, + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + rules = lightstone_rules, + action_off = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_off", param2 = node.param2}) + end, + }} + }) + + minetest.register_craft({ + output = "mesecons_lightstone:lightstone_" .. name .. "_off", + recipe = { + {"",base_item,""}, + {base_item,"default:torch",base_item}, + {"","group:mesecon_conductor_craftable",""} + } + }) +end + + +mesecon.lightstone_add("red", "default:clay_brick", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png") +mesecon.lightstone_add("green", "default:cactus", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png") +mesecon.lightstone_add("blue", "mesecons_materials:fiber", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png") +mesecon.lightstone_add("gray", "default:cobble", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png") +mesecon.lightstone_add("darkgray", "default:gravel", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png") +mesecon.lightstone_add("yellow", "default:mese_crystal_fragment", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png") diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_off.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_off.png new file mode 100644 index 0000000..09acc22 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_on.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_on.png new file mode 100644 index 0000000..93c8638 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_off.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_off.png new file mode 100644 index 0000000..7e5aae7 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_on.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_on.png new file mode 100644 index 0000000..e6d4d00 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_off.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_off.png new file mode 100644 index 0000000..f168fc2 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_on.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_on.png new file mode 100644 index 0000000..24c5470 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_green_off.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_green_off.png new file mode 100644 index 0000000..2f214fa Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_green_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_green_on.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_green_on.png new file mode 100644 index 0000000..225bf4e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_green_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_red_off.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_red_off.png new file mode 100644 index 0000000..3c828b2 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_red_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_red_on.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_red_on.png new file mode 100644 index 0000000..512b0fe Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_red_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_off.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_off.png new file mode 100644 index 0000000..2e7fed0 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_on.png b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_on.png new file mode 100644 index 0000000..8943aca Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/depends.txt b/mods/minetest-mod-mesecons/mesecons_luacontroller/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_luacontroller/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/init.lua b/mods/minetest-mod-mesecons/mesecons_luacontroller/init.lua new file mode 100644 index 0000000..df681d9 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_luacontroller/init.lua @@ -0,0 +1,630 @@ +-- ______ +-- | +-- | +-- | __ ___ _ __ _ _ +-- | | | | | |\ | | |_| | | | | |_ |_| +-- |___| |______ |__| | \| | | \ |__| |_ |_ |_ |\ +-- | +-- | +-- + +-- Reference +-- ports = get_real_port_states(pos): gets if inputs are powered from outside +-- newport = merge_port_states(state1, state2): just does result = state1 or state2 for every port +-- set_port(pos, rule, state): activates/deactivates the mesecons according to the port states +-- set_port_states(pos, ports): Applies new port states to a LuaController at pos +-- run(pos): runs the code in the controller at pos +-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error messages +-- resetn(pos): performs a hardware reset, turns off all ports +-- +-- The Sandbox +-- The whole code of the controller runs in a sandbox, +-- a very restricted environment. +-- However, as this does not prevent you from using e.g. loops, +-- we need to check for these prohibited commands first. +-- Actually the only way to damage the server is to +-- use too much memory from the sandbox. +-- You can add more functions to the environment +-- (see where local env is defined) +-- Something nice to play is is appending minetest.env to it. + +local BASENAME = "mesecons_luacontroller:luacontroller" + +local rules = { + a = {x = -1, y = 0, z = 0, name="A"}, + b = {x = 0, y = 0, z = 1, name="B"}, + c = {x = 1, y = 0, z = 0, name="C"}, + d = {x = 0, y = 0, z = -1, name="D"}, +} + + +------------------ +-- Action stuff -- +------------------ +-- These helpers are required to set the port states of the luacontroller + +local function update_real_port_states(pos, rule_name, new_state) + local meta = minetest.get_meta(pos) + if rule_name == nil then + meta:set_int("real_portstates", 1) + return + end + local n = meta:get_int("real_portstates") - 1 + local L = {} + for i = 1, 4 do + L[i] = n % 2 + n = math.floor(n / 2) + end + -- (0,-1) (-1,0) (1,0) (0,1) + local pos_to_side = { 4, 1, nil, 3, 2 } + if rule_name.x == nil then + for _, rname in ipairs(rule_name) do + local port = pos_to_side[rname.x + (2 * rname.z) + 3] + L[port] = (newstate == "on") and 1 or 0 + end + else + local port = pos_to_side[rule_name.x + (2 * rule_name.z) + 3] + L[port] = (new_state == "on") and 1 or 0 + end + meta:set_int("real_portstates", + 1 + + 1 * L[1] + + 2 * L[2] + + 4 * L[3] + + 8 * L[4]) +end + + +local port_names = {"a", "b", "c", "d"} + +local function get_real_port_states(pos) + -- Determine if ports are powered (by itself or from outside) + local meta = minetest.get_meta(pos) + local L = {} + local n = meta:get_int("real_portstates") - 1 + for _, name in ipairs(port_names) do + L[name] = ((n % 2) == 1) + n = math.floor(n / 2) + end + return L +end + + +local function merge_port_states(ports, vports) + return { + a = ports.a or vports.a, + b = ports.b or vports.b, + c = ports.c or vports.c, + d = ports.d or vports.d, + } +end + +local function generate_name(ports) + local d = ports.d and 1 or 0 + local c = ports.c and 1 or 0 + local b = ports.b and 1 or 0 + local a = ports.a and 1 or 0 + return BASENAME..d..c..b..a +end + + +local function set_port(pos, rule, state) + if state then + mesecon.receptor_on(pos, {rule}) + else + mesecon.receptor_off(pos, {rule}) + end +end + + +local function clean_port_states(ports) + ports.a = ports.a and true or false + ports.b = ports.b and true or false + ports.c = ports.c and true or false + ports.d = ports.d and true or false +end + + +local function set_port_states(pos, ports) + local node = minetest.get_node(pos) + local name = node.name + clean_port_states(ports) + local vports = minetest.registered_nodes[name].virtual_portstates + local new_name = generate_name(ports) + + if name ~= new_name and vports then + -- Problem: + -- We need to place the new node first so that when turning + -- off some port, it won't stay on because the rules indicate + -- there is an onstate output port there. + -- When turning the output off then, it will however cause feedback + -- so that the luacontroller will receive an "off" event by turning + -- its output off. + -- Solution / Workaround: + -- Remember which output was turned off and ignore next "off" event. + local meta = minetest.get_meta(pos) + local ign = minetest.deserialize(meta:get_string("ignore_offevents")) or {} + if ports.a and not vports.a and not mesecon.is_powered(pos, rules.a) then ign.A = true end + if ports.b and not vports.b and not mesecon.is_powered(pos, rules.b) then ign.B = true end + if ports.c and not vports.c and not mesecon.is_powered(pos, rules.c) then ign.C = true end + if ports.d and not vports.d and not mesecon.is_powered(pos, rules.d) then ign.D = true end + meta:set_string("ignore_offevents", minetest.serialize(ign)) + + minetest.swap_node(pos, {name = new_name, param2 = node.param2}) + + if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end + if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end + if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end + if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end + end +end + + +----------------- +-- Overheating -- +----------------- + +local function overheat_off(pos) + mesecon.receptor_off(pos, mesecon.rules.flat) +end + + +local function overheat(pos, meta) + if mesecon.do_overheat(pos) then -- If too hot + local node = minetest.get_node(pos) + node.name = BASENAME.."_burnt" + minetest.swap_node(pos, node) + -- Wait for pending operations + minetest.after(0.2, overheat_off, pos) + return true + end +end + +------------------------ +-- Ignored off events -- +------------------------ + +local function ignore_event(event, meta) + if event.type ~= "off" then return false end + local ignore_offevents = minetest.deserialize(meta:get_string("ignore_offevents")) or {} + if ignore_offevents[event.pin.name] then + ignore_offevents[event.pin.name] = nil + meta:set_string("ignore_offevents", minetest.serialize(ignore_offevents)) + return true + end +end + +------------------------- +-- Parsing and running -- +------------------------- + +local function safe_print(param) + print(dump(param)) +end + +local function remove_functions(x) + local tp = type(x) + if tp == "table" then + for key, value in pairs(x) do + local key_t, val_t = type(key), type(value) + if key_t == "function" or val_t == "function" then + x[key] = nil + else + if key_t == "table" then + remove_functions(key) + end + if val_t == "table" then + remove_functions(value) + end + end + end + elseif tp == "function" then + return nil + end + return x +end + +local function get_interrupt(pos) + -- iid = interrupt id + local function interrupt(time, iid) + if type(time) ~= "number" then return end + local luac_id = minetest.get_meta(pos):get_int("luac_id") + mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1) + end + return interrupt +end + + +local function get_digiline_send(pos) + if not digiline then return end + return function(channel, msg) + minetest.after(0, function() + digiline:receptor_send(pos, digiline.rules.default, channel, msg) + end) + end +end + + +local safe_globals = { + "assert", "error", "ipairs", "next", "pairs", "pcall", "select", + "tonumber", "tostring", "type", "unpack", "_VERSION", "xpcall", +} +local function create_environment(pos, mem, event) + -- Gather variables for the environment + local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates + local vports_copy = {} + for k, v in pairs(vports) do vports_copy[k] = v end + local rports = get_real_port_states(pos) + + -- Create new library tables on each call to prevent one LuaController + -- from breaking a library and messing up other LuaControllers. + local env = { + pin = merge_port_states(vports, rports), + port = vports_copy, + event = event, + mem = mem, + heat = minetest.get_meta(pos):get_int("heat"), + heat_max = mesecon.setting("overheat_max", 20), + print = safe_print, + interrupt = get_interrupt(pos), + digiline_send = get_digiline_send(pos), + string = { + byte = string.byte, + char = string.char, + format = string.format, + gsub = string.gsub, + len = string.len, + lower = string.lower, + upper = string.upper, + rep = string.rep, + reverse = string.reverse, + sub = string.sub, + }, + math = { + abs = math.abs, + acos = math.acos, + asin = math.asin, + atan = math.atan, + atan2 = math.atan2, + ceil = math.ceil, + cos = math.cos, + cosh = math.cosh, + deg = math.deg, + exp = math.exp, + floor = math.floor, + fmod = math.fmod, + frexp = math.frexp, + huge = math.huge, + ldexp = math.ldexp, + log = math.log, + log10 = math.log10, + max = math.max, + min = math.min, + modf = math.modf, + pi = math.pi, + pow = math.pow, + rad = math.rad, + random = math.random, + sin = math.sin, + sinh = math.sinh, + sqrt = math.sqrt, + tan = math.tan, + tanh = math.tanh, + }, + table = { + concat = table.concat, + insert = table.insert, + maxn = table.maxn, + remove = table.remove, + sort = table.sort, + }, + os = { + clock = os.clock, + difftime = os.difftime, + time = os.time, + }, + } + env._G = env + + for _, name in pairs(safe_globals) do + env[name] = _G[name] + end + + return env +end + + +local function timeout() + debug.sethook() -- Clear hook + error("Code timed out!") +end + + +local function code_prohibited(code) + -- LuaJIT doesn't increment the instruction counter when running + -- loops, so we have to sanitize inputs if we're using LuaJIT. + if not jit then + return false + end + local prohibited = {"while", "for", "do", "repeat", "until", "goto"} + code = " "..code.." " + for _, p in ipairs(prohibited) do + if string.find(code, "[^%w_]"..p.."[^%w_]") then + return "Prohibited command: "..p + end + end +end + + +local function create_sandbox(code, env) + if code:byte(1) == 27 then + return nil, "Binary code prohibited." + end + local f, msg = loadstring(code) + if not f then return nil, msg end + setfenv(f, env) + + return function(...) + debug.sethook(timeout, "", 10000) + local ok, ret = pcall(f, ...) + debug.sethook() -- Clear hook + if not ok then error(ret) end + return ret + end +end + + +local function load_memory(meta) + return minetest.deserialize(meta:get_string("lc_memory")) or {} +end + + +local function save_memory(meta, mem) + meta:set_string("lc_memory", + minetest.serialize( + remove_functions(mem) + ) + ) +end + + +local function run(pos, event) + local meta = minetest.get_meta(pos) + if overheat(pos) then return end + if ignore_event(event, meta) then return end + + -- Load code & mem from meta + local mem = load_memory(meta) + local code = meta:get_string("code") + + local err = code_prohibited(code) + if err then return err end + + -- Create environment + local env = create_environment(pos, mem, event) + + -- Create the sandbox and execute code + local f, msg = create_sandbox(code, env) + if not f then return msg end + local success, msg = pcall(f) + if not success then return msg end + if type(env.port) ~= "table" then + return "Ports set are invalid." + end + + save_memory(meta, env.mem) + + -- Actually set the ports + set_port_states(pos, env.port) +end + +mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid) + -- There is no luacontroller anymore / it has been reprogrammed / replaced + if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end + run(pos, {type="interrupt", iid = iid}) +end) + +local function reset_meta(pos, code, errmsg) + local meta = minetest.get_meta(pos) + meta:set_string("code", code) + code = minetest.formspec_escape(code or "") + errmsg = minetest.formspec_escape(errmsg or "") + meta:set_string("formspec", "size[10,8]".. + "background[-0.2,-0.25;10.4,8.75;jeija_luac_background.png]".. + "textarea[0.2,0.6;10.2,5;code;;"..code.."]".. + "image_button[3.75,6;2.5,1;jeija_luac_runbutton.png;program;]".. + "image_button_exit[9.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]".. + "label[0.1,5;"..errmsg.."]") + meta:set_int("heat", 0) + meta:set_int("luac_id", math.random(1, 65535)) +end + +local function reset(pos) + set_port_states(pos, {a=false, b=false, c=false, d=false}) +end + + +----------------------- +-- Node Registration -- +----------------------- + +local output_rules = {} +local input_rules = {} + +local node_box = { + type = "fixed", + fixed = { + {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, -- Bottom slab + {-5/16, -7/16, -5/16, 5/16, -6/16, 5/16}, -- Circuit board + {-3/16, -6/16, -3/16, 3/16, -5/16, 3/16}, -- IC + } +} + +local selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 }, +} + +local digiline = { + receptor = {}, + effector = { + action = function(pos, node, channel, msg) + run(pos, {type = "digiline", channel = channel, msg = msg}) + end + } +} +local function on_receive_fields(pos, form_name, fields) + if not fields.program then + return + end + reset(pos) + reset_meta(pos, fields.code) + local err = run(pos, {type="program"}) + if err then + print(err) + reset_meta(pos, fields.code, err) + end +end + +for a = 0, 1 do -- 0 = off 1 = on +for b = 0, 1 do +for c = 0, 1 do +for d = 0, 1 do + local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a) + local node_name = BASENAME..cid + local top = "jeija_luacontroller_top.png" + if a == 1 then + top = top.."^jeija_luacontroller_LED_A.png" + end + if b == 1 then + top = top.."^jeija_luacontroller_LED_B.png" + end + if c == 1 then + top = top.."^jeija_luacontroller_LED_C.png" + end + if d == 1 then + top = top.."^jeija_luacontroller_LED_D.png" + end + + local groups + if a + b + c + d ~= 0 then + groups = {dig_immediate=2, not_in_creative_inventory=1, overheat = 1} + else + groups = {dig_immediate=2, overheat = 1} + end + + output_rules[cid] = {} + input_rules[cid] = {} + if a == 1 then table.insert(output_rules[cid], rules.a) end + if b == 1 then table.insert(output_rules[cid], rules.b) end + if c == 1 then table.insert(output_rules[cid], rules.c) end + if d == 1 then table.insert(output_rules[cid], rules.d) end + + if a == 0 then table.insert( input_rules[cid], rules.a) end + if b == 0 then table.insert( input_rules[cid], rules.b) end + if c == 0 then table.insert( input_rules[cid], rules.c) end + if d == 0 then table.insert( input_rules[cid], rules.d) end + + local mesecons = { + effector = { + rules = input_rules[cid], + action_change = function (pos, _, rule_name, new_state) + update_real_port_states(pos, rule_name, new_state) + run(pos, {type=new_state, pin=rule_name}) + end, + }, + receptor = { + state = mesecon.state.on, + rules = output_rules[cid] + } + } + + minetest.register_node(node_name, { + description = "LuaController", + drawtype = "nodebox", + tiles = { + top, + "jeija_microcontroller_bottom.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png" + }, + inventory_image = top, + paramtype = "light", + groups = groups, + drop = BASENAME.."0000", + sunlight_propagates = true, + selection_box = selection_box, + node_box = node_box, + on_construct = reset_meta, + on_receive_fields = on_receive_fields, + sounds = default.node_sound_stone_defaults(), + mesecons = mesecons, + digiline = digiline, + -- Virtual portstates are the ports that + -- the node shows as powered up (light up). + virtual_portstates = { + a = a == 1, + b = b == 1, + c = c == 1, + d = d == 1, + }, + after_dig_node = function (pos, node) + mesecon.receptor_off(pos, output_rules) + end, + is_luacontroller = true, + }) +end +end +end +end + +------------------------------ +-- Overheated LuaController -- +------------------------------ + +minetest.register_node(BASENAME .. "_burnt", { + drawtype = "nodebox", + tiles = { + "jeija_luacontroller_burnt_top.png", + "jeija_microcontroller_bottom.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png" + }, + inventory_image = "jeija_luacontroller_burnt_top.png", + paramtype = "light", + groups = {dig_immediate=2, not_in_creative_inventory=1}, + drop = BASENAME.."0000", + sunlight_propagates = true, + selection_box = selection_box, + node_box = node_box, + on_construct = reset_meta, + on_receive_fields = on_receive_fields, + sounds = default.node_sound_stone_defaults(), + virtual_portstates = {a = false, b = false, c = false, d = false}, + mesecons = { + effector = { + rules = mesecon.rules.flat, + action_change = function(pos, _, rule_name, new_state) + update_real_port_states(pos, rule_name, new_state) + end, + }, + }, +}) + +------------------------ +-- Craft Registration -- +------------------------ + +minetest.register_craft({ + output = BASENAME.."0000 2", + recipe = { + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''}, + } +}) + diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luac_background.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luac_background.png new file mode 100644 index 0000000..40e316c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luac_background.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luac_runbutton.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luac_runbutton.png new file mode 100644 index 0000000..157507f Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luac_runbutton.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_A.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_A.png new file mode 100644 index 0000000..a187e8e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_A.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_B.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_B.png new file mode 100644 index 0000000..738ba96 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_B.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_C.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_C.png new file mode 100644 index 0000000..abe0fe6 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_C.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_D.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_D.png new file mode 100644 index 0000000..cc10170 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_LED_D.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_burnt_top.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_burnt_top.png new file mode 100644 index 0000000..d1a17af Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_burnt_top.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_top.png b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_top.png new file mode 100644 index 0000000..3128230 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_luacontroller/textures/jeija_luacontroller_top.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_materials/depends.txt b/mods/minetest-mod-mesecons/mesecons_materials/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_materials/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_materials/init.lua b/mods/minetest-mod-mesecons/mesecons_materials/init.lua new file mode 100644 index 0000000..5ebf605 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_materials/init.lua @@ -0,0 +1,41 @@ +--GLUE +minetest.register_craftitem("mesecons_materials:glue", { + image = "jeija_glue.png", + on_place_on_ground = minetest.craftitem_place_item, + description="Glue", +}) + +minetest.register_craftitem("mesecons_materials:fiber", { + image = "jeija_fiber.png", + on_place_on_ground = minetest.craftitem_place_item, + description="Fiber", +}) + +minetest.register_craft({ + output = "mesecons_materials:glue 2", + type = "cooking", + recipe = "group:sapling", + cooktime = 2 +}) + +minetest.register_craft({ + output = "mesecons_materials:fiber 6", + type = "cooking", + recipe = "mesecons_materials:glue", + cooktime = 4 +}) + +-- Silicon +minetest.register_craftitem("mesecons_materials:silicon", { + image = "jeija_silicon.png", + on_place_on_ground = minetest.craftitem_place_item, + description="Silicon", +}) + +minetest.register_craft({ + output = "mesecons_materials:silicon 4", + recipe = { + {"group:sand", "group:sand"}, + {"group:sand", "default:steel_ingot"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/MeseconMicro.odt b/mods/minetest-mod-mesecons/mesecons_microcontroller/MeseconMicro.odt new file mode 100644 index 0000000..be82d1b Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/MeseconMicro.odt differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/MeseconMicro.pdf b/mods/minetest-mod-mesecons/mesecons_microcontroller/MeseconMicro.pdf new file mode 100644 index 0000000..7ab7484 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/MeseconMicro.pdf differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/depends.txt b/mods/minetest-mod-mesecons/mesecons_microcontroller/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_microcontroller/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/init.lua b/mods/minetest-mod-mesecons/mesecons_microcontroller/init.lua new file mode 100644 index 0000000..7e290a3 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_microcontroller/init.lua @@ -0,0 +1,692 @@ +EEPROM_SIZE = 255 + +local microc_rules = {} + +for a = 0, 1 do +for b = 0, 1 do +for c = 0, 1 do +for d = 0, 1 do +local nodename = "mesecons_microcontroller:microcontroller"..tostring(d)..tostring(c)..tostring(b)..tostring(a) +local top = "jeija_microcontroller_top.png" +if tostring(a) == "1" then + top = top.."^jeija_microcontroller_LED_A.png" +end +if tostring(b) == "1" then + top = top.."^jeija_microcontroller_LED_B.png" +end +if tostring(c) == "1" then + top = top.."^jeija_microcontroller_LED_C.png" +end +if tostring(d) == "1" then + top = top.."^jeija_microcontroller_LED_D.png" +end +if tostring(d)..tostring(c)..tostring(b)..tostring(a) ~= "0000" then + groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon = 3, overheat = 1} +else + groups = {dig_immediate=2, mesecon = 3, overheat = 1} +end +local rules={} +if (a == 1) then table.insert(rules, {x = -1, y = 0, z = 0}) end +if (b == 1) then table.insert(rules, {x = 0, y = 0, z = 1}) end +if (c == 1) then table.insert(rules, {x = 1, y = 0, z = 0}) end +if (d == 1) then table.insert(rules, {x = 0, y = 0, z = -1}) end + +local input_rules={} +if (a == 0) then table.insert(input_rules, {x = -1, y = 0, z = 0, name = "A"}) end +if (b == 0) then table.insert(input_rules, {x = 0, y = 0, z = 1, name = "B"}) end +if (c == 0) then table.insert(input_rules, {x = 1, y = 0, z = 0, name = "C"}) end +if (d == 0) then table.insert(input_rules, {x = 0, y = 0, z = -1, name = "D"}) end +microc_rules[nodename] = rules + +local mesecons = {effector = +{ + rules = input_rules, + action_change = function (pos, node, rulename, newstate) + yc_update_real_portstates(pos, node, rulename, newstate) + update_yc(pos) + end +}} +if nodename ~= "mesecons_microcontroller:microcontroller0000" then + mesecons.receptor = { + state = mesecon.state.on, + rules = rules + } +end + +minetest.register_node(nodename, { + description = "Microcontroller", + drawtype = "nodebox", + tiles = { + top, + "jeija_microcontroller_bottom.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png" + }, + + sunlight_propagates = true, + paramtype = "light", + walkable = true, + groups = groups, + drop = "mesecons_microcontroller:microcontroller0000 1", + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 }, + }, + node_box = { + type = "fixed", + fixed = { + { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab + { -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board + { -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC + } + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("code", "") + meta:set_string("formspec", "size[9,2.5]".. + "field[0.256,-0.2;9,2;code;Code:;]".. + "button[0 ,0.2;1.5,3;band;AND]".. + "button[1.5,0.2;1.5,3;bxor;XOR]".. + "button[3 ,0.2;1.5,3;bnot;NOT]".. + "button[4.5,0.2;1.5,3;bnand;NAND]".. + "button[6 ,0.2;1.5,3;btflop;T-Flop]".. + "button[7.5,0.2;1.5,3;brsflop;RS-Flop]".. + "button_exit[3.5,1;2,3;program;Program]") + meta:set_string("infotext", "Unprogrammed Microcontroller") + local r = "" + for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0" + meta:set_string("eeprom", r) + end, + on_receive_fields = function(pos, formanme, fields, sender) + local meta = minetest.get_meta(pos) + if fields.band then + fields.code = "sbi(C, A&B) :A and B are inputs, C is output" + elseif fields.bxor then + fields.code = "sbi(C, A~B) :A and B are inputs, C is output" + elseif fields.bnot then + fields.code = "sbi(B, !A) :A is input, B is output" + elseif fields.bnand then + fields.code = "sbi(C, !A|!B) :A and B are inputs, C is output" + elseif fields.btflop then + fields.code = "if(A)sbi(1,1);if(!A)sbi(B,!B)sbi(1,0); if(C)off(B,1); :A is input, B is output (Q), C is reset, toggles with falling edge" + elseif fields.brsflop then + fields.code = "if(A)on(C);if(B)off(C); :A is S (Set), B is R (Reset), C is output (R dominates)" + end + if fields.code == nil then return end + + meta:set_string("code", fields.code) + meta:set_string("formspec", "size[9,2.5]".. + "field[0.256,-0.2;9,2;code;Code:;"..minetest.formspec_escape(fields.code).."]".. + "button[0 ,0.2;1.5,3;band;AND]".. + "button[1.5,0.2;1.5,3;bxor;XOR]".. + "button[3 ,0.2;1.5,3;bnot;NOT]".. + "button[4.5,0.2;1.5,3;bnand;NAND]".. + "button[6 ,0.2;1.5,3;btflop;T-Flop]".. + "button[7.5,0.2;1.5,3;brsflop;RS-Flop]".. + "button_exit[3.5,1;2,3;program;Program]") + meta:set_string("infotext", "Programmed Microcontroller") + yc_reset (pos) + update_yc(pos) + end, + sounds = default.node_sound_stone_defaults(), + mesecons = mesecons, + after_dig_node = function (pos, node) + rules = microc_rules[node.name] + mesecon.receptor_off(pos, rules) + end, +}) +end +end +end +end + +minetest.register_craft({ + output = 'craft "mesecons_microcontroller:microcontroller0000" 2', + recipe = { + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''}, + } +}) + +function yc_reset(pos) + yc_action(pos, {a=false, b=false, c=false, d=false}) + local meta = minetest.get_meta(pos) + meta:set_int("afterid", 0) + local r = "" + for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0" + meta:set_string("eeprom", r) +end + +function update_yc(pos) + local meta = minetest.get_meta(pos) + + if (mesecon.do_overheat(pos)) then + minetest.remove_node(pos) + minetest.after(0.2, function (pos) + mesecon.receptor_off(pos, mesecon.rules.flat) + end , pos) -- wait for pending parsings + minetest.add_item(pos, "mesecons_microcontroller:microcontroller0000") + end + + local code = meta:get_string("code") + code = yc_code_remove_commentary(code) + code = string.gsub(code, " ", "") --Remove all spaces + code = string.gsub(code, " ", "") --Remove all tabs + if yc_parsecode(code, pos) == nil then + meta:set_string("infotext", "Code not valid!\n"..code) + else + meta:set_string("infotext", "Working Microcontroller\n"..code) + end +end + + +--Code Parsing +function yc_code_remove_commentary(code) + local is_string = false + for i = 1, #code do + if code:sub(i, i) == '"' then + is_string = not is_string --toggle is_string + elseif code:sub(i, i) == ":" and not is_string then + return code:sub(1, i-1) + end + end + return code +end + +function yc_parsecode(code, pos) + local meta = minetest.get_meta(pos) + local endi = 1 + local Lreal = yc_get_real_portstates(pos) + local Lvirtual = yc_get_virtual_portstates(pos) + if Lvirtual == nil then return nil end + local c + local eeprom = meta:get_string("eeprom") + while true do + local command, params + command, endi = parse_get_command(code, endi) + if command == nil then return nil end + if command == true then break end --end of code + if command == "if" then + local r + r, endi = yc_command_if(code, endi, yc_merge_portstates(Lreal, Lvirtual), eeprom) + if r == nil then return nil end + if r == true then -- nothing + elseif r == false then + local endi_new = yc_skip_to_else (code, endi) + if endi_new == nil then --else > not found + endi = yc_skip_to_endif(code, endi) + else + endi = endi_new + end + if endi == nil then return nil end + end + else + params, endi = parse_get_params(code, endi) + if not params then return nil end + end + if command == "on" then + L = yc_command_on (params, Lvirtual) + elseif command == "off" then + L = yc_command_off(params, Lvirtual) + elseif command == "print" then + local su = yc_command_print(params, eeprom, yc_merge_portstates(Lreal, Lvirtual)) + if su ~= true then return nil end + elseif command == "after" then + local su = yc_command_after(params, pos) + if su == nil then return nil end + elseif command == "sbi" then + local new_eeprom + new_eeprom, Lvirtual = yc_command_sbi (params, eeprom, yc_merge_portstates(Lreal, Lvirtual), Lvirtual) + if new_eeprom == nil then return nil + else eeprom = new_eeprom end + elseif command == "if" then --nothing + else + return nil + end + if Lvirtual == nil then return nil end + if eeprom == nil then return nil else + minetest.get_meta(pos):set_string("eeprom", eeprom) end + end + yc_action(pos, Lvirtual) + return true +end + +function parse_get_command(code, starti) + i = starti + local s + while s ~= "" do + s = string.sub(code, i, i) + if s == "(" then + return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after ( + end + if s == ";" and starti == i then + starti = starti + 1 + i = starti + elseif s == ">" then + starti = yc_skip_to_endif(code, starti) + if starti == nil then return nil end + i = starti + else + i = i + 1 + end + end + + if starti == i-1 then + return true, true + end + return nil, nil +end + +function parse_get_params(code, starti) + i = starti + local s + local params = {} + local is_string = false + while s ~= "" do + s = string.sub(code, i, i) + if code:sub(i, i) == '"' then + is_string = (is_string==false) --toggle is_string + end + if s == ")" and is_string == false then + table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after ) + return params, i + 1 + end + if s == "," and is_string == false then + table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after ) + starti = i + 1 + end + i = i + 1 + end + return nil, nil +end + +function yc_parse_get_eeprom_param(cond, starti) + i = starti + local s + local addr + while s ~= "" do + s = string.sub(cond, i, i) + if string.find("0123456789", s) == nil or s == "" then + addr = string.sub(cond, starti, i-1) -- i: last number i+1 after last number + return addr, i + end + if s == "," then return nil, nil end + i = i + 1 + end + return nil, nil +end + +function yc_skip_to_endif(code, starti) + local i = starti + local s = false + local open_ifs = 1 + while s ~= nil and s~= "" do + s = code:sub(i, i) + if s == "i" and code:sub(i+1, i+1) == "f" then --if in µCScript + open_ifs = open_ifs + 1 + end + if s == ";" then + open_ifs = open_ifs - 1 + end + if open_ifs == 0 then + return i + 1 + end + i = i + 1 + end + return nil +end + +function yc_skip_to_else(code, starti) + local i = starti + local s = false + local open_ifs = 1 + while s ~= nil and s~= "" do + s = code:sub(i, i) + if s == "i" and code:sub(i+1, i+1) == "f" then --if in µCScript + open_ifs = open_ifs + 1 + end + if s == ";" then + open_ifs = open_ifs - 1 + end + if open_ifs == 1 and s == ">" then + return i + 1 + end + i = i + 1 + end + return nil +end + +--Commands +function yc_command_on(params, L) + local rules = {} + for i, port in ipairs(params) do + L = yc_set_portstate (port, true, L) + end + return L +end + +function yc_command_off(params, L) + local rules = {} + for i, port in ipairs(params) do + L = yc_set_portstate (port, false, L) + end + return L +end + +function yc_command_print(params, eeprom, L) + local s = "" + for i, param in ipairs(params) do + if param:sub(1,1) == '"' and param:sub(#param, #param) == '"' then + s = s..param:sub(2, #param-1) + else + r = yc_command_parsecondition(param, L, eeprom) + if r == "1" or r == "0" then + s = s..r + else return nil end + end + end + print(s) --don't remove + return true +end + +function yc_command_sbi(params, eeprom, L, Lv) + if params[1]==nil or params[2]==nil or params[3] ~=nil then return nil end + local status = yc_command_parsecondition(params[2], L, eeprom) + + if status == nil then return nil, nil end + + if string.find("ABCD", params[1])~=nil and #params[1]==1 then --is a port + if status == "1" then + Lv = yc_set_portstate (params[1], true, Lv) + else + Lv = yc_set_portstate (params[1], false, Lv) + end + return eeprom, Lv; + end + + --is an eeprom address + local new_eeprom = ""; + for i=1, #eeprom do + if tonumber(params[1])==i then + new_eeprom = new_eeprom..status + else + new_eeprom = new_eeprom..eeprom:sub(i, i) + end + end + return new_eeprom, Lv +end + +-- after (delay) +function yc_command_after(params, pos) + if params[1] == nil or params[2] == nil or params[3] ~= nil then return nil end + + --get time (maximum time is 200) + local time = tonumber(params[1]) + if time == nil or time > 200 then + return nil + end + + --get code in quotes "code" + if string.sub(params[2], 1, 1) ~= '"' or string.sub(params[2], #params[2], #params[2]) ~= '"' then return nil end + local code = string.sub(params[2], 2, #params[2] - 1) + + local afterid = math.random(10000) + local meta = minetest.get_meta(pos) + meta:set_int("afterid", afterid) + minetest.after(time, yc_command_after_execute, {pos = pos, code = code, afterid = afterid}) + return true +end + +function yc_command_after_execute(params) + local meta = minetest.get_meta(params.pos) + if meta:get_int("afterid") == params.afterid then --make sure the node has not been changed + if yc_parsecode(params.code, params.pos) == nil then + meta:set_string("infotext", "Code in after() not valid!") + else + if code ~= nil then + meta:set_string("infotext", "Working Microcontroller\n"..code) + else + meta:set_string("infotext", "Working Microcontroller") + end + end + end +end + +--If +function yc_command_if(code, starti, L, eeprom) + local cond, endi = yc_command_if_getcondition(code, starti) + if cond == nil then return nil end + + cond = yc_command_parsecondition(cond, L, eeprom) + + local result + if cond == "0" then result = false + elseif cond == "1" then result = true end + if not result then end + return result, endi --endi from local cond, endi = yc_command_if_getcondition(code, starti) +end + +--Condition parsing +function yc_command_if_getcondition(code, starti) + i = starti + local s + local brackets = 1 --1 Bracket to close + while s ~= "" do + s = string.sub(code, i, i) + + if s == ")" then + brackets = brackets - 1 + end + + if s == "(" then + brackets = brackets + 1 + end + + if brackets == 0 then + return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after ( + end + + i = i + 1 + end + return nil, nil +end + +function yc_command_parsecondition(cond, L, eeprom) + cond = string.gsub(cond, "A", tonumber(L.a and 1 or 0)) + cond = string.gsub(cond, "B", tonumber(L.b and 1 or 0)) + cond = string.gsub(cond, "C", tonumber(L.c and 1 or 0)) + cond = string.gsub(cond, "D", tonumber(L.d and 1 or 0)) + + + local i = 1 + local l = string.len(cond) + while i<=l do + local s = cond:sub(i,i) + if s == "#" then + local addr, endi = yc_parse_get_eeprom_param(cond, i+1) + local buf = yc_eeprom_read(tonumber(addr), eeprom) + if buf == nil then return nil end + local call = cond:sub(i, endi-1) + cond = string.gsub(cond, call, buf) + i = 0 + l = string.len(cond) + end + i = i + 1 + end + + cond = string.gsub(cond, "!0", "1") + cond = string.gsub(cond, "!1", "0") + + local i = 2 + local l = string.len(cond) + while i<=l do + local s = cond:sub(i,i) + local b = tonumber(cond:sub(i-1, i-1)) + local a = tonumber(cond:sub(i+1, i+1)) + if cond:sub(i+1, i+1) == nil then break end + if s == "=" then + if a==nil then return nil end + if b==nil then return nil end + if a == b then buf = "1" end + if a ~= b then buf = "0" end + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + i = i + 1 + end + + local i = 2 + local l = string.len(cond) + while i<=l do + local s = cond:sub(i,i) + local b = tonumber(cond:sub(i-1, i-1)) + local a = tonumber(cond:sub(i+1, i+1)) + if cond:sub(i+1, i+1) == nil then break end + if s == "&" then + if a==nil then return nil end + local buf = ((a==1) and (b==1)) + if buf == true then buf = "1" end + if buf == false then buf = "0" end + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + if s == "|" then + if a==nil then return nil end + local buf = ((a == 1) or (b == 1)) + if buf == true then buf = "1" end + if buf == false then buf = "0" end + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + if s == "~" then + if a==nil then return nil end + local buf = (((a == 1) or (b == 1)) and not((a==1) and (b==1))) + if buf == true then buf = "1" end + if buf == false then buf = "0" end + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + i = i + 1 + end + + return cond +end + +--Virtual-Hardware functions +function yc_eeprom_read(number, eeprom) + if not number then return end + return eeprom:sub(number, number) +end + +--Real I/O functions +function yc_action(pos, L) --L-->Lvirtual + local Lv = yc_get_virtual_portstates(pos) + local name = "mesecons_microcontroller:microcontroller" + ..tonumber(L.d and 1 or 0) + ..tonumber(L.c and 1 or 0) + ..tonumber(L.b and 1 or 0) + ..tonumber(L.a and 1 or 0) + local node = minetest.get_node(pos) + minetest.swap_node(pos, {name = name, param2 = node.param2}) + + yc_action_setports(pos, L, Lv) +end + +function yc_action_setports(pos, L, Lv) + local name = "mesecons_microcontroller:microcontroller" + local rules + if Lv.a ~= L.a then + rules = microc_rules[name.."0001"] + if L.a == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end + end + if Lv.b ~= L.b then + rules = microc_rules[name.."0010"] + if L.b == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end + end + if Lv.c ~= L.c then + rules = microc_rules[name.."0100"] + if L.c == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end + end + if Lv.d ~= L.d then + rules = microc_rules[name.."1000"] + if L.d == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end + end +end + +function yc_set_portstate(port, state, L) + if port == "A" then L.a = state + elseif port == "B" then L.b = state + elseif port == "C" then L.c = state + elseif port == "D" then L.d = state + else return nil end + return L +end + +function yc_update_real_portstates(pos, node, rulename, newstate) + local meta = minetest.get_meta(pos) + if rulename == nil then + meta:set_int("real_portstates", 1) + return + end + local n = meta:get_int("real_portstates") - 1 + local L = {} + for i = 1, 4 do + L[i] = n%2 + n = math.floor(n/2) + end + if rulename.x == nil then + for _, rname in ipairs(rulename) do + local port = ({4, 1, nil, 3, 2})[rname.x+2*rname.z+3] + L[port] = (newstate == "on") and 1 or 0 + end + else + local port = ({4, 1, nil, 3, 2})[rulename.x+2*rulename.z+3] + L[port] = (newstate == "on") and 1 or 0 + end + meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4]) +end + +function yc_get_real_portstates(pos) -- determine if ports are powered (by itself or from outside) + local meta = minetest.get_meta(pos) + local L = {} + local n = meta:get_int("real_portstates") - 1 + for _, index in ipairs({"a", "b", "c", "d"}) do + L[index] = ((n%2) == 1) + n = math.floor(n/2) + end + return L +end + +function yc_get_virtual_portstates(pos) -- portstates according to the name + local name = minetest.get_node(pos).name + local b, a = string.find(name, ":microcontroller") + if a == nil then return nil end + a = a + 1 + + local Lvirtual = {a=false, b=false, c=false, d=false} + if name:sub(a , a ) == "1" then Lvirtual.d = true end + if name:sub(a+1, a+1) == "1" then Lvirtual.c = true end + if name:sub(a+2, a+2) == "1" then Lvirtual.b = true end + if name:sub(a+3, a+3) == "1" then Lvirtual.a = true end + return Lvirtual +end + +function yc_merge_portstates(Lreal, Lvirtual) + local L = {a=false, b=false, c=false, d=false} + if Lvirtual.a or Lreal.a then L.a = true end + if Lvirtual.b or Lreal.b then L.b = true end + if Lvirtual.c or Lreal.c then L.c = true end + if Lvirtual.d or Lreal.d then L.d = true end + return L +end diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_A.png b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_A.png new file mode 100644 index 0000000..64526cf Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_A.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_B.png b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_B.png new file mode 100644 index 0000000..1f7b451 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_B.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_C.png b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_C.png new file mode 100644 index 0000000..399cc2c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_C.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_D.png b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_D.png new file mode 100644 index 0000000..506389c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_LED_D.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_bottom.png b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_bottom.png new file mode 100644 index 0000000..3a9161e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_bottom.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_sides.png b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_sides.png new file mode 100644 index 0000000..b367644 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_sides.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_top.png b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_top.png new file mode 100644 index 0000000..438c934 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_microcontroller/textures/jeija_microcontroller_top.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_movestones/depends.txt b/mods/minetest-mod-mesecons/mesecons_movestones/depends.txt new file mode 100644 index 0000000..a596cf8 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_movestones/depends.txt @@ -0,0 +1,3 @@ +mesecons +mesecons_materials +mesecons_mvps diff --git a/mods/minetest-mod-mesecons/mesecons_movestones/init.lua b/mods/minetest-mod-mesecons/mesecons_movestones/init.lua new file mode 100644 index 0000000..7790658 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_movestones/init.lua @@ -0,0 +1,226 @@ +-- MOVESTONE +-- Non-sticky: +-- Moves along mesecon lines +-- Pushes all blocks in front of it +-- +-- Sticky one +-- Moves along mesecon lines +-- Pushes all block in front of it +-- Pull all blocks in its back + +function mesecon.get_movestone_direction(pos) + getactivated = 0 + local lpos + local getactivated = 0 + local rules = { + {x=0, y=1, z=-1}, + {x=0, y=0, z=-1}, + {x=0, y=-1, z=-1}, + {x=0, y=1, z=1}, + {x=0, y=-1, z=1}, + {x=0, y=0, z=1}, + {x=1, y=0, z=0}, + {x=1, y=1, z=0}, + {x=1, y=-1, z=0}, + {x=-1, y=1, z=0}, + {x=-1, y=-1, z=0}, + {x=-1, y=0, z=0}} + + lpos = {x=pos.x+1, y=pos.y, z=pos.z} + for n = 1, 3 do + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + return {x=0, y=0, z=-1} + end + end + + lpos = {x = pos.x-1, y = pos.y, z = pos.z} + for n=4, 6 do + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + return {x=0, y=0, z=1} + end + end + + lpos = {x = pos.x, y = pos.y, z = pos.z+1} + for n=7, 9 do + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + return {x=-1, y=0, z=0} + end + end + + lpos = {x = pos.x, y = pos.y, z = pos.z-1} + for n=10, 12 do + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + return {x=1, y=0, z=0} + end + end +end + +minetest.register_node("mesecons_movestones:movestone", { + tiles = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_arrows.png", "jeija_movestone_arrows.png"}, + paramtype2 = "facedir", + legacy_facedir_simple = true, + groups = {cracky=3}, + description="Movestone", + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + action_on = function (pos, node) + local direction=mesecon.get_movestone_direction(pos) + if not direction then return end + minetest.remove_node(pos) + mesecon.on_dignode(pos, node) + minetest.add_entity(pos, "mesecons_movestones:movestone_entity") + end + }} +}) + +minetest.register_entity("mesecons_movestones:movestone_entity", { + physical = false, + visual = "sprite", + textures = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_arrows.png", "jeija_movestone_arrows.png"}, + collisionbox = {-0.5,-0.5,-0.5, 0.5, 0.5, 0.5}, + visual = "cube", + lastdir = {x=0, y=0, z=0}, + + on_punch = function(self, hitter) + self.object:remove() + hitter:get_inventory():add_item("main", "mesecons_movestones:movestone") + end, + + on_step = function(self, dtime) + local pos = self.object:getpos() + pos.x, pos.y, pos.z = math.floor(pos.x+0.5), math.floor(pos.y+0.5), math.floor(pos.z+0.5) + local direction = mesecon.get_movestone_direction(pos) + + local maxpush = mesecon.setting("movestone_max_push", 50) + if not direction then -- no mesecon power + --push only solid nodes + local name = minetest.get_node(pos).name + if name ~= "air" and name ~= "ignore" + and ((not minetest.registered_nodes[name]) + or minetest.registered_nodes[name].liquidtype == "none") then + mesecon.mvps_push(pos, self.lastdir, maxpush) + end + local nn = {name="mesecons_movestones:movestone"} + minetest.add_node(pos, nn) + self.object:remove() + mesecon.on_placenode(pos, nn) + return + end + + local success, stack, oldstack = + mesecon.mvps_push(pos, direction, maxpush) + if not success then -- Too large stack/stopper in the way + local nn = {name="mesecons_movestones:movestone"} + minetest.add_node(pos, nn) + self.object:remove() + mesecon.on_placenode(pos, nn) + return + else + mesecon.mvps_process_stack (stack) + mesecon.mvps_move_objects (pos, direction, oldstack) + self.lastdir = direction + end + + self.object:setvelocity({x=direction.x*2, y=direction.y*2, z=direction.z*2}) + end, +}) + +minetest.register_craft({ + output = "mesecons_movestones:movestone 2", + recipe = { + {"default:stone", "default:stone", "default:stone"}, + {"group:mesecon_conductor_craftable", "group:mesecon_conductor_craftable", "group:mesecon_conductor_craftable"}, + {"default:stone", "default:stone", "default:stone"}, + } +}) + + + +-- STICKY_MOVESTONE + +minetest.register_node("mesecons_movestones:sticky_movestone", { + tiles = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_sticky_movestone.png", "jeija_sticky_movestone.png"}, + inventory_image = minetest.inventorycube("jeija_sticky_movestone.png", "jeija_movestone_side.png", "jeija_movestone_side.png"), + paramtype2 = "facedir", + legacy_facedir_simple = true, + groups = {cracky=3}, + description="Sticky Movestone", + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + action_on = function (pos, node) + local direction=mesecon.get_movestone_direction(pos) + if not direction then return end + minetest.remove_node(pos) + mesecon.on_dignode(pos, node) + minetest.add_entity(pos, "mesecons_movestones:sticky_movestone_entity") + end + }} +}) + +minetest.register_craft({ + output = "mesecons_movestones:sticky_movestone 2", + recipe = { + {"mesecons_materials:glue", "mesecons_movestones:movestone", "mesecons_materials:glue"}, + } +}) + +minetest.register_entity("mesecons_movestones:sticky_movestone_entity", { + physical = false, + visual = "sprite", + textures = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_sticky_movestone.png", "jeija_sticky_movestone.png"}, + collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + visual = "cube", + lastdir = {x=0, y=0, z=0}, + + on_punch = function(self, hitter) + self.object:remove() + hitter:get_inventory():add_item("main", 'mesecons_movestones:sticky_movestone') + end, + + on_step = function(self, dtime) + local pos = self.object:getpos() + pos.x, pos.y, pos.z = math.floor(pos.x+0.5), math.floor(pos.y+0.5), math.floor(pos.z+0.5) + local direction = mesecon.get_movestone_direction(pos) + + if not direction then -- no mesecon power + --push only solid nodes + local name = minetest.get_node(pos).name + if name ~= "air" and name ~= "ignore" + and ((not minetest.registered_nodes[name]) + or minetest.registered_nodes[name].liquidtype == "none") then + mesecon.mvps_push(pos, self.lastdir, + mesecon.setting("movestone_max_push", 50)) + --STICKY + mesecon.mvps_pull_all(pos, self.lastdir) + end + local nn = {name="mesecons_movestones:sticky_movestone"} + minetest.add_node(pos, nn) + self.object:remove() + mesecon.on_placenode(pos, nn) + return + end + + local success, stack, oldstack = + mesecon.mvps_push(pos, direction, mesecon.setting("movestone_max_push", 50)) + if not success then -- Too large stack/stopper in the way + local nn = {name="mesecons_movestones:sticky_movestone"} + minetest.add_node(pos, nn) + self.object:remove() + mesecon.on_placenode(pos, nn) + return + else + mesecon.mvps_process_stack (stack) + mesecon.mvps_move_objects (pos, direction, oldstack) + self.lastdir = direction + end + + self.object:setvelocity({x=direction.x*2, y=direction.y*2, z=direction.z*2}) + + --STICKY + mesecon.mvps_pull_all(pos, direction) + end, +}) + + +mesecon.register_mvps_unmov("mesecons_movestones:movestone_entity") +mesecon.register_mvps_unmov("mesecons_movestones:sticky_movestone_entity") diff --git a/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_movestone_arrows.png b/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_movestone_arrows.png new file mode 100644 index 0000000..358c357 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_movestone_arrows.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_movestone_side.png b/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_movestone_side.png new file mode 100644 index 0000000..de753ef Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_movestone_side.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_sticky_movestone.png b/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_sticky_movestone.png new file mode 100644 index 0000000..8953cf1 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_movestones/textures/jeija_sticky_movestone.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_mvps/depends.txt b/mods/minetest-mod-mesecons/mesecons_mvps/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_mvps/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_mvps/init.lua b/mods/minetest-mod-mesecons/mesecons_mvps/init.lua new file mode 100644 index 0000000..bcbda17 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_mvps/init.lua @@ -0,0 +1,235 @@ +--register stoppers for movestones/pistons + +mesecon.mvps_stoppers = {} +mesecon.mvps_unmov = {} +mesecon.on_mvps_move = {} + +function mesecon.is_mvps_stopper(node, pushdir, stack, stackid) + local get_stopper = mesecon.mvps_stoppers[node.name] + if type (get_stopper) == "function" then + get_stopper = get_stopper(node, pushdir, stack, stackid) + end + return get_stopper +end + +function mesecon.register_mvps_stopper(nodename, get_stopper) + if get_stopper == nil then + get_stopper = true + end + mesecon.mvps_stoppers[nodename] = get_stopper +end + +-- Objects that cannot be moved (e.g. movestones) +function mesecon.register_mvps_unmov(objectname) + mesecon.mvps_unmov[objectname] = true; +end + +function mesecon.is_mvps_unmov(objectname) + return mesecon.mvps_unmov[objectname] +end + +-- Functions to be called on mvps movement +function mesecon.register_on_mvps_move(callback) + mesecon.on_mvps_move[#mesecon.on_mvps_move+1] = callback +end + +local function on_mvps_move(moved_nodes) + for _, callback in ipairs(mesecon.on_mvps_move) do + callback(moved_nodes) + end +end + +function mesecon.mvps_process_stack(stack) + -- update mesecons for placed nodes ( has to be done after all nodes have been added ) + for _, n in ipairs(stack) do + mesecon.on_placenode(n.pos, minetest.get_node(n.pos)) + end +end + +function mesecon.mvps_get_stack(pos, dir, maximum) + -- determine the number of nodes to be pushed + local np = {x = pos.x, y = pos.y, z = pos.z} + local nodes = {} + while true do + local nn = minetest.get_node_or_nil(np) + if not nn or #nodes > maximum then + -- don't push at all, something is in the way (unloaded map or too many nodes) + return nil + end + + if nn.name == "air" + or (minetest.registered_nodes[nn.name] + and minetest.registered_nodes[nn.name].liquidtype ~= "none") then --is liquid + break + end + + table.insert (nodes, {node = nn, pos = np}) + + np = mesecon.addPosRule(np, dir) + end + return nodes +end + +function mesecon.mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: direction of push; maximum: maximum nodes to be pushed + local nodes = mesecon.mvps_get_stack(pos, dir, maximum) + + if not nodes then return end + -- determine if one of the nodes blocks the push + for id, n in ipairs(nodes) do + if mesecon.is_mvps_stopper(n.node, dir, nodes, id) then + return + end + end + + -- remove all nodes + for _, n in ipairs(nodes) do + n.meta = minetest.get_meta(n.pos):to_table() + minetest.remove_node(n.pos) + end + + -- update mesecons for removed nodes ( has to be done after all nodes have been removed ) + for _, n in ipairs(nodes) do + mesecon.on_dignode(n.pos, n.node) + end + + -- add nodes + for _, n in ipairs(nodes) do + local np = mesecon.addPosRule(n.pos, dir) + minetest.add_node(np, n.node) + minetest.get_meta(np):from_table(n.meta) + end + + local moved_nodes = {} + local oldstack = mesecon.tablecopy(nodes) + for i in ipairs(nodes) do + moved_nodes[i] = {} + moved_nodes[i].oldpos = nodes[i].pos + nodes[i].pos = mesecon.addPosRule(nodes[i].pos, dir) + moved_nodes[i].pos = nodes[i].pos + moved_nodes[i].node = nodes[i].node + moved_nodes[i].meta = nodes[i].meta + end + + on_mvps_move(moved_nodes) + + return true, nodes, oldstack +end + +mesecon.register_on_mvps_move(function(moved_nodes) + for _, n in ipairs(moved_nodes) do + mesecon.on_placenode(n.pos, n.node) + mesecon.update_autoconnect(n.pos) + end +end) + +function mesecon.mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: direction of pull (matches push direction for sticky pistons) + local np = mesecon.addPosRule(pos, dir) + local nn = minetest.get_node(np) + + if ((not minetest.registered_nodes[nn.name]) --unregistered node + or minetest.registered_nodes[nn.name].liquidtype == "none") --non-liquid node + and not mesecon.is_mvps_stopper(nn, {x = -dir.x, y = -dir.y, z = -dir.z}, {{pos = np, node = nn}}, 1) then --non-stopper node + local meta = minetest.get_meta(np):to_table() + minetest.remove_node(np) + minetest.add_node(pos, nn) + minetest.get_meta(pos):from_table(meta) + + nodeupdate(np) + nodeupdate(pos) + mesecon.on_dignode(np, nn) + mesecon.update_autoconnect(np) + on_mvps_move({{pos = pos, oldpos = np, node = nn, meta = meta}}) + end + return {{pos = np, node = {param2 = 0, name = "air"}}, {pos = pos, node = nn}} +end + +function mesecon.mvps_pull_all(pos, direction) -- pos: pos of mvps; direction: direction of pull + local lpos = {x=pos.x-direction.x, y=pos.y-direction.y, z=pos.z-direction.z} -- 1 away + local lnode = minetest.get_node(lpos) + local lpos2 = {x=pos.x-direction.x*2, y=pos.y-direction.y*2, z=pos.z-direction.z*2} -- 2 away + local lnode2 = minetest.get_node(lpos2) + + --avoid pulling solid nodes + if lnode.name ~= "ignore" + and lnode.name ~= "air" + and ((not minetest.registered_nodes[lnode.name]) + or minetest.registered_nodes[lnode.name].liquidtype == "none") then + return + end + + --avoid pulling empty or liquid nodes + if lnode2.name == "ignore" + or lnode2.name == "air" + or (minetest.registered_nodes[lnode2.name] + and minetest.registered_nodes[lnode2.name].liquidtype ~= "none") then + return + end + + local moved_nodes = {} + local oldpos = {x=lpos2.x + direction.x, y=lpos2.y + direction.y, z=lpos2.z + direction.z} + repeat + lnode2 = minetest.get_node(lpos2) + local meta = minetest.get_meta(lnode2):to_table() + minetest.add_node(oldpos, lnode2) + minetest.get_meta(oldpos):from_table(meta) + moved_nodes[#moved_nodes+1] = {pos = oldpos, oldpos = lpos2, node = lnode2, meta = meta} + nodeupdate(oldpos) + oldpos = {x=lpos2.x, y=lpos2.y, z=lpos2.z} + lpos2.x = lpos2.x-direction.x + lpos2.y = lpos2.y-direction.y + lpos2.z = lpos2.z-direction.z + lnode = minetest.get_node(lpos2) + until lnode.name == "air" + or lnode.name == "ignore" + or (minetest.registered_nodes[lnode.name] + and minetest.registered_nodes[lnode.name].liquidtype ~= "none") + minetest.remove_node(oldpos) + mesecon.on_dignode(oldpos, lnode2) + mesecon.update_autoconnect(oldpos) + on_mvps_move(moved_nodes) +end + +function mesecon.mvps_move_objects(pos, dir, nodestack) + local objects_to_move = {} + + -- Move object at tip of stack + local pushpos = mesecon.addPosRule(pos, -- get pos at tip of stack + {x = dir.x * #nodestack, + y = dir.y * #nodestack, + z = dir.z * #nodestack}) + + + local objects = minetest.get_objects_inside_radius(pushpos, 1) + for _, obj in ipairs(objects) do + table.insert(objects_to_move, obj) + end + + -- Move objects lying/standing on the stack (before it was pushed - oldstack) + if tonumber(minetest.setting_get("movement_gravity")) > 0 and dir.y == 0 then + -- If gravity positive and dir horizontal, push players standing on the stack + for _, n in ipairs(nodestack) do + local p_above = mesecon.addPosRule(n.pos, {x=0, y=1, z=0}) + local objects = minetest.get_objects_inside_radius(p_above, 1) + for _, obj in ipairs(objects) do + table.insert(objects_to_move, obj) + end + end + end + + for _, obj in ipairs(objects_to_move) do + local entity = obj:get_luaentity() + if not entity or not mesecon.is_mvps_unmov(entity.name) then + local np = mesecon.addPosRule(obj:getpos(), dir) + + --move only if destination is not solid + local nn = minetest.get_node(np) + if not ((not minetest.registered_nodes[nn.name]) + or minetest.registered_nodes[nn.name].walkable) then + obj:setpos(np) + end + end + end +end + +mesecon.register_mvps_stopper("default:chest_locked") +mesecon.register_mvps_stopper("default:furnace") diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/depends.txt b/mods/minetest-mod-mesecons/mesecons_noteblock/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_noteblock/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/init.lua b/mods/minetest-mod-mesecons/mesecons_noteblock/init.lua new file mode 100644 index 0000000..d63b93e --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_noteblock/init.lua @@ -0,0 +1,78 @@ +minetest.register_node("mesecons_noteblock:noteblock", { + description = "Noteblock", + tiles = {"mesecons_noteblock.png"}, + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}, + visual_scale = 1.3, + paramtype="light", + after_place_node = function(pos) + minetest.add_node(pos, {name="mesecons_noteblock:noteblock", param2=0}) + end, + on_punch = function (pos, node) -- change sound when punched + local param2 = node.param2+1 + if param2==12 then param2=0 end + minetest.add_node(pos, {name = node.name, param2 = param2}) + mesecon.noteblock_play(pos, param2) + end, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector = { -- play sound when activated + action_on = function (pos, node) + mesecon.noteblock_play(pos, node.param2) + end + }} +}) + +minetest.register_craft({ + output = "mesecons_noteblock:noteblock 1", + recipe = { + {"group:wood", "group:wood", "group:wood"}, + {"group:mesecon_conductor_craftable", "default:steel_ingot", "group:mesecon_conductor_craftable"}, + {"group:wood", "group:wood", "group:wood"}, + } +}) + +mesecon.noteblock_play = function (pos, param2) + local soundname + if param2==8 then + soundname="mesecons_noteblock_a" + elseif param2==9 then + soundname="mesecons_noteblock_asharp" + elseif param2==10 then + soundname="mesecons_noteblock_b" + elseif param2==11 then + soundname="mesecons_noteblock_c" + elseif param2==0 then + soundname="mesecons_noteblock_csharp" + elseif param2==1 then + soundname="mesecons_noteblock_d" + elseif param2==2 then + soundname="mesecons_noteblock_dsharp" + elseif param2==3 then + soundname="mesecons_noteblock_e" + elseif param2==4 then + soundname="mesecons_noteblock_f" + elseif param2==5 then + soundname="mesecons_noteblock_fsharp" + elseif param2==6 then + soundname="mesecons_noteblock_g" + elseif param2==7 then + soundname="mesecons_noteblock_gsharp" + end + local block_below_name = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name + if block_below_name == "default:glass" then + soundname="mesecons_noteblock_hihat" + end + if block_below_name == "default:stone" then + soundname="mesecons_noteblock_kick" + end + if block_below_name == "default:chest" then + soundname="mesecons_noteblock_snare" + end + if block_below_name == "default:tree" then + soundname="mesecons_noteblock_crash" + end + if block_below_name == "default:wood" then + soundname="mesecons_noteblock_litecrash" + end + minetest.sound_play(soundname, + {pos = pos, gain = 1.0, max_hear_distance = 32,}) +end diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a.ogg new file mode 100644 index 0000000..5668a8a Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp.ogg new file mode 100644 index 0000000..4cd2dcc Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b.ogg new file mode 100644 index 0000000..621a6b5 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c.ogg new file mode 100644 index 0000000..e235978 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_crash.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_crash.ogg new file mode 100644 index 0000000..d33027a Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_crash.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp.ogg new file mode 100644 index 0000000..50ba835 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d.ogg new file mode 100644 index 0000000..f1227ba Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp.ogg new file mode 100644 index 0000000..817728e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e.ogg new file mode 100644 index 0000000..c91d1a6 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f.ogg new file mode 100644 index 0000000..3f1eaea Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp.ogg new file mode 100644 index 0000000..9f13797 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g.ogg new file mode 100644 index 0000000..d2a90dd Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp.ogg new file mode 100644 index 0000000..6177b8c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_hihat.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_hihat.ogg new file mode 100644 index 0000000..d05a870 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_hihat.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_kick.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_kick.ogg new file mode 100644 index 0000000..108e89e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_kick.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_litecrash.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_litecrash.ogg new file mode 100644 index 0000000..21aecfa Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_litecrash.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_snare.ogg b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_snare.ogg new file mode 100644 index 0000000..25d7b78 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/sounds/mesecons_noteblock_snare.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_noteblock/textures/mesecons_noteblock.png b/mods/minetest-mod-mesecons/mesecons_noteblock/textures/mesecons_noteblock.png new file mode 100644 index 0000000..2d602a2 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_noteblock/textures/mesecons_noteblock.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/depends.txt b/mods/minetest-mod-mesecons/mesecons_pistons/depends.txt new file mode 100644 index 0000000..01f085b --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_pistons/depends.txt @@ -0,0 +1,2 @@ +mesecons +mesecons_mvps diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/init.lua b/mods/minetest-mod-mesecons/mesecons_pistons/init.lua new file mode 100644 index 0000000..71e63e7 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_pistons/init.lua @@ -0,0 +1,760 @@ +-- Get mesecon rules of pistons +piston_rules = +{{x=0, y=0, z=1}, --everything apart from z- (pusher side) + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=1, y=1, z=0}, + {x=1, y=-1, z=0}, + {x=-1, y=1, z=0}, + {x=-1, y=-1, z=0}, + {x=0, y=1, z=1}, + {x=0, y=-1, z=1}} + +local piston_up_rules = +{{x=0, y=0, z=-1}, --everything apart from y+ (pusher side) + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=1, y=-1, z=0}, + {x=-1, y=-1, z=0}, + {x=0, y=-1, z=1}, + {x=0, y=-1, z=-1}} + +local piston_down_rules = +{{x=0, y=0, z=-1}, --everything apart from y- (pusher side) + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=1, y=1, z=0}, + {x=-1, y=1, z=0}, + {x=0, y=1, z=1}, + {x=0, y=1, z=-1}} + +local piston_get_rules = function (node) + local rules = piston_rules + for i = 1, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +piston_facedir_direction = function (node) + local rules = {{x = 0, y = 0, z = -1}} + for i = 1, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules[1] +end + +piston_get_direction = function(dir, node) + if type(dir) == "function" then + return dir(node) + else + return dir + end +end + +local piston_remove_pusher = function(pos, node) + local pistonspec = minetest.registered_nodes[node.name].mesecons_piston + local dir = piston_get_direction(pistonspec.dir, node) + local pusherpos = mesecon.addPosRule(pos, dir) + local pushername = minetest.get_node(pusherpos).name + + -- make sure there actually is a pusher (for compatibility reasons mainly) + if pushername ~= pistonspec.pusher then + return + end + + minetest.remove_node(pusherpos) + minetest.sound_play("piston_retract", { + pos = pos, + max_hear_distance = 20, + gain = 0.3, + }) + nodeupdate(pusherpos) +end + +local piston_on = function(pos, node) + local pistonspec = minetest.registered_nodes[node.name].mesecons_piston + + local dir = piston_get_direction(pistonspec.dir, node) + local np = mesecon.addPosRule(pos, dir) + local maxpush = mesecon.setting("piston_max_push", 15) + local success, stack, oldstack = mesecon.mvps_push(np, dir, maxpush) + if success then + minetest.add_node(pos, {param2 = node.param2, name = pistonspec.onname}) + minetest.add_node(np, {param2 = node.param2, name = pistonspec.pusher}) + minetest.sound_play("piston_extend", { + pos = pos, + max_hear_distance = 20, + gain = 0.3, + }) + mesecon.mvps_process_stack (stack) + mesecon.mvps_move_objects (np, dir, oldstack) + end +end + +local piston_off = function(pos, node) + local pistonspec = minetest.registered_nodes[node.name].mesecons_piston + minetest.add_node(pos, {param2 = node.param2, name = pistonspec.offname}) + piston_remove_pusher(pos, node) + + if pistonspec.sticky then + local dir = piston_get_direction(pistonspec.dir, node) + local pullpos = mesecon.addPosRule(pos, dir) + local stack = mesecon.mvps_pull_single(pullpos, dir) + mesecon.mvps_process_stack(pos, dir, stack) + end +end + +local piston_orientate = function(pos, placer) + -- not placed by player + if not placer then return end + + -- placer pitch in degrees + local pitch = placer:get_look_pitch() * (180 / math.pi) + + local node = minetest.get_node(pos) + local pistonspec = minetest.registered_nodes[node.name].mesecons_piston + if pitch > 55 then --looking upwards + minetest.add_node(pos, {name=pistonspec.piston_down}) + elseif pitch < -55 then --looking downwards + minetest.add_node(pos, {name=pistonspec.piston_up}) + end +end + + +-- Horizontal pistons + +local pt = 3/16 -- pusher thickness + +local piston_pusher_box = { + type = "fixed", + fixed = { + {-2/16, -2/16, -.5 + pt, 2/16, 2/16, .5 + pt}, + {-.5 , -.5 , -.5 , .5 , .5 , -.5 + pt}, + } +} + +local piston_on_box = { + type = "fixed", + fixed = { + {-.5, -.5, -.5 + pt, .5, .5, .5} + } +} + + +-- Normal (non-sticky) ones: + +local pistonspec_normal = { + offname = "mesecons_pistons:piston_normal_off", + onname = "mesecons_pistons:piston_normal_on", + dir = piston_facedir_direction, + pusher = "mesecons_pistons:piston_pusher_normal", + piston_down = "mesecons_pistons:piston_down_normal_off", + piston_up = "mesecons_pistons:piston_up_normal_off", +} + +-- offstate +minetest.register_node("mesecons_pistons:piston_normal_off", { + description = "Piston", + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_bottom.png", + "mesecons_piston_left.png", + "mesecons_piston_right.png", + "mesecons_piston_back.png", + "mesecons_piston_pusher_front.png" + }, + groups = {cracky = 3}, + paramtype2 = "facedir", + after_place_node = piston_orientate, + mesecons_piston = pistonspec_normal, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_on = piston_on, + rules = piston_get_rules + }} +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_normal_on", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_bottom.png", + "mesecons_piston_left.png", + "mesecons_piston_right.png", + "mesecons_piston_back.png", + "mesecons_piston_on_front.png" + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_normal_off", + after_dig_node = piston_remove_pusher, + node_box = piston_on_box, + selection_box = piston_on_box, + mesecons_piston = pistonspec_normal, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_off = piston_off, + rules = piston_get_rules + }} +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_pusher_normal", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_top.png", + "mesecons_piston_pusher_bottom.png", + "mesecons_piston_pusher_left.png", + "mesecons_piston_pusher_right.png", + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_front.png" + }, + paramtype = "light", + paramtype2 = "facedir", + diggable = false, + corresponding_piston = "mesecons_pistons:piston_normal_on", + selection_box = piston_pusher_box, + node_box = piston_pusher_box, +}) + +-- Sticky ones + +local pistonspec_sticky = { + offname = "mesecons_pistons:piston_sticky_off", + onname = "mesecons_pistons:piston_sticky_on", + dir = piston_facedir_direction, + pusher = "mesecons_pistons:piston_pusher_sticky", + sticky = true, + piston_down = "mesecons_pistons:piston_down_sticky_off", + piston_up = "mesecons_pistons:piston_up_sticky_off", +} + +-- offstate +minetest.register_node("mesecons_pistons:piston_sticky_off", { + description = "Sticky Piston", + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_bottom.png", + "mesecons_piston_left.png", + "mesecons_piston_right.png", + "mesecons_piston_back.png", + "mesecons_piston_pusher_front_sticky.png" + }, + groups = {cracky = 3}, + paramtype2 = "facedir", + after_place_node = piston_orientate, + mesecons_piston = pistonspec_sticky, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_on = piston_on, + rules = piston_get_rules + }} +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_sticky_on", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_bottom.png", + "mesecons_piston_left.png", + "mesecons_piston_right.png", + "mesecons_piston_back.png", + "mesecons_piston_on_front.png" + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_normal_off", + after_dig_node = piston_remove_pusher, + node_box = piston_on_box, + selection_box = piston_on_box, + mesecons_piston = pistonspec_sticky, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_off = piston_off, + rules = piston_get_rules + }} +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_pusher_sticky", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_top.png", + "mesecons_piston_pusher_bottom.png", + "mesecons_piston_pusher_left.png", + "mesecons_piston_pusher_right.png", + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_front_sticky.png" + }, + paramtype = "light", + paramtype2 = "facedir", + diggable = false, + corresponding_piston = "mesecons_pistons:piston_sticky_on", + selection_box = piston_pusher_box, + node_box = piston_pusher_box, +}) + +-- +-- +-- UP +-- +-- + +local piston_up_pusher_box = { + type = "fixed", + fixed = { + {-2/16, -.5 - pt, -2/16, 2/16, .5 - pt, 2/16}, + {-.5 , .5 - pt, -.5 , .5 , .5 , .5}, + } +} + +local piston_up_on_box = { + type = "fixed", + fixed = { + {-.5, -.5, -.5 , .5, .5-pt, .5} + } +} + +-- Normal + +local pistonspec_normal_up = { + offname = "mesecons_pistons:piston_up_normal_off", + onname = "mesecons_pistons:piston_up_normal_on", + dir = {x = 0, y = 1, z = 0}, + pusher = "mesecons_pistons:piston_up_pusher_normal" +} + +-- offstate +minetest.register_node("mesecons_pistons:piston_up_normal_off", { + tiles = { + "mesecons_piston_pusher_front.png", + "mesecons_piston_back.png", + "mesecons_piston_left.png^[transformR270", + "mesecons_piston_right.png^[transformR90", + "mesecons_piston_bottom.png", + "mesecons_piston_top.png^[transformR180", + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_normal_off", + mesecons_piston = pistonspec_normal_up, + mesecons = {effector={ + action_on = piston_on, + rules = piston_up_rules, + }} +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_up_normal_on", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_on_front.png", + "mesecons_piston_back.png", + "mesecons_piston_left.png^[transformR270", + "mesecons_piston_right.png^[transformR90", + "mesecons_piston_bottom.png", + "mesecons_piston_top.png^[transformR180", + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_normal_off", + after_dig_node = piston_remove_pusher, + node_box = piston_up_on_box, + selection_box = piston_up_on_box, + mesecons_piston = pistonspec_normal_up, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_off = piston_off, + rules = piston_up_rules, + }} +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_up_pusher_normal", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_front.png", + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_left.png^[transformR270", + "mesecons_piston_pusher_right.png^[transformR90", + "mesecons_piston_pusher_bottom.png", + "mesecons_piston_pusher_top.png^[transformR180", + }, + paramtype = "light", + paramtype2 = "facedir", + diggable = false, + corresponding_piston = "mesecons_pistons:piston_up_normal_on", + selection_box = piston_up_pusher_box, + node_box = piston_up_pusher_box, +}) + + + +-- Sticky + + +local pistonspec_sticky_up = { + offname = "mesecons_pistons:piston_up_sticky_off", + onname = "mesecons_pistons:piston_up_sticky_on", + dir = {x = 0, y = 1, z = 0}, + pusher = "mesecons_pistons:piston_up_pusher_sticky", + sticky = true +} + +-- offstate +minetest.register_node("mesecons_pistons:piston_up_sticky_off", { + tiles = { + "mesecons_piston_pusher_front_sticky.png", + "mesecons_piston_back.png", + "mesecons_piston_left.png^[transformR270", + "mesecons_piston_right.png^[transformR90", + "mesecons_piston_bottom.png", + "mesecons_piston_top.png^[transformR180", + "mesecons_piston_tb.png" + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_sticky_off", + mesecons_piston = pistonspec_sticky_up, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_on = piston_on, + rules = piston_up_rules, + }} +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_up_sticky_on", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_on_front.png", + "mesecons_piston_back.png", + "mesecons_piston_left.png^[transformR270", + "mesecons_piston_right.png^[transformR90", + "mesecons_piston_bottom.png", + "mesecons_piston_top.png^[transformR180", + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_normal_off", + after_dig_node = piston_remove_pusher, + node_box = piston_up_on_box, + selection_box = piston_up_on_box, + mesecons_piston = pistonspec_sticky_up, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_off = piston_off, + rules = piston_up_rules, + }} +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_up_pusher_sticky", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_front_sticky.png", + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_left.png^[transformR270", + "mesecons_piston_pusher_right.png^[transformR90", + "mesecons_piston_pusher_bottom.png", + "mesecons_piston_pusher_top.png^[transformR180", + }, + paramtype = "light", + paramtype2 = "facedir", + diggable = false, + corresponding_piston = "mesecons_pistons:piston_up_sticky_on", + selection_box = piston_up_pusher_box, + node_box = piston_up_pusher_box, +}) + +-- +-- +-- DOWN +-- +-- + +local piston_down_pusher_box = { + type = "fixed", + fixed = { + {-2/16, -.5 + pt, -2/16, 2/16, .5 + pt, 2/16}, + {-.5 , -.5 , -.5 , .5 , -.5 + pt, .5}, + } +} + +local piston_down_on_box = { + type = "fixed", + fixed = { + {-.5, -.5+pt, -.5 , .5, .5, .5} + } +} + + + +-- Normal + +local pistonspec_normal_down = { + offname = "mesecons_pistons:piston_down_normal_off", + onname = "mesecons_pistons:piston_down_normal_on", + dir = {x = 0, y = -1, z = 0}, + pusher = "mesecons_pistons:piston_down_pusher_normal", +} + +-- offstate +minetest.register_node("mesecons_pistons:piston_down_normal_off", { + tiles = { + "mesecons_piston_back.png", + "mesecons_piston_pusher_front.png", + "mesecons_piston_left.png^[transformR90", + "mesecons_piston_right.png^[transformR270", + "mesecons_piston_bottom.png^[transformR180", + "mesecons_piston_top.png", + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_normal_off", + mesecons_piston = pistonspec_normal_down, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_on = piston_on, + rules = piston_down_rules, + }} +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_down_normal_on", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_back.png", + "mesecons_piston_on_front.png", + "mesecons_piston_left.png^[transformR90", + "mesecons_piston_right.png^[transformR270", + "mesecons_piston_bottom.png^[transformR180", + "mesecons_piston_top.png", + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_normal_off", + after_dig_node = piston_remove_pusher, + node_box = piston_down_on_box, + selection_box = piston_down_on_box, + mesecons_piston = pistonspec_normal_down, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_off = piston_off, + rules = piston_down_rules, + }} +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_down_pusher_normal", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_front.png", + "mesecons_piston_pusher_left.png^[transformR90", + "mesecons_piston_pusher_right.png^[transformR270", + "mesecons_piston_pusher_bottom.png^[transformR180", + "mesecons_piston_pusher_top.png", + }, + paramtype = "light", + paramtype2 = "facedir", + diggable = false, + corresponding_piston = "mesecons_pistons:piston_down_normal_on", + selection_box = piston_down_pusher_box, + node_box = piston_down_pusher_box, +}) + +-- Sticky + +local pistonspec_sticky_down = { + onname = "mesecons_pistons:piston_down_sticky_on", + offname = "mesecons_pistons:piston_down_sticky_off", + dir = {x = 0, y = -1, z = 0}, + pusher = "mesecons_pistons:piston_down_pusher_sticky", + sticky = true +} + +-- offstate +minetest.register_node("mesecons_pistons:piston_down_sticky_off", { + tiles = { + "mesecons_piston_back.png", + "mesecons_piston_pusher_front_sticky.png", + "mesecons_piston_left.png^[transformR90", + "mesecons_piston_right.png^[transformR270", + "mesecons_piston_bottom.png^[transformR180", + "mesecons_piston_top.png", + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_sticky_off", + mesecons_piston = pistonspec_sticky_down, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_on = piston_on, + rules = piston_down_rules, + }} +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_down_sticky_on", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_back.png", + "mesecons_piston_on_front.png", + "mesecons_piston_left.png^[transformR90", + "mesecons_piston_right.png^[transformR270", + "mesecons_piston_bottom.png^[transformR180", + "mesecons_piston_top.png", + }, + inventory_image = "mesecons_piston_top.png", + wield_image = "mesecons_piston_top.png", + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + drop = "mesecons_pistons:piston_sticky_off", + after_dig_node = piston_remove_pusher, + node_box = piston_down_on_box, + selection_box = piston_down_on_box, + mesecons_piston = pistonspec_sticky_down, + sounds = default.node_sound_wood_defaults(), + mesecons = {effector={ + action_off = piston_off, + rules = piston_down_rules, + }} +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_down_pusher_sticky", { + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_front_sticky.png", + "mesecons_piston_pusher_left.png^[transformR90", + "mesecons_piston_pusher_right.png^[transformR270", + "mesecons_piston_pusher_bottom.png^[transformR180", + "mesecons_piston_pusher_top.png", + }, + paramtype = "light", + paramtype2 = "facedir", + diggable = false, + corresponding_piston = "mesecons_pistons:piston_down_sticky_on", + selection_box = piston_down_pusher_box, + node_box = piston_down_pusher_box, +}) + + +-- Register pushers as stoppers if they would be seperated from the piston +local piston_pusher_get_stopper = function (node, dir, stack, stackid) + if (stack[stackid + 1] + and stack[stackid + 1].node.name == minetest.registered_nodes[node.name].corresponding_piston + and stack[stackid + 1].node.param2 == node.param2) + or (stack[stackid - 1] + and stack[stackid - 1].node.name == minetest.registered_nodes[node.name].corresponding_piston + and stack[stackid - 1].node.param2 == node.param2) then + return false + end + return true +end + +local piston_pusher_up_down_get_stopper = function (node, dir, stack, stackid) + if (stack[stackid + 1] + and stack[stackid + 1].node.name == minetest.registered_nodes[node.name].corresponding_piston) + or (stack[stackid - 1] + and stack[stackid - 1].node.name == minetest.registered_nodes[node.name].corresponding_piston) then + return false + end + return true +end + +mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_normal", piston_pusher_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_sticky", piston_pusher_get_stopper) + +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_pusher_normal", piston_pusher_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_pusher_sticky", piston_pusher_up_down_get_stopper) + +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_pusher_normal", piston_pusher_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_pusher_sticky", piston_pusher_up_down_get_stopper) + + +-- Register pistons as stoppers if they would be seperated from the stopper +local piston_up_down_get_stopper = function (node, dir, stack, stackid) + if (stack[stackid + 1] + and stack[stackid + 1].node.name == minetest.registered_nodes[node.name].mesecons_piston.pusher) + or (stack[stackid - 1] + and stack[stackid - 1].node.name == minetest.registered_nodes[node.name].mesecons_piston.pusher) then + return false + end + return true +end + +local piston_get_stopper = function (node, dir, stack, stackid) + pistonspec = minetest.registered_nodes[node.name].mesecons_piston + dir = piston_get_direction(pistonspec.dir, node) + local pusherpos = mesecon.addPosRule(stack[stackid].pos, dir) + local pushernode = minetest.get_node(pusherpos) + + if minetest.registered_nodes[node.name].mesecons_piston.pusher == pushernode.name then + for _, s in ipairs(stack) do + if mesecon.cmpPos(s.pos, pusherpos) -- pusher is also to be pushed + and s.node.param2 == node.param2 then + return false + end + end + end + return true +end + +mesecon.register_mvps_stopper("mesecons_pistons:piston_normal_on", piston_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_sticky_on", piston_get_stopper) + +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_normal_on", piston_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_sticky_on", piston_up_down_get_stopper) + +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_normal_on", piston_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_sticky_on", piston_up_down_get_stopper) + +--craft recipes +minetest.register_craft({ + output = "mesecons_pistons:piston_normal_off 2", + recipe = { + {"group:wood", "group:wood", "group:wood"}, + {"default:cobble", "default:steel_ingot", "default:cobble"}, + {"default:cobble", "group:mesecon_conductor_craftable", "default:cobble"}, + } +}) + +minetest.register_craft({ + output = "mesecons_pistons:piston_sticky_off", + recipe = { + {"mesecons_materials:glue"}, + {"mesecons_pistons:piston_normal_off"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/sounds/piston_extend.ogg b/mods/minetest-mod-mesecons/mesecons_pistons/sounds/piston_extend.ogg new file mode 100644 index 0000000..e234ad9 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/sounds/piston_extend.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/sounds/piston_retract.ogg b/mods/minetest-mod-mesecons/mesecons_pistons/sounds/piston_retract.ogg new file mode 100644 index 0000000..feb9f04 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/sounds/piston_retract.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_back.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_back.png new file mode 100644 index 0000000..6a57dce Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_back.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_bottom.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_bottom.png new file mode 100644 index 0000000..5a3af9b Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_bottom.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_left.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_left.png new file mode 100644 index 0000000..215dd73 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_left.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_on_front.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_on_front.png new file mode 100644 index 0000000..0ade67e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_on_front.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_back.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_back.png new file mode 100644 index 0000000..fe87943 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_back.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_bottom.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_bottom.png new file mode 100644 index 0000000..87c4e81 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_bottom.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front.png new file mode 100644 index 0000000..8ec9dc6 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front_sticky.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front_sticky.png new file mode 100644 index 0000000..e38b4e6 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front_sticky.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_left.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_left.png new file mode 100644 index 0000000..bc5495b Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_left.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_right.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_right.png new file mode 100644 index 0000000..32ee32f Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_right.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_top.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_top.png new file mode 100644 index 0000000..72f04e9 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_pusher_top.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_right.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_right.png new file mode 100644 index 0000000..176463c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_right.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_top.png b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_top.png new file mode 100644 index 0000000..5c8bace Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pistons/textures/mesecons_piston_top.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_powerplant/depends.txt b/mods/minetest-mod-mesecons/mesecons_powerplant/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_powerplant/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_powerplant/init.lua b/mods/minetest-mod-mesecons/mesecons_powerplant/init.lua new file mode 100644 index 0000000..33cedff --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_powerplant/init.lua @@ -0,0 +1,31 @@ +-- The POWER_PLANT +-- Just emits power. always. + +minetest.register_node("mesecons_powerplant:power_plant", { + drawtype = "plantlike", + visual_scale = 1, + tiles = {"jeija_power_plant.png"}, + inventory_image = "jeija_power_plant.png", + paramtype = "light", + walkable = false, + groups = {dig_immediate=3, mesecon = 2}, + light_source = LIGHT_MAX-9, + description="Power Plant", + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, + }, + sounds = default.node_sound_leaves_defaults(), + mesecons = {receptor = { + state = mesecon.state.on + }} +}) + +minetest.register_craft({ + output = "mesecons_powerplant:power_plant 1", + recipe = { + {"group:mesecon_conductor_craftable"}, + {"group:mesecon_conductor_craftable"}, + {"group:sapling"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_powerplant/textures/jeija_power_plant.png b/mods/minetest-mod-mesecons/mesecons_powerplant/textures/jeija_power_plant.png new file mode 100644 index 0000000..edc8891 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_powerplant/textures/jeija_power_plant.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/depends.txt b/mods/minetest-mod-mesecons/mesecons_pressureplates/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_pressureplates/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/init.lua b/mods/minetest-mod-mesecons/mesecons_pressureplates/init.lua new file mode 100644 index 0000000..0fda1f3 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_pressureplates/init.lua @@ -0,0 +1,94 @@ +local pp_box_off = { + type = "fixed", + fixed = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 }, +} + +local pp_box_on = { + type = "fixed", + fixed = { -7/16, -8/16, -7/16, 7/16, -7.5/16, 7/16 }, +} + +pp_on_timer = function (pos, elapsed) + local node = minetest.get_node(pos) + local basename = minetest.registered_nodes[node.name].pressureplate_basename + + -- This is a workaround for a strange bug that occurs when the server is started + -- For some reason the first time on_timer is called, the pos is wrong + if not basename then return end + + local objs = minetest.get_objects_inside_radius(pos, 1) + local two_below = mesecon.addPosRule(pos, {x = 0, y = -2, z = 0}) + + if objs[1] == nil and node.name == basename .. "_on" then + minetest.add_node(pos, {name = basename .. "_off"}) + mesecon.receptor_off(pos, mesecon.rules.pplate) + else + for k, obj in pairs(objs) do + local objpos = obj:getpos() + if objpos.y > pos.y-1 and objpos.y < pos.y then + minetest.add_node(pos, {name = basename .. "_on"}) + mesecon.receptor_on(pos, mesecon.rules.pplate ) + end + end + end + return true +end + +-- Register a Pressure Plate +-- offstate: name of the pressure plate when inactive +-- onstate: name of the pressure plate when active +-- description: description displayed in the player's inventory +-- tiles_off: textures of the pressure plate when inactive +-- tiles_on: textures of the pressure plate when active +-- image: inventory and wield image of the pressure plate +-- recipe: crafting recipe of the pressure plate + +function mesecon.register_pressure_plate(basename, description, textures_off, textures_on, image_w, image_i, recipe) + mesecon.register_node(basename, { + drawtype = "nodebox", + inventory_image = image_i, + wield_image = image_w, + paramtype = "light", + description = description, + pressureplate_basename = basename, + on_timer = pp_on_timer, + on_construct = function(pos) + minetest.get_node_timer(pos):start(mesecon.setting("pplate_interval", 0.1)) + end, + },{ + mesecons = {receptor = { state = mesecon.state.off, rules = mesecon.rules.pplate }}, + node_box = pp_box_off, + selection_box = pp_box_off, + groups = {snappy = 2, oddly_breakable_by_hand = 3}, + tiles = textures_off + },{ + mesecons = {receptor = { state = mesecon.state.on, rules = mesecon.rules.pplate }}, + node_box = pp_box_on, + selection_box = pp_box_on, + groups = {snappy = 2, oddly_breakable_by_hand = 3, not_in_creative_inventory = 1}, + tiles = textures_on + }) + + minetest.register_craft({ + output = basename .. "_off", + recipe = recipe, + }) +end + +mesecon.register_pressure_plate( + "mesecons_pressureplates:pressure_plate_wood", + "Wooden Pressure Plate", + {"jeija_pressure_plate_wood_off.png","jeija_pressure_plate_wood_off.png","jeija_pressure_plate_wood_off_edges.png"}, + {"jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on_edges.png"}, + "jeija_pressure_plate_wood_wield.png", + "jeija_pressure_plate_wood_inv.png", + {{"group:wood", "group:wood"}}) + +mesecon.register_pressure_plate( + "mesecons_pressureplates:pressure_plate_stone", + "Stone Pressure Plate", + {"jeija_pressure_plate_stone_off.png","jeija_pressure_plate_stone_off.png","jeija_pressure_plate_stone_off_edges.png"}, + {"jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on_edges.png"}, + "jeija_pressure_plate_stone_wield.png", + "jeija_pressure_plate_stone_inv.png", + {{"default:cobble", "default:cobble"}}) diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_inv.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_inv.png new file mode 100644 index 0000000..bfe5a1d Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_inv.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off.png new file mode 100644 index 0000000..46140da Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off_edges.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off_edges.png new file mode 100644 index 0000000..2ad9acc Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off_edges.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on.png new file mode 100644 index 0000000..dc64931 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on_edges.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on_edges.png new file mode 100644 index 0000000..51add95 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on_edges.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_wield.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_wield.png new file mode 100644 index 0000000..c533567 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_wield.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_inv.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_inv.png new file mode 100644 index 0000000..36dacd0 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_inv.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off.png new file mode 100644 index 0000000..ca98757 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off_edges.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off_edges.png new file mode 100644 index 0000000..665ae97 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off_edges.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on.png new file mode 100644 index 0000000..e1a7d8e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on_edges.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on_edges.png new file mode 100644 index 0000000..358f2ea Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on_edges.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_wield.png b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_wield.png new file mode 100644 index 0000000..50b321d Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_wield.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_random/depends.txt b/mods/minetest-mod-mesecons/mesecons_random/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_random/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_random/init.lua b/mods/minetest-mod-mesecons/mesecons_random/init.lua new file mode 100644 index 0000000..0136309 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_random/init.lua @@ -0,0 +1,85 @@ +-- REMOVESTONE + +minetest.register_node("mesecons_random:removestone", { + tiles = {"jeija_removestone.png"}, + inventory_image = minetest.inventorycube("jeija_removestone_inv.png"), + groups = {cracky=3}, + description="Removestone", + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + action_on = function (pos, node) + minetest.remove_node(pos) + mesecon.update_autoconnect(pos) + end + }} +}) + +minetest.register_craft({ + output = 'mesecons_random:removestone 4', + recipe = { + {"", "default:cobble", ""}, + {"default:cobble", "group:mesecon_conductor_craftable", "default:cobble"}, + {"", "default:cobble", ""}, + } +}) + +-- GHOSTSTONE + +minetest.register_node("mesecons_random:ghoststone", { + description="ghoststone", + tiles = {"jeija_ghoststone.png"}, + is_ground_content = true, + inventory_image = minetest.inventorycube("jeija_ghoststone_inv.png"), + groups = {cracky=3}, + sounds = default.node_sound_stone_defaults(), + mesecons = {conductor = { + state = mesecon.state.off, + rules = { --axes + {x = -1, y = 0, z = 0}, + {x = 1, y = 0, z = 0}, + {x = 0, y = -1, z = 0}, + {x = 0, y = 1, z = 0}, + {x = 0, y = 0, z = -1}, + {x = 0, y = 0, z = 1}, + }, + onstate = "mesecons_random:ghoststone_active" + }} +}) + +minetest.register_node("mesecons_random:ghoststone_active", { + drawtype = "airlike", + pointable = false, + walkable = false, + diggable = false, + sunlight_propagates = true, + paramtype = "light", + mesecons = {conductor = { + state = mesecon.state.on, + rules = { + {x = -1, y = 0, z = 0}, + {x = 1, y = 0, z = 0}, + {x = 0, y = -1, z = 0}, + {x = 0, y = 1, z = 0}, + {x = 0, y = 0, z = -1}, + {x = 0, y = 0, z = 1}, + }, + offstate = "mesecons_random:ghoststone" + }}, + on_construct = function(pos) + --remove shadow + pos2 = {x = pos.x, y = pos.y + 1, z = pos.z} + if ( minetest.get_node(pos2).name == "air" ) then + minetest.dig_node(pos2) + end + end +}) + + +minetest.register_craft({ + output = 'mesecons_random:ghoststone 4', + recipe = { + {"default:steel_ingot", "default:cobble", "default:steel_ingot"}, + {"default:cobble", "group:mesecon_conductor_craftable", "default:cobble"}, + {"default:steel_ingot", "default:cobble", "default:steel_ingot"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_ghoststone.png b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_ghoststone.png new file mode 100644 index 0000000..1917b7c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_ghoststone.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_ghoststone_inv.png b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_ghoststone_inv.png new file mode 100644 index 0000000..c715d7f Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_ghoststone_inv.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_removestone.png b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_removestone.png new file mode 100644 index 0000000..1917b7c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_removestone.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_removestone_inv.png b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_removestone_inv.png new file mode 100644 index 0000000..c715d7f Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_random/textures/jeija_removestone_inv.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/depends.txt b/mods/minetest-mod-mesecons/mesecons_receiver/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_receiver/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/init.lua b/mods/minetest-mod-mesecons/mesecons_receiver/init.lua new file mode 100644 index 0000000..b5c79e7 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_receiver/init.lua @@ -0,0 +1,158 @@ +rcvboxes = { + { -3/16, -3/16, -8/16 , 3/16, 3/16 , -13/32 }, -- the smaller bump + { -1/32, -1/32, -3/2 , 1/32, 1/32 , -1/2 }, -- the wire through the block + { -2/32, -1/2 , -.5 , 2/32, 0 , -.5002+3/32 }, -- the vertical wire bit + { -2/32, -1/2 , -7/16+0.002 , 2/32, -14/32, 16/32+0.001 } -- the horizontal wire +} + +local receiver_get_rules = function (node) + local rules = { {x = 1, y = 0, z = 0}, + {x = -2, y = 0, z = 0}} + if node.param2 == 2 then + rules = mesecon.rotate_rules_left(rules) + elseif node.param2 == 3 then + rules = mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) + elseif node.param2 == 0 then + rules = mesecon.rotate_rules_right(rules) + end + return rules +end + +minetest.register_node("mesecons_receiver:receiver_on", { + drawtype = "nodebox", + tiles = { + "receiver_top_on.png", + "receiver_bottom_on.png", + "receiver_lr_on.png", + "receiver_lr_on.png", + "receiver_fb_on.png", + "receiver_fb_on.png", + }, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + walkable = false, + selection_box = { + type = "fixed", + fixed = { -3/16, -8/16, -8/16, 3/16, 3/16, 8/16 } + }, + node_box = { + type = "fixed", + fixed = rcvboxes + }, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons:wire_00000000_off", + mesecons = {conductor = { + state = mesecon.state.on, + rules = receiver_get_rules, + offstate = "mesecons_receiver:receiver_off" + }} +}) + +minetest.register_node("mesecons_receiver:receiver_off", { + drawtype = "nodebox", + description = "You hacker you", + tiles = { + "receiver_top_off.png", + "receiver_bottom_off.png", + "receiver_lr_off.png", + "receiver_lr_off.png", + "receiver_fb_off.png", + "receiver_fb_off.png", + }, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + walkable = false, + selection_box = { + type = "fixed", + fixed = { -3/16, -8/16, -8/16, 3/16, 3/16, 8/16 } + }, + node_box = { + type = "fixed", + fixed = rcvboxes + }, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons:wire_00000000_off", + mesecons = {conductor = { + state = mesecon.state.off, + rules = receiver_get_rules, + onstate = "mesecons_receiver:receiver_on" + }} +}) + +function mesecon.receiver_get_pos_from_rcpt(pos, param2) + local rules = {{x = 2, y = 0, z = 0}} + if param2 == nil then param2 = minetest.get_node(pos).param2 end + if param2 == 2 then + rules = mesecon.rotate_rules_left(rules) + elseif param2 == 3 then + rules = mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) + elseif param2 == 0 then + rules = mesecon.rotate_rules_right(rules) + end + local np = { x = pos.x + rules[1].x, + y = pos.y + rules[1].y, + z = pos.z + rules[1].z} + return np +end + +function mesecon.receiver_place(rcpt_pos) + local node = minetest.get_node(rcpt_pos) + local pos = mesecon.receiver_get_pos_from_rcpt(rcpt_pos, node.param2) + local nn = minetest.get_node(pos) + + if string.find(nn.name, "mesecons:wire_") ~= nil then + minetest.dig_node(pos) + if mesecon.is_power_on(rcpt_pos) then + minetest.add_node(pos, {name = "mesecons_receiver:receiver_on", param2 = node.param2}) + mesecon.receptor_on(pos, receiver_get_rules(node)) + else + minetest.add_node(pos, {name = "mesecons_receiver:receiver_off", param2 = node.param2}) + end + mesecon.update_autoconnect(pos) + end +end + +function mesecon.receiver_remove(rcpt_pos, dugnode) + local pos = mesecon.receiver_get_pos_from_rcpt(rcpt_pos, dugnode.param2) + local nn = minetest.get_node(pos) + if string.find(nn.name, "mesecons_receiver:receiver_") ~=nil then + minetest.dig_node(pos) + local node = {name = "mesecons:wire_00000000_off"} + minetest.add_node(pos, node) + mesecon.update_autoconnect(pos) + mesecon.on_placenode(pos, node) + end +end + +minetest.register_on_placenode(function (pos, node) + if minetest.get_item_group(node.name, "mesecon_needs_receiver") == 1 then + mesecon.receiver_place(pos) + end +end) + +minetest.register_on_dignode(function(pos, node) + if minetest.get_item_group(node.name, "mesecon_needs_receiver") == 1 then + mesecon.receiver_remove(pos, node) + end +end) + +minetest.register_on_placenode(function (pos, node) + if string.find(node.name, "mesecons:wire_") ~=nil then + local rules = { {x = 2, y = 0, z = 0}, + {x =-2, y = 0, z = 0}, + {x = 0, y = 0, z = 2}, + {x = 0, y = 0, z =-2}} + local i = 1 + while rules[i] ~= nil do + local np = { x = pos.x + rules[i].x, + y = pos.y + rules[i].y, + z = pos.z + rules[i].z} + if minetest.get_item_group(minetest.get_node(np).name, "mesecon_needs_receiver") == 1 then + mesecon.receiver_place(np) + end + i = i + 1 + end + end +end) diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_bottom_off.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_bottom_off.png new file mode 100644 index 0000000..b95903e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_bottom_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_bottom_on.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_bottom_on.png new file mode 100644 index 0000000..d0b7006 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_bottom_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_fb_off.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_fb_off.png new file mode 100644 index 0000000..aed3008 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_fb_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_fb_on.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_fb_on.png new file mode 100644 index 0000000..0916736 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_fb_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_lr_off.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_lr_off.png new file mode 100644 index 0000000..1fb2b3a Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_lr_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_lr_on.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_lr_on.png new file mode 100644 index 0000000..087c0b4 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_lr_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_top_off.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_top_off.png new file mode 100644 index 0000000..ae50106 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_top_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_top_on.png b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_top_on.png new file mode 100644 index 0000000..5b48cac Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_receiver/textures/receiver_top_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_solarpanel/depends.txt b/mods/minetest-mod-mesecons/mesecons_solarpanel/depends.txt new file mode 100644 index 0000000..bc7b062 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_solarpanel/depends.txt @@ -0,0 +1,2 @@ +mesecons +mesecons_materials diff --git a/mods/minetest-mod-mesecons/mesecons_solarpanel/init.lua b/mods/minetest-mod-mesecons/mesecons_solarpanel/init.lua new file mode 100644 index 0000000..bc5a408 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_solarpanel/init.lua @@ -0,0 +1,95 @@ +-- Solar Panel +minetest.register_node("mesecons_solarpanel:solar_panel_on", { + drawtype = "nodebox", + tiles = { "jeija_solar_panel.png", }, + inventory_image = "jeija_solar_panel.png", + wield_image = "jeija_solar_panel.png", + paramtype = "light", + paramtype2 = "wallmounted", + walkable = false, + is_ground_content = true, + node_box = { + type = "wallmounted", + wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 }, + wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 }, + wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 }, + }, + selection_box = { + type = "wallmounted", + wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 }, + wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 }, + wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 }, + }, + drop = "mesecons_solarpanel:solar_panel_off", + groups = {dig_immediate=3, not_in_creative_inventory = 1}, + sounds = default.node_sound_glass_defaults(), + mesecons = {receptor = { + state = mesecon.state.on + }} +}) + +-- Solar Panel +minetest.register_node("mesecons_solarpanel:solar_panel_off", { + drawtype = "nodebox", + tiles = { "jeija_solar_panel.png", }, + inventory_image = "jeija_solar_panel.png", + wield_image = "jeija_solar_panel.png", + paramtype = "light", + paramtype2 = "wallmounted", + walkable = false, + is_ground_content = true, + node_box = { + type = "wallmounted", + wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 }, + wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 }, + wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 }, + }, + selection_box = { + type = "wallmounted", + wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 }, + wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 }, + wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 }, + }, + groups = {dig_immediate=3}, + description="Solar Panel", + sounds = default.node_sound_glass_defaults(), + mesecons = {receptor = { + state = mesecon.state.off + }} +}) + +minetest.register_craft({ + output = "mesecons_solarpanel:solar_panel_off 1", + recipe = { + {"mesecons_materials:silicon", "mesecons_materials:silicon"}, + {"mesecons_materials:silicon", "mesecons_materials:silicon"}, + } +}) + +minetest.register_abm( + {nodenames = {"mesecons_solarpanel:solar_panel_off"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local light = minetest.get_node_light(pos, nil) + + if light >= 12 then + minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_on", param2=node.param2}) + mesecon.receptor_on(pos) + end + end, +}) + +minetest.register_abm( + {nodenames = {"mesecons_solarpanel:solar_panel_on"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local light = minetest.get_node_light(pos, nil) + + if light < 12 then + minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_off", param2=node.param2}) + mesecon.receptor_off(pos) + end + end, +}) diff --git a/mods/minetest-mod-mesecons/mesecons_solarpanel/textures/jeija_solar_panel.png b/mods/minetest-mod-mesecons/mesecons_solarpanel/textures/jeija_solar_panel.png new file mode 100644 index 0000000..a7b0f75 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_solarpanel/textures/jeija_solar_panel.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_switch/depends.txt b/mods/minetest-mod-mesecons/mesecons_switch/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_switch/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_switch/init.lua b/mods/minetest-mod-mesecons/mesecons_switch/init.lua new file mode 100644 index 0000000..2b3c3ee --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_switch/init.lua @@ -0,0 +1,35 @@ +-- MESECON_SWITCH + +mesecon.register_node("mesecons_switch:mesecon_switch", { + paramtype2="facedir", + description="Switch", + sounds = default.node_sound_stone_defaults(), + on_punch = function (pos, node) + if(mesecon.flipstate(pos, node) == "on") then + mesecon.receptor_on(pos) + else + mesecon.receptor_off(pos) + end + minetest.sound_play("mesecons_switch", {pos=pos}) + end +},{ + groups = {dig_immediate=2}, + tiles = { "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_off.png"}, + mesecons = {receptor = { state = mesecon.state.off }} +},{ + groups = {dig_immediate=2, not_in_creative_inventory=1}, + tiles = { "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_on.png"}, + mesecons = {receptor = { state = mesecon.state.on }} +}) + +minetest.register_craft({ + output = "mesecons_switch:mesecon_switch_off 2", + recipe = { + {"default:steel_ingot", "default:cobble", "default:steel_ingot"}, + {"group:mesecon_conductor_craftable","", "group:mesecon_conductor_craftable"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_switch/sounds/mesecons_switch.ogg b/mods/minetest-mod-mesecons/mesecons_switch/sounds/mesecons_switch.ogg new file mode 100644 index 0000000..53d45c1 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_switch/sounds/mesecons_switch.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_torch/depends.txt b/mods/minetest-mod-mesecons/mesecons_torch/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_torch/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mods/minetest-mod-mesecons/mesecons_torch/init.lua b/mods/minetest-mod-mesecons/mesecons_torch/init.lua new file mode 100644 index 0000000..91f8e65 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_torch/init.lua @@ -0,0 +1,118 @@ +--MESECON TORCHES + +local rotate_torch_rules = function (rules, param2) + if param2 == 5 then + return mesecon.rotate_rules_right(rules) + elseif param2 == 2 then + return mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) --180 degrees + elseif param2 == 4 then + return mesecon.rotate_rules_left(rules) + elseif param2 == 1 then + return mesecon.rotate_rules_down(rules) + elseif param2 == 0 then + return mesecon.rotate_rules_up(rules) + else + return rules + end +end + +local torch_get_output_rules = function(node) + local rules = { + {x = 1, y = 0, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 0, y = 0, z =-1}, + {x = 0, y = 1, z = 0}, + {x = 0, y =-1, z = 0}} + + return rotate_torch_rules(rules, node.param2) +end + +local torch_get_input_rules = function(node) + local rules = {{x = -2, y = 0, z = 0}, + {x = -1, y = 1, z = 0}} + + return rotate_torch_rules(rules, node.param2) +end + +minetest.register_craft({ + output = "mesecons_torch:mesecon_torch_on 4", + recipe = { + {"group:mesecon_conductor_craftable"}, + {"default:stick"},} +}) + +local torch_selectionbox = +{ + type = "wallmounted", + wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1}, + wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1}, + wall_side = {-0.5, -0.1, -0.1, -0.5+0.6, 0.1, 0.1}, +} + +minetest.register_node("mesecons_torch:mesecon_torch_off", { + drawtype = "torchlike", + tiles = {"jeija_torches_off.png", "jeija_torches_off_ceiling.png", "jeija_torches_off_side.png"}, + inventory_image = "jeija_torches_off.png", + paramtype = "light", + walkable = false, + paramtype2 = "wallmounted", + selection_box = torch_selectionbox, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_torch:mesecon_torch_on", + mesecons = {receptor = { + state = mesecon.state.off, + rules = torch_get_output_rules + }} +}) + +minetest.register_node("mesecons_torch:mesecon_torch_on", { + drawtype = "torchlike", + tiles = {"jeija_torches_on.png", "jeija_torches_on_ceiling.png", "jeija_torches_on_side.png"}, + inventory_image = "jeija_torches_on.png", + wield_image = "jeija_torches_on.png", + paramtype = "light", + sunlight_propagates = true, + walkable = false, + paramtype2 = "wallmounted", + selection_box = torch_selectionbox, + groups = {dig_immediate=3}, + light_source = LIGHT_MAX-5, + description="Mesecon Torch", + mesecons = {receptor = { + state = mesecon.state.on, + rules = torch_get_output_rules + }}, +}) + +minetest.register_abm({ + nodenames = {"mesecons_torch:mesecon_torch_off","mesecons_torch:mesecon_torch_on"}, + interval = 1, + chance = 1, + action = function(pos, node) + local is_powered = false + for _, rule in ipairs(torch_get_input_rules(node)) do + local src = mesecon.addPosRule(pos, rule) + if mesecon.is_power_on(src) then + is_powered = true + end + end + + if is_powered then + if node.name == "mesecons_torch:mesecon_torch_on" then + minetest.swap_node(pos, {name = "mesecons_torch:mesecon_torch_off", param2 = node.param2}) + mesecon.receptor_off(pos, torch_get_output_rules(node)) + end + elseif node.name == "mesecons_torch:mesecon_torch_off" then + minetest.swap_node(pos, {name = "mesecons_torch:mesecon_torch_on", param2 = node.param2}) + mesecon.receptor_on(pos, torch_get_output_rules(node)) + end + end +}) + +-- Param2 Table (Block Attached To) +-- 5 = z-1 +-- 3 = x-1 +-- 4 = z+1 +-- 2 = x+1 +-- 0 = y+1 +-- 1 = y-1 diff --git a/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off.png b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off.png new file mode 100644 index 0000000..537920c Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off_ceiling.png b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off_ceiling.png new file mode 100644 index 0000000..3934e6e Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off_ceiling.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off_side.png b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off_side.png new file mode 100644 index 0000000..ecb2951 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_off_side.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on.png b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on.png new file mode 100644 index 0000000..a93dcc2 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on_ceiling.png b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on_ceiling.png new file mode 100644 index 0000000..24fe201 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on_ceiling.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on_side.png b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on_side.png new file mode 100644 index 0000000..fe7dfd2 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_torch/textures/jeija_torches_on_side.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/depends.txt b/mods/minetest-mod-mesecons/mesecons_walllever/depends.txt new file mode 100644 index 0000000..19c798c --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_walllever/depends.txt @@ -0,0 +1,2 @@ +mesecons +mesecons_receiver diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/init.lua b/mods/minetest-mod-mesecons/mesecons_walllever/init.lua new file mode 100644 index 0000000..bd71871 --- /dev/null +++ b/mods/minetest-mod-mesecons/mesecons_walllever/init.lua @@ -0,0 +1,75 @@ +-- WALL LEVER +-- Basically a switch that can be attached to a wall +-- Powers the block 2 nodes behind (using a receiver) +mesecon.register_node("mesecons_walllever:wall_lever", { + description="Lever", + drawtype = "nodebox", + inventory_image = "jeija_wall_lever_off.png", + wield_image = "jeija_wall_lever_off.png", + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + walkable = false, + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, 3/16, 8/16, 8/16, 8/16 }, + }, + sounds = default.node_sound_wood_defaults(), + on_punch = function (pos, node) + if(mesecon.flipstate(pos, node) == "on") then + mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) + else + mesecon.receptor_off(pos, mesecon.rules.buttonlike_get(node)) + end + minetest.sound_play("mesecons_lever", {pos=pos}) + end +},{ + tiles = { "jeija_wall_lever_tb.png", "jeija_wall_lever_bottom.png", + "jeija_wall_lever_sides.png", "jeija_wall_lever_sides.png", + "jeija_wall_lever_back.png", "jeija_wall_lever_off.png", + }, + node_box = { + type = "fixed", + fixed = {{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the base "slab" + { -5/16, -3/16, 5/16, 5/16, 3/16, 6/16 }, -- the lighted ring area + { -4/16, -2/16, 4/16, 4/16, 2/16, 5/16 }, -- the raised bit + { -2/16, -1/16, 3/16, 2/16, 1/16, 4/16 }, -- the lever "hinge" + { -1/16, -8/16, 4/16, 1/16, 0, 6/16 }} -- the lever itself. + }, + mesecons = {receptor = { + rules = mesecon.rules.buttonlike_get, + state = mesecon.state.off + }}, + groups = {dig_immediate = 2, mesecon_needs_receiver = 1} +},{ + tiles = { + "jeija_wall_lever_top.png", + "jeija_wall_lever_tb.png", + "jeija_wall_lever_sides.png", + "jeija_wall_lever_sides.png", + "jeija_wall_lever_back.png", + "jeija_wall_lever_on.png", + }, + node_box = { + type = "fixed", + fixed = {{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the base "slab" + { -5/16, -3/16, 5/16, 5/16, 3/16, 6/16 }, -- the lighted ring area + { -4/16, -2/16, 4/16, 4/16, 2/16, 5/16 }, -- the raised bit + { -2/16, -1/16, 3/16, 2/16, 1/16, 4/16 }, -- the lever "hinge" + { -1/16, 0, 4/16, 1/16, 8/16, 6/16 }} -- the lever itself. + }, + mesecons = {receptor = { + rules = mesecon.rules.buttonlike_get, + state = mesecon.state.on + }}, + groups = {dig_immediate = 2, mesecon_needs_receiver = 1, not_in_creative_inventory = 1} +}) + +minetest.register_craft({ + output = "mesecons_walllever:wall_lever_off 2", + recipe = { + {"group:mesecon_conductor_craftable"}, + {"default:stone"}, + {"default:stick"}, + } +}) diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/sounds/mesecons_lever.ogg b/mods/minetest-mod-mesecons/mesecons_walllever/sounds/mesecons_lever.ogg new file mode 100644 index 0000000..53d45c1 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/sounds/mesecons_lever.ogg differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_back.png b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_back.png new file mode 100644 index 0000000..9047e70 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_back.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_bottom.png b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_bottom.png new file mode 100644 index 0000000..041da96 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_bottom.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_off.png b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_off.png new file mode 100644 index 0000000..474f8c1 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_off.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_on.png b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_on.png new file mode 100644 index 0000000..01cbc24 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_on.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_sides.png b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_sides.png new file mode 100644 index 0000000..5864f26 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_sides.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_tb.png b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_tb.png new file mode 100644 index 0000000..50348d3 Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_tb.png differ diff --git a/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_top.png b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_top.png new file mode 100644 index 0000000..31161ec Binary files /dev/null and b/mods/minetest-mod-mesecons/mesecons_walllever/textures/jeija_wall_lever_top.png differ diff --git a/mods/minetest-mod-mesecons/modpack.txt b/mods/minetest-mod-mesecons/modpack.txt new file mode 100644 index 0000000..33d91f5 --- /dev/null +++ b/mods/minetest-mod-mesecons/modpack.txt @@ -0,0 +1 @@ +The presence of this file indicates that the current folder is a modpack. \ No newline at end of file diff --git a/mods/moreblocks/LICENSE.txt b/mods/moreblocks/LICENSE.txt new file mode 100644 index 0000000..726257d --- /dev/null +++ b/mods/moreblocks/LICENSE.txt @@ -0,0 +1,13 @@ ++---- zlib/libpng license ----+ + +Copyright (c) 2013-2014 Calinou and contributors + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/mods/moreblocks/README.txt b/mods/moreblocks/README.txt new file mode 100644 index 0000000..aa99eda --- /dev/null +++ b/mods/moreblocks/README.txt @@ -0,0 +1,12 @@ +More Blocks +========== + +More Blocks for Minetest (http://minetest.net), a free and open source infinite +world block sandbox game. + +To install, just clone this repository into your "mods" directory. + +More Blocks code is under the zlib license, textures are under CC BY-SA 3.0 unported. + +Forum topic: http://forum.minetest.net/viewtopic.php?id=509 + diff --git a/mods/moreblocks/aliases.lua b/mods/moreblocks/aliases.lua new file mode 100644 index 0000000..ad6fe35 --- /dev/null +++ b/mods/moreblocks/aliases.lua @@ -0,0 +1,75 @@ +-- More Blocks aliases + +minetest.register_alias("sweeper", "moreblocks:sweeper") +minetest.register_alias("circular_saw", "moreblocks:circular_saw") +minetest.register_alias("jungle_stick", "moreblocks:jungle_stick") + +-- Old block/item replacement + +minetest.register_alias("moreblocks:oerkkiblock", "default:mossycobble") +minetest.register_alias("moreblocks:screwdriver", "screwdriver:screwdriver") + +-- Node and item renaming + +minetest.register_alias("moreblocks:stone_bricks", "default:stonebrick") +minetest.register_alias("moreblocks:stonebrick", "default:stonebrick") +minetest.register_alias("moreblocks:junglewood", "default:junglewood") +minetest.register_alias("moreblocks:jungle_wood", "default:junglewood") + +for _, t in pairs(circular_saw.names) do + minetest.register_alias("moreblocks:"..t[1].."_jungle_wood"..t[2], + "moreblocks:"..t[1].."_junglewood"..t[2]) +end +minetest.register_alias("moreblocks:horizontaltree", "moreblocks:horizontal_tree") +minetest.register_alias("moreblocks:horizontaljungletree", "moreblocks:horizontal_jungle_tree") +minetest.register_alias("moreblocks:stonesquare", "moreblocks:stone_tile") +minetest.register_alias("moreblocks:circlestonebrick", "moreblocks:circle_stone_bricks") +minetest.register_alias("moreblocks:ironstonebrick", "moreblocks:iron_stone_bricks") +minetest.register_alias("moreblocks:fence_junglewood", "moreblocks:fence_jungle_wood") +minetest.register_alias("moreblocks:coalstone", "moreblocks:coal_stone") +minetest.register_alias("moreblocks:ironstone", "moreblocks:iron_stone") +minetest.register_alias("moreblocks:woodtile", "moreblocks:wood_tile") +minetest.register_alias("moreblocks:woodtile_full", "moreblocks:wood_tile_full") +minetest.register_alias("moreblocks:woodtile_centered", "moreblocks:wood_tile_centered") +minetest.register_alias("moreblocks:woodtile_up", "moreblocks:wood_tile_up") +minetest.register_alias("moreblocks:woodtile_down", "moreblocks:wood_tile_down") +minetest.register_alias("moreblocks:woodtile_left", "moreblocks:wood_tile_left") +minetest.register_alias("moreblocks:woodtile_right", "moreblocks:wood_tile_right") +minetest.register_alias("moreblocks:coalglass", "moreblocks:coal_glass") +minetest.register_alias("moreblocks:ironglass", "moreblocks:iron_glass") +minetest.register_alias("moreblocks:glowglass", "moreblocks:glow_glass") +minetest.register_alias("moreblocks:superglowglass", "moreblocks:super_glow_glass") +minetest.register_alias("moreblocks:trapglass", "moreblocks:trap_glass") +minetest.register_alias("moreblocks:trapstone", "moreblocks:trap_stone") +minetest.register_alias("moreblocks:cactuschecker", "moreblocks:cactus_checker") +minetest.register_alias("moreblocks:coalchecker", "moreblocks:coal_checker") +minetest.register_alias("moreblocks:ironchecker", "moreblocks:iron_checker") +minetest.register_alias("moreblocks:cactusbrick", "moreblocks:cactus_brick") +minetest.register_alias("moreblocks:cleanglass", "moreblocks:clean_glass") +minetest.register_alias("moreblocks:emptybookshelf", "moreblocks:empty_bookshelf") +minetest.register_alias("moreblocks:junglestick", "moreblocks:jungle_stick") +minetest.register_alias("moreblocks:splitstonesquare","moreblocks:split_stone_tile") +minetest.register_alias("moreblocks:allfacestree","moreblocks:all_faces_tree") + +-- ABM for horizontal trees (fix facedir). + +local horizontal_tree_convert_facedir = {7, 12, 9, 18} + +minetest.register_abm({ + nodenames = {"moreblocks:horizontal_tree","moreblocks:horizontal_jungle_tree"}, + interval = 1, + chance = 1, + action = function(pos, node) + if node.name == "moreblocks:horizontal_tree" then + node.name = "default:tree" + else + node.name = "default:jungletree" + end + node.param2 = node.param2 < 3 and node.param2 or 0 + minetest.set_node(pos, { + name = node.name, + param2 = horizontal_tree_convert_facedir[node.param2 + 1] + }) + end, +}) + diff --git a/mods/moreblocks/circular_saw.lua b/mods/moreblocks/circular_saw.lua new file mode 100644 index 0000000..b7d791c --- /dev/null +++ b/mods/moreblocks/circular_saw.lua @@ -0,0 +1,360 @@ + +local S = moreblocks.gettext +circular_saw = {} + +circular_saw.known_stairs = setmetatable({}, { + __newindex = function(k, v) + local modname = minetest.get_current_modname() + print(("WARNING: mod %s tried to add node %s to the circular saw" + .." manually."):format(modname, v)) + end, +}) + +-- This is populated by stairsplus:register_all +circular_saw.known_nodes = {} + +-- How many microblocks does this shape at the output inventory cost? +circular_saw.cost_in_microblocks = { + 1, 1, 1, 1, 1, 1, 1, 2, + 2, 3, 2, 4, 2, 4, 5, 6, + 7, 1, 1, 2, 4, 6, 7, 8, + 3, 1, 1, 2, 4, 0, 0, 0, +} + +circular_saw.names = { + {"micro", "_1"}, + {"panel", "_1"}, + {"micro", "_2"}, + {"panel", "_2"}, + {"micro", "_4"}, + {"panel", "_4"}, + {"micro", ""}, + {"panel", ""}, + {"micro", "_12"}, + {"panel", "_12"}, + {"micro", "_14"}, + {"panel", "_14"}, + {"micro", "_15"}, + {"panel", "_15"}, + {"stair", "_outer"}, + {"stair", ""}, + {"stair", "_inner"}, + {"slab", "_1"}, + {"slab", "_2"}, + {"slab", "_quarter"}, + {"slab", ""}, + {"slab", "_three_quarter"}, + {"slab", "_14"}, + {"slab", "_15"}, + {"stair", "_half"}, + {"stair", "_alt_1"}, + {"stair", "_alt_2"}, + {"stair", "_alt_4"}, + {"stair", "_alt"}, +} + +function circular_saw:get_cost(inv, stackname) + for i, item in pairs(inv:get_list("output")) do + if item:get_name() == stackname then + return circular_saw.cost_in_microblocks[i] + end + end +end + +function circular_saw:get_output_inv(modname, material, amount, max) + if (not max or max < 1) then + max = 99 + end + + local list = {} + -- If there is nothing inside display empty inventory + if amount < 1 then + return list + end + + for i, t in ipairs(circular_saw.names) do + local cost = circular_saw.cost_in_microblocks[i] + table.insert(list, modname..":"..t[1].."_"..material..t[2] + .." "..math.min(math.floor(amount/cost), max)) + end + return list +end + + +-- Reset empty circular_saw after last full block has been taken out +-- (or the circular_saw has been placed the first time) +-- note: max_offered is not reset +function circular_saw:reset(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + inv:set_list("input", {}) + inv:set_list("micro", {}) + inv:set_list("output", {}) + meta:set_int("anz", 0) + + meta:set_string("infotext", + S("Circular Saw is empty (owned by %s)") + :format(meta:get_string("owner") or "")) +end + + +-- Player has taken something out of the box or placed something inside +-- that amounts to count microblocks +function circular_saw:update_inventory(pos, amount) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + + amount = meta:get_int("anz") + amount + + -- The material is recycled automaticly. + inv:set_list("recycle", {}) + + if amount < 1 then -- If the last block is taken out. + self:reset(pos) + return + end + + local stack = inv:get_stack("input", 1) + -- At least one "normal" block is necessary to see what kind of stairs are requested. + if stack:is_empty() then + -- Any microblocks not taken out yet are now lost. + -- (covers material loss in the machine) + self:reset(pos) + return + + end + local node_name = stack:get_name() + local name_parts = circular_saw.known_nodes[node_name] + local modname = name_parts[1] + local material = name_parts[2] + + -- Display as many full blocks as possible + inv:set_list("input", { + node_name.." ".. math.floor(amount / 8) + }) + + -- The stairnodes made of default nodes use moreblocks namespace, other mods keep own. + if modname == "default" then + modname = "moreblocks" + end + --print("circular_saw set to " ..modname.. " : " + -- ..material.. " with "..(amount).." microblocks.") + + -- 0-7 microblocks may remain left-over. + inv:set_list("micro", { + modname..":micro_"..material.."_bottom "..(amount % 8) + }) + -- Display + inv:set_list("output", + self:get_output_inv(modname, material, amount, + meta:get_int("max_offered"))) + -- Store how many microblocks are available + meta:set_int("anz", amount) + + meta:set_string("infotext", + S("Circular Saw is working on %s (owned by %s)") + :format(material, meta:get_string("owner") or "")) +end + + +-- The amount of items offered per shape can be configured +function circular_saw.on_receive_fields(pos, formname, fields, sender) + local meta = minetest.get_meta(pos) + local max = tonumber(fields.max_offered) + if max and max > 0 then + meta:set_string("max_offered", max) + -- update to show the correct number of items + circular_saw:update_inventory(pos, 0) + end +end + + +-- Moving the inventory of the circular_saw around is not allowed because it +-- is a fictional inventory. Moving inventory around would be rather +-- impractical and make things more difficult to calculate. +function circular_saw.allow_metadata_inventory_move( + pos, from_list, from_index, to_list, to_index, count, player) + return 0 +end + + +-- Only input- and recycle-slot are intended as input slots +function circular_saw.allow_metadata_inventory_put( + pos, listname, index, stack, player) + -- The player is not allowed to put something in there + if listname == "output" or listname == "micro" then + return 0 + end + + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stackname = stack:get_name() + local count = stack:get_count() + + -- Only alow those items that are offered in the output inventory to be recycled + if listname == "recycle" then + if not inv:contains_item("output", stackname) then + return 0 + end + local stackmax = stack:get_stack_max() + local instack = inv:get_stack("input", 1) + local microstack = inv:get_stack("micro", 1) + local incount = instack:get_count() + local incost = (incount * 8) + microstack:get_count() + local maxcost = (stackmax * 8) + 7 + local cost = circular_saw:get_cost(inv, stackname) + if (incost + cost) > maxcost then + return math.max((maxcost - incost) / cost, 0) + end + return count + end + + -- Only accept certain blocks as input which are known to be craftable into stairs + if listname == "input" then + if not inv:is_empty("input") and + inv:get_stack("input", index):get_name() ~= stackname then + return 0 + end + for name, t in pairs(circular_saw.known_nodes) do + if name == stackname and inv:room_for_item("input", stack) then + return count + end + end + return 0 + end +end + +-- Taking is allowed from all slots (even the internal microblock slot) +-- Putting something in is slightly more complicated than taking anything +-- because we have to make sure it is of a suitable material +function circular_saw.on_metadata_inventory_put( + pos, listname, index, stack, player) + -- We need to find out if the circular_saw is already set to a + -- specific material or not + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stackname = stack:get_name() + local count = stack:get_count() + + -- Putting something into the input slot is only possible if that had + -- been empty before or did contain something of the same material + if listname == "input" then + -- Each new block is worth 8 microblocks + circular_saw:update_inventory(pos, 8 * count) + elseif listname == "recycle" then + -- Lets look which shape this represents + local cost = circular_saw:get_cost(inv, stackname) + circular_saw:update_inventory(pos, cost * count) + end +end + +function circular_saw.on_metadata_inventory_take( + pos, listname, index, stack, player) + -- If it is one of the offered stairs: find out how many + -- microblocks have to be substracted + if listname == "output" then + -- We do know how much each block at each position costs + local cost = circular_saw.cost_in_microblocks[index] + * stack:get_count() + + circular_saw:update_inventory(pos, -cost) + elseif listname == "micro" then + -- Each microblock costs 1 microblock + circular_saw:update_inventory(pos, -stack:get_count()) + elseif listname == "input" then + -- Each normal (= full) block taken costs 8 microblocks + circular_saw:update_inventory(pos, 8 * -stack:get_count()) + end + -- The recycle field plays no role here since it is processed immediately. +end + + +function circular_saw.on_construct(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", "size[11,9]".. + "label[0,0;"..S("Input\nmaterial").."]".. + "list[current_name;input;1.5,0;1,1;]".. + "label[0,1;"..S("Left-over").."]".. + "list[current_name;micro;1.5,1;1,1;]".. + "label[0,2;"..S("Recycle\noutput").."]".. + "list[current_name;recycle;1.5,2;1,1;]".. + "field[0.3,3.5;1,1;max_offered;"..S("Max")..":;${max_offered}]".. + "button[1,3.2;1,1;Set;"..S("Set").."]".. + "list[current_name;output;2.8,0;8,4;]".. + "list[current_player;main;1.5,5;8,4;]") + + meta:set_int("anz", 0) -- No microblocks inside yet. + meta:set_string("max_offered", 99) -- How many items of this kind are offered by default? + meta:set_string("infotext", S("Circular Saw is empty")) + + local inv = meta:get_inventory() + inv:set_size("input", 1) -- Input slot for full blocks of material x. + inv:set_size("micro", 1) -- Storage for 1-7 surplus microblocks. + inv:set_size("recycle", 1) -- Surplus partial blocks can be placed here. + inv:set_size("output", 4*8) -- 4x8 versions of stair-parts of material x. + + circular_saw:reset(pos) +end + + +function circular_saw.can_dig(pos,player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if not inv:is_empty("input") or + not inv:is_empty("micro") or + not inv:is_empty("recycle") then + return false + end + + -- Can be dug by anyone when empty ,not only by the owner. + return true +end + +minetest.register_node("moreblocks:circular_saw", { + description = S("Circular Saw"), + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-0.4, -0.5, -0.4, -0.25, 0.25, -0.25}, -- Leg + {0.25, -0.5, 0.25, 0.4, 0.25, 0.4}, -- Leg + {-0.4, -0.5, 0.25, -0.25, 0.25, 0.4}, -- Leg + {0.25, -0.5, -0.4, 0.4, 0.25, -0.25}, -- Leg + {-0.5, 0.25, -0.5, 0.5, 0.375, 0.5}, -- Tabletop + {-0.01, 0.4375, -0.125, 0.01, 0.5, 0.125}, -- Saw blade (top) + {-0.01, 0.375, -0.1875, 0.01, 0.4375, 0.1875}, -- Saw blade (bottom) + {-0.25, -0.0625, -0.25, 0.25, 0.25, 0.25}, -- Motor case + }, + }, + tiles = {"moreblocks_circular_saw_top.png", + "moreblocks_circular_saw_bottom.png", + "moreblocks_circular_saw_side.png"}, + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy = 2,oddly_breakable_by_hand = 2}, + sounds = default.node_sound_wood_defaults(), + on_construct = circular_saw.on_construct, + can_dig = circular_saw.can_dig, + -- Set the owner of this circular saw. + after_place_node = function(pos, placer) + local meta = minetest.get_meta(pos) + local owner = placer and placer:get_player_name() or "" + meta:set_string("owner", owner) + meta:set_string("infotext", + S("Circular Saw is empty (owned by %s)") + :format(owner)) + end, + + -- The amount of items offered per shape can be configured. + on_receive_fields = circular_saw.on_receive_fields, + allow_metadata_inventory_move = circular_saw.allow_metadata_inventory_move, + -- Only input- and recycle-slot are intended as input slots. + allow_metadata_inventory_put = circular_saw.allow_metadata_inventory_put, + -- Taking is allowed from all slots (even the internal microblock slot). Moving is forbidden. + -- Putting something in is slightly more complicated than taking anything because we have to make sure it is of a suitable material. + on_metadata_inventory_put = circular_saw.on_metadata_inventory_put, + on_metadata_inventory_take = circular_saw.on_metadata_inventory_take, +}) + diff --git a/mods/moreblocks/config.lua b/mods/moreblocks/config.lua new file mode 100644 index 0000000..d257ab6 --- /dev/null +++ b/mods/moreblocks/config.lua @@ -0,0 +1,25 @@ +moreblocks.config = {} + +local function getbool_default(setting, default) + local value = minetest.setting_getbool(setting) + if value == nil then + value = default + end + return value +end + +local function setting(settingtype, name, default) + if settingtype == "bool" then + moreblocks.config[name] = + getbool_default("moreblocks." .. name, default) + else + moreblocks.config[name] = + minetest.setting_get("moreblocks." .. name) or default + end +end + +-- Whether to direct wood based on player posititon when placing the block (true or false). +setting("bool", "wood_facedir", false) + +-- Show stairs/slabs/panels/microblocks in creative inventory (true or false). +setting("bool", "show_stairsplus_creative_inv", false) diff --git a/mods/moreblocks/crafting.lua b/mods/moreblocks/crafting.lua new file mode 100644 index 0000000..d54e8ef --- /dev/null +++ b/mods/moreblocks/crafting.lua @@ -0,0 +1,424 @@ +-- Crafting + +minetest.register_craft({ + output = "default:stick", + recipe = {{"default:dry_shrub"},} +}) + +minetest.register_craft({ + output = "default:stick", + recipe = {{"default:sapling"},} +}) + +minetest.register_craft({ + output = "default:stick", + recipe = {{"default:junglesapling"},} +}) + +minetest.register_craft({ + output = "default:wood", + recipe = { + {"default:stick", "default:stick"}, + {"default:stick", "default:stick"}, + } +}) + +minetest.register_craft({ + output = "default:junglewood", + recipe = { + {"moreblocks:jungle_stick", "moreblocks:jungle_stick"}, + {"moreblocks:jungle_stick", "moreblocks:jungle_stick"}, + } +}) + +minetest.register_craft({ + output = "default:dirt_with_grass", + type = "shapeless", + recipe = {"default:junglegrass", "default:dirt"}, +}) + +minetest.register_craft({ + output = "default:dirt_with_grass", + type = "shapeless", + recipe = {"default:mese", "default:dirt"}, +}) + +minetest.register_craft({ + output = "default:mossycobble", + type = "shapeless", + recipe = {"default:junglegrass", "default:cobble"}, +}) + +minetest.register_craft({ + output = "default:mossycobble", + type = "shapeless", + recipe = {"default:mese_crystal_fragment", "default:cobble"}, +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile 9", + recipe = { + {"default:wood", "default:wood", "default:wood"}, + {"default:wood", "default:wood", "default:wood"}, + {"default:wood", "default:wood", "default:wood"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile_flipped", + recipe = {{"moreblocks:wood_tile"},} +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile_center 9", + recipe = { + {"default:wood", "default:wood", "default:wood"}, + {"default:wood", "moreblocks:wood_tile", "default:wood"}, + {"default:wood", "default:wood", "default:wood"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile_full 4", + recipe = { + {"moreblocks:wood_tile", "moreblocks:wood_tile"}, + {"moreblocks:wood_tile", "moreblocks:wood_tile"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile_up", + recipe = { + {"default:stick"}, + {"moreblocks:wood_tile_center"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile_down", + recipe = { + {"moreblocks:wood_tile_center"}, + {"default:stick"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile_left", + recipe = { + {"default:stick", "moreblocks:wood_tile_center"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:wood_tile_right", + recipe = { + {"moreblocks:wood_tile_center", "default:stick"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:junglestick 4", + recipe = {{"default:junglewood"},} +}) + +minetest.register_craft({ + output = "moreblocks:fence_jungle_wood 2", + recipe = { + {"moreblocks:jungle_stick", "moreblocks:jungle_stick", "moreblocks:jungle_stick"}, + {"moreblocks:jungle_stick", "moreblocks:jungle_stick", "moreblocks:jungle_stick"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:circle_stone_bricks 8", + recipe = { + {"default:stone", "default:stone", "default:stone"}, + {"default:stone", "", "default:stone"}, + {"default:stone", "default:stone", "default:stone"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:all_faces_tree 8", + recipe = { + {"default:tree", "default:tree", "default:tree"}, + {"default:tree", "", "default:tree"}, + {"default:tree", "default:tree", "default:tree"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:all_faces_jungle_tree 8", + recipe = { + {"default:jungletree", "default:jungletree", "default:jungletree"}, + {"default:jungletree", "", "default:jungletree"}, + {"default:jungletree", "default:jungletree", "default:jungletree"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:sweeper 4", + recipe = { + {"default:junglegrass"}, + {"default:stick"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:stone_tile 4", + recipe = { + {"default:cobble", "default:cobble"}, + {"default:cobble", "default:cobble"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:split_stone_tile", + recipe = { + {"moreblocks:stone_tile"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:empty_bookshelf", + type = "shapeless", + recipe = {"moreblocks:sweeper", "default:bookshelf"}, +}) + +minetest.register_craft({ + output = "moreblocks:coal_stone_bricks 4", + recipe = { + {"moreblocks:coal_stone", "moreblocks:coal_stone"}, + {"moreblocks:coal_stone", "moreblocks:coal_stone"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:iron_stone_bricks 4", + recipe = { + {"moreblocks:iron_stone", "moreblocks:iron_stone"}, + {"moreblocks:iron_stone", "moreblocks:iron_stone"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:plankstone 4", + recipe = { + {"default:stone", "default:wood"}, + {"default:wood", "default:stone"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:plankstone 4", + recipe = { + {"default:wood", "default:stone"}, + {"default:stone", "default:wood"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:coal_checker 4", + recipe = { + {"default:stone", "default:coal_lump"}, + {"default:coal_lump", "default:stone"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:coal_checker 4", + recipe = { + {"default:coal_lump", "default:stone"}, + {"default:stone", "default:coal_lump"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:iron_checker 4", + recipe = { + {"default:steel_ingot", "default:stone"}, + {"default:stone", "default:steel_ingot"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:iron_checker 4", + recipe = { + {"default:stone", "default:steel_ingot"}, + {"default:steel_ingot", "default:stone"}, + } +}) + +minetest.register_craft({ + output = "default:chest_locked", + type = "shapeless", + recipe = {"default:steel_ingot", "default:chest"}, +}) +minetest.register_craft({ + output = "default:chest_locked", + type = "shapeless", + recipe = {"default:copper_ingot", "default:chest"}, +}) + +minetest.register_craft({ + output = "default:chest_locked", + type = "shapeless", + recipe = {"default:bronze_ingot", "default:chest"}, +}) + +minetest.register_craft({ + output = "default:chest_locked", + type = "shapeless", + recipe = {"default:gold_ingot", "default:chest"}, +}) + +minetest.register_craft({ + output = "moreblocks:iron_glass", + type = "shapeless", + recipe = {"default:steel_ingot", "default:glass"}, +}) + +minetest.register_craft({ + output = "default:glass", + type = "shapeless", + recipe = {"default:coal_lump", "moreblocks:iron_glass"}, +}) + + +minetest.register_craft({ + output = "moreblocks:coal_glass", + type = "shapeless", + recipe = {"default:coal_lump", "default:glass"}, +}) + +minetest.register_craft({ + output = "default:glass", + type = "shapeless", + recipe = {"default:steel_ingot", "moreblocks:coal_glass"}, +}) + +minetest.register_craft({ + output = "moreblocks:clean_glass", + type = "shapeless", + recipe = {"moreblocks:sweeper", "default:glass"}, +}) + +minetest.register_craft({ + output = "moreblocks:glow_glass", + type = "shapeless", + recipe = {"default:torch", "default:glass"}, +}) + +minetest.register_craft({ + output = "moreblocks:trap_glow_glass", + type = "shapeless", + recipe = {"default:mese_crystal_fragment", "default:glass", "default:torch"}, +}) + +minetest.register_craft({ + output = "moreblocks:trap_glow_glass", + type = "shapeless", + recipe = {"default:mese_crystal_fragment", "moreblocks:glow_glass"}, +}) + +minetest.register_craft({ + output = "moreblocks:super_glow_glass", + type = "shapeless", + recipe = {"default:torch", "default:torch", "default:glass"}, +}) + +minetest.register_craft({ + output = "moreblocks:super_glow_glass", + type = "shapeless", + recipe = {"default:torch", "moreblocks:glow_glass"}, +}) + + +minetest.register_craft({ + output = "moreblocks:trap_super_glow_glass", + type = "shapeless", + recipe = {"default:mese_crystal_fragment", "default:glass", "default:torch", "default:torch"}, +}) + +minetest.register_craft({ + output = "moreblocks:trap_super_glow_glass", + type = "shapeless", + recipe = {"default:mese_crystal_fragment", "moreblocks:super_glow_glass"}, +}) + +minetest.register_craft({ + output = "moreblocks:coal_stone", + type = "shapeless", + recipe = {"default:coal_lump", "default:stone"}, +}) + +minetest.register_craft({ + output = "default:stone", + type = "shapeless", + recipe = {"default:steel_ingot", "moreblocks:coal_stone"}, +}) + +minetest.register_craft({ + output = "moreblocks:iron_stone", + type = "shapeless", + recipe = {"default:steel_ingot", "default:stone"}, +}) + +minetest.register_craft({ + output = "default:stone", + type = "shapeless", + recipe = {"default:coal_lump", "moreblocks:iron_stone"}, +}) + +minetest.register_craft({ + output = "moreblocks:trap_stone", + type = "shapeless", + recipe = {"default:mese_crystal_fragment", "default:stone"}, +}) + +minetest.register_craft({ + output = "moreblocks:trap_glass", + type = "shapeless", + recipe = {"default:mese_crystal_fragment", "default:glass"}, +}) + +minetest.register_craft({ + output = "moreblocks:cactus_brick", + type = "shapeless", + recipe = {"default:cactus", "default:brick"}, +}) + +minetest.register_craft({ + output = "moreblocks:cactus_checker 4", + recipe = { + {"default:cactus", "default:stone"}, + {"default:stone", "default:cactus"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:cactuschecker 4", + recipe = { + {"default:stone", "default:cactus"}, + {"default:cactus", "default:stone"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:rope 3", + recipe = { + {"default:junglegrass"}, + {"default:junglegrass"}, + {"default:junglegrass"}, + } +}) + +minetest.register_craft({ + output = "moreblocks:circular_saw", + recipe = { + { "", "default:steel_ingot", "" }, + { "group:wood", "group:wood", "group:wood"}, + { "group:wood", "", "group:wood"}, + } +}) + diff --git a/mods/moreblocks/depends.txt b/mods/moreblocks/depends.txt new file mode 100644 index 0000000..198fe8a --- /dev/null +++ b/mods/moreblocks/depends.txt @@ -0,0 +1,2 @@ +default +intllib? diff --git a/mods/moreblocks/init.lua b/mods/moreblocks/init.lua new file mode 100644 index 0000000..27cf9d5 --- /dev/null +++ b/mods/moreblocks/init.lua @@ -0,0 +1,31 @@ +--[[ +-- More Blocks (moreblocks) by Calinou +-- Licensed under the zlib license for code and CC BY-SA 3.0 for textures, see LICENSE.txt for info. +--]] + +moreblocks = {} + +-- Load translation library if intllib is installed + +local S = nil +if intllib then + S = intllib.Getter() +else + S = function(s) return s end +end +moreblocks.gettext = S + +local modpath = minetest.get_modpath("moreblocks") + +dofile(modpath .. "/config.lua") +dofile(modpath .. "/circular_saw.lua") +dofile(modpath .. "/stairsplus/init.lua") +dofile(modpath .. "/nodes.lua") +dofile(modpath .. "/redefinitions.lua") +dofile(modpath .. "/crafting.lua") +dofile(modpath .. "/aliases.lua") + +if minetest.setting_getbool("log_mods") then + print(S("[moreblocks] loaded.")) +end + diff --git a/mods/moreblocks/locale/de.txt b/mods/moreblocks/locale/de.txt new file mode 100644 index 0000000..542f977 --- /dev/null +++ b/mods/moreblocks/locale/de.txt @@ -0,0 +1,67 @@ +# Translation by Xanthin + +###init.lua### +[moreblocks] loaded. = [moreblocks] geladen. + +###nodes.lua### +Jungle Wood Fence = Tropenholzzaun +Empty Bookshelf = Leeres Buecherregal +Clean Glass = Klares Glas +Plankstone = Brettstein +Wooden Tile = Holzfliese +Full Wooden Tile = Vollholzfliese +Centered Wooden Tile = Holzfliese mittig +Up Wooden Tile = Holzfliese oben +Down Wooden Tile = Holzfliese unten +Left Wooden Tile = Holzfliese links +Right Wooden Tile = Holzfliese rechts +Circle Stone Bricks = Kreissteinziegel +Stone Tile = Steinfliese +Split Stone Tile = Geteilte Steinfliese +Glow Glass = Leuchtglas +Super Glow Glass = Superleuchtglas +Coal Glass = Kohleglas +Iron Glass = Eisenglas +Coal Checker = Karierte Kohle +Iron Checker = Kariertes Eisen +Trap Stone = Steinfalle +Trap Glass = Glasfalle +Trap Glow Glass = Leuchtglasfalle +Trap Super Glow Glass = Superleuchtglasfalle +Coal Stone = Kohlestein +Iron Stone = Eisenstein +Coal Stone Bricks = Kohlesteinziegel +Iron Stone Bricks = Eisensteinziegel +Cactus Checker = Karierter Kaktus +Cactus Brick = Kaktusziegel +Sweeper = Besen +Jungle Stick = Tropenholzstock +Rope = Seil +All-faces Tree = Baumscheibenstamm + +###circular_saw.lua### +Circular Saw = Kreissaege +Circular saw, empty (owned by %s) = Kreissaege, leer (gehoert %s) +Circular saw, working with %s (owned by %s) = Kreissaege, arbeitet mit %s (gehoert %s) +Circular saw, empty = Kreissaege, leer +Circular saw is empty (owned by %s) = Kreissaege ist leer (gehoert %s) + +Input\nmaterial = Ausgangs-\nmaterial +Left-over = Rest +Max = Anzahl +Set = Ok +Recycle\noutput = Wiederver-\nwerten + +###./stairsplus/*### +%s Stairs = %streppe +%s Slab = %sstufe +%s Panel = %spaneel +%s Microblock = %smikroblock + +%s Pane = %sscheibe +%s Fence = %szaun + +###ownership.lua### +someone = jemand +Sorry, %s owns that spot. = Tut mir leid, %s gehoert diese Stelle. + diff --git a/mods/moreblocks/locale/es.txt b/mods/moreblocks/locale/es.txt new file mode 100644 index 0000000..d11ba49 --- /dev/null +++ b/mods/moreblocks/locale/es.txt @@ -0,0 +1,52 @@ +# Translation by kaeza + +[moreblocks] loaded. = [moreblocks] cargado. + +Jungle Wooden Planks = Tablones de madera de jungla +Empty Bookshelf = Estante para libros vacío +Clean Glass = Cristal Limpio +Plankstone = Tablones de piedra +Wooden Tile = Parquet +Full Wooden Tile = Parquet Completo +Centered Wooden Tile = Parquet Centrado +Up Wooden Tile = Parquet Superior +Down Wooden Tile = Parquet Inferior +Left Wooden Tile = Parquet Izquierdo +Right Wooden Tile = Parquet Derecho +Circle Stone Bricks = Bloques de Piedra Circulares +Stone Tile = Baldosa de Piedra +Split Stone Tile = Baldosas de Piedra Partida +Glow Glass = Cristal Brillante +Super Glow Glass = Cristal Súper Brillante +Coal Glass = Cristal con Carbón +Iron Glass = Cristal con Hierro +Coal Checker = Cuadros de Carbón +Iron Checker = Cuadros de Hierro +Trap Stone = Piedra Trampa +Trap Glass = Cristal Trampa +Coal Stone = Carbón y Piedra +Iron Stone = Hierro y Piedra +Cactus Checker = Cuadros de Cactus +Cactus Brick = Ladrillos de Cactus +Sweeper = Limpiador +Jungle Stick = Varita de Madera de Jungla +Horizontal Tree = Tronco de árbol horizontal +Horizontal Jungle Tree = Tronco de árbol de la jungla horizontal +Rope = Soga +All-faces Tree = Tronco de Ãrbol + +%s Stairs = Escalera de %s +%s Slab = Losa de %s +%s Panel = Panel de %s +%s Microblock = Microbloque de %s + +Wooden = Madera +Papyrus = Papiro +Dry Shrub = Arbusto Desértico +Sapling = Brote de Ãrbol +Wooden Planks = Tablones de Madera +Ladder = Escalera de Mano +Glass = Cristal + +%s Pane = Panel de %s +%s Fence = Valla de %s diff --git a/mods/moreblocks/locale/fr.txt b/mods/moreblocks/locale/fr.txt new file mode 100644 index 0000000..6bd7f98 --- /dev/null +++ b/mods/moreblocks/locale/fr.txt @@ -0,0 +1,72 @@ +# Translation by Calinou + +###init.lua### +[moreblocks] loaded. = [moreblocks] a été chargé. + +Jungle Wooden Planks = Planches de bois de jungle +Empty Bookshelf = Ètagère vide +Clean Glass = Verre propre +Plankstone = Pierre-bois +Wooden Tile = Dalle en bois +Full Wooden Tile = Dalle en bois complète +Centered Wooden Tile = Dalle en bois centrée +Up Wooden Tile = Dalle en bois vers le haut +Down Wooden Tile = Dalle en bois vers le bas +Left Wooden Tile = Dalle en bois vers la gauche +Right Wooden Tile = Dalle en bois vers la droite +Circle Stone Bricks = Briques en pierre circulaires +Stone Tile = Dalle en pierre +Split Stone Tile = Dalle en pierre découpée +Glow Glass = Verre brillant +Super Glow Glass = Verre très brillant +Coal Glass = Verre de charbon +Iron Glass = Verre de fer +Coal Checker = Damier en charbon +Iron Checker = Damier en fer +Trap Stone = Pierre traversable +Trap Glass = Verre traversable +Trap Glow Glass = Verre brillant traversable +Trap Super Glow Glass = Verre très brillant traversable +Coal Stone = Pierre de charbon +Iron Stone = Pierre de fer +Coal Stone Bricks = Briques en pierre de charbon +Iron Stone Bricks = Briques en pierre de fer +Cactus Checker = Damier en cactus +Cactus Brick = Briques de cactus +Sweeper = Balai +Jungle Stick = Bâton en bois de jungle +Horizontal Tree = Tronc d'arbre horizontal +Horizontal Jungle Tree = Tronc d'arbre de jungle horizontal +Rope = Corde +All-faces Tree = Tronc d'arbre + +###redefinition.lua### +Wooden = bois +Papyrus = Papyrus +Dry Shrub = Buisson mort +Sapling = Pousse d'arbre +Wooden Planks = Planches de bois +Ladder = Échelle +Glass = Verre + +###circular_saw.lua### +Circular Saw = Scie circulaire +Circular saw, empty (owned by %s) = Scie circulaire, vide (propriété de %s) +Circular saw, working with %s (owned by %s) = Scie circulaire, manipule %s (propriété de %s) +Circular saw, empty = Scie circulaire, vide +Circular saw is empty (owned by %s) = Scie circulaire est vide (propriété de %s) + +Input material = Entrée du matériel +Rest/microblocks = Reste/microbloc +Max: = Max: +Set = Fixer +Recycle output = Recyclage + +###./stairsplus/*### +%s Stairs = Escaliers en %s +%s Slab = Demi-dalle en %s +%s Panel = Barre en %s +%s Microblock = Microbloc en %s + +%s Pane = Panneau en %s +%s Fence = Barrière en %s \ No newline at end of file diff --git a/mods/moreblocks/locale/template.txt b/mods/moreblocks/locale/template.txt new file mode 100644 index 0000000..2b88227 --- /dev/null +++ b/mods/moreblocks/locale/template.txt @@ -0,0 +1,64 @@ +###init.lua### +[moreblocks] loaded. = + +###nodes.lua### +Jungle Wood Fence = +Empty Bookshelf = +Clean Glass = +Plankstone = +Wooden Tile = +Full Wooden Tile = +Centered Wooden Tile = +Up Wooden Tile = +Down Wooden Tile = +Left Wooden Tile = +Right Wooden Tile = +Circle Stone Bricks = +Stone Tile = +Split Stone Tile = +Glow Glass = +Super Glow Glass = +Coal Glass = +Iron Glass = +Coal Checker = +Iron Checker = +Trap Stone = +Trap Glass = +Trap Glow Glass = +Trap Super Glow Glass = +Coal Stone = +Iron Stone = +Coal Stone Bricks = +Iron Stone Bricks = +Cactus Checker = +Cactus Brick = +Sweeper = +Jungle Stick = +Rope = +All-faces Tree = + +###circular_saw.lua### +Circular Saw = +Circular saw, empty (owned by %s) = +Circular saw, working with %s (owned by %s) = +Circular saw, empty = +Circular saw is empty (owned by %s) = + +Input\nmaterial = +Left-over = +Max = +Set = +Recycle\noutput = + +###ownership.lua### +someone = +Sorry, %s owns that spot. = + +###./stairsplus/*### +%s Stairs = +%s Slab = +%s Panel = +%s Microblock = + +%s Pane = +%s Fence = diff --git a/mods/moreblocks/nodes.lua b/mods/moreblocks/nodes.lua new file mode 100644 index 0000000..95718c8 --- /dev/null +++ b/mods/moreblocks/nodes.lua @@ -0,0 +1,315 @@ +local S = moreblocks.gettext + +local sound_wood = default.node_sound_wood_defaults() +local sound_stone = default.node_sound_stone_defaults() +local sound_glass = default.node_sound_glass_defaults() +local sound_leaves = default.node_sound_leaves_defaults() + +local function tile_tiles(name) + local tex = "moreblocks_"..name..".png" + return {tex, tex, tex, tex, tex.."^[transformR90", tex.."^[transformR90"} +end + +local nodes = { + ["wood_tile"] = { + description = S("Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile"), + sounds = sound_wood, + }, + ["wood_tile_flipped"] = { + description = S("Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile_flipped"), + sounds = sound_wood, + no_stairs = true, + }, + ["wood_tile_center"] = { + description = S("Centered Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile_center"), + sounds = sound_wood, + }, + ["wood_tile_full"] = { + description = S("Full Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile_full"), + sounds = sound_wood, + }, + ["wood_tile_up"] = { + description = S("Up Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile_up"), + sounds = sound_wood, + no_stairs = true, + }, + ["wood_tile_down"] = { + description = S("Down Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile_down"), + sounds = sound_wood, + no_stairs = true, + }, + ["wood_tile_left"] = { + description = S("Left Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile_left"), + sounds = sound_wood, + no_stairs = true, + }, + ["wood_tile_right"] = { + description = S("Right Wooden Tile"), + groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3}, + paramtype2 = "facedir", + tiles = tile_tiles("wood_tile_right"), + sounds = sound_wood, + no_stairs = true, + }, + ["circle_stone_bricks"] = { + description = S("Circle Stone Bricks"), + groups = {cracky=3}, + sounds = sound_stone, + }, + ["coal_stone_bricks"] = { + description = S("Coal Stone Bricks"), + groups = {cracky=3}, + sounds = sound_stone, + }, + ["iron_stone_bricks"] = { + description = S("Iron Stone Bricks"), + groups = {cracky=3}, + sounds = sound_stone, + }, + ["stone_tile"] = { + description = S("Stone Tile"), + groups = {cracky=3}, + sounds = sound_stone, + }, + ["split_stone_tile"] = { + description = S("Split Stone Tile"), + tiles = {"moreblocks_split_stone_tile_top.png", + "moreblocks_split_stone_tile.png"}, + groups = {cracky=3}, + sounds = sound_stone, + }, + ["plankstone"] = { + description = S("Plankstone"), + groups = {cracky=3}, + tiles = tile_tiles("plankstone"), + sounds = sound_stone, + }, + ["iron_glass"] = { + description = S("Iron Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + }, + ["coal_glass"] = { + description = S("Coal Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + }, + ["clean_glass"] = { + description = S("Clean Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + }, + ["cactus_brick"] = { + description = S("Cactus Brick"), + groups = {cracky=3}, + sounds = sound_stone, + }, + ["cactus_checker"] = { + description = S("Cactus Checker"), + groups = {cracky=3}, + paramtype2 = "facedir", + tiles = tile_tiles("cactus_checker"), + sounds = sound_stone, + }, + ["empty_bookshelf"] = { + description = S("Empty Bookshelf"), + tiles = {"default_wood.png", "default_wood.png", + "moreblocks_empty_bookshelf.png"}, + groups = {snappy=2,choppy=3,oddly_breakable_by_hand=2,flammable=3}, + sounds = sound_wood, + no_stairs = true, + }, + ["coal_stone"] = { + description = S("Coal Stone"), + groups = {cracky=3}, + sounds = sound_stone, + }, + ["iron_stone"] = { + description = S("Iron Stone"), + groups = {cracky=3}, + sounds = sound_stone, + }, + ["coal_checker"] = { + description = S("Coal Checker"), + tiles = tile_tiles("coal_checker"), + paramtype2 = "facedir", + groups = {cracky=3}, + sounds = sound_stone, + }, + ["iron_checker"] = { + description = S("Iron Checker"), + tiles = tile_tiles("iron_checker"), + paramtype2 = "facedir", + groups = {cracky=3}, + sounds = sound_stone, + }, + ["trap_stone"] = { + description = S("Trap Stone"), + walkable = false, + groups = {cracky=3}, + sounds = sound_stone, + no_stairs = true, + }, + ["trap_glass"] = { + description = S("Trap Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + walkable = false, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + no_stairs = true, + }, + ["fence_jungle_wood"] = { + description = S("Jungle Wood Fence"), + drawtype = "fencelike", + tiles = {"default_junglewood.png"}, + inventory_image = "default_fence_overlay.png^default_junglewood.png^default_fence_overlay.png^[makealpha:255,126,126", + wield_image = "default_fence_overlay.png^default_junglewood.png^default_fence_overlay.png^[makealpha:255,126,126", + paramtype = "light", + selection_box = { + type = "fixed", + fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7}, + }, + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,flammable=2}, + sounds = sound_wood, + no_stairs = true, + }, + ["all_faces_tree"] = { + description = S("All-faces Tree"), + tiles = {"default_tree_top.png"}, + groups = {tree=1,snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2}, + sounds = sound_wood, + furnace_burntime = 30, + }, + ["all_faces_jungle_tree"] = { + description = S("All-faces Jungle Tree"), + tiles = {"default_jungletree_top.png"}, + groups = {tree=1,snappy=1,choppy=2,oddly_breakable_by_hand=1,flammable=2}, + sounds = sound_wood, + furnace_burntime = 30, + }, + ["glow_glass"] = { + description = S("Glow Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + light_source = 11, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + }, + ["trap_glow_glass"] = { + description = S("Trap Glow Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + light_source = 11, + walkable = false, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + no_stairs = true, + }, + ["super_glow_glass"] = { + description = S("Super Glow Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + light_source = 15, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + }, + ["trap_super_glow_glass"] = { + description = S("Trap Super Glow Glass"), + drawtype = "glasslike_framed", + paramtype = "light", + sunlight_propagates = true, + light_source = 15, + walkable = false, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + sounds = sound_glass, + no_stairs = true, + }, + ["rope"] = { + description = S("Rope"), + drawtype = "signlike", + inventory_image = "moreblocks_rope.png", + wield_image = "moreblocks_rope.png", + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "wallmounted", + walkable = false, + climbable = true, + selection_box = {type = "wallmounted",}, + groups = {snappy = 3, flammable = 2}, + sounds = sound_leaves, + no_stairs = true, + }, +} + +for name, def in pairs(nodes) do + def.tiles = def.tiles or {"moreblocks_"..name..".png"} + minetest.register_node("moreblocks:"..name, def) + minetest.register_alias(name, "moreblocks:"..name) + if not def.no_stairs then + local groups = {} + for k, v in pairs(def.groups) do groups[k] = v end + stairsplus:register_all("moreblocks", name, "moreblocks:"..name, { + description = def.description, + groups = groups, + tiles = def.tiles, + sunlight_propagates = def.sunlight_propagates, + light_source = def.light_source, + sounds = def.sounds, + }) + end +end + + +-- Items + +minetest.register_craftitem("moreblocks:sweeper", { + description = S("Sweeper"), + inventory_image = "moreblocks_sweeper.png", +}) + +minetest.register_craftitem("moreblocks:jungle_stick", { + description = S("Jungle Stick"), + inventory_image = "moreblocks_junglestick.png", + groups = {stick=1}, +}) + +minetest.register_craftitem("moreblocks:nothing", { + inventory_image = "invisible.png", + on_use = function() end, +}) + diff --git a/mods/moreblocks/ownership.lua b/mods/moreblocks/ownership.lua new file mode 100644 index 0000000..9cd4cb3 --- /dev/null +++ b/mods/moreblocks/ownership.lua @@ -0,0 +1,35 @@ + +local S = moreblocks.gettext + +function moreblocks.node_is_owned(pos, placer) + local ownername = false + if type(IsPlayerNodeOwner) == "function" then -- node_ownership mod + if HasOwner(pos, placer) then -- returns true if the node is owned + if not IsPlayerNodeOwner(pos, placer:get_player_name()) then + if type(getLastOwner) == "function" then -- ...is an old version + ownername = getLastOwner(pos) + elseif type(GetNodeOwnerName) == "function" then -- ...is a recent version + ownername = GetNodeOwnerName(pos) + else + ownername = S("someone") + end + end + end + + elseif type(isprotect)=="function" then -- glomie's protection mod + if not isprotect(5, pos, placer) then + ownername = S("someone") + end + elseif type(protector)=="table" and type(protector.can_dig)=="function" then -- Zeg9's protection mod + if not protector.can_dig(5, pos, placer) then + ownername = S("someone") + end + end + + if ownername ~= false then + minetest.chat_send_player( placer:get_player_name(), S("Sorry, %s owns that spot."):format(ownername) ) + return true + else + return false + end +end diff --git a/mods/moreblocks/redefinitions.lua b/mods/moreblocks/redefinitions.lua new file mode 100644 index 0000000..8dad8a7 --- /dev/null +++ b/mods/moreblocks/redefinitions.lua @@ -0,0 +1,143 @@ +-- Redefinitions of some default crafting recipes + +minetest.register_craft({ + output = "default:sign_wall 4", + recipe = { + {"default:wood", "default:wood", "default:wood"}, + {"default:wood", "default:wood", "default:wood"}, + {"", "default:stick", ""}, + } +}) + +minetest.register_craft({ + output = "default:ladder 3", + recipe = { + {"default:stick", "", "default:stick"}, + {"default:stick", "default:stick", "default:stick"}, + {"default:stick", "", "default:stick"}, + } +}) + +minetest.register_craft({ + output = "default:paper 3", + recipe = { + {"default:papyrus", "default:papyrus", "default:papyrus"}, + } +}) + +minetest.register_craft({ + output = "default:rail 16", + recipe = { + {"default:steel_ingot", "", "default:steel_ingot"}, + {"default:steel_ingot", "default:stick", "default:steel_ingot"}, + {"default:steel_ingot", "", "default:steel_ingot"}, + } +}) + +minetest.register_craft({ + output = "default:axe_wood", + recipe = { + {"default:wood", "default:wood"}, + {"default:stick", "default:wood"}, + {"default:stick", ""}, + } +}) + +minetest.register_craft({ + output = "default:axe_stone", + recipe = { + {"default:cobble", "default:cobble"}, + {"default:stick", "default:cobble"}, + {"default:stick", ""}, + } +}) + +minetest.register_craft({ + output = "default:axe_steel", + recipe = { + {"default:steel_ingot", "default:steel_ingot"}, + {"default:stick", "default:steel_ingot"}, + {"default:stick", ""}, + } +}) + +-- Tool repair buff (15% bonus instead of 2%) + +minetest.register_craft({ + type = "toolrepair", + additional_wear = -0.15, +}) + +-- Redefinitions of some default nodes + +if minetest.override_item then -- Don't bother overriding nodes if minetest.override_item isn't available + +if moreblocks.config.wood_facedir then + minetest.override_item("default:wood", { + paramtype2 = "facedir", + }) +end + +-- Make glass and obsidian glass framed, like the More Blocks glasses +--[[ +minetest.override_item("default:glass", { + drawtype = "glasslike_framed", +}) + +minetest.override_item("default:obsidian_glass", { + drawtype = "glasslike_framed", +}) +--]] +-- Let there be light! + +minetest.override_item("default:ladder", { + paramtype = "light", + sunlight_propagates = true, +}) + +minetest.override_item("default:sapling", { + paramtype = "light", + sunlight_propagates = true, +}) + +minetest.override_item("default:dry_shrub", { + paramtype = "light", + sunlight_propagates = true, +}) + +minetest.override_item("default:papyrus", { + paramtype = "light", + sunlight_propagates = true, +}) + +minetest.override_item("default:fence_wood", { + paramtype = "light", + sunlight_propagates = true, +}) + +minetest.override_item("default:junglegrass", { + paramtype = "light", + sunlight_propagates = true, +}) + +minetest.override_item("default:junglesapling", { + paramtype = "light", + sunlight_propagates = true, +}) + +minetest.override_item("default:grass_1", { + inventory_image = "default_grass_3.png", -- Use a bigger inventory image + wield_image = "default_grass_3.png", + paramtype = "light", + sunlight_propagates = true, +}) + +for i = 2, 5 do + minetest.override_item("default:grass_"..i, { + paramtype = "light", + sunlight_propagates = true, + }) +end + +end -- End if minetest.override_item + diff --git a/mods/moreblocks/stairsplus/API.md b/mods/moreblocks/stairsplus/API.md new file mode 100644 index 0000000..480b848 --- /dev/null +++ b/mods/moreblocks/stairsplus/API.md @@ -0,0 +1,25 @@ +API documentation for StairsPlus +================================ +- - - - - - - - - - - - - - - - + +* `stairsplus:register_all(modname, subname, recipeitem, fields)` + Registers a stair, slab, panel, microblock, and any other types of + microblocks to be added in the future. + Also registers the node with the circular saw. + Example: + ```lua + stairsplus:register_all("moreblocks", "wood", "defaut:wood", { + description = "Wooden", + tiles = {"default_wood.png"}, + groups = {oddly_breakabe_by_hand=1}, + sounds = default.node_sound_wood_defaults(), + }) + ``` +The following register only a particular type of microblock. +You will probably never want to use them directly. + +* `stairsplus:register_stair(modname, subname, recipeitem, fields)` +* `stairsplus:register_slab(modname, subname, recipeitem, fields)` +* `stairsplus:register_panel(modname, subname, recipeitem, fields)` +* `stairsplus:register_micro(modname, subname, recipeitem, fields)` + diff --git a/mods/moreblocks/stairsplus/aliases.lua b/mods/moreblocks/stairsplus/aliases.lua new file mode 100644 index 0000000..e197035 --- /dev/null +++ b/mods/moreblocks/stairsplus/aliases.lua @@ -0,0 +1,63 @@ + +local function register_stairsplus_alias(modname, origname, newname) + minetest.register_alias(modname..":slab_"..origname, "moreblocks:slab_"..newname) + minetest.register_alias(modname..":slab_"..origname.."_inverted", "moreblocks:slab_"..newname.."_inverted") + minetest.register_alias(modname..":slab_"..origname.."_wall", "moreblocks:slab_"..newname.."_wall") + minetest.register_alias(modname..":slab_"..origname.."_quarter", "moreblocks:slab_"..newname.."_quarter") + minetest.register_alias(modname..":slab_"..origname.."_quarter_inverted", "moreblocks:slab_"..newname.."_quarter_inverted") + minetest.register_alias(modname..":slab_"..origname.."_quarter_wall", "moreblocks:slab_"..newname.."_quarter_wall") + minetest.register_alias(modname..":slab_"..origname.."_three_quarter", "moreblocks:slab_"..newname.."_three_quarter") + minetest.register_alias(modname..":slab_"..origname.."_three_quarter_inverted", "moreblocks:slab_"..newname.."_three_quarter_inverted") + minetest.register_alias(modname..":slab_"..origname.."_three_quarter_wall", "moreblocks:slab_"..newname.."_three_quarter_wall") + minetest.register_alias(modname..":stair_"..origname, "moreblocks:stair_"..newname) + minetest.register_alias(modname..":stair_"..origname.."_inverted", "moreblocks:stair_"..newname.."_inverted") + minetest.register_alias(modname..":stair_"..origname.."_wall", "moreblocks:stair_"..newname.."_wall") + minetest.register_alias(modname..":stair_"..origname.."_wall_half", "moreblocks:stair_"..newname.."_wall_half") + minetest.register_alias(modname..":stair_"..origname.."_wall_half_inverted", "moreblocks:stair_"..newname.."_wall_half_inverted") + minetest.register_alias(modname..":stair_"..origname.."_half", "moreblocks:stair_"..newname.."_half") + minetest.register_alias(modname..":stair_"..origname.."_half_inverted", "moreblocks:stair_"..newname.."_half_inverted") + minetest.register_alias(modname..":stair_"..origname.."_right_half", "moreblocks:stair_"..newname.."_right_half") + minetest.register_alias(modname..":stair_"..origname.."_right_half_inverted", "moreblocks:stair_"..newname.."_right_half_inverted") + minetest.register_alias(modname..":stair_"..origname.."_wall_half", "moreblocks:stair_"..newname.."_wall_half") + minetest.register_alias(modname..":stair_"..origname.."_wall_half_inverted", "moreblocks:stair_"..newname.."_wall_half_inverted") + minetest.register_alias(modname..":stair_"..origname.."_inner", "moreblocks:stair_"..newname.."_inner") + minetest.register_alias(modname..":stair_"..origname.."_inner_inverted", "moreblocks:stair_"..newname.."_inner_inverted") + minetest.register_alias(modname..":stair_"..origname.."_outer", "moreblocks:stair_"..newname.."_outer") + minetest.register_alias(modname..":stair_"..origname.."_outer_inverted", "moreblocks:stair_"..newname.."_outer_inverted") + minetest.register_alias(modname..":panel_"..origname.."_bottom", "moreblocks:panel_"..newname.."_bottom") + minetest.register_alias(modname..":panel_"..origname.."_top", "moreblocks:panel_"..newname.."_top") + minetest.register_alias(modname..":panel_"..origname.."_vertical", "moreblocks:panel_"..newname.."_vertical") + minetest.register_alias(modname..":micro_"..origname.."_bottom", "moreblocks:micro_"..newname.."_bottom") + minetest.register_alias(modname..":micro_"..origname.."_top", "moreblocks:micro_"..newname.."_top") +end + +register_stairsplus_alias("stairsplus", "stone", "stone") +register_stairsplus_alias("stairsplus", "wood", "wood") +register_stairsplus_alias("stairsplus", "cobble", "cobble") +register_stairsplus_alias("stairsplus", "brick", "brick") +register_stairsplus_alias("stairsplus", "sandstone", "sandstone") +register_stairsplus_alias("stairsplus", "glass", "glass") +register_stairsplus_alias("stairsplus", "tree", "tree") +register_stairsplus_alias("stairsplus", "jungletree", "jungletree") +register_stairsplus_alias("stairsplus", "desert_stone", "desert_stone") +register_stairsplus_alias("stairsplus", "steelblock", "steelblock") +register_stairsplus_alias("stairsplus", "mossycobble", "mossycobble") + +register_stairsplus_alias("moreblocks", "coalstone", "coal_stone") +register_stairsplus_alias("moreblocks", "junglewood", "jungle_wood") +register_stairsplus_alias("moreblocks", "circlestonebrick", "circle_stone_bricks") +register_stairsplus_alias("moreblocks", "ironstone", "iron_stone") +register_stairsplus_alias("moreblocks", "coalglass", "coal_glass") +register_stairsplus_alias("moreblocks", "ironglass", "iron_glass") +register_stairsplus_alias("moreblocks", "glowglass", "glow_glass") +register_stairsplus_alias("moreblocks", "superglowglass", "super_glow_glass") +register_stairsplus_alias("moreblocks", "coalchecker", "coal_checker") +register_stairsplus_alias("moreblocks", "ironchecker", "iron_checker") +register_stairsplus_alias("moreblocks", "cactuschecker", "cactus_checker") +register_stairsplus_alias("moreblocks", "ironstonebrick", "iron_stone_bricks") +register_stairsplus_alias("moreblocks", "stonesquare", "stone_tile") +register_stairsplus_alias("moreblocks", "splitstonesquare", "split_stone_tile") +register_stairsplus_alias("moreblocks", "woodtile", "wood_tile") +register_stairsplus_alias("moreblocks", "woodtile_centered", "wood_tile_centered") +register_stairsplus_alias("moreblocks", "woodtile_full", "wood_tile_full") + diff --git a/mods/moreblocks/stairsplus/conversion.lua b/mods/moreblocks/stairsplus/conversion.lua new file mode 100644 index 0000000..d3f7988 --- /dev/null +++ b/mods/moreblocks/stairsplus/conversion.lua @@ -0,0 +1,132 @@ +-- Function to convert all stairs/slabs/etc nodes from +-- inverted, wall, etc to regular + 6d facedir + +local dirs1 = {21, 20, 23, 22, 21} +local dirs2 = {15, 8, 17, 6, 15} +local dirs3 = {14, 11, 16, 5, 14} + +function stairsplus:register_6dfacedir_conversion(modname, material) + --print("Register stairsplus 6d facedir conversion") + --print('ABM for '..modname..' "'..material..'"') + + local objects_list1 = { + modname..":slab_"..material.."_inverted", + modname..":slab_"..material.."_quarter_inverted", + modname..":slab_"..material.."_three_quarter_inverted", + modname..":stair_"..material.."_inverted", + modname..":stair_"..material.."_wall", + modname..":stair_"..material.."_wall_half", + modname..":stair_"..material.."_wall_half_inverted", + modname..":stair_"..material.."_half_inverted", + modname..":stair_"..material.."_right_half_inverted", + modname..":panel_"..material.."_vertical", + modname..":panel_"..material.."_top", + } + + local objects_list2 = { + modname..":slab_"..material.."_wall", + modname..":slab_"..material.."_quarter_wall", + modname..":slab_"..material.."_three_quarter_wall", + modname..":stair_"..material.."_inner_inverted", + modname..":stair_"..material.."_outer_inverted", + modname..":micro_"..material.."_top" + } + + for _, object in pairs(objects_list1) do + local flip_upside_down = false + local flip_to_wall = false + + local dest_object = object + + if string.find(dest_object, "_inverted") then + flip_upside_down = true + dest_object = string.gsub(dest_object, "_inverted", "") + end + + if string.find(object, "_top") then + flip_upside_down = true + dest_object = string.gsub(dest_object, "_top", "") + end + + if string.find(dest_object, "_wall") then + flip_to_wall = true + dest_object = string.gsub(dest_object, "_wall", "") + end + + if string.find(dest_object, "_vertical") then + flip_to_wall = true + dest_object = string.gsub(dest_object, "_vertical", "") + end + + if string.find(dest_object, "_half") and not string.find(dest_object, "_right_half") then + dest_object = string.gsub(dest_object, "_half", "_right_half") + elseif string.find(dest_object, "_right_half") then + dest_object = string.gsub(dest_object, "_right_half", "_half") + end + + --print(" +---> convert "..object) + --print(" | to "..dest_object) + + minetest.register_abm({ + nodenames = {object}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local fdir = node.param2 or 0 + + if flip_upside_down and not flip_to_wall then + nfdir = dirs1[fdir + 2] + elseif flip_to_wall and not flip_upside_down then + nfdir = dirs2[fdir + 1] + elseif flip_to_wall and flip_upside_down then + nfdir = dirs3[fdir + 2] + end + minetest.set_node(pos, {name = dest_object, param2 = nfdir}) + end + }) + end + + for _, object in pairs(objects_list2) do + local flip_upside_down = false + local flip_to_wall = false + + local dest_object = object + + if string.find(dest_object, "_inverted") then + flip_upside_down = true + dest_object = string.gsub(dest_object, "_inverted", "") + end + + if string.find(dest_object, "_top") then + flip_upside_down = true + dest_object = string.gsub(dest_object, "_top", "") + end + + if string.find(dest_object, "_wall") then + flip_to_wall = true + dest_object = string.gsub(dest_object, "_wall", "") + end + + --print(" +---> convert "..object) + --print(" | to "..dest_object) + + minetest.register_abm({ + nodenames = {object}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local fdir = node.param2 + local nfdir = 20 + + if flip_upside_down and not flip_to_wall then + nfdir = dirs1[fdir + 1] + elseif flip_to_wall and not flip_upside_down then + nfdir = dirs2[fdir + 2] + + end + minetest.set_node(pos, {name = dest_object, param2 = nfdir}) + end + }) + end +end + diff --git a/mods/moreblocks/stairsplus/init.lua b/mods/moreblocks/stairsplus/init.lua new file mode 100644 index 0000000..74d7ddb --- /dev/null +++ b/mods/moreblocks/stairsplus/init.lua @@ -0,0 +1,46 @@ + +-- Nodes will be called :{stair,slab,panel,micro}_ + +local modpath = minetest.get_modpath("moreblocks").."/stairsplus" + +stairsplus = {} +stairsplus.expect_infinite_stacks = false + +if not minetest.get_modpath("unified_inventory") and + minetest.setting_getbool("creative_mode") then + stairsplus.expect_infinite_stacks = true +end + +function stairsplus:register_all(modname, subname, recipeitem, fields) + fields = fields or {} + fields.groups = fields.groups or {} + if not moreblocks.config.show_stairsplus_creative_inv then + fields.groups.not_in_creative_inventory = 1 + end + self:register_stair(modname, subname, recipeitem, fields) + self:register_slab (modname, subname, recipeitem, fields) + self:register_panel(modname, subname, recipeitem, fields) + self:register_micro(modname, subname, recipeitem, fields) + -- self:register_6dfacedir_conversion(modname, subname) + circular_saw.known_nodes[recipeitem] = {modname, subname} +end + +function register_stair_slab_panel_micro(modname, subname, recipeitem, groups, images, description, drop, light) + stairsplus:register_all(modname, subname, recipeitem, { + groups = groups, + tiles = images, + description = description, + drop = drop, + light_source = light + }) +end + +-- dofile(modpath.."/aliases.lua") +-- dofile(modpath.."/conversion.lua") + +dofile(modpath.."/stairs.lua") +dofile(modpath.."/slabs.lua") +dofile(modpath.."/panels.lua") +dofile(modpath.."/microblocks.lua") +dofile(modpath.."/registrations.lua") + diff --git a/mods/moreblocks/stairsplus/microblocks.lua b/mods/moreblocks/stairsplus/microblocks.lua new file mode 100644 index 0000000..6a19bf1 --- /dev/null +++ b/mods/moreblocks/stairsplus/microblocks.lua @@ -0,0 +1,113 @@ +-- Load translation library if intllib is installed + +local S +if intllib then + S = intllib.Getter(minetest.get_current_modname()) +else + S = function(s) return s end +end + +-- Node will be called :micro_ + +function register_micro(modname, subname, recipeitem, groups, images, description, drop, light) + return stairsplus:register_micro(modname, subname, recipeitem, { + groups = groups, + tiles = images, + description = description, + drop = drop, + light_source = light, + sounds = default.node_sound_stone_defaults(), + }) +end + +function stairsplus:register_micro(modname, subname, recipeitem, fields) + local defs = { + [""] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0, 0, 0.5}, + }, + }, + ["_1"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0, -0.4375, 0.5}, + }, + }, + ["_2"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0, -0.375, 0.5}, + }, + }, + ["_4"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0, -0.25, 0.5}, + }, + }, + ["_12"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0, 0.25, 0.5}, + }, + }, + ["_14"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0, 0.375, 0.5}, + }, + }, + ["_15"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0, 0.4375, 0.5}, + }, + } + } + + local desc = S("%s Microblock"):format(fields.description) + for alternate, def in pairs(defs) do + def.drawtype = "nodebox" + def.paramtype = "light" + def.paramtype2 = "facedir" + def.on_place = minetest.rotate_node + for k, v in pairs(fields) do + def[k] = v + end + def.description = desc + if fields.drop then + def.drop = modname..":micro_"..fields.drop..alternate + end + minetest.register_node(":"..modname..":micro_"..subname..alternate, def) + end + + minetest.register_alias(modname..":micro_"..subname.."_bottom", modname..":micro_"..subname) + + -- Some saw-less recipe. + + minetest.register_craft({ + output = "moreblocks:micro_" .. subname .. " 6", + recipe = { + {"moreblocks:stair_" .. subname}, + }, + }) + minetest.register_craft({ + output = "moreblocks:micro_" .. subname .. " 4", + recipe = { + {"moreblocks:slab_" .. subname}, + }, + }) + minetest.register_craft({ + output = "moreblocks:micro_" .. subname .. " 2", + recipe = { + {"moreblocks:panel_" .. subname}, + }, + }) + minetest.register_craft({ + type = "shapeless", + output = recipeitem, + recipe = {"moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname}, + }) +end + diff --git a/mods/moreblocks/stairsplus/panels.lua b/mods/moreblocks/stairsplus/panels.lua new file mode 100644 index 0000000..7e4fd8d --- /dev/null +++ b/mods/moreblocks/stairsplus/panels.lua @@ -0,0 +1,114 @@ +-- Load translation library if intllib is installed + +local S +if intllib then + S = intllib.Getter(minetest.get_current_modname()) +else + S = function(s) return s end +end + +-- Node will be called :panel_ + +function register_panel(modname, subname, recipeitem, groups, images, description, drop, light) + return stairsplus:register_panel(modname, subname, recipeitem, { + groups = groups, + tiles = images, + description = description, + drop = drop, + light_source = light, + sounds = default.node_sound_stone_defaults(), + }) +end + + +function stairsplus:register_panel(modname, subname, recipeitem, fields) + local defs = { + [""] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0.5, 0, 0.5}, + }, + }, + ["_1"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0.5, -0.4375, 0.5}, + }, + }, + ["_2"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0.5, -0.375, 0.5}, + }, + }, + ["_4"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0.5, -0.25, 0.5}, + }, + }, + ["_12"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0.5, 0.25, 0.5}, + }, + }, + ["_14"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0.5, 0.375, 0.5}, + }, + }, + ["_15"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, 0, 0.5, 0.4375, 0.5}, + }, + } + } + + local desc = S("%s Panel"):format(fields.description) + for alternate, def in pairs(defs) do + def.drawtype = "nodebox" + def.paramtype = "light" + def.paramtype2 = "facedir" + def.on_place = minetest.rotate_node + for k, v in pairs(fields) do + def[k] = v + end + def.description = desc + if fields.drop then + def.drop = modname..":panel_"..fields.drop..alternate + end + minetest.register_node(":"..modname..":panel_"..subname..alternate, def) + end + minetest.register_alias(modname..":panel_"..subname.."_bottom", modname..":panel_"..subname) + + -- Some saw-less recipe. + + minetest.register_craft({ + output = "moreblocks:panel_" .. subname .. " 12", + recipe = { + {recipeitem, ""}, + {recipeitem, recipeitem}, + }, + }) + minetest.register_craft({ + output = "moreblocks:panel_" .. subname .. " 12", + recipe = { + {"", recipeitem}, + {recipeitem, recipeitem}, + }, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:panel_" .. subname, + recipe = {"moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname}, + }) + minetest.register_craft({ + type = "shapeless", + output = recipeitem, + recipe = {"moreblocks:panel_" .. subname, "moreblocks:panel_" .. subname, "moreblocks:panel_" .. subname, "moreblocks:panel_" .. subname}, + }) +end + diff --git a/mods/moreblocks/stairsplus/registrations.lua b/mods/moreblocks/stairsplus/registrations.lua new file mode 100644 index 0000000..491c72f --- /dev/null +++ b/mods/moreblocks/stairsplus/registrations.lua @@ -0,0 +1,51 @@ +-- Default stairs/slabs/panels/microblocks. + +local default_nodes = { + "stone", + "cobble", + "mossycobble", + "brick", + "sandstone", + "steelblock", + "goldblock", + "copperblock", + "bronzeblock", + "diamondblock", + "desert_stone", +-- "desert_cobble", -- Does not work in minetest_game. + "glass", + "tree", + "wood", + "jungletree", + "junglewood", + "obsidian", + "obsidian_glass", + "stonebrick", + "desert_stonebrick", + "sandstonebrick", +} + +for _, name in pairs(default_nodes) do + local nodename = "default:"..name + local ndef = minetest.registered_nodes[nodename] + local groups = {} + for k, v in pairs(ndef.groups) + -- Ignore wood and stone groups to not make them usable in crafting. + do if k ~= "wood" and k ~= "stone" then + groups[k] = v + end + end + local drop + if type(ndef.drop) == "string" then + drop = ndef.drop:sub(9) + end + stairsplus:register_all("moreblocks", name, nodename, { + description = ndef.description, + drop = drop, + groups = groups, + sounds = ndef.sounds, + tiles = ndef.tiles, + sunlight_propagates = true, + }) +end + diff --git a/mods/moreblocks/stairsplus/slabs.lua b/mods/moreblocks/stairsplus/slabs.lua new file mode 100644 index 0000000..be5b308 --- /dev/null +++ b/mods/moreblocks/stairsplus/slabs.lua @@ -0,0 +1,104 @@ +-- Load translation library if intllib is installed + +local S +if intllib then + S = intllib.Getter(minetest.get_current_modname()) +else + S = function(s) return s end +end + +-- Node will be called :slab_ + +function register_slab(modname, subname, recipeitem, groups, images, description, drop, light) + return stairsplus:register_slab(modname, subname, recipeitem, { + groups = groups, + tiles = images, + description = description, + drop = drop, + light_source = light, + sounds = default.node_sound_stone_defaults(), + }) +end + +function stairsplus:register_slab(modname, subname, recipeitem, fields) + local defs = { + [""] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5}, + }, + }, + ["_quarter"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.25, 0.5}, + }, + }, + ["_three_quarter"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0.25, 0.5}, + }, + }, + ["_1"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5}, + }, + }, + ["_2"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.375, 0.5}, + }, + }, + ["_14"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0.375, 0.5}, + }, + }, + ["_15"] = { + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5}, + }, + }, + } + local desc = S("%s Slab"):format(fields.description) + for alternate, def in pairs(defs) do + def.drawtype = "nodebox" + def.paramtype = "light" + def.paramtype2 = "facedir" + def.on_place = minetest.rotate_node + for k, v in pairs(fields) do + def[k] = v + end + def.description = desc + if fields.drop then + def.drop = modname..":slab_"..fields.drop..alternate + end + minetest.register_node(":"..modname..":slab_"..subname..alternate, def) + end + minetest.register_alias("stairs:slab_"..subname, modname..":slab_"..subname) + + -- Some saw-less recipe. + + minetest.register_craft({ + output = "moreblocks:slab_" .. subname .. " 6", + recipe = { + {recipeitem, recipeitem, recipeitem}, + }, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:slab_" .. subname, + recipe = {"moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname}, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:slab_" .. subname, + recipe = {"moreblocks:panel_" .. subname, "moreblocks:panel_" .. subname}, + }) +end + diff --git a/mods/moreblocks/stairsplus/stairs.lua b/mods/moreblocks/stairsplus/stairs.lua new file mode 100644 index 0000000..1830686 --- /dev/null +++ b/mods/moreblocks/stairsplus/stairs.lua @@ -0,0 +1,195 @@ +-- Load translation library if intllib is installed + +local S +if intllib then + S = intllib.Getter(minetest.get_current_modname()) +else + S = function(s) return s end +end + +-- Node will be called :stair_ + +function register_stair(modname, subname, recipeitem, groups, images, description, drop, light) + return stairsplus:register_stair(modname, subname, recipeitem, { + groups = groups, + tiles = images, + description = description, + drop = drop, + light_source = light, + sounds = default.node_sound_stone_defaults(), + }) +end + +function stairsplus:register_stair(modname, subname, recipeitem, fields) + local defs = { + [""] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, 0, 0.5}, + {-0.5, 0, 0, 0.5, 0.5, 0.5}, + }, + }, + }, + ["_half"] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0, 0, 0.5}, + {-0.5, 0, 0, 0, 0.5, 0.5}, + }, + }, + }, + ["_right_half" ]= { + node_box = { + type = "fixed", + fixed = { + {0, -0.5, -0.5, 0.5, 0, 0.5}, + {0, 0, 0, 0.5, 0.5, 0.5}, + }, + }, + }, + ["_inner"] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, 0, 0.5}, + {-0.5, 0, 0, 0.5, 0.5, 0.5}, + {-0.5, 0, -0.5, 0, 0.5, 0}, + }, + }, + }, + ["_outer"] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, 0, 0.5}, + {-0.5, 0, 0, 0, 0.5, 0.5}, + }, + }, + }, + ["_alt"] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, 0, 0}, + {-0.5, 0, 0, 0.5, 0.5, 0.5}, + }, + }, + }, + ["_alt_1"] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.0625, -0.5, 0.5, 0, 0}, + {-0.5, 0.4375, 0, 0.5, 0.5, 0.5}, + }, + }, + }, + ["_alt_2"] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.125, -0.5, 0.5, 0, 0}, + {-0.5, 0.375, 0, 0.5, 0.5, 0.5}, + }, + }, + }, + ["_alt_4"] = { + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.25, -0.5, 0.5, 0, 0}, + {-0.5, 0.25, 0, 0.5, 0.5, 0.5}, + }, + }, + }, + } + + local desc = S("%s Stairs"):format(fields.description) + for alternate, def in pairs(defs) do + def.drawtype = "nodebox" + def.paramtype = "light" + def.paramtype2 = "facedir" + def.on_place = minetest.rotate_node + for k, v in pairs(fields) do + def[k] = v + end + def.description = desc + if fields.drop then + def.drop = modname..":stair_"..fields.drop..alternate + end + minetest.register_node(":"..modname..":stair_"..subname..alternate, def) + end + minetest.register_alias(":stairs:stair_"..subname, modname..":stair_"..subname) + + -- Some saw-less recipes. + + minetest.register_craft({ + output = "moreblocks:stair_" .. subname .. " 8", + recipe = { + {recipeitem, "", ""}, + {recipeitem, recipeitem, ""}, + {recipeitem, recipeitem, recipeitem}, + }, + }) + + minetest.register_craft({ + output = "moreblocks:stair_" .. subname .. " 8", + recipe = { + {"", "", recipeitem}, + {"", recipeitem, recipeitem}, + {recipeitem, recipeitem, recipeitem}, + }, + }) + minetest.register_craft({ + output = "moreblocks:stair_" .. subname, + recipe = { + {"moreblocks:panel_" .. subname}, + {"moreblocks:slab_" .. subname}, + }, + }) + minetest.register_craft({ + output = "moreblocks:stair_" .. subname .. "_outer", + recipe = { + {"moreblocks:micro_" .. subname}, + {"moreblocks:slab_" .. subname}, + }, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:stair_" .. subname .. "_half", + recipe = {"moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname}, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:stair_" .. subname .. "_right_half", + recipe = {"moreblocks:stair_" .. subname .. "_half"}, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:stair_" .. subname .. "_half", + recipe = {"moreblocks:stair_" .. subname .. "_right_half"}, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:stair_" .. subname, + recipe = {"moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname}, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:stair_" .. subname .. "_inner", + recipe = {"moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname}, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:stair_" .. subname .. "_outer", + recipe = {"moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname, "moreblocks:micro_" .. subname}, + }) + minetest.register_craft({ + type = "shapeless", + output = "moreblocks:stair_" .. subname, + recipe = {"moreblocks:panel_" .. subname, "moreblocks:panel_" .. subname, "moreblocks:panel_" .. subname}, + }) +end + diff --git a/mods/moreblocks/textures/default_fence_overlay.png b/mods/moreblocks/textures/default_fence_overlay.png new file mode 100644 index 0000000..780e736 Binary files /dev/null and b/mods/moreblocks/textures/default_fence_overlay.png differ diff --git a/mods/moreblocks/textures/invisible.png b/mods/moreblocks/textures/invisible.png new file mode 100644 index 0000000..4b5b302 Binary files /dev/null and b/mods/moreblocks/textures/invisible.png differ diff --git a/mods/moreblocks/textures/moreblocks_cactus_brick.png b/mods/moreblocks/textures/moreblocks_cactus_brick.png new file mode 100644 index 0000000..9d3a6c2 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_cactus_brick.png differ diff --git a/mods/moreblocks/textures/moreblocks_cactus_checker.png b/mods/moreblocks/textures/moreblocks_cactus_checker.png new file mode 100644 index 0000000..134766a Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_cactus_checker.png differ diff --git a/mods/moreblocks/textures/moreblocks_circle_stone_bricks.png b/mods/moreblocks/textures/moreblocks_circle_stone_bricks.png new file mode 100644 index 0000000..4ca0134 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_circle_stone_bricks.png differ diff --git a/mods/moreblocks/textures/moreblocks_circular_saw_bottom.png b/mods/moreblocks/textures/moreblocks_circular_saw_bottom.png new file mode 100644 index 0000000..1522829 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_circular_saw_bottom.png differ diff --git a/mods/moreblocks/textures/moreblocks_circular_saw_side.png b/mods/moreblocks/textures/moreblocks_circular_saw_side.png new file mode 100644 index 0000000..ce9e16f Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_circular_saw_side.png differ diff --git a/mods/moreblocks/textures/moreblocks_circular_saw_top.png b/mods/moreblocks/textures/moreblocks_circular_saw_top.png new file mode 100644 index 0000000..96f3350 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_circular_saw_top.png differ diff --git a/mods/moreblocks/textures/moreblocks_clean_glass.png b/mods/moreblocks/textures/moreblocks_clean_glass.png new file mode 100644 index 0000000..140ee2b Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_clean_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_coal_checker.png b/mods/moreblocks/textures/moreblocks_coal_checker.png new file mode 100644 index 0000000..7619e56 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_coal_checker.png differ diff --git a/mods/moreblocks/textures/moreblocks_coal_glass.png b/mods/moreblocks/textures/moreblocks_coal_glass.png new file mode 100644 index 0000000..5cb7227 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_coal_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_coal_glass_stairsplus.png b/mods/moreblocks/textures/moreblocks_coal_glass_stairsplus.png new file mode 100644 index 0000000..8086a28 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_coal_glass_stairsplus.png differ diff --git a/mods/moreblocks/textures/moreblocks_coal_stone.png b/mods/moreblocks/textures/moreblocks_coal_stone.png new file mode 100644 index 0000000..1e514ed Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_coal_stone.png differ diff --git a/mods/moreblocks/textures/moreblocks_coal_stone_bricks.png b/mods/moreblocks/textures/moreblocks_coal_stone_bricks.png new file mode 100644 index 0000000..366e445 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_coal_stone_bricks.png differ diff --git a/mods/moreblocks/textures/moreblocks_empty_bookshelf.png b/mods/moreblocks/textures/moreblocks_empty_bookshelf.png new file mode 100644 index 0000000..b49fd2e Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_empty_bookshelf.png differ diff --git a/mods/moreblocks/textures/moreblocks_fence_jungle_wood.png b/mods/moreblocks/textures/moreblocks_fence_jungle_wood.png new file mode 100644 index 0000000..b59db10 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_fence_jungle_wood.png differ diff --git a/mods/moreblocks/textures/moreblocks_fence_wood.png b/mods/moreblocks/textures/moreblocks_fence_wood.png new file mode 100644 index 0000000..e3510c5 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_fence_wood.png differ diff --git a/mods/moreblocks/textures/moreblocks_glass.png b/mods/moreblocks/textures/moreblocks_glass.png new file mode 100644 index 0000000..912b029 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_glass_stairsplus.png b/mods/moreblocks/textures/moreblocks_glass_stairsplus.png new file mode 100644 index 0000000..b879ec3 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_glass_stairsplus.png differ diff --git a/mods/moreblocks/textures/moreblocks_glow_glass.png b/mods/moreblocks/textures/moreblocks_glow_glass.png new file mode 100644 index 0000000..843bebf Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_glow_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_glow_glass_stairsplus.png b/mods/moreblocks/textures/moreblocks_glow_glass_stairsplus.png new file mode 100644 index 0000000..cdb8044 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_glow_glass_stairsplus.png differ diff --git a/mods/moreblocks/textures/moreblocks_iron_checker.png b/mods/moreblocks/textures/moreblocks_iron_checker.png new file mode 100644 index 0000000..fb11fdb Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_iron_checker.png differ diff --git a/mods/moreblocks/textures/moreblocks_iron_glass.png b/mods/moreblocks/textures/moreblocks_iron_glass.png new file mode 100644 index 0000000..51be0d6 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_iron_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_iron_glass_stairsplus.png b/mods/moreblocks/textures/moreblocks_iron_glass_stairsplus.png new file mode 100644 index 0000000..52e3bf3 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_iron_glass_stairsplus.png differ diff --git a/mods/moreblocks/textures/moreblocks_iron_stone.png b/mods/moreblocks/textures/moreblocks_iron_stone.png new file mode 100644 index 0000000..20c42f3 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_iron_stone.png differ diff --git a/mods/moreblocks/textures/moreblocks_iron_stone_bricks.png b/mods/moreblocks/textures/moreblocks_iron_stone_bricks.png new file mode 100644 index 0000000..1f817f8 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_iron_stone_bricks.png differ diff --git a/mods/moreblocks/textures/moreblocks_junglestick.png b/mods/moreblocks/textures/moreblocks_junglestick.png new file mode 100644 index 0000000..7c6c462 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_junglestick.png differ diff --git a/mods/moreblocks/textures/moreblocks_obsidian_glass_stairsplus.png b/mods/moreblocks/textures/moreblocks_obsidian_glass_stairsplus.png new file mode 100644 index 0000000..3eb22d0 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_obsidian_glass_stairsplus.png differ diff --git a/mods/moreblocks/textures/moreblocks_plankstone.png b/mods/moreblocks/textures/moreblocks_plankstone.png new file mode 100644 index 0000000..b1a65c5 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_plankstone.png differ diff --git a/mods/moreblocks/textures/moreblocks_plankstone_2.png b/mods/moreblocks/textures/moreblocks_plankstone_2.png new file mode 100644 index 0000000..953c2f5 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_plankstone_2.png differ diff --git a/mods/moreblocks/textures/moreblocks_rope.png b/mods/moreblocks/textures/moreblocks_rope.png new file mode 100644 index 0000000..19787fe Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_rope.png differ diff --git a/mods/moreblocks/textures/moreblocks_split_stone_tile.png b/mods/moreblocks/textures/moreblocks_split_stone_tile.png new file mode 100644 index 0000000..d7d69af Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_split_stone_tile.png differ diff --git a/mods/moreblocks/textures/moreblocks_split_stone_tile_top.png b/mods/moreblocks/textures/moreblocks_split_stone_tile_top.png new file mode 100644 index 0000000..3c8eb6d Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_split_stone_tile_top.png differ diff --git a/mods/moreblocks/textures/moreblocks_stone_tile.png b/mods/moreblocks/textures/moreblocks_stone_tile.png new file mode 100644 index 0000000..0f9038f Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_stone_tile.png differ diff --git a/mods/moreblocks/textures/moreblocks_super_glow_glass.png b/mods/moreblocks/textures/moreblocks_super_glow_glass.png new file mode 100644 index 0000000..a9d4c5f Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_super_glow_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_super_glow_glass_stairsplus.png b/mods/moreblocks/textures/moreblocks_super_glow_glass_stairsplus.png new file mode 100644 index 0000000..9118c78 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_super_glow_glass_stairsplus.png differ diff --git a/mods/moreblocks/textures/moreblocks_sweeper.png b/mods/moreblocks/textures/moreblocks_sweeper.png new file mode 100644 index 0000000..eda3cc3 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_sweeper.png differ diff --git a/mods/moreblocks/textures/moreblocks_trap_glass.png b/mods/moreblocks/textures/moreblocks_trap_glass.png new file mode 100644 index 0000000..25c3387 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_trap_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_trap_glow_glass.png b/mods/moreblocks/textures/moreblocks_trap_glow_glass.png new file mode 100644 index 0000000..1096dd7 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_trap_glow_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_trap_stone.png b/mods/moreblocks/textures/moreblocks_trap_stone.png new file mode 100644 index 0000000..764aa81 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_trap_stone.png differ diff --git a/mods/moreblocks/textures/moreblocks_trap_super_glow_glass.png b/mods/moreblocks/textures/moreblocks_trap_super_glow_glass.png new file mode 100644 index 0000000..fef974b Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_trap_super_glow_glass.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood.png b/mods/moreblocks/textures/moreblocks_wood.png new file mode 100644 index 0000000..89841da Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile.png b/mods/moreblocks/textures/moreblocks_wood_tile.png new file mode 100644 index 0000000..b6c9667 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile_center.png b/mods/moreblocks/textures/moreblocks_wood_tile_center.png new file mode 100644 index 0000000..3bc4649 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile_center.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile_down.png b/mods/moreblocks/textures/moreblocks_wood_tile_down.png new file mode 100644 index 0000000..711e0f7 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile_down.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile_flipped.png b/mods/moreblocks/textures/moreblocks_wood_tile_flipped.png new file mode 100644 index 0000000..2657822 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile_flipped.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile_full.png b/mods/moreblocks/textures/moreblocks_wood_tile_full.png new file mode 100644 index 0000000..7ec7f05 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile_full.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile_left.png b/mods/moreblocks/textures/moreblocks_wood_tile_left.png new file mode 100644 index 0000000..5c9b864 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile_left.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile_right.png b/mods/moreblocks/textures/moreblocks_wood_tile_right.png new file mode 100644 index 0000000..a7473ae Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile_right.png differ diff --git a/mods/moreblocks/textures/moreblocks_wood_tile_up.png b/mods/moreblocks/textures/moreblocks_wood_tile_up.png new file mode 100644 index 0000000..2a49873 Binary files /dev/null and b/mods/moreblocks/textures/moreblocks_wood_tile_up.png differ diff --git a/mods/nether/README.txt b/mods/nether/README.txt new file mode 100644 index 0000000..4206d0e --- /dev/null +++ b/mods/nether/README.txt @@ -0,0 +1,25 @@ +Minetest 0.4 mod: nether +======================== + +License of source code: +----------------------- +Copyright (C) 2013 PilzAdam + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +License of media (textures and sounds) +-------------------------------------- +Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) +http://creativecommons.org/licenses/by-sa/3.0/ + +Authors of media files +----------------------- +Everything not listed in here: +Copyright (C) 2013 PilzAdam + +nether_rack.png: Zeg9 +nether_glowstone.png: BlockMen diff --git a/mods/nether/depends.txt b/mods/nether/depends.txt new file mode 100644 index 0000000..d2ad5d4 --- /dev/null +++ b/mods/nether/depends.txt @@ -0,0 +1,4 @@ +default +quartz +fake_fire + diff --git a/mods/nether/init.lua b/mods/nether/init.lua new file mode 100644 index 0000000..6a7e735 --- /dev/null +++ b/mods/nether/init.lua @@ -0,0 +1,446 @@ +-- Minetest 0.4 Mod: Nether + +local NETHER_DEPTH = -5000 +local NETHER_AMBIENT = 4 +local nether_created = false + +minetest.register_node("nether:portal", { + description = "Nether Portal", + tiles = { + "nether_transparent.png", + "nether_transparent.png", + "nether_transparent.png", + "nether_transparent.png", + { + name = "nether_portal.png", + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2, + }, + }, + { + name = "nether_portal.png", + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2, + }, + }, + }, + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + use_texture_alpha = true, + walkable = false, + digable = false, + pointable = false, + buildable_to = false, + drop = "", + light_source = 5, + post_effect_color = {a=180, r=128, g=0, b=128}, + alpha = 192, + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.1, 0.5, 0.5, 0.1}, + }, + }, + groups = {not_in_creative_inventory=1} +}) + +local function build_portal(pos, target) + local p = {x=pos.x-1, y=pos.y-1, z=pos.z} + local p1 = {x=pos.x-1, y=pos.y-1, z=pos.z} + local p2 = {x=p1.x+3, y=p1.y+4, z=p1.z} + local emin = {x=pos.x-100, y=pos.y-100, z=pos.z-100} + local emax = {x=p1.x+100, y=p1.y+100, z=p1.z+100} + local perlin1 = minetest.get_perlin(11,3, 0.5, 100) + local perlin2 = minetest.get_perlin(23,3, 0.5, 50) + local perlin3 = minetest.get_perlin(17,3, 0.5, 100) + local vm = minetest.get_voxel_manip() + local gmin + local gmax + + gmin, gmax = vm:read_from_map(emin, emax) + + local data = vm:get_data() + local area = VoxelArea:new{MinEdge=gmin, MaxEdge=gmax} + local c_air = minetest.get_content_id("air") + local c_fire = minetest.get_content_id("fake_fire:fake_fire") + local c_lava = minetest.get_content_id("lava_source") + local c_netherrack = minetest.get_content_id("nether:rack") + + for x=pos.x-100,pos.x+100,1 do + for z=pos.z-100,pos.z+100,1 do + local h = math.floor(10*math.abs(perlin1:get2d({x=x, y=z}))+2) + local h2 = 3*h + if math.abs(x-pos.x) < 21 and math.abs(z-pos.z) < 21 then + h = math.floor(h * math.max(math.abs(x-pos.x)+5, math.abs(z-pos.z)+5) / 25) + end + for y=pos.y-h,pos.y+h2,1 do + local p_pos = area:index(x, y, z) + data[p_pos] = c_air + end + for y=pos.y-50,pos.y-7,1 do + local s = (y-pos.y+50)/100-.25 + local h3 = 36+math.floor(20*perlin3:get2d({x=x, y=z})) + if perlin2:get3d({x=x, y=y, z=z}) > s and pos.y-y < h3 then + local p_pos = area:index(x, y, z) + data[p_pos] = c_air + if pos.y - y > 40 then + data[area:index(x, y, z)] = c_lava + end + end + end + if math.random() < .01 and data[area:index(x, pos.y-h-1, z)] == c_netherrack then + data[area:index(x, pos.y-h, z)] = c_fire + end + end + end + vm:set_data(data) + --vm:set_lighting({day=15, night=9}) + --vm:calc_lighting() + -- vm:update_liquids() + vm:write_to_map() + vm:update_map() + + for i=1,4 do + minetest.env:set_node(p, {name="default:obsidian"}) + p.y = p.y+1 + end + for i=1,3 do + minetest.env:set_node(p, {name="default:obsidian"}) + p.x = p.x+1 + end + for i=1,4 do + minetest.env:set_node(p, {name="default:obsidian"}) + p.y = p.y-1 + end + for i=1,3 do + minetest.env:set_node(p, {name="default:obsidian"}) + p.x = p.x-1 + end + for x=p1.x,p2.x do + for y=p1.y,p2.y do + p = {x=x, y=y, z=p1.z} + if not (x == p1.x or x == p2.x or y==p1.y or y==p2.y) then + minetest.env:set_node(p, {name="nether:portal", param2=0}) + end + local meta = minetest.env:get_meta(p) + meta:set_string("p1", minetest.pos_to_string(p1)) + meta:set_string("p2", minetest.pos_to_string(p2)) + meta:set_string("target", minetest.pos_to_string(target)) + + end + end + nether_created = true +end + +minetest.register_abm({ + nodenames = {"nether:portal"}, + interval = 1, + chance = 2, + action = function(pos, node) + minetest.add_particlespawner( + 32, --amount + 4, --time + {x=pos.x-0.25, y=pos.y-0.25, z=pos.z-0.25}, --minpos + {x=pos.x+0.25, y=pos.y+0.25, z=pos.z+0.25}, --maxpos + {x=-0.8, y=-0.8, z=-0.8}, --minvel + {x=0.8, y=0.8, z=0.8}, --maxvel + {x=0,y=0,z=0}, --minacc + {x=0,y=0,z=0}, --maxacc + 0.5, --minexptime + 1, --maxexptime + 1, --minsize + 2, --maxsize + false, --collisiondetection + "nether_particle.png" --texture + ) + for _,obj in ipairs(minetest.env:get_objects_inside_radius(pos, 1)) do + if obj:is_player() then + local meta = minetest.env:get_meta(pos) + local target = minetest.string_to_pos(meta:get_string("target")) + if target then + minetest.after(3, function(obj, pos, target) + local objpos = obj:getpos() + objpos.y = objpos.y+0.1 -- Fix some glitches at -8000 + if minetest.env:get_node(objpos).name ~= "nether:portal" then + return + end + obj:setpos(target) + + local function check_and_build_portal(pos, target) + local n = minetest.env:get_node_or_nil(target) + if n and n.name ~= "nether:portal" then + build_portal(target, pos) + minetest.after(2, check_and_build_portal, pos, target) + minetest.after(4, check_and_build_portal, pos, target) + elseif not n then + minetest.after(1, check_and_build_portal, pos, target) + end + end + + minetest.after(1, check_and_build_portal, pos, target) + + end, obj, pos, target) + end + end + end + end, +}) + +local function move_check(p1, max, dir) + local p = {x=p1.x, y=p1.y, z=p1.z} + local d = math.abs(max-p1[dir]) / (max-p1[dir]) + p[dir] = p[dir] + d + while p[dir] ~= max - d do + p[dir] = p[dir] + d + if minetest.env:get_node(p).name ~= "default:obsidian" then + return false + end + end + return true +end + +local function check_portal(p1, p2) + if p1.x ~= p2.x then + if not move_check(p1, p2.x, "x") then + return false + end + if not move_check(p2, p1.x, "x") then + return false + end + elseif p1.z ~= p2.z then + if not move_check(p1, p2.z, "z") then + return false + end + if not move_check(p2, p1.z, "z") then + return false + end + else + return false + end + + if not move_check(p1, p2.y, "y") then + return false + end + if not move_check(p2, p1.y, "y") then + return false + end + + return true +end + +local function is_portal(pos) + for d=-3,3 do + for y=-4,4 do + local px = {x=pos.x+d, y=pos.y+y, z=pos.z} + local pz = {x=pos.x, y=pos.y+y, z=pos.z+d} + if check_portal(px, {x=px.x+3, y=px.y+4, z=px.z}) then + return px, {x=px.x+3, y=px.y+4, z=px.z} + end + if check_portal(pz, {x=pz.x, y=pz.y+4, z=pz.z+3}) then + return pz, {x=pz.x, y=pz.y+4, z=pz.z+3} + end + end + end +end + +local function make_portal(pos) + local p1, p2 = is_portal(pos) + if not p1 or not p2 then + return false + end + + for d=1,2 do + for y=p1.y+1,p2.y-1 do + local p + if p1.z == p2.z then + p = {x=p1.x+d, y=y, z=p1.z} + else + p = {x=p1.x, y=y, z=p1.z+d} + end + if minetest.env:get_node(p).name ~= "air" then + return false + end + end + end + + local param2 + if p1.z == p2.z then param2 = 0 else param2 = 1 end + + local target = {x=p1.x, y=p1.y, z=p1.z} + target.x = target.x + 1 + if target.y < NETHER_DEPTH then + target.y = math.random(-50, 20) + else + target.y = NETHER_DEPTH - 1000 + end + + for d=0,3 do + for y=p1.y,p2.y do + local p = {} + if param2 == 0 then p = {x=p1.x+d, y=y, z=p1.z} else p = {x=p1.x, y=y, z=p1.z+d} end + if minetest.env:get_node(p).name == "air" then + minetest.env:set_node(p, {name="nether:portal", param2=param2}) + end + local meta = minetest.env:get_meta(p) + meta:set_string("p1", minetest.pos_to_string(p1)) + meta:set_string("p2", minetest.pos_to_string(p2)) + meta:set_string("target", minetest.pos_to_string(target)) + end + end + return true +end + +minetest.register_node(":default:obsidian", { + description = "Obsidian", + tiles = {"default_obsidian.png"}, + is_ground_content = true, + sounds = default.node_sound_stone_defaults(), + groups = {cracky=1,level=2}, + + on_destruct = function(pos) + local meta = minetest.env:get_meta(pos) + local p1 = minetest.string_to_pos(meta:get_string("p1")) + local p2 = minetest.string_to_pos(meta:get_string("p2")) + local target = minetest.string_to_pos(meta:get_string("target")) + if not p1 or not p2 then + return + end + for x=p1.x,p2.x do + for y=p1.y,p2.y do + for z=p1.z,p2.z do + local nn = minetest.env:get_node({x=x,y=y,z=z}).name + if nn == "default:obsidian" or nn == "nether:portal" then + if nn == "nether:portal" then + minetest.env:remove_node({x=x,y=y,z=z}) + end + local m = minetest.env:get_meta({x=x,y=y,z=z}) + m:set_string("p1", "") + m:set_string("p2", "") + m:set_string("target", "") + end + end + end + end + meta = minetest.env:get_meta(target) + if not meta then + return + end + p1 = minetest.string_to_pos(meta:get_string("p1")) + p2 = minetest.string_to_pos(meta:get_string("p2")) + if not p1 or not p2 then + return + end + for x=p1.x,p2.x do + for y=p1.y,p2.y do + for z=p1.z,p2.z do + local nn = minetest.env:get_node({x=x,y=y,z=z}).name + if nn == "default:obsidian" or nn == "nether:portal" then + if nn == "nether:portal" then + minetest.env:remove_node({x=x,y=y,z=z}) + end + local m = minetest.env:get_meta({x=x,y=y,z=z}) + m:set_string("p1", "") + m:set_string("p2", "") + m:set_string("target", "") + end + end + end + end + end, +}) + +minetest.register_craftitem(":default:mese_crystal_fragment", { + description = "Mese Crystal Fragment", + inventory_image = "default_mese_crystal_fragment.png", + on_place = function(stack,_, pt) + if pt.under and minetest.env:get_node(pt.under).name == "default:obsidian" then + local done = make_portal(pt.under) + if done and not minetest.setting_getbool("creative_mode") then + stack:take_item() + end + end + return stack + end, +}) + +minetest.register_node("nether:rack", { + description = "Netherrack", + tiles = {"nether_rack.png"}, + is_ground_content = true, + drop = { + max_items = 1, + items = {{ + rarity = 3, + items = {"nether:rack"}, + }} + }, + light_source = NETHER_AMBIENT, + groups = {cracky=3,level=0}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("nether:sand", { + description = "Nethersand", + tiles = {"nether_sand.png"}, + is_ground_content = true, + light_source = NETHER_AMBIENT, + groups = {crumbly=3,level=2,falling_node=1}, + sounds = default.node_sound_dirt_defaults({ + footstep = {name="default_gravel_footstep", gain=0.45}, + }), +}) + +minetest.register_node("nether:glowstone", { + description = "Glowstone", + tiles = {"nether_glowstone.png"}, + is_ground_content = true, + light_source = 13, + groups = {cracky=3,oddly_breakable_by_hand=3}, + sounds = default.node_sound_glass_defaults(), +}) + +minetest.register_node("nether:brick", { + description = "Nether Brick", + tiles = {"nether_brick.png"}, + groups = {cracky=2,level=2}, + light_source = NETHER_AMBIENT-2, + sounds = default.node_sound_stone_defaults(), +}) + +local function replace(old, new) + for i=1,8 do + minetest.register_ore({ + ore_type = "scatter", + ore = new, + wherein = old, + clust_scarcity = 1, + clust_num_ores = 1, + clust_size = 1, + height_min = -31000, + height_max = NETHER_DEPTH, + }) + end +end + +replace("default:stone", "nether:rack") +replace("default:stone_with_coal", "quartz:quartz_ore") +replace("default:stone_with_iron", "nether:glowstone") +replace("default:stone_with_mese", "quartz:quartz_ore") +replace("default:mese", "quartz:quartz_ore") +replace("default:stone_with_diamond", "default:lava_source") +replace("default:stone_with_gold", "nether:glowstone") +replace("default:stone_with_copper", "nether:sand") +replace("default:gravel", "quartz:quartz_ore") +replace("default:dirt", "nether:sand") +replace("default:sand", "nether:sand") +replace("default:cobble", "nether:brick") +replace("default:mossycobble", "nether:brick") +replace("stairs:stair_cobble", "nether:brick") diff --git a/mods/nether/textures/nether_brick.png b/mods/nether/textures/nether_brick.png new file mode 100644 index 0000000..5e0e585 Binary files /dev/null and b/mods/nether/textures/nether_brick.png differ diff --git a/mods/nether/textures/nether_glowstone.png b/mods/nether/textures/nether_glowstone.png new file mode 100644 index 0000000..e23b1fa Binary files /dev/null and b/mods/nether/textures/nether_glowstone.png differ diff --git a/mods/nether/textures/nether_particle.png b/mods/nether/textures/nether_particle.png new file mode 100644 index 0000000..56a5b78 Binary files /dev/null and b/mods/nether/textures/nether_particle.png differ diff --git a/mods/nether/textures/nether_portal.png b/mods/nether/textures/nether_portal.png new file mode 100644 index 0000000..dc7384e Binary files /dev/null and b/mods/nether/textures/nether_portal.png differ diff --git a/mods/nether/textures/nether_rack.png b/mods/nether/textures/nether_rack.png new file mode 100644 index 0000000..7a6c899 Binary files /dev/null and b/mods/nether/textures/nether_rack.png differ diff --git a/mods/nether/textures/nether_sand.png b/mods/nether/textures/nether_sand.png new file mode 100644 index 0000000..cd88466 Binary files /dev/null and b/mods/nether/textures/nether_sand.png differ diff --git a/mods/nether/textures/nether_transparent.png b/mods/nether/textures/nether_transparent.png new file mode 100644 index 0000000..4883728 Binary files /dev/null and b/mods/nether/textures/nether_transparent.png differ diff --git a/mods/nether/textures/old/nether_brick.png b/mods/nether/textures/old/nether_brick.png new file mode 100644 index 0000000..3e8c803 Binary files /dev/null and b/mods/nether/textures/old/nether_brick.png differ diff --git a/mods/nether/textures/old/nether_rack.png b/mods/nether/textures/old/nether_rack.png new file mode 100644 index 0000000..201a11a Binary files /dev/null and b/mods/nether/textures/old/nether_rack.png differ diff --git a/mods/nether/textures/old/nether_sand.png b/mods/nether/textures/old/nether_sand.png new file mode 100644 index 0000000..8ec343d Binary files /dev/null and b/mods/nether/textures/old/nether_sand.png differ diff --git a/mods/permaleaves/depends.txt b/mods/permaleaves/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/mods/permaleaves/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/permaleaves/init.lua b/mods/permaleaves/init.lua new file mode 100644 index 0000000..ce18f1e --- /dev/null +++ b/mods/permaleaves/init.lua @@ -0,0 +1,11 @@ +minetest.register_node("permaleaves:leaves", { + description = "Permanent leaves", + drawtype = "allfaces_optional", + visual_scale = 1.3, + tiles = {"default_leaves.png"}, + paramtype = "light", + waving = 1, + is_ground_content = false, + groups = {snappy=3, flammable=2, leaves=1}, + sounds = default.node_sound_leaves_defaults(), +}) diff --git a/mods/player_textures/README.txt b/mods/player_textures/README.txt new file mode 100644 index 0000000..ffd9dc1 --- /dev/null +++ b/mods/player_textures/README.txt @@ -0,0 +1,15 @@ +Player Textures Mod for Minetest +================================ + +This mod allows players to use different textures. Just place the texture in +the player_textures/textures/ folder like this: +player_.png +and the player with the name will have this textures. + +License of source code: +----------------------- +WTFPL + +License of the example textures: +-------------------------------- +WTFPL diff --git a/mods/player_textures/depends.txt b/mods/player_textures/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/mods/player_textures/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/player_textures/init.lua b/mods/player_textures/init.lua new file mode 100644 index 0000000..ac979b1 --- /dev/null +++ b/mods/player_textures/init.lua @@ -0,0 +1,8 @@ +minetest.register_on_joinplayer(function(player) + local filename = minetest.get_modpath("player_textures").."/textures/player_"..player:get_player_name() + local f = io.open(filename..".png") + if f then + f:close() + default.player_set_textures(player, {"player_"..player:get_player_name()..".png"}) + end +end) diff --git a/mods/player_textures/textures/.directory b/mods/player_textures/textures/.directory new file mode 100644 index 0000000..7c90b05 --- /dev/null +++ b/mods/player_textures/textures/.directory @@ -0,0 +1,4 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2014,3,4,23,55,54 +Version=3 diff --git a/mods/player_textures/textures/player_lee.png b/mods/player_textures/textures/player_lee.png new file mode 100644 index 0000000..dbc2de8 Binary files /dev/null and b/mods/player_textures/textures/player_lee.png differ diff --git a/mods/player_textures/textures/player_squid.png b/mods/player_textures/textures/player_squid.png new file mode 100644 index 0000000..d88ad6e Binary files /dev/null and b/mods/player_textures/textures/player_squid.png differ diff --git a/mods/player_textures/textures/player_stampy.png b/mods/player_textures/textures/player_stampy.png new file mode 100644 index 0000000..04d7a83 Binary files /dev/null and b/mods/player_textures/textures/player_stampy.png differ diff --git a/mods/quartz/README.txt b/mods/quartz/README.txt new file mode 100644 index 0000000..8e6fd5d --- /dev/null +++ b/mods/quartz/README.txt @@ -0,0 +1,82 @@ + ___ _ __ __ _ + / _ \ _ _ __ _ _ __| |_ ____ | \/ | ___ __| | + | | | | | | |/ _` | '__| __|_ / | |\/| |/ _ \ / _` | + | |_| | |_| | (_| | | | |_ / / | | | | (_) | (_| | + \__\_\\__,_|\__,_|_| \__/___| |_| |_|\___/ \__,_| + + +This mod adds quartz ore and some decorative blocks to minetest. + + +Crafting: + +Quartz Block: +c = quartz crystal x = nothing + +x|x|x +----- +c|c|x +----- +c|c|x + +Quartz Pillar: +q = quartz block x = nothing + +x|x|x +----- +x|q|x +----- +x|x|x + + +Quartz Slab: +q = quartz block x = nothing + +x|x|x +----- +x|x|x +----- +q|q|q + +Quartz Stairs: +q = quartz block x = nothing + +q|x|x +q|q|x +q|q|q + +Quartz Pillar Slab: +q = quartz pillar x = nothing + +x|x|x +----- +x|x|x +----- +q|q|q + +Chiseled Quartz: +q = quartz slab x = nothing + +x|x|x +----- +x|q|x +----- +x|q|x + +Quartz Crystal Piece (usless as of now): +c = quartz crystal x = nothing + +x|x|x +----- +x|c|x +----- +x|x|x + + +License: + +CC BY-SA 3.0 + +More info at http://creativecommons.org/licenses/by-sa/3.0/ + + diff --git a/mods/quartz/depends.txt b/mods/quartz/depends.txt new file mode 100644 index 0000000..40c22ed --- /dev/null +++ b/mods/quartz/depends.txt @@ -0,0 +1,3 @@ +default, +stairs, +moreblocks? diff --git a/mods/quartz/init.lua b/mods/quartz/init.lua new file mode 100644 index 0000000..99fe84f --- /dev/null +++ b/mods/quartz/init.lua @@ -0,0 +1,190 @@ +dofile(minetest.get_modpath("quartz").."/settings.txt") + +--Node Registration + +--Quartz Crystal +minetest.register_craftitem("quartz:quartz_crystal", { + description = "Quartz Crystal", + inventory_image = "quartz_crystal_full.png", +}) +minetest.register_craftitem("quartz:quartz_crystal_piece", { + description = "Quartz Crystal Piece", + inventory_image = "quartz_crystal_piece.png", +}) + +--Ore +minetest.register_node("quartz:quartz_ore", { + description = "Quartz Ore", + tiles = {"default_stone.png^quartz_ore.png"}, + groups = {cracky=3, stone=1}, + drop = 'quartz:quartz_crystal', + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_ore({ + ore_type = "scatter", + ore = "quartz:quartz_ore", + wherein = "default:stone", + clust_scarcity = 10*10*10, + clust_num_ores = 6, + clust_size = 5, + height_min = -31000, + height_max = -5, +}) + +--Quartz Block +minetest.register_node("quartz:block", { + description = "Quartz Block", + tiles = {"quartz_block.png"}, + groups = {cracky=3, oddly_breakable_by_hand=1}, + sounds = default.node_sound_glass_defaults(), +}) + +--Chiseled Quartz +minetest.register_node("quartz:chiseled", { + description = "Chiseled Quartz", + tiles = {"quartz_chiseled.png"}, + groups = {cracky=3, oddly_breakable_by_hand=1}, + sounds = default.node_sound_glass_defaults(), +}) + +--Quartz Pillar +minetest.register_node("quartz:pillar", { + description = "Quartz Pillar", + paramtype2 = "facedir", + tiles = {"quartz_pillar_top.png", "quartz_pillar_top.png", "quartz_pillar_side.png"}, + groups = {cracky=3, oddly_breakable_by_hand=1}, + sounds = default.node_sound_glass_defaults(), + on_place = minetest.rotate_node +}) + + +--Stairs & Slabs +stairs.register_stair_and_slab("quartzblock", "quartz:block", + {cracky=3, oddly_breakable_by_hand=1}, + {"quartz_block.png"}, + "Quartz stair", + "Quartz slab", + default.node_sound_glass_defaults()) + +stairs.register_slab("quartzstair", "quartz:pillar", + {cracky=3, oddly_breakable_by_hand=1}, + {"quartz_pillar_top.png", "quartz_pillar_top.png", "quartz_pillar_side.png"}, + "Quartz Pillar stair", + "Quartz Pillar slab", + default.node_sound_glass_defaults()) + + + + + + + +--Crafting + +--Quartz Crystal Piece +minetest.register_craft({ + output = '"quartz:quartz_crystal_piece" 3', + recipe = { + {'quartz:quartz_crystal'} + } +}) + +--Quartz Block +minetest.register_craft({ + output = '"quartz:block" 4', + recipe = { + {'quartz:quartz_crystal', 'quartz:quartz_crystal', ''}, + {'quartz:quartz_crystal', 'quartz:quartz_crystal', ''}, + {'', '', ''} + } +}) + +--Chiseled Quartz +minetest.register_craft({ + output = 'quartz:chiseled 2', + recipe = { + {'stairs:slab_quartzblock', '', ''}, + {'stairs:slab_quartzblock', '', ''}, + {'', '', ''}, + } +}) + +--Chiseled Quartz(for stairsplus) +minetest.register_craft({ + output = 'quartz:chiseled 2', + recipe = { + {'quartz:slab_block', '', ''}, + {'quartz:slab_block', '', ''}, + {'', '', ''}, + } +}) + +--Quartz Pillar +minetest.register_craft({ + output = 'quartz:pillar 2', + recipe = { + {'quartz:block', '', ''}, + {'quartz:block', '', ''}, + {'', '', ''}, + } +}) + +--abms +local dirs2 = { 12, 9, 18, 7, 12 } + +minetest.register_abm({ + nodenames = { "quartz:pillar_horizontal" }, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local fdir = node.param2 or 0 + nfdir = dirs2[fdir+1] + minetest.add_node(pos, {name = "quartz:pillar", param2 = nfdir}) + end, +}) + +--These are deprecated, don't use them + +if enable_horizontal_pillar then + --Quartz Pillar (horizontal) + minetest.register_node("quartz:pillar_horizontal", { + description = "Quartz Pillar Horizontal", + tiles = {"quartz_pillar_side.png", "quartz_pillar_side.png", "quartz_pillar_side.png^[transformR90", + "quartz_pillar_side.png^[transformR90", "quartz_pillar_top.png", "quartz_pillar_top.png"}, + paramtype2 = "facedir", + drop = 'quartz:pillar', + groups = {cracky=3, oddly_breakable_by_hand=1, not_in_creative_inventory=1}, + sounds = default.node_sound_glass_defaults(), + }) +end + + +--Compatibility with stairsplus + +if minetest.get_modpath("moreblocks") and enable_stairsplus then + register_stair_slab_panel_micro("quartz", "block", "quartz:block", + {cracky=3}, + {"quartz_block.png"}, + "Quartz Block", + "block", + 0) + + register_stair_slab_panel_micro("quartz", "chiseled", "quartz:chiseled", + {cracky=3}, + {"quartz_chiseled.png"}, + "Chiseled Quartz", + "chiseled", + 0) + + register_stair_slab_panel_micro("quartz", "pillar", "quartz:pillar", + {cracky=3}, + {"quartz_pillar_top.png", "quartz_pillar_top.png", "quartz_pillar_side.png"}, + "Quartz Pillar", + "pillar", + 0) + + table.insert(circular_saw.known_stairs, "quartz:block") + table.insert(circular_saw.known_stairs, "quartz:chiseled") + table.insert(circular_saw.known_stairs, "quartz:pillar") +end diff --git a/mods/quartz/settings.txt b/mods/quartz/settings.txt new file mode 100644 index 0000000..4876858 --- /dev/null +++ b/mods/quartz/settings.txt @@ -0,0 +1,7 @@ +-- Set this to true to allow usage of the stairsplus mod in moreblocks + +enable_stairsplus = true + +-- This enables the old horizontal pillar block(deprecated, be sure to convert them back to normal pillars) + +enable_horizontal_pillar = true diff --git a/mods/quartz/textures/.directory b/mods/quartz/textures/.directory new file mode 100644 index 0000000..12dc9a6 --- /dev/null +++ b/mods/quartz/textures/.directory @@ -0,0 +1,4 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2014,5,11,20,5,42 +Version=3 diff --git a/mods/quartz/textures/quartz_block.png b/mods/quartz/textures/quartz_block.png new file mode 100644 index 0000000..230807e Binary files /dev/null and b/mods/quartz/textures/quartz_block.png differ diff --git a/mods/quartz/textures/quartz_chiseled.png b/mods/quartz/textures/quartz_chiseled.png new file mode 100644 index 0000000..e8c9b96 Binary files /dev/null and b/mods/quartz/textures/quartz_chiseled.png differ diff --git a/mods/quartz/textures/quartz_crystal_full.png b/mods/quartz/textures/quartz_crystal_full.png new file mode 100644 index 0000000..35de75a Binary files /dev/null and b/mods/quartz/textures/quartz_crystal_full.png differ diff --git a/mods/quartz/textures/quartz_crystal_piece.png b/mods/quartz/textures/quartz_crystal_piece.png new file mode 100644 index 0000000..45e448f Binary files /dev/null and b/mods/quartz/textures/quartz_crystal_piece.png differ diff --git a/mods/quartz/textures/quartz_ore.png b/mods/quartz/textures/quartz_ore.png new file mode 100644 index 0000000..7a8ad21 Binary files /dev/null and b/mods/quartz/textures/quartz_ore.png differ diff --git a/mods/quartz/textures/quartz_pillar_side.png b/mods/quartz/textures/quartz_pillar_side.png new file mode 100644 index 0000000..b6d696e Binary files /dev/null and b/mods/quartz/textures/quartz_pillar_side.png differ diff --git a/mods/quartz/textures/quartz_pillar_side_horizontal.png b/mods/quartz/textures/quartz_pillar_side_horizontal.png new file mode 100644 index 0000000..5eccff6 Binary files /dev/null and b/mods/quartz/textures/quartz_pillar_side_horizontal.png differ diff --git a/mods/quartz/textures/quartz_pillar_top.png b/mods/quartz/textures/quartz_pillar_top.png new file mode 100644 index 0000000..c729bc7 Binary files /dev/null and b/mods/quartz/textures/quartz_pillar_top.png differ diff --git a/mods/sim_paint/._MTGITSYNC_IGNORE_ b/mods/sim_paint/._MTGITSYNC_IGNORE_ new file mode 100644 index 0000000..e69de29 diff --git a/mods/sim_paint/depends.txt b/mods/sim_paint/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/mods/sim_paint/depends.txt @@ -0,0 +1 @@ +default diff --git a/mods/sim_paint/init.lua b/mods/sim_paint/init.lua new file mode 100644 index 0000000..5acc415 --- /dev/null +++ b/mods/sim_paint/init.lua @@ -0,0 +1,117 @@ +-- Modified paintings mod. +-- The original is by jordan4ibanez. +-- My changes are licensed under either CC-0 or WTFPL. You can do what +-- you want with my changes. + +minetest.register_node("sim_paint:canvas", { + description = "Painting", + drawtype = "signlike", + tile_images = {"sim_paint_canvas.png"}, + inventory_image = "sim_paint_canvas.png", + wield_image = "sim_paint_canvas.png", + paramtype = "light", + paramtype2 = "wallmounted", + sunlight_propagates = true, + walkable = false, + paramtype2 = 'wallmounted', + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3}, + selection_box = { + type = "wallmounted", + --wall_top = + --wall_bottom = + --wall_side = + }, + material = minetest.digprop_constanttime(0.5), + furnace_burntime = 10, + legacy_wallmounted = true, +}) + +minetest.register_craft({ + output = 'sim_paint:canvas', + recipe = { + { 'default:stick', 'default:stick', 'default:stick'}, + { 'default:stick', 'default:paper', 'default:stick'}, + { 'default:stick', 'default:stick', 'default:stick'}, + }, +}) + +-- Shortcut function for defining paintings. + +function register_painting(id, image) + minetest.register_node("sim_paint:id_" .. tostring(id), { + drawtype = "signlike", + tile_images = {image}, + inventory_image = image, + paramtype = "light", + sunlight_propagates = true, + walkable = false, + paramtype = 'light', + paramtype2 = 'wallmounted', + drop = 'sim_paint:canvas', + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3}, + selection_box = { + type = "wallmounted", + --wall_top = + --wall_bottom = + --wall_side = + }, + material = minetest.digprop_constanttime(0.0), + furnace_burntime = 10, + legacy_wallmounted = true + }) +end + +-- Paintings can be added by adding to the list below. +-- +-- Example: +-- local paintings = { +-- "paintings_fluttershy.png", +-- "paintings_pinkiepie.png" +-- } +-- +-- This will register two paintings. Their names start at "sim_paint:id_1", +-- and increment: "sim_paint:id_2" "sim_paint:id_3" and so on. +-- +-- The corresponding image filename is used as the texture. Yay? :) +-- + +local paintings = { + "bedroom_0.png", + "bedroom_1.png", + "bedroom_2.png", + "bedroom_3.png", + "brewing_0.png", + "brewing_1.png", + "brewing_2.png", + "brewing_3.png", + "base_0.png", + "base_1.png", + "base_2.png", + "base_3.png", +} + +-- Below is very important code. + +local AMOUNT_OF_PAINTING_TYPES = #paintings +for i=1,AMOUNT_OF_PAINTING_TYPES do + register_painting(i, paintings[i]) +end + +--RANDOM GIVER + +minetest.register_on_placenode(function(pos, newnode, placer) + --first section detects if it is the base painting + if newnode.name == "sim_paint:canvas" then + --param.2 detects the state that this object is placed in and stores it + local state = newnode.param2 + + --this makes the game generate a random number + local i = math.random(1, AMOUNT_OF_PAINTING_TYPES) + + --removes the painting_canvas + if minetest.env:remove_node(pos) then + minetest.env:add_node(pos, {name="sim_paint:id_" .. tostring(i),param2=state}) + end + end +end) + diff --git a/mods/sim_paint/textures/.directory b/mods/sim_paint/textures/.directory new file mode 100644 index 0000000..4b11d2b --- /dev/null +++ b/mods/sim_paint/textures/.directory @@ -0,0 +1,4 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2014,2,25,21,54,31 +Version=3 diff --git a/mods/sim_paint/textures/a.png b/mods/sim_paint/textures/a.png new file mode 100644 index 0000000..2d2aa30 Binary files /dev/null and b/mods/sim_paint/textures/a.png differ diff --git a/mods/sim_paint/textures/b.png b/mods/sim_paint/textures/b.png new file mode 100644 index 0000000..55aa4e0 Binary files /dev/null and b/mods/sim_paint/textures/b.png differ diff --git a/mods/sim_paint/textures/base_0.png b/mods/sim_paint/textures/base_0.png new file mode 100644 index 0000000..42e99e1 Binary files /dev/null and b/mods/sim_paint/textures/base_0.png differ diff --git a/mods/sim_paint/textures/base_1.png b/mods/sim_paint/textures/base_1.png new file mode 100644 index 0000000..a65e448 Binary files /dev/null and b/mods/sim_paint/textures/base_1.png differ diff --git a/mods/sim_paint/textures/base_2.png b/mods/sim_paint/textures/base_2.png new file mode 100644 index 0000000..7b8fd3f Binary files /dev/null and b/mods/sim_paint/textures/base_2.png differ diff --git a/mods/sim_paint/textures/base_3.png b/mods/sim_paint/textures/base_3.png new file mode 100644 index 0000000..c28a10f Binary files /dev/null and b/mods/sim_paint/textures/base_3.png differ diff --git a/mods/sim_paint/textures/bedroom_0.png b/mods/sim_paint/textures/bedroom_0.png new file mode 100644 index 0000000..8641207 Binary files /dev/null and b/mods/sim_paint/textures/bedroom_0.png differ diff --git a/mods/sim_paint/textures/bedroom_1.png b/mods/sim_paint/textures/bedroom_1.png new file mode 100644 index 0000000..aab37be Binary files /dev/null and b/mods/sim_paint/textures/bedroom_1.png differ diff --git a/mods/sim_paint/textures/bedroom_2.png b/mods/sim_paint/textures/bedroom_2.png new file mode 100644 index 0000000..8a5b911 Binary files /dev/null and b/mods/sim_paint/textures/bedroom_2.png differ diff --git a/mods/sim_paint/textures/bedroom_3.png b/mods/sim_paint/textures/bedroom_3.png new file mode 100644 index 0000000..c5f1063 Binary files /dev/null and b/mods/sim_paint/textures/bedroom_3.png differ diff --git a/mods/sim_paint/textures/brewing_0.png b/mods/sim_paint/textures/brewing_0.png new file mode 100644 index 0000000..9594a1a Binary files /dev/null and b/mods/sim_paint/textures/brewing_0.png differ diff --git a/mods/sim_paint/textures/brewing_1.png b/mods/sim_paint/textures/brewing_1.png new file mode 100644 index 0000000..f5ba4e4 Binary files /dev/null and b/mods/sim_paint/textures/brewing_1.png differ diff --git a/mods/sim_paint/textures/brewing_2.png b/mods/sim_paint/textures/brewing_2.png new file mode 100644 index 0000000..aaf6cab Binary files /dev/null and b/mods/sim_paint/textures/brewing_2.png differ diff --git a/mods/sim_paint/textures/brewing_3.png b/mods/sim_paint/textures/brewing_3.png new file mode 100644 index 0000000..1d0bdd7 Binary files /dev/null and b/mods/sim_paint/textures/brewing_3.png differ diff --git a/mods/sim_paint/textures/c.png b/mods/sim_paint/textures/c.png new file mode 100644 index 0000000..6496d60 Binary files /dev/null and b/mods/sim_paint/textures/c.png differ diff --git a/mods/sim_paint/textures/conv.txt b/mods/sim_paint/textures/conv.txt new file mode 100644 index 0000000..a5a8079 --- /dev/null +++ b/mods/sim_paint/textures/conv.txt @@ -0,0 +1,5 @@ +# Create sim_paint tiles from images (needs ImageMagick) + +convert a.png -crop 32x32 bedroom_%d.png +convert b.png -crop 32x32 brewing_%d.png +convert c.png -crop 32x32 base_%d.png diff --git a/mods/sim_paint/textures/sim_paint_canvas.png b/mods/sim_paint/textures/sim_paint_canvas.png new file mode 100644 index 0000000..3337166 Binary files /dev/null and b/mods/sim_paint/textures/sim_paint_canvas.png differ diff --git a/mods/torches/README.txt b/mods/torches/README.txt new file mode 100644 index 0000000..ef1b16d --- /dev/null +++ b/mods/torches/README.txt @@ -0,0 +1,40 @@ +Minetest mod "Torches" +======================= +version: 1.3.2 + +License of source code and textures: WTFPL +----------------------------------------- +(c) Copyright BlockMen (2013-2014) + + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + + +Using the mod: +-------------- + +This mod adds 3D torches to Minetest. They also have real flames and look much more realistic. + +Notice: Already placed old torches will be converted to new, ceiling placed will be removed + + +Changelog: +---------- +- Torches on wall dont fall when node under it is dug +- Torches fall directly when not placed on floor or wall +- fixed different placing bugs + +1.3: +- Torches only show flames when player is near (13 blocks) +- Old torches are converted to new, ceiling torches are dropped + +1.3.1: +- fix dropping torches when digging a block next to it +- all torches attached to a block get droped when dug + +1.3.2: +- fix crashes by unknown nodes diff --git a/mods/torches/depends.txt b/mods/torches/depends.txt new file mode 100644 index 0000000..331d858 --- /dev/null +++ b/mods/torches/depends.txt @@ -0,0 +1 @@ +default \ No newline at end of file diff --git a/mods/torches/init.lua b/mods/torches/init.lua new file mode 100644 index 0000000..1d57f60 --- /dev/null +++ b/mods/torches/init.lua @@ -0,0 +1,252 @@ +-- Reduce particles send to client if on Server +local SERVER = minetest.is_singleplayer() or false +SERVER = not SERVER +local dur = 0 +if SERVER then + dur = 8 --too high?? +end + +local VIEW_DISTANCE = 13 -- if player is near that distance flames are shown + +local null = {x=0, y=0, z=0} + +local dirs = {{-1,0,-1},{-1,0,0},{0,0,-1}, +{1,0,1},{1,0,0},{0,0,1},{0,1,0}} + +--fire_particles +local function add_fire(pos, duration) + if duration < 1 then + duration = 1.1 + end + pos.y = pos.y+0.19 + minetest.add_particle(pos, null, null, duration, + 1.5, true, "torches_fire"..tostring(math.random(1,2)) ..".png") + pos.y = pos.y +0.01 + minetest.add_particle(pos, null, null, duration-0.3, + 1.5, true, "torches_fire"..tostring(math.random(1,2)) ..".png") +end + +--help functions +function check_attached_node_fdir(p, n) + local def = minetest.registered_nodes[n.name] + local d = {x=0, y=0, z=0} + if def.paramtype2 == "facedir" then + if n.param2 == 0 then + d.z = 1 + elseif n.param2 == 1 then + d.x = 1 + elseif n.param2 == 2 then + d.z = -1 + elseif n.param2 == 3 then + d.x = -1 + end + end + local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z} + local nn = minetest.env:get_node(p2).name + local def2 = minetest.registered_nodes[nn] + if def2 and not def2.walkable then + return false + end + return true +end + +local function is_wall(wallparam) + if wallparam == 0 then return false end + local para2 = 0 + if wallparam == 2 then + para2 = 1 + elseif wallparam == 3 then + para2 = 3 + elseif wallparam == 4 then + para2 = 0 + elseif wallparam == 5 then + para2 = 2 + end + return para2 +end + +local function player_near(pos) + for _,object in ipairs(minetest.env:get_objects_inside_radius(pos, VIEW_DISTANCE)) do + if object:is_player() then + return true + end + end + + return false +end + +-- abms for flames +minetest.register_abm({ + nodenames = {"torches:wand"}, + interval = 1+dur, + chance = 1, + action = function(pos) + if player_near(pos) then + add_fire(pos, dur) + end + end +}) + +minetest.register_abm({ + nodenames = {"torches:floor"}, + interval = 1+dur, + chance = 1, + action = function(pos) + if player_near(pos) then + add_fire(pos, dur) + end + end +}) + +-- convert old torches and remove ceiling placed +minetest.register_abm({ + nodenames = {"default:torch"}, + interval = 1, + chance = 1, + action = function(pos) + local n = minetest.get_node(pos) + local def = minetest.registered_nodes[n.name] + if def then + local wdir = n.param2 + if wdir == 0 then + minetest.remove_node(pos) + elseif wdir == 1 then + minetest.set_node(pos, {name = "torches:floor"}) + else + minetest.set_node(pos, {name = "torches:wand", param2 = is_wall(wdir)}) + end + end + end +}) + +--node_boxes +minetest.register_craftitem(":default:torch", { + description = "Torch", + inventory_image = "torches_torch.png", + wield_image = "torches_torch.png", + wield_scale = {x=1,y=1,z=1+1/16}, + liquids_pointable = false, + on_place = function(itemstack, placer, pointed_thing) + if pointed_thing.type ~= "node" or string.find(minetest.env:get_node(pointed_thing.above).name, "torch") then + return itemstack + end + local above = pointed_thing.above + local under = pointed_thing.under + local wdir = minetest.dir_to_wallmounted({x = under.x - above.x, y = under.y - above.y, z = under.z - above.z}) + local u_n = minetest.get_node(under) + local udef = minetest.registered_nodes[u_n.name] + if u_n and udef and not udef.walkable then above = under end + u_n = minetest.get_node(above) + udef = minetest.registered_nodes[u_n.name] + if u_n and udef and udef.walkable then return itemstack end + if wdir == 1 then + minetest.env:add_node(above, {name = "torches:floor"}) + else + minetest.env:add_node(above, {name = "torches:wand", param2 = is_wall(wdir)}) + end + if not wdir == 0 or not minetest.setting_getbool("creative_mode") then + itemstack:take_item() + end + add_fire(above, dur) + return itemstack + + end + +}) + +minetest.register_node("torches:floor", { + --description = "Fakel", + inventory_image = "default_torch.png", + wield_image = "torches_torch.png", + wield_scale = {x=1,y=1,z=1+2/16}, + drawtype = "nodebox", + tiles = {"torches_torch.png^[transformfy", "default_wood.png", "torches_torch.png", + "torches_torch.png^[transformfx", "torches_torch.png", "torches_torch.png"}, + paramtype = "light", + paramtype2 = "none", + sunlight_propagates = true, + drop = "default:torch", + walkable = false, + light_source = 13, + groups = {choppy=2,dig_immediate=3,flammable=1,not_in_creative_inventory=1,torch=1}, + legacy_wallmounted = true, + node_box = { + type = "fixed", + fixed = {-1/16, -0.5, -1/16, 1/16, 2/16, 1/16}, + }, + selection_box = { + type = "fixed", + fixed = {-1/16, -0.5, -1/16, 1/16, 2/16, 1/16}, + }, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + if not digger:is_player() then minetest.add_item(pos, {name="default:torch"}) end + end, + update = function(pos,node, pos2) + if pos2.y < pos.y then + minetest.dig_node(pos) + end + end, +}) + +local wall_ndbx = { + {-1/16,-6/16, 6/16, 1/16, -5/16, 0.5}, + {-1/16,-5/16, 5/16, 1/16, -4/16, 7/16}, + {-1/16,-4/16, 4/16, 1/16, -3/16, 6/16}, + {-1/16,-3/16, 3/16, 1/16, -2/16, 5/16}, + {-1/16,-2/16, 2/16, 1/16, -1/16, 4/16}, + {-1/16,-1/16, 1/16, 1/16, 0, 3/16}, + {-1/16,0, 1/16, 1/16, 1/16, 2/16}, + {-1/16, 0, -1/16, 1/16, 2/16, 1/16}, +} + +minetest.register_node("torches:wand", { + --description = "Fakel", + inventory_image = "default_torch.png", + wield_image = "torches_torch.png", + wield_scale = {x=1,y=1,z=1+1/16}, + drawtype = "nodebox", + tiles = {"torches_torch.png^[transformfy", "default_wood.png", "torches_side.png", + "torches_side.png^[transformfx", "default_wood.png", "torches_torch.png"}, + + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + walkable = false, + light_source = 13, + groups = {choppy=2,dig_immediate=3,flammable=1,not_in_creative_inventory=1,torch=1}, + legacy_wallmounted = true, + drop = "default:torch", + node_box = { + type = "fixed", + fixed = wall_ndbx + }, + selection_box = { + type = "fixed", + fixed = {-1/16, -6/16, 7/16, 1/16, 2/16, 2/16}, + }, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + if not digger:is_player() then minetest.add_item(pos, {name="default:torch"}) end + end, + update = function(pos,node) + if not check_attached_node_fdir(pos, node) then + minetest.dig_node(pos) + end + end, + + +}) + +minetest.register_on_dignode(function(pos, oldnode, digger) + if minetest.find_node_near(pos, 1, {"group:torch"}) == nil then return end + for i=1,#dirs do + local v = dirs[i] + local p = {x=pos.x+v[1],y=pos.y+v[2],z=pos.z+v[3]} + local n = minetest.get_node_or_nil(p) + if n and n.name then + local def = minetest.registered_nodes[n.name] + if def and def.update then + def.update(p, n, pos) + end + end + end +end) diff --git a/mods/torches/textures/torches_fire1.png b/mods/torches/textures/torches_fire1.png new file mode 100644 index 0000000..45a5d28 Binary files /dev/null and b/mods/torches/textures/torches_fire1.png differ diff --git a/mods/torches/textures/torches_fire2.png b/mods/torches/textures/torches_fire2.png new file mode 100644 index 0000000..d09eb19 Binary files /dev/null and b/mods/torches/textures/torches_fire2.png differ diff --git a/mods/torches/textures/torches_side.png b/mods/torches/textures/torches_side.png new file mode 100644 index 0000000..d279c04 Binary files /dev/null and b/mods/torches/textures/torches_side.png differ diff --git a/mods/torches/textures/torches_torch.png b/mods/torches/textures/torches_torch.png new file mode 100644 index 0000000..bc47491 Binary files /dev/null and b/mods/torches/textures/torches_torch.png differ diff --git a/mods/weather/weather/init.lua b/mods/weather/weather/init.lua index 81cf964..41dc257 100644 --- a/mods/weather/weather/init.lua +++ b/mods/weather/weather/init.lua @@ -33,11 +33,11 @@ minetest.register_globalstep(function(dtime) save_weather() end else - if math.random(1, 50000) == 1 then + if math.random(1, 30000) == 2 then weather = "rain" save_weather() end - if math.random(1, 50000) == 2 then + if math.random(1, 60000) == 2 then weather = "snow" save_weather() end diff --git a/mods/xpanes/init.lua b/mods/xpanes/init.lua new file mode 100644 index 0000000..ea9df71 --- /dev/null +++ b/mods/xpanes/init.lua @@ -0,0 +1,120 @@ +-- xPanes mod by xyz +function pane(node, desc, dropitem, recipeitem) + local function rshift(x, by) + return math.floor(x / 2 ^ by) + end + + local directions = { + {x = 1, y = 0, z = 0}, + {x = 0, y = 0, z = 1}, + {x = -1, y = 0, z = 0}, + {x = 0, y = 0, z = -1}, + } + + local function update_pane(pos) + if minetest.env:get_node(pos).name:find("xpanes:pane_"..node) == nil then + return + end + local sum = 0 + for i = 1, 4 do + local node = minetest.env:get_node({x = pos.x + directions[i].x, y = pos.y + directions[i].y, z = pos.z + directions[i].z}) + if minetest.registered_nodes[node.name].walkable ~= false then + if string.find(node.name, "fence") == nil then + if string.find(node.name, "mesecons") == nil then + sum = sum + 2 ^ (i - 1) + end + end + end + end + if sum == 0 then + sum = 15 + end + minetest.env:add_node(pos, {name = "xpanes:pane_"..node.."_"..sum}) + end + + local function update_nearby(pos) + for i = 1,4 do + update_pane({x = pos.x + directions[i].x, y = pos.y + directions[i].y, z = pos.z + directions[i].z}) + end + end + + local half_blocks = { + {0, -0.5, -0.06, 0.5, 0.5, 0.06}, + {-0.06, -0.5, 0, 0.06, 0.5, 0.5}, + {-0.5, -0.5, -0.06, 0, 0.5, 0.06}, + {-0.06, -0.5, -0.5, 0.06, 0.5, 0} + } + + local full_blocks = { + {-0.5, -0.5, -0.06, 0.5, 0.5, 0.06}, + {-0.06, -0.5, -0.5, 0.06, 0.5, 0.5} + } + + for i = 1, 15 do + local need = {} + local cnt = 0 + for j = 1, 4 do + if rshift(i, j - 1) % 2 == 1 then + need[j] = true + cnt = cnt + 1 + end + end + local take = {} + if need[1] == true and need[3] == true then + need[1] = nil + need[3] = nil + table.insert(take, full_blocks[1]) + end + if need[2] == true and need[4] == true then + need[2] = nil + need[4] = nil + table.insert(take, full_blocks[2]) + end + for k in pairs(need) do + table.insert(take, half_blocks[k]) + end + local texture = "xpanes_pane_"..node..".png" + if cnt == 1 then + texture = "xpanes_pane_half_"..node..".png" + end + minetest.register_node("xpanes:pane_"..node.."_"..i, { + drawtype = "nodebox", + tile_images = {"xpanes_top_"..node..".png", "xpanes_top_"..node..".png", texture}, + paramtype = "light", + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + drop = dropitem, + node_box = { + type = "fixed", + fixed = take + }, + selection_box = { + type = "fixed", + fixed = take + } + }) + end + + minetest.register_node("xpanes:pane_"..node, { + description = desc, + tile_images = {"xpanes_space.png"}, + inventory_image = "xpanes_pane_"..node..".png", + wield_image = "xpanes_pane_"..node..".png", + node_placement_prediction = "", + on_construct = update_pane, + drop = "", + }) + + minetest.register_on_placenode(update_nearby) + minetest.register_on_dignode(update_nearby) + + minetest.register_craft({ + output = 'xpanes:pane_'..node..' 16', + recipe = { + {recipeitem, recipeitem, recipeitem}, + {recipeitem, recipeitem, recipeitem} + } + }) +end + +pane("glass", "Glass Pane", "", "default:glass") +pane("iron", "Iron Fence", "xpanes:pane_iron", "default:steel_ingot") \ No newline at end of file diff --git a/mods/xpanes/textures/.directory b/mods/xpanes/textures/.directory new file mode 100644 index 0000000..ea5867f --- /dev/null +++ b/mods/xpanes/textures/.directory @@ -0,0 +1,4 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2014,7,7,18,22,13 +Version=3 diff --git a/mods/xpanes/textures/xpanes_pane_glass.png b/mods/xpanes/textures/xpanes_pane_glass.png new file mode 100644 index 0000000..e7fa21f Binary files /dev/null and b/mods/xpanes/textures/xpanes_pane_glass.png differ diff --git a/mods/xpanes/textures/xpanes_pane_half_glass.png b/mods/xpanes/textures/xpanes_pane_half_glass.png new file mode 100644 index 0000000..0cb12b2 Binary files /dev/null and b/mods/xpanes/textures/xpanes_pane_half_glass.png differ diff --git a/mods/xpanes/textures/xpanes_pane_half_iron.png b/mods/xpanes/textures/xpanes_pane_half_iron.png new file mode 100644 index 0000000..1bcbda4 Binary files /dev/null and b/mods/xpanes/textures/xpanes_pane_half_iron.png differ diff --git a/mods/xpanes/textures/xpanes_pane_iron.png b/mods/xpanes/textures/xpanes_pane_iron.png new file mode 100644 index 0000000..1bcbda4 Binary files /dev/null and b/mods/xpanes/textures/xpanes_pane_iron.png differ diff --git a/mods/xpanes/textures/xpanes_space.png b/mods/xpanes/textures/xpanes_space.png new file mode 100644 index 0000000..c2e8752 Binary files /dev/null and b/mods/xpanes/textures/xpanes_space.png differ diff --git a/mods/xpanes/textures/xpanes_top_glass.png b/mods/xpanes/textures/xpanes_top_glass.png new file mode 100644 index 0000000..bf9cd92 Binary files /dev/null and b/mods/xpanes/textures/xpanes_top_glass.png differ diff --git a/mods/xpanes/textures/xpanes_top_iron.png b/mods/xpanes/textures/xpanes_top_iron.png new file mode 100644 index 0000000..7ec2772 Binary files /dev/null and b/mods/xpanes/textures/xpanes_top_iron.png differ