8 Commits

Author SHA1 Message Date
bce5306abe Fix Mining Drill Mk1 not drilling
Problem introduced in  0f6bdb1
2022-06-19 16:50:20 +02:00
167ab93905 Maintenance: Remove depends.txt and error on old MT versions 2022-06-14 20:49:21 +02:00
5beb84bed9 Improve/trim the user manual further
Detailed information can be found on Wikipedia. The user manual
should be a compact documentation of the mod as whole.
This replaces long explanations with relevant links for use by
people who are interested in going deeper into this matter.
2022-06-14 20:46:16 +02:00
f9b0906a82 Switching station: Begin optimizations 2022-06-08 21:57:46 +02:00
9a39a94272 Further document the API 2022-06-08 20:19:53 +02:00
349676f243 CNC: Fix startup error and texture warnings 2022-06-06 21:19:04 +02:00
0f6bdb1bde Correct (almost) all luacheck warnings
Also includes a few code opimizations:
- Combined mining drill functions
- Shorter alias registration (unused?)
- Add TODOs to address later
2022-06-06 21:04:13 +02:00
0211c582e9 Add charge set/get callbacks (#600)
For the easier making of multi mod chargeable tools.
2022-06-06 18:53:50 +02:00
32 changed files with 617 additions and 724 deletions

View File

@ -1,6 +1,8 @@
unused_args = false
allow_defined_top = true
max_line_length = 999
max_line_length = 150
-- Allow shadowed variables (callbacks in callbacks)
redefined = false
globals = {
"technic", "minetest",
@ -32,19 +34,7 @@ read_globals = {
"craftguide", "i3"
}
files["concrete/init.lua"].ignore = { "steel_ingot" }
files["technic/machines/MV/tool_workshop.lua"].ignore = { "pos" }
files["technic/machines/other/frames.lua"].ignore = { "item_texture", "item_type", "adj", "connected", "" }
files["technic/machines/register/battery_box.lua"].ignore = { "pos", "tube_upgrade" }
files["technic/machines/register/cables.lua"].ignore = { "name", "from_below", "p" }
files["technic/machines/register/common.lua"].ignore = { "result" }
files["technic/machines/register/generator.lua"].ignore = { "node" }
files["technic/machines/switching_station.lua"].ignore = { "pos1", "tier", "poshash" }
files["technic/radiation.lua"].ignore = { "LAVA_VISC" }
files["technic/tools/chainsaw.lua"].ignore = { "pos" }
files["technic/tools/mining_drill.lua"].ignore = { "mode" }
files["technic_chests/register.lua"].ignore = { "fs_helpers", "name", "locked_after_place" }
files["technic_cnc/cnc.lua"].ignore = { "multiplier" }
files["wrench/init.lua"].ignore = { "name", "stack" }
-- Loop warning
files["technic/machines/other/frames.lua"].ignore = { "" }
-- Long lines
files["technic_cnc/cnc_api.lua"].ignore = { "" }

16
LICENSE.txt Normal file
View File

@ -0,0 +1,16 @@
Minetest Mod: technic
Copyright (C) 2012-2022 RealBadAngel and contributors
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

View File

@ -24,7 +24,8 @@ world. A few notable features:
## FAQ
The modpack is explained in the [Manual](manual.md) included in this repository.
The modpack is explained in the **[Manual](manual.md)** included in this repository.
Machine and tool descriptions can be found on the **[GitHub Wiki](https://github.com/minetest-mods/technic/wiki)**.
1. My technic circuit doesn't work. No power is distributed.
* Make sure you have a switching station connected.
@ -32,13 +33,13 @@ The modpack is explained in the [Manual](manual.md) included in this repository.
* Each machine type requires its own cable type. If you do not have a
matching circuit, consider using a "Supply Converter" for simplicity.
The API documentation can be found here: [Technic API](technic/doc/api.md)
For modders: **[Technic Lua API](technic/doc/api.md)**
## License
Unless otherwise stated, all components of this modpack are licensed under the
LGPLv2 or later. See also the individual mod folders for their
[LGPLv2 or later](LICENSE.txt). See also the individual mod folders for their
secondary/alternate licenses, if any.

View File

@ -1,4 +0,0 @@
default
basic_materials
intllib?
moreblocks?

View File

@ -16,13 +16,6 @@ for i = 32, 63 do
"technic:concrete_post_with_platform")
end
local steel_ingot
if minetest.get_modpath("technic_worldgen") then
steel_ingot = "technic:carbon_steel_ingot"
else
steel_ingot = "default:steel_ingot"
end
minetest.register_craft({
output = 'technic:concrete_post_platform 6',
recipe = {

View File

@ -1,9 +0,0 @@
default
technic_worldgen
basic_materials
concrete
unifieddyes?
intllib?
moreblocks?
steel?
streetsmod?

View File

@ -57,36 +57,47 @@ if minetest.get_modpath("moreblocks") then
tiles={"technic_stainless_steel_block.png"},
})
function register_technic_stairs_alias(modname, origname, newmod, newname)
minetest.register_alias(modname .. ":slab_" .. origname, newmod..":slab_" .. newname)
minetest.register_alias(modname .. ":slab_" .. origname .. "_inverted", newmod..":slab_" .. newname .. "_inverted")
minetest.register_alias(modname .. ":slab_" .. origname .. "_wall", newmod..":slab_" .. newname .. "_wall")
minetest.register_alias(modname .. ":slab_" .. origname .. "_quarter", newmod..":slab_" .. newname .. "_quarter")
minetest.register_alias(modname .. ":slab_" .. origname .. "_quarter_inverted", newmod..":slab_" .. newname .. "_quarter_inverted")
minetest.register_alias(modname .. ":slab_" .. origname .. "_quarter_wall", newmod..":slab_" .. newname .. "_quarter_wall")
minetest.register_alias(modname .. ":slab_" .. origname .. "_three_quarter", newmod..":slab_" .. newname .. "_three_quarter")
minetest.register_alias(modname .. ":slab_" .. origname .. "_three_quarter_inverted", newmod..":slab_" .. newname .. "_three_quarter_inverted")
minetest.register_alias(modname .. ":slab_" .. origname .. "_three_quarter_wall", newmod..":slab_" .. newname .. "_three_quarter_wall")
minetest.register_alias(modname .. ":stair_" .. origname, newmod..":stair_" .. newname)
minetest.register_alias(modname .. ":stair_" .. origname .. "_inverted", newmod..":stair_" .. newname .. "_inverted")
minetest.register_alias(modname .. ":stair_" .. origname .. "_wall", newmod..":stair_" .. newname .. "_wall")
minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half", newmod..":stair_" .. newname .. "_wall_half")
minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half_inverted", newmod..":stair_" .. newname .. "_wall_half_inverted")
minetest.register_alias(modname .. ":stair_" .. origname .. "_half", newmod..":stair_" .. newname .. "_half")
minetest.register_alias(modname .. ":stair_" .. origname .. "_half_inverted", newmod..":stair_" .. newname .. "_half_inverted")
minetest.register_alias(modname .. ":stair_" .. origname .. "_right_half", newmod..":stair_" .. newname .. "_right_half")
minetest.register_alias(modname .. ":stair_" .. origname .. "_right_half_inverted", newmod..":stair_" .. newname .. "_right_half_inverted")
minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half", newmod..":stair_" .. newname .. "_wall_half")
minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half_inverted", newmod..":stair_" .. newname .. "_wall_half_inverted")
minetest.register_alias(modname .. ":stair_" .. origname .. "_inner", newmod..":stair_" .. newname .. "_inner")
minetest.register_alias(modname .. ":stair_" .. origname .. "_inner_inverted", newmod..":stair_" .. newname .. "_inner_inverted")
minetest.register_alias(modname .. ":stair_" .. origname .. "_outer", newmod..":stair_" .. newname .. "_outer")
minetest.register_alias(modname .. ":stair_" .. origname .. "_outer_inverted", newmod..":stair_" .. newname .. "_outer_inverted")
minetest.register_alias(modname .. ":panel_" .. origname .. "_bottom", newmod..":panel_" .. newname .. "_bottom")
minetest.register_alias(modname .. ":panel_" .. origname .. "_top", newmod..":panel_" .. newname .. "_top")
minetest.register_alias(modname .. ":panel_" .. origname .. "_vertical", newmod..":panel_" .. newname .. "_vertical")
minetest.register_alias(modname .. ":micro_" .. origname .. "_bottom", newmod..":micro_" .. newname .. "_bottom")
minetest.register_alias(modname .. ":micro_" .. origname .. "_top", newmod..":micro_" .. newname .. "_top")
function register_technic_stairs_alias(origmod, origname, newmod, newname)
local func = minetest.register_alias
local function remap(kind, suffix)
-- Old: stairsplus:slab_concrete_wall
-- New: technic:slab_concrete_wall
func(("%s:%s_%s%s"):format(origmod, kind, origname, suffix),
("%s:%s_%s%s"):format(newmod, kind, newname, suffix))
end
-- Slabs
remap("slab", "")
remap("slab", "_inverted")
remap("slab", "_wall")
remap("slab", "_quarter")
remap("slab", "_quarter_inverted")
remap("slab", "_quarter_wall")
remap("slab", "_three_quarter")
remap("slab", "_three_quarter_inverted")
remap("slab", "_three_quarter_wall")
-- Stairs
remap("stair", "")
remap("stair", "_inverted")
remap("stair", "_wall")
remap("stair", "_wall_half")
remap("stair", "_wall_half_inverted")
remap("stair", "_half")
remap("stair", "_half_inverted")
remap("stair", "_right_half")
remap("stair", "_right_half_inverted")
remap("stair", "_inner")
remap("stair", "_inner_inverted")
remap("stair", "_outer")
remap("stair", "_outer_inverted")
-- Other
remap("panel", "_bottom")
remap("panel", "_top")
remap("panel", "_vertical")
remap("micro", "_bottom")
remap("micro", "_top")
end
register_technic_stairs_alias("stairsplus", "concrete", "technic", "concrete")

369
manual.md
View File

@ -12,16 +12,16 @@ Documentation of the mod dependencies can be found here:
* [Moreores Forum Post](https://forum.minetest.net/viewtopic.php?t=549)
* [Basic materials Repository](https://gitlab.com/VanessaE/basic_materials)
## Recipes
## 1.0 Recipes
Recipes for items registered by technic are not specifically documented here.
Please consult a craft guide mod to look up the recipes in-game.
**Recommended mod:** [Unified Inventory](https://github.com/minetest-mods/unified_inventory)
## Substances
## 2.0 Substances
### Ores
### 2.1 Ores
Technic registers a few ores which are needed to craft machines or items.
Each ore type is found at a specific range of elevations so you will
@ -59,14 +59,14 @@ of its usage, so you will usually have a surplus of it.
#### Zinc
Use: brass
Depth: 2m, more commonly below -32m
Generated below: 2m, more commonly below -32m
Zinc only has a few uses but is a common metal.
#### Chromium
Use: stainless steel
Depth: -100m, more commonly below -200m
Generated below: -100m, more commonly below -200m
#### Uranium
Use: nuclear reactor fuel
@ -82,14 +82,14 @@ Keep a safety distance of a meter to avoid being harmed by radiation.
#### Silver ²
Use: conductors
Depth: -2m, evenly common
Generated below: -2m, evenly common
Silver is a semi-precious metal and is the best conductor of all the pure elements.
#### Gold ¹
Use: various
Depth: -64m, more commonly below -256m
Generated below: -64m, more commonly below -256m
Gold is a precious metal. It is most notably used in electrical items due to
its combination of good conductivity and corrosion resistance.
@ -97,7 +97,7 @@ its combination of good conductivity and corrosion resistance.
#### Mithril ²
Use: chests
Depth: -512m, evenly common
Generated below: -512m, evenly common
Mithril is a fictional ore, being derived from J. R. R. Tolkien's
Middle-Earth setting. It is little used.
@ -114,7 +114,7 @@ Use: mainly for cutting machines
Diamond is a precious gemstone. It is used moderately, mainly for reasons
connected to its extreme hardness.
### Rocks
### 2.2 Rocks
This section describes the rock types added by technic. Further rock types
are supported by technic machines. These can be processed using the grinder:
@ -136,7 +136,7 @@ Granite is found in dense clusters and is much harder to dig than standard
stone. It has mainly decorative use, but also appears in a couple of
machine recipes.
### Rubber
### 2.3 Rubber
Rubber is a biologically-derived material that has industrial uses due
to its electrical resistivity and its impermeability. In technic, it
is used in a few recipes, and it must be acquired by tapping rubber trees.
@ -150,7 +150,7 @@ observed by its appearance.
To obtain rubber from latex, alloy latex with coal dust.
### Metals
## 3.0 Metal processing
Generally, each metal can exist in five forms:
* ore -> stone containing the lump
@ -162,7 +162,7 @@ Generally, each metal can exist in five forms:
Metals can be converted between dust, ingot and block, but can't be converted
from them back to ore or lump forms.
#### Grinding
### Grinding
Ores can be processed as follows:
* ore -> lump (digging) -> ingot (melting)
@ -171,121 +171,59 @@ Ores can be processed as follows:
At the expense of some energy consumption, the grinder can extract more material
from the lump, resulting in 2x dust which can be melted to two ingots in total.
#### Alloying
Alloying recipes in which a metal is the base ingredient, to produce a
metal alloy, always come in two forms, using the metal either as dust
or as an ingot. If the secondary ingredient is also a metal, it must
be supplied in the same form as the base ingredient. The output alloy
is also returned in the same form.
### Alloying
Input: two ingredients of the same form - lump or dust
Example: 2x copper ingots + zinc ingot -> 3x brass ingot (alloying)
Output: resulting alloy, as an ingot
The same will also work for dust ingredients, resulting in brass dist.
Example: 2x copper ingots + 1x zinc ingot -> 3x brass ingot (alloying)
### iron and its alloys ###
Note that grinding before alloying is the preferred method to gain more output.
Iron forms several important alloys. In real-life history, iron was the
second metal to be used as the base component of deliberately-constructed
alloys (the first was copper), and it was the first metal whose working
required processes of any metallurgical sophistication. The game
mechanics around iron broadly imitate the historical progression of
processes around it, rather than the less-varied modern processes.
#### iron and its alloys
The two-component alloying system of iron with carbon is of huge
importance, both in the game and in real life. The basic Minetest game
doesn't distinguish between these pure iron and these alloys at all,
but technic introduces a distinction based on the carbon content, and
renames some items of the basic game accordingly.
Historically iron was the first metal whose working required processes of any
metallurgical sophistication. The mod's mechanics around iron broadly imitate
the historical progression of processes around it to get more variety.
The iron/carbon spectrum is represented in the game by three metal
substances: wrought iron, carbon steel, and cast iron. Wrought iron
has low carbon content (less than 0.25%), resists shattering, and
is easily welded, but is relatively soft and susceptible to rusting.
In real-life history it was used for rails, gates, chains, wire, pipes,
fasteners, and other purposes. Cast iron has high carbon content
(2.1% to 4%), is especially hard, and resists corrosion, but is
relatively brittle, and difficult to work. Historically it was used
to build large structures such as bridges, and for cannons, cookware,
and engine cylinders. Carbon steel has medium carbon content (0.25%
to 2.1%), and intermediate properties: moderately hard and also tough,
somewhat resistant to corrosion. In real life it is now used for most
of the purposes previously satisfied by wrought iron and many of those
of cast iron, but has historically been especially important for its
use in swords, armor, skyscrapers, large bridges, and machines.
Notable alloys:
In real-life history, the first form of iron to be refined was
wrought iron, which is nearly pure iron, having low carbon content.
It was produced from ore by a low-temperature furnace process (the
"bloomery") in which the ore/iron remains solid and impurities (slag)
are progressively removed by hammering ("working", hence "wrought").
This began in the middle East, around 1800 BCE.
* Wrought iron: <0.25% carbon
* Resists shattering but is relatively soft.
* Known since: 1800 BC (approx.)
* Cast iron: 2.1% to 4% carbon.
* Especially hard and rather corrosion-resistant
* Known since: 1200 BC (approx.)
* Carbon steel: 0.25% to 2.1% carbon.
* Intermediate of the two above.
* Known since: 1600 AD (approx.)
Historically, the next forms of iron to be refined were those of high
carbon content. This was the result of the development of a more
sophisticated kind of furnace, the blast furnace, capable of reaching
higher temperatures. The real advantage of the blast furnace is that it
melts the metal, allowing it to be cast straight into a shape supplied by
a mould, rather than having to be gradually beaten into the desired shape.
A side effect of the blast furnace is that carbon from the furnace's fuel
is unavoidably incorporated into the metal. Normally iron is processed
twice through the blast furnace: once producing "pig iron", which has
very high carbon content and lots of impurities but lower melting point,
casting it into rough ingots, then remelting the pig iron and casting it
into the final moulds. The result is called "cast iron". Pig iron was
first produced in China around 1200 BCE, and cast iron later in the 5th
century BCE. Incidentally, the Chinese did not have the bloomery process,
so this was their first iron refining process, and, unlike the rest of
the world, their first wrought iron was made from pig iron rather than
directly from ore.
Technic introduces a distinction based on the carbon content, and renames some
items of the basic game accordingly. Iron and Steel are now distinguished.
Carbon steel, with intermediate carbon content, was developed much later,
in Europe in the 17th century CE. It required a more sophisticated
process, because the blast furnace made it extremely difficult to achieve
a controlled carbon content. Tweaks of the blast furnace would sometimes
produce an intermediate carbon content by luck, but the first processes to
reliably produce steel were based on removing almost all the carbon from
pig iron and then explicitly mixing a controlled amount of carbon back in.
Notable references:
In the game, the bloomery process is represented by ordinary cooking
or grinding of an iron lump. The lump represents unprocessed ore,
and is identified only as "iron", not specifically as wrought iron.
This standard refining process produces dust or an ingot which is
specifically identified as wrought iron. Thus the standard refining
process produces the (nearly) pure metal.
* https://en.wikipedia.org/wiki/Iron
* https://en.wikipedia.org/wiki/Stainless_steel
* ... plus many more.
Cast iron is trickier. You might expect from the real-life notes above
that cooking an iron lump (representing ore) would produce pig iron that
can then be cooked again to produce cast iron. This is kind of the case,
but not exactly, because as already noted cooking an iron lump produces
wrought iron. The game doesn't distinguish between low-temperature
and high-temperature cooking processes: the same furnace is used not
just to cast all kinds of metal but also to cook food. So there is no
distinction between cooking processes to produce distinct wrought iron
and pig iron. But repeated cooking *is* available as a game mechanic,
and is indeed used to produce cast iron: re-cooking a wrought iron ingot
produces a cast iron ingot. So pig iron isn't represented in the game as
a distinct item; instead wrought iron stands in for pig iron in addition
to its realistic uses as wrought iron.
Processes:
Carbon steel is produced by a more regular in-game process: alloying
wrought iron with coal dust (which is essentially carbon). This bears
a fair resemblance to the historical development of carbon steel.
This alloying recipe is relatively time-consuming for the amount of
material processed, when compared against other alloying recipes, and
carbon steel is heavily used, so it is wise to alloy it in advance,
when you're not waiting for it.
* Iron -> Wrought iron (melting)
* Wrought iron -> Cast iron (melting)
* Wrought iron + coal dust -> Carbon steel (alloying)
* Carbon steel + coal dust -> Cast iron (alloying)
* Carbon steel + chromium -> Stainless steel (alloying)
There are additional recipes that permit all three of these types of iron
to be converted into each other. Alloying carbon steel again with coal
dust produces cast iron, with its higher carbon content. Cooking carbon
steel or cast iron produces wrought iron, in an abbreviated form of the
bloomery process.
Reversible processes:
There's one more iron alloy in the game: stainless steel. It is managed
in a completely regular manner, created by alloying carbon steel with
chromium.
* Cast iron -> Wrought iron (melting)
* Carbon steel -> Wrought iron (melting)
### uranium enrichment ###
Check your preferred crafting guide for more information.
### Uranium enrichment
When uranium is to be used to fuel a nuclear reactor, it is not
sufficient to merely isolate and refine uranium metal. It is necessary
@ -460,35 +398,15 @@ a post and adjacent concrete block.
industrial processes
--------------------
### alloying ###
### Alloying
In technic, alloying is a way of combining items to create other items,
distinct from standard crafting. Alloying always uses inputs of exactly
two distinct types, and produces a single output. Like cooking, which
takes a single input, it is performed using a powered machine, known
generically as an "alloy furnace". An alloy furnace always has two
input slots, and it doesn't matter which way round the two ingredients
are placed in the slots. Many alloying recipes require one or both
slots to contain a stack of more than one of the ingredient item: the
quantity required of each ingredient is part of the recipe.
In Technic, alloying is a way of combining items to create other items,
distinct from standard crafting. Alloying always uses inputs of exactly
two distinct types, and produces a single output.
As with the furnaces used for cooking, there are multiple kinds of alloy
furnace, powered in different ways. The most-used alloy furnaces are
electrically powered. There is also an alloy furnace that is powered
by directly burning fuel, just like the basic cooking furnace. Building
almost any electrical machine, including the electrically-powered alloy
furnaces, requires a machine casing component, one ingredient of which
is brass, an alloy. It is therefore necessary to use the fuel-fired
alloy furnace in the early part of the game, on the way to building
electrical machinery.
Check your preferred crafting guide for more information.
Alloying recipes are mainly concerned with metals. These recipes
combine a base metal with some other element, most often another metal,
to produce a new metal. This is discussed in the section on metal.
There are also a few alloying recipes in which the base ingredient is
non-metallic, such as the recipe for the silicon wafer.
### grinding, extracting, and compressing ###
### Grinding, extracting, and compressing
Grinding, extracting, and compressing are three distinct, but very
similar, ways of converting one item into another. They are all quite
@ -562,57 +480,17 @@ metal alloys. This can only be done using the dust form of the alloy.
It recovers both components of binary metal/metal alloys. It can't
recover the carbon from steel or cast iron.
chests
Chests
------
The technic mod replaces the basic Minetest game's single type of
chest with a range of chests that have different sizes and features.
The chest types are identified by the materials from which they are made;
the better chests are made from more exotic materials. The chest types
form a linear sequence, each being (with one exception noted below)
strictly more powerful than the preceding one. The sequence begins with
the wooden chest from the basic game, and each later chest type is built
by upgrading a chest of the preceding type. The chest types are:
See [GitHub Wiki / Chests](https://github.com/minetest-mods/technic/wiki/Chests)
1. wooden chest: 8&times;4 (32) slots
2. iron chest: 9&times;5 (45) slots
3. copper chest: 12&times;5 (60) slots
4. silver chest: 12&times;6 (72) slots
5. gold chest: 15&times;6 (90) slots
6. mithril chest: 15&times;6 (90) slots
Features of extended chests:
The iron and later chests have the ability to sort their contents,
when commanded by a button in their interaction forms. Item types are
sorted in the same order used in the unified\_inventory craft guide.
The copper and later chests also have an auto-sorting facility that can
be enabled from the interaction form. An auto-sorting chest automatically
sorts its contents whenever a player closes the chest. The contents will
then usually be in a sorted state when the chest is opened, but may not
be if pneumatic tubes have operated on the chest while it was closed,
or if two players have the chest open simultaneously.
* Larger storage space
* Labelling
* Advanced item sorting
The silver and gold chests, but not the mithril chest, have a built-in
sign-like capability. They can be given a textual label, which will
be visible when hovering over the chest. The gold chest, but again not
the mithril chest, can be further labelled with a colored patch that is
visible from a moderate distance.
The mithril chest is currently an exception to the upgrading system.
It has only as many inventory slots as the preceding (gold) type, and has
fewer of the features. It has no feature that other chests don't have:
it is strictly weaker than the gold chest. It is planned that in the
future it will acquire some unique features, but for now the only reason
to use it is aesthetic.
The size of the largest chests is dictated by the maximum size
of interaction form that the game engine can successfully display.
If in the future the engine becomes capable of handling larger forms,
by scaling them to fit the screen, the sequence of chest sizes will
likely be revised.
As with the chest of the basic Minetest game, each chest type comes
in both locked and unlocked flavors. All of the chests work with the
pneumatic tubes of the pipeworks mod.
radioactivity
-------------
@ -750,115 +628,44 @@ so the positioning of holes in each layer must still be considered.
Tricky shine paths can also be addressed by just keeping players out of
the dangerous area.
electrical power
----------------
## Electrical power
Most machines in technic are electrically powered. To operate them it is
necessary to construct an electrical power network. The network links
together power generators and power-consuming machines, connecting them
using power cables.
Electrical networks in Technic are defined by a single tier (see below)
and consist of:
There are three tiers of electrical networking: low voltage (LV),
medium voltage (MV), and high voltage (HV). Each network must operate
at a single voltage, and most electrical items are specific to a single
voltage. Generally, the machines of higher tiers are more powerful,
but consume more energy and are more expensive to build, than machines
of lower tiers. It is normal to build networks of all three tiers,
in ascending order as one progresses through the game, but it is not
strictly necessary to do this. Building HV equipment requires some parts
that can only be manufactured using electrical machines, either LV or MV,
so it is not possible to build an HV network first, but it is possible
to skip either LV or MV on the way to HV.
* 1x Switching Station (central management unit)
* Any further stations are disabled automatically
* Electricity producers (PR)
* Electricity consumers/receivers (RE)
* Accumulators/batteries (BA)
Each voltage has its own cable type, with distinctive insulation. Cable
segments connect to each other and to compatible machines automatically.
Incompatible electrical items don't connect. All non-cable electrical
items must be connected via cable: they don't connect directly to each
other. Most electrical items can connect to cables in any direction,
but there are a couple of important exceptions noted below.
### Tiers
To be useful, an electrical network must connect at least one power
generator to at least one power-consuming machine. In addition to these
items, the network must have a "switching station" in order to operate:
no energy will flow without one. Unlike most electrical items, the
switching station is not voltage-specific: the same item will manage
a network of any tier. However, also unlike most electrical items,
it is picky about the direction in which it is connected to the cable:
the cable must be directly below the switching station.
* LV: Low Voltage. Low material costs but is slower.
* MV: Medium Voltage. Higher processing speed.
* HV: High Voltage. High material costs but is the fastest.
Hovering over a network's switching station will show the aggregate energy
supply and demand, which is useful for troubleshooting. Electrical energy
is measured in "EU", and power (energy flow) in EU per second (EU/s).
Energy is shifted around a network instantaneously once per second.
Tiers can be converted from one to another using the Supply Converter node.
Its top connects to the input, the bottom to the output network. Configure
the input power by right-clicking it.
In a simple network with only generators and consumers, if total
demand exceeds total supply then no energy will flow, the machines
will do nothing, and the generators' output will be lost. To handle
this situation, it is recommended to add a battery box to the network.
A battery box will store generated energy, and when enough has been
stored to run the consumers for one second it will deliver it to the
consumers, letting them run part-time. It also stores spare energy
when supply exceeds demand, to let consumers run full-time when their
demand occasionally peaks above the supply. More battery boxes can
be added to cope with larger periods of mismatched supply and demand,
such as those resulting from using solar generators (which only produce
energy in the daytime).
### Machine upgrade slots
When there are electrical networks of multiple tiers, it can be appealing
to generate energy on one tier and transfer it to another. The most
direct way to do this is with the "supply converter", which can be
directly wired into two networks. It is another tier-independent item,
and also particular about the direction of cable connections: it must
have the cable of one network directly above, and the cable of another
network directly below. The supply converter demands 10000 EU/s from
the network above, and when this network gives it power it supplies 9000
EU/s to the network below. Thus it is only 90% efficient, unlike most of
the electrical system which is 100% efficient in moving energy around.
To transfer more than 10000 EU/s between networks, connect multiple
supply converters in parallel.
Generally, machines of MV and HV tiers have two upgrade slots.
Only specific items will have any upgrading effect. The occupied slots do
count, but not the actual stack size.
powered machines
----------------
**Type 1: Energy upgrade**
### powered machine tiers ###
Consists of any battery item. Reduces the machine's power consumption
regardless the charge of the item.
Each powered machine takes its power in some specific form, being
either fuel-fired (burning fuel directly) or electrically powered at
some specific voltage. There is a general progression through the
game from using fuel-fired machines to electrical machines, and to
higher electrical voltages. The most important kinds of machine come
in multiple variants that are powered in different ways, so the earlier
ones can be superseded. However, some machines are only available for
a specific power tier, so the tier can't be entirely superseded.
**Type 2: Tube upgrade**
### powered machine upgrades ###
Consists of a control logic unit item. Ejects processed items into pneumatic
tubes for quicker processing.
Some machines have inventory slots that are used to upgrade them in
some way. Generally, machines of MV and HV tiers have two upgrade slots,
and machines of lower tiers (fuel-fired and LV) do not. Any item can
be placed in an upgrade slot, but only specific items will have any
upgrading effect. It is possible to have multiple upgrades of the same
type, but this can't be achieved by stacking more than one upgrade item
in one slot: it is necessary to put the same kind of item in more than one
upgrade slot. The ability to upgrade machines is therefore very limited.
Two kinds of upgrade are currently possible: an energy upgrade and a
tube upgrade.
An energy upgrade consists of a battery item, the same kind of battery
that serves as a mobile energy store. The effect of an energy upgrade
is to improve in some way the machine's use of electrical energy, most
often by making it use less energy. The upgrade effect has no relation
to energy stored in the battery: the battery's charge level is irrelevant
and will not be affected.
A tube upgrade consists of a control logic unit item. The effect of a
tube upgrade is to make the machine able, or more able, to eject items
it has finished with into pneumatic tubes. The machines that can take
this kind of upgrade are in any case capable of accepting inputs from
pneumatic tubes. These upgrades are essential in using powered machines
as components in larger automated systems.
### tubes with powered machines ###
### Machines + Tubes (pipeworks)
Generally, powered machines of MV and HV tiers can work with pneumatic
tubes, and those of lower tiers cannot. (As an exception, the fuel-fired

View File

@ -2,6 +2,10 @@
This file documents the functions within the technic modpack for use in mods.
[Switch to plaintext format](https://raw.githubusercontent.com/minetest-mods/technic/master/technic/doc/api.md)
**Undocumented API may change at any time.**
## Tiers
Tier are network types. List of pre-registered tiers:
@ -37,33 +41,84 @@ Available functions:
The machine type indicates the direction of power flow.
List of pre-registered machine types:
* `technic.receiver = "RE"` e.g. grinder
* `technic.producer = "PR"` e.g. solar panel
* `technic.receiver = "RE"`: consumes energy. e.g. grinder
* `technic.producer = "PR"`: provides energy. e.g. solar panel
* `technic.producer_receiver = "PR_RE"` supply converter
* `technic.battery = "BA"` e.g. LV battery box
* `technic.battery = "BA"`: stores energy. e.g. LV battery box
Available functions:
* `technic.register_base_machine(data)`
* Registers a new node and defines the underlying machine behaviour. `data` fields:
* `tier`: string, see #Tiers
* `typename`: string, equivalent to the processing type registered
by `technic.register_recipe`. Examples: `"cooking"` `"alloy"`
* `machine_name`: string, node name
* `machine_desc`: string, node description
* `demand`: table, EU consumption values for each upgrade level.
Up to three indices. Index 1 == no upgrade. Example: `{3000, 2000, 1000}`.
* `upgrade`: (boolean), whether to add upgrade slots
* `modname`: (string), mod origin
* `tube`: (boolean), whether the machine has Pipeworks connectivity
* `can_insert`: (func), see Pipeworks documentation
* Accepts all inputs by default, if `tube = 1`
* See also: `technic.can_insert_unique_stack`
* `insert_object`: (func), see Pipeworks documentation
* Accepts all inputs by default, if `tube = 1`
* See also: `technic.insert_object_unique_stack`
* `connect_sides`: (table), see Lua API documentation. Defaults to all directions but front.
* `technic.register_machine(tier, nodename, machine_type)`
* Register an existing node as machine, bound to the network tier
* `tier`: see `register_tier`
* `tier`: string, see #Tiers
* `nodename`: string, node name
* `machine_type`: string, following options are possible:
* `"RE"`: Receiver
* `"PR"`: Producer
* `"BA"`: Battery, energy storage
* `technic.receiver = "RE"`: Consumes energy
* `technic.producer = "PR"`: Provides energy
* `technic.battery = "BA"`: Energy storage
* See also `Machine types`
Functions to use for callbacks:
Callbacks for pipeworks item transfer:
* `technic.can_insert_unique_stack(pos, node, stack, direction)`
* `technic.insert_object_unique_stack(pos, node, stack, direction)`
* Functions for the parameters `can_insert` and `insert_object` to avoid
filling multiple inventory slots with same type of item.
### Specific machines
* `technic.register_solar_array(data)`
* data is a table (TODO)
### Recipes
* `technic.register_recipe_type(typename, recipedef)`
* Registers a new recipe type used for machine processing
* `typename`: string, name of the recipe type
* Fields of `recipedef`:
* `description`: string, descriptor of the recipe type
* `input_size`: (numeric), count of input ItemStacks. default 1
* `output_size`: (numeric), count of output ItemStacks. default 1
* `technic.register_recipe(recipe)`
* Registers a individual input/output recipe. Fields of `recipe`:
* `input`: table, integer-indexed list of input ItemStacks.
* `output`: table/ItemStack, single output or list of output ItemStacks.
* `time`: numeric, process time in seconds.
* `technic.get_recipe(typename, items)`
* `typename`: string, see `technic.register_recipe_type`
* `items`: table, integer-indexed list of input ItemStacks.
* Returns: `recipe` table on success, `nil` otherwise
The following functions can be used to register recipes for
a specific machine type:
* Centrifuge
* `technic.register_separating_recipe(recipe)`
* Compressor
* `technic.register_compressor_recipe(recipe)`
* Furnaces (electric, normal)
* `minetest.register_recipe(recipe)`
* Extractor
* `technic.register_extractor_recipe(recipe)`
* Freezer
* `technic.register_freezer_recipe(recipe)`
* Grinder
* `technic.register_grinder_recipe(recipe)`
## Tools
@ -132,7 +187,7 @@ Groups:
Additional definition fields:
* `wear_represents = "string"`
* `<itemdef>.wear_represents = "string"`
* Specifies how the tool wear level is handled. Available modes:
* `"mechanical_wear"`: represents physical damage
* `"technic_RE_charge"`: represents electrical charge
@ -140,10 +195,22 @@ Additional definition fields:
* This callback is used to update the node.
Modders have to manually change the information about supply etc. in the
node metadata.
* Technic-registered machines use this callback by default.
* `<itemdef>.technic_disabled_machine_name = "string"`
* Specifies the machine's node name to use when it's not connected connected to a network
* `<itemdef>.technic_on_disable = function(pos, node) ...`
* This callback is run when the machine is no longer connected to a technic-powered network.
* `<itemdef>.technic_get_charge = function(itemstack) ...`
* Optional callback to overwrite the default charge behaviour.
* `itemstack`: ItemStack, the tool to analyse
* Return values:
* `charge`: Electrical charge of the tool
* `max_charge`: Upper charge limit
* Etc. `local charge, maxcharge = itemdef.technic_get_charge(itemstack)`
* `<itemdef>.technic_set_charge = function(itemstack, charge) ...`
* Optional callback to overwrite the default charge behaviour.
* `itemstack`: ItemStack, the tool to update
* `charge`: numeric, value between `0` and `max_charge`
## Node Metadata fields
@ -165,33 +232,30 @@ data:
multiple tiers (or networks).
## Switching Station mechanics
## Manual: Network basics
The switching station is the center of all power distribution on an electric
network.
network. This node is used to calculate the power supply of the network and
to distribute the power across nodes.
The station collects power from sources (PR), distributes it to sinks (RE),
and uses the excess/shortfall to charge and discharge batteries (BA).
The switching station is the center of all electricity distribution. It collects
power from sources (PR), distributes it to sinks (RE), and uses the
excess/shortfall to charge and discharge batteries (BA).
For now, all supply and demand values are expressed in kW.
As a thumb of rule, "EU" (energy unit) values are expressed in kW.
It works like this:
All PR,BA,RE nodes are indexed and tagged with the switching station.
The tagging is a workaround to allow more stations to be built without allowing
a cheat with duplicating power.
All the RE nodes are queried for their current EU demand. Those which are off
would require no or a small standby EU demand, while those which are on would
require more.
If the total demand is less than the available power they are all updated with
the demand number.
If any surplus exists from the PR nodes the batteries will be charged evenly
with this.
If the total demand requires draw on the batteries they will be discharged
evenly.
Network functionality:
If the total demand is more than the available power all RE nodes will be shut
down. We have a brown-out situation.
Hence for now all the power distribution logic resides in this single node.
1. All PR, BA, RE nodes are indexed and tagged with one switching station.
The tagging is a workaround to allow more stations to be built without allowing
a cheat with duplicating power.
2. All the RE nodes are queried for their current EU demand.
If the total demand is less than the available power they are all updated
with the demand number.
3. BA nodes are evenly charged from energy surplus.
4. Excess power draw will discharge batteries evenly.
5. If the total demand is more than the available power all RE nodes will be shut
down. We have a brown-out situation.
## Deprecated functions

View File

@ -1,7 +1,11 @@
-- Minetest 0.4.7 mod: technic
-- namespace: technic
-- (c) 2012-2013 by RealBadAngel <mk@realbadangel.pl>
if not minetest.get_translator then
error("[technic] Your Minetest version is no longer supported."
.. " (version < 5.0.0)")
end
local load_start = os.clock()
technic = rawget(_G, "technic") or {}
@ -16,7 +20,17 @@ technic.modpath = modpath
if rawget(_G, "intllib") then
technic.getter = intllib.Getter()
else
technic.getter = function(s,a,...)if a==nil then return s end a={a,...}return s:gsub("(@?)@(%(?)(%d+)(%)?)",function(e,o,n,c)if e==""then return a[tonumber(n)]..(o==""and c or"")else return"@"..o..n..c end end) end
-- Intllib copypasta: TODO replace with the client-side translation API
technic.getter = function(s,a,...)
if a==nil then return s end
a={a,...}
return s:gsub("(@?)@(%(?)(%d+)(%)?)", function(e,o,n,c)
if e==""then
return a[tonumber(n)]..(o==""and c or"")
end
return "@"..o..n..c
end)
end
end
local S = technic.getter

View File

@ -112,10 +112,13 @@ local function set_forcefield_formspec(meta)
else
formspec = formspec.."button[0,1;5,1;mesecon_mode_0;"..S("Controlled by Mesecon Signal").."]"
end
-- TODO: String replacement with %s will stop working with client-side translations
if meta:get_int("enabled") == 0 then
formspec = formspec.."button[0,1.75;5,1;enable;"..S("%s Disabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
formspec = formspec.."button[0,1.75;5,1;enable;"..
S("%s Disabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
else
formspec = formspec.."button[0,1.75;5,1;disable;"..S("%s Enabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
formspec = formspec.."button[0,1.75;5,1;disable;"..
S("%s Enabled"):format(S("%s Forcefield Emitter"):format("HV")).."]"
end
meta:set_string("formspec", formspec)
end

View File

@ -47,14 +47,19 @@ local function set_quarry_demand(meta)
local radius = meta:get_int("size")
local diameter = radius*2 + 1
local machine_name = S("%s Quarry"):format("HV")
if meta:get_int("enabled") == 0 or meta:get_int("purge_on") == 1 then
meta:set_string("infotext", S(meta:get_int("purge_on") == 1 and "%s purging cache" or "%s Disabled"):format(machine_name))
local do_purge = meta:get_int("purge_on") == 1
if meta:get_int("enabled") == 0 or do_purge then
local infotext = do_purge and
S("%s purging cache") or S("%s Disabled")
meta:set_string("infotext", infotext:format(machine_name))
meta:set_int("HV_EU_demand", 0)
elseif meta:get_int("dug") == diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) then
meta:set_string("infotext", S("%s Finished"):format(machine_name))
meta:set_int("HV_EU_demand", 0)
else
meta:set_string("infotext", S(meta:get_int("HV_EU_input") >= quarry_demand and "%s Active" or "%s Unpowered"):format(machine_name))
local infotext = meta:get_int("HV_EU_input") >= quarry_demand
and S("%s Active") or S("%s Unpowered")
meta:set_string("infotext", infotext:format(machine_name))
meta:set_int("HV_EU_demand", quarry_demand)
end
end

View File

@ -36,7 +36,8 @@ technic.register_inductive_machine = function(name)
end
-- Appliances:
-- has_supply: pos of supply node if the appliance has a power radiator near with sufficient power for the demand else ""
-- has_supply: pos of supply node if the appliance has a power radiator near
-- with sufficient power for the demand else ""
-- EU_demand: The power demand of the device.
-- EU_charge: Actual use. set to EU_demand if active==1
-- active: set to 1 if the device is on

View File

@ -48,20 +48,23 @@ local function forceload_on(pos, meta)
end
local function set_display(pos, meta)
local ESC = minetest.formspec_escape
meta:set_string("infotext", S(meta:get_int("enabled") ~= 0 and "%s Enabled" or "%s Disabled"):format(desc))
meta:set_string("formspec",
"size[5,3.5]"..
"item_image[0,0;1,1;technic:admin_anchor]"..
"label[1,0;"..minetest.formspec_escape(desc).."]"..
"label[0,1;"..minetest.formspec_escape(S("Owner:").." "..meta:get_string("owner")).."]"..
"label[1,0;"..ESC(desc).."]"..
"label[0,1;"..ESC(S("Owner:").." "..meta:get_string("owner")).."]"..
(meta:get_int("locked") == 0 and
"button[3,1;2,1;lock;"..minetest.formspec_escape(S("Unlocked")).."]" or
"button[3,1;2,1;unlock;"..minetest.formspec_escape(S("Locked")).."]")..
"field[0.25,2.3;1,1;radius;"..minetest.formspec_escape(S("Radius:"))..";"..meta:get_int("radius").."]"..
"button[3,1;2,1;lock;"..ESC(S("Unlocked")).."]" or
"button[3,1;2,1;unlock;"..ESC(S("Locked")).."]")..
"field[0.25,2.3;1,1;radius;"..ESC(S("Radius:"))..";"..meta:get_int("radius").."]"..
(meta:get_int("enabled") == 0 and
"button[3,2;2,1;enable;"..minetest.formspec_escape(S("Disabled")).."]" or
"button[3,2;2,1;disable;"..minetest.formspec_escape(S("Enabled")).."]")..
"label[0,3;"..minetest.formspec_escape(S("Keeping %d/%d map blocks loaded"):format(#currently_forceloaded_positions(meta), #compute_forceload_positions(pos, meta))).."]")
"button[3,2;2,1;enable;"..ESC(S("Disabled")).."]" or
"button[3,2;2,1;disable;"..ESC(S("Enabled")).."]")..
"label[0,3;"..ESC(S("Keeping %d/%d map blocks loaded"):format(
#currently_forceloaded_positions(meta), #compute_forceload_positions(pos, meta)
)).."]")
end
minetest.register_node("technic:admin_anchor", {
@ -80,7 +83,8 @@ minetest.register_node("technic:admin_anchor", {
end,
can_dig = function (pos, player)
local meta = minetest.get_meta(pos)
return meta:get_int("locked") == 0 or (player and player:is_player() and player:get_player_name() == meta:get_string("owner"))
return meta:get_int("locked") == 0 or
(player and player:is_player() and player:get_player_name() == meta:get_string("owner"))
end,
on_destruct = function (pos)
local meta = minetest.get_meta(pos)
@ -99,7 +103,11 @@ minetest.register_node("technic:admin_anchor", {
forceload_off(meta)
if fields.disable then meta:set_int("enabled", 0) end
if fields.enable then meta:set_int("enabled", 1) end
if fields.radius and string.find(fields.radius, "^[0-9]+$") and tonumber(fields.radius) < 256 then meta:set_int("radius", fields.radius) end
if fields.radius
and string.find(fields.radius, "^[0-9]+$")
and tonumber(fields.radius) < 256 then
meta:set_int("radius", fields.radius)
end
if meta:get_int("enabled") ~= 0 then
forceload_on(pos, meta)
end

View File

@ -88,22 +88,22 @@ local function pos_in_list(l, pos)
return false
end
local function table_empty(table)
for _, __ in pairs(table) do
local function table_empty(what)
for _ in pairs(what) do
return false
end
return true
end
local function add_table(table, toadd)
local function add_table(what, toadd)
local i = 1
while true do
local o = table[i]
local o = what[i]
if o == toadd then return end
if o == nil then break end
i = i + 1
end
table[i] = toadd
what[i] = toadd
end
local function move_nodes_vect(poslist, vect, must_not_move, owner)
@ -398,20 +398,6 @@ minetest.register_entity("technic:frame_entity", {
local pos = vector.round(self.object:getpos())
frames_pos[pos_to_string(pos)] = node.name
local stack = ItemStack(node.name)
local itemtable = stack:to_table()
local itemname = nil
if itemtable then
itemname = stack:to_table().name
end
local item_texture = nil
local item_type = ""
if minetest.registered_items[itemname] then
item_texture = minetest.registered_items[itemname].inventory_image
item_type = minetest.registered_items[itemname].type
end
local prop = {
is_visible = true,
textures = { node.name },

View File

@ -304,9 +304,9 @@ function technic.register_battery_box(data)
drop = "technic:"..ltier.."_battery_box0",
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local EU_upgrade, tube_upgrade = 0, 0
local EU_upgrade, _ = 0
if data.upgrade then
EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta)
EU_upgrade, _ = technic.handle_machine_upgrades(meta)
end
local max_charge = data.max_charge * (1 + EU_upgrade / 10)
local charge = meta:get_int("internal_EU_charge")
@ -345,9 +345,9 @@ function technic.register_battery_box(data)
meta = minetest.get_meta(pos)
if not pipeworks.may_configure(pos, sender) then return end
fs_helpers.on_receive_fields(pos, fields)
local EU_upgrade, tube_upgrade = 0, 0
local EU_upgrade, _ = 0
if data.upgrade then
EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta)
EU_upgrade, _ = technic.handle_machine_upgrades(meta)
end
local max_charge = data.max_charge * (1 + EU_upgrade / 10)
local charge = meta:get_int("internal_EU_charge")
@ -409,6 +409,30 @@ minetest.register_on_player_receive_fields(
end
)
local function default_get_charge(itemstack)
-- check if is chargable
local tool_name = itemstack:get_name()
if not technic.power_tools[tool_name] then
return 0, 0
end
-- Set meta data for the tool if it didn't do it itself
local item_meta = minetest.deserialize(itemstack:get_metadata()) or {}
if not item_meta.charge then
item_meta.charge = 0
end
return item_meta.charge, technic.power_tools[tool_name]
end
local function default_set_charge(itemstack, charge)
local tool_name = itemstack:get_name()
if technic.power_tools[tool_name] then
technic.set_RE_wear(itemstack, charge, technic.power_tools[tool_name])
end
local item_meta = minetest.deserialize(itemstack:get_metadata()) or {}
item_meta.charge = charge
itemstack:set_metadata(minetest.serialize(item_meta))
end
function technic.charge_tools(meta, batt_charge, charge_step)
local inv = meta:get_inventory()
if inv:is_empty("src") then
@ -416,18 +440,18 @@ function technic.charge_tools(meta, batt_charge, charge_step)
end
local src_stack = inv:get_stack("src", 1)
local tool_name = src_stack:get_name()
if not technic.power_tools[tool_name] then
-- get callbacks
local src_def = src_stack:get_definition()
local technic_get_charge = src_def.technic_get_charge or default_get_charge
local technic_set_charge = src_def.technic_set_charge or default_set_charge
-- get tool charge
local tool_charge, item_max_charge = technic_get_charge(src_stack)
if item_max_charge==0 then
return batt_charge, false
end
-- Set meta data for the tool if it didn't do it itself
local src_meta = minetest.deserialize(src_stack:get_metadata()) or {}
if not src_meta.charge then
src_meta.charge = 0
end
-- Do the charging
local item_max_charge = technic.power_tools[tool_name]
local tool_charge = src_meta.charge
if tool_charge >= item_max_charge then
return batt_charge, true
elseif batt_charge <= 0 then
@ -437,9 +461,7 @@ function technic.charge_tools(meta, batt_charge, charge_step)
charge_step = math.min(charge_step, item_max_charge - tool_charge)
tool_charge = tool_charge + charge_step
batt_charge = batt_charge - charge_step
technic.set_RE_wear(src_stack, tool_charge, item_max_charge)
src_meta.charge = tool_charge
src_stack:set_metadata(minetest.serialize(src_meta))
technic_set_charge(src_stack, tool_charge)
inv:set_stack("src", 1, src_stack)
return batt_charge, (tool_charge == item_max_charge)
end
@ -450,21 +472,20 @@ function technic.discharge_tools(meta, batt_charge, charge_step, max_charge)
if inv:is_empty("dst") then
return batt_charge, false
end
local srcstack = inv:get_stack("dst", 1)
local toolname = srcstack:get_name()
if technic.power_tools[toolname] == nil then
local src_stack = inv:get_stack("dst", 1)
-- get callbacks
local src_def = src_stack:get_definition()
local technic_get_charge = src_def.technic_get_charge or default_get_charge
local technic_set_charge = src_def.technic_set_charge or default_set_charge
-- get tool charge
local tool_charge, item_max_charge = technic_get_charge(src_stack)
if item_max_charge==0 then
return batt_charge, false
end
-- Set meta data for the tool if it didn't do it itself :-(
local src_meta = minetest.deserialize(srcstack:get_metadata())
src_meta = src_meta or {}
if not src_meta.charge then
src_meta.charge = 0
end
-- Do the discharging
local item_max_charge = technic.power_tools[toolname]
local tool_charge = src_meta.charge
if tool_charge <= 0 then
return batt_charge, true
elseif batt_charge >= max_charge then
@ -474,10 +495,8 @@ function technic.discharge_tools(meta, batt_charge, charge_step, max_charge)
charge_step = math.min(charge_step, tool_charge)
tool_charge = tool_charge - charge_step
batt_charge = batt_charge + charge_step
technic.set_RE_wear(srcstack, tool_charge, item_max_charge)
src_meta.charge = tool_charge
srcstack:set_metadata(minetest.serialize(src_meta))
inv:set_stack("dst", 1, srcstack)
technic_set_charge(src_stack, tool_charge)
inv:set_stack("dst", 1, src_stack)
return batt_charge, (tool_charge == 0)
end

View File

@ -63,24 +63,24 @@ local function clear_networks(pos)
-- This is similar to check_node_subp
technic.cables[minetest.hash_node_position(pos)] = network_id
pos.visited = 1
if technic.is_tier_cable(name, tier) then
if technic.is_tier_cable(node.name, tier) then
-- Found a cable
table.insert(network.all_nodes,pos)
elseif technic.machines[tier][node.name] then
meta:set_string(tier.."_network",minetest.pos_to_string(sw_pos))
if technic.machines[tier][node.name] == technic.producer then
table.insert(network.PR_nodes,pos)
elseif technic.machines[tier][node.name] == technic.receiver then
table.insert(network.RE_nodes,pos)
elseif technic.machines[tier][node.name] == technic.producer_receiver then
table.insert(network.PR_nodes,pos)
table.insert(network.RE_nodes,pos)
elseif technic.machines[tier][node.name] == "SPECIAL" and
(pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) and
from_below then
table.insert(network.SP_nodes,pos)
elseif technic.machines[tier][node.name] == technic.battery then
table.insert(network.BA_nodes,pos)
-- Found a machine
local eu_type = technic.machines[tier][node.name]
meta:set_string(tier.."_network", minetest.pos_to_string(sw_pos))
if eu_type == technic.producer then
table.insert(network.PR_nodes, pos)
elseif eu_type == technic.receiver then
table.insert(network.RE_nodes, pos)
elseif eu_type == technic.producer_receiver then
table.insert(network.PR_nodes, pos)
table.insert(network.RE_nodes, pos)
elseif eu_type == technic.battery then
table.insert(network.BA_nodes, pos)
end
-- Note: SPECIAL (i.e. switching station) is not traversed!
end
elseif dead_end and not placed then
-- Dead end removed, remove it from the network

View File

@ -45,14 +45,12 @@ minetest.register_node("technic:switching_station",{
meta:set_string("active", 1)
meta:set_string("channel", "switching_station"..minetest.pos_to_string(pos))
meta:set_string("formspec", "field[channel;Channel;${channel}]")
local poshash = minetest.hash_node_position(pos)
technic.redundant_warn.poshash = nil
end,
after_dig_node = function(pos)
minetest.forceload_free_block(pos)
pos.y = pos.y - 1
minetest.forceload_free_block(pos)
local poshash = minetest.hash_node_position(pos)
technic.redundant_warn.poshash = nil
end,
on_receive_fields = function(pos, formname, fields, sender)
@ -100,8 +98,10 @@ local function flatten(map)
end
-- Add a wire node to the LV/MV/HV network
-- Returns: indicator whether the cable is new in the network
local hash_node_position = minetest.hash_node_position
local function add_network_node(nodes, pos, network_id)
local node_id = minetest.hash_node_position(pos)
local node_id = hash_node_position(pos)
technic.cables[node_id] = network_id
if nodes[node_id] then
return false
@ -117,39 +117,45 @@ local function add_cable_node(nodes, pos, network_id, queue)
end
-- Generic function to add found connected nodes to the right classification array
local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos, from_below, network_id, queue)
local check_node_subp = function(network, pos, machines, sw_pos, from_below, network_id, queue)
technic.get_or_load_node(pos)
local name = minetest.get_node(pos).name
if technic.is_tier_cable(name, tier) then
add_cable_node(all_nodes, pos,network_id, queue)
elseif machines[name] then
--dprint(name.." is a "..machines[name])
local meta = minetest.get_meta(pos)
meta:set_string(tier.."_network",minetest.pos_to_string(sw_pos))
if machines[name] == technic.producer then
add_network_node(PR_nodes, pos, network_id)
elseif machines[name] == technic.receiver then
add_network_node(RE_nodes, pos, network_id)
elseif machines[name] == technic.producer_receiver then
add_network_node(PR_nodes, pos, network_id)
add_network_node(RE_nodes, pos, network_id)
elseif machines[name] == "SPECIAL" and
(pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) and
from_below then
-- Another switching station -> disable it
add_network_node(SP_nodes, pos, network_id)
meta:set_int("active", 0)
elseif machines[name] == technic.battery then
add_network_node(BA_nodes, pos, network_id)
end
meta:set_int(tier.."_EU_timeout", 2) -- Touch node
if technic.is_tier_cable(name, network.tier) then
add_cable_node(network.all_nodes, pos, network_id, queue)
return
end
local eu_type = machines[name]
if not eu_type then
return
end
--dprint(name.." is a "..machines[name])
local meta = minetest.get_meta(pos)
meta:set_string(network.tier.."_network", minetest.pos_to_string(sw_pos))
if eu_type == technic.producer then
add_network_node(network.PR_nodes, pos, network_id)
elseif eu_type == technic.receiver then
add_network_node(network.RE_nodes, pos, network_id)
elseif eu_type == technic.producer_receiver then
add_network_node(network.PR_nodes, pos, network_id)
add_network_node(network.RE_nodes, pos, network_id)
elseif eu_type == technic.battery then
add_network_node(network.BA_nodes, pos, network_id)
elseif eu_type == "SPECIAL" and from_below and
not vector.equals(pos, sw_pos) then
-- Another switching station -> disable it
add_network_node(network.SP_nodes, pos, network_id)
meta:set_int("active", 0)
end
meta:set_int(network.tier.."_EU_timeout", 2) -- Touch node
end
-- Traverse a network given a list of machines and a cable type name
local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos, network_id, queue)
local traverse_network = function(network, pos, machines, sw_pos, network_id, queue)
local positions = {
{x=pos.x+1, y=pos.y, z=pos.z},
{x=pos.x-1, y=pos.y, z=pos.z},
@ -158,7 +164,7 @@ local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_no
{x=pos.x, y=pos.y, z=pos.z+1},
{x=pos.x, y=pos.y, z=pos.z-1}}
for i, cur_pos in pairs(positions) do
check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, cur_pos, machines, tier, sw_pos, i == 3, network_id, queue)
check_node_subp(network, cur_pos, machines, sw_pos, i == 3, network_id, queue)
end
end
@ -169,43 +175,51 @@ local touch_nodes = function(list, tier)
end
end
local get_network = function(sw_pos, pos1, tier)
local network_id = minetest.hash_node_position(pos1)
local get_network = function(sw_pos, cable_pos, tier)
local network_id = minetest.hash_node_position(cable_pos)
local cached = technic.networks[network_id]
if cached and cached.tier == tier then
-- Re-use cached system data
touch_nodes(cached.PR_nodes, tier)
touch_nodes(cached.BA_nodes, tier)
touch_nodes(cached.RE_nodes, tier)
for _, pos in ipairs(cached.SP_nodes) do
-- Disable all other switching stations (again)
local meta = minetest.get_meta(pos)
meta:set_int("active", 0)
meta:set_string("active_pos", minetest.serialize(sw_pos))
end
return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes
end
local PR_nodes = {}
local BA_nodes = {}
local RE_nodes = {}
local SP_nodes = {}
local all_nodes = {}
local machines = technic.machines[tier]
local network = {
tier = tier,
PR_nodes = {},
BA_nodes = {},
RE_nodes = {},
SP_nodes = {},
all_nodes = {}
}
-- Traverse the network step by step starting from the node underneath the switching station
local queue = {}
add_cable_node(all_nodes, pos1, network_id, queue)
add_cable_node(network.all_nodes, cable_pos, network_id, queue)
while next(queue) do
local to_visit = {}
for _, pos in ipairs(queue) do
traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes,
pos, technic.machines[tier], tier, sw_pos, network_id, to_visit)
traverse_network(network, pos, machines, sw_pos, network_id, to_visit)
end
queue = to_visit
end
PR_nodes = flatten(PR_nodes)
BA_nodes = flatten(BA_nodes)
RE_nodes = flatten(RE_nodes)
SP_nodes = flatten(SP_nodes)
all_nodes = flatten(all_nodes)
technic.networks[network_id] = {tier = tier, all_nodes = all_nodes, SP_nodes = SP_nodes,
PR_nodes = PR_nodes, RE_nodes = RE_nodes, BA_nodes = BA_nodes}
return PR_nodes, BA_nodes, RE_nodes
-- Convert { [hash] = pos, ... } to { pos, ... }
network.PR_nodes = flatten(network.PR_nodes)
network.BA_nodes = flatten(network.BA_nodes)
network.RE_nodes = flatten(network.RE_nodes)
network.SP_nodes = flatten(network.SP_nodes)
network.all_nodes = flatten(network.all_nodes)
technic.networks[network_id] = network
return network.PR_nodes, network.BA_nodes, network.RE_nodes
end
-----------------------------------------------
@ -215,19 +229,17 @@ end
technic.powerctrl_state = true
minetest.register_chatcommand("powerctrl", {
params = "state",
params = "[on/off]",
description = "Enables or disables technic's switching station ABM",
privs = { basic_privs = true },
func = function(name, state)
if state == "on" then
technic.powerctrl_state = true
else
technic.powerctrl_state = false
end
technic.powerctrl_state = (state:trim():lower() == "on")
minetest.chat_send_player(name, "Technic switching station: " ..
(technic.powerctrl_state and "on" or "off"))
end
})
-- Run all the nodes
-- Run `technic_run` on all nodes in the power grid
local function run_nodes(list, run_stage)
for _, pos in ipairs(list) do
technic.get_or_load_node(pos)
@ -243,28 +255,23 @@ end
minetest.register_abm({
nodenames = {"technic:switching_station"},
label = "Switching Station", -- allows the mtt profiler to profile this abm individually
label = "Switching Station", -- name for the Minetest mod profiler
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
if not technic.powerctrl_state then return end
local meta = minetest.get_meta(pos)
local meta = minetest.get_meta(pos)
local meta1
local pos1 = {}
local tier = ""
local PR_nodes
local BA_nodes
local RE_nodes
local PR_nodes, BA_nodes, RE_nodes
local machine_name = S("Switching Station")
-- Which kind of network are we on:
pos1 = {x=pos.x, y=pos.y-1, z=pos.z}
local cable_pos = {x=pos.x, y=pos.y-1, z=pos.z}
--Disable if necessary
if meta:get_int("active") ~= 1 then
minetest.forceload_free_block(pos)
minetest.forceload_free_block(pos1)
minetest.forceload_free_block(cable_pos)
meta:set_string("infotext",S("%s Already Present"):format(machine_name))
local poshash = minetest.hash_node_position(pos)
@ -276,18 +283,18 @@ minetest.register_abm({
return
end
local name = minetest.get_node(pos1).name
local name = minetest.get_node(cable_pos).name
local tier = technic.get_cable_tier(name)
if tier then
-- Forceload switching station
minetest.forceload_block(pos)
minetest.forceload_block(pos1)
PR_nodes, BA_nodes, RE_nodes = get_network(pos, pos1, tier)
minetest.forceload_block(cable_pos)
PR_nodes, BA_nodes, RE_nodes = get_network(pos, cable_pos, tier)
else
--dprint("Not connected to a network")
meta:set_string("infotext", S("%s Has No Network"):format(machine_name))
minetest.forceload_free_block(pos)
minetest.forceload_free_block(pos1)
minetest.forceload_free_block(cable_pos)
return
end
@ -340,20 +347,14 @@ minetest.register_abm({
end
--dprint("Total RE demand:"..RE_eu_demand)
-- Get all the power from the BA nodes
local BA_eu_supply = 0
-- Batteries
local BA_eu_supply, BA_eu_demand = 0, 0
for _, pos1 in pairs(BA_nodes) do
meta1 = minetest.get_meta(pos1)
BA_eu_supply = BA_eu_supply + meta1:get_int(eu_supply_str)
end
--dprint("Total BA supply:"..BA_eu_supply)
-- Get all the demand from the BA nodes
local BA_eu_demand = 0
for _, pos1 in pairs(BA_nodes) do
meta1 = minetest.get_meta(pos1)
BA_eu_demand = BA_eu_demand + meta1:get_int(eu_demand_str)
end
--dprint("Total BA supply:"..BA_eu_supply)
--dprint("Total BA demand:"..BA_eu_demand)
meta:set_string("infotext", S("@1. Supply: @2 Demand: @3",
@ -374,8 +375,8 @@ minetest.register_abm({
end
-- Data that will be used by the power monitor
meta:set_int("supply",PR_eu_supply)
meta:set_int("demand",RE_eu_demand)
meta:set_int("supply", PR_eu_supply)
meta:set_int("demand", RE_eu_demand)
-- If the PR supply is enough for the RE demand supply them all
if PR_eu_supply >= RE_eu_demand then

View File

@ -428,7 +428,7 @@ for _, state in pairs({"flowing", "source"}) do
liquidtype = state,
liquid_alternative_flowing = "technic:corium_flowing",
liquid_alternative_source = "technic:corium_source",
liquid_viscosity = LAVA_VISC,
liquid_viscosity = 7, -- like lava
liquid_renewable = false,
damage_per_second = 6,
post_effect_color = {a=192, r=80, g=160, b=80},

View File

@ -44,7 +44,10 @@ end
-- Wear down a tool depending on the remaining charge.
function technic.set_RE_wear(itemstack, item_load, max_load)
if (minetest.registered_items[itemstack:get_name()].wear_represents or "mechanical_wear") ~= "technic_RE_charge" then return itemstack end
local def = minetest.registered_items[itemstack:get_name()]
if (def.wear_represents or "mechanical_wear") ~= "technic_RE_charge" then
return itemstack
end
local temp
if item_load == 0 then
temp = 0

View File

@ -36,7 +36,10 @@ function technic.register_can(d)
local charge = get_can_level(itemstack)
if charge == data.can_capacity then return end
if minetest.is_protected(pointed_thing.under, user:get_player_name()) then
minetest.log("action", user:get_player_name().." tried to take "..node.name.." at protected position "..minetest.pos_to_string(pointed_thing.under).." with a "..data.can_name)
minetest.log("action", user:get_player_name()..
" tried to take "..node.name..
" at protected position "..minetest.pos_to_string(pointed_thing.under)..
" with a "..data.can_name)
return
end
minetest.remove_node(pointed_thing.under)
@ -63,7 +66,10 @@ function technic.register_can(d)
local charge = get_can_level(itemstack)
if charge == 0 then return end
if minetest.is_protected(pos, user:get_player_name()) then
minetest.log("action", user:get_player_name().." tried to place "..data.liquid_source_name.." at protected position "..minetest.pos_to_string(pos).." with a "..data.can_name)
minetest.log("action", user:get_player_name()..
" tried to place "..data.liquid_source_name..
" at protected position "..minetest.pos_to_string(pos)..
" with a "..data.can_name)
return
end
minetest.set_node(pos, {name=data.liquid_source_name})

View File

@ -46,20 +46,27 @@ local mining_drill_mode_text = {
{S("3x3 nodes.")},
}
local function drill_dig_it0 (pos,player)
local function drill_dig_it0(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
minetest.record_protection_violation(pos, player:get_player_name())
return
end
local node = minetest.get_node(pos)
if node.name == "air" or node.name == "ignore" then return end
if node.name == "default:lava_source" then return end
if node.name == "default:lava_flowing" then return end
if node.name == "default:water_source" then minetest.remove_node(pos) return end
if node.name == "default:water_flowing" then minetest.remove_node(pos) return end
local def = minetest.registered_nodes[node.name]
if not def then return end
def.on_dig(pos, node, player)
local ndef = minetest.registered_nodes[node.name]
if not ndef or ndef.drawtype == "airlike" then
-- Covers "air", "ignore", unknown nodes and more.
return
end
local groups = ndef and ndef.groups or {}
if groups.lava then
return
end
if groups.water then
minetest.remove_node(pos)
return
end
ndef.on_dig(pos, node, player)
end
local function drill_dig_it1 (player)
@ -239,97 +246,61 @@ local function pos_is_pointable(pos)
return nodedef and nodedef.pointable
end
local function mining_drill_mk2_setmode(user,itemstack)
local player_name=user:get_player_name()
local item=itemstack:to_table()
local mode = nil
local meta=minetest.deserialize(item["metadata"])
if meta==nil then
meta={}
mode=0
local function mining_drill_mkX_setmode(user, itemstack, drill_type, max_modes)
local player_name = user:get_player_name()
local meta = minetest.deserialize(itemstack:get_metadata()) or {}
if not meta["mode"] then
minetest.chat_send_player(player_name,
S("Use while sneaking to change Mining Drill Mk%d modes."):format(drill_type))
end
if meta["mode"]==nil then
minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk%d modes."):format(2))
meta["mode"]=0
mode=0
end
mode=(meta["mode"])
mode=mode+1
if mode>=5 then mode=1 end
minetest.chat_send_player(player_name, S("Mining Drill Mk%d Mode %d"):format(2, mode)..": "..mining_drill_mode_text[mode][1])
itemstack:set_name("technic:mining_drill_mk2_"..mode);
meta["mode"]=mode
local mode = (meta["mode"] or 0) + 1
if mode > max_modes then mode = 1 end
minetest.chat_send_player(player_name,
S("Mining Drill Mk%d Mode %d"):format(2, mode)..
": "..mining_drill_mode_text[mode][1])
itemstack:set_name(("technic:mining_drill_mk%d_%s"):format(drill_type, mode))
meta["mode"] = mode
itemstack:set_metadata(minetest.serialize(meta))
return itemstack
end
local function mining_drill_mk3_setmode(user,itemstack)
local player_name=user:get_player_name()
local item=itemstack:to_table()
local meta=minetest.deserialize(item["metadata"])
if meta==nil then
meta={}
mode=0
end
if meta["mode"]==nil then
minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk%d modes."):format(3))
meta["mode"]=0
mode=0
end
mode=(meta["mode"])
mode=mode+1
if mode>=6 then mode=1 end
minetest.chat_send_player(player_name, S("Mining Drill Mk%d Mode %d"):format(3, mode)..": "..mining_drill_mode_text[mode][1])
itemstack:set_name("technic:mining_drill_mk3_"..mode);
meta["mode"]=mode
itemstack:set_metadata(minetest.serialize(meta))
return itemstack
end
local function mining_drill_mk2_handler(itemstack, user, pointed_thing)
local function mining_drill_mkX_handler(itemstack, user, pointed_thing, drill_type, max_modes)
local keys = user:get_player_control()
local meta = minetest.deserialize(itemstack:get_metadata())
if not meta or not meta.mode or keys.sneak then
return mining_drill_mk2_setmode(user, itemstack)
end
if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) or not meta.charge then
return
end
local charge_to_take = cost_to_use(2, meta.mode)
if meta.charge >= charge_to_take then
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
drill_dig_it(pos, user, meta.mode)
if not technic.creative_mode then
meta.charge = meta.charge - charge_to_take
itemstack:set_metadata(minetest.serialize(meta))
technic.set_RE_wear(itemstack, meta.charge, max_charge[2])
local meta = minetest.deserialize(itemstack:get_metadata()) or {}
-- Mode switching (if possible)
if max_modes > 1 then
if not meta.mode or keys.sneak then
return mining_drill_mkX_setmode(user, itemstack, drill_type, max_modes)
end
end
if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) then
return
end
if not meta.charge then
return
end
-- Check whether the tool has enough charge
local charge_to_take = cost_to_use(drill_type, meta.mode or 1)
if meta.charge < charge_to_take then
return
end
-- Do the actual shoorting action
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
drill_dig_it(pos, user, meta.mode or 1)
if not technic.creative_mode then
meta.charge = meta.charge - charge_to_take
itemstack:set_metadata(minetest.serialize(meta))
technic.set_RE_wear(itemstack, meta.charge, max_charge[drill_type])
end
return itemstack
end
local function mining_drill_mk3_handler(itemstack, user, pointed_thing)
local keys = user:get_player_control()
local meta = minetest.deserialize(itemstack:get_metadata())
if not meta or not meta.mode or keys.sneak then
return mining_drill_mk3_setmode(user, itemstack)
end
if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) or not meta.charge then
return
end
local charge_to_take = cost_to_use(3, meta.mode)
if meta.charge >= charge_to_take then
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
drill_dig_it(pos, user, meta.mode)
if not technic.creative_mode then
meta.charge = meta.charge - charge_to_take
itemstack:set_metadata(minetest.serialize(meta))
technic.set_RE_wear(itemstack, meta.charge, max_charge[3])
end
end
return itemstack
end
-- Simple mining drill registration
technic.register_power_tool("technic:mining_drill", max_charge[1])
@ -340,34 +311,20 @@ minetest.register_tool("technic:mining_drill", {
wear_represents = "technic_RE_charge",
on_refill = technic.refill_RE_charge,
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) then
return itemstack
end
local meta = minetest.deserialize(itemstack:get_metadata())
if not meta or not meta.charge then
return
end
local charge_to_take = cost_to_use(1, 1)
if meta.charge >= charge_to_take then
local pos = minetest.get_pointed_thing_position(pointed_thing, false)
drill_dig_it(pos, user, 1)
if not technic.creative_mode then
meta.charge = meta.charge - charge_to_take
itemstack:set_metadata(minetest.serialize(meta))
technic.set_RE_wear(itemstack, meta.charge, max_charge[1])
end
end
mining_drill_mkX_handler(itemstack, user, pointed_thing, 1, 1)
return itemstack
end,
})
-- Mk2 registration
minetest.register_tool("technic:mining_drill_mk2", {
description = S("Mining Drill Mk%d"):format(2),
inventory_image = "technic_mining_drill_mk2.png",
wear_represents = "technic_RE_charge",
on_refill = technic.refill_RE_charge,
on_use = function(itemstack, user, pointed_thing)
mining_drill_mk2_handler(itemstack, user, pointed_thing)
mining_drill_mkX_handler(itemstack, user, pointed_thing, 2, 4)
return itemstack
end,
})
@ -384,20 +341,22 @@ for i = 1, 4 do
on_refill = technic.refill_RE_charge,
groups = {not_in_creative_inventory=1},
on_use = function(itemstack, user, pointed_thing)
mining_drill_mk2_handler(itemstack, user, pointed_thing)
mining_drill_mkX_handler(itemstack, user, pointed_thing, 2, 4)
return itemstack
end,
})
end
-- Mk3 registration
minetest.register_tool("technic:mining_drill_mk3", {
description = S("Mining Drill Mk%d"):format(3),
inventory_image = "technic_mining_drill_mk3.png",
wear_represents = "technic_RE_charge",
on_refill = technic.refill_RE_charge,
on_use = function(itemstack, user, pointed_thing)
mining_drill_mk3_handler(itemstack,user,pointed_thing)
return itemstack
mining_drill_mkX_handler(itemstack, user, pointed_thing, 3, 5)
return itemstack
end,
})
@ -413,8 +372,8 @@ for i=1,5,1 do
on_refill = technic.refill_RE_charge,
groups = {not_in_creative_inventory=1},
on_use = function(itemstack, user, pointed_thing)
mining_drill_mk3_handler(itemstack,user,pointed_thing)
return itemstack
mining_drill_mkX_handler(itemstack, user, pointed_thing, 3, 5)
return itemstack
end,
})
end

View File

@ -33,6 +33,7 @@ minetest.register_tool("technic:prospector", {
toolstack:set_metadata(minetest.serialize(toolmeta))
technic.set_RE_wear(toolstack, toolmeta.charge, technic.power_tools[toolstack:get_name()])
end
-- What in the heaven's name is this evil sorcery ?
local start_pos = pointed_thing.under
local forward = minetest.facedir_to_dir(minetest.dir_to_facedir(user:get_look_dir(), true))
local right = forward.x ~= 0 and { x=0, y=1, z=0 } or (forward.y ~= 0 and { x=0, y=0, z=1 } or { x=1, y=0, z=0 })
@ -42,13 +43,36 @@ minetest.register_tool("technic:prospector", {
for f = 0, toolmeta.look_depth-1 do
for r = 0, look_diameter-1 do
for u = 0, look_diameter-1 do
if minetest.get_node(vector.add(vector.add(vector.add(base_pos, vector.multiply(forward, f)), vector.multiply(right, r)), vector.multiply(up, u))).name == toolmeta.target then found = true end
if minetest.get_node(
vector.add(
vector.add(
vector.add(base_pos,
vector.multiply(forward, f)),
vector.multiply(right, r)),
vector.multiply(up, u))
).name == toolmeta.target then
found = true
break
end
end
if found then break end
end
if found then break end
end
if math.random() < 0.02 then found = not found end
minetest.chat_send_player(user:get_player_name(), minetest.registered_nodes[toolmeta.target].description.." is "..(found and "present" or "absent").." in "..look_diameter.."x"..look_diameter.."x"..toolmeta.look_depth.." region")
minetest.sound_play("technic_prospector_"..(found and "hit" or "miss"), { pos = vector.add(user:get_pos(), { x = 0, y = 1, z = 0 }), gain = 1.0, max_hear_distance = 10 })
if math.random() < 0.02 then
found = not found
end
local ndef = minetest.registered_nodes[toolmeta.target]
minetest.chat_send_player(user:get_player_name(),
ndef.description.." is "..(found and "present" or "absent")..
" in "..look_diameter.."x"..look_diameter.."x"..toolmeta.look_depth.." region")
minetest.sound_play("technic_prospector_"..(found and "hit" or "miss"), {
pos = vector.add(user:get_pos(), { x = 0, y = 1, z = 0 }),
gain = 1.0,
max_hear_distance = 10
})
return toolstack
end,
on_place = function(toolstack, user, pointed_thing)

View File

@ -1,7 +0,0 @@
default
basic_materials
moreblocks?
moreores?
pipeworks?
intllib?
tubelib?

View File

@ -1,7 +1,7 @@
local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end
local pipeworks = rawget(_G, "pipeworks")
local fs_helpers = rawget(_G, "fs_helpers")
local fs_helpers
local tubelib_exists = minetest.global_exists("tubelib")
local allow_label = ""
@ -97,7 +97,8 @@ local function set_formspec(pos, data, page)
if data.autosort then
local status = meta:get_int("autosort")
formspec = formspec.."button["..(data.hileft+2)..","..(data.height+1.1)..";3,0.8;autosort_to_"..(1-status)..";"..S("Auto-sort is %s"):format(status == 1 and S("On") or S("Off")).."]"
formspec = formspec.."button["..(data.hileft+2)..","..(data.height+1.1)..";3,0.8;autosort_to_"..(1-status)..";"..
S("Auto-sort is %s"):format(status == 1 and S("On") or S("Off")).."]"
end
if data.infotext then
local formspec_infotext = minetest.formspec_escape(meta:get_string("infotext"))
@ -221,7 +222,6 @@ function technic.chests:definition(name, data)
data.lotop = data.height + 2
data.ovheight = data.lotop + 4
local locked_after_place = nil
local front = {"technic_"..lname.."_chest_front.png"}
data.base_formspec = "size["..data.ovwidth..","..data.ovheight.."]"..
"label[0,0;"..S("%s Chest"):format(name).."]"..
@ -239,6 +239,7 @@ function technic.chests:definition(name, data)
data.base_formspec = data.base_formspec..get_color_buttons(data.coleft, data.lotop)
end
local locked_after_place
if data.locked then
locked_after_place = function(pos, placer)
local meta = minetest.get_meta(pos)

View File

@ -163,12 +163,12 @@ local function form_handler(pos, formname, fields, sender)
local inv = meta:get_inventory()
local inputstack = inv:get_stack("src", 1)
local inputname = inputstack:get_name()
local multiplier = 0
local size = meta:get_int("size")
if size < 1 then size = 1 end
for k, _ in pairs(fields) do
-- Set a multipier for the half/full size capable blocks
local multiplier
if twosize_products[k] ~= nil then
multiplier = size * twosize_products[k]
else

View File

@ -2,6 +2,7 @@
-- Again code is adapted from the NonCubic Blocks MOD v1.4 by yves_de_beck
local S = technic_cnc.getter
local ALPHA_CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or true
-- REGISTER NONCUBIC FORMS, CREATE MODELS AND RECIPES:
------------------------------------------------------
@ -298,6 +299,7 @@ function technic_cnc.register_program(recipeitem, suffix, model, groups, images,
tiles = images,
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = ALPHA_CLIP,
walkable = true,
groups = groups,
selection_box = sbox,
@ -325,11 +327,10 @@ function technic_cnc.register_all(recipeitem, groups, images, description)
end
end
-- REGISTER NEW TECHNIC_CNC_API's PART 2: technic_cnc..register_element_end(subname, recipeitem, groups, images, desc_element_xyz)
-----------------------------------------------------------------------------------------------------------------------
function technic_cnc.register_slope_edge_etc(recipeitem, groups, images, desc_slope, desc_slope_lying, desc_slope_upsdown, desc_slope_edge, desc_slope_inner_edge, desc_slope_upsdwn_edge, desc_slope_upsdwn_inner_edge, desc_pyramid, desc_spike, desc_onecurvededge, desc_twocurvededge, desc_cylinder, desc_cylinder_horizontal, desc_spheroid, desc_element_straight, desc_element_edge, desc_element_t, desc_element_cross, desc_element_end)
-- TODO: Remove this evil sorcery
technic_cnc.register_slope(recipeitem, groups, images, desc_slope)
technic_cnc.register_slope_lying(recipeitem, groups, images, desc_slope_lying)
technic_cnc.register_slope_upsdown(recipeitem, groups, images, desc_slope_upsdown)
@ -354,10 +355,12 @@ end
-- REGISTER STICKS: noncubic.register_xyz(recipeitem, groups, images, desc_element_xyz)
------------------------------------------------------------------------------------------------------------
function technic_cnc.register_stick_etc(recipeitem, groups, images, desc_stick)
-- TODO: Remove this evil sorcery
technic_cnc.register_stick(recipeitem, groups, images, desc_stick)
end
function technic_cnc.register_elements(recipeitem, groups, images, desc_element_straight_double, desc_element_edge_double, desc_element_t_double, desc_element_cross_double, desc_element_end_double)
-- TODO: Remove this evil sorcery
technic_cnc.register_element_straight_double(recipeitem, groups, images, desc_element_straight_double)
technic_cnc.register_element_edge_double(recipeitem, groups, images, desc_element_edge_double)
technic_cnc.register_element_t_double(recipeitem, groups, images, desc_element_t_double)

View File

@ -1,3 +0,0 @@
default
basic_materials
technic?

View File

@ -10,7 +10,17 @@ technic_cnc.use_technic = technic_cnc.technic_modpath
if rawget(_G, "intllib") then
technic_cnc.getter = intllib.Getter()
else
technic_cnc.getter = function(s,a,...)if a==nil then return s end a={a,...}return s:gsub("(@?)@(%(?)(%d+)(%)?)",function(e,o,n,c)if e==""then return a[tonumber(n)]..(o==""and c or"")else return"@"..o..n..c end end) end
-- Intllib copypasta: TODO replace with the client-side translation API
technic_cnc.getter = function(s,a,...)
if a==nil then return s end
a={a,...}
return s:gsub("(@?)@(%(?)(%d+)(%)?)", function(e,o,n,c)
if e==""then
return a[tonumber(n)]..(o==""and c or"")
end
return "@"..o..n..c
end)
end
end
dofile(modpath.."/cnc.lua")

View File

@ -1,9 +0,0 @@
default
basic_materials
intllib?
mg?
doors?
farming?
glooptest?
mesecons_doors?
vessels?

View File

@ -1,6 +0,0 @@
default
technic?
technic_chests?
technic_worldgen?
intllib?

View File

@ -32,34 +32,37 @@ local function get_pickup_name(name)
end
local function restore(pos, placer, itemstack)
local name = itemstack:get_name()
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local data = itemstack:get_meta():get_string("data")
data = (data ~= "" and data) or itemstack:get_metadata()
data = minetest.deserialize(data)
if not data then
minetest.remove_node(pos)
minetest.log("error", placer:get_player_name().." wanted to place "..
name.." at "..minetest.pos_to_string(pos)..
itemstack:get_name().." at "..minetest.pos_to_string(pos)..
", but it had no data.")
minetest.log("verbose", "itemstack: "..itemstack:to_string())
return true
end
local node = minetest.get_node(pos)
minetest.set_node(pos, {name = data.name, param2 = node.param2})
for name, value in pairs(data.metas) do
local meta_type = get_meta_type(data.name, name)
-- Apply stored metadata to the current node
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
for key, value in pairs(data.metas) do
local meta_type = get_meta_type(data.name, key)
if meta_type == wrench.META_TYPE_INT then
meta:set_int(name, value)
meta:set_int(key, value)
elseif meta_type == wrench.META_TYPE_FLOAT then
meta:set_float(name, value)
meta:set_float(key, value)
elseif meta_type == wrench.META_TYPE_STRING then
meta:set_string(name, value)
meta:set_string(key, value)
end
end
local lists = data.lists
for listname, list in pairs(lists) do
for listname, list in pairs(data.lists) do
inv:set_list(listname, list)
end
itemstack:take_item()
@ -108,15 +111,15 @@ minetest.register_tool("wrench:wrench", {
minetest.record_protection_violation(pos, player_name)
return
end
local name = minetest.get_node(pos).name
local def = wrench.registered_nodes[name]
local node_name = minetest.get_node(pos).name
local def = wrench.registered_nodes[node_name]
if not def then
return
end
local stack = ItemStack(get_pickup_name(name))
local stack_pickup = ItemStack(get_pickup_name(node_name))
local player_inv = placer:get_inventory()
if not player_inv:room_for_item("main", stack) then
if not player_inv:room_for_item("main", stack_pickup) then
return
end
local meta = minetest.get_meta(pos)
@ -131,10 +134,12 @@ minetest.register_tool("wrench:wrench", {
end
end
-- Do the actual pickup:
local metadata = {}
metadata.name = name
metadata.name = node_name
metadata.version = LATEST_SERIALIZATION_VERSION
-- Serialize inventory lists + items
local inv = meta:get_inventory()
local lists = {}
for _, listname in pairs(def.lists or {}) do
@ -146,22 +151,23 @@ minetest.register_tool("wrench:wrench", {
end
metadata.lists = lists
local item_meta = stack:get_meta()
-- Serialize node metadata fields
local item_meta = stack_pickup:get_meta()
metadata.metas = {}
for name, meta_type in pairs(def.metas or {}) do
for key, meta_type in pairs(def.metas or {}) do
if meta_type == wrench.META_TYPE_INT then
metadata.metas[name] = meta:get_int(name)
metadata.metas[key] = meta:get_int(key)
elseif meta_type == wrench.META_TYPE_FLOAT then
metadata.metas[name] = meta:get_float(name)
metadata.metas[key] = meta:get_float(key)
elseif meta_type == wrench.META_TYPE_STRING then
metadata.metas[name] = meta:get_string(name)
metadata.metas[key] = meta:get_string(key)
end
end
item_meta:set_string("data", minetest.serialize(metadata))
minetest.remove_node(pos)
itemstack:add_wear(65535 / 20)
player_inv:add_item("main", stack)
player_inv:add_item("main", stack_pickup)
return itemstack
end,
})