built on 11/12/2020 18:07:29

This commit is contained in:
Joachim Stolberg 2020-12-11 18:07:29 +01:00
parent 98d9e1b7cf
commit 67ba0cde5b
87 changed files with 3820 additions and 1580 deletions

View File

@ -92,24 +92,24 @@ minetest.register_on_respawnplayer(function(player)
end end
end) end)
local function control_player(player) local function control_player(player_name)
local player_name = player:get_player_name()
if Currently_left_the_game[player_name] then if Currently_left_the_game[player_name] then
Currently_left_the_game[player_name] = nil Currently_left_the_game[player_name] = nil
return return
end end
local player = minetest.get_player_by_name(player_name)
if player then if player then
local pos = player:get_pos() local pos = player:get_pos()
if pos then if pos then
--pos.y = math.floor(pos.y) --pos.y = math.floor(pos.y)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
if string.sub(node.name,1,13) == "autobahn:node" then if string.sub(node.name,1,13) == "autobahn:node" then
minetest.after(0.5, control_player, player) minetest.after(0.5, control_player, player_name)
else else
pos.y = pos.y - 1 pos.y = pos.y - 1
node = minetest.get_node(pos) node = minetest.get_node(pos)
if string.sub(node.name,1,13) == "autobahn:node" then if string.sub(node.name,1,13) == "autobahn:node" then
minetest.after(0.5, control_player, player) minetest.after(0.5, control_player, player_name)
else else
reset_player_privs(player) reset_player_privs(player)
end end
@ -125,11 +125,13 @@ local NodeTbl1 = {
["autobahn:node3"] = true, ["autobahn:node3"] = true,
["autobahn:node4"] = true, ["autobahn:node4"] = true,
["autobahn:node5"] = true, ["autobahn:node5"] = true,
["autobahn:node6"] = true,
["autobahn:node12"] = true, ["autobahn:node12"] = true,
["autobahn:node22"] = true, ["autobahn:node22"] = true,
["autobahn:node32"] = true, ["autobahn:node32"] = true,
["autobahn:node42"] = true, ["autobahn:node42"] = true,
["autobahn:node52"] = true, ["autobahn:node52"] = true,
["autobahn:node62"] = true,
} }
local NodeTbl2 = { local NodeTbl2 = {
["autobahn:node11"] = true, ["autobahn:node11"] = true,
@ -137,6 +139,7 @@ local NodeTbl2 = {
["autobahn:node31"] = true, ["autobahn:node31"] = true,
["autobahn:node41"] = true, ["autobahn:node41"] = true,
["autobahn:node51"] = true, ["autobahn:node51"] = true,
["autobahn:node61"] = true,
} }
local NodeTbl3 = { local NodeTbl3 = {
["autobahn:node1"] = true, ["autobahn:node1"] = true,
@ -144,6 +147,7 @@ local NodeTbl3 = {
["autobahn:node3"] = true, ["autobahn:node3"] = true,
["autobahn:node4"] = true, ["autobahn:node4"] = true,
["autobahn:node5"] = true, ["autobahn:node5"] = true,
["autobahn:node6"] = true,
} }
-- 1) _o_ -- 1) _o_
@ -227,7 +231,9 @@ local function register_node(name, tiles, drawtype, mesh, box, drop)
sunlight_propagates = true, sunlight_propagates = true,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
is_ground_content = false, is_ground_content = false,
groups = {cracky=2, crumbly=2, not_in_creative_inventory=(mesh==nil) and 0 or 1}, groups = {cracky=2, crumbly=2,
fall_damage_add_percent = -80,
not_in_creative_inventory=(mesh==nil) and 0 or 1},
drop = "autobahn:"..drop, drop = "autobahn:"..drop,
after_place_node = function(pos, placer, itemstack, pointed_thing) after_place_node = function(pos, placer, itemstack, pointed_thing)
@ -239,7 +245,8 @@ local function register_node(name, tiles, drawtype, mesh, box, drop)
reset_player_privs(clicker) reset_player_privs(clicker)
else else
set_player_privs(clicker) set_player_privs(clicker)
minetest.after(0.5, control_player, clicker) local player_name = clicker:get_player_name()
minetest.after(0.5, control_player, player_name)
end end
end, end,
}) })
@ -277,12 +284,14 @@ local Nodes = {
{name="node31", tiles={"autobahn3.png","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp1.obj", box=sb1, drop="node3"}, {name="node31", tiles={"autobahn3.png","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp1.obj", box=sb1, drop="node3"},
{name="node41", tiles={"autobahn2.png^[transformR180]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp1.obj", box=sb1, drop="node4"}, {name="node41", tiles={"autobahn2.png^[transformR180]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp1.obj", box=sb1, drop="node4"},
{name="node51", tiles={"autobahn4.png^[transformR90]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp1.obj", box=sb1, drop="node5"}, {name="node51", tiles={"autobahn4.png^[transformR90]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp1.obj", box=sb1, drop="node5"},
{name="node61", tiles={"autobahn5.png^[transformR90]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp1.obj", box=sb1, drop="node6"},
{name="node12", tiles={"autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node1"}, {name="node12", tiles={"autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node1"},
{name="node22", tiles={"autobahn2.png","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node2"}, {name="node22", tiles={"autobahn2.png","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node2"},
{name="node32", tiles={"autobahn3.png","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node3"}, {name="node32", tiles={"autobahn3.png","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node3"},
{name="node42", tiles={"autobahn2.png^[transformR180]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node4"}, {name="node42", tiles={"autobahn2.png^[transformR180]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node4"},
{name="node52", tiles={"autobahn4.png^[transformR90]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node5"}, {name="node52", tiles={"autobahn4.png^[transformR90]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node5"},
{name="node62", tiles={"autobahn5.png^[transformR90]","autobahn1.png"}, drawtype="mesh", mesh="autobahn_ramp2.obj", box=sb2, drop="node6"},
} }
for _,item in ipairs(Nodes) do for _,item in ipairs(Nodes) do
@ -405,10 +414,14 @@ if minetest.global_exists("minecart") then
minecart.register_protected_node("autobahn:node21") minecart.register_protected_node("autobahn:node21")
minecart.register_protected_node("autobahn:node31") minecart.register_protected_node("autobahn:node31")
minecart.register_protected_node("autobahn:node41") minecart.register_protected_node("autobahn:node41")
minecart.register_protected_node("autobahn:node51")
minecart.register_protected_node("autobahn:node61")
minecart.register_protected_node("autobahn:node12") minecart.register_protected_node("autobahn:node12")
minecart.register_protected_node("autobahn:node22") minecart.register_protected_node("autobahn:node22")
minecart.register_protected_node("autobahn:node32") minecart.register_protected_node("autobahn:node32")
minecart.register_protected_node("autobahn:node42") minecart.register_protected_node("autobahn:node42")
minecart.register_protected_node("autobahn:node52")
minecart.register_protected_node("autobahn:node62")
end end

View File

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

View File

@ -117,4 +117,4 @@ History
2020-06-27 v1.07 Route storage and cart command bugfixes 2020-06-27 v1.07 Route storage and cart command bugfixes
2020-07-24 V1.08 Adapted to new techage ICTA style 2020-07-24 V1.08 Adapted to new techage ICTA style
2020-08-14 V1.09 Hopper support for digtron, protector:chest and default:furnace added 2020-08-14 V1.09 Hopper support for digtron, protector:chest and default:furnace added
2020-11-12 V1.10 Make carts more robust against server lag

View File

@ -53,8 +53,18 @@ local function on_punch(pos, node, puncher)
if not minecart.teleport_enabled then return end if not minecart.teleport_enabled then return end
local route = minecart.get_route(P2S(pos)) local route = minecart.get_route(P2S(pos))
if route and route.dest_pos and puncher and puncher:is_player() then if route and route.dest_pos and puncher and puncher:is_player() then
-- only teleport if the user is not pressing shift
if not puncher:get_player_control()['sneak'] then if not puncher:get_player_control()['sneak'] then
puncher:set_pos(S2P(route.dest_pos)) local playername = puncher:get_player_name()
local pos = S2P(route.dest_pos)
local teleport = function()
-- Make sure the player object still exists
local player = minetest.get_player_by_name(playername)
if player and pos then player:set_pos(pos) end
end
minetest.after(0.25, teleport)
end end
end end
end end

View File

@ -17,6 +17,12 @@
-- 2) Only the owner can start the recording -- 2) Only the owner can start the recording
-- 3) But any player can act as cargo, cart punched by owner or buffer -- 3) But any player can act as cargo, cart punched by owner or buffer
local SLOPE_ACCELERATION = 3
local MAX_SPEED = 7
local PUNCH_SPEED = 3
local SLOWDOWN = 0.4
local RAILTYPE = minetest.get_item_group("carts:rail", "connect_to_raillike")
local Y_OFFS_ON_SLOPES = 0.5
-- for lazy programmers -- for lazy programmers
local M = minetest.get_meta local M = minetest.get_meta
@ -24,6 +30,83 @@ local S = minecart.S
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos local S2P = minetest.string_to_pos
local MP = minetest.get_modpath("minecart") local MP = minetest.get_modpath("minecart")
local D = function(pos) return minetest.pos_to_string(vector.round(pos)) end
local tRails = {
["carts:rail"] = true,
["carts:powerrail"] = true,
["carts:brakerail"] = true,
}
local lRails = {"carts:rail", "carts:powerrail", "carts:brakerail"}
local function get_rail_node(pos)
local rail_pos = vector.round(pos)
local node = minecart.get_node_lvm(rail_pos)
if tRails[node.name] then
return rail_pos, node
end
end
local function find_rail_node(pos)
local rail_pos = vector.round(pos)
local node = get_rail_node(rail_pos)
if node then
return rail_pos, node
end
local pos1 = {x=rail_pos.x-1, y=rail_pos.y-1, z=rail_pos.z-1}
local pos2 = {x=rail_pos.x+1, y=rail_pos.y+1, z=rail_pos.z+1}
for _,pos3 in ipairs(minetest.find_nodes_in_area(pos1, pos2, lRails)) do
--print("invalid position1", D(pos), D(pos3))
return pos3, minecart.get_node_lvm(pos3)
end
--print("invalid position2", D(pos))
end
local function get_pitch(dir)
local pitch = 0
if dir.y == -1 then
pitch = -math.pi/4
elseif dir.y == 1 then
pitch = math.pi/4
end
return pitch * (dir.z == 0 and -1 or 1)
end
local function get_yaw(dir)
local yaw = 0
if dir.x < 0 then
yaw = math.pi/2*3
elseif dir.x > 0 then
yaw = math.pi/2
elseif dir.z < 0 then
yaw = math.pi
end
return yaw
end
local function push_cart(self, pos, punch_dir, puncher)
local vel = self.object:get_velocity()
punch_dir = punch_dir or carts:velocity_to_dir(puncher:get_look_dir())
punch_dir.y = 0
local cart_dir = carts:get_rail_direction(pos, punch_dir, nil, nil, RAILTYPE)
-- Always start in horizontal direction
cart_dir.y = 0
if vector.equals(cart_dir, {x=0, y=0, z=0}) then return end
local speed = vector.multiply(cart_dir, PUNCH_SPEED)
local new_vel = vector.add(vel, speed)
local yaw = get_yaw(cart_dir)
local pitch = get_pitch(cart_dir)
self.object:set_rotation({x = pitch, y = yaw, z = 0})
self.object:set_velocity(new_vel)
self.old_pos = vector.round(pos)
self.stopped = false
end
local api = {} local api = {}
@ -94,31 +177,20 @@ function api:on_punch(puncher, time_from_last_punch, tool_capabilities, directio
return return
end end
-- running carts can't be punched or removed from external
if not stopped then
return
end
-- Punched by non-authorized player -- Punched by non-authorized player
if puncher_name and not puncher_is_owner then if puncher_name and not puncher_is_owner then
minetest.chat_send_player(puncher_name, S("[minecart] Cart is protected by ")..(self.owner or "")) minetest.chat_send_player(puncher_name, S("[minecart] Cart is protected by ")..(self.owner or ""))
return return
end end
if not self.railtype then
local node = minetest.get_node(pos).name
self.railtype = minetest.get_item_group(node, "connect_to_raillike")
end
-- Punched by non-player -- Punched by non-player
if not puncher_name then if not puncher_name then
local cart_dir = carts:get_rail_direction(pos, direction, nil, nil, self.railtype) local cart_dir = carts:get_rail_direction(pos, direction, nil, nil, RAILTYPE)
if vector.equals(cart_dir, {x=0, y=0, z=0}) then if vector.equals(cart_dir, {x=0, y=0, z=0}) then
return return
end end
self.velocity = vector.multiply(cart_dir, 2)
self.punched = true
api.load_cargo(self, pos) api.load_cargo(self, pos)
push_cart(self, pos, cart_dir)
minecart.start_cart(pos, self.myID) minecart.start_cart(pos, self.myID)
return return
end end
@ -131,7 +203,7 @@ function api:on_punch(puncher, time_from_last_punch, tool_capabilities, directio
end end
-- detach driver -- detach driver
if self.driver then if self.driver then
carts:manage_attachment(puncher_name, nil) carts:manage_attachment(puncher, nil)
end end
-- Pick up cart -- Pick up cart
api.remove_cart(self, pos, puncher) api.remove_cart(self, pos, puncher)
@ -147,23 +219,7 @@ function api:on_punch(puncher, time_from_last_punch, tool_capabilities, directio
api.load_cargo(self, pos) api.load_cargo(self, pos)
-- Normal punch by owner to start the cart push_cart(self, pos, nil, puncher)
local punch_dir = carts:velocity_to_dir(puncher:get_look_dir())
punch_dir.y = 0
local cart_dir = carts:get_rail_direction(pos, punch_dir, nil, nil, self.railtype)
if vector.equals(cart_dir, {x=0, y=0, z=0}) then
return
end
self.velocity = vector.multiply(cart_dir, 2)
self.old_dir = cart_dir
self.punched = true
end
local function rail_on_step_event(handler, obj, dtime)
if handler then
handler(obj, dtime)
end
end end
-- sound refresh interval = 1.0sec -- sound refresh interval = 1.0sec
@ -193,65 +249,92 @@ local function rail_sound(self, dtime)
end end
end end
local function get_railparams(pos) local function rail_on_step(self)
local node = minetest.get_node(pos) -- Check if same position as before
return carts.railparams[node.name] or {}
end
local v3_len = vector.length
local function rail_on_step(self, dtime)
local vel = self.object:get_velocity()
local pos = self.object:get_pos() local pos = self.object:get_pos()
local rot = self.object:get_rotation() local rot = self.object:get_rotation()
local stopped = minecart.stopped(vel) and rot.x == 0 local on_slope = rot.x ~= 0
--print("rail_on_step_new", P2S(pos), rot.x)
-- cart position correction on slopes
if on_slope then
pos.y = pos.y - Y_OFFS_ON_SLOPES
end
-- Used as fallback position
self.old_pos = self.old_pos or pos
local pos_rounded = vector.round(pos)
-- Same pos as before
if vector.equals(pos_rounded, self.old_pos) then
return -- nothing todo
end
-- Check if stopped
local vel = self.object:get_velocity()
local stopped = not on_slope and minecart.stopped(vel)
local is_minecart = self.node_name == nil local is_minecart = self.node_name == nil
local recording = is_minecart and self.driver == self.owner local recording = is_minecart and self.driver == self.owner
-- cart position correction on slopes if stopped then
if rot.x ~= 0 then if not self.stopped then
pos.y = pos.y - 0.5
end
if self.punched then
vel = vector.add(vel, self.velocity)
self.object:set_velocity(vel)
self.old_dir.y = 0
self.stopped = false
elseif stopped and not self.stopped then
local param2 = minetest.dir_to_facedir(self.old_dir) local param2 = minetest.dir_to_facedir(self.old_dir)
api.stop_cart(pos, self, self.node_name or "minecart:cart", param2) api.stop_cart(pos, self, self.node_name or "minecart:cart", param2)
if recording then if recording then
minecart.stop_recording(self, pos, vel, self.driver) minecart.stop_recording(self, pos_rounded, vel, self.driver)
end end
api.unload_cargo(self, pos) api.unload_cargo(self, pos)
self.stopped = true self.stopped = true
self.object:set_velocity({x=0, y=0, z=0}) end
self.object:set_acceleration({x=0, y=0, z=0}) self.old_pos = pos_rounded
return return -- nothing todo
elseif stopped then
return
end end
if recording then -- Check if invalid position (not on rail anymore)
minecart.store_next_waypoint(self, pos, vel) local rail_pos, node = get_rail_node(pos)
if not node then
rail_pos, node = find_rail_node(self.old_pos)
if rail_pos then
pos_rounded = rail_pos
if on_slope then
self.object:set_pos({x=rail_pos.x, y=rail_pos.y + Y_OFFS_ON_SLOPES, z=rail_pos.z})
else
self.object:set_pos(rail_pos)
end end
else
local cart_dir = carts:velocity_to_dir(vel) self.object:set_pos(pos)
local same_dir = vector.equals(cart_dir, self.old_dir) minetest.log("error", "[minecart] No valid position "..(P2S(pos) or "nil"))
local update = {} return -- no valid position
if self.old_pos and not self.punched and same_dir then
local flo_pos = vector.round(pos)
local flo_old = vector.round(self.old_pos)
if vector.equals(flo_pos, flo_old) then
-- Do not check one node multiple times
return
end end
end end
local ctrl, player -- Calc speed (value)
local speed = math.sqrt((vel.x+vel.z)^2 + vel.y^2)
-- Check if slope position
if pos_rounded.y > self.old_pos.y then
speed = speed - SLOPE_ACCELERATION
elseif pos_rounded.y < self.old_pos.y then
speed = speed + SLOPE_ACCELERATION
else
speed = speed - SLOWDOWN
end
-- Add power/brake rail acceleration
local acc = (carts.railparams[node.name] or {}).acceleration or 0
speed = speed + acc
-- Determine new direction
local dir = carts:velocity_to_dir(vel)
if speed < 0 then
if on_slope then
dir = vector.multiply(dir, -1)
-- start with a value > 0
speed = 0.5
else
speed = 0
end
end
-- Get player controls -- Get player controls
local ctrl, player
if recording then if recording then
player = minetest.get_player_by_name(self.driver) player = minetest.get_player_by_name(self.driver)
if player then if player then
@ -259,158 +342,56 @@ local function rail_on_step(self, dtime)
end end
end end
local railparams -- new_dir: New moving direction of the cart
-- keys: Currently pressed L/R key, used to ignore the key on the next rail node
-- dir: New moving direction of the cart local new_dir, keys = carts:get_rail_direction(rail_pos, dir, ctrl, self.old_keys, RAILTYPE)
-- switch_keys: Currently pressed L/R key, used to ignore the key on the next rail node
local dir, switch_keys = carts:get_rail_direction(
pos, cart_dir, ctrl, self.old_switch, self.railtype
)
-- handle junctions -- handle junctions
if switch_keys then -- recording if recording and keys then
minecart.set_junction(self, pos, dir, switch_keys) minecart.set_junction(self, rail_pos, new_dir, keys)
else -- normal run else -- normal run
dir, switch_keys = minecart.get_junction(self, pos, dir) new_dir, keys = minecart.get_junction(self, rail_pos, new_dir)
end end
self.old_keys = keys
local dir_changed = not vector.equals(dir, self.old_dir) -- Detect U-turn
if (dir.x ~= 0 and dir.x == -new_dir.x) or (dir.z ~= 0 and dir.z == -new_dir.z) then
local new_acc = {x=0, y=0, z=0} -- Stop the cart
if vector.equals(dir, {x=0, y=0, z=0}) then self.object:set_velocity({x=0, y=0, z=0})
vel = {x = 0, y = 0, z = 0} self.object:move_to(pos_rounded)
local pos_r = vector.round(pos)
if not carts:is_rail(pos_r, self.railtype)
and self.old_pos then
pos = self.old_pos
else
pos = pos_r
end
update.pos = true
update.vel = true
else
-- Direction change detected
if dir_changed then
vel = vector.multiply(dir, math.abs(vel.x + vel.z))
update.vel = true
if dir.y ~= self.old_dir.y then
pos = vector.round(pos)
update.pos = true
end
end
-- Center on the rail
if dir.z ~= 0 and math.floor(pos.x + 0.5) ~= pos.x then
pos.x = math.floor(pos.x + 0.5)
update.pos = true
end
if dir.x ~= 0 and math.floor(pos.z + 0.5) ~= pos.z then
pos.z = math.floor(pos.z + 0.5)
update.pos = true
end
-- Slow down or speed up..
local acc = dir.y * -1.5
-- Get rail for corrected position
railparams = get_railparams(pos)
-- no need to check for railparams == nil since we always make it exist.
local speed_mod = railparams.acceleration
if speed_mod and speed_mod ~= 0 then
-- Try to make it similar to the original carts mod
acc = acc + speed_mod
else
acc = acc - 0.4
end
new_acc = vector.multiply(dir, acc)
end
-- Limits
local max_vel = carts.speed_max
for _, v in pairs({"x","y","z"}) do
if math.abs(vel[v]) > max_vel then
vel[v] = carts:get_sign(vel[v]) * max_vel
new_acc[v] = 0
update.vel = true
end
end
self.object:set_acceleration(new_acc)
self.old_pos = vector.round(pos)
if not vector.equals(dir, {x=0, y=0, z=0}) then
self.old_dir = vector.new(dir)
end
self.old_switch = switch_keys
if self.punched then
self.punched = false
update.vel = true
end
railparams = railparams or get_railparams(pos)
if not (update.vel or update.pos) then
rail_on_step_event(railparams.on_step, self, dtime)
return return
end -- New direction
elseif not vector.equals(dir, new_dir) then
local yaw = 0 if new_dir.y ~= 0 then
if self.old_dir.x < 0 then self.object:set_pos({x=pos_rounded.x, y=pos_rounded.y + Y_OFFS_ON_SLOPES, z=pos_rounded.z})
yaw = math.pi/2*3
elseif self.old_dir.x > 0 then
yaw = math.pi/2
elseif self.old_dir.z < 0 then
yaw = math.pi
end
--self.object:set_yaw(yaw * math.pi)
local pitch = 0
if self.old_dir.z ~= 0 then
if dir.y == -1 then
pitch = -math.pi/4
elseif dir.y == 1 then
pitch = math.pi/4
end
else else
if dir.y == -1 then self.object:set_pos(pos_rounded)
pitch = math.pi/4
elseif dir.y == 1 then
pitch = -math.pi/4
end end
end end
-- Set velocity and rotation
local new_vel = vector.multiply(new_dir, math.min(speed, MAX_SPEED))
local yaw = get_yaw(new_dir)
local pitch = get_pitch(new_dir)
self.object:set_rotation({x = pitch, y = yaw, z = 0}) self.object:set_rotation({x = pitch, y = yaw, z = 0})
self.object:set_velocity(new_vel)
-- cart position correction on slopes
if pitch ~= 0 then
pos.y = pos.y + 0.5
update.pos = true
vel = vector.divide(vel, 2)
update.vel = true
elseif self.old_pitch ~= 0 then
vel = vector.multiply(vel, 2)
update.vel = true
end
self.old_pitch = pitch
if update.vel then if recording then
self.object:set_velocity(vel) minecart.store_next_waypoint(self, rail_pos, vel)
end
if update.pos then
if dir_changed then
self.object:set_pos(pos)
else
self.object:move_to(pos)
end
end end
-- call event handler self.old_pos = pos_rounded
rail_on_step_event(railparams.on_step, self, dtime)
end end
function api:on_step(dtime) function api:on_step(dtime)
rail_on_step(self, dtime) self.delay = (self.delay or 0) + dtime
rail_sound(self, dtime) if self.delay > 0.09 then
rail_on_step(self)
rail_sound(self, self.delay)
self.delay = 0
end
end end
return api return api

View File

@ -49,7 +49,7 @@ function api.get_station_name(pos)
end end
end end
function api.load_cart(pos, vel, item) function api.load_cart(pos, vel, pitch, yaw, item)
-- Add cart to map -- Add cart to map
local obj = minetest.add_entity(pos, item.entity_name or "minecart:cart", nil) local obj = minetest.add_entity(pos, item.entity_name or "minecart:cart", nil)
-- Determine ID -- Determine ID
@ -67,6 +67,7 @@ function api.load_cart(pos, vel, item)
item.cargo = nil item.cargo = nil
-- Start cart -- Start cart
obj:set_velocity(vel) obj:set_velocity(vel)
obj:set_rotation({x = pitch or 0, y = yaw or 0, z = 0})
return myID return myID
else else
print("Entity has no ID") print("Entity has no ID")

View File

@ -13,12 +13,10 @@
minecart = {} minecart = {}
-- Version for compatibility checks, see readme.md/history -- Version for compatibility checks, see readme.md/history
minecart.version = 1.09 minecart.version = 1.10
minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false
minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") ~= false minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") == true
print("minecart_hopper_enabled", dump(minetest.settings:get_bool("minecart_hopper_enabled")))
minecart.S = minetest.get_translator("minecart") minecart.S = minetest.get_translator("minecart")
local MP = minetest.get_modpath("minecart") local MP = minetest.get_modpath("minecart")

View File

@ -51,6 +51,24 @@ function minecart.register_cart_names(cart_name_stopped, cart_name_running)
end end
end end
function minecart.get_node_lvm(pos)
local node = minetest.get_node_or_nil(pos)
if node then
return node
end
local vm = minetest.get_voxel_manip()
local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
local data = vm:get_data()
local param2_data = vm:get_param2_data()
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
local idx = area:indexp(pos)
node = {
name = minetest.get_name_from_content_id(data[idx]),
param2 = param2_data[idx]
}
return node
end
function minecart.stopped(vel, tolerance) function minecart.stopped(vel, tolerance)
tolerance = tolerance or 0.05 tolerance = tolerance or 0.05
return math.abs(vel.x) < tolerance and math.abs(vel.z) < tolerance return math.abs(vel.x) < tolerance and math.abs(vel.z) < tolerance
@ -64,6 +82,13 @@ local function is_air_like(name)
return false return false
end end
function minecart.range(val, min, max)
val = tonumber(val)
if val < min then return min end
if val > max then return max end
return val
end
function minecart.get_next_node(pos, param2) function minecart.get_next_node(pos, param2)
local pos2 = param2 and vector.add(pos, param2_to_dir[param2]) or pos local pos2 = param2 and vector.add(pos, param2_to_dir[param2]) or pos
local node = minetest.get_node(pos2) local node = minetest.get_node(pos2)

View File

@ -33,26 +33,26 @@ local NodesAtStation = {}
-- --
-- Helper functions -- Helper functions
-- --
local function calc_pos_and_vel(item) local function get_pos_vel_pitch_yaw(item)
if item.start_time and item.start_key then -- cart on recorded route if item.start_time and item.start_key then -- cart on recorded route
local run_time = minetest.get_gametime() - item.start_time local run_time = minetest.get_gametime() - item.start_time
local waypoints = get_route(item.start_key).waypoints local waypoints = get_route(item.start_key).waypoints
local waypoint = waypoints[run_time] local waypoint = waypoints[run_time]
if waypoint then if waypoint then
return S2P(waypoint[1]), S2P(waypoint[2]) return S2P(waypoint[1]), S2P(waypoint[2]), 0, 0
end end
end end
if item.last_pos then if item.last_pos then
item.last_pos = vector.round(item.last_pos) item.last_pos = vector.round(item.last_pos)
if carts:is_rail(item.last_pos, minetest.raillike_group("rail")) then if carts:is_rail(item.last_pos, minetest.raillike_group("rail")) then
return item.last_pos, item.last_vel return item.last_pos, item.last_vel, item.last_pitch or 0, item.last_yaw or 0
end end
item.last_pos.y = item.last_pos.y - 1 item.last_pos.y = item.last_pos.y - 1
if carts:is_rail(item.last_pos, minetest.raillike_group("rail")) then if carts:is_rail(item.last_pos, minetest.raillike_group("rail")) then
return item.last_pos, item.last_vel return item.last_pos, item.last_vel, item.last_pitch or 0, item.last_yaw or 0
end end
end end
return item.start_pos, {x=0, y=0, z=0} return item.start_pos, {x=0, y=0, z=0}, 0, 0
end end
-- --
@ -132,24 +132,29 @@ local function monitoring()
if entity then -- cart entity running if entity then -- cart entity running
local pos = entity.object:get_pos() local pos = entity.object:get_pos()
local vel = entity.object:get_velocity() local vel = entity.object:get_velocity()
local rot = entity.object:get_rotation()
if not minetest.get_node_or_nil(pos) then -- unloaded area if not minetest.get_node_or_nil(pos) then -- unloaded area
lib.unload_cart(pos, vel, entity, item) lib.unload_cart(pos, vel, entity, item)
item.stopped = minecart.stopped(vel) item.stopped = minecart.stopped(vel)
end end
-- store last pos from cart -- store last pos from cart
item.last_pos, item.last_vel = pos, vel item.last_pos, item.last_vel, item.last_pitch, item.last_yaw = pos, vel, rot.x, rot.y
else -- no cart running else -- no cart running
local pos, vel = calc_pos_and_vel(item) local pos, vel, pitch, yaw = get_pos_vel_pitch_yaw(item)
if pos and vel then if pos and vel then
if minetest.get_node_or_nil(pos) then -- loaded area if minetest.get_node_or_nil(pos) then -- loaded area
local myID = lib.load_cart(pos, vel, item) if pitch > 0 then
pos.y = pos.y + 0.5
end
local myID = lib.load_cart(pos, vel, pitch, yaw, item)
if myID then if myID then
item.stopped = minecart.stopped(vel) item.stopped = minecart.stopped(vel)
to_be_added[myID] = table.copy(item) to_be_added[myID] = table.copy(item)
CartsOnRail[key] = nil -- invalid old ID CartsOnRail[key] = nil -- invalid old ID
end end
end end
item.last_pos, item.last_vel = pos, vel item.last_pos, item.last_vel, item.last_pitch, item.last_yaw = pos, vel, pitch, yaw
else else
-- should never happen -- should never happen
minetest.log("error", "[minecart] Cart of owner "..(item.owner or "nil").." got lost") minetest.log("error", "[minecart] Cart of owner "..(item.owner or "nil").." got lost")

View File

@ -19,7 +19,7 @@ Instructions:
Important to know: Important to know:
- 12 units of hydrogen are sufficient for a flight of 6 minutes - 12 units of hydrogen are sufficient for a flight of 6 minutes
- Maximum 5 items stacks in your inventory are allowed including the controller. - Maximum of 99 items in your inventory are allowed including the controller.
Otherwise you would be too heavy :-) Otherwise you would be too heavy :-)
- The Jetpack also wears out and can be used for approximately 10 flights - The Jetpack also wears out and can be used for approximately 10 flights
- Always hold the controller tight during the flight, otherwise it will switch off :) - Always hold the controller tight during the flight, otherwise it will switch off :)

View File

@ -13,13 +13,16 @@
-- Load support for I18n. -- Load support for I18n.
local S = minetest.get_translator("ta4_jetpack") local S = minetest.get_translator("ta4_jetpack")
local ta4_jetpack = {}
local Players = {} local Players = {}
local Jetpacks = {} local Jetpacks = {}
local ItemsBlocklist = {}
local MAX_HEIGHT = tonumber(minetest.settings:get("ta4_jetpack_max_height")) or 500 local MAX_HEIGHT = tonumber(minetest.settings:get("ta4_jetpack_max_height")) or 500
local MAX_VSPEED = tonumber(minetest.settings:get("ta4_jetpack_max_vertical_speed")) or 20 local MAX_VSPEED = tonumber(minetest.settings:get("ta4_jetpack_max_vertical_speed")) or 20
local MAX_HSPEED = (tonumber(minetest.settings:get("ta4_jetpack_max_horizontal_speed")) or 12) / 4 local MAX_HSPEED = (tonumber(minetest.settings:get("ta4_jetpack_max_horizontal_speed")) or 12) / 4
local MAX_NUM_INV_ITEMS = tonumber(minetest.settings:get("ta4_jetpack_max_num_inv_items")) or 5 local MAX_NUM_INV_ITEMS = tonumber(minetest.settings:get("ta4_jetpack_max_num_inv_items")) or 99
-- Flight time maximum 6 min or 360 s or 3600 steps. -- Flight time maximum 6 min or 360 s or 3600 steps.
-- 12 units hydrogen for 3600 steps means 0.0033 units hydrogen / step. -- 12 units hydrogen for 3600 steps means 0.0033 units hydrogen / step.
@ -31,6 +34,11 @@ local STEPS_TO_FUEL = 0.0033
local WEAR_VALUE = 180 -- roughly 10 flys, 6 min each local WEAR_VALUE = 180 -- roughly 10 flys, 6 min each
-- API function to register items that are forbidden in inventory during flight.
ta4_jetpack.register_forbidden_item = function(itemname)
ItemsBlocklist[itemname] = true
end
local function store_player_physics(player) local function store_player_physics(player)
local meta = player:get_meta() local meta = player:get_meta()
-- Check access conflicts with other mods -- Check access conflicts with other mods
@ -143,19 +151,22 @@ local function check_player_load(player)
local bags_meta = meta:get_string("unified_inventory:bags") local bags_meta = meta:get_string("unified_inventory:bags")
if bags_meta then if bags_meta then
if next(minetest.deserialize(bags_meta) or {}) then if next(minetest.deserialize(bags_meta) or {}) then
return S("check your bags!") return S("You are too heavy: Check your bags!")
end end
end end
for _, stack in ipairs(inv:get_list("craft") or {}) do for _, stack in ipairs(inv:get_list("craft") or {}) do
if not stack:is_empty() then if not stack:is_empty() then
return S("check your carfting menu!") return S("You are too heavy: Check your crafting menu!")
end end
end end
local count = 0 local count = 0
for _, stack in ipairs(inv:get_list("main") or {}) do for _, stack in ipairs(inv:get_list("main") or {}) do
count = count + (stack:is_empty() and 0 or 1) count = count + stack:get_count()
if count > MAX_NUM_INV_ITEMS then if count > MAX_NUM_INV_ITEMS then
return S("check your inventory!") return S("You are too heavy: Check your inventory!")
end
if ItemsBlocklist[stack:get_name()] then
return S("You may not transport @1 with a jetpack!", stack:get_description())
end end
end end
end end
@ -349,7 +360,7 @@ local function turn_controller_on_off(itemstack, user)
-- check inventory load -- check inventory load
local res = check_player_load(user) local res = check_player_load(user)
if res then if res then
minetest.chat_send_player(name, S("[Jetpack] You are too heavy: ")..res) minetest.chat_send_player(name, S("[Jetpack]").." "..res)
return itemstack return itemstack
end end
-- check fuel -- check fuel
@ -533,3 +544,6 @@ techage.add_manual_items({
ta4_jetpack = "ta4_jetpack.png", ta4_jetpack = "ta4_jetpack.png",
ta4_jetpack_controller = 'ta4_jetpack_controller_inv.png'}) ta4_jetpack_controller = 'ta4_jetpack_controller_inv.png'})
ta4_jetpack.register_forbidden_item("techage:cylinder_large_hydrogen")
ta4_jetpack.register_forbidden_item("techage:cylinder_small_hydrogen")
ta4_jetpack.register_forbidden_item("techage:hydrogen")

View File

@ -5,10 +5,11 @@ TA4 Jetpack=TA4 Jetpac
TA4 Jetpack Controller Off=TA4 Jetpack Controller Aus TA4 Jetpack Controller Off=TA4 Jetpack Controller Aus
TA4 Jetpack Controller On=TA4 Jetpack Controller An TA4 Jetpack Controller On=TA4 Jetpack Controller An
Use the controller (left click) to fill the tank with hydrogen=Benutze den Controller (linksklick) um den Tank mit Wasserstoff zu füllen Use the controller (left click) to fill the tank with hydrogen=Benutze den Controller (linksklick) um den Tank mit Wasserstoff zu füllen
[Jetpack] You are too heavy: =[Jetpack] Du bist zu schwer: You are too heavy: Check your bags!=Du bist zu schwer: Prüfe deine Rucksäcke!
You are too heavy: Check your crafting menu!=Du bist zu schwer: Prüfe dein Crafting Menü!
You are too heavy: Check your inventory!=Du bist zu schwer: Prüfe dein Inventar!
You may not transport @1 with a jetpack!=Du darfst @1 nicht mit dem Jetpack transportieren!
[Jetpack]=[Jetpack]
[Jetpack] You don't have your jetpack on your back!=[Jetpack] Du hast dein Jetpack nicht auf dem Rücken! [Jetpack] You don't have your jetpack on your back!=[Jetpack] Du hast dein Jetpack nicht auf dem Rücken!
[Jetpack] Your tank is empty!=[Jetpack] Dein Tank ist leer! [Jetpack] Your tank is empty!=[Jetpack] Dein Tank ist leer!
check your bags!=Prüfe deine Rucksäcke!
check your carfting menu!=Prüfe dein Crafting Menü!
check your inventory!=Prüfe dein Inventar!
##### not used anymore ##### ##### not used anymore #####

View File

@ -3,9 +3,11 @@ TA4 Jetpack=
TA4 Jetpack Controller Off= TA4 Jetpack Controller Off=
TA4 Jetpack Controller On= TA4 Jetpack Controller On=
Use the controller (left click) to fill the tank with hydrogen= Use the controller (left click) to fill the tank with hydrogen=
[Jetpack] You are too heavy: = You are too heavy: Check your bags!=
You are too heavy: Check your crafting menu!=
You are too heavy: Check your inventory!=
You may not transport @1 with a jetpack!=
[Jetpack]=
[Jetpack] You don't have your jetpack on your back!= [Jetpack] You don't have your jetpack on your back!=
[Jetpack] Your tank is empty!= [Jetpack] Your tank is empty!=
check your bags!= ##### not used anymore #####
check your carfting menu!=
check your inventory!=

View File

@ -17,7 +17,7 @@ techage.add_to_manual('DE', {
"\n".. "\n"..
"\n", "\n",
" - 12 Einheiten Wasserstoff reichen für einen Flug von 6 Minuten\n".. " - 12 Einheiten Wasserstoff reichen für einen Flug von 6 Minuten\n"..
" - Maximal 5 Stapel von Gegenständen im Spieler-Inventar sind zulässig\\, einschließlich des Controllers\n(Sonst wärst du zu schwer :-)\n".. " - Maximal 99 Gegenstände im Spieler-Inventar sind zulässig\\, einschließlich des Controllers\n(Sonst wärst du zu schwer :-)\n"..
" - Das Jetpack nutzt sich ab und kann für ca. 10 Flüge verwendet werden\n".. " - Das Jetpack nutzt sich ab und kann für ca. 10 Flüge verwendet werden\n"..
" - Halte den Controller während des Fluges immer fest\\, sonst schaltet er sich aus :)\n".. " - Halte den Controller während des Fluges immer fest\\, sonst schaltet er sich aus :)\n"..
"\n".. "\n"..

View File

@ -21,7 +21,7 @@ Das Jetpack ist inspiriert vom Jetpack von spirit689 (https://github.com/spirit6
## Was du wissen solltest ## Was du wissen solltest
- 12 Einheiten Wasserstoff reichen für einen Flug von 6 Minuten - 12 Einheiten Wasserstoff reichen für einen Flug von 6 Minuten
- Maximal 5 Stapel von Gegenständen im Spieler-Inventar sind zulässig, einschließlich des Controllers - Maximal 99 Gegenstände im Spieler-Inventar sind zulässig, einschließlich des Controllers
(Sonst wärst du zu schwer :-) (Sonst wärst du zu schwer :-)
- Das Jetpack nutzt sich ab und kann für ca. 10 Flüge verwendet werden - Das Jetpack nutzt sich ab und kann für ca. 10 Flüge verwendet werden
- Halte den Controller während des Fluges immer fest, sonst schaltet er sich aus :) - Halte den Controller während des Fluges immer fest, sonst schaltet er sich aus :)

View File

@ -18,7 +18,7 @@ techage.add_to_manual('EN', {
"\n".. "\n"..
"\n", "\n",
" - 12 units of hydrogen are sufficient for a flight of 6 minutes\n".. " - 12 units of hydrogen are sufficient for a flight of 6 minutes\n"..
" - Maximum 5 items stacks in your inventory are allowed including the controller.\nOtherwise you would be too heavy :-)\n".. " - Maximum 99 items in your inventory are allowed including the controller.\nOtherwise you would be too heavy :-)\n"..
" - The Jetpack also wears out and can be used for approximately 10 flights\n".. " - The Jetpack also wears out and can be used for approximately 10 flights\n"..
" - Always hold the controller tight during the flight\\, otherwise it will switch off :)\n".. " - Always hold the controller tight during the flight\\, otherwise it will switch off :)\n"..
"\n".. "\n"..

View File

@ -22,7 +22,7 @@ and by the historical game Lunar Lander.
## Important to know ## Important to know
- 12 units of hydrogen are sufficient for a flight of 6 minutes - 12 units of hydrogen are sufficient for a flight of 6 minutes
- Maximum 5 items stacks in your inventory are allowed including the controller. - Maximum 99 items in your inventory are allowed including the controller.
Otherwise you would be too heavy :-) Otherwise you would be too heavy :-)
- The Jetpack also wears out and can be used for approximately 10 flights - The Jetpack also wears out and can be used for approximately 10 flights
- Always hold the controller tight during the flight, otherwise it will switch off :) - Always hold the controller tight during the flight, otherwise it will switch off :)

View File

@ -8,7 +8,7 @@ ta4_jetpack_max_vertical_speed (maximum vertical speed) int 20
ta4_jetpack_max_horizontal_speed (maximum horizontal speed) int 12 ta4_jetpack_max_horizontal_speed (maximum horizontal speed) int 12
# Maximum number of inventory items a player can take # Maximum number of inventory items a player can take
ta4_jetpack_max_num_inv_items (maximum number of inventory items) int 5 ta4_jetpack_max_num_inv_items (maximum number of inventory items) int 99

View File

@ -1,28 +0,0 @@
The Techage mod for Minetest is
Copyright (C) 2019-2020 Joachim Stolberg
License of source code
----------------------
This mod is free software; you can redistribute and/or
modify it under the terms of the GNU General Public License version 3 or later
published by the Free Software Foundation.
This mod is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this mod; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
License of media (textures, sounds and documentation)
-----------------------------------------------------
All textures, sounds and documentation files are licensed under the
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
http://creativecommons.org/licenses/by-sa/3.0/

View File

@ -77,6 +77,14 @@ Available worlds will be converted to 'lsqlite3', but there is no way back, so:
### History ### History
**2020-11-01 V0.25**
- Pull request #37: Trowel: Add protection support (from Thomas-S)
- Pull request #38: Charcoal Pile: Ignore "ignore" nodes (from Thomas-S)
- Autocrafter: Add register function for uncraftable items
- Fix bug: Tubes do not recognize when TA2 nodes are added/removed
- TA4 chest/tank: Add 'public' checkbox to allow public access
- Add nodes TA2 Power Generator and TA3 Electric Motor
**2020-10-20 V0.24** **2020-10-20 V0.24**
- Pull request #27: Liquid Tanks: Add protection support (from Thomas-S) - Pull request #27: Liquid Tanks: Add protection support (from Thomas-S)
- Pull request #28: Quarry: Improve digging behaviour (from Thomas-S) - Pull request #28: Quarry: Improve digging behaviour (from Thomas-S)

View File

@ -178,7 +178,7 @@ techage.register_node({"techage:chest_ta2", "techage:chest_ta3"}, {
local function formspec4(pos) local function formspec4(pos)
return "size[10,9]".. return "size[10,9]"..
"tabheader[0,0;tab;"..S("Inventory,Configuration")..";1;;true]".. "tabheader[0,0;tab;"..S("Inventory,Pre-Assignment,Config")..";1;;true]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
@ -189,9 +189,9 @@ local function formspec4(pos)
"listring[current_player;main]" "listring[current_player;main]"
end end
local function formspec4_cfg(pos) local function formspec4_pre(pos)
return "size[10,9]".. return "size[10,9]"..
"tabheader[0,0;tab;"..S("Inventory,Configuration")..";2;;true]".. "tabheader[0,0;tab;"..S("Inventory,Pre-Assignment,Config")..";2;;true]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
@ -201,8 +201,23 @@ local function formspec4_cfg(pos)
"listring[current_player;main]" "listring[current_player;main]"
end end
local function formspec4_cfg(pos)
local meta = minetest.get_meta(pos)
local label = meta:get_string("label") or ""
local public = dump((meta:get_int("public") or 0) == 1)
return "size[10,5]"..
"tabheader[0,0;tab;"..S("Inventory,Pre-Assignment,Config")..";3;;true]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"field[0.5,1;9,1;label;"..S("Node label:")..";"..label.."]" ..
"checkbox[1,2;public;"..S("Allow public access to the chest")..";"..public.."]"..
"button_exit[3.5,4;3,1;exit;"..S("Save").."]"
end
local function ta4_allow_metadata_inventory_put(pos, listname, index, stack, player) local function ta4_allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0 return 0
end end
@ -214,7 +229,8 @@ local function ta4_allow_metadata_inventory_put(pos, listname, index, stack, pla
end end
local function ta4_allow_metadata_inventory_take(pos, listname, index, stack, player) local function ta4_allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0 return 0
end end
@ -226,7 +242,8 @@ local function ta4_allow_metadata_inventory_take(pos, listname, index, stack, pl
end end
local function ta4_allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) local function ta4_allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if minetest.is_protected(pos, player:get_player_name()) then local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0 return 0
end end
@ -276,10 +293,25 @@ minetest.register_node("techage:chest_ta4", {
mem.filter = nil mem.filter = nil
meta:set_string("formspec", formspec4(pos)) meta:set_string("formspec", formspec4(pos))
elseif fields.tab == "2" then elseif fields.tab == "2" then
meta:set_string("formspec", formspec4_pre(pos))
elseif fields.tab == "3" then
meta:set_string("formspec", formspec4_cfg(pos)) meta:set_string("formspec", formspec4_cfg(pos))
elseif fields.quit == "true" then elseif fields.quit == "true" then
mem.filter = nil mem.filter = nil
end end
if fields.public then
meta:set_int("public", fields.public == "true" and 1 or 0)
end
if fields.exit then
local number = meta:get_string("node_number")
if fields.label ~= "" then
meta:set_string("infotext", minetest.formspec_escape(fields.label).." #"..number)
else
meta:set_string("infotext", S("TA4 Protected Chest").." "..number)
end
meta:set_string("label", fields.label)
meta:set_string("formspec", formspec4_cfg(pos))
end
end, end,
techage_set_numbers = function(pos, numbers, player_name) techage_set_numbers = function(pos, numbers, player_name)

View File

@ -180,10 +180,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
if (meta:contains("node_number")) then if (meta:contains("node_number")) then
meta:set_string("node_number", "") meta:set_string("node_number", "")
end end
local number = "-" local number = techage.add_node(pos, name_pas, stage == 2)
if stage > 2 then
number = techage.add_node(pos, name_pas)
end
if crd.power_netw then if crd.power_netw then
crd.power_netw:after_place_node(pos) crd.power_netw:after_place_node(pos)
end end

View File

@ -35,7 +35,7 @@ local function formspec(self, pos, nvm)
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
power.formspec_label_bar(0, 0.8, S("power"), PWR_CAPA, nvm.provided).. power.formspec_label_bar(pos, 0, 0.8, S("power"), PWR_CAPA, nvm.provided)..
"image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]" "tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]"
end end

View File

@ -20,11 +20,16 @@ local S = techage.S
local DESCRIPTION = S("TA4 8x2000 Chest") local DESCRIPTION = S("TA4 8x2000 Chest")
local STACK_SIZE = 2000 local STACK_SIZE = 2000
local function gen_stack(inv, idx)
inv[idx] = {name = "", count = 0}
end
local function gen_inv(nvm) local function gen_inv(nvm)
nvm.inventory = {} nvm.inventory = {}
for i = 1,8 do for i = 1,8 do
nvm.inventory[i] = {name = "", count = 0} gen_stack(nvm.inventory, i)
end end
return nvm.inventory
end end
local function repair_inv(nvm) local function repair_inv(nvm)
@ -32,33 +37,26 @@ local function repair_inv(nvm)
for i = 1,8 do for i = 1,8 do
local item = nvm.inventory[i] local item = nvm.inventory[i]
if not item or type(item) ~= "table" if not item or type(item) ~= "table"
or not item.name or type(item.name) ~= "string" or not item.name or type(item.name) ~= "string" or item.name == ""
or not item.count or type(item.count) ~= "number" then or not item.count or type(item.count) ~= "number" or item.count < 1
nvm.inventory[i] = {name = "", count = 0} then
gen_stack(nvm.inventory, i)
end end
end end
end end
local function get_stack(nvm, idx) local function get_stack(nvm, idx)
nvm.inventory = nvm.inventory or {} nvm.inventory = nvm.inventory or {}
if nvm.inventory[idx] then return nvm.inventory[idx] or gen_stack(nvm.inventory, idx)
return nvm.inventory[idx]
end
nvm.inventory[idx] = {name = "", count = 0}
return nvm.inventory[idx]
end end
local function get_count(nvm, idx) local function get_count(nvm, idx)
if idx and idx > 0 then
nvm.inventory = nvm.inventory or {} nvm.inventory = nvm.inventory or {}
if nvm.inventory[idx] then if idx and idx > 0 then
return nvm.inventory[idx].count or 0 return nvm.inventory[idx] and nvm.inventory[idx].count or 0
else
return 0
end
else else
local count = 0 local count = 0
for _,item in ipairs(nvm.inventory or {}) do for _,item in ipairs(nvm.inventory) do
count = count + item.count or 0 count = count + item.count or 0
end end
return count return count
@ -68,9 +66,7 @@ end
local function get_itemstring(nvm, idx) local function get_itemstring(nvm, idx)
if idx and idx > 0 then if idx and idx > 0 then
nvm.inventory = nvm.inventory or {} nvm.inventory = nvm.inventory or {}
if nvm.inventory[idx] then return nvm.inventory[idx] and nvm.inventory[idx].name or ""
return nvm.inventory[idx].name or ""
end
end end
return "" return ""
end end
@ -97,11 +93,11 @@ local function inv_state(nvm)
end end
local function max_stacksize(item_name) local function max_stacksize(item_name)
local ndef = minetest.registered_nodes[item_name] or minetest.registered_items[item_name] or minetest.registered_craftitems[item_name] -- It is sufficient to use minetest.registered_items as all registration
if ndef then -- functions (node, craftitems, tools) add the definitions there.
return ndef.stack_max local ndef = minetest.registered_items[item_name]
end -- Return 1 as fallback so that slots with unknown items can be emptied.
return 0 return ndef and ndef.stack_max or 1
end end
local function get_stacksize(pos) local function get_stacksize(pos)
@ -112,102 +108,159 @@ local function get_stacksize(pos)
return size return size
end end
-- Sort the items into the nvm inventory -- Returns a boolean that indicates if an itemstack and nvmstack can be combined.
local function sort_in(pos, nvm, stack) -- The second return value is a string describing the reason.
local old_counts = {} -- This function guarantees not to modify any of both stacks.
local orig_count = stack:get_count() local function doesItemStackMatchNvmStack(itemstack, nvmstack)
for idx,item in ipairs(nvm.inventory or {}) do if itemstack:get_count() == 0 or nvmstack.count == 0 then
if item.name and (item.name == "" or item.name == stack:get_name()) then return true, "Empty stack"
local count = math.min(stack:get_count(), get_stacksize(pos) - item.count)
old_counts[idx] = item.count -- store old value
item.count = item.count + count
item.name = stack:get_name()
stack:set_count(stack:get_count() - count)
if stack:get_count() == 0 then
return true
end end
if nvmstack.name and nvmstack.name ~= "" and nvmstack.name ~= itemstack:get_name() then
return false, "Mismatching names"
end end
-- The following seems to be the most reliable approach to compare meta.
local nvm_meta = ItemStack():get_meta()
nvm_meta:from_table(minetest.deserialize(nvmstack.meta))
if not nvm_meta:equals(itemstack:get_meta()) then
return false, "Mismatching meta"
end end
-- restore old values if (nvmstack.wear or 0) ~= itemstack:get_wear() then
for idx,cnt in pairs(old_counts) do return false, "Mismatching wear"
nvm.inventory[idx].count = cnt
end end
stack:set_count(orig_count) return true, "Stacks match"
return false
end end
local function move_items_to_stack(item, stack, num)
item.count = item.count - num -- Generic function for adding items to the 8x2000 Chest
stack.count = stack.count + num -- This function guarantees not to modify the itemstack.
if stack.count > 0 then -- The number of items that were added to the chest is returned.
stack.name = item.name local function add_to_chest(pos, input_stack, idx)
local nvm = techage.get_nvm(pos)
local nvm_stack = get_stack(nvm, idx)
if input_stack:get_count() == 0 then
return 0
end end
if item.count == 0 then if not doesItemStackMatchNvmStack(input_stack, nvm_stack) then
item.name = "" -- empty return 0
end end
local count = math.min(input_stack:get_count(), get_stacksize(pos) - (nvm_stack.count or 0))
if nvm_stack.count == 0 then
nvm_stack.name = input_stack:get_name()
nvm_stack.meta = minetest.serialize(input_stack:get_meta():to_table())
nvm_stack.wear = input_stack:get_wear()
end
nvm_stack.count = nvm_stack.count + count
return count
end
local function stackOrNil(stack)
if stack and stack.get_count and stack:get_count() > 0 then
return stack return stack
end
return nil
end end
local function get_item(pos, nvm, item_name, count) -- Generic function for taking items from the 8x2000 Chest
local stack = {count = 0} -- output_stack is directly modified; but nil can also be supplied.
-- The resulting output_stack is returned from the function.
-- keep_assignment indicates if the meta information for this function should be considered (manual vs. tubes).
local function take_from_chest(pos, idx, output_stack, max_total_count, keep_assignment)
local nvm = techage.get_nvm(pos)
local nvm_stack = get_stack(nvm, idx)
output_stack = output_stack or ItemStack()
local assignment_count = keep_assignment and M(pos):get_int("assignment") == 1 and 1 or 0
local count = math.min(nvm_stack.count - assignment_count, max_stacksize(nvm_stack.name))
if max_total_count then
count = math.min(count, max_total_count - output_stack:get_count())
end
if count < 1 then
return stackOrNil(output_stack)
end
if not doesItemStackMatchNvmStack(output_stack, nvm_stack) then
return stackOrNil(output_stack)
end
output_stack:add_item(ItemStack({
name = nvm_stack.name,
count = count,
wear = nvm_stack.wear,
}))
output_stack:get_meta():from_table(minetest.deserialize(nvm_stack.meta))
nvm_stack.count = nvm_stack.count - count
if nvm_stack.count == 0 then
gen_stack(nvm.inventory or {}, idx)
end
return stackOrNil(output_stack)
end
-- Function for adding items to the 8x2000 Chest via automation, e.g. pushers
local function tube_add_to_chest(pos, input_stack)
local nvm = techage.get_nvm(pos)
nvm.inventory = nvm.inventory or {} nvm.inventory = nvm.inventory or {}
if item_name then -- Backup some values needed for restoring the old
-- Take specified items from the chest -- state if items can't fully be added to chest.
for _,item in ipairs(nvm.inventory) do local orig_count = input_stack:get_count()
if item.name == item_name then local backup = table.copy(nvm.inventory)
local num = math.min(item.count, count - stack.count, max_stacksize(item.name))
if M(pos):get_int("assignment") == 1 and num == item.count then for idx = 1,8 do
-- never take the last item input_stack:take_item(add_to_chest(pos, input_stack, idx))
num = num - 1
end
stack = move_items_to_stack(item, stack, num)
if stack.count == count then
return ItemStack(stack)
end
end
end
elseif M(pos):get_int("priority") == 1 then
-- Take any items. The position within the inventory is from right to left
for idx = 8,1,-1 do
local item = nvm.inventory[idx]
if item.name ~= "" and (stack.name == nil or stack.name == item.name) then
local num = math.min(item.count, count - stack.count, max_stacksize(item.name))
if M(pos):get_int("assignment") == 1 and num == item.count then
-- never take the last item
num = num - 1
end
stack = move_items_to_stack(item, stack, num)
if stack.count == count then
return ItemStack(stack)
end
end
end end
if input_stack:get_count() > 0 then
nvm.inventory = backup -- Restore old nvm inventory
input_stack:set_count(orig_count) -- Restore input_stack
return false -- No items were added to chest
else else
-- Take any items. The position within the inventory return true -- Items were added successfully
-- is incremented each time so that different item stacks will be considered. end
end
-- Function for taking items from the 8x2000 Chest via automation, e.g. pushers
local function tube_take_from_chest(pos, item_name, count)
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
nvm.inventory = nvm.inventory or {}
mem.startpos = mem.startpos or 1 mem.startpos = mem.startpos or 1
for idx = mem.startpos, mem.startpos + 8 do local prio = M(pos):get_int("priority") == 1
idx = (idx % 8) + 1 local startpos = prio and 8 or mem.startpos
local item = nvm.inventory[idx] local endpos = prio and 1 or mem.startpos + 8
if item.name ~= "" and (stack.name == nil or stack.name == item.name) then local step = prio and -1 or 1
local num = math.min(item.count, count - stack.count, max_stacksize(item.name)) local itemstack = ItemStack()
if M(pos):get_int("assignment") == 1 and num == item.count then for idx = startpos,endpos,step do
-- never take the last item idx = ((idx - 1) % 8) + 1
num = num - 1 local nvmstack = get_stack(nvm, idx)
end if not item_name or item_name == nvmstack.name then
stack = move_items_to_stack(item, stack, num) take_from_chest(pos, idx, itemstack, count - itemstack:get_count(), true)
if stack.count == count then if itemstack:get_count() == count then
mem.startpos = idx mem.startpos = idx + 1
return ItemStack(stack) return itemstack
end end
end end
mem.startpos = idx mem.startpos = idx + 1
end end
return stackOrNil(itemstack)
end
-- Function for manually adding items to the 8x2000 Chest via the formspec
local function inv_add_to_chest(pos, idx)
local inv = M(pos):get_inventory()
local inv_stack = inv:get_stack("main", idx)
local count = add_to_chest(pos, inv_stack, idx)
inv_stack:set_count(inv_stack:get_count() - count)
inv:set_stack("main", idx, inv_stack)
end
-- Function for manually taking items from the 8x2000 Chest via the formspec
local function inv_take_from_chest(pos, idx)
local inv = M(pos):get_inventory()
local inv_stack = inv:get_stack("main", idx)
if inv_stack:get_count() > 0 then
return
end end
if stack.count > 0 then local output_stack = take_from_chest(pos, idx)
return ItemStack(stack) if output_stack then
inv:set_stack("main", idx, output_stack)
end end
end end
@ -218,9 +271,15 @@ local function formspec_container(x, y, nvm, inv)
tbl[#tbl+1] = "box["..(xpos - 0.03)..",0;0.86,0.9;#808080]" tbl[#tbl+1] = "box["..(xpos - 0.03)..",0;0.86,0.9;#808080]"
local stack = get_stack(nvm, i) local stack = get_stack(nvm, i)
if stack.name ~= "" then if stack.name ~= "" then
local itemname = stack.name.." "..stack.count local itemstack = ItemStack({
name = stack.name,
count = stack.count,
wear = stack.wear,
})
itemstack:get_meta():from_table(minetest.deserialize(stack.meta))
local itemname = itemstack:to_string()
--tbl[#tbl+1] = "item_image["..xpos..",1;1,1;"..itemname.."]" --tbl[#tbl+1] = "item_image["..xpos..",1;1,1;"..itemname.."]"
tbl[#tbl+1] = techage.item_image(xpos, 0, itemname) tbl[#tbl+1] = techage.item_image(xpos, 0, itemname, stack.count)
end end
if inv:get_stack("main", i):get_count() == 0 then if inv:get_stack("main", i):get_count() == 0 then
tbl[#tbl+1] = "image_button["..xpos..",1;1,1;techage_form_get_arrow.png;get"..i..";]" tbl[#tbl+1] = "image_button["..xpos..",1;1,1;techage_form_get_arrow.png;get"..i..";]"
@ -366,47 +425,6 @@ local function on_rightclick(pos, node, clicker)
end end
end end
-- take items from chest
local function move_from_nvm_to_inv(pos, idx)
local nvm = techage.get_nvm(pos)
local inv = M(pos):get_inventory()
local inv_stack = inv:get_stack("main", idx)
local nvm_stack = get_stack(nvm, idx)
if nvm_stack.count > 0 and inv_stack:get_count() == 0 then
local count = math.min(nvm_stack.count, max_stacksize(nvm_stack.name))
nvm_stack.count = nvm_stack.count - count
inv:set_stack("main", idx, {name = nvm_stack.name, count = count})
if nvm_stack.count == 0 then
nvm_stack.name = ""
end
end
end
-- add items to chest
local function move_from_inv_to_nvm(pos, idx)
local nvm = techage.get_nvm(pos)
local inv = M(pos):get_inventory()
local inv_stack = inv:get_stack("main", idx)
local nvm_stack = get_stack(nvm, idx)
if inv_stack:get_count() > 0 then
-- Don't handle items with meta or wear information because it would get lost.
local meta_table = inv_stack:get_meta():to_table()
if meta_table ~= nil and next(meta_table.fields) ~= nil or inv_stack:get_wear() ~= 0 then
return
end
if nvm_stack.count == 0 or nvm_stack.name == inv_stack:get_name() then
local count = math.min(inv_stack:get_count(), get_stacksize(pos) - nvm_stack.count)
nvm_stack.count = nvm_stack.count + count
nvm_stack.name = inv_stack:get_name()
inv_stack:set_count(inv_stack:get_count() - count)
inv:set_stack("main", idx, inv_stack)
end
end
end
local function on_receive_fields(pos, formname, fields, player) local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then if minetest.is_protected(pos, player:get_player_name()) then
return return
@ -414,10 +432,10 @@ local function on_receive_fields(pos, formname, fields, player)
for i = 1,8 do for i = 1,8 do
if fields["get"..i] ~= nil then if fields["get"..i] ~= nil then
move_from_nvm_to_inv(pos, i) inv_take_from_chest(pos, i)
break break
elseif fields["add"..i] ~= nil then elseif fields["add"..i] ~= nil then
move_from_inv_to_nvm(pos, i) inv_add_to_chest(pos, i)
break break
end end
end end
@ -534,24 +552,21 @@ minetest.register_node("techage:ta4_chest_dummy", {
techage.register_node({"techage:ta4_chest"}, { techage.register_node({"techage:ta4_chest"}, {
on_pull_item = function(pos, in_dir, num, item_name) on_pull_item = function(pos, in_dir, num, item_name)
local nvm = techage.get_nvm(pos) local res = tube_take_from_chest(pos, item_name, num)
local res = get_item(pos, nvm, item_name, num)
if techage.is_activeformspec(pos) then if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos)) M(pos):set_string("formspec", formspec(pos))
end end
return res return res
end, end,
on_push_item = function(pos, in_dir, stack) on_push_item = function(pos, in_dir, stack)
local nvm = techage.get_nvm(pos) local res = tube_add_to_chest(pos, stack)
local res = sort_in(pos, nvm, stack)
if techage.is_activeformspec(pos) then if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos)) M(pos):set_string("formspec", formspec(pos))
end end
return res return res
end, end,
on_unpull_item = function(pos, in_dir, stack) on_unpull_item = function(pos, in_dir, stack)
local nvm = techage.get_nvm(pos) local res = tube_add_to_chest(pos, stack)
local res = sort_in(pos, nvm, stack)
if techage.is_activeformspec(pos) then if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos)) M(pos):set_string("formspec", formspec(pos))
end end

View File

@ -207,29 +207,40 @@ end
-- Add node to the techage lists. -- Add node to the techage lists.
-- Function determines and returns the node position number, -- Function determines and returns the node position number,
-- needed for message communication. -- needed for message communication.
function techage.add_node(pos, name) -- If TA2 node, return '-' instead of a real number, because
-- TA2 nodes should not support number based commands.
function techage.add_node(pos, name, is_ta2)
if item_handling_node(name) then if item_handling_node(name) then
Tube:after_place_node(pos) Tube:after_place_node(pos)
end end
if is_ta2 then
return "-"
end
local key = minetest.hash_node_position(pos) local key = minetest.hash_node_position(pos)
return NumbersToBeRecycled[key] or get_number(pos, true) local num = NumbersToBeRecycled[key]
if num then
backend.set_nodepos(num, pos)
NumbersToBeRecycled[key] = nil
return num
end
return get_number(pos, true)
end end
-- Function removes the node from the techage lists. -- Function removes the node from the techage lists.
function techage.remove_node(pos, oldnode, oldmetadata) function techage.remove_node(pos, oldnode, oldmetadata)
local number = oldmetadata and oldmetadata.fields and oldmetadata.fields.node_number local number = oldmetadata and oldmetadata.fields and oldmetadata.fields.node_number or oldmetadata.fields.number
print("number1", dump(oldmetadata))
number = number or get_number(pos) number = number or get_number(pos)
print("number2", number)
if number and tonumber(number) then if number and tonumber(number) then
local key = minetest.hash_node_position(pos) local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = number NumbersToBeRecycled[key] = number
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
if ninfo then
NodeInfoCache[number] = nil NodeInfoCache[number] = nil
if item_handling_node(ninfo.name) then print("number3", number)
end
if oldnode and item_handling_node(oldnode.name) then
Tube:after_dig_node(pos) Tube:after_dig_node(pos)
end end
end
end
end end

View File

@ -240,19 +240,15 @@ function techage.is_ocean(pos)
return true return true
end end
function techage.item_image(x, y, itemname) function techage.item_image(x, y, itemname, count)
local name, size = unpack(string.split(itemname, " ")) local name, size = unpack(string.split(itemname, " "))
size = count and count or size
size = tonumber(size) or 1
local label = "" local label = ""
local tooltip = "" local text = minetest.formspec_escape(ItemStack(itemname):get_description())
local ndef = minetest.registered_nodes[name] or minetest.registered_items[name] or minetest.registered_craftitems[name] local tooltip = "tooltip["..x..","..y..";1,1;"..text..";#0C3D32;#FFFFFF]"
if ndef and ndef.description then if minetest.registered_tools[name] and size > 1 then
local text = minetest.formspec_escape(ndef.description)
tooltip = "tooltip["..x..","..y..";1,1;"..text..";#0C3D32;#FFFFFF]"
end
if ndef and ndef.stack_max == 1 then
size = tonumber(size)
local offs = 0 local offs = 0
if size < 10 then if size < 10 then
offs = 0.65 offs = 0.65

View File

@ -36,6 +36,19 @@ function techage.liquid.formspec(pos, nvm)
if nvm.liquid and nvm.liquid.amount and nvm.liquid.amount > 0 and nvm.liquid.name then if nvm.liquid and nvm.liquid.amount and nvm.liquid.amount > 0 and nvm.liquid.name then
itemname = nvm.liquid.name.." "..nvm.liquid.amount itemname = nvm.liquid.name.." "..nvm.liquid.amount
end end
local name = minetest.get_node(pos).name
if name == "techage:ta4_tank" then
local public = dump((M(pos):get_int("public") or 0) == 1)
return "size[5,3]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;4.8,0.5;#c6e8ff]"..
"label[1.5,-0.1;"..minetest.colorize("#000000", title).."]"..
help(4.4, -0.1)..
techage.item_image(2, 1, itemname)..
"checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]"
else
return "size[4,2]".. return "size[4,2]"..
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
@ -44,6 +57,7 @@ function techage.liquid.formspec(pos, nvm)
"label[1,-0.1;"..minetest.colorize("#000000", title).."]".. "label[1,-0.1;"..minetest.colorize("#000000", title).."]"..
help(3.4, -0.1).. help(3.4, -0.1)..
techage.item_image(1.5, 1, itemname) techage.item_image(1.5, 1, itemname)
end
end end
function techage.liquid.is_empty(pos) function techage.liquid.is_empty(pos)
@ -205,7 +219,8 @@ local function empty_on_punch(pos, nvm, full_container, item_count)
end end
function techage.liquid.on_punch(pos, node, puncher, pointed_thing) function techage.liquid.on_punch(pos, node, puncher, pointed_thing)
if minetest.is_protected(pos, puncher:get_player_name()) then local public = M(pos):get_int("public") == 1
if not public and minetest.is_protected(pos, puncher:get_player_name()) then
return return
end end

View File

@ -26,6 +26,8 @@ end
function techage.mark_region(name, pos1, pos2, owner, secs) function techage.mark_region(name, pos1, pos2, owner, secs)
if not name or not pos1 or not pos2 then return end
techage.unmark_region(name) techage.unmark_region(name)
local thickness = 0.2 local thickness = 0.2
@ -82,6 +84,7 @@ minetest.register_entity(":techage:region_cube", {
textures = {"techage_cube_mark.png"}, textures = {"techage_cube_mark.png"},
use_texture_alpha = true, use_texture_alpha = true,
physical = false, physical = false,
glow = 12,
}, },
on_step = function(self, dtime) on_step = function(self, dtime)
if marker_region[self.player_name] == nil then if marker_region[self.player_name] == nil then

View File

@ -114,7 +114,7 @@ minetest.register_entity(":techage:position_side", {
physical = false, physical = false,
visual_size = {x = 1.1, y = 1.1, z = 1.1}, visual_size = {x = 1.1, y = 1.1, z = 1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55}, collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 8, glow = 12,
}, },
on_step = function(self, dtime) on_step = function(self, dtime)
if marker_region[self.player_name] == nil then if marker_region[self.player_name] == nil then

View File

@ -243,7 +243,7 @@ local function collect_network_nodes(pos, outdir, tlib2)
end end
for _,ntype in ipairs(ntypes) do for _,ntype in ipairs(ntypes) do
if not netw[ntype] then netw[ntype] = {} end if not netw[ntype] then netw[ntype] = {} end
netw[ntype][#netw[ntype] + 1] = {pos = pos, indir = indir, nominal = ndef.nominal or 0} netw[ntype][#netw[ntype] + 1] = {pos = pos, indir = indir, nominal = ndef.nominal}
end end
end) end)
netw.best_before = minetest.get_gametime() + BEST_BEFORE netw.best_before = minetest.get_gametime() + BEST_BEFORE

View File

@ -41,7 +41,7 @@ function techage.valid_place_for_windturbine(pos, player_name, num_turbines)
if data then if data then
local name = minetest.get_biome_name(data.biome) local name = minetest.get_biome_name(data.biome)
if not string.find(name, "ocean") then if not string.find(name, "ocean") then
chat_message(player_name, S("This is a "..name.." biome and no ocean!")) chat_message(player_name, S("This is a").." "..name.." "..S("biome and no ocean!"))
return false return false
end end
end end
@ -60,7 +60,7 @@ function techage.valid_place_for_windturbine(pos, player_name, num_turbines)
pos2 = {x=pos.x+20, y=1, z=pos.z+20} pos2 = {x=pos.x+20, y=1, z=pos.z+20}
num = #minetest.find_nodes_in_area(pos1, pos2, num = #minetest.find_nodes_in_area(pos1, pos2,
{"default:water_source", "default:water_flowing", "ignore"}) {"default:water_source", "default:water_flowing", "ignore"})
print(num, (41 * 41 * 0.9))
if num < (41*41 * 0.8) then if num < (41*41 * 0.8) then
techage.mark_region(player_name, pos1, pos2, "") techage.mark_region(player_name, pos1, pos2, "")
chat_message(player_name, S("Here is not enough water (41x41 m)!")) chat_message(player_name, S("Here is not enough water (41x41 m)!"))
@ -69,6 +69,7 @@ function techage.valid_place_for_windturbine(pos, player_name, num_turbines)
-- Check for next wind turbine -- Check for next wind turbine
pos1 = {x=pos.x-13, y=2, z=pos.z-13} pos1 = {x=pos.x-13, y=2, z=pos.z-13}
pos2 = {x=pos.x+13, y=22, z=pos.z+13} pos2 = {x=pos.x+13, y=22, z=pos.z+13}
num = #minetest.find_nodes_in_area(pos1, pos2, {"techage:ta4_wind_turbine"}) num = #minetest.find_nodes_in_area(pos1, pos2, {"techage:ta4_wind_turbine"})
if num > num_turbines then if num > num_turbines then
techage.mark_region(player_name, pos1, pos2, "") techage.mark_region(player_name, pos1, pos2, "")

View File

@ -59,6 +59,15 @@ local function take_liquid(pos, indir, name, amount)
return amount, name return amount, name
end end
local function untake_liquid(pos, indir, name, amount)
local leftover = liquid.srv_put(pos, indir, name, amount)
if techage.is_activeformspec(pos) then
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", liquid.formspec(pos, nvm))
end
return leftover
end
local function put_liquid(pos, indir, name, amount) local function put_liquid(pos, indir, name, amount)
-- check if it is not powder -- check if it is not powder
local ndef = minetest.registered_craftitems[name] or {} local ndef = minetest.registered_craftitems[name] or {}
@ -153,6 +162,7 @@ minetest.register_node("techage:tank_cart", {
peek = liquid.srv_peek, peek = liquid.srv_peek,
put = put_liquid, put = put_liquid,
take = take_liquid, take = take_liquid,
untake = untake_liquid,
}, },
networks = networks_def, networks = networks_def,
on_rightclick = on_rightclick, on_rightclick = on_rightclick,

View File

@ -157,9 +157,11 @@ local function untake(recipe, pos, liquids)
for _,item in pairs(recipe.input) do for _,item in pairs(recipe.input) do
if item.name ~= "" then if item.name ~= "" then
local outdir = liquids[item.name] or reload_liquids(pos)[item.name] local outdir = liquids[item.name] or reload_liquids(pos)[item.name]
if outdir then
liquid.untake(pos, outdir, item.name, item.num) liquid.untake(pos, outdir, item.name, item.num)
end end
end end
end
end end
local function dosing(pos, nvm, elapsed) local function dosing(pos, nvm, elapsed)

View File

@ -32,7 +32,7 @@ local function formspec(self, pos, nvm)
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
power.formspec_label_bar(0, 0.8, S("power"), PWR_CAPA, nvm.provided).. power.formspec_label_bar(pos, 0, 0.8, S("power"), PWR_CAPA, nvm.provided)..
"image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]" "tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]"
end end

View File

@ -49,7 +49,7 @@ local function formspec(self, pos, nvm)
default.gui_slots.. default.gui_slots..
"box[0,-0.1;4.8,0.5;#c6e8ff]".. "box[0,-0.1;4.8,0.5;#c6e8ff]"..
"label[1,-0.1;"..minetest.colorize("#000000", S("Digtron Battery")).."]".. "label[1,-0.1;"..minetest.colorize("#000000", S("Digtron Battery")).."]"..
power.formspec_label_bar(0, 0.8, S("Load"), TOTAL_MAX, total, S("Coal Equivalents")).. power.formspec_label_bar(pos, 0, 0.8, S("Load"), TOTAL_MAX, total, S("Coal Equivalents"))..
"image_button[2.6,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.6,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.6,2;1,1;"..self:get_state_tooltip(nvm).."]".. "tooltip[2.6,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"image[3.75,2;1,1;"..techage.get_power_image(pos, nvm).."]" "image[3.75,2;1,1;"..techage.get_power_image(pos, nvm).."]"

View File

@ -48,6 +48,7 @@ techage.Items = {
ta2_chest = "techage:chest_ta2", ta2_chest = "techage:chest_ta2",
ta2_forceload = "techage:forceload", ta2_forceload = "techage:forceload",
ta2_driveaxle = "techage:axle", ta2_driveaxle = "techage:axle",
ta2_generator = "techage:ta2_generator_off",
--------------------- ---------------------
techage_ta3 = "techage_ta3.png", techage_ta3 = "techage_ta3.png",
techage_ta31 = "techage_ta3b.png", techage_ta31 = "techage_ta3b.png",
@ -114,6 +115,7 @@ techage.Items = {
ta3_pipe_wall_entry = "techage:ta3_pipe_wall_entry", ta3_pipe_wall_entry = "techage:ta3_pipe_wall_entry",
ta3_mesecons_converter = "techage:ta3_mesecons_converter", ta3_mesecons_converter = "techage:ta3_mesecons_converter",
ta3_valve = "techage:ta3_valve_closed", ta3_valve = "techage:ta3_valve_closed",
ta3_motor = "techage:ta3_motor_off",
---------------------------- ----------------------------
techage_ta4 = "techage_ta4.png", techage_ta4 = "techage_ta4.png",
ta4_windturbine = "techage:ta4_wind_turbine", ta4_windturbine = "techage:ta4_wind_turbine",

View File

@ -28,6 +28,7 @@ techage.manual_DE.aTitel = {
"3,TA2 Schwungrad / Flywheel", "3,TA2 Schwungrad / Flywheel",
"3,TA2 Dampfleitungen / Steam Pipe", "3,TA2 Dampfleitungen / Steam Pipe",
"3,TA2 Antriebsachsen / TA2 Drive Axle", "3,TA2 Antriebsachsen / TA2 Drive Axle",
"3,TA2 Stromgenerator / TA2 Power Generator",
"2,Items schieben und sortieren", "2,Items schieben und sortieren",
"3,Röhren / TechAge Tube", "3,Röhren / TechAge Tube",
"3,TA2 Schieber / Pusher", "3,TA2 Schieber / Pusher",
@ -66,6 +67,8 @@ techage.manual_DE.aTitel = {
"3,TA3 Kleiner Stromgenerator / Tiny Power Generator", "3,TA3 Kleiner Stromgenerator / Tiny Power Generator",
"3,TA3 Akku Block / Akku Box", "3,TA3 Akku Block / Akku Box",
"3,TA3 Strom Terminal / Power Terminal", "3,TA3 Strom Terminal / Power Terminal",
"3,TA3 Elektromotor / TA3 Electric Motor",
"3,TA3 Strom Terminal / Power Terminal",
"2,TA3 Industrieofen", "2,TA3 Industrieofen",
"3,TA3 Ofen-Ölbrenner / Furnace Oil Burner", "3,TA3 Ofen-Ölbrenner / Furnace Oil Burner",
"3,TA3 Ofenoberteil / Furnace Top", "3,TA3 Ofenoberteil / Furnace Top",
@ -399,6 +402,14 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"Um Lampen oder andere Stromverbraucher an einer Dampfmaschine betreiben zu können\\, wird der TA2 Stromgenerator benötigt. Der TA2 Stromgenerator muss auf einer Seite mit Antriebsachsen verbunden werden und liefert dann auf der anderen Seite elektrischen Strom.\n"..
"\n"..
"Wird der Stromgenerator nicht mit ausreichend Kraft versorgt\\, geht er in einen Fehlerzustand und muss über einen Rechtsklick wieder aktiviert werden.\n"..
"\n"..
"Das Stromgenerator nimmt primär max. 25 ku an Achsenkraft auf und gibt sekundär max. 24 ku als Strom wieder ab. Er verbraucht also ein ku für die Umwandlung.\n"..
"\n"..
"\n"..
"\n",
"Um Gegenstände (Items) von einer Verarbeitungsstation zur nächsten weiter zu transportieren\\, werden Schieber und Röhren verwendet. Siehe Plan.\n".. "Um Gegenstände (Items) von einer Verarbeitungsstation zur nächsten weiter zu transportieren\\, werden Schieber und Röhren verwendet. Siehe Plan.\n"..
"\n".. "\n"..
"\n".. "\n"..
@ -424,6 +435,8 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"Der Verteiler besitzt dazu ein Menü mit 4 Filter mit unterschiedlichen Farben\\, entsprechend den 4 Ausgängen. Soll ein Ausgang genutzt werden\\, so muss der entsprechende Filter über die \"on\" Checkbox aktiviert werden. Alle Items\\, die für diesen Filter konfiguriert sind\\, werden über den zugeordneten Ausgang ausgegeben. Wird ein Filter aktiviert\\, ohne das Items konfiguriert werden\\, so sprechen wir hier von einem \"nicht-konfigurierten\"\\, offenen Ausgang.\n".. "Der Verteiler besitzt dazu ein Menü mit 4 Filter mit unterschiedlichen Farben\\, entsprechend den 4 Ausgängen. Soll ein Ausgang genutzt werden\\, so muss der entsprechende Filter über die \"on\" Checkbox aktiviert werden. Alle Items\\, die für diesen Filter konfiguriert sind\\, werden über den zugeordneten Ausgang ausgegeben. Wird ein Filter aktiviert\\, ohne das Items konfiguriert werden\\, so sprechen wir hier von einem \"nicht-konfigurierten\"\\, offenen Ausgang.\n"..
"\n".. "\n"..
"*Achtung: Der Verteiler ist an seinen Ausgängen gleichzeitig ein Schieber. Daher niemals die Gegenstände mit einem Schieber aus dem Verteiler ziehen!*\n"..
"\n"..
"Für einen nicht-konfigurierten Ausgang gibt es zwei Betriebsarten:\n".. "Für einen nicht-konfigurierten Ausgang gibt es zwei Betriebsarten:\n"..
"\n".. "\n"..
"1) Alle Items ausgeben\\, die an keine anderen Ausgängen ausgegeben werden können\\, auch wenn diese blockiert sind.\n".. "1) Alle Items ausgeben\\, die an keine anderen Ausgängen ausgegeben werden können\\, auch wenn diese blockiert sind.\n"..
@ -649,6 +662,21 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"Um TA2 Maschinen über das Stromnetz betreiben zu können\\, wird der TA3 Elektromotor benötigt. Dieser wandelt Strom in Achsenkraft um.\n"..
"Wird der Elektromotor nicht mit ausreichend Strom versorgt\\, geht er in einen Fehlerzustand und muss über einen Rechtsklick wieder aktiviert werden.\n"..
"\n"..
"Das Elektromotor nimmt primär max. 40 ku an Strom auf und gibt sekundär max. 39 ku als Achsenkraft wieder ab. Er verbraucht also ein ku für die Umwandlung.\n"..
"\n"..
"\n"..
"\n",
"Das Strom-Terminal muss mit dem Stromnetz verbunden werden. Es zeigt Daten aus dem Stromnetz an.\n"..
"\n"..
"In der oberen Hälfte werden nur die Daten eines ausgewählten Typs ausgegeben. Wird als Typ bspw. \"Kraftwerk\" gewählt\\, so werden nur die Daten von Öl- und Kohlekraftwerken gesammelt und ausgegeben. Links werden die Daten von Generatoren (Stromabgabe) und rechts die Daten von Energiespeichern (Stromaufnahme) ausgegeben. Beim Akkublocks bspw. wird beides ausgegeben\\, da der Akku Strom aufnehmen und abgeben kann.\n"..
"\n"..
"In der unteren Hälfte werden die Daten aller Generatoren und Speichersystemen des ganzen Stromnetzen zusammengefasst ausgegeben.\n"..
"\n"..
"\n"..
"\n",
"Der TA3 Industrieofen dient als Ergänzung zu normalen Ofen (furnace). Damit können alle Waren mit \"Koch\" Rezepten\\, auch im Industrieofen hergestellt werden. Es gibt aber auch spezielle Rezepte\\, die nur im Industrieofen hergestellt werden können.\n".. "Der TA3 Industrieofen dient als Ergänzung zu normalen Ofen (furnace). Damit können alle Waren mit \"Koch\" Rezepten\\, auch im Industrieofen hergestellt werden. Es gibt aber auch spezielle Rezepte\\, die nur im Industrieofen hergestellt werden können.\n"..
"Der Industrieofen hat sein eigenes Menü zur Rezeptauswahl. Abhängig von den Waren im Industrieofen Inventar links kann rechts das Ausgangsprodukt gewählt werden.\n".. "Der Industrieofen hat sein eigenes Menü zur Rezeptauswahl. Abhängig von den Waren im Industrieofen Inventar links kann rechts das Ausgangsprodukt gewählt werden.\n"..
"\n".. "\n"..
@ -935,7 +963,7 @@ techage.manual_DE.aText = {
" - 'pub' schalte in den öffentlichen Modus um\n".. " - 'pub' schalte in den öffentlichen Modus um\n"..
" - 'priv' schalte in den privaten Modus um\n".. " - 'priv' schalte in den privaten Modus um\n"..
"\n".. "\n"..
"Im privaten Modul kann nur der Besitzer selbst Kommandos eingeben oder Tasten nutzen.\n".. "Im privaten Modus (private) kann das Terminal nur von Spielern verwendet werden\\, die an diesem Ort bauen können\\, also Protection Rechte besitzen. Im öffentlichen Modus (public) können alle Spieler die vorkonfigurierten Tasten verwenden.\n"..
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
@ -1070,10 +1098,11 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"Eine Windkraftanlagen liefern immer dann Strom\\, wenn Wind vorhanden ist. Im Spiel gibt es keinen Wind\\, aber die Mod simuliert dies dadurch\\, dass sich nur morgens (5:00 - 9:00) und abends (17:00 - 21:00) die Windräder drehen und damit Strom liefern\\, sofern diese an geeigneten Stellen errichtet werden.\n".. "Eine Windkraftanlage liefern immer dann Strom\\, wenn Wind vorhanden ist. Im Spiel gibt es keinen Wind\\, aber die Mod simuliert dies dadurch\\, dass sich nur morgens (5:00 - 9:00) und abends (17:00 - 21:00) die Windräder drehen. Eine Windkraftanlage liefert nur dann Strom\\, wenn sie an einer geeigneten Stelle aufgestellt ist.\n"..
"\n".. "\n"..
"Die TA Windkraftanlagen sind reine Offshore Anlagen\\, das heißt\\, die müssen im Meer (Wasser) errichtet werden. Dies bedeutet\\, dass um den Mast herum mit einem Abstand von 20 Blöcken nur Wasser sein darf und das mindestens 2 Blöcke tief.\n".. "Die TA Windkraftanlagen sind reine Offshore Anlagen\\, das heißt\\, die müssen im Meer errichtet werden. Dies bedeutet\\, dass Windkraftanlagen nur in einem Meer (occean) Biom errichtet werden können und dass um den Mast herum ausreichend Wasser und freie Sicht vorhanden sein müssen.\n"..
"Der Rotor muss in einer Höhe (Y-Koordinate) von 12 bis maximal 20 m platziert werden. Der Abstand zu weiteren Windkraftanlagen muss mindestens 14 m betragen.\n".. "\n"..
"Um eine geeignete Stelle zu finden\\, musst du mit dem Schraubenschlüssel (TechAge Info Werkzeug) auf das Wasser klicken. Ob diese Stelle für den Mast der Windkraftanlage geeignet ist\\, wird dir als Chat Nachricht angezeigt.\n"..
"\n".. "\n"..
"Der Strom muss vom Rotor-Block durch den Mast nach unten geführt werden. Dazu zuerst die Stromleitung nach oben ziehen und das Stromkabel dann mit TA4 Säulenblöcke \"verputzen\". Unten kann eine Arbeitsplattform errichtet werden. Der Plan rechts zeigt den Aufbau im oberen Teil.\n".. "Der Strom muss vom Rotor-Block durch den Mast nach unten geführt werden. Dazu zuerst die Stromleitung nach oben ziehen und das Stromkabel dann mit TA4 Säulenblöcke \"verputzen\". Unten kann eine Arbeitsplattform errichtet werden. Der Plan rechts zeigt den Aufbau im oberen Teil.\n"..
"\n".. "\n"..
@ -1160,7 +1189,7 @@ techage.manual_DE.aText = {
" - Hülle mit 7x7x7 Concrete Blocks\\, gefüllt mit 125 Gravel\\, Speicherkapazität: 2\\,5 Tage bei 60 ku\n".. " - Hülle mit 7x7x7 Concrete Blocks\\, gefüllt mit 125 Gravel\\, Speicherkapazität: 2\\,5 Tage bei 60 ku\n"..
" - Hülle mit 9x9x9 Concrete Blocks\\, gefüllt mit 343 Gravel\\, Speicherkapazität: 6\\,5 Tage bei 60 ku\n".. " - Hülle mit 9x9x9 Concrete Blocks\\, gefüllt mit 343 Gravel\\, Speicherkapazität: 6\\,5 Tage bei 60 ku\n"..
"\n".. "\n"..
"In der Betonhülle darf ein Fenster aus einem Obsidian Glas Block sein. Dieses muss ziemlich in der Mitte der Wand platziert werden. Durch dieses Fenster sieht man\\, ob der Speicher mehr als 80 % geladen ist. Im Plan rechts sieht man den Aufbau aus TA4 Wärmetauscher bestehend aus 3 Blöcken\\, der TA4 Turbine und dem TA4 Generator. Beim Wärmetauscher ist auf die Ausrichtung achten (der Pfeil bei Block 1 muss zur Turbine zeigen).\n".. "In der Betonhülle darf ein Fenster aus einem Obsidian Glas Block sein. Dieses muss ziemlich in der Mitte der Wand platziert werden. Durch dieses Fenster sieht man\\, ob der Speicher mehr als 80 % geladen ist. Im Plan rechts sieht man den Aufbau aus TA4 Wärmetauscher bestehend aus 3 Blöcken\\, der TA4 Turbine und dem TA4 Generator. Beim Wärmetauscher ist auf die Ausrichtung zu achten (der Pfeil bei Block 1 muss zur Turbine zeigen).\n"..
"\n".. "\n"..
"Entgegen dem Plan rechts müssen die Anschlüsse am Speicherblock auf gleicher Ebene sein (horizontal angeordnet\\, also nicht unten und oben). Die Rohrzuläufe (TA4 Pipe Inlet) müssen genau in der Mitte der Wand sein und stehen sich damit gegenüber. Als Röhren kommen die gelbel TA4 Röhren zum Einsatz. Die TA3 Dampfrohre können hier nicht verwendet werden.\n".. "Entgegen dem Plan rechts müssen die Anschlüsse am Speicherblock auf gleicher Ebene sein (horizontal angeordnet\\, also nicht unten und oben). Die Rohrzuläufe (TA4 Pipe Inlet) müssen genau in der Mitte der Wand sein und stehen sich damit gegenüber. Als Röhren kommen die gelbel TA4 Röhren zum Einsatz. Die TA3 Dampfrohre können hier nicht verwendet werden.\n"..
"Sowohl der Generator als auch der Wärmetauscher haben einen Stromanschluss und müssen mit dem Stromnetz verbunden werden.\n".. "Sowohl der Generator als auch der Wärmetauscher haben einen Stromanschluss und müssen mit dem Stromnetz verbunden werden.\n"..
@ -1349,9 +1378,9 @@ techage.manual_DE.aText = {
"Wird etwas in die Kiste gelegt\\, oder entnommen\\, oder eine der Tasten \"F1\"/\"F2\" gedrückt\\, so wird ein Event-Signal an den Lua Controller gesendet.\n".. "Wird etwas in die Kiste gelegt\\, oder entnommen\\, oder eine der Tasten \"F1\"/\"F2\" gedrückt\\, so wird ein Event-Signal an den Lua Controller gesendet.\n"..
"Die Sensor Kiste unterstützt folgende Kommandos:\n".. "Die Sensor Kiste unterstützt folgende Kommandos:\n"..
"\n".. "\n"..
" - Über 'state = $read_data(<num>\\, \"state\")' kann der Status der Kiste abgefragt werden. Mögliche Antworten sind: \"empty\"\\, \"loaded\"\\, \"full\"\n".. " - Über 'state = $send_cmnd(<num>\\, \"state\")' kann der Status der Kiste abgefragt werden. Mögliche Antworten sind: \"empty\"\\, \"loaded\"\\, \"full\"\n"..
" - Über 'name\\, action = $read_data(<num>\\, \"action\")' kann die letzte Spieleraktion abgefragt werden. 'name' ist der Spielername\\, Als 'action' wird zurückgeliefert: \"put\"\\, \"take\"\\, \"f1\"\\, \"f2\".\n".. " - Über 'name\\, action = $send_cmnd(<num>\\, \"action\")' kann die letzte Spieleraktion abgefragt werden. 'name' ist der Spielername\\, Als 'action' wird zurückgeliefert: \"put\"\\, \"take\"\\, \"f1\"\\, \"f2\".\n"..
" - Über 'stacks = $read_data(<num>\\, \"stacks\")' kann der Inhalt der Kiste ausgelesen werden. Siehe dazu: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest\n".. " - Über 'stacks = $send_cmnd(<num>\\, \"stacks\")' kann der Inhalt der Kiste ausgelesen werden. Siehe dazu: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest\n"..
" - Über '$send_cmnd(<num>\\, \"text\"\\, \"press both buttons andnput something into the chest\")' kann der Text im Menü der Sensor Kiste gesetzt werden.\n".. " - Über '$send_cmnd(<num>\\, \"text\"\\, \"press both buttons andnput something into the chest\")' kann der Text im Menü der Sensor Kiste gesetzt werden.\n"..
"\n".. "\n"..
"Über die Checkbox \"Erlaube öffentlichen Zugriff\" kann eingestellt werden\\, ob die Kiste von jedem genutzt werden darf\\, oder nur von Spielern die hier Zugriffsrechte haben.\n".. "Über die Checkbox \"Erlaube öffentlichen Zugriff\" kann eingestellt werden\\, ob die Kiste von jedem genutzt werden darf\\, oder nur von Spielern die hier Zugriffsrechte haben.\n"..
@ -1497,7 +1526,7 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"Der Kiste besitzt ein zusätzliches Kommandos für den Lua Controller:\n".. "Der Kiste besitzt ein zusätzliches Kommandos für den Lua Controller:\n"..
"\n".. "\n"..
" - 'count' dient zur Anfrage\\, wie viele Items in der Kiste sind.\nBeispiel 1: '$read_data(CHEST\\, \"count\")' --> Summe der Items über alle 8 Speicher\nBeispiel 2: '$read_data(CHEST\\, \"count\"\\, 2)' --> Anzahl der Items in Speicher 2 (zweiter von links)\n".. " - 'count' dient zur Anfrage\\, wie viele Items in der Kiste sind.\nBeispiel 1: '$send_cmnd(CHEST\\, \"count\")' --> Summe der Items über alle 8 Speicher\nBeispiel 2: '$send_cmnd(CHEST\\, \"count\"\\, 2)' --> Anzahl der Items in Speicher 2 (zweiter von links)\n"..
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
@ -1572,6 +1601,7 @@ techage.manual_DE.aItemName = {
"ta2_flywheel", "ta2_flywheel",
"ta2_steampipe", "ta2_steampipe",
"ta2_driveaxle", "ta2_driveaxle",
"ta2_generator",
"", "",
"tube", "tube",
"ta2_pusher", "ta2_pusher",
@ -1610,6 +1640,8 @@ techage.manual_DE.aItemName = {
"ta3_tinygenerator", "ta3_tinygenerator",
"ta3_akkublock", "ta3_akkublock",
"ta3_powerterminal", "ta3_powerterminal",
"ta3_motor",
"ta3_powerterminal",
"", "",
"ta3_furnacefirebox", "ta3_furnacefirebox",
"ta3_furnace", "ta3_furnace",
@ -1764,6 +1796,7 @@ techage.manual_DE.aPlanTable = {
"", "",
"", "",
"", "",
"",
"itemtransport", "itemtransport",
"", "",
"", "",
@ -1802,6 +1835,8 @@ techage.manual_DE.aPlanTable = {
"", "",
"", "",
"", "",
"",
"",
"ta3_furnace", "ta3_furnace",
"", "",
"", "",

View File

@ -28,6 +28,7 @@ techage.manual_EN.aTitel = {
"3,TA2 Flywheel", "3,TA2 Flywheel",
"3,TA2 Steam Pipes", "3,TA2 Steam Pipes",
"3,TA2 Drive Axle / TA2 Gearbox", "3,TA2 Drive Axle / TA2 Gearbox",
"3,TA2 Power Generator",
"2,Push and sort items", "2,Push and sort items",
"3,TechAge Tube", "3,TechAge Tube",
"3,TA2 Pusher", "3,TA2 Pusher",
@ -66,6 +67,7 @@ techage.manual_EN.aTitel = {
"3,TA3 Small Power Generator", "3,TA3 Small Power Generator",
"3,TA3 Battery Block", "3,TA3 Battery Block",
"3,TA3 Power Terminal", "3,TA3 Power Terminal",
"3,TA3 Electric Motor",
"2,TA3 Industrial Furnace", "2,TA3 Industrial Furnace",
"3,TA3 Furnace Oil Burner", "3,TA3 Furnace Oil Burner",
"3,TA3 Furnace Top", "3,TA3 Furnace Top",
@ -399,6 +401,14 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"The TA2 Power Generator is required to operate lamps or other power consumers on a steam engine. The TA2 Power Generator has to be connected to drive axles on one side and then supplies electricity on the other side.\n"..
"\n"..
"If the Power Generator is not supplied with sufficient power\\, it goes into an error state and must be reactivated with a right-click.\n"..
"\n"..
"The Power Generator takes max. 25 ku of axle power and provides on the other side max. 24 ku as electricity. So he consumes one ku for the conversion.\n"..
"\n"..
"\n"..
"\n",
"In order to transport objects from one processing station to the next\\, pushers and tubes are used. See plan.\n".. "In order to transport objects from one processing station to the next\\, pushers and tubes are used. See plan.\n"..
"\n".. "\n"..
"\n".. "\n"..
@ -424,6 +434,8 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"The distributor has a menu with 4 filters with different colors\\, corresponding to the 4 outputs. If an output is to be used\\, the corresponding filter must be activated via the \"on\" checkbox. All items that are configured for this filter are output via the assigned output. If a filter is activated without items being configured\\, we are talking about an \"unconfigured\"\\, open output.\n".. "The distributor has a menu with 4 filters with different colors\\, corresponding to the 4 outputs. If an output is to be used\\, the corresponding filter must be activated via the \"on\" checkbox. All items that are configured for this filter are output via the assigned output. If a filter is activated without items being configured\\, we are talking about an \"unconfigured\"\\, open output.\n"..
"\n".. "\n"..
"*Attention: The distributor is also a pusher at its output sides. Therefore\\, never pull items out of the distributor with a pusher!*\n"..
"\n"..
"There are two operating modes for a non-configured output:\n".. "There are two operating modes for a non-configured output:\n"..
"\n".. "\n"..
"1) Output all items that cannot be output to any other exit\\, even if they are blocked.\n".. "1) Output all items that cannot be output to any other exit\\, even if they are blocked.\n"..
@ -649,6 +661,13 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"The TA3 Electric Motor is required in order to be able to operate TA2 machines via the power grid. The TA3 Electric Motor converts electricity into axle power.\n"..
"If the electric motor is not supplied with sufficient power\\, it goes into an fault state and must be reactivated with a right-click.\n"..
"\n"..
"The electric motor takes max. 40 ku of electricity and provides on the other side max. 39 ku as axle power. So he consumes one ku for the conversion.\n"..
"\n"..
"\n"..
"\n",
"The TA3 industrial furnace serves as a supplement to normal furnaces. This means that all goods can be produced with \"cooking\" recipes\\, even in an industrial furnace. But there are also special recipes that can only be made in an industrial furnace.\n".. "The TA3 industrial furnace serves as a supplement to normal furnaces. This means that all goods can be produced with \"cooking\" recipes\\, even in an industrial furnace. But there are also special recipes that can only be made in an industrial furnace.\n"..
"The industrial furnace has its own menu for recipe selection. Depending on the goods in the industrial furnace inventory on the left\\, the output product can be selected on the right.\n".. "The industrial furnace has its own menu for recipe selection. Depending on the goods in the industrial furnace inventory on the left\\, the output product can be selected on the right.\n"..
"\n".. "\n"..
@ -933,7 +952,9 @@ techage.manual_EN.aText = {
" - 'pub' switch to public mode\n".. " - 'pub' switch to public mode\n"..
" - 'priv' switch to private mode\n".. " - 'priv' switch to private mode\n"..
"\n".. "\n"..
"In the private mode\\, only the owner can enter commands himself or use keys.\n".. "In private mode\\, the terminal can only be used by players who can build at this location\\, i.e. who have protection rights.\n"..
"\n"..
"In public mode\\, all players can use the preconfigured keys.\n"..
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
@ -1060,10 +1081,11 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"A wind turbine always delivers electricity when there is wind. There is no wind in the game\\, but the mod simulates this by only turning the wind turbines in the morning (5:00 a.m. - 9:00 a.m.) and in the evening (5:00 p.m. - 9:00 p.m.) and thus supplying electricity\\, provided they are positioned appropriately.\n".. "A wind turbine always supplies electricity when there is wind. There is no wind in the game\\, but the mod simulates this by turning the wind turbines only in the morning (5:00 - 9:00) and in the evening (17:00 - 21:00). A wind turbine only supplies electricity if it is set up in a suitable location.\n"..
"\n".. "\n"..
"The TA wind turbines are pure offshore plants\\, which means that they have to be installed in the sea (water). This means that there must be in the minimum 20 blocks of water around the mast and at least 2 blocks deep.\n".. "The TA wind power plants are pure offshore plants\\, which means that they have to be built in the sea. This means that wind turbines can only be build in a sea (occean) biome and that there must be sufficient water and a clear view around the mast.\n"..
"The rotor must be placed at a height (Y coordinate) of 12 to a maximum of 20 m. The distance to other wind turbines must be at least 14 m.\n".. "\n"..
"To find a suitable spot\\, click on the water with the wrench (TechAge Info Tool). A chat message will show you whether this position is suitable for the mast of the wind turbine.\n"..
"\n".. "\n"..
"The current must be led from the rotor block down through the mast. First pull the power line up and then \"plaster\" the power cable with TA4 pillar blocks. A work platform can be built below. The plan on the right shows the structure in the upper part.\n".. "The current must be led from the rotor block down through the mast. First pull the power line up and then \"plaster\" the power cable with TA4 pillar blocks. A work platform can be built below. The plan on the right shows the structure in the upper part.\n"..
"\n".. "\n"..
@ -1340,9 +1362,9 @@ techage.manual_EN.aText = {
"If something is put into the box or removed\\, or one of the \"F1\" / \"F2\" keys is pressed\\, an event signal is sent to the Lua controller.\n".. "If something is put into the box or removed\\, or one of the \"F1\" / \"F2\" keys is pressed\\, an event signal is sent to the Lua controller.\n"..
"The sensor box supports the following commands:\n".. "The sensor box supports the following commands:\n"..
"\n".. "\n"..
" - The status of the box can be queried via 'state = $read_data(<num>\\, \"state\")'. Possible answers are: \"empty\"\\, \"loaded\"\\, \"full\"\n".. " - The status of the box can be queried via 'state = $send_cmnd(<num>\\, \"state\")'. Possible answers are: \"empty\"\\, \"loaded\"\\, \"full\"\n"..
" - The last player action can be queried via 'name\\, action = $read_data(<num>\\, \"action\")'. 'name' is the player name. One of the following is returned as 'action': \"put\"\\, \"take\"\\, \"f1\"\\, \"f2\".\n".. " - The last player action can be queried via 'name\\, action = $send_cmnd(<num>\\, \"action\")'. 'name' is the player name. One of the following is returned as 'action': \"put\"\\, \"take\"\\, \"f1\"\\, \"f2\".\n"..
" - The contents of the box can be read out via 'stacks = $read_data(<num>\\, \"stacks\")'. See: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest\n".. " - The contents of the box can be read out via 'stacks = $send_cmnd(<num>\\, \"stacks\")'. See: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest\n"..
" - Via '$send_cmnd(<num>\\, \"text\"\\, \"press both buttons andnput something into the chest\")' the text can be set in the menu of the sensor box.\n".. " - Via '$send_cmnd(<num>\\, \"text\"\\, \"press both buttons andnput something into the chest\")' the text can be set in the menu of the sensor box.\n"..
"\n".. "\n"..
"The checkbox \"Allow public chest access\" can be used to set whether the box can be used by everyone or only by players who have access/protection rights here.\n".. "The checkbox \"Allow public chest access\" can be used to set whether the box can be used by everyone or only by players who have access/protection rights here.\n"..
@ -1471,7 +1493,7 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"If the chest is filled with a pusher\\, all stores fill from left to right. If all 8 stores are full and no further items can be added\\, further items are rejected.\n".. "If the chest is filled with a pusher\\, all stores fill from left to right. If all 8 stores are full and no further items can be added\\, further items are rejected.\n"..
"\n".. "\n"..
"* Row function *\n".. "*Row function*\n"..
"\n".. "\n"..
"Several TA4 8x2000 chests can be connected to a large chest with more content. To do this\\, the chests must be placed in a row one after the other.\n".. "Several TA4 8x2000 chests can be connected to a large chest with more content. To do this\\, the chests must be placed in a row one after the other.\n"..
"\n".. "\n"..
@ -1488,7 +1510,7 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"The chest has an additional command for the Lua controller:\n".. "The chest has an additional command for the Lua controller:\n"..
"\n".. "\n"..
" - 'count' is used to request how many items are in the chest.\nExample 1: '$read_data(CHEST\\, \"count\")' -> Sum of items across all 8 stores\nExample 2: '$read_data(CHEST\\, \"count\"\\, 2)' -> number of items in store 2 (second from left)\n".. " - 'count' is used to request how many items are in the chest.\nExample 1: '$send_cmnd(CHEST\\, \"count\")' -> Sum of items across all 8 stores\nExample 2: '$send_cmnd(CHEST\\, \"count\"\\, 2)' -> number of items in store 2 (second from left)\n"..
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
@ -1563,6 +1585,7 @@ techage.manual_EN.aItemName = {
"ta2_flywheel", "ta2_flywheel",
"ta2_steampipe", "ta2_steampipe",
"ta2_driveaxle", "ta2_driveaxle",
"ta2_generator",
"", "",
"tube", "tube",
"ta2_pusher", "ta2_pusher",
@ -1601,6 +1624,7 @@ techage.manual_EN.aItemName = {
"ta3_tinygenerator", "ta3_tinygenerator",
"ta3_akkublock", "ta3_akkublock",
"ta3_powerterminal", "ta3_powerterminal",
"ta3_motor",
"", "",
"ta3_furnacefirebox", "ta3_furnacefirebox",
"ta3_furnace", "ta3_furnace",
@ -1755,6 +1779,7 @@ techage.manual_EN.aPlanTable = {
"", "",
"", "",
"", "",
"",
"itemtransport", "itemtransport",
"", "",
"", "",
@ -1793,6 +1818,7 @@ techage.manual_EN.aPlanTable = {
"", "",
"", "",
"", "",
"",
"ta3_furnace", "ta3_furnace",
"", "",
"", "",

View File

@ -185,7 +185,7 @@ local PN270 = {"techage_gaspipe_knee.png^[transformR270", "techage:ta4_pipeS"}
techage.ConstructionPlans["ta3_tank"] = { techage.ConstructionPlans["ta3_tank"] = {
{false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false},
{false, Tubes, PushR, Tubes, Fillr, Tubes, PushR, Tubes, false, false}, {false, Tubes, PushR, Tubes, Fillr, Tubes, PushR, Tubes, false, false},
{false, false, false, false, TANK3, PIPEH, PIPEH, Pump, PIPEH, Tank}, {false, false, false, false, TANK3, PIPEH, PIPEH, Pump, PIPEH, false},
{false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false},
} }

View File

@ -32,7 +32,7 @@ local function formspec(self, pos, nvm)
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
power.formspec_label_bar(0, 0.8, S("Electricity"), PWR_CAPA, nvm.provided).. power.formspec_label_bar(pos, 0, 0.8, S("Electricity"), PWR_CAPA, nvm.provided)..
"image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]" "tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]"
end end

View File

@ -44,8 +44,8 @@ local function formspec(self, pos, nvm)
default.gui_slots.. default.gui_slots..
"box[0,-0.1;5.8,0.5;#c6e8ff]".. "box[0,-0.1;5.8,0.5;#c6e8ff]"..
"label[2,-0.1;"..minetest.colorize( "#000000", S("Heat Exchanger")).."]".. "label[2,-0.1;"..minetest.colorize( "#000000", S("Heat Exchanger")).."]"..
power.formspec_label_bar(0, 0.8, S("Electricity"), needed_max, needed).. power.formspec_label_bar(pos, 0, 0.8, S("Electricity"), needed_max, needed)..
power.formspec_label_bar(3.5, 0.8, S("Thermal"), capa_max, capa, "").. power.formspec_label_bar(pos, 3.5, 0.8, S("Thermal"), capa_max, capa, "")..
arrow.. arrow..
"image_button[2.5,3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.5,3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.5,3;1,1;"..self:get_state_tooltip(nvm).."]" "tooltip[2.5,3;1,1;"..self:get_state_tooltip(nvm).."]"

View File

@ -111,7 +111,7 @@ local function process(inv, recipe, output)
if recipe.waste then if recipe.waste then
local leftover = inv:add_item("dst", ItemStack(recipe.waste)) local leftover = inv:add_item("dst", ItemStack(recipe.waste))
if leftover:get_count() > 0 then if leftover:get_count() > 0 then
inv:set_list("src", leftover) inv:add_item("src", leftover)
return techage.BLOCKED return techage.BLOCKED
end end
end end

View File

@ -242,7 +242,12 @@ local tubing = {
end end
end, end,
on_recv_message = function(pos, src, topic, payload) on_recv_message = function(pos, src, topic, payload)
if topic == "output" then
local nvm = techage.get_nvm(pos)
return string.split(nvm.output or "unknown", " ")[1]
else
return CRD(pos).State:on_receive_message(pos, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end, end,
} }

View File

@ -44,7 +44,7 @@ local function formspec(self, pos, nvm)
default.gui_slots.. default.gui_slots..
"box[0,-0.1;5.8,0.5;#c6e8ff]".. "box[0,-0.1;5.8,0.5;#c6e8ff]"..
"label[2.5,-0.1;"..minetest.colorize( "#000000", S("Electrolyzer")).."]".. "label[2.5,-0.1;"..minetest.colorize( "#000000", S("Electrolyzer")).."]"..
techage.power.formspec_label_bar(0.1, 0.8, S("Electricity"), PWR_NEEDED, nvm.taken).. techage.power.formspec_label_bar(pos, 0.1, 0.8, S("Electricity"), PWR_NEEDED, nvm.taken)..
arrow.. arrow..
"image_button[3,2.5;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[3,2.5;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3,2.5;1,1;"..self:get_state_tooltip(nvm).."]".. "tooltip[3,2.5;1,1;"..self:get_state_tooltip(nvm).."]"..
@ -156,6 +156,15 @@ local function after_dig_node(pos, oldnode, oldmetadata, digger)
Cable:after_dig_node(pos) Cable:after_dig_node(pos)
end end
local function put(pos, indir, name, amount)
local leftover = liquid.srv_put(pos, indir, name, amount)
if techage.is_activeformspec(pos) then
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(State, pos, nvm))
end
return leftover
end
local function tubelib2_on_update2(pos, outdir, tlib2, node) local function tubelib2_on_update2(pos, outdir, tlib2, node)
if tlib2.tube_type == "pipe2" then if tlib2.tube_type == "pipe2" then
liquid.update_network(pos, outdir, tlib2) liquid.update_network(pos, outdir, tlib2)
@ -182,14 +191,8 @@ local netw_def = {
local liquid_def = { local liquid_def = {
capa = CAPACITY, capa = CAPACITY,
peek = liquid.srv_peek, peek = liquid.srv_peek,
put = function(pos, indir, name, amount) put = put,
local leftover = liquid.srv_put(pos, indir, name, amount) untake = put,
if techage.is_activeformspec(pos) then
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(State, pos, nvm))
end
return leftover
end,
take = function(pos, indir, name, amount) take = function(pos, indir, name, amount)
amount, name = liquid.srv_take(pos, indir, name, amount) amount, name = liquid.srv_take(pos, indir, name, amount)
if techage.is_activeformspec(pos) then if techage.is_activeformspec(pos) then

View File

@ -48,7 +48,7 @@ local function formspec(self, pos, nvm)
arrow.. arrow..
"image_button[2,2.5;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2,2.5;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2,2.5;1,1;"..self:get_state_tooltip(nvm).."]".. "tooltip[2,2.5;1,1;"..self:get_state_tooltip(nvm).."]"..
techage.power.formspec_label_bar(3.5, 0.8, S("Electricity"), PWR_CAPA, nvm.given) techage.power.formspec_label_bar(pos, 3.5, 0.8, S("Electricity"), PWR_CAPA, nvm.given)
end end
local function start_node(pos, nvm, state) local function start_node(pos, nvm, state)

View File

@ -1,79 +1,448 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Script to generate the template file and update the translation files. # Script to generate the template file and update the translation files.
# Copy the script into the mod or modpack root folder and run it there.
# #
# Copyright (C) 2019 Joachim Stolberg # Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer
# LGPLv2.1+ # LGPLv2.1+
# #
# Copy the script into the mod root folder and adapt the last code lines to you needs. # See https://github.com/minetest-tools/update_translations for
# potential future updates to this script.
from __future__ import print_function from __future__ import print_function
import os, fnmatch, re, shutil import os, fnmatch, re, shutil, errno
from sys import argv as _argv
from sys import stderr as _stderr
pattern_lua = re.compile(r'[ \.=^\t]S\("(.+?)"\)', re.DOTALL) # Running params
pattern_tr = re.compile(r'(.+?[^@])=(.+)') params = {"recursive": False,
"help": False,
"mods": False,
"verbose": False,
"folders": [],
"no-old-file": False
}
# Available CLI options
options = {"recursive": ['--recursive', '-r'],
"help": ['--help', '-h'],
"mods": ['--installed-mods'],
"verbose": ['--verbose', '-v'],
"no-old-file": ['--no-old-file']
}
def gen_template(templ_file, lkeyStrings): # Strings longer than this will have extra space added between
lOut = [] # them in the translation files to make it easier to distinguish their
lkeyStrings.sort() # beginnings and endings at a glance
for s in lkeyStrings: doublespace_threshold = 60
lOut.append("%s=" % s)
open(templ_file, "wt").write("\n".join(lOut))
def set_params_folders(tab: list):
'''Initialize params["folders"] from CLI arguments.'''
# Discarding argument 0 (tool name)
for param in tab[1:]:
stop_param = False
for option in options:
if param in options[option]:
stop_param = True
break
if not stop_param:
params["folders"].append(os.path.abspath(param))
def set_params(tab: list):
'''Initialize params from CLI arguments.'''
for option in options:
for option_name in options[option]:
if option_name in tab:
params[option] = True
break
def print_help(name):
'''Prints some help message.'''
print(f'''SYNOPSIS
{name} [OPTIONS] [PATHS...]
DESCRIPTION
{', '.join(options["help"])}
prints this help message
{', '.join(options["recursive"])}
run on all subfolders of paths given
{', '.join(options["mods"])}
run on locally installed modules
{', '.join(options["no-old-file"])}
do not create *.old files
{', '.join(options["verbose"])}
add output information
''')
def main():
'''Main function'''
set_params(_argv)
set_params_folders(_argv)
if params["help"]:
print_help(_argv[0])
elif params["recursive"] and params["mods"]:
print("Option --installed-mods is incompatible with --recursive")
else:
# Add recursivity message
print("Running ", end='')
if params["recursive"]:
print("recursively ", end='')
# Running
if params["mods"]:
print(f"on all locally installed modules in {os.path.abspath('~/.minetest/mods/')}")
run_all_subfolders("~/.minetest/mods")
elif len(params["folders"]) >= 2:
print("on folder list:", params["folders"])
for f in params["folders"]:
if params["recursive"]:
run_all_subfolders(f)
else:
update_folder(f)
elif len(params["folders"]) == 1:
print("on folder", params["folders"][0])
if params["recursive"]:
run_all_subfolders(params["folders"][0])
else:
update_folder(params["folders"][0])
else:
print("on folder", os.path.abspath("./"))
if params["recursive"]:
run_all_subfolders(os.path.abspath("./"))
else:
update_folder(os.path.abspath("./"))
#group 2 will be the string, groups 1 and 3 will be the delimiters (" or ')
#See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
pattern_lua_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
pattern_lua_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
pattern_lua_bracketed_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
pattern_lua_bracketed_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
# Handles "concatenation" .. " of strings"
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
pattern_tr = re.compile(r'(.*?[^@])=(.*)')
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
pattern_tr_filename = re.compile(r'\.tr$')
pattern_po_language_code = re.compile(r'(.*)\.po$')
#attempt to read the mod's name from the mod.conf file. Returns None on failure
def get_modname(folder):
try:
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
for line in mod_conf:
match = pattern_name.match(line)
if match:
return match.group(1)
except FileNotFoundError:
pass
return None
#If there are already .tr files in /locale, returns a list of their names
def get_existing_tr_files(folder):
out = []
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
if pattern_tr_filename.search(name):
out.append(name)
return out
# A series of search and replaces that massage a .po file's contents into
# a .tr file's equivalent
def process_po_file(text):
# The first three items are for unused matches
text = re.sub(r'#~ msgid "', "", text)
text = re.sub(r'"\n#~ msgstr ""\n"', "=", text)
text = re.sub(r'"\n#~ msgstr "', "=", text)
# comment lines
text = re.sub(r'#.*\n', "", text)
# converting msg pairs into "=" pairs
text = re.sub(r'msgid "', "", text)
text = re.sub(r'"\nmsgstr ""\n"', "=", text)
text = re.sub(r'"\nmsgstr "', "=", text)
# various line breaks and escape codes
text = re.sub(r'"\n"', "", text)
text = re.sub(r'"\n', "\n", text)
text = re.sub(r'\\"', '"', text)
text = re.sub(r'\\n', '@n', text)
# remove header text
text = re.sub(r'=Project-Id-Version:.*\n', "", text)
# remove double-spaced lines
text = re.sub(r'\n\n', '\n', text)
return text
# Go through existing .po files and, if a .tr file for that language
# *doesn't* exist, convert it and create it.
# The .tr file that results will subsequently be reprocessed so
# any "no longer used" strings will be preserved.
# Note that "fuzzy" tags will be lost in this process.
def process_po_files(folder, modname):
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
code_match = pattern_po_language_code.match(name)
if code_match == None:
continue
language_code = code_match.group(1)
tr_name = modname + "." + language_code + ".tr"
tr_file = os.path.join(root, tr_name)
if os.path.exists(tr_file):
if params["verbose"]:
print(f"{tr_name} already exists, ignoring {name}")
continue
fname = os.path.join(root, name)
with open(fname, "r", encoding='utf-8') as po_file:
if params["verbose"]:
print(f"Importing translations from {name}")
text = process_po_file(po_file.read())
with open(tr_file, "wt", encoding='utf-8') as tr_out:
tr_out.write(text)
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
# Creates a directory if it doesn't exist, silently does
# nothing if it already exists
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
# Converts the template dictionary to a text to be written as a file
# dKeyStrings is a dictionary of localized string to source file sets
# dOld is a dictionary of existing translations and comments from
# the previous version of this text
def strings_to_text(dkeyStrings, dOld, mod_name, header_comments):
lOut = [f"# textdomain: {mod_name}\n"]
if header_comments is not None:
lOut.append(header_comments)
dGroupedBySource = {}
for key in dkeyStrings:
sourceList = list(dkeyStrings[key])
sourceList.sort()
sourceString = "\n".join(sourceList)
listForSource = dGroupedBySource.get(sourceString, [])
listForSource.append(key)
dGroupedBySource[sourceString] = listForSource
lSourceKeys = list(dGroupedBySource.keys())
lSourceKeys.sort()
for source in lSourceKeys:
localizedStrings = dGroupedBySource[source]
localizedStrings.sort()
lOut.append("")
lOut.append(source)
lOut.append("")
for localizedString in localizedStrings:
val = dOld.get(localizedString, {})
translation = val.get("translation", "")
comment = val.get("comment")
if len(localizedString) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{localizedString}={translation}")
if len(localizedString) > doublespace_threshold:
lOut.append("")
unusedExist = False
for key in dOld:
if key not in dkeyStrings:
val = dOld[key]
translation = val.get("translation")
comment = val.get("comment")
# only keep an unused translation if there was translated
# text or a comment associated with it
if translation != None and (translation != "" or comment):
if not unusedExist:
unusedExist = True
lOut.append("\n\n##### not used anymore #####\n")
if len(key) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{key}={translation}")
if len(key) > doublespace_threshold:
lOut.append("")
return "\n".join(lOut) + '\n'
# Writes a template.txt file
# dkeyStrings is the dictionary returned by generate_template
def write_template(templ_file, dkeyStrings, mod_name):
# read existing template file to preserve comments
existing_template = import_tr_file(templ_file)
text = strings_to_text(dkeyStrings, existing_template[0], mod_name, existing_template[2])
mkdir_p(os.path.dirname(templ_file))
with open(templ_file, "wt", encoding='utf-8') as template_file:
template_file.write(text)
# Gets all translatable strings from a lua file
def read_lua_file_strings(lua_file): def read_lua_file_strings(lua_file):
lOut = [] lOut = []
text = open(lua_file).read() with open(lua_file, encoding='utf-8') as text_file:
for s in pattern_lua.findall(text): text = text_file.read()
#TODO remove comments here
text = re.sub(pattern_concat, "", text)
strings = []
for s in pattern_lua_s.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed_s.findall(text):
strings.append(s)
for s in pattern_lua_fs.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed_fs.findall(text):
strings.append(s)
for s in strings:
s = re.sub(r'"\.\.\s+"', "", s) s = re.sub(r'"\.\.\s+"', "", s)
s = re.sub("@[^@=n]", "@@", s) s = re.sub("@[^@=0-9]", "@@", s)
s = s.replace('\\"', '"')
s = s.replace("\\'", "'")
s = s.replace("\n", "@n") s = s.replace("\n", "@n")
s = s.replace("\\n", "@n") s = s.replace("\\n", "@n")
s = s.replace("=", "@=") s = s.replace("=", "@=")
lOut.append(s) lOut.append(s)
return lOut return lOut
def inport_tr_file(tr_file): # Gets strings from an existing translation file
# returns both a dictionary of translations
# and the full original source text so that the new text
# can be compared to it for changes.
# Returns also header comments in the third return value.
def import_tr_file(tr_file):
dOut = {} dOut = {}
text = None
header_comment = None
if os.path.exists(tr_file): if os.path.exists(tr_file):
for line in open(tr_file, "r").readlines(): with open(tr_file, "r", encoding='utf-8') as existing_file :
s = line.strip() # save the full text to allow for comparison
if s == "" or s[0] == "#": # of the old version with the new output
continue text = existing_file.read()
match = pattern_tr.match(s) existing_file.seek(0)
if match: # a running record of the current comment block
dOut[match.group(1)] = match.group(2) # we're inside, to allow preceeding multi-line comments
return dOut # to be retained for a translation line
latest_comment_block = None
for line in existing_file.readlines():
line = line.rstrip('\n')
if line[:3] == "###":
if header_comment is None:
# Save header comments
header_comment = latest_comment_block or ""
# Stip textdomain line
tmp_h_c = ""
for l in header_comment.split('\n'):
if not l.startswith("# textdomain:"):
tmp_h_c += l + '\n'
header_comment = tmp_h_c
def generate_template(templ_file): # Reset comment block if we hit a header
lOut = [] latest_comment_block = None
for root, dirs, files in os.walk('./'): continue
if line[:1] == "#":
# Save the comment we're inside
if not latest_comment_block:
latest_comment_block = line
else:
latest_comment_block = latest_comment_block + "\n" + line
continue
match = pattern_tr.match(line)
if match:
# this line is a translated line
outval = {}
outval["translation"] = match.group(2)
if latest_comment_block:
# if there was a comment, record that.
outval["comment"] = latest_comment_block
latest_comment_block = None
dOut[match.group(1)] = outval
return (dOut, text, header_comment)
# Walks all lua files in the mod folder, collects translatable strings,
# and writes it to a template.txt file
# Returns a dictionary of localized strings to source file sets
# that can be used with the strings_to_text function.
def generate_template(folder, mod_name):
dOut = {}
for root, dirs, files in os.walk(folder):
for name in files: for name in files:
if fnmatch.fnmatch(name, "*.lua"): if fnmatch.fnmatch(name, "*.lua"):
fname = os.path.join(root, name) fname = os.path.join(root, name)
found = read_lua_file_strings(fname) found = read_lua_file_strings(fname)
print(fname, len(found)) if params["verbose"]:
lOut.extend(found) print(f"{fname}: {str(len(found))} translatable strings")
lOut = list(set(lOut))
lOut.sort()
gen_template(templ_file, lOut)
return lOut
def update_tr_file(lNew, mod_name, tr_file): for s in found:
lOut = ["# textdomain: %s\n" % mod_name] sources = dOut.get(s, set())
if os.path.exists(tr_file): sources.add(f"### {os.path.basename(fname)} ###")
shutil.copyfile(tr_file, tr_file+".old") dOut[s] = sources
dOld = inport_tr_file(tr_file)
for key in lNew:
val = dOld.get(key, "")
lOut.append("%s=%s" % (key, val))
lOut.append("##### not used anymore #####")
for key in dOld:
if key not in lNew:
lOut.append("%s=%s" % (key, dOld[key]))
open(tr_file, "w").write("\n".join(lOut))
data = generate_template("./locale/template.txt") if len(dOut) == 0:
update_tr_file(data, "techage", "./locale/techage.de.tr") return None
#update_tr_file(data, "techage", "./locale/techage.fr.tr") templ_file = os.path.join(folder, "locale/template.txt")
print("Done.\n") write_template(templ_file, dOut, mod_name)
return dOut
# Updates an existing .tr file, copying the old one to a ".old" file
# if any changes have happened
# dNew is the data used to generate the template, it has all the
# currently-existing localized strings
def update_tr_file(dNew, mod_name, tr_file):
if params["verbose"]:
print(f"updating {tr_file}")
tr_import = import_tr_file(tr_file)
dOld = tr_import[0]
textOld = tr_import[1]
textNew = strings_to_text(dNew, dOld, mod_name, tr_import[2])
if textOld and textOld != textNew:
print(f"{tr_file} has changed.")
if not params["no-old-file"]:
shutil.copyfile(tr_file, f"{tr_file}.old")
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
new_tr_file.write(textNew)
# Updates translation files for the mod in the given folder
def update_mod(folder):
modname = get_modname(folder)
if modname is not None:
process_po_files(folder, modname)
print(f"Updating translations for {modname}")
data = generate_template(folder, modname)
if data == None:
print(f"No translatable strings found in {modname}")
else:
for tr_file in get_existing_tr_files(folder):
update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file))
else:
print(f"\033[31mUnable to find modname in folder {folder}.\033[0m", file=_stderr)
exit(1)
# Determines if the folder being pointed to is a mod or a mod pack
# and then runs update_mod accordingly
def update_folder(folder):
is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
if is_modpack:
subfolders = [f.path for f in os.scandir(folder) if f.is_dir()]
for subfolder in subfolders:
update_mod(subfolder + "/")
else:
update_mod(folder)
print("Done.")
def run_all_subfolders(folder):
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir()]:
update_folder(modfolder + "/")
main()

View File

@ -385,13 +385,9 @@ minetest.register_node("techage:ta4_icta_controller", {
on_receive_fields = on_receive_fields, on_receive_fields = on_receive_fields,
on_dig = function(pos, node, puncher, pointed_thing) after_dig_node = function(pos, oldnode, oldmetadata)
if minetest.is_protected(pos, puncher:get_player_name()) then techage.remove_node(pos, oldnode, oldmetadata)
return techage.del_mem(pos)
end
techage.remove_node(pos)
minetest.node_dig(pos, node, puncher, pointed_thing)
end, end,
on_timer = on_timer, on_timer = on_timer,

View File

@ -14,6 +14,8 @@
local S = techage.S local S = techage.S
techage.display = {}
local NUM_ROWS = 5 local NUM_ROWS = 5
local RADIUS = 6 local RADIUS = 6
local Param2ToFacedir = {[0] = 0, 0, 3, 1, 2, 0} local Param2ToFacedir = {[0] = 0, 0, 3, 1, 2, 0}
@ -33,7 +35,7 @@ local function lcdlib_bugfix(text_tbl)
return "" return ""
end end
local function display_update(pos, objref) function techage.display.display_update(pos, objref)
pos = vector.round(pos) pos = vector.round(pos)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
local text = lcdlib_bugfix(nvm.text) local text = lcdlib_bugfix(nvm.text)
@ -44,7 +46,7 @@ local function display_update(pos, objref)
visual_size = {x=0.94, y=0.94} }) visual_size = {x=0.94, y=0.94} })
end end
local function display_updateXL(pos, objref) function techage.display.display_updateXL(pos, objref)
pos = vector.round(pos) pos = vector.round(pos)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
local text = lcdlib_bugfix(nvm.text) local text = lcdlib_bugfix(nvm.text)
@ -55,7 +57,7 @@ local function display_updateXL(pos, objref)
visual_size = {x=0.94*1.9, y=0.94} }) visual_size = {x=0.94*1.9, y=0.94} })
end end
local function on_timer(pos) function techage.display.on_timer(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
mem.ticks = mem.ticks or 0 mem.ticks = mem.ticks or 0
@ -77,7 +79,7 @@ local function on_timer(pos)
return true return true
end end
local lcd_box = { techage.display.lcd_box = {
type = "wallmounted", type = "wallmounted",
wall_top = {-8/16, 15/32, -8/16, 8/16, 8/16, 8/16} wall_top = {-8/16, 15/32, -8/16, 8/16, 8/16, 8/16}
} }
@ -90,13 +92,13 @@ minetest.register_node("techage:ta4_display", {
paramtype = "light", paramtype = "light",
sunlight_propagates = true, sunlight_propagates = true,
paramtype2 = "wallmounted", paramtype2 = "wallmounted",
node_box = lcd_box, node_box = techage.display.lcd_box,
selection_box = lcd_box, selection_box = techage.display.lcd_box,
light_source = 6, light_source = 6,
display_entities = { display_entities = {
["techage:display_entity"] = { depth = 0.42, ["techage:display_entity"] = { depth = 0.42,
on_display_update = display_update}, on_display_update = techage.display.display_update},
}, },
after_place_node = function(pos, placer) after_place_node = function(pos, placer)
@ -114,7 +116,7 @@ minetest.register_node("techage:ta4_display", {
techage.remove_node(pos, oldnode, oldmetadata) techage.remove_node(pos, oldnode, oldmetadata)
end, end,
on_timer = on_timer, on_timer = techage.display.on_timer,
on_place = lcdlib.on_place, on_place = lcdlib.on_place,
on_construct = lcdlib.on_construct, on_construct = lcdlib.on_construct,
on_destruct = lcdlib.on_destruct, on_destruct = lcdlib.on_destruct,
@ -124,7 +126,7 @@ minetest.register_node("techage:ta4_display", {
sounds = default.node_sound_glass_defaults(), sounds = default.node_sound_glass_defaults(),
}) })
local lcd_boxXL = { techage.display.lcd_boxXL = {
type = "fixed", type = "fixed",
fixed = {-0.9, -8/16, -8/16, 0.9, -15/32, 8/16} fixed = {-0.9, -8/16, -8/16, 0.9, -15/32, 8/16}
} }
@ -137,13 +139,13 @@ minetest.register_node("techage:ta4_displayXL", {
paramtype = "light", paramtype = "light",
sunlight_propagates = true, sunlight_propagates = true,
paramtype2 = "wallmounted", paramtype2 = "wallmounted",
node_box = lcd_boxXL, node_box = techage.display.lcd_boxXL,
selection_box = lcd_boxXL, selection_box = techage.display.lcd_boxXL,
light_source = 6, light_source = 6,
display_entities = { display_entities = {
["techage:display_entityXL"] = { depth = 0.42, ["techage:display_entityXL"] = { depth = 0.42,
on_display_update = display_updateXL}, on_display_update = techage.display.display_updateXL},
}, },
after_place_node = function(pos, placer) after_place_node = function(pos, placer)
@ -161,7 +163,7 @@ minetest.register_node("techage:ta4_displayXL", {
techage.remove_node(pos, oldnode, oldmetadata) techage.remove_node(pos, oldnode, oldmetadata)
end, end,
on_timer = on_timer, on_timer = techage.display.on_timer,
on_place = lcdlib.on_place, on_place = lcdlib.on_place,
on_construct = lcdlib.on_construct, on_construct = lcdlib.on_construct,
on_destruct = lcdlib.on_destruct, on_destruct = lcdlib.on_destruct,
@ -189,7 +191,7 @@ minetest.register_craft({
}, },
}) })
local function add_line(pos, payload, cycle_time) function techage.display.add_line(pos, payload, cycle_time)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
nvm.text = nvm.text or {} nvm.text = nvm.text or {}
@ -206,7 +208,7 @@ local function add_line(pos, payload, cycle_time)
table.insert(nvm.text, payload) table.insert(nvm.text, payload)
end end
local function write_row(pos, payload, cycle_time) function techage.display.write_row(pos, payload, cycle_time)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
nvm.text = nvm.text or {} nvm.text = nvm.text or {}
@ -227,7 +229,7 @@ local function write_row(pos, payload, cycle_time)
nvm.text[row] = str nvm.text[row] = str
end end
local function clear_screen(pos, cycle_time) function techage.display.clear_screen(pos, cycle_time)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
mem.ticks = mem.ticks or 0 mem.ticks = mem.ticks or 0
@ -242,11 +244,11 @@ end
techage.register_node({"techage:ta4_display"}, { techage.register_node({"techage:ta4_display"}, {
on_recv_message = function(pos, src, topic, payload) on_recv_message = function(pos, src, topic, payload)
if topic == "add" then -- add one line and scroll if necessary if topic == "add" then -- add one line and scroll if necessary
add_line(pos, payload, 1) techage.display.add_line(pos, payload, 1)
elseif topic == "set" then -- overwrite the given row elseif topic == "set" then -- overwrite the given row
write_row(pos, payload, 1) techage.display.write_row(pos, payload, 1)
elseif topic == "clear" then -- clear the screen elseif topic == "clear" then -- clear the screen
clear_screen(pos, 1) techage.display.clear_screen(pos, 1)
end end
end, end,
}) })
@ -254,11 +256,11 @@ techage.register_node({"techage:ta4_display"}, {
techage.register_node({"techage:ta4_displayXL"}, { techage.register_node({"techage:ta4_displayXL"}, {
on_recv_message = function(pos, src, topic, payload) on_recv_message = function(pos, src, topic, payload)
if topic == "add" then -- add one line and scroll if necessary if topic == "add" then -- add one line and scroll if necessary
add_line(pos, payload, 2) techage.display.add_line(pos, payload, 2)
elseif topic == "set" then -- overwrite the given row elseif topic == "set" then -- overwrite the given row
write_row(pos, payload, 2) techage.display.write_row(pos, payload, 2)
elseif topic == "clear" then -- clear the screen elseif topic == "clear" then -- clear the screen
clear_screen(pos, 2) techage.display.clear_screen(pos, 2)
end end
end, end,
}) })

View File

@ -13,7 +13,7 @@
techage = {} techage = {}
-- Version for compatibility checks, see readme.md/history -- Version for compatibility checks, see readme.md/history
techage.version = 0.23 techage.version = 0.25
if minetest.global_exists("tubelib") then if minetest.global_exists("tubelib") then
minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!") minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!")
@ -217,6 +217,8 @@ dofile(MP.."/oil/reboiler.lua")
-- TA3 power based -- TA3 power based
dofile(MP.."/ta3_power/tiny_generator.lua") dofile(MP.."/ta3_power/tiny_generator.lua")
dofile(MP.."/ta3_power/akkubox.lua") dofile(MP.."/ta3_power/akkubox.lua")
dofile(MP.."/ta3_power/axle2power.lua")
dofile(MP.."/ta3_power/power2axle.lua")
-- Digtron -- Digtron
if minetest.global_exists("digtron") then if minetest.global_exists("digtron") then

View File

@ -97,6 +97,7 @@ end
local function flame(pos, height, heat, first_time) local function flame(pos, height, heat, first_time)
local idx local idx
local playername = minetest.get_meta(pos):get_string("playername")
pos = {x=pos.x, y=pos.y+height, z=pos.z} pos = {x=pos.x, y=pos.y+height, z=pos.z}
for idx=heat,1,-1 do for idx=heat,1,-1 do
pos = {x=pos.x, y=pos.y+1, z=pos.z} pos = {x=pos.x, y=pos.y+1, z=pos.z}
@ -113,6 +114,9 @@ local function flame(pos, height, heat, first_time)
end end
return return
end end
if minetest.is_protected(pos, playername) then
return
end
minetest.add_node(pos, {name = "techage:flame"..math.min(idx,7)}) minetest.add_node(pos, {name = "techage:flame"..math.min(idx,7)})
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_int("heat", idx) meta:set_int("heat", idx)

View File

@ -46,7 +46,7 @@ techage.recipes.add("ta4_doser", {
-- Hydrogenate -- Hydrogenate
techage.recipes.add("ta4_doser", { techage.recipes.add("ta4_doser", {
output = "techage:bitumen 2", output = "techage:bitumen 1",
input = { input = {
"techage:fueloil 1", "techage:fueloil 1",
"techage:hydrogen 1", "techage:hydrogen 1",
@ -55,7 +55,7 @@ techage.recipes.add("ta4_doser", {
}) })
techage.recipes.add("ta4_doser", { techage.recipes.add("ta4_doser", {
output = "techage:fueloil 2", output = "techage:fueloil 1",
input = { input = {
"techage:naphtha 1", "techage:naphtha 1",
"techage:hydrogen 1", "techage:hydrogen 1",
@ -64,7 +64,7 @@ techage.recipes.add("ta4_doser", {
}) })
techage.recipes.add("ta4_doser", { techage.recipes.add("ta4_doser", {
output = "techage:naphtha 2", output = "techage:naphtha 1",
input = { input = {
"techage:gasoline 1", "techage:gasoline 1",
"techage:hydrogen 1", "techage:hydrogen 1",

View File

@ -20,6 +20,7 @@ local Cable = techage.ElectricCable
local power = techage.power local power = techage.power
local Flowers = {} local Flowers = {}
local Plants = {} local Plants = {}
local Ignore = { ["flowers:waterlily_waving"] = true }
-- 9 plant positions below the light -- 9 plant positions below the light
local Positions = { local Positions = {
{x = 0, y =-1, z = 0}, {x = 0, y =-1, z = 0},
@ -143,16 +144,20 @@ minetest.after(1, function()
if name and type(name) == "string" then if name and type(name) == "string" then
local mod = string.split(name, ":")[1] local mod = string.split(name, ":")[1]
if mod == "flowers" or mod == "bakedclay" then -- Bakedclay also registers flowers as decoration. if mod == "flowers" or mod == "bakedclay" then -- Bakedclay also registers flowers as decoration.
if not Ignore[name] then
techage.register_flower(name) techage.register_flower(name)
end end
end end
end end
end
for name,ndef in pairs(minetest.registered_nodes) do for name,ndef in pairs(minetest.registered_nodes) do
if type(name) == "string" then if type(name) == "string" then
local mod = string.split(name, ":")[1] local mod = string.split(name, ":")[1]
if mod == "farming" and ndef.on_timer then -- probably a plant that still needs to grow if mod == "farming" and ndef.on_timer then -- probably a plant that still needs to grow
if not Ignore[name] then
techage.register_plant(name) techage.register_plant(name)
end end
end end
end end
end
end) end)

View File

@ -217,6 +217,14 @@ minetest.register_node("techage:ta4_tank", {
tubelib2_on_update2 = function(pos, outdir, tlib2, node) tubelib2_on_update2 = function(pos, outdir, tlib2, node)
liquid.update_network(pos, outdir) liquid.update_network(pos, outdir)
end, end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if fields.public then
M(pos):set_int("public", fields.public == "true" and 1 or 0)
end
end,
on_timer = node_timer, on_timer = node_timer,
on_punch = liquid.on_punch, on_punch = liquid.on_punch,
after_dig_node = function(pos, oldnode, oldmetadata, digger) after_dig_node = function(pos, oldnode, oldmetadata, digger)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -222,16 +222,17 @@ minetest.register_node("techage:ta3_sequencer", {
on_receive_fields = on_receive_fields, on_receive_fields = on_receive_fields,
on_dig = function(pos, node, puncher, pointed_thing) can_dig = function(pos, puncher)
if minetest.is_protected(pos, puncher:get_player_name()) then if minetest.is_protected(pos, puncher:get_player_name()) then
return return false
end end
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if not nvm.running then return not nvm.running
techage.remove_node(pos) end,
minetest.node_dig(pos, node, puncher, pointed_thing)
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos) techage.del_mem(pos)
end
end, end,
on_timer = check_rules, on_timer = check_rules,

View File

@ -15,41 +15,23 @@
local M = minetest.get_meta local M = minetest.get_meta
local S = techage.S local S = techage.S
local HELP_TA3 = S("#### TA3 Terminal ####@n".. local HELP_TA3 = "Syntax:\n"..
"@n".. " cmd <num> <cmnd>\n"..
"Send commands to your machines@n".. "\n"..
"and output text messages from your@n".. "like: cmd 181 on\n"..
"machines to the Terminal.@n".. "or: cmd 4573 state\n"..
"@n".. "\n"..
"Command syntax:@n".. "Local commands:\n"..
" cmd <num> <cmnd>@n".. "- clear = clear screen\n"..
"@n".. "- help = this message\n"..
"example: cmd 181 on@n".. "- pub = switch to public use of buttons\n"..
"<num> is the number of the node to which the command is sent@n".. "- priv = switch to private use of buttons\n"..
"'on' is the command to turn machines/nodes on@n".. "To program a user button with a command:\n"..
"Further commands can be retrieved by clicking on@n".. " set <button-num> <button-text> <command>\n"..
"machines/nodes with the Techage Info Tool.@n".. "e.g.: set 1 ON cmd 123 on"
"@n"..
"Local commands:@n"..
"- clear = clear screen@n"..
"- help = this message@n"..
"- pub = switch to public use@n"..
"- priv = switch to private use@n"..
"To program a user button with a command:@n"..
" set <button-num> <button-text> <command>@n"..
"e.g. 'set 1 ON cmd 123 on'@n")
local CMNDS_TA3 = S("Syntax error, try help") local CMNDS_TA3 = S("Syntax error, try help")
--local function formspec1()
-- return "size[6,4]"..
-- default.gui_bg..
-- default.gui_bg_img..
-- default.gui_slots..
-- "field[0.5,1;5,1;number;Techage Controller number:;]" ..
-- "button_exit[1.5,2.5;2,1;exit;Save]"
--end
local function get_string(meta, num, default) local function get_string(meta, num, default)
local s = meta:get_string("bttn_text"..num) local s = meta:get_string("bttn_text"..num)
if not s or s == "" then if not s or s == "" then
@ -106,6 +88,7 @@ end
local function command(pos, command, player) local function command(pos, command, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner") or "" local owner = meta:get_string("owner") or ""
if command then if command then
command = command:sub(1,80) command = command:sub(1,80)
command = string.trim(command) command = string.trim(command)
@ -117,16 +100,15 @@ local function command(pos, command, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("output", HELP_TA3) meta:set_string("output", HELP_TA3)
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(meta))
elseif command == "pub" and owner == player then elseif command == "pub" then
meta:set_int("public", 1) meta:set_int("public", 1)
output(pos, player..":$ "..command) output(pos, player..":$ "..command)
output(pos, S("Switched to public use!")) output(pos, S("Switched to public use!"))
elseif command == "priv" and owner == player then elseif command == "priv" then
meta:set_int("public", 0) meta:set_int("public", 0)
output(pos, player..":$ "..command) output(pos, player..":$ "..command)
output(pos, S("Switched to private use!")) output(pos, S("Switched to private use!"))
elseif meta:get_int("public") == 1 or owner == player or else
minetest.check_player_privs(player, "server") then
output(pos, "$ "..command) output(pos, "$ "..command)
local own_num = meta:get_string("node_number") local own_num = meta:get_string("node_number")
local num, cmnd, payload = command:match('^cmd%s+([0-9]+)%s+(%w+)%s*(.*)$') local num, cmnd, payload = command:match('^cmd%s+([0-9]+)%s+(%w+)%s*(.*)$')
@ -206,16 +188,25 @@ local function register_terminal(num, tiles, node_box, selection_box)
on_receive_fields = function(pos, formname, fields, player) on_receive_fields = function(pos, formname, fields, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local public = meta:get_int("public") == 1
local protected = minetest.is_protected(pos, player:get_player_name())
if not protected then
local evt = minetest.explode_table_event(fields.output) local evt = minetest.explode_table_event(fields.output)
if evt.type == "DCL" then if evt.type == "DCL" then
local s = get_line_text(pos, evt.row) local s = get_line_text(pos, evt.row)
meta:set_string("command", s) meta:set_string("command", s)
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(meta))
return
elseif (fields.key_enter == "true" or fields.ok) and fields.cmnd ~= "" then elseif (fields.key_enter == "true" or fields.ok) and fields.cmnd ~= "" then
command(pos, fields.cmnd, player:get_player_name()) command(pos, fields.cmnd, player:get_player_name())
meta:set_string("command", "") meta:set_string("command", "")
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(meta))
elseif fields.bttn1 then send_cmnd(pos, meta, 1) return
end
end
if public or not protected then
if fields.bttn1 then send_cmnd(pos, meta, 1)
elseif fields.bttn2 then send_cmnd(pos, meta, 2) elseif fields.bttn2 then send_cmnd(pos, meta, 2)
elseif fields.bttn3 then send_cmnd(pos, meta, 3) elseif fields.bttn3 then send_cmnd(pos, meta, 3)
elseif fields.bttn4 then send_cmnd(pos, meta, 4) elseif fields.bttn4 then send_cmnd(pos, meta, 4)
@ -225,6 +216,7 @@ local function register_terminal(num, tiles, node_box, selection_box)
elseif fields.bttn8 then send_cmnd(pos, meta, 8) elseif fields.bttn8 then send_cmnd(pos, meta, 8)
elseif fields.bttn9 then send_cmnd(pos, meta, 9) elseif fields.bttn9 then send_cmnd(pos, meta, 9)
end end
end
end, end,
after_dig_node = function(pos, oldnode, oldmetadata) after_dig_node = function(pos, oldnode, oldmetadata)

View File

@ -541,13 +541,9 @@ minetest.register_node("techage:ta4_lua_controller", {
end end
end, end,
on_dig = function(pos, node, puncher, pointed_thing) after_dig_node = function(pos, oldnode, oldmetadata)
if minetest.is_protected(pos, puncher:get_player_name()) then techage.remove_node(pos, oldnode, oldmetadata)
return techage.del_mem(pos)
end
techage.remove_node(pos)
minetest.node_dig(pos, node, puncher, pointed_thing)
end, end,
on_timer = on_timer, on_timer = on_timer,
@ -631,7 +627,7 @@ techage.register_node({"techage:ta4_lua_controller"}, {
elseif topic == "term" then elseif topic == "term" then
set_input(pos, number, "term", payload) set_input(pos, number, "term", payload)
elseif topic == "msg" then elseif topic == "msg" then
set_input(pos, number, "msg", payload) set_input(pos, number, "msg", {src = src, data = payload})
elseif topic == "state" then elseif topic == "state" then
local running = meta:get_int("running") or STATE_STOPPED local running = meta:get_int("running") or STATE_STOPPED
return techage.StateStrings[running] or "stopped" return techage.StateStrings[running] or "stopped"

View File

@ -86,11 +86,14 @@ minetest.register_node("techage:ta4_server", {
return return
end end
techage.del_mem(pos) techage.del_mem(pos)
techage.remove_node(pos)
minetest.node_dig(pos, node, puncher, pointed_thing) minetest.node_dig(pos, node, puncher, pointed_thing)
end, end,
on_timer = function(pos, elasped) after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
on_timer = function(pos, elasped)
local meta = M(pos) local meta = M(pos)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
nvm.size = nvm.size or 0 nvm.size = nvm.size or 0

View File

@ -108,7 +108,7 @@ local function command(pos, cmnd, player)
if techage.lua_ctlr.not_protected(owner, num) then if techage.lua_ctlr.not_protected(owner, num) then
--output(pos, player..":$ msg "..num.." "..text) --output(pos, player..":$ msg "..num.." "..text)
output(pos, "> msg "..num.." "..text) output(pos, "> msg "..num.." "..text)
techage.send_single(own_number, num, "msg", {src=own_number, text=text}) techage.send_single(own_number, num, "msg", text)
return return
end end
end end
@ -230,26 +230,31 @@ techage.lua_ctlr.register_action("put_term", {
}) })
techage.lua_ctlr.register_function("get_msg", { techage.lua_ctlr.register_function("get_msg", {
cmnd = function(self) cmnd = function(self, raw)
local msg = techage.lua_ctlr.get_msg(self.meta.number) local msg = techage.lua_ctlr.get_msg(self.meta.number)
if msg then if msg then
return msg.src, msg.text local data = msg.data
if not raw then
data = tostring(data or "")
end
return msg.src, data
end end
end, end,
help = ' $get_msg() --> number and text string or nil\n'.. help = ' $get_msg([raw]) --> number and any value or nil\n'..
' If the optional `raw` parameter is not set or false,\n'..
' the second return value is guaranteed to be a string.\n'..
' Read a received messages. Number is the node\n'.. ' Read a received messages. Number is the node\n'..
' number of the sender.\n'.. ' number of the sender.\n'..
' example: num,msg = $get_msg().' ' example: num,msg = $get_msg().'
}) })
techage.lua_ctlr.register_action("send_msg", { techage.lua_ctlr.register_action("send_msg", {
cmnd = function(self, num, text) cmnd = function(self, num, data)
local msg = {src = self.meta.number, text = tostring(text or "")}
if techage.lua_ctlr.not_protected(self.meta.owner, num) then if techage.lua_ctlr.not_protected(self.meta.owner, num) then
techage.send_single(self.meta.number, num, "msg", msg) techage.send_single(self.meta.number, num, "msg", data)
end end
end, end,
help = " $send_msg(num, text)\n".. help = " $send_msg(num, data)\n"..
' Send a message to the controller with number "num".\n'.. ' Send a message to the controller with number "num".\n'..
' example: $send_msg("0123", "test")' ' example: $send_msg("0123", "test")'
}) })

View File

@ -70,6 +70,17 @@ Die Antriebsachsen dienen zur Kraftübertragung von der Dampfmaschine zu anderen
[ta2_driveaxle|image] [ta2_driveaxle|image]
### TA2 Stromgenerator / TA2 Power Generator
Um Lampen oder andere Stromverbraucher an einer Dampfmaschine betreiben zu können, wird der TA2 Stromgenerator benötigt. Der TA2 Stromgenerator muss auf einer Seite mit Antriebsachsen verbunden werden und liefert dann auf der anderen Seite elektrischen Strom.
Wird der Stromgenerator nicht mit ausreichend Kraft versorgt, geht er in einen Fehlerzustand und muss über einen Rechtsklick wieder aktiviert werden.
Das Stromgenerator nimmt primär max. 25 ku an Achsenkraft auf und gibt sekundär max. 24 ku als Strom wieder ab. Er verbraucht also ein ku für die Umwandlung.
[ta2_generator|image]
## Items schieben und sortieren ## Items schieben und sortieren
@ -107,6 +118,8 @@ Der Verteiler ist in der Lage, die Items aus seinem Inventar sortiert in bis zu
Der Verteiler besitzt dazu ein Menü mit 4 Filter mit unterschiedlichen Farben, entsprechend den 4 Ausgängen. Soll ein Ausgang genutzt werden, so muss der entsprechende Filter über die "on" Checkbox aktiviert werden. Alle Items, die für diesen Filter konfiguriert sind, werden über den zugeordneten Ausgang ausgegeben. Wird ein Filter aktiviert, ohne das Items konfiguriert werden, so sprechen wir hier von einem "nicht-konfigurierten", offenen Ausgang. Der Verteiler besitzt dazu ein Menü mit 4 Filter mit unterschiedlichen Farben, entsprechend den 4 Ausgängen. Soll ein Ausgang genutzt werden, so muss der entsprechende Filter über die "on" Checkbox aktiviert werden. Alle Items, die für diesen Filter konfiguriert sind, werden über den zugeordneten Ausgang ausgegeben. Wird ein Filter aktiviert, ohne das Items konfiguriert werden, so sprechen wir hier von einem "nicht-konfigurierten", offenen Ausgang.
**Achtung: Der Verteiler ist an seinen Ausgängen gleichzeitig ein Schieber. Daher niemals die Gegenstände mit einem Schieber aus dem Verteiler ziehen!**
Für einen nicht-konfigurierten Ausgang gibt es zwei Betriebsarten: Für einen nicht-konfigurierten Ausgang gibt es zwei Betriebsarten:
1) Alle Items ausgeben, die an keine anderen Ausgängen ausgegeben werden können, auch wenn diese blockiert sind. 1) Alle Items ausgeben, die an keine anderen Ausgängen ausgegeben werden können, auch wenn diese blockiert sind.

View File

@ -71,6 +71,18 @@ The drive axles are used to transmit power from the steam engine to other machin
[ta2_driveaxle|image] [ta2_driveaxle|image]
### TA2 Power Generator
The TA2 Power Generator is required to operate lamps or other power consumers on a steam engine. The TA2 Power Generator has to be connected to drive axles on one side and then supplies electricity on the other side.
If the Power Generator is not supplied with sufficient power, it goes into an error state and must be reactivated with a right-click.
The Power Generator takes max. 25 ku of axle power and provides on the other side max. 24 ku as electricity. So he consumes one ku for the conversion.
[ta2_generator|image]
## Push and sort items ## Push and sort items
In order to transport objects from one processing station to the next, pushers and tubes are used. See plan. In order to transport objects from one processing station to the next, pushers and tubes are used. See plan.
@ -107,6 +119,8 @@ The distributor is able to transport the items from his inventory sorted in up t
The distributor has a menu with 4 filters with different colors, corresponding to the 4 outputs. If an output is to be used, the corresponding filter must be activated via the "on" checkbox. All items that are configured for this filter are output via the assigned output. If a filter is activated without items being configured, we are talking about an "unconfigured", open output. The distributor has a menu with 4 filters with different colors, corresponding to the 4 outputs. If an output is to be used, the corresponding filter must be activated via the "on" checkbox. All items that are configured for this filter are output via the assigned output. If a filter is activated without items being configured, we are talking about an "unconfigured", open output.
**Attention: The distributor is also a pusher at its output sides. Therefore, never pull items out of the distributor with a pusher!**
There are two operating modes for a non-configured output: There are two operating modes for a non-configured output:
1) Output all items that cannot be output to any other exit, even if they are blocked. 1) Output all items that cannot be output to any other exit, even if they are blocked.

View File

@ -198,6 +198,27 @@ In der unteren Hälfte werden die Daten aller Generatoren und Speichersystemen d
[ta3_powerterminal|image] [ta3_powerterminal|image]
### TA3 Elektromotor / TA3 Electric Motor
Um TA2 Maschinen über das Stromnetz betreiben zu können, wird der TA3 Elektromotor benötigt. Dieser wandelt Strom in Achsenkraft um.
Wird der Elektromotor nicht mit ausreichend Strom versorgt, geht er in einen Fehlerzustand und muss über einen Rechtsklick wieder aktiviert werden.
Das Elektromotor nimmt primär max. 40 ku an Strom auf und gibt sekundär max. 39 ku als Achsenkraft wieder ab. Er verbraucht also ein ku für die Umwandlung.
[ta3_motor|image]
### TA3 Strom Terminal / Power Terminal
Das Strom-Terminal muss mit dem Stromnetz verbunden werden. Es zeigt Daten aus dem Stromnetz an.
In der oberen Hälfte werden nur die Daten eines ausgewählten Typs ausgegeben. Wird als Typ bspw. "Kraftwerk" gewählt, so werden nur die Daten von Öl- und Kohlekraftwerken gesammelt und ausgegeben. Links werden die Daten von Generatoren (Stromabgabe) und rechts die Daten von Energiespeichern (Stromaufnahme) ausgegeben. Beim Akkublocks bspw. wird beides ausgegeben, da der Akku Strom aufnehmen und abgeben kann.
In der unteren Hälfte werden die Daten aller Generatoren und Speichersystemen des ganzen Stromnetzen zusammengefasst ausgegeben.
[ta3_powerterminal|image]
## TA3 Industrieofen ## TA3 Industrieofen
Der TA3 Industrieofen dient als Ergänzung zu normalen Ofen (furnace). Damit können alle Waren mit "Koch" Rezepten, auch im Industrieofen hergestellt werden. Es gibt aber auch spezielle Rezepte, die nur im Industrieofen hergestellt werden können. Der TA3 Industrieofen dient als Ergänzung zu normalen Ofen (furnace). Damit können alle Waren mit "Koch" Rezepten, auch im Industrieofen hergestellt werden. Es gibt aber auch spezielle Rezepte, die nur im Industrieofen hergestellt werden können.
@ -569,7 +590,7 @@ Das Terminal besitzt folgende, lokalen Kommandos:
- `pub` schalte in den öffentlichen Modus um - `pub` schalte in den öffentlichen Modus um
- `priv` schalte in den privaten Modus um - `priv` schalte in den privaten Modus um
Im privaten Modul kann nur der Besitzer selbst Kommandos eingeben oder Tasten nutzen. Im privaten Modus (private) kann das Terminal nur von Spielern verwendet werden, die an diesem Ort bauen können, also Protection Rechte besitzen. Im öffentlichen Modus (public) können alle Spieler die vorkonfigurierten Tasten verwenden.
[ta3_terminal|image] [ta3_terminal|image]

View File

@ -198,6 +198,18 @@ In the lower half, the data of all generators and storage systems of the entire
[ta3_powerterminal|image] [ta3_powerterminal|image]
### TA3 Electric Motor
The TA3 Electric Motor is required in order to be able to operate TA2 machines via the power grid. The TA3 Electric Motor converts electricity into axle power.
If the electric motor is not supplied with sufficient power, it goes into an fault state and must be reactivated with a right-click.
The electric motor takes max. 40 ku of electricity and provides on the other side max. 39 ku as axle power. So he consumes one ku for the conversion.
[ta3_motor|image]
## TA3 Industrial Furnace ## TA3 Industrial Furnace
The TA3 industrial furnace serves as a supplement to normal furnaces. This means that all goods can be produced with "cooking" recipes, even in an industrial furnace. But there are also special recipes that can only be made in an industrial furnace. The TA3 industrial furnace serves as a supplement to normal furnaces. This means that all goods can be produced with "cooking" recipes, even in an industrial furnace. But there are also special recipes that can only be made in an industrial furnace.
@ -567,7 +579,9 @@ The terminal has the following local commands:
- `pub` switch to public mode - `pub` switch to public mode
- `priv` switch to private mode - `priv` switch to private mode
In the private mode, only the owner can enter commands himself or use keys. In private mode, the terminal can only be used by players who can build at this location, i.e. who have protection rights.
In public mode, all players can use the preconfigured keys.
[ta3_terminal|image] [ta3_terminal|image]

View File

@ -7,10 +7,11 @@ Regenerative Energiequellen wie Wind, Sonne und Biokraft helfen dir, das Ölzeit
## Windkraftanlage ## Windkraftanlage
Eine Windkraftanlagen liefern immer dann Strom, wenn Wind vorhanden ist. Im Spiel gibt es keinen Wind, aber die Mod simuliert dies dadurch, dass sich nur morgens (5:00 - 9:00) und abends (17:00 - 21:00) die Windräder drehen und damit Strom liefern, sofern diese an geeigneten Stellen errichtet werden. Eine Windkraftanlage liefern immer dann Strom, wenn Wind vorhanden ist. Im Spiel gibt es keinen Wind, aber die Mod simuliert dies dadurch, dass sich nur morgens (5:00 - 9:00) und abends (17:00 - 21:00) die Windräder drehen. Eine Windkraftanlage liefert nur dann Strom, wenn sie an einer geeigneten Stelle aufgestellt ist.
Die TA Windkraftanlagen sind reine Offshore Anlagen, das heißt, die müssen im Meer (Wasser) errichtet werden. Dies bedeutet, dass um den Mast herum mit einem Abstand von 20 Blöcken nur Wasser sein darf und das mindestens 2 Blöcke tief. Die TA Windkraftanlagen sind reine Offshore Anlagen, das heißt, die müssen im Meer errichtet werden. Dies bedeutet, dass Windkraftanlagen nur in einem Meer (occean) Biom errichtet werden können und dass um den Mast herum ausreichend Wasser und freie Sicht vorhanden sein müssen.
Der Rotor muss in einer Höhe (Y-Koordinate) von 12 bis maximal 20 m platziert werden. Der Abstand zu weiteren Windkraftanlagen muss mindestens 14 m betragen.
Um eine geeignete Stelle zu finden, musst du mit dem Schraubenschlüssel (TechAge Info Werkzeug) auf das Wasser klicken. Ob diese Stelle für den Mast der Windkraftanlage geeignet ist, wird dir als Chat Nachricht angezeigt.
Der Strom muss vom Rotor-Block durch den Mast nach unten geführt werden. Dazu zuerst die Stromleitung nach oben ziehen und das Stromkabel dann mit TA4 Säulenblöcke "verputzen". Unten kann eine Arbeitsplattform errichtet werden. Der Plan rechts zeigt den Aufbau im oberen Teil. Der Strom muss vom Rotor-Block durch den Mast nach unten geführt werden. Dazu zuerst die Stromleitung nach oben ziehen und das Stromkabel dann mit TA4 Säulenblöcke "verputzen". Unten kann eine Arbeitsplattform errichtet werden. Der Plan rechts zeigt den Aufbau im oberen Teil.
@ -390,9 +391,9 @@ Die TA4 Sensor Kiste dient zum Aufbau von Automatischen Lagern oder Verkaufsauto
Wird etwas in die Kiste gelegt, oder entnommen, oder eine der Tasten "F1"/"F2" gedrückt, so wird ein Event-Signal an den Lua Controller gesendet. Wird etwas in die Kiste gelegt, oder entnommen, oder eine der Tasten "F1"/"F2" gedrückt, so wird ein Event-Signal an den Lua Controller gesendet.
Die Sensor Kiste unterstützt folgende Kommandos: Die Sensor Kiste unterstützt folgende Kommandos:
- Über `state = $read_data(<num>, "state")` kann der Status der Kiste abgefragt werden. Mögliche Antworten sind: "empty", "loaded", "full" - Über `state = $send_cmnd(<num>, "state")` kann der Status der Kiste abgefragt werden. Mögliche Antworten sind: "empty", "loaded", "full"
- Über `name, action = $read_data(<num>, "action")` kann die letzte Spieleraktion abgefragt werden. `name` ist der Spielername, Als `action` wird zurückgeliefert: "put", "take", "f1", "f2". - Über `name, action = $send_cmnd(<num>, "action")` kann die letzte Spieleraktion abgefragt werden. `name` ist der Spielername, Als `action` wird zurückgeliefert: "put", "take", "f1", "f2".
- Über `stacks = $read_data(<num>, "stacks")` kann der Inhalt der Kiste ausgelesen werden. Siehe dazu: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest - Über `stacks = $send_cmnd(<num>, "stacks")` kann der Inhalt der Kiste ausgelesen werden. Siehe dazu: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest
- Über `$send_cmnd(<num>, "text", "press both buttons and\nput something into the chest")` kann der Text im Menü der Sensor Kiste gesetzt werden. - Über `$send_cmnd(<num>, "text", "press both buttons and\nput something into the chest")` kann der Text im Menü der Sensor Kiste gesetzt werden.
Über die Checkbox "Erlaube öffentlichen Zugriff" kann eingestellt werden, ob die Kiste von jedem genutzt werden darf, oder nur von Spielern die hier Zugriffsrechte haben. Über die Checkbox "Erlaube öffentlichen Zugriff" kann eingestellt werden, ob die Kiste von jedem genutzt werden darf, oder nur von Spielern die hier Zugriffsrechte haben.
@ -596,8 +597,8 @@ Die Kiste kann nur von den Spielern genutzt werden, die an diesem Ort auch bauen
Der Kiste besitzt ein zusätzliches Kommandos für den Lua Controller: Der Kiste besitzt ein zusätzliches Kommandos für den Lua Controller:
- `count` dient zur Anfrage, wie viele Items in der Kiste sind. - `count` dient zur Anfrage, wie viele Items in der Kiste sind.
Beispiel 1: `$read_data(CHEST, "count")` --> Summe der Items über alle 8 Speicher Beispiel 1: `$send_cmnd(CHEST, "count")` --> Summe der Items über alle 8 Speicher
Beispiel 2: `$read_data(CHEST, "count", 2)` --> Anzahl der Items in Speicher 2 (zweiter von links) Beispiel 2: `$send_cmnd(CHEST, "count", 2)` --> Anzahl der Items in Speicher 2 (zweiter von links)
[ta4_8x2000_chest|image] [ta4_8x2000_chest|image]

View File

@ -7,10 +7,11 @@ Renewable energy sources such as wind, sun and biofuels help you to leave the oi
## Wind Turbine ## Wind Turbine
A wind turbine always delivers electricity when there is wind. There is no wind in the game, but the mod simulates this by only turning the wind turbines in the morning (5:00 a.m. - 9:00 a.m.) and in the evening (5:00 p.m. - 9:00 p.m.) and thus supplying electricity, provided they are positioned appropriately. A wind turbine always supplies electricity when there is wind. There is no wind in the game, but the mod simulates this by turning the wind turbines only in the morning (5:00 - 9:00) and in the evening (17:00 - 21:00). A wind turbine only supplies electricity if it is set up in a suitable location.
The TA wind turbines are pure offshore plants, which means that they have to be installed in the sea (water). This means that there must be in the minimum 20 blocks of water around the mast and at least 2 blocks deep. The TA wind power plants are pure offshore plants, which means that they have to be built in the sea. This means that wind turbines can only be build in a sea (occean) biome and that there must be sufficient water and a clear view around the mast.
The rotor must be placed at a height (Y coordinate) of 12 to a maximum of 20 m. The distance to other wind turbines must be at least 14 m.
To find a suitable spot, click on the water with the wrench (TechAge Info Tool). A chat message will show you whether this position is suitable for the mast of the wind turbine.
The current must be led from the rotor block down through the mast. First pull the power line up and then "plaster" the power cable with TA4 pillar blocks. A work platform can be built below. The plan on the right shows the structure in the upper part. The current must be led from the rotor block down through the mast. First pull the power line up and then "plaster" the power cable with TA4 pillar blocks. A work platform can be built below. The plan on the right shows the structure in the upper part.
@ -392,9 +393,9 @@ The TA4 sensor box is used to set up automatic warehouses or vending machines in
If something is put into the box or removed, or one of the "F1" / "F2" keys is pressed, an event signal is sent to the Lua controller. If something is put into the box or removed, or one of the "F1" / "F2" keys is pressed, an event signal is sent to the Lua controller.
The sensor box supports the following commands: The sensor box supports the following commands:
- The status of the box can be queried via `state = $read_data(<num>, "state")`. Possible answers are: "empty", "loaded", "full" - The status of the box can be queried via `state = $send_cmnd(<num>, "state")`. Possible answers are: "empty", "loaded", "full"
- The last player action can be queried via `name, action = $read_data(<num>, "action")`. `name` is the player name. One of the following is returned as `action`: "put", "take", "f1", "f2". - The last player action can be queried via `name, action = $send_cmnd(<num>, "action")`. `name` is the player name. One of the following is returned as `action`: "put", "take", "f1", "f2".
- The contents of the box can be read out via `stacks = $read_data(<num>, "stacks")`. See: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest - The contents of the box can be read out via `stacks = $send_cmnd(<num>, "stacks")`. See: https://github.com/joe7575/techage/blob/master/manuals/ta4_lua_controller_EN.md#sensor-chest
- Via `$send_cmnd(<num>, "text", "press both buttons and\nput something into the chest")` the text can be set in the menu of the sensor box. - Via `$send_cmnd(<num>, "text", "press both buttons and\nput something into the chest")` the text can be set in the menu of the sensor box.
The checkbox "Allow public chest access" can be used to set whether the box can be used by everyone or only by players who have access/protection rights here. The checkbox "Allow public chest access" can be used to set whether the box can be used by everyone or only by players who have access/protection rights here.
@ -579,7 +580,7 @@ The TA4 8x2000 chest does not have a normal inventory like other chest, but has
If the chest is filled with a pusher, all stores fill from left to right. If all 8 stores are full and no further items can be added, further items are rejected. If the chest is filled with a pusher, all stores fill from left to right. If all 8 stores are full and no further items can be added, further items are rejected.
** Row function ** **Row function**
Several TA4 8x2000 chests can be connected to a large chest with more content. To do this, the chests must be placed in a row one after the other. Several TA4 8x2000 chests can be connected to a large chest with more content. To do this, the chests must be placed in a row one after the other.
@ -597,8 +598,8 @@ The chest can only be used by players who can build at this location, i.e. who h
The chest has an additional command for the Lua controller: The chest has an additional command for the Lua controller:
- `count` is used to request how many items are in the chest. - `count` is used to request how many items are in the chest.
Example 1: `$read_data(CHEST, "count")` -> Sum of items across all 8 stores Example 1: `$send_cmnd(CHEST, "count")` -> Sum of items across all 8 stores
Example 2: `$read_data(CHEST, "count", 2)` -> number of items in store 2 (second from left) Example 2: `$send_cmnd(CHEST, "count", 2)` -> number of items in store 2 (second from left)
[ta4_8x2000_chest|image] [ta4_8x2000_chest|image]

View File

@ -106,7 +106,7 @@ class MyRenderer(mistune.Renderer):
## ##
def block_code(self, code, lang): def block_code(self, code, lang):
text = formspec_escape(code.strip()) text = formspec_escape(code.strip())
lines = text.split("\n") lines = text.split("\\n")
lines = [" " + item for item in lines] lines = [" " + item for item in lines]
self.TextChunck.extend(lines) self.TextChunck.extend(lines)
self.TextChunck.append("") self.TextChunck.append("")

View File

@ -346,10 +346,16 @@ In addition to Lua standard function the Lua Controller provides the following f
### Techage Command Functions ### Techage Command Functions
* `$read_data(num, ident, add_data)` - Read any kind of data from another block with the given number _num_. With the `$send_cmnd(num, ident, add_data)` function, you can send commands to and retrieve data from another block with the given number _num_.
_ident_ specifies the data to be read. The possible commands can be classified in two groups: Commands for reading data and commands for triggering an action.
_add_data_ is for additional data and normally not needed. Please note, that this is not a technical distinction, only a logical.
The result is block dependent (see table below):
**Reading data**
- _ident_ specifies the data to be read.
- _add_data_ is for additional data and normally not needed.
- The result is block dependent (see table below)
| ident | returned data | comment | | ident | returned data | comment |
| ------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | ------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
@ -358,18 +364,22 @@ In addition to Lua standard function the Lua Controller provides the following f
| "state" | one of: "empty", "loaded", "full" | State of a chest or Sensor Chest | | "state" | one of: "empty", "loaded", "full" | State of a chest or Sensor Chest |
| "fuel" | number | fuel value of a fuel consuming block | | "fuel" | number | fuel value of a fuel consuming block |
| "depth" | number | Read the current depth value of a quarry block (1..80) | | "depth" | number | Read the current depth value of a quarry block (1..80) |
| "load" | number | Read the load value in percent (0..100) of a tank, silo, accu, or battery block, or from the Signs Bot Box. Silo and tank return two values: The percentage value and the absolute value in units.<br /> Example: percent, absolute = $read_data("223", "load") | | "load" | number | Read the load value in percent (0..100) of a tank, silo, accu, or battery block, or from the Signs Bot Box. Silo and tank return two values: The percentage value and the absolute value in units.<br /> Example: percent, absolute = $send_cmnd("223", "load") |
| "delivered" | number | Read the current delivered power value of a generator block. A power consuming block (accu) provides a negative value | | "delivered" | number | Read the current delivered power value of a generator block. A power consuming block (accu) provides a negative value |
| "action" | player-name, action-string | only for Sensor Chests | | "action" | player-name, action-string | Only for Sensor Chests |
| "stacks" | Array with up to 4 Stores with the inventory content (see example) | only for Sensor Chests | | "stacks" | Array with up to 4 Stores with the inventory content (see example) | Only for Sensor Chests |
| "count" | number | Read the item counter of the TA4 Item Detector block | | "count" | number | Read the item counter of the TA4 Item Detector block |
| "count" | number of items | Read the total amount of TA4 chest items. An optional number as `add_data` is used to address only one inventory slot (1..8, from left to right). | | "count" | number of items | Read the total amount of TA4 chest items. An optional number as `add_data` is used to address only one inventory slot (1..8, from left to right). |
| "itemstring" | item string of the given slot | Specific command for the TA4 8x2000 Chest to read the item type (technical name) of one chest slot, specified via `add_data` (1..8).<br />Example: s = $read_data("223", "itemstring", 1) | | "itemstring" | item string of the given slot | Specific command for the TA4 8x2000 Chest to read the item type (technical name) of one chest slot, specified via `add_data` (1..8).<br />Example: s = $send_cmnd("223", "itemstring", 1) |
| "output" | recipe output string, <br />e.g.: "default:glass" | Only for the Industrial Furnace. If no recipe is active, the command returns "unknown" |
**Trigger an action**
* `$send_cmnd(num, cmnd, data)` - Send a command to another block. _num_ is the number of the remote block, like "1234". _cmnd_ is the command, _data_ is additional data (see table below): - _num_ is the number of the remote block, like "1234"
- _cmnd_ is the command
- _data_ is additional data (see table below)
| cmnd | data | comment | | cmnd | data | comment |
| -------------------------------- | ------------ | ------------------------------------------------------------ | | -------------------------------- | ------------ | ------------------------------------------------------------ |
@ -406,11 +416,10 @@ In contrast the Controller can send text strings to the terminal.
### Further Functions ### Further Functions
Messages are used to transport data between Controllers. Messages are text strings or any other data. Incoming messages are stored in order (up to 10) and can be read one after the other. Messages are used to transport data between Controllers. Messages can contain arbitrary data. Incoming messages are stored in order (up to 10) and can be read one after the other.
* `$get_msg()` - Read a received message. The function returns the sender number and the message. (see example "Emails") * `$get_msg([raw])` - Read a received message. The function returns the sender number and the message. (see example "Emails"). If the _raw_ parameter is not set or false, the message is guaranteed to be a string.
* `$send_msg(num, msg)` - Send a message to another Controller. _num_ is the destination number. (see example "Emails") * `$send_msg(num, msg)` - Send a message to another Controller. _num_ is the destination number. (see example "Emails")
* `$chat(text)` - Send yourself a chat message. _text_ is a text string. * `$chat(text)` - Send yourself a chat message. _text_ is a text string.
* `$door(pos, text)` - Open/Close a door at position "pos". * `$door(pos, text)` - Open/Close a door at position "pos".
@ -419,7 +428,7 @@ Messages are used to transport data between Controllers. Messages are text strin
* `$item_description("default:apple")` * `$item_description("default:apple")`
Get the description (item name) for a specified itemstring, e. g. determined via the TA4 8x2000 Chest command `itemstring`: Get the description (item name) for a specified itemstring, e. g. determined via the TA4 8x2000 Chest command `itemstring`:
`str = $read_data("223", "itemstring", 1)` `str = $send_cmnd("223", "itemstring", 1)`
`descr = $item_description(str)` `descr = $item_description(str)`
@ -504,15 +513,15 @@ if ticks % 60 == 0 then
$display(DISPLAY, 1, min.." min") $display(DISPLAY, 1, min.." min")
-- Cactus chest overrun -- Cactus chest overrun
sts = $read_data("1034", "state") -- read pusher status sts = $send_cmnd("1034", "state") -- read pusher status
if sts == "blocked" then $display(DISPLAY, 2, "Cactus full") end if sts == "blocked" then $display(DISPLAY, 2, "Cactus full") end
-- Tree chest overrun -- Tree chest overrun
sts = $read_data("1065", "state") -- read pusher status sts = $send_cmnd("1065", "state") -- read pusher status
if sts == "blocked" then $display(DISPLAY, 3, "Tree full") end if sts == "blocked" then $display(DISPLAY, 3, "Tree full") end
-- Furnace fuel empty -- Furnace fuel empty
sts = $read_data("1544", "state") -- read pusher status sts = $send_cmnd("1544", "state") -- read pusher status
if sts == "standby" then $display(DISPLAY, 4, "Furnace fuel") end if sts == "standby" then $display(DISPLAY, 4, "Furnace fuel") end
end end
``` ```
@ -570,7 +579,7 @@ loop() code:
```lua ```lua
if event then if event then
name = $read_data(SENSOR, "name") name = $send_cmnd(SENSOR, "name")
if name == "" then -- no player arround if name == "" then -- no player arround
$clear_screen(DISPLAY) $clear_screen(DISPLAY)
else else
@ -602,13 +611,13 @@ loop() code:
```lua ```lua
if event and $get_input(SENSOR) == "on" then if event and $get_input(SENSOR) == "on" then
-- read inventory state -- read inventory state
state = $read_data(SENSOR, "state") state = $send_cmnd(SENSOR, "state")
$print("state: "..state) $print("state: "..state)
-- read player name and action -- read player name and action
name, action = $read_data(SENSOR, "action") name, action = $send_cmnd(SENSOR, "action")
$print("action"..": "..name.." "..action) $print("action"..": "..name.." "..action)
-- read inventory content -- read inventory content
stacks = $read_data(SENSOR, "stacks") stacks = $send_cmnd(SENSOR, "stacks")
for i,stack in stacks.next() do for i,stack in stacks.next() do
$print("stack: "..stack.get("name").." "..stack.get("count")) $print("stack: "..stack.get("name").." "..stack.get("count"))
end end

View File

@ -27,6 +27,7 @@
- [TA2 Schwungrad / Flywheel](./manual_ta2_DE.md#ta2-schwungrad--flywheel) - [TA2 Schwungrad / Flywheel](./manual_ta2_DE.md#ta2-schwungrad--flywheel)
- [TA2 Dampfleitungen / Steam Pipe](./manual_ta2_DE.md#ta2-dampfleitungen--steam-pipe) - [TA2 Dampfleitungen / Steam Pipe](./manual_ta2_DE.md#ta2-dampfleitungen--steam-pipe)
- [TA2 Antriebsachsen / TA2 Drive Axle](./manual_ta2_DE.md#ta2-antriebsachsen--ta2-drive-axle) - [TA2 Antriebsachsen / TA2 Drive Axle](./manual_ta2_DE.md#ta2-antriebsachsen--ta2-drive-axle)
- [TA2 Stromgenerator / TA2 Power Generator](./manual_ta2_DE.md#ta2-stromgenerator--ta2-power-generator)
- [Items schieben und sortieren](./manual_ta2_DE.md#items-schieben-und-sortieren) - [Items schieben und sortieren](./manual_ta2_DE.md#items-schieben-und-sortieren)
- [Röhren / TechAge Tube](./manual_ta2_DE.md#röhren--techage-tube) - [Röhren / TechAge Tube](./manual_ta2_DE.md#röhren--techage-tube)
- [TA2 Schieber / Pusher](./manual_ta2_DE.md#ta2-schieber--pusher) - [TA2 Schieber / Pusher](./manual_ta2_DE.md#ta2-schieber--pusher)
@ -44,10 +45,10 @@
- [TA2 Flüssigkeitensammler / Liquid Sampler](./manual_ta2_DE.md#ta2-flüssigkeitensammler--liquid-sampler) - [TA2 Flüssigkeitensammler / Liquid Sampler](./manual_ta2_DE.md#ta2-flüssigkeitensammler--liquid-sampler)
- [TA2 Gesicherte Kiste / Protected Chest](./manual_ta2_DE.md#ta2-gesicherte-kiste--protected-chest) - [TA2 Gesicherte Kiste / Protected Chest](./manual_ta2_DE.md#ta2-gesicherte-kiste--protected-chest)
- [Techage Forceload Block](./manual_ta2_DE.md#techage-forceload-block) - [Techage Forceload Block](./manual_ta2_DE.md#techage-forceload-block)
- [TA3: Ölzeitalter](./manual_ta3_DE.md#ta3:-ölzeitalter) - [TA3: Ölzeitalter](./manual_ta3_DE.md#ta3:-Ölzeitalter)
- [Kohlekraftwerk / Ölkraftwerk](./manual_ta3_DE.md#kohlekraftwerk--ölkraftwerk) - [Kohlekraftwerk / Ölkraftwerk](./manual_ta3_DE.md#kohlekraftwerk--Ölkraftwerk)
- [TA3 Kraftwerks-Feuerbox / Power Station Firebox](./manual_ta3_DE.md#ta3-kraftwerks-feuerbox--power-station-firebox) - [TA3 Kraftwerks-Feuerbox / Power Station Firebox](./manual_ta3_DE.md#ta3-kraftwerks-feuerbox--power-station-firebox)
- [TA3 Kraftwerks-Ölbrenner / TA3 Power Station Oil Burner](./manual_ta3_DE.md#ta3-kraftwerks-ölbrenner--ta3-power-station-oil-burner) - [TA3 Kraftwerks-Ölbrenner / TA3 Power Station Oil Burner](./manual_ta3_DE.md#ta3-kraftwerks-Ölbrenner--ta3-power-station-oil-burner)
- [TA3 Boiler unten/oben](./manual_ta3_DE.md#ta3-boiler-untenoben) - [TA3 Boiler unten/oben](./manual_ta3_DE.md#ta3-boiler-untenoben)
- [TA3 Turbine](./manual_ta3_DE.md#ta3-turbine) - [TA3 Turbine](./manual_ta3_DE.md#ta3-turbine)
- [TA3 Generator](./manual_ta3_DE.md#ta3-generator) - [TA3 Generator](./manual_ta3_DE.md#ta3-generator)
@ -65,8 +66,10 @@
- [TA3 Kleiner Stromgenerator / Tiny Power Generator](./manual_ta3_DE.md#ta3-kleiner-stromgenerator--tiny-power-generator) - [TA3 Kleiner Stromgenerator / Tiny Power Generator](./manual_ta3_DE.md#ta3-kleiner-stromgenerator--tiny-power-generator)
- [TA3 Akku Block / Akku Box](./manual_ta3_DE.md#ta3-akku-block---akku-box) - [TA3 Akku Block / Akku Box](./manual_ta3_DE.md#ta3-akku-block---akku-box)
- [TA3 Strom Terminal / Power Terminal](./manual_ta3_DE.md#ta3-strom-terminal--power-terminal) - [TA3 Strom Terminal / Power Terminal](./manual_ta3_DE.md#ta3-strom-terminal--power-terminal)
- [TA3 Elektromotor / TA3 Electric Motor](./manual_ta3_DE.md#ta3-elektromotor--ta3-electric-motor)
- [TA3 Strom Terminal / Power Terminal](./manual_ta3_DE.md#ta3-strom-terminal--power-terminal)
- [TA3 Industrieofen](./manual_ta3_DE.md#ta3-industrieofen) - [TA3 Industrieofen](./manual_ta3_DE.md#ta3-industrieofen)
- [TA3 Ofen-Ölbrenner / Furnace Oil Burner](./manual_ta3_DE.md#ta3-ofen-ölbrenner--furnace-oil-burner) - [TA3 Ofen-Ölbrenner / Furnace Oil Burner](./manual_ta3_DE.md#ta3-ofen-Ölbrenner--furnace-oil-burner)
- [TA3 Ofenoberteil / Furnace Top](./manual_ta3_DE.md#ta3-ofenoberteil--furnace-top) - [TA3 Ofenoberteil / Furnace Top](./manual_ta3_DE.md#ta3-ofenoberteil--furnace-top)
- [TA3 Gebläse / Booster](./manual_ta3_DE.md#ta3-gebläse--booster) - [TA3 Gebläse / Booster](./manual_ta3_DE.md#ta3-gebläse--booster)
- [Flüssigkeiten](./manual_ta3_DE.md#flüssigkeiten) - [Flüssigkeiten](./manual_ta3_DE.md#flüssigkeiten)
@ -76,18 +79,18 @@
- [TA4 Röhre / Pipe](./manual_ta3_DE.md#ta4-röhre--pipe) - [TA4 Röhre / Pipe](./manual_ta3_DE.md#ta4-röhre--pipe)
- [TA3 Rohr/Wanddurchbruch / TA3 Pipe Wall Entry Blöcke](./manual_ta3_DE.md#ta3-rohrwanddurchbruch--ta3-pipe-wall-entry-blöcke) - [TA3 Rohr/Wanddurchbruch / TA3 Pipe Wall Entry Blöcke](./manual_ta3_DE.md#ta3-rohrwanddurchbruch--ta3-pipe-wall-entry-blöcke)
- [TA Ventil / TA Valve](./manual_ta3_DE.md#ta-ventil--ta-valve) - [TA Ventil / TA Valve](./manual_ta3_DE.md#ta-ventil--ta-valve)
- [Öl-Förderung](./manual_ta3_DE.md#öl-förderung) - [Öl-Förderung](./manual_ta3_DE.md#Öl-förderung)
- [TA3 Ölexplorer / Oil Explorer](./manual_ta3_DE.md#ta3-ölexplorer--oil-explorer) - [TA3 Ölexplorer / Oil Explorer](./manual_ta3_DE.md#ta3-Ölexplorer--oil-explorer)
- [TA3 Ölbohrkiste / Oil Drill Box](./manual_ta3_DE.md#ta3-ölbohrkiste--oil-drill-box) - [TA3 Ölbohrkiste / Oil Drill Box](./manual_ta3_DE.md#ta3-Ölbohrkiste--oil-drill-box)
- [TA3 Ölpumpe / Oil Pumpjack](./manual_ta3_DE.md#ta3-ölpumpe--oil-pumpjack) - [TA3 Ölpumpe / Oil Pumpjack](./manual_ta3_DE.md#ta3-Ölpumpe--oil-pumpjack)
- [TA3 Bohrgestänge / Drill Pipe](./manual_ta3_DE.md#ta3-bohrgestänge--drill-pipe) - [TA3 Bohrgestänge / Drill Pipe](./manual_ta3_DE.md#ta3-bohrgestänge--drill-pipe)
- [Öltank / Oil Tank](./manual_ta3_DE.md#öltank--oil-tank) - [Öltank / Oil Tank](./manual_ta3_DE.md#Öltank--oil-tank)
- [Öl-Transport](./manual_ta3_DE.md#öl-transport) - [Öl-Transport](./manual_ta3_DE.md#Öl-transport)
- [Öl-Transport mit dem Tankwagen](./manual_ta3_DE.md#öl-transport-mit-dem-tankwagen) - [Öl-Transport mit dem Tankwagen](./manual_ta3_DE.md#Öl-transport-mit-dem-tankwagen)
- [Öl-Transport mit Fässern über Minecarts](./manual_ta3_DE.md#öl-transport-mit-fässern-über-minecarts) - [Öl-Transport mit Fässern über Minecarts](./manual_ta3_DE.md#Öl-transport-mit-fässern-über-minecarts)
- [Tankwagen / Tank Cart](./manual_ta3_DE.md#tankwagen--tank-cart) - [Tankwagen / Tank Cart](./manual_ta3_DE.md#tankwagen--tank-cart)
- [Kistenwagen / Chest Cart](./manual_ta3_DE.md#kistenwagen--chest-cart) - [Kistenwagen / Chest Cart](./manual_ta3_DE.md#kistenwagen--chest-cart)
- [Öl-Verarbeitung](./manual_ta3_DE.md#öl-verarbeitung) - [Öl-Verarbeitung](./manual_ta3_DE.md#Öl-verarbeitung)
- [Destillationsturm / distiller tower](./manual_ta3_DE.md#destillationsturm--distiller-tower) - [Destillationsturm / distiller tower](./manual_ta3_DE.md#destillationsturm--distiller-tower)
- [Aufkocher / reboiler)](./manual_ta3_DE.md#aufkocher--reboiler)) - [Aufkocher / reboiler)](./manual_ta3_DE.md#aufkocher--reboiler))
- [Logik-/Schalt-Blöcke](./manual_ta3_DE.md#logik-schalt-blöcke) - [Logik-/Schalt-Blöcke](./manual_ta3_DE.md#logik-schalt-blöcke)

View File

@ -27,6 +27,7 @@
- [TA2 Flywheel](./manual_ta2_EN.md#ta2-flywheel) - [TA2 Flywheel](./manual_ta2_EN.md#ta2-flywheel)
- [TA2 Steam Pipes](./manual_ta2_EN.md#ta2-steam-pipes) - [TA2 Steam Pipes](./manual_ta2_EN.md#ta2-steam-pipes)
- [TA2 Drive Axle / TA2 Gearbox](./manual_ta2_EN.md#ta2-drive-axle--ta2-gearbox) - [TA2 Drive Axle / TA2 Gearbox](./manual_ta2_EN.md#ta2-drive-axle--ta2-gearbox)
- [TA2 Power Generator](./manual_ta2_EN.md#ta2-power-generator)
- [Push and sort items](./manual_ta2_EN.md#push-and-sort-items) - [Push and sort items](./manual_ta2_EN.md#push-and-sort-items)
- [TechAge Tube](./manual_ta2_EN.md#techage-tube) - [TechAge Tube](./manual_ta2_EN.md#techage-tube)
- [TA2 Pusher](./manual_ta2_EN.md#ta2-pusher) - [TA2 Pusher](./manual_ta2_EN.md#ta2-pusher)
@ -65,6 +66,7 @@
- [TA3 Small Power Generator](./manual_ta3_EN.md#ta3-small-power-generator) - [TA3 Small Power Generator](./manual_ta3_EN.md#ta3-small-power-generator)
- [TA3 Battery Block](./manual_ta3_EN.md#ta3-battery-block) - [TA3 Battery Block](./manual_ta3_EN.md#ta3-battery-block)
- [TA3 Power Terminal](./manual_ta3_EN.md#ta3-power-terminal) - [TA3 Power Terminal](./manual_ta3_EN.md#ta3-power-terminal)
- [TA3 Electric Motor](./manual_ta3_EN.md#ta3-electric-motor)
- [TA3 Industrial Furnace](./manual_ta3_EN.md#ta3-industrial-furnace) - [TA3 Industrial Furnace](./manual_ta3_EN.md#ta3-industrial-furnace)
- [TA3 Furnace Oil Burner](./manual_ta3_EN.md#ta3-furnace-oil-burner) - [TA3 Furnace Oil Burner](./manual_ta3_EN.md#ta3-furnace-oil-burner)
- [TA3 Furnace Top](./manual_ta3_EN.md#ta3-furnace-top) - [TA3 Furnace Top](./manual_ta3_EN.md#ta3-furnace-top)

View File

@ -27,7 +27,7 @@ local function start_consumer(tbl, tlib_type)
if def and def["cstate"] == NOPOWER and (def["calive"] or 0) > 0 then if def and def["cstate"] == NOPOWER and (def["calive"] or 0) > 0 then
local ndef = net_def(v.pos, tlib_type) local ndef = net_def(v.pos, tlib_type)
def["cstate"] = RUNNING def["cstate"] = RUNNING
def["taken"] = v.nominal or 0 def["taken"] = v.nominal or def.curr_power or 0
if ndef.on_power then if ndef.on_power then
ndef.on_power(v.pos, tlib_type) ndef.on_power(v.pos, tlib_type)
end end
@ -73,10 +73,10 @@ local function get_consumer_sum(tbl, tlib_type, cycle_time)
if def and def["cstate"] ~= STOPPED then if def and def["cstate"] ~= STOPPED then
def["calive"] = (def["calive"] or 1) - cycle_time/2 def["calive"] = (def["calive"] or 1) - cycle_time/2
if def["calive"] >= 0 then if def["calive"] >= 0 then
sum = sum + v.nominal sum = sum + (v.nominal or def.curr_power or 0)
end end
end end
--print(N(v.pos), P2S(v.pos), def["cstate"], def["calive"]) --print(N(v.pos), P2S(v.pos), def["cstate"], def["calive"], sum)
end end
return sum return sum
end end
@ -155,7 +155,7 @@ function techage.power.get_con1_sum(network, tlib_type)
local nvm = techage.get_nvm(v.pos) local nvm = techage.get_nvm(v.pos)
local def = nvm[tlib_type] -- power related network data local def = nvm[tlib_type] -- power related network data
if def and def["cstate"] ~= STOPPED then if def and def["cstate"] ~= STOPPED then
sum = sum + v.nominal sum = sum + (v.nominal or def.curr_power or 0)
end end
end end
return sum return sum

View File

@ -48,11 +48,24 @@ function techage.power.formspec_power_bar(max_power, current_power)
return "techage_form_level_bg.png^[lowpart:"..percent..":techage_form_level_fg.png" return "techage_form_level_bg.png^[lowpart:"..percent..":techage_form_level_fg.png"
end end
function techage.power.formspec_label_bar(x, y, label, max_power, current_power, unit) function techage.power.formspec_label_bar(pos, x, y, label, max_power, current_power, unit)
local percent, ypos local percent, ypos
current_power = current_power or 0
max_power = max_power or 1 max_power = max_power or 1
unit = unit or "ku" unit = unit or "ku"
if current_power == 0 then
-- check if power network is overloaded
if techage.power.network_overloaded(pos, techage.ElectricCable) then
return "container["..x..","..y.."]"..
"box[0,0;2.3,3.3;#395c74]"..
"label[0.2,0;"..label.."]"..
"label[0.7,0.4;"..max_power.." "..unit.."]"..
"image[0,0.5;1,3;techage_form_level_red_fg.png]"..
"container_end[]"
end
end
current_power = current_power or 0
if current_power == 0 then if current_power == 0 then
percent = 0 percent = 0
ypos = 2.8 ypos = 2.8

View File

@ -148,6 +148,17 @@ function techage.power.power_available(pos, Cable)
return netw and netw.on and netw.alive and netw.alive > 0 return netw and netw.on and netw.alive and netw.alive > 0
end end
function techage.power.network_overloaded(pos, Cable)
local nvm = techage.get_nvm(pos)
local tlib_type = Cable.tube_type
local netID = nvm[Cable.tube_type] and nvm[Cable.tube_type]["netID"]
local netw = networks.has_network(tlib_type, netID)
if netw then
local sum = (netw.available1 or 0) + (netw.available2 or 0)
return sum > 0 and sum < (netw.needed1 or 0)
end
end
-- this is more a try to start, the start will be performed by on_power() -- this is more a try to start, the start will be performed by on_power()
function techage.power.consumer_start(pos, Cable, cycle_time) function techage.power.consumer_start(pos, Cable, cycle_time)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
@ -228,5 +239,24 @@ function techage.power.generator_alive(pos, Cable, cycle_time, outdir, curr_powe
return 0 return 0
end end
-- Calculate the needed power over all con1 consumers
function techage.power.needed_power(pos, Cable, outdir)
local sum = 0
networks.connection_walk(pos, outdir, Cable, function(pos, indir, node)
local net = net_def(pos, Cable.tube_type) -- network definition
if net.ntype == "con1" then
local nvm = techage.get_nvm(pos)
local def = nvm[Cable.tube_type] -- power related data
if def and def["cstate"] ~= STOPPED then
if def["calive"] >= 0 then
sum = sum + (net.nominal or def.curr_power or 0)
end
end
end
end)
return sum
end
-- function delete_netID(pos, outdir, Cable) -- function delete_netID(pos, outdir, Cable)
techage.power.delete_netID = delete_netID techage.power.delete_netID = delete_netID

View File

@ -129,10 +129,10 @@ local function formspec(pos, nvm)
"box[0,-0.1;9.8,0.5;#c6e8ff]".. "box[0,-0.1;9.8,0.5;#c6e8ff]"..
"label[4,-0.1;"..minetest.colorize( "#000000", S("Network Data")).."]".. "label[4,-0.1;"..minetest.colorize( "#000000", S("Network Data")).."]"..
"label[9.5,-0.1;"..minetest.colorize( "#000000", star).."]".. "label[9.5,-0.1;"..minetest.colorize( "#000000", star).."]"..
power.formspec_label_bar(0, 0.7, S("Genera. 1"), gen1.pow_act, gen1.pow_used).. power.formspec_label_bar(pos, 0, 0.7, S("Genera. 1"), gen1.pow_act, gen1.pow_used)..
power.formspec_label_bar(2.5, 0.7, S("Genera. 2"), gen2.pow_act, gen2.pow_used).. power.formspec_label_bar(pos, 2.5, 0.7, S("Genera. 2"), gen2.pow_act, gen2.pow_used)..
power.formspec_label_bar(5, 0.7, S("Consum. 2"), con2.pow_act, con2.pow_used).. power.formspec_label_bar(pos, 5, 0.7, S("Consum. 2"), con2.pow_act, con2.pow_used)..
power.formspec_label_bar(7.5, 0.7, S("Consum. 1"), con1.pow_act, con1.pow_used).. power.formspec_label_bar(pos, 7.5, 0.7, S("Consum. 1"), con1.pow_act, con1.pow_used)..
"box[0,4.3;9.8,0.4;#c6e8ff]".. "box[0,4.3;9.8,0.4;#c6e8ff]"..
"box[0,4.85;9.8,0.4;#395c74]".. "box[0,4.85;9.8,0.4;#395c74]"..
"box[0,5.35;9.8,0.4;#395c74]".. "box[0,5.35;9.8,0.4;#395c74]"..

View File

@ -37,6 +37,7 @@ local Generators = {
S("Energy storage"), S("Energy storage"),
S("Fuel cell"), S("Fuel cell"),
S("Electrolyzer"), S("Electrolyzer"),
S("TA2 Generator"),
} }
local Storage = { local Storage = {
@ -55,6 +56,7 @@ local GeneratorPerformances = {
60, -- S("Energy storage") 60, -- S("Energy storage")
25, -- S("Fuel cell") 25, -- S("Fuel cell")
30, -- S("Electrolyzer") 30, -- S("Electrolyzer")
24, -- S("TA2 Generator")
} }
-- --

View File

@ -67,8 +67,8 @@ local function formspec(self, pos, nvm)
default.gui_slots.. default.gui_slots..
"box[0,-0.1;5.8,0.5;#c6e8ff]".. "box[0,-0.1;5.8,0.5;#c6e8ff]"..
"label[2.5,-0.1;"..minetest.colorize( "#000000", S("Inverter")).."]".. "label[2.5,-0.1;"..minetest.colorize( "#000000", S("Inverter")).."]"..
power.formspec_label_bar(0, 0.8, S("Power DC"), PWR_PERF, max_power).. power.formspec_label_bar(pos, 0, 0.8, S("Power DC"), PWR_PERF, max_power)..
power.formspec_label_bar(3.5, 0.8, S("Power AC"), max_power, delivered).. power.formspec_label_bar(pos, 3.5, 0.8, S("Power AC"), max_power, delivered)..
arrow.. arrow..
"image_button[2.5,3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.5,3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.5,3;1,1;"..self:get_state_tooltip(nvm).."]" "tooltip[2.5,3;1,1;"..self:get_state_tooltip(nvm).."]"

View File

@ -38,7 +38,7 @@ local function formspec(self, pos, nvm)
default.gui_bg.. default.gui_bg..
default.gui_bg_img.. default.gui_bg_img..
default.gui_slots.. default.gui_slots..
power.formspec_label_bar(0, 0.8, S("power"), PWR_CAPA, nvm.provided).. power.formspec_label_bar(pos, 0, 0.8, S("power"), PWR_CAPA, nvm.provided)..
"image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.8,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]" "tooltip[2.8,2;1,1;"..self:get_state_tooltip(nvm).."]"
end end

View File

@ -36,7 +36,7 @@ local function formspec(self, pos, nvm)
default.gui_slots.. default.gui_slots..
"box[0,-0.1;4.8,0.5;#c6e8ff]".. "box[0,-0.1;4.8,0.5;#c6e8ff]"..
"label[1,-0.1;"..minetest.colorize( "#000000", S("TA3 Akku Box")).."]".. "label[1,-0.1;"..minetest.colorize( "#000000", S("TA3 Akku Box")).."]"..
power.formspec_label_bar(0, 0.8, S("Load"), PWR_CAPA, capa).. power.formspec_label_bar(pos, 0, 0.8, S("Load"), PWR_CAPA, capa)..
"image_button[2.6,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[2.6,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3,2;1,1;"..self:get_state_tooltip(nvm).."]".. "tooltip[3,2;1,1;"..self:get_state_tooltip(nvm).."]"..
"label[3.7,1.2;"..S("Electricity").."]".. "label[3.7,1.2;"..S("Electricity").."]"..

View File

@ -0,0 +1,236 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2 Power Generator
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local Cable = techage.ElectricCable
local Axle = techage.Axle
local power = techage.power
local networks = techage.networks
local CYCLE_TIME = 2
local PWR_PERF = 24
local function swap_node(pos, name)
local node = techage.get_node_lvm(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function on_power(pos)
local nvm = techage.get_nvm(pos)
nvm.axle = nvm.axle or {}
nvm.consumer_powered = true
M(pos):set_string("infotext", S("TA2 Power Generator"))
swap_node(pos, "techage:ta2_generator_on")
nvm.ticks = 0
local outdir = M(pos):get_int("outdir")
nvm.axle.curr_power = techage.power.needed_power(pos, Cable, outdir)
end
local function on_nopower(pos)
local nvm = techage.get_nvm(pos)
nvm.consumer_powered = false
if (nvm.ticks or 0) < 4 then
M(pos):set_string("infotext", S("TA2 Power Generator: Overload fault?\n(restart with right-click)"))
end
nvm.ticks = 0
end
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
nvm.axle = nvm.axle or {}
-- trigger network on consumer side
nvm.ticks = (nvm.ticks or 0) + 1
if nvm.ticks % 2 then
power.consumer_alive(pos, Axle, CYCLE_TIME)
end
-- handle generator side delayed
if nvm.ticks > 3 then
local outdir = M(pos):get_int("outdir")
if nvm.consumer_powered and not nvm.running_as_generator then
nvm.running_as_generator = true
power.generator_start(pos, Cable, CYCLE_TIME, outdir, nvm.max_power)
elseif not nvm.consumer_powered and nvm.running_as_generator then
nvm.running_as_generator = false
power.generator_stop(pos, Cable, outdir)
end
if nvm.running_as_generator then
nvm.axle.curr_power = power.generator_alive(pos, Cable, CYCLE_TIME, outdir, PWR_PERF) + 1
else
swap_node(pos, "techage:ta2_generator_off")
end
end
return true
end
local function tubelib2_on_update2(pos, outdir, tlib2, node)
local nvm = techage.get_nvm(pos)
nvm.axle = nvm.axle or {}
nvm.axle.curr_power = 1
power.update_network(pos, outdir, tlib2)
end
minetest.register_node("techage:ta2_generator_off", {
description = S("TA2 Power Generator"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_arrow.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_hole_electric.png",
"techage_filling_ta2.png^techage_axle_clutch.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_generator_red.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_generator_red.png^[transformFX]",
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
after_place_node = function(pos)
local nvm = techage.get_nvm(pos)
nvm.axle = nvm.axle or {}
nvm.axle.curr_power = 1
nvm.consumer_powered = false
nvm.running_as_generator = false
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
M(pos):set_int("leftdir", networks.side_to_outdir(pos, "L"))
Cable:after_place_node(pos)
Axle:after_place_node(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
power.consumer_start(pos, Axle, CYCLE_TIME*2)
M(pos):set_string("infotext", S("TA2 Power Generator"))
end,
on_rightclick = function(pos, node, clicker)
local nvm = techage.get_nvm(pos)
nvm.axle = nvm.axle or {}
nvm.axle.curr_power = 1
M(pos):set_string("infotext", S("TA2 Power Generator"))
end,
after_dig_node = function(pos, oldnode)
Cable:after_dig_node(pos)
Axle:after_dig_node(pos)
techage.del_mem(pos)
end,
tubelib2_on_update2 = tubelib2_on_update2,
on_timer = node_timer,
networks = {
ele1 = {
sides = {R = 1},
ntype = "gen1",
nominal = PWR_PERF,
},
axle = {
sides = {L = 1},
ntype = "con1",
on_power = on_power,
on_nopower = on_nopower,
},
}
})
minetest.register_node("techage:ta2_generator_on", {
description = S("TA2 Power Generator"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_arrow.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_hole_electric.png",
{
image = "techage_filling4_ta2.png^techage_axle_clutch4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
{
image = "techage_filling4_ta2.png^techage_appl_generator_red4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.3,
},
},
{
image = "techage_filling4_ta2.png^techage_appl_generator_red4.png^[transformFX]^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.3,
},
},
},
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
is_ground_content = false,
drop = "",
groups = {not_in_creative_inventory=1},
diggable = false,
tubelib2_on_update2 = tubelib2_on_update2,
on_timer = node_timer,
networks = {
ele1 = {
sides = {R = 1},
ntype = "gen1",
nominal = PWR_PERF,
},
axle = {
sides = {L = 1},
ntype = "con1",
on_power = on_power,
on_nopower = on_nopower,
},
}
})
techage.register_node({"techage:ta2_generator_off", "techage:ta2_generator_on"}, {
on_node_load = function(pos, node)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
Cable:add_secondary_node_names({"techage:ta2_generator_off", "techage:ta2_generator_on"})
Axle:add_secondary_node_names({"techage:ta2_generator_off", "techage:ta2_generator_on"})
minetest.register_craft({
output = "techage:ta2_generator_off",
recipe = {
{"basic_materials:steel_bar", "dye:red", "default:wood"},
{'techage:axle', 'basic_materials:gear_steel', 'techage:electric_cableS'},
{"default:wood", "techage:iron_ingot", "basic_materials:steel_bar"},
},
})

View File

@ -0,0 +1,245 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Electric Motor
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local Cable = techage.ElectricCable
local Axle = techage.Axle
local power = techage.power
local networks = techage.networks
local CYCLE_TIME = 2
local PWR_PERF = 40
-- Axles texture animation
local function switch_axles(pos, on)
for _,outdir in ipairs(networks.get_node_connections(pos, "axle")) do
Axle:switch_tube_line(pos, outdir, on and "on" or "off")
end
end
local function swap_node(pos, name)
local node = techage.get_node_lvm(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function on_power(pos)
local nvm = techage.get_nvm(pos)
nvm.ele1 = nvm.ele1 or {}
nvm.consumer_powered = true
M(pos):set_string("infotext", S("TA3 Electric Motor"))
swap_node(pos, "techage:ta3_motor_on")
nvm.ticks = 0
local outdir = M(pos):get_int("outdir")
nvm.ele1.curr_power = techage.power.needed_power(pos, Axle, outdir)
end
local function on_nopower(pos)
local nvm = techage.get_nvm(pos)
nvm.consumer_powered = false
if (nvm.ticks or 0) < 4 then
M(pos):set_string("infotext", S("TA3 Electric Motor: Overload fault?\n(restart with right-click)"))
end
nvm.ticks = 0
end
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
nvm.ele1 = nvm.ele1 or {}
-- trigger network on consumer side
nvm.ticks = (nvm.ticks or 0) + 1
if nvm.ticks % 2 then
power.consumer_alive(pos, Cable, CYCLE_TIME)
end
-- handle generator side delayed
if nvm.ticks > 3 then
local outdir = M(pos):get_int("outdir")
if nvm.consumer_powered and not nvm.running_as_generator then
nvm.running_as_generator = true
power.generator_start(pos, Axle, CYCLE_TIME, outdir, nvm.max_power)
switch_axles(pos, true)
elseif not nvm.consumer_powered and nvm.running_as_generator then
nvm.running_as_generator = false
power.generator_stop(pos, Axle, outdir)
switch_axles(pos, false)
end
if nvm.running_as_generator then
nvm.ele1.curr_power = power.generator_alive(pos, Axle, CYCLE_TIME, outdir, PWR_PERF) + 1
else
swap_node(pos, "techage:ta3_motor_off")
end
end
return true
end
local function tubelib2_on_update2(pos, outdir, tlib2, node)
local nvm = techage.get_nvm(pos)
nvm.ele1 = nvm.ele1 or {}
nvm.ele1.curr_power = 1
power.update_network(pos, outdir, tlib2)
end
minetest.register_node("techage:ta3_motor_off", {
description = S("TA3 Electric Motor"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_axle_clutch.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_hole_electric.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_generator_red.png^[transformFX]",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_generator_red.png",
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
after_place_node = function(pos)
local nvm = techage.get_nvm(pos)
nvm.ele1 = nvm.ele1 or {}
nvm.ele1.curr_power = 1
nvm.consumer_powered = false
nvm.running_as_generator = false
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
M(pos):set_int("leftdir", networks.side_to_outdir(pos, "L"))
Cable:after_place_node(pos)
Axle:after_place_node(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
power.consumer_start(pos, Cable, CYCLE_TIME*2)
M(pos):set_string("infotext", S("TA3 Electric Motor"))
end,
on_rightclick = function(pos, node, clicker)
local nvm = techage.get_nvm(pos)
nvm.ele1 = nvm.ele1 or {}
nvm.ele1.curr_power = 1
M(pos):set_string("infotext", S("TA3 Electric Motor"))
end,
after_dig_node = function(pos, oldnode)
Cable:after_dig_node(pos)
Axle:after_dig_node(pos)
techage.del_mem(pos)
end,
tubelib2_on_update2 = tubelib2_on_update2,
on_timer = node_timer,
networks = {
axle = {
sides = {R = 1},
ntype = "gen1",
nominal = PWR_PERF,
},
ele1 = {
sides = {L = 1},
ntype = "con1",
on_power = on_power,
on_nopower = on_nopower,
},
}
})
minetest.register_node("techage:ta3_motor_on", {
description = S("TA3 Electric Motor"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
{
image = "techage_filling4_ta3.png^techage_axle_clutch4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_hole_electric.png",
{
image = "techage_filling4_ta3.png^techage_appl_generator_red4.png^[transformFX]^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.3,
},
},
{
image = "techage_filling4_ta3.png^techage_appl_generator_red4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.3,
},
},
},
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
is_ground_content = false,
drop = "",
groups = {not_in_creative_inventory=1},
diggable = false,
tubelib2_on_update2 = tubelib2_on_update2,
on_timer = node_timer,
networks = {
axle = {
sides = {R = 1},
ntype = "gen1",
nominal = PWR_PERF,
},
ele1 = {
sides = {L = 1},
ntype = "con1",
on_power = on_power,
on_nopower = on_nopower,
},
}
})
techage.register_node({"techage:ta3_motor_off", "techage:ta3_motor_on"}, {
on_node_load = function(pos, node)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
Cable:add_secondary_node_names({"techage:ta3_motor_off", "techage:ta3_motor_on"})
Axle:add_secondary_node_names({"techage:ta3_motor_off", "techage:ta3_motor_on"})
minetest.register_craft({
output = "techage:ta3_motor_off",
recipe = {
{"basic_materials:steel_bar", "dye:red", "default:wood"},
{'techage:electric_cableS', 'basic_materials:gear_steel', 'techage:axle'},
{"default:wood", "techage:iron_ingot", "basic_materials:steel_bar"},
},
})

View File

@ -39,7 +39,7 @@ local function formspec(self, pos, nvm)
"image[1.4,1.6;1,1;techage_form_arrow_bg.png^[transformR270]".. "image[1.4,1.6;1,1;techage_form_arrow_bg.png^[transformR270]"..
"image_button[1.4,3.2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]".. "image_button[1.4,3.2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[1.5,3;1,1;"..self:get_state_tooltip(nvm).."]".. "tooltip[1.5,3;1,1;"..self:get_state_tooltip(nvm).."]"..
power.formspec_label_bar(2.5, 0.8, S("Electricity"), PWR_CAPA, nvm.provided) power.formspec_label_bar(pos, 2.5, 0.8, S("Electricity"), PWR_CAPA, nvm.provided)
end end
local function play_sound(pos) local function play_sound(pos)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -245,6 +245,11 @@ local function read_state(itemstack, user, pointed_thing)
fuel = dump(fuel) fuel = dump(fuel)
minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": fuel = "..fuel.." ") minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": fuel = "..fuel.." ")
end end
local output = techage.send_single("0", number, "output", nil)
if output and output ~= "" and output ~= "unsupported" then
output = dump(output)
minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": output = "..output.." ")
end
local load, abs = techage.send_single("0", number, "load", nil) local load, abs = techage.send_single("0", number, "load", nil)
if load and load ~= "" and load ~= "unsupported" then if load and load ~= "" and load ~= "unsupported" then
load, abs = dump(load), abs and dump(abs) or "--" load, abs = dump(load), abs and dump(abs) or "--"

View File

@ -51,46 +51,9 @@ end
local function add_rotor(pos, nvm, player_name) local function add_rotor(pos, nvm, player_name)
nvm.error = false nvm.error = false
-- Check for next wind turbine if not techage.valid_place_for_windturbine(pos, nil, 1) then
local pos1 = {x=pos.x-13, y=pos.y-9, z=pos.z-13}
local pos2 = {x=pos.x+13, y=pos.y+10, z=pos.z+13}
local num = #minetest.find_nodes_in_area(pos1, pos2, {"techage:ta4_wind_turbine"})
if num > 1 then
if player_name then
techage.mark_region(player_name, pos1, pos2, "")
minetest.chat_send_player(player_name, S("[TA4 Wind Turbine]")..
" "..S("The wind turbines are too close together!"))
end
M(pos):set_string("infotext", S("TA4 Wind Turbine").." "..S("Error"))
nvm.error = true
return
end
-- Check for water surface (occean)
pos1 = {x=pos.x-20, y=0, z=pos.z-20}
pos2 = {x=pos.x+20, y=1, z=pos.z+20}
local num = #minetest.find_nodes_in_area(pos1, pos2, {"default:water_source", "default:water_flowing", "ignore"})
if num < (41*41*2-MAX_NUM_FOREIGN_NODES) then
if player_name then
techage.mark_region(player_name, pos1, pos2, "")
minetest.chat_send_player(player_name, S("[TA4 Wind Turbine]")..
" "..S("More water expected (2 m deep)!"))
end
M(pos):set_string("infotext", S("TA4 Wind Turbine").." "..S("Error"))
nvm.error = true
return
end
if pos.y < 12 or pos.y > 20 then
if player_name then
pos1 = {x=pos.x-13, y=12, z=pos.z-13}
pos2 = {x=pos.x+13, y=20, z=pos.z+13}
techage.mark_region(player_name, pos1, pos2, "")
minetest.chat_send_player(player_name, S("[TA4 Wind Turbine]")..
" "..S("No wind at this altitude!"))
end
M(pos):set_string("infotext", S("TA4 Wind Turbine").." "..S("Error"))
nvm.error = true nvm.error = true
M(pos):set_string("infotext", S("TA4 Wind Turbine")..": "..S("Not suitable position!"))
return return
end end

View File

@ -58,7 +58,7 @@ function tubelib2.get_node_lvm(pos)
local data = vm:get_data() local data = vm:get_data()
local param2_data = vm:get_param2_data() local param2_data = vm:get_param2_data()
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge}) local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
local idx = area:index(pos.x, pos.y, pos.z) local idx = area:indexp(pos)
node = { node = {
name = minetest.get_name_from_content_id(data[idx]), name = minetest.get_name_from_content_id(data[idx]),
param2 = param2_data[idx] param2 = param2_data[idx]