forked from MTSR/techage_modpack
built on 18/06/2020 23:23:53
This commit is contained in:
parent
15d227f61c
commit
76bc68f37a
@ -48,6 +48,8 @@ The mod features are:
|
||||
- Minecarts run through unloaded areas (only the stations/hopper have to be loaded)
|
||||
- Extra Minecart privs for rail workers
|
||||
- Ingame documentation (German and English), based on the mod "doc"
|
||||
- API to register carts from other mods
|
||||
- chat command '/mycart <num>' to output cart state and location
|
||||
|
||||
|
||||
Technical Background
|
||||
@ -67,18 +69,21 @@ Introduction
|
||||
2. Place a Railway Buffer at both endpoints. (buffers are always needed,
|
||||
they store the route and timing information)
|
||||
3. Give both Railway Buffers unique station names, like Oxford and Cambridge
|
||||
4. Drive from buffer to buffer in both directions using a Minecart(!) to record the
|
||||
4. Place a Minecart at a buffer and give it a cart number (1..999)
|
||||
5. Drive from buffer to buffer in both directions using the Minecart(!) to record the
|
||||
routes (use 'right-left' keys to control the Minecart)
|
||||
5. Punch the buffers to check the connection data (e.g. "Oxford: connected to Cambridge")
|
||||
6. Optional: Configure the Minecart stop time in one or both buffers. The Minecart
|
||||
6. Punch the buffers to check the connection data (e.g. "Oxford: connected to Cambridge")
|
||||
7. Optional: Configure the Minecart stop time in one or both buffers. The Minecart
|
||||
will then start automatically after the configured time
|
||||
7. Optional: Protect your rail network with the Protection Landmarks (one Landmark
|
||||
8. Optional: Protect your rail network with the Protection Landmarks (one Landmark
|
||||
at least every 16 nodes/meters)
|
||||
8. Place a Minecart in front of the buffer and check whether it starts after the
|
||||
9. Place a Minecart in front of the buffer and check whether it starts after the
|
||||
configured time
|
||||
9. Drop items into the Minecart and punch the cart to start it, or "sneak+click" the
|
||||
Minecart to get the items back
|
||||
10. Dig the empty cart with a second "sneak+click" (as usual)
|
||||
10. Check the cart state via the chat command: /mycart <num>
|
||||
'<num>' is the cart number
|
||||
11. Drop items into the Minecart and punch the cart to start it, or "sneak+click" the
|
||||
Minecart to get the items back
|
||||
12. Dig the empty cart with a second "sneak+click" (as usual)
|
||||
|
||||
|
||||
Hopper
|
||||
@ -107,4 +112,6 @@ History
|
||||
2020-02-24 v1.02 Hopper improved
|
||||
2020-03-05 v1.03 Hopper again improved
|
||||
2020-03-28 v1.04 cart unloading bugfix
|
||||
2020-05-14 v1.05 API changed to be able to register carts
|
||||
2020-06-14 v1.06 API changed and chat command added
|
||||
|
||||
|
@ -1,450 +0,0 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
Cart API for external cart definitions on a node based model
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = minecart.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
|
||||
-- register cart here, because entity is already registered
|
||||
minecart.register_cart_names("minecart:cart", "minecart:cart")
|
||||
|
||||
function minecart.register_cart_entity(entity_name, node_name, entity_def)
|
||||
entity_def.velocity = {x=0, y=0, z=0} -- only used on punch
|
||||
entity_def.old_dir = {x=1, y=0, z=0} -- random value to start the cart on punch
|
||||
entity_def.old_pos = nil
|
||||
entity_def.old_switch = 0
|
||||
entity_def.node_name = node_name
|
||||
minetest.register_entity(entity_name, entity_def)
|
||||
-- register node for punching
|
||||
minecart.register_cart_names(node_name, entity_name)
|
||||
end
|
||||
|
||||
local function switch_to_node(pos, node_name, owner, param2, cargo)
|
||||
local node = minetest.get_node(pos)
|
||||
local rail = node.name
|
||||
local ndef = minetest.registered_nodes[node_name]
|
||||
if ndef then
|
||||
node.name = node_name
|
||||
node.param2 = param2
|
||||
minetest.add_node(pos, node)
|
||||
M(pos):set_string("removed_rail", rail)
|
||||
M(pos):set_string("owner", owner)
|
||||
if ndef.after_place_node then
|
||||
ndef.after_place_node(pos)
|
||||
end
|
||||
if cargo and ndef.set_cargo then
|
||||
ndef.set_cargo(pos, cargo)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function minecart.node_on_place(itemstack, placer, pointed_thing, node_name)
|
||||
local under = pointed_thing.under
|
||||
local node = minetest.get_node(under)
|
||||
local udef = minetest.registered_nodes[node.name]
|
||||
if udef and udef.on_rightclick and
|
||||
not (placer and placer:is_player() and
|
||||
placer:get_player_control().sneak) then
|
||||
return udef.on_rightclick(under, node, placer, itemstack,
|
||||
pointed_thing) or itemstack
|
||||
end
|
||||
|
||||
if not pointed_thing.type == "node" then
|
||||
return
|
||||
end
|
||||
local owner = placer:get_player_name()
|
||||
local param2 = minetest.dir_to_facedir(placer:get_look_dir())
|
||||
if carts:is_rail(pointed_thing.under) then
|
||||
switch_to_node(pointed_thing.under, node_name, owner, param2)
|
||||
elseif carts:is_rail(pointed_thing.above) then
|
||||
switch_to_node(pointed_thing.above, node_name, owner, param2)
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
minetest.sound_play({name = "default_place_node_metal", gain = 0.5},
|
||||
{pos = pointed_thing.above})
|
||||
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(placer:get_player_name())) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function minecart.node_on_punch(pos, node, puncher, pointed_thing, entity_name, dir)
|
||||
local ndef = minetest.registered_nodes[node.name]
|
||||
local cargo = {}
|
||||
-- Player digs cart by sneak-punch
|
||||
if puncher and puncher:get_player_control().sneak then
|
||||
-- Pick up cart
|
||||
if ndef.can_dig and ndef.can_dig(pos, puncher) then
|
||||
local inv = puncher:get_inventory()
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(puncher:get_player_name()))
|
||||
or not inv:contains_item("main", node.name) then
|
||||
local leftover = inv:add_item("main", node.name)
|
||||
-- If no room in inventory add a replacement cart to the world
|
||||
if not leftover:is_empty() then
|
||||
minetest.add_item(pos, leftover)
|
||||
end
|
||||
end
|
||||
node.name = M(pos):get_string("removed_rail")
|
||||
if node.name == "" then
|
||||
node.name = "carts:rail"
|
||||
end
|
||||
minetest.remove_node(pos)
|
||||
minetest.add_node(pos, node)
|
||||
end
|
||||
return
|
||||
end
|
||||
-- start cart
|
||||
node.name = M(pos):get_string("removed_rail")
|
||||
if node.name ~= "" then
|
||||
if ndef.get_cargo then
|
||||
cargo = ndef.get_cargo(pos)
|
||||
end
|
||||
minetest.add_node(pos, node)
|
||||
local obj = minetest.add_entity(pos, entity_name)
|
||||
local owner = puncher and puncher:get_player_name()
|
||||
minecart.add_cart_to_monitoring(obj, owner, cargo)
|
||||
obj:punch(puncher or obj, 1, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 1},
|
||||
}, dir)
|
||||
end
|
||||
end
|
||||
|
||||
function minecart:on_activate(staticdata, dtime_s)
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
end
|
||||
|
||||
|
||||
function minecart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
|
||||
--print("on_punch", direction)
|
||||
local pos = self.object:get_pos()
|
||||
local vel = self.object:get_velocity()
|
||||
local stopped = vector.equals(vel, {x=0, y=0, z=0})
|
||||
|
||||
-- running carts can't be punched
|
||||
if not stopped then
|
||||
return
|
||||
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-authorized player
|
||||
if puncher and self.owner and self.owner ~= puncher:get_player_name()
|
||||
and not minetest.check_player_privs(puncher:get_player_name(), "minecart") then
|
||||
return
|
||||
end
|
||||
|
||||
-- Punched by non-player
|
||||
if not puncher or not puncher:is_player() then
|
||||
local cart_dir = carts:get_rail_direction(pos, direction, 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.punched = true
|
||||
return
|
||||
end
|
||||
|
||||
-- Player digs cart by sneak-punch
|
||||
if puncher:get_player_control().sneak then
|
||||
if self.sound_handle then
|
||||
minetest.sound_stop(self.sound_handle)
|
||||
end
|
||||
|
||||
-- Pick up cart
|
||||
local node_name = self.node_name or "minecart:cart"
|
||||
local inv = puncher:get_inventory()
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(puncher:get_player_name()))
|
||||
or not inv:contains_item("main", node_name) then
|
||||
local leftover = inv:add_item("main", node_name)
|
||||
-- If no room in inventory add a replacement cart to the world
|
||||
if not leftover:is_empty() then
|
||||
minetest.add_item(self.object:get_pos(), leftover)
|
||||
end
|
||||
end
|
||||
minecart.on_dig(self)
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
-- sound refresh interval = 1.0sec
|
||||
local function rail_sound(self, dtime)
|
||||
if not self.sound_ttl then
|
||||
self.sound_ttl = 1.0
|
||||
return
|
||||
elseif self.sound_ttl > 0 then
|
||||
self.sound_ttl = self.sound_ttl - dtime
|
||||
return
|
||||
end
|
||||
self.sound_ttl = 1.0
|
||||
if self.sound_handle then
|
||||
local handle = self.sound_handle
|
||||
self.sound_handle = nil
|
||||
minetest.after(0.2, minetest.sound_stop, handle)
|
||||
end
|
||||
local vel = self.object:get_velocity() or {x=0, y=0, z=0}
|
||||
local speed = vector.length(vel)
|
||||
if speed > 0 then
|
||||
self.sound_handle = minetest.sound_play(
|
||||
"carts_cart_moving", {
|
||||
object = self.object,
|
||||
gain = (speed / carts.speed_max) / 2,
|
||||
loop = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function get_railparams(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
return carts.railparams[node.name] or {}
|
||||
end
|
||||
|
||||
local function rail_on_step(self, dtime)
|
||||
local vel = self.object:get_velocity()
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
if self.punched then
|
||||
minecart.start_run(self, pos, vel, self.driver)
|
||||
vel = vector.add(vel, self.velocity)
|
||||
self.object:set_velocity(vel)
|
||||
self.old_dir.y = 0
|
||||
elseif vector.equals(vel, {x=0, y=0, z=0}) then
|
||||
if minecart.get_route_key(pos) then
|
||||
local cargo = minecart.stopped(self, pos)
|
||||
local param2 = minetest.dir_to_facedir(self.old_dir)
|
||||
switch_to_node(vector.round(pos), self.node_name, self.owner, param2, cargo)
|
||||
minecart.on_dig(self)
|
||||
self.object:remove()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- cart position correction on slopes
|
||||
local rot = self.object:get_rotation()
|
||||
if rot.x ~= 0 then
|
||||
pos.y = pos.y - 0.5
|
||||
end
|
||||
|
||||
local cart_dir = carts:velocity_to_dir(vel)
|
||||
local same_dir = vector.equals(cart_dir, self.old_dir)
|
||||
local update = {}
|
||||
|
||||
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
|
||||
|
||||
local ctrl, player
|
||||
|
||||
|
||||
local stop_wiggle = false
|
||||
if self.old_pos and same_dir then
|
||||
-- Detection for "skipping" nodes (perhaps use average dtime?)
|
||||
-- It's sophisticated enough to take the acceleration in account
|
||||
local acc = self.object:get_acceleration()
|
||||
local distance = dtime * (vector.length(vel) + 0.5 * dtime * vector.length(acc))
|
||||
|
||||
local new_pos, new_dir = carts:pathfinder(
|
||||
pos, self.old_pos, self.old_dir, distance, ctrl,
|
||||
self.old_switch, self.railtype
|
||||
)
|
||||
|
||||
if new_pos then
|
||||
-- No rail found: set to the expected position
|
||||
pos = new_pos
|
||||
update.pos = true
|
||||
cart_dir = new_dir
|
||||
end
|
||||
elseif self.old_pos and self.old_dir.y ~= 1 and not self.punched then
|
||||
-- Stop wiggle
|
||||
stop_wiggle = true
|
||||
end
|
||||
|
||||
local railparams
|
||||
|
||||
-- dir: New moving direction of the cart
|
||||
-- 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
|
||||
)
|
||||
------------------------------- changed
|
||||
if switch_keys then
|
||||
minecart.set_junction(self, pos, dir, switch_keys)
|
||||
else
|
||||
dir, switch_keys = minecart.get_junction(self, pos, dir)
|
||||
end
|
||||
------------------------------- changed
|
||||
local dir_changed = not vector.equals(dir, self.old_dir)
|
||||
|
||||
local new_acc = {x=0, y=0, z=0}
|
||||
if stop_wiggle or vector.equals(dir, {x=0, y=0, z=0}) then
|
||||
vel = {x = 0, y = 0, z = 0}
|
||||
local pos_r = vector.round(pos)
|
||||
if not carts:is_rail(pos_r, self.railtype)
|
||||
and self.old_pos then
|
||||
pos = self.old_pos
|
||||
elseif not stop_wiggle then
|
||||
pos = pos_r
|
||||
else
|
||||
pos.y = math.floor(pos.y + 0.5)
|
||||
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 * -4.0
|
||||
|
||||
-- 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
|
||||
-- Handbrake or coast
|
||||
if ctrl and ctrl.down then
|
||||
acc = acc - 3
|
||||
else
|
||||
acc = acc - 0.4
|
||||
end
|
||||
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}) and not stop_wiggle 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
|
||||
return
|
||||
end
|
||||
|
||||
local yaw = 0
|
||||
if self.old_dir.x < 0 then
|
||||
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
|
||||
if dir.y == -1 then
|
||||
pitch = math.pi/4
|
||||
elseif dir.y == 1 then
|
||||
pitch = -math.pi/4
|
||||
end
|
||||
end
|
||||
self.object:set_rotation({x = pitch, y = yaw, z = 0})
|
||||
|
||||
-- cart position correction on slopes
|
||||
if pitch ~= 0 then
|
||||
pos.y = pos.y + 0.5
|
||||
update.pos = true
|
||||
end
|
||||
|
||||
if update.vel then
|
||||
self.object:set_velocity(vel)
|
||||
end
|
||||
if update.pos then
|
||||
if dir_changed then
|
||||
self.object:set_pos(pos)
|
||||
else
|
||||
self.object:move_to(pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minecart:on_step(dtime)
|
||||
rail_on_step(self, dtime)
|
||||
rail_sound(self, dtime)
|
||||
end
|
@ -1,468 +0,0 @@
|
||||
local S = minecart.S
|
||||
|
||||
local cart_entity = {
|
||||
initial_properties = {
|
||||
physical = false, -- otherwise going uphill breaks
|
||||
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
visual = "mesh",
|
||||
mesh = "carts_cart.b3d",
|
||||
visual_size = {x=1, y=1},
|
||||
textures = {"carts_cart.png^minecart_cart.png"},
|
||||
static_save = false,
|
||||
},
|
||||
------------------------------------ changed
|
||||
owner = nil,
|
||||
------------------------------------ changed
|
||||
driver = nil,
|
||||
punched = false, -- used to re-send velocity and position
|
||||
velocity = {x=0, y=0, z=0}, -- only used on punch
|
||||
old_dir = {x=1, y=0, z=0}, -- random value to start the cart on punch
|
||||
old_pos = nil,
|
||||
old_switch = 0,
|
||||
railtype = nil,
|
||||
attached_items = {}
|
||||
}
|
||||
|
||||
function cart_entity:on_rightclick(clicker)
|
||||
if not clicker or not clicker:is_player() then
|
||||
return
|
||||
end
|
||||
local player_name = clicker:get_player_name()
|
||||
if self.driver and player_name == self.driver then
|
||||
self.driver = nil
|
||||
carts:manage_attachment(clicker, nil)
|
||||
elseif not self.driver then
|
||||
self.driver = player_name
|
||||
carts:manage_attachment(clicker, self.object)
|
||||
|
||||
-- player_api does not update the animation
|
||||
-- when the player is attached, reset to default animation
|
||||
player_api.set_animation(clicker, "stand")
|
||||
end
|
||||
end
|
||||
|
||||
function cart_entity:on_activate(staticdata, dtime_s)
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
end
|
||||
|
||||
-- 0.5.x and later: When the driver leaves
|
||||
function cart_entity:on_detach_child(child)
|
||||
if child and child:get_player_name() == self.driver then
|
||||
self.driver = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function add_cargo_to_player_inv(self, pos, puncher)
|
||||
local added = false
|
||||
local inv = puncher:get_inventory()
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do
|
||||
local entity = obj:get_luaentity()
|
||||
if not obj:is_player() and entity and entity.name == "__builtin:item" then
|
||||
obj:remove()
|
||||
local item = ItemStack(entity.itemstring)
|
||||
local leftover = inv:add_item("main", item)
|
||||
if leftover:get_count() > 0 then
|
||||
minetest.add_item(pos, leftover)
|
||||
end
|
||||
added = true
|
||||
end
|
||||
end
|
||||
return added
|
||||
end
|
||||
|
||||
function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
|
||||
local pos = self.object:get_pos()
|
||||
local vel = self.object:get_velocity()
|
||||
if not self.railtype or vector.equals(vel, {x=0, y=0, z=0}) then
|
||||
local node = minetest.get_node(pos).name
|
||||
self.railtype = minetest.get_item_group(node, "connect_to_raillike")
|
||||
end
|
||||
-- Punched by non-player
|
||||
if not puncher or not puncher:is_player() then
|
||||
local cart_dir = carts:get_rail_direction(pos, direction, 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.punched = true
|
||||
return
|
||||
end
|
||||
------------------------------------ changed
|
||||
-- Punched by non-authorized player
|
||||
if puncher and self.owner and self.owner ~= puncher:get_player_name()
|
||||
and not minetest.check_player_privs(puncher:get_player_name(), "minecart") then
|
||||
return
|
||||
end
|
||||
------------------------------------ changed
|
||||
-- Player digs cart by sneak-punch
|
||||
if puncher:get_player_control().sneak then
|
||||
if self.sound_handle then
|
||||
minetest.sound_stop(self.sound_handle)
|
||||
end
|
||||
-- Detach driver and items
|
||||
if self.driver then
|
||||
if self.old_pos then
|
||||
self.object:set_pos(self.old_pos)
|
||||
end
|
||||
local player = minetest.get_player_by_name(self.driver)
|
||||
carts:manage_attachment(player, nil)
|
||||
end
|
||||
------------------------------------ changed
|
||||
if add_cargo_to_player_inv(self, pos, puncher) then
|
||||
return
|
||||
end
|
||||
------------------------------------ changed
|
||||
-- Pick up cart
|
||||
local inv = puncher:get_inventory()
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(puncher:get_player_name()))
|
||||
or not inv:contains_item("main", "minecart:cart") then
|
||||
local leftover = inv:add_item("main", "minecart:cart")
|
||||
-- If no room in inventory add a replacement cart to the world
|
||||
if not leftover:is_empty() then
|
||||
minetest.add_item(self.object:get_pos(), leftover)
|
||||
end
|
||||
end
|
||||
------------------------------------ changed
|
||||
minecart.on_dig(self)
|
||||
------------------------------------ changed
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
------------------------------------ changed
|
||||
minecart.start_recording(self, pos, vel, puncher)
|
||||
------------------------------------ changed
|
||||
-- Player punches cart to alter velocity
|
||||
if puncher:get_player_name() == self.driver then
|
||||
if math.abs(vel.x + vel.z) > carts.punch_speed_max then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
local punch_interval = 1
|
||||
if tool_capabilities and tool_capabilities.full_punch_interval then
|
||||
punch_interval = tool_capabilities.full_punch_interval
|
||||
end
|
||||
time_from_last_punch = math.min(time_from_last_punch or punch_interval, punch_interval)
|
||||
local f = 2 * (time_from_last_punch / punch_interval)
|
||||
|
||||
------------------------------------ changed
|
||||
if vector.equals(vel, {x=0, y=0, z=0}) then
|
||||
self.velocity = vector.multiply(cart_dir, f)
|
||||
else
|
||||
self.velocity = {x=0, y=0, z=0}
|
||||
end
|
||||
------------------------------------ changed
|
||||
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
|
||||
|
||||
-- sound refresh interval = 1.0sec
|
||||
local function rail_sound(self, dtime)
|
||||
if not self.sound_ttl then
|
||||
self.sound_ttl = 1.0
|
||||
return
|
||||
elseif self.sound_ttl > 0 then
|
||||
self.sound_ttl = self.sound_ttl - dtime
|
||||
return
|
||||
end
|
||||
self.sound_ttl = 1.0
|
||||
if self.sound_handle then
|
||||
local handle = self.sound_handle
|
||||
self.sound_handle = nil
|
||||
minetest.after(0.2, minetest.sound_stop, handle)
|
||||
end
|
||||
local vel = self.object:get_velocity()
|
||||
local speed = vector.length(vel)
|
||||
if speed > 0 then
|
||||
self.sound_handle = minetest.sound_play(
|
||||
"carts_cart_moving", {
|
||||
object = self.object,
|
||||
gain = (speed / carts.speed_max) / 2,
|
||||
loop = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function get_railparams(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
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()
|
||||
------------------------------------ changed
|
||||
local pos = self.object:get_pos()
|
||||
minecart.store_next_waypoint(self, pos, vel)
|
||||
------------------------------------ changed
|
||||
if self.punched then
|
||||
------------------------------- changed
|
||||
minecart.start_run(self, pos, vel, self.driver)
|
||||
------------------------------- changed
|
||||
vel = vector.add(vel, self.velocity)
|
||||
self.object:set_velocity(vel)
|
||||
self.old_dir.y = 0
|
||||
elseif vector.equals(vel, {x=0, y=0, z=0}) then
|
||||
------------------------------- changed
|
||||
minecart.stopped(self, pos)
|
||||
------------------------------- changed
|
||||
return
|
||||
end
|
||||
|
||||
--local pos = self.object:get_pos()
|
||||
local cart_dir = carts:velocity_to_dir(vel)
|
||||
local same_dir = vector.equals(cart_dir, self.old_dir)
|
||||
local update = {}
|
||||
|
||||
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
|
||||
|
||||
local ctrl, player
|
||||
|
||||
-- Get player controls
|
||||
if self.driver then
|
||||
player = minetest.get_player_by_name(self.driver)
|
||||
if player then
|
||||
ctrl = player:get_player_control()
|
||||
end
|
||||
end
|
||||
|
||||
local stop_wiggle = false
|
||||
if self.old_pos and same_dir then
|
||||
-- Detection for "skipping" nodes (perhaps use average dtime?)
|
||||
-- It's sophisticated enough to take the acceleration in account
|
||||
local acc = self.object:get_acceleration()
|
||||
local distance = dtime * (v3_len(vel) + 0.5 * dtime * v3_len(acc))
|
||||
|
||||
local new_pos, new_dir = carts:pathfinder(
|
||||
pos, self.old_pos, self.old_dir, distance, ctrl,
|
||||
self.old_switch, self.railtype
|
||||
)
|
||||
|
||||
if new_pos then
|
||||
-- No rail found: set to the expected position
|
||||
pos = new_pos
|
||||
update.pos = true
|
||||
cart_dir = new_dir
|
||||
end
|
||||
elseif self.old_pos and self.old_dir.y ~= 1 and not self.punched then
|
||||
-- Stop wiggle
|
||||
stop_wiggle = true
|
||||
end
|
||||
|
||||
local railparams
|
||||
|
||||
-- dir: New moving direction of the cart
|
||||
-- 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
|
||||
)
|
||||
------------------------------- changed
|
||||
if switch_keys then
|
||||
minecart.set_junction(self, pos, dir, switch_keys)
|
||||
else
|
||||
dir, switch_keys = minecart.get_junction(self, pos, dir)
|
||||
end
|
||||
------------------------------- changed
|
||||
local dir_changed = not vector.equals(dir, self.old_dir)
|
||||
|
||||
local new_acc = {x=0, y=0, z=0}
|
||||
if stop_wiggle or vector.equals(dir, {x=0, y=0, z=0}) then
|
||||
vel = {x = 0, y = 0, z = 0}
|
||||
local pos_r = vector.round(pos)
|
||||
if not carts:is_rail(pos_r, self.railtype)
|
||||
and self.old_pos then
|
||||
pos = self.old_pos
|
||||
elseif not stop_wiggle then
|
||||
pos = pos_r
|
||||
else
|
||||
pos.y = math.floor(pos.y + 0.5)
|
||||
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 * -4.0
|
||||
|
||||
-- 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
|
||||
-- Handbrake or coast
|
||||
if ctrl and ctrl.down then
|
||||
acc = acc - 3
|
||||
else
|
||||
acc = acc - 0.4
|
||||
end
|
||||
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}) and not stop_wiggle then
|
||||
self.old_dir = vector.new(dir)
|
||||
end
|
||||
self.old_switch = switch_keys
|
||||
|
||||
if self.punched then
|
||||
-- Collect dropped items
|
||||
------------------------------- changed
|
||||
minecart.attach_cargo(self, pos)
|
||||
------------------------------- changed
|
||||
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
|
||||
end
|
||||
|
||||
local yaw = 0
|
||||
if self.old_dir.x < 0 then
|
||||
yaw = 0.5
|
||||
elseif self.old_dir.x > 0 then
|
||||
yaw = 1.5
|
||||
elseif self.old_dir.z < 0 then
|
||||
yaw = 1
|
||||
end
|
||||
self.object:set_yaw(yaw * math.pi)
|
||||
|
||||
local anim = {x=0, y=0}
|
||||
if dir.y == -1 then
|
||||
anim = {x=1, y=1}
|
||||
elseif dir.y == 1 then
|
||||
anim = {x=2, y=2}
|
||||
end
|
||||
self.object:set_animation(anim, 1, 0)
|
||||
|
||||
if update.vel then
|
||||
self.object:set_velocity(vel)
|
||||
end
|
||||
if update.pos then
|
||||
if dir_changed then
|
||||
self.object:set_pos(pos)
|
||||
else
|
||||
self.object:move_to(pos)
|
||||
end
|
||||
end
|
||||
|
||||
-- call event handler
|
||||
rail_on_step_event(railparams.on_step, self, dtime)
|
||||
end
|
||||
|
||||
function cart_entity:on_step(dtime)
|
||||
rail_on_step(self, dtime)
|
||||
rail_sound(self, dtime)
|
||||
end
|
||||
|
||||
minetest.register_entity("minecart:cart", cart_entity)
|
||||
|
||||
minetest.register_craftitem("minecart:cart", {
|
||||
description = S("Minecart (Sneak+Click to pick up)"),
|
||||
inventory_image = minetest.inventorycube("carts_cart_top.png", "carts_cart_side.png^minecart_logo.png", "carts_cart_side.png^minecart_logo.png"),
|
||||
wield_image = "carts_cart_side.png",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local under = pointed_thing.under
|
||||
local node = minetest.get_node(under)
|
||||
local udef = minetest.registered_nodes[node.name]
|
||||
if udef and udef.on_rightclick and
|
||||
not (placer and placer:is_player() and
|
||||
placer:get_player_control().sneak) then
|
||||
return udef.on_rightclick(under, node, placer, itemstack,
|
||||
pointed_thing) or itemstack
|
||||
end
|
||||
|
||||
if not pointed_thing.type == "node" then
|
||||
return
|
||||
end
|
||||
if carts:is_rail(pointed_thing.under) then
|
||||
------------------------------- changed
|
||||
local cart = minetest.add_entity(pointed_thing.under, "minecart:cart")
|
||||
minecart.add_cart_to_monitoring(cart, placer:get_player_name())
|
||||
------------------------------- changed
|
||||
elseif carts:is_rail(pointed_thing.above) then
|
||||
------------------------------- changed
|
||||
local cart = minetest.add_entity(pointed_thing.above, "minecart:cart")
|
||||
minecart.add_cart_to_monitoring(cart, placer:get_player_name())
|
||||
------------------------------- changed
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
minetest.sound_play({name = "default_place_node_metal", gain = 0.5},
|
||||
{pos = pointed_thing.above})
|
||||
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(placer:get_player_name())) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "minecart:cart",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:cobble", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
},
|
||||
})
|
416
minecart/cart_lib1.lua
Normal file
416
minecart/cart_lib1.lua
Normal file
@ -0,0 +1,416 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
Cart library functions (level 1)
|
||||
|
||||
]]--
|
||||
|
||||
-- Notes:
|
||||
-- 1) Only the owner can punch der cart
|
||||
-- 2) Only the owner can start the recording
|
||||
-- 3) But any player can act as cargo, cart punched by owner or buffer
|
||||
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = minecart.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
|
||||
local api = {}
|
||||
|
||||
function api:init(is_node_cart)
|
||||
local lib
|
||||
|
||||
if is_node_cart then
|
||||
lib = dofile(MP.."/cart_lib2n.lua")
|
||||
else
|
||||
lib = dofile(MP.."/cart_lib2e.lua")
|
||||
end
|
||||
|
||||
-- add lib to local api
|
||||
for k,v in pairs(lib) do
|
||||
api[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
-- Player get on / off
|
||||
function api:on_rightclick(clicker)
|
||||
if not clicker or not clicker:is_player() then
|
||||
return
|
||||
end
|
||||
local player_name = clicker:get_player_name()
|
||||
if self.driver and player_name == self.driver then
|
||||
self.driver = nil
|
||||
carts:manage_attachment(clicker, nil)
|
||||
elseif not self.driver then
|
||||
self.driver = player_name
|
||||
carts:manage_attachment(clicker, self.object)
|
||||
|
||||
-- player_api does not update the animation
|
||||
-- when the player is attached, reset to default animation
|
||||
player_api.set_animation(clicker, "stand")
|
||||
end
|
||||
end
|
||||
|
||||
function api:on_activate(staticdata, dtime_s)
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
end
|
||||
|
||||
function api:on_detach_child(child)
|
||||
if child and child:get_player_name() == self.driver then
|
||||
self.driver = nil
|
||||
end
|
||||
end
|
||||
|
||||
function api:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
|
||||
local pos = self.object:get_pos()
|
||||
local vel = self.object:get_velocity()
|
||||
local stopped = vector.equals(vel, {x=0, y=0, z=0})
|
||||
local is_minecart = self.node_name == nil
|
||||
local node_name = self.node_name or "minecart:cart"
|
||||
local puncher_name = puncher and puncher:is_player() and puncher:get_player_name()
|
||||
local puncher_is_owner = puncher_name and (not self.owner or self.owner == "" or
|
||||
puncher_name == self.owner or
|
||||
minetest.check_player_privs(puncher_name, "minecart"))
|
||||
local puncher_is_driver = self.driver and self.driver == puncher_name
|
||||
local sneak_punch = puncher_name and puncher:get_player_control().sneak
|
||||
local no_cargo = next(self.cargo or {}) == nil
|
||||
|
||||
-- driver wants to leave/remove the empty Minecart by sneak-punch
|
||||
if is_minecart and sneak_punch and puncher_is_driver and no_cargo then
|
||||
if puncher_is_owner then
|
||||
api.remove_cart(self, pos, puncher)
|
||||
end
|
||||
carts:manage_attachment(puncher, nil)
|
||||
return
|
||||
end
|
||||
|
||||
-- running carts can't be punched or removed from external
|
||||
if not stopped then
|
||||
return
|
||||
end
|
||||
|
||||
-- Punched by non-authorized player
|
||||
if puncher_name and not puncher_is_owner then
|
||||
minetest.chat_send_player(puncher_name, S("[minecart] Cart is protected by ")..(self.owner or ""))
|
||||
return
|
||||
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
|
||||
if not puncher_name then
|
||||
local cart_dir = carts:get_rail_direction(pos, direction, 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.punched = true
|
||||
api.load_cargo(self, pos)
|
||||
minecart.start_cart(pos, self.myID)
|
||||
return
|
||||
end
|
||||
|
||||
-- Sneak-punched by owner
|
||||
if sneak_punch then
|
||||
-- Unload the cargo
|
||||
if api.add_cargo_to_player_inv(self, pos, puncher) then
|
||||
return
|
||||
end
|
||||
-- detach driver
|
||||
if self.driver then
|
||||
carts:manage_attachment(puncher_name, nil)
|
||||
end
|
||||
-- Pick up cart
|
||||
api.remove_cart(self, pos, puncher)
|
||||
return
|
||||
end
|
||||
|
||||
-- Cart with driver punched to start recording
|
||||
if puncher_is_driver then
|
||||
minecart.start_recording(self, pos, vel, puncher)
|
||||
else
|
||||
minecart.start_cart(pos, self.myID)
|
||||
end
|
||||
|
||||
api.load_cargo(self, pos)
|
||||
|
||||
-- Normal punch by owner to start the cart
|
||||
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
|
||||
|
||||
-- sound refresh interval = 1.0sec
|
||||
local function rail_sound(self, dtime)
|
||||
if not self.sound_ttl then
|
||||
self.sound_ttl = 1.0
|
||||
return
|
||||
elseif self.sound_ttl > 0 then
|
||||
self.sound_ttl = self.sound_ttl - dtime
|
||||
return
|
||||
end
|
||||
self.sound_ttl = 1.0
|
||||
if self.sound_handle then
|
||||
local handle = self.sound_handle
|
||||
self.sound_handle = nil
|
||||
minetest.after(0.2, minetest.sound_stop, handle)
|
||||
end
|
||||
if not self.stopped then
|
||||
local vel = self.object:get_velocity() or {x=0, y=0, z=0}
|
||||
local speed = vector.length(vel)
|
||||
self.sound_handle = minetest.sound_play(
|
||||
"carts_cart_moving", {
|
||||
object = self.object,
|
||||
gain = (speed / carts.speed_max) / 2,
|
||||
loop = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function get_railparams(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
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 rot = self.object:get_rotation()
|
||||
local stopped = minecart.stopped(vel) and rot.x == 0
|
||||
local is_minecart = self.node_name == nil
|
||||
local recording = is_minecart and self.driver == self.owner
|
||||
|
||||
-- cart position correction on slopes
|
||||
if rot.x ~= 0 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)
|
||||
api.stop_cart(pos, self, self.node_name or "minecart:cart", param2)
|
||||
if recording then
|
||||
minecart.stop_recording(self, pos, vel, self.driver)
|
||||
end
|
||||
api.unload_cargo(self, pos)
|
||||
self.stopped = true
|
||||
self.object:set_velocity({x=0, y=0, z=0})
|
||||
self.object:set_acceleration({x=0, y=0, z=0})
|
||||
return
|
||||
elseif stopped then
|
||||
return
|
||||
end
|
||||
|
||||
if recording then
|
||||
minecart.store_next_waypoint(self, pos, vel)
|
||||
end
|
||||
|
||||
local cart_dir = carts:velocity_to_dir(vel)
|
||||
local same_dir = vector.equals(cart_dir, self.old_dir)
|
||||
local update = {}
|
||||
|
||||
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
|
||||
|
||||
local ctrl, player
|
||||
|
||||
-- Get player controls
|
||||
if recording then
|
||||
player = minetest.get_player_by_name(self.driver)
|
||||
if player then
|
||||
ctrl = player:get_player_control()
|
||||
end
|
||||
end
|
||||
|
||||
local railparams
|
||||
|
||||
-- dir: New moving direction of the cart
|
||||
-- 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
|
||||
if switch_keys then -- recording
|
||||
minecart.set_junction(self, pos, dir, switch_keys)
|
||||
else -- normal run
|
||||
dir, switch_keys = minecart.get_junction(self, pos, dir)
|
||||
end
|
||||
|
||||
local dir_changed = not vector.equals(dir, self.old_dir)
|
||||
|
||||
local new_acc = {x=0, y=0, z=0}
|
||||
if vector.equals(dir, {x=0, y=0, z=0}) then
|
||||
vel = {x = 0, y = 0, z = 0}
|
||||
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 * -2.0
|
||||
|
||||
-- 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
|
||||
end
|
||||
|
||||
local yaw = 0
|
||||
if self.old_dir.x < 0 then
|
||||
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
|
||||
if dir.y == -1 then
|
||||
pitch = math.pi/4
|
||||
elseif dir.y == 1 then
|
||||
pitch = -math.pi/4
|
||||
end
|
||||
end
|
||||
self.object:set_rotation({x = pitch, y = yaw, z = 0})
|
||||
|
||||
-- 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
|
||||
self.object:set_velocity(vel)
|
||||
end
|
||||
if update.pos then
|
||||
if dir_changed then
|
||||
self.object:set_pos(pos)
|
||||
else
|
||||
self.object:move_to(pos)
|
||||
end
|
||||
end
|
||||
|
||||
-- call event handler
|
||||
rail_on_step_event(railparams.on_step, self, dtime)
|
||||
end
|
||||
|
||||
function api:on_step(dtime)
|
||||
rail_on_step(self, dtime)
|
||||
rail_sound(self, dtime)
|
||||
end
|
||||
|
||||
return api
|
150
minecart/cart_lib2e.lua
Normal file
150
minecart/cart_lib2e.lua
Normal file
@ -0,0 +1,150 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
Cart library functions for entity based carts (level 2)
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = minecart.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
|
||||
local api = dofile(MP.."/cart_lib3.lua")
|
||||
|
||||
-- Add node, set metadata, and load carge
|
||||
local function add_cart(pos, node_name, param2, owner, userID, cargo)
|
||||
local obj = minetest.add_entity(pos, node_name)
|
||||
local myID = api.get_object_id(obj)
|
||||
if myID then
|
||||
-- Copy item data to cart entity
|
||||
local entity = obj:get_luaentity()
|
||||
entity.owner = owner
|
||||
entity.userID = userID
|
||||
entity.cargo = cargo
|
||||
entity.myID = myID
|
||||
obj:set_nametag_attributes({color = "#FFFF00", text = owner..": "..userID})
|
||||
minecart.add_to_monitoring(obj, myID, owner, userID)
|
||||
return myID
|
||||
else
|
||||
print("Entity has no ID")
|
||||
end
|
||||
end
|
||||
|
||||
function api.stop_cart(pos, entity, node_name, param2)
|
||||
-- Stop sound
|
||||
if entity.sound_handle then
|
||||
minetest.sound_stop(entity.sound_handle)
|
||||
entity.sound_handle = nil
|
||||
end
|
||||
minecart.stop_cart(pos, entity.myID)
|
||||
end
|
||||
|
||||
|
||||
-- Player adds the node
|
||||
function api.add_cart(itemstack, placer, pointed_thing, node_name)
|
||||
local owner = placer:get_player_name()
|
||||
local meta = placer:get_meta()
|
||||
local param2 = minetest.dir_to_facedir(placer:get_look_dir())
|
||||
local userID = 0
|
||||
local cargo = {}
|
||||
|
||||
-- Add node
|
||||
if carts:is_rail(pointed_thing.under) then
|
||||
add_cart(pointed_thing.under, node_name, param2, owner, userID, cargo)
|
||||
meta:set_string("cart_pos", P2S(pointed_thing.under))
|
||||
elseif carts:is_rail(pointed_thing.above) then
|
||||
add_cart(pointed_thing.above, node_name, param2, owner, userID, cargo)
|
||||
meta:set_string("cart_pos", P2S(pointed_thing.above))
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
minetest.sound_play({name = "default_place_node_metal", gain = 0.5},
|
||||
{pos = pointed_thing.above})
|
||||
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(placer:get_player_name())) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
minetest.show_formspec(owner, "minecart:userID_entity",
|
||||
"size[4,3]" ..
|
||||
"label[0,0;Enter cart number:]" ..
|
||||
"field[1,1;3,1;userID;;]" ..
|
||||
"button_exit[1,2;2,1;exit;Save]")
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Player removes the node
|
||||
function api.remove_cart(self, pos, player)
|
||||
-- Add cart to player inventory
|
||||
local inv = player:get_inventory()
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(player:get_player_name()))
|
||||
or not inv:contains_item("main", "minecart:cart") then
|
||||
local leftover = inv:add_item("main", "minecart:cart")
|
||||
-- If no room in inventory add a replacement cart to the world
|
||||
if not leftover:is_empty() then
|
||||
minetest.add_item(pos, leftover)
|
||||
end
|
||||
end
|
||||
minecart.remove_from_monitoring(self.myID)
|
||||
self.object:remove()
|
||||
-- Stop sound
|
||||
if self.sound_handle then
|
||||
minetest.sound_stop(self.sound_handle)
|
||||
self.sound_handle = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function api.load_cargo(self, pos)
|
||||
self.cargo = self.cargo or {}
|
||||
for _, obj_ in pairs(minetest.get_objects_inside_radius(pos, 1)) do
|
||||
local entity = obj_:get_luaentity()
|
||||
if not obj_:is_player() and entity and entity.name == "__builtin:item" then
|
||||
obj_:remove()
|
||||
self.cargo[#self.cargo + 1] = entity.itemstring
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function api.unload_cargo(self, pos)
|
||||
-- Spawn loaded items again
|
||||
for _,item in ipairs(self.cargo or {}) do
|
||||
minetest.add_item(pos, ItemStack(item))
|
||||
end
|
||||
self.cargo = {}
|
||||
end
|
||||
|
||||
-- in the case the owner punches the cart
|
||||
function api.add_cargo_to_player_inv(self, pos, puncher)
|
||||
local added = false
|
||||
local inv = puncher:get_inventory()
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do
|
||||
local entity = obj:get_luaentity()
|
||||
if not obj:is_player() and entity and entity.name == "__builtin:item" then
|
||||
obj:remove()
|
||||
local item = ItemStack(entity.itemstring)
|
||||
local leftover = inv:add_item("main", item)
|
||||
if leftover:get_count() > 0 then
|
||||
minetest.add_item(pos, leftover)
|
||||
end
|
||||
added = true -- don't dig the cart
|
||||
end
|
||||
end
|
||||
return added
|
||||
end
|
||||
|
||||
return api
|
198
minecart/cart_lib2n.lua
Normal file
198
minecart/cart_lib2n.lua
Normal file
@ -0,0 +1,198 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
Cart library functions for node based carts (level 2)
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = minecart.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
|
||||
local api = dofile(MP.."/cart_lib3.lua")
|
||||
|
||||
-- Add node, set metadata, and load carge
|
||||
local function add_cart(pos, node_name, param2, owner, userID, cargo)
|
||||
local ndef = minetest.registered_nodes[node_name]
|
||||
local node = minetest.get_node(pos)
|
||||
local meta = M(pos)
|
||||
local rail = node.name
|
||||
minetest.add_node(pos, {name = node_name, param2 = param2})
|
||||
meta:set_string("removed_rail", rail)
|
||||
meta:set_string("owner", owner)
|
||||
meta:set_string("userID", userID)
|
||||
meta:set_string("infotext", minetest.get_color_escape_sequence("#FFFF00")..owner..": "..userID)
|
||||
if ndef.after_place_node then
|
||||
ndef.after_place_node(pos)
|
||||
end
|
||||
if cargo and ndef.set_cargo then
|
||||
ndef.set_cargo(pos, cargo)
|
||||
end
|
||||
end
|
||||
|
||||
-- called after punch cart
|
||||
local function start_cart(pos, node_name, entity_name, puncher, dir)
|
||||
-- Read node metadata
|
||||
local ndef = minetest.registered_nodes[node_name]
|
||||
if ndef then
|
||||
local meta = M(pos)
|
||||
local rail = meta:get_string("removed_rail")
|
||||
local userID = meta:get_int("userID")
|
||||
local cart_owner = meta:get_string("owner")
|
||||
local cargo = ndef.get_cargo and ndef.get_cargo(pos) or {}
|
||||
-- swap node to rail
|
||||
minetest.remove_node(pos)
|
||||
minetest.add_node(pos, {name = rail})
|
||||
-- Add entity
|
||||
local obj = minetest.add_entity(pos, entity_name)
|
||||
-- Determine ID
|
||||
local myID = api.get_object_id(obj)
|
||||
if myID then
|
||||
-- Copy metadata to cart entity
|
||||
local entity = obj:get_luaentity()
|
||||
entity.owner = cart_owner
|
||||
entity.userID = userID
|
||||
entity.cargo = cargo
|
||||
entity.myID = myID
|
||||
obj:set_nametag_attributes({color = "#ffff00", text = cart_owner..": "..userID})
|
||||
minecart.add_to_monitoring(obj, myID, cart_owner, userID)
|
||||
minecart.node_at_station(cart_owner, userID, nil)
|
||||
-- punch cart to prevent the stopped handling
|
||||
obj:punch(puncher or obj, 1, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 1},
|
||||
}, dir)
|
||||
return myID
|
||||
else
|
||||
print("Entity has no ID")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function api.stop_cart(pos, entity, node_name, param2)
|
||||
-- rail buffer reached?
|
||||
if api.get_route_key(pos) then
|
||||
-- Read entity data
|
||||
local owner = entity.owner or ""
|
||||
local userID = entity.userID or 0
|
||||
local cargo = entity.cargo or {}
|
||||
-- Remove entity
|
||||
minecart.remove_from_monitoring(entity.myID)
|
||||
minecart.node_at_station(owner, userID, pos)
|
||||
entity.object:remove()
|
||||
-- Add cart node
|
||||
add_cart(pos, node_name, param2, owner, userID, cargo)
|
||||
end
|
||||
-- Stop sound
|
||||
if entity.sound_handle then
|
||||
minetest.sound_stop(entity.sound_handle)
|
||||
entity.sound_handle = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Player adds the node
|
||||
function api.add_cart(itemstack, placer, pointed_thing, node_name)
|
||||
local owner = placer:get_player_name()
|
||||
local meta = placer:get_meta()
|
||||
local param2 = minetest.dir_to_facedir(placer:get_look_dir())
|
||||
local userID = 0
|
||||
local cargo = {}
|
||||
|
||||
-- Add node
|
||||
if carts:is_rail(pointed_thing.under) then
|
||||
add_cart(pointed_thing.under, node_name, param2, owner, userID, cargo)
|
||||
meta:set_string("cart_pos", P2S(pointed_thing.under))
|
||||
elseif carts:is_rail(pointed_thing.above) then
|
||||
add_cart(pointed_thing.above, node_name, param2, owner, userID, cargo)
|
||||
meta:set_string("cart_pos", P2S(pointed_thing.above))
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
minetest.sound_play({name = "default_place_node_metal", gain = 0.5},
|
||||
{pos = pointed_thing.above})
|
||||
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(placer:get_player_name())) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
minetest.show_formspec(owner, "minecart:userID_node",
|
||||
"size[4,3]" ..
|
||||
"label[0,0;Enter cart number:]" ..
|
||||
"field[1,1;3,1;userID;;]" ..
|
||||
"button_exit[1,2;2,1;exit;Save]")
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function api.node_on_punch(pos, node, puncher, pointed_thing, entity_name, dir)
|
||||
local ndef = minetest.registered_nodes[node.name]
|
||||
-- Player digs cart by sneak-punch
|
||||
if puncher and puncher:get_player_control().sneak then
|
||||
api.remove_cart(nil, pos, puncher)
|
||||
return
|
||||
end
|
||||
start_cart(pos, node.name, entity_name, puncher, dir)
|
||||
end
|
||||
|
||||
local function add_to_player_inventory(pos, player, node_name)
|
||||
local inv = player:get_inventory()
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(player:get_player_name()))
|
||||
or not inv:contains_item("main", node_name) then
|
||||
local leftover = inv:add_item("main", node_name)
|
||||
-- If no room in inventory add a replacement cart to the world
|
||||
if not leftover:is_empty() then
|
||||
minetest.add_item(pos, leftover)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Player removes the node
|
||||
function api.remove_cart(self, pos, player)
|
||||
if self then -- cart is still an entity
|
||||
add_to_player_inventory(pos, player, self.node_name or "minecart:cart")
|
||||
minecart.remove_from_monitoring(self.myID)
|
||||
self.object:remove()
|
||||
else
|
||||
local node = minetest.get_node(pos)
|
||||
local ndef = minetest.registered_nodes[node.name]
|
||||
if ndef.can_dig and ndef.can_dig(pos, player) then
|
||||
add_to_player_inventory(pos, player, node.name)
|
||||
node.name = M(pos):get_string("removed_rail")
|
||||
if node.name == "" then
|
||||
node.name = "carts:rail"
|
||||
end
|
||||
minetest.remove_node(pos)
|
||||
minetest.add_node(pos, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function api.load_cargo()
|
||||
-- nothing to load
|
||||
end
|
||||
|
||||
function api.unload_cargo()
|
||||
-- nothing to unload
|
||||
end
|
||||
|
||||
function api.add_cargo_to_player_inv()
|
||||
-- nothing to do
|
||||
end
|
||||
|
||||
-- needed by minecart.punch_cart and node carts
|
||||
minecart.node_on_punch = api.node_on_punch
|
||||
|
||||
return api
|
89
minecart/cart_lib3.lua
Normal file
89
minecart/cart_lib3.lua
Normal file
@ -0,0 +1,89 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
Cart library base functions (level 3)
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = minecart.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
|
||||
local api = {}
|
||||
|
||||
function api.get_object_id(object)
|
||||
for id, entity in pairs(minetest.luaentities) do
|
||||
if entity.object == object then
|
||||
return id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function api.get_route_key(pos, player_name)
|
||||
local pos1 = minetest.find_node_near(pos, 1, {"minecart:buffer"})
|
||||
if pos1 then
|
||||
local meta = minetest.get_meta(pos1)
|
||||
if player_name == nil or player_name == meta:get_string("owner") then
|
||||
return P2S(pos1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function api.get_station_name(pos)
|
||||
local pos1 = minetest.find_node_near(pos, 1, {"minecart:buffer"})
|
||||
if pos1 then
|
||||
local name = M(pos1):get_string("name")
|
||||
if name ~= "" then
|
||||
return name
|
||||
end
|
||||
return "-"
|
||||
end
|
||||
end
|
||||
|
||||
function api.load_cart(pos, vel, item)
|
||||
-- Add cart to map
|
||||
local obj = minetest.add_entity(pos, item.entity_name or "minecart:cart", nil)
|
||||
-- Determine ID
|
||||
local myID = api.get_object_id(obj)
|
||||
if myID then
|
||||
-- Copy item data to cart entity
|
||||
local entity = obj:get_luaentity()
|
||||
entity.owner = item.owner or ""
|
||||
entity.userID = item.userID or 0
|
||||
entity.cargo = item.cargo or {}
|
||||
entity.myID = myID
|
||||
obj:set_nametag_attributes({color = "#FFFF00", text = entity.owner..": "..entity.userID})
|
||||
-- Update item data
|
||||
item.owner = entity.owner
|
||||
item.cargo = nil
|
||||
-- Start cart
|
||||
obj:set_velocity(vel)
|
||||
return myID
|
||||
else
|
||||
print("Entity has no ID")
|
||||
end
|
||||
end
|
||||
|
||||
function api.unload_cart(pos, vel, entity, item)
|
||||
-- Copy entity data to item
|
||||
item.cargo = entity.cargo
|
||||
item.entity_name = entity.object:get_entity_name()
|
||||
-- Remove entity from map
|
||||
entity.object:remove()
|
||||
-- Stop sound
|
||||
if entity.sound_handle then
|
||||
minetest.sound_stop(entity.sound_handle)
|
||||
entity.sound_handle = nil
|
||||
end
|
||||
end
|
||||
|
||||
return api
|
@ -26,13 +26,15 @@ local summary_doc = table.concat({
|
||||
S("1. Place your rails and build a route with two endpoints. Junctions are allowed as long as each route has its own start and endpoint."),
|
||||
S("2. Place a Railway Buffer at both endpoints (buffers are always needed, they store the route and timing information)."),
|
||||
S("3. Give both Railway Buffers unique station names, like Oxford and Cambridge."),
|
||||
S("4. Drive from buffer to buffer in both directions using a Minecart(!) to record the routes (use 'right-left' keys to control the Minecart)."),
|
||||
S("5. Punch the buffers to check the connection data (e.g. 'Oxford: connected to Cambridge')."),
|
||||
S("6. Optional: Configure the Minecart stop time in one or both buffers. The Minecart will then start automatically after the configured time."),
|
||||
S("7. Optional: Protect your rail network with the Protection Landmarks (one Landmark at least every 16 nodes/meters)."),
|
||||
S("8. Place a Minecart in front of the buffer and check whether it starts after the configured time."),
|
||||
S("9. Drop items into the Minecart and punch the cart to start it, or 'sneak+click' the Minecart to get the items back."),
|
||||
S("10. Dig the empty cart with a second 'sneak+click' (as usual)."),
|
||||
S("4. Place a Minecart at a buffer and give it a cart number (1..999)"),
|
||||
S("5. Drive from buffer to buffer in both directions using the Minecart(!) to record the routes (use 'right-left' keys to control the Minecart)."),
|
||||
S("6. Punch the buffers to check the connection data (e.g. 'Oxford: connected to Cambridge')."),
|
||||
S("7. Optional: Configure the Minecart stop time in one or both buffers. The Minecart will then start automatically after the configured time."),
|
||||
S("8. Optional: Protect your rail network with the Protection Landmarks (one Landmark at least every 16 nodes/meters)."),
|
||||
S("9. Place a Minecart in front of the buffer and check whether it starts after the configured time."),
|
||||
S("10. Check the cart state via the chat command: /mycart <num>\n '<num>' is the cart number"),
|
||||
S("11. Drop items into the Minecart and punch the cart to start it, or 'sneak+click' the Minecart to get the items back."),
|
||||
S("12. Dig the empty cart with a second 'sneak+click' (as usual)."),
|
||||
}, "\n")
|
||||
|
||||
local cart_doc = S("Primary used to transport items. You can drop items into the Minecart and punch the cart to get started. Sneak+click the cart to get the items back")
|
||||
|
@ -1,38 +1,79 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Generate a template file for translation purposes
|
||||
# Script to generate the template file and update the translation files.
|
||||
#
|
||||
# Copyright (C) 2019 Joachim Stolberg
|
||||
# LGPLv2.1+
|
||||
#
|
||||
# Copy the script into the mod root folder and adapt the last code lines to you needs.
|
||||
|
||||
from __future__ import print_function
|
||||
import os, fnmatch, re, shutil
|
||||
|
||||
import os, fnmatch, re
|
||||
|
||||
pattern = re.compile(r'[ \.=^\t]S\("(.+?)"\)', re.DOTALL)
|
||||
|
||||
pattern_lua = re.compile(r'[ \.=^\t]S\("(.+?)"\)', re.DOTALL)
|
||||
pattern_tr = re.compile(r'(.+?[^@])=(.+)')
|
||||
|
||||
def gen_template(templ_file, lkeyStrings):
|
||||
lOut = []
|
||||
lkeyStrings = list(set(lkeyStrings))
|
||||
lkeyStrings.sort()
|
||||
for s in lkeyStrings:
|
||||
lOut.append("%s=" % s)
|
||||
file(templ_file, "wt").write("\n".join(lOut))
|
||||
open(templ_file, "wt").write("\n".join(lOut))
|
||||
|
||||
def read_strings(fname):
|
||||
def read_lua_file_strings(lua_file):
|
||||
lOut = []
|
||||
text = file(fname).read()
|
||||
for s in pattern.findall(text):
|
||||
text = open(lua_file).read()
|
||||
for s in pattern_lua.findall(text):
|
||||
s = re.sub(r'"\.\.\s+"', "", s)
|
||||
s = re.sub("@[^@=n]", "@@", s)
|
||||
s = s.replace("\n", "@n")
|
||||
s = s.replace("\\n", "@n")
|
||||
s = s.replace("=", "@=")
|
||||
lOut.append(s)
|
||||
return lOut
|
||||
|
||||
def i18n(templ_file):
|
||||
def inport_tr_file(tr_file):
|
||||
dOut = {}
|
||||
if os.path.exists(tr_file):
|
||||
for line in open(tr_file, "r").readlines():
|
||||
s = line.strip()
|
||||
if s == "" or s[0] == "#":
|
||||
continue
|
||||
match = pattern_tr.match(s)
|
||||
if match:
|
||||
dOut[match.group(1)] = match.group(2)
|
||||
return dOut
|
||||
|
||||
def generate_template(templ_file):
|
||||
lOut = []
|
||||
for root, dirs, files in os.walk('./'):
|
||||
for name in files:
|
||||
if fnmatch.fnmatch(name, "*.lua"):
|
||||
fname = os.path.join(root, name)
|
||||
print fname
|
||||
lOut.extend(read_strings(fname))
|
||||
found = read_lua_file_strings(fname)
|
||||
print(fname, len(found))
|
||||
lOut.extend(found)
|
||||
lOut = list(set(lOut))
|
||||
lOut.sort()
|
||||
gen_template(templ_file, lOut)
|
||||
return lOut
|
||||
|
||||
def update_tr_file(lNew, mod_name, tr_file):
|
||||
lOut = ["# textdomain: %s\n" % mod_name]
|
||||
if os.path.exists(tr_file):
|
||||
shutil.copyfile(tr_file, tr_file+".old")
|
||||
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))
|
||||
|
||||
i18n("./locale/template.txt")
|
||||
print "Done.\n"
|
||||
data = generate_template("./locale/template.txt")
|
||||
update_tr_file(data, "minecart", "./locale/minecart.de.tr")
|
||||
print("Done.\n")
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
minecart = {}
|
||||
|
||||
-- Version for compatibility checks, see readme.md/history
|
||||
minecart.version = 1.05
|
||||
minecart.version = 1.06
|
||||
|
||||
minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false
|
||||
|
||||
@ -23,11 +23,11 @@ minecart.S = minetest.get_translator("minecart")
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
dofile(MP.."/storage.lua")
|
||||
dofile(MP.."/lib.lua")
|
||||
dofile(MP.."/routes.lua")
|
||||
dofile(MP.."/cart_entity.lua")
|
||||
dofile(MP.."/monitoring.lua")
|
||||
dofile(MP.."/recording.lua")
|
||||
dofile(MP.."/minecart.lua")
|
||||
dofile(MP.."/buffer.lua")
|
||||
dofile(MP.."/protection.lua")
|
||||
dofile(MP.."/cart_api.lua")
|
||||
|
||||
if minecart.hopper_enabled then
|
||||
dofile(MP.."/hopper.lua")
|
||||
|
@ -51,6 +51,11 @@ function minecart.register_cart_names(cart_name_stopped, cart_name_running)
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.stopped(vel, tolerance)
|
||||
tolerance = tolerance or 0.05
|
||||
return math.abs(vel.x) < tolerance and math.abs(vel.z) < tolerance
|
||||
end
|
||||
|
||||
local function is_air_like(name)
|
||||
local ndef = minetest.registered_nodes[name]
|
||||
if ndef and ndef.buildable_to then
|
||||
@ -65,6 +70,17 @@ function minecart.get_next_node(pos, param2)
|
||||
return pos2, node
|
||||
end
|
||||
|
||||
local function get_cart_object(pos, radius)
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(pos, radius or 0.5)) do
|
||||
if tValidCartEntities[object:get_entity_name()] then
|
||||
local vel = object:get_velocity()
|
||||
if vector.equals(vel, {x=0, y=0, z=0}) then -- still standing?
|
||||
return object
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- check if cart can be pushed
|
||||
function minecart.check_cart_for_pushing(pos, param2, radius)
|
||||
local pos2 = param2 and vector.add(pos, param2_to_dir[param2]) or pos
|
||||
@ -73,17 +89,7 @@ function minecart.check_cart_for_pushing(pos, param2, radius)
|
||||
return true
|
||||
end
|
||||
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(pos2, radius or 0.5)) do
|
||||
--print(object:get_entity_name(), tValidCartEntities[object:get_entity_name()])
|
||||
if tValidCartEntities[object:get_entity_name()] then
|
||||
local vel = object:get_velocity()
|
||||
if vector.equals(vel, {x=0, y=0, z=0}) then -- still standing?
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
return get_cart_object(pos2, radius) ~= nil
|
||||
end
|
||||
|
||||
-- check if cargo can be loaded
|
||||
@ -139,7 +145,7 @@ function minecart.take_items(pos, param2, num)
|
||||
local owner = M(pos):get_string("owner")
|
||||
local inv = minetest.get_inventory({type="node", pos=npos})
|
||||
|
||||
if def and inv and (not def.allow_take or def.allow_take(npos, nil, owner)) then
|
||||
if def and inv and def.take_listname and (not def.allow_take or def.allow_take(npos, nil, owner)) then
|
||||
return minecart.inv_take_items(inv, def.take_listname, num)
|
||||
else
|
||||
local ndef = minetest.registered_nodes[node.name]
|
||||
@ -155,7 +161,7 @@ function minecart.put_items(pos, param2, stack)
|
||||
local owner = M(pos):get_string("owner")
|
||||
local inv = minetest.get_inventory({type="node", pos=npos})
|
||||
|
||||
if def and inv and (not def.allow_put or def.allow_put(npos, stack, owner)) then
|
||||
if def and inv and def.put_listname and (not def.allow_put or def.allow_put(npos, stack, owner)) then
|
||||
local leftover = inv:add_item(def.put_listname, stack)
|
||||
if leftover:get_count() > 0 then
|
||||
return leftover
|
||||
@ -206,14 +212,12 @@ function minecart.punch_cart(pos, param2, radius, dir)
|
||||
return true
|
||||
end
|
||||
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(pos2, radius or 0.5)) do
|
||||
if tValidCartEntities[object:get_entity_name()] then
|
||||
object:punch(object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 1},
|
||||
}, dir)
|
||||
break -- start only one cart
|
||||
end
|
||||
local obj = get_cart_object(pos2, radius)
|
||||
if obj then
|
||||
obj:punch(obj, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 1},
|
||||
}, dir)
|
||||
end
|
||||
end
|
||||
|
||||
@ -230,6 +234,44 @@ function minecart.register_inventory(node_names, def)
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.register_cart_entity(entity_name, node_name, entity_def)
|
||||
entity_def.velocity = {x=0, y=0, z=0} -- only used on punch
|
||||
entity_def.old_dir = {x=1, y=0, z=0} -- random value to start the cart on punch
|
||||
entity_def.old_pos = nil
|
||||
entity_def.old_switch = 0
|
||||
entity_def.node_name = node_name
|
||||
minetest.register_entity(entity_name, entity_def)
|
||||
-- register node for punching
|
||||
minecart.register_cart_names(node_name, entity_name)
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname == "minecart:userID_node" then
|
||||
if fields.exit == "Save" or fields.key_enter == "true" then
|
||||
local cart_pos = S2P(player:get_meta():get_string("cart_pos"))
|
||||
local userID = tonumber(fields.userID) or 0
|
||||
M(cart_pos):set_int("userID", userID)
|
||||
M(cart_pos):set_string("infotext", minetest.get_color_escape_sequence("#FFFF00")..player:get_player_name()..": "..userID)
|
||||
minecart.node_at_station(player:get_player_name(), userID, cart_pos)
|
||||
end
|
||||
return true
|
||||
end
|
||||
if formname == "minecart:userID_entity" then
|
||||
if fields.exit == "Save" or fields.key_enter == "true" then
|
||||
local cart_pos = S2P(player:get_meta():get_string("cart_pos"))
|
||||
local obj = get_cart_object(cart_pos)
|
||||
if obj then
|
||||
local entity = obj:get_luaentity()
|
||||
entity.userID = tonumber(fields.userID) or 0
|
||||
obj:set_nametag_attributes({color = "#ffff00", text = entity.owner..": "..entity.userID})
|
||||
minecart.update_userID(entity.myID, entity.userID)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end)
|
||||
|
||||
minecart.register_inventory({"default:chest", "default:chest_open"}, {
|
||||
put = {
|
||||
listname = "main",
|
||||
|
@ -1,16 +1,17 @@
|
||||
# textdomain: minecart
|
||||
|
||||
1. Place your rails and build a route with two endpoints. Junctions are allowed as long as each route has its own start and endpoint.=1. Baue eine Schienenstrecke mit zwei Enden. Kreuzungen sind zulässig, solange jede Route ihre eigenen Start- und Endpunkte hat.
|
||||
10. Dig the empty cart with a second 'sneak+click' (as usual).=10. Klicke erneut mit gedrückter Shift-Taste auf den Wagen, um diesen zu entfernen.
|
||||
10. Check the cart state via the chat command: /mycart <num>@n '<num>' is the cart number=Prüfe den Status des Wagen mit dem Chat Kommando: /mycart <num>@n <num> ist die Wagennummer
|
||||
11. Drop items into the Minecart and punch the cart to start it, or 'sneak+click' the Minecart to get the items back.=11: Lege Gegenstände in ein Wagen (Taste Q) und starte dann den Wagen durch Anklicken. Klicke mit gedrückter Shift-Taste auf den Wagen, um Gegenstände wieder auszuladen.
|
||||
12. Dig the empty cart with a second 'sneak+click' (as usual).=10. Klicke erneut mit gedrückter Shift-Taste auf den Wagen, um diesen zu entfernen.
|
||||
2. Place a Railway Buffer at both endpoints (buffers are always needed, they store the route and timing information).=2. Platziere einen Prellbock an beide Schienenenden (Prellböcke sind zwingend notwendig, sie speichern die Routen- und Zeit-Informationen).
|
||||
3. Give both Railway Buffers unique station names, like Oxford and Cambridge.=3. Gib beiden Prellböcken eindeutige Stationsnamen wie: Stuttgart und München.
|
||||
4. Drive from buffer to buffer in both directions using a Minecart(!) to record the routes (use 'right-left' keys to control the Minecart).=4. Um eine Route aufzuzeichnen, fahre die Route in beide Richtungen von Prellbock zu Prellbock mit einem Minecart Wagen(!). Nutze 'links-rechts' Tasten zur Steuerung.
|
||||
5. Punch the buffers to check the connection data (e.g. 'Oxford: connected to Cambridge').=5. Schlage auf die Prellböcke um die Verbindungsdaten zu prüfen (bspw.: 'München: verbunden mit Stuttgart')
|
||||
6. Optional: Configure the Minecart stop time in one or both buffers. The Minecart will then start automatically after the configured time.=6. Optional: Konfiguriere die Wagenwartezeit in einem oder in beiden Prellböcken. Der Wagen startet dann nach dieser Zeit automatisch.
|
||||
7. Optional: Protect your rail network with the Protection Landmarks (one Landmark at least every 16 nodes/meters).=7. Optional: Schütze deine Schienen mit Hilfe der Meilensteine (ein Meilenstein mindestens alle 16 Blöcke).
|
||||
8. Place a Minecart in front of the buffer and check whether it starts after the configured time.=8. Platziere einen Wagen direkt vor einem Prellbock und prüfe, ob er nach der konfigurierten Zeit startet.
|
||||
9. Drop items into the Minecart and punch the cart to start it, or 'sneak+click' the Minecart to get the items back.=9: Lege Gegenstände in ein Wagen (Taste Q) und starte dann den Wagen durch Anklicken. Klicke mit gedrückter Shift-Taste auf den Wagen, um Gegenstände wieder auszuladen.
|
||||
A minecart running through unloaded areas, mainly used for item transportation=Ein Wagen, welcher auch durch nicht geladene Kartenbereiche fährt, primär für den Transport von Gegenständen genutzt (Lore)
|
||||
4. Place a Minecart at a buffer and give it a cart number (1..999)=4. Platziere einen Minecart Wagen an einem Prellbock und gib dem Wagen eine Wagennummer (1..999)
|
||||
5. Drive from buffer to buffer in both directions using the Minecart(!) to record the routes (use 'right-left' keys to control the Minecart).=5. Um eine Route aufzuzeichnen, fahre die Route in beide Richtungen von Prellbock zu Prellbock mit dem Minecart Wagen(!). Nutze 'links-rechts' Tasten zur Steuerung.
|
||||
6. Punch the buffers to check the connection data (e.g. 'Oxford: connected to Cambridge').=6. Schlage auf die Prellböcke um die Verbindungsdaten zu prüfen (bspw.: 'München: verbunden mit Stuttgart')
|
||||
7. Optional: Configure the Minecart stop time in one or both buffers. The Minecart will then start automatically after the configured time.=7. Optional: Konfiguriere die Wagenwartezeit in einem oder in beiden Prellböcken. Der Wagen startet dann nach dieser Zeit automatisch.
|
||||
8. Optional: Protect your rail network with the Protection Landmarks (one Landmark at least every 16 nodes/meters).=8. Optional: Schütze deine Schienen mit Hilfe der Meilensteine (ein Meilenstein mindestens alle 16 Blöcke).
|
||||
9. Place a Minecart in front of the buffer and check whether it starts after the configured time.=9. Platziere einen Wagen direkt vor einem Prellbock und prüfe, ob er nach der konfigurierten Zeit startet.
|
||||
Allow to dig/place rails in Minecart Landmark areas=Erlaubt dir, Schienen in Meilensteinbereichen zu setzen/zu entfernen
|
||||
Minecart=Minecart
|
||||
Minecart (Sneak+Click to pick up)=Minecart (Shift+Klick zum Entfernen des Carts)
|
||||
@ -27,9 +28,10 @@ Summary=Zusammenfassung
|
||||
Used as buffer on both rail ends. Needed to be able to record the cart routes=Preckblöcke müssen an beiden Schienenenden platziert sein, so dass Aufzeichnungen der Strecke gemacht werden können.
|
||||
Used to load/unload Minecart. The Hopper can push/pull items to/from chests and drop/pickup items to/from Minecarts. To unload a Minecart place the hopper below the rail. To load the Minecart, place the hopper right next to the Minecart.=Um Wagen zu be- und entladen. Der Hopper kann Gegenstände aus Kisten Holen und legen, sowie diese in Wagen fallen lassen bzw. aus Wagen entnehmen. Um einen Wagen zu entladen, muss der Hopper unter die Schiene platziert werden. Um einen Wagen zu beladen, muss der Hopper direkt neben die Schiene platziert werden.
|
||||
[minecart] Area is protected!=[minecart] Bereich ist geschützt!
|
||||
[minecart] Please start at a Railway Buffer!=[minecart] Bitte starte beim Prellbock!
|
||||
[minecart] Cart is protected by = Wagen ist geschützt durch
|
||||
[minecart] Recording canceled!=[minecart] Aufzeichnung abgebrochen!
|
||||
[minecart] Route stored!=[minecart] Strecke gespeichert
|
||||
[minecart] Start route recording!=[minecart] Starte die Streckenaufzeichnung!
|
||||
connected to=verbunden mit
|
||||
##### not used anymore #####
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
1. Place your rails and build a route with two endpoints. Junctions are allowed as long as each route has its own start and endpoint.=
|
||||
10. Dig the empty cart with a second 'sneak+click' (as usual).=
|
||||
10. Check the cart state via the chat command: /mycart <num>@n '<num>' is the cart number=
|
||||
11. Drop items into the Minecart and punch the cart to start it, or 'sneak+click' the Minecart to get the items back.=
|
||||
12. Dig the empty cart with a second 'sneak+click' (as usual).=
|
||||
2. Place a Railway Buffer at both endpoints (buffers are always needed, they store the route and timing information).=
|
||||
3. Give both Railway Buffers unique station names, like Oxford and Cambridge.=
|
||||
4. Drive from buffer to buffer in both directions using a Minecart(!) to record the routes (use 'right-left' keys to control the Minecart).=
|
||||
5. Punch the buffers to check the connection data (e.g. 'Oxford: connected to Cambridge').=
|
||||
6. Optional: Configure the Minecart stop time in one or both buffers. The Minecart will then start automatically after the configured time.=
|
||||
7. Optional: Protect your rail network with the Protection Landmarks (one Landmark at least every 16 nodes/meters).=
|
||||
8. Place a Minecart in front of the buffer and check whether it starts after the configured time.=
|
||||
9. Drop items into the Minecart and punch the cart to start it, or 'sneak+click' the Minecart to get the items back.=
|
||||
4. Place a Minecart at a buffer and give it a cart number (1..999)=
|
||||
5. Drive from buffer to buffer in both directions using the Minecart(!) to record the routes (use 'right-left' keys to control the Minecart).=
|
||||
6. Punch the buffers to check the connection data (e.g. 'Oxford: connected to Cambridge').=
|
||||
7. Optional: Configure the Minecart stop time in one or both buffers. The Minecart will then start automatically after the configured time.=
|
||||
8. Optional: Protect your rail network with the Protection Landmarks (one Landmark at least every 16 nodes/meters).=
|
||||
9. Place a Minecart in front of the buffer and check whether it starts after the configured time.=
|
||||
Allow to dig/place rails in Minecart Landmark areas=
|
||||
Minecart=
|
||||
Minecart (Sneak+Click to pick up)=
|
||||
@ -24,7 +26,7 @@ Summary=
|
||||
Used as buffer on both rail ends. Needed to be able to record the cart routes=
|
||||
Used to load/unload Minecart. The Hopper can push/pull items to/from chests and drop/pickup items to/from Minecarts. To unload a Minecart place the hopper below the rail. To load the Minecart, place the hopper right next to the Minecart.=
|
||||
[minecart] Area is protected!=
|
||||
[minecart] Please start at a Railway Buffer!=
|
||||
[minecart] Cart is protected by =
|
||||
[minecart] Recording canceled!=
|
||||
[minecart] Route stored!=
|
||||
[minecart] Start route recording!=
|
||||
|
84
minecart/minecart.lua
Normal file
84
minecart/minecart.lua
Normal file
@ -0,0 +1,84 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
]]--
|
||||
|
||||
local S = minecart.S
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
local lib = dofile(MP.."/cart_lib1.lua")
|
||||
|
||||
lib:init(false)
|
||||
|
||||
local cart_entity = {
|
||||
initial_properties = {
|
||||
physical = false, -- otherwise going uphill breaks
|
||||
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
visual = "mesh",
|
||||
mesh = "carts_cart.b3d",
|
||||
visual_size = {x=1, y=1},
|
||||
textures = {"carts_cart.png^minecart_cart.png"},
|
||||
static_save = false,
|
||||
},
|
||||
------------------------------------ changed
|
||||
owner = nil,
|
||||
------------------------------------ changed
|
||||
driver = nil,
|
||||
punched = false, -- used to re-send velocity and position
|
||||
velocity = {x=0, y=0, z=0}, -- only used on punch
|
||||
old_dir = {x=1, y=0, z=0}, -- random value to start the cart on punch
|
||||
old_pos = nil,
|
||||
old_switch = 0,
|
||||
railtype = nil,
|
||||
cargo = {},
|
||||
on_rightclick = lib.on_rightclick,
|
||||
on_activate = lib.on_activate,
|
||||
on_detach_child = lib.on_detach_child,
|
||||
on_punch = lib.on_punch,
|
||||
on_step = lib.on_step,
|
||||
}
|
||||
|
||||
|
||||
minetest.register_entity("minecart:cart", cart_entity)
|
||||
|
||||
minecart.register_cart_names("minecart:cart", "minecart:cart")
|
||||
|
||||
|
||||
minetest.register_craftitem("minecart:cart", {
|
||||
description = S("Minecart (Sneak+Click to pick up)"),
|
||||
inventory_image = minetest.inventorycube("carts_cart_top.png", "carts_cart_side.png^minecart_logo.png", "carts_cart_side.png^minecart_logo.png"),
|
||||
wield_image = "carts_cart_side.png",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
-- use cart as tool
|
||||
local under = pointed_thing.under
|
||||
local node = minetest.get_node(under)
|
||||
local udef = minetest.registered_nodes[node.name]
|
||||
if udef and udef.on_rightclick and
|
||||
not (placer and placer:is_player() and
|
||||
placer:get_player_control().sneak) then
|
||||
return udef.on_rightclick(under, node, placer, itemstack,
|
||||
pointed_thing) or itemstack
|
||||
end
|
||||
|
||||
if not pointed_thing.type == "node" then
|
||||
return
|
||||
end
|
||||
|
||||
return lib.add_cart(itemstack, placer, pointed_thing, "minecart:cart")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "minecart:cart",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:cobble", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
},
|
||||
})
|
||||
|
333
minecart/monitoring.lua
Normal file
333
minecart/monitoring.lua
Normal file
@ -0,0 +1,333 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
]]--
|
||||
|
||||
-- Some notes:
|
||||
-- 1) Entity IDs are volatile. For each server restart all carts get new IDs.
|
||||
-- 2) Monitoring is performed for entities only. Stopped carts in form of
|
||||
-- real nodes need no monitoring.
|
||||
-- 3) But nodes at startions have to call 'node_at_station' to be "visible"
|
||||
-- for the chat commands
|
||||
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local S = minecart.S
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
local lib = dofile(MP.."/cart_lib3.lua")
|
||||
|
||||
local CartsOnRail = minecart.CartsOnRail -- from storage.lua
|
||||
local get_route = minecart.get_route -- from storage.lua
|
||||
local NodesAtStation = {}
|
||||
|
||||
--
|
||||
-- Helper functions
|
||||
--
|
||||
local function calc_pos_and_vel(item)
|
||||
if item.start_time and item.start_key then -- cart on recorded route
|
||||
local run_time = minetest.get_gametime() - item.start_time
|
||||
local waypoints = get_route(item.start_key).waypoints
|
||||
local waypoint = waypoints[run_time]
|
||||
if waypoint then
|
||||
return S2P(waypoint[1]), S2P(waypoint[2])
|
||||
end
|
||||
end
|
||||
if item.last_pos then
|
||||
item.last_pos = vector.round(item.last_pos)
|
||||
if carts:is_rail(item.last_pos, minetest.raillike_group("rail")) then
|
||||
return item.last_pos, item.last_vel
|
||||
end
|
||||
item.last_pos.y = item.last_pos.y - 1
|
||||
if carts:is_rail(item.last_pos, minetest.raillike_group("rail")) then
|
||||
return item.last_pos, item.last_vel
|
||||
end
|
||||
end
|
||||
return item.start_pos, {x=0, y=0, z=0}
|
||||
end
|
||||
|
||||
--
|
||||
-- Monitoring of cart entities
|
||||
--
|
||||
function minecart.add_to_monitoring(obj, myID, owner, userID)
|
||||
local pos = vector.round(obj:get_pos())
|
||||
CartsOnRail[myID] = {
|
||||
start_key = lib.get_route_key(pos),
|
||||
start_pos = pos,
|
||||
owner = owner, -- needed for query API
|
||||
userID = userID, -- needed for query API
|
||||
stopped = true,
|
||||
entity_name = obj:get_entity_name()
|
||||
}
|
||||
end
|
||||
|
||||
-- Called after cart number formspec is closed
|
||||
function minecart.update_userID(myID, userID)
|
||||
if CartsOnRail[myID] then
|
||||
CartsOnRail[myID].userID = userID
|
||||
end
|
||||
end
|
||||
|
||||
-- When cart entity is removed
|
||||
function minecart.remove_from_monitoring(myID)
|
||||
if myID then
|
||||
CartsOnRail[myID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- For node carts at stations
|
||||
function minecart.node_at_station(owner, userID, pos)
|
||||
NodesAtStation[owner] = NodesAtStation[owner] or {}
|
||||
NodesAtStation[owner][userID] = pos
|
||||
end
|
||||
|
||||
function minecart.start_cart(pos, myID)
|
||||
local item = CartsOnRail[myID]
|
||||
if item and item.stopped then
|
||||
item.stopped = false
|
||||
item.start_pos = pos
|
||||
-- cart started from a buffer?
|
||||
local start_key = lib.get_route_key(pos)
|
||||
if start_key then
|
||||
item.start_time = minetest.get_gametime()
|
||||
item.start_key = start_key
|
||||
item.junctions = minecart.get_route(start_key).junctions
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function minecart.stop_cart(pos, myID)
|
||||
local item = CartsOnRail[myID]
|
||||
if item and not item.stopped then
|
||||
item.start_time = nil
|
||||
item.start_key = nil
|
||||
item.start_pos = nil
|
||||
item.junctions = nil
|
||||
item.stopped = true
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function monitoring()
|
||||
local to_be_added = {}
|
||||
for key, item in pairs(CartsOnRail) do
|
||||
local entity = minetest.luaentities[key]
|
||||
--print("Cart:", key, item.owner, item.myID, item.userID, item.stopped)
|
||||
if entity then -- cart entity running
|
||||
local pos = entity.object:get_pos()
|
||||
local vel = entity.object:get_velocity()
|
||||
if not minetest.get_node_or_nil(pos) then -- unloaded area
|
||||
lib.unload_cart(pos, vel, entity, item)
|
||||
item.stopped = minecart.stopped(vel)
|
||||
end
|
||||
-- store last pos from cart
|
||||
item.last_pos, item.last_vel = pos, vel
|
||||
else -- no cart running
|
||||
local pos, vel = calc_pos_and_vel(item)
|
||||
if pos and vel then
|
||||
if minetest.get_node_or_nil(pos) then -- loaded area
|
||||
local myID = lib.load_cart(pos, vel, item)
|
||||
if myID then
|
||||
item.stopped = minecart.stopped(vel)
|
||||
to_be_added[myID] = table.copy(item)
|
||||
CartsOnRail[key] = nil -- invalid old ID
|
||||
end
|
||||
end
|
||||
item.last_pos, item.last_vel = pos, vel
|
||||
else
|
||||
CartsOnRail[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
-- table maintenance
|
||||
for key,val in pairs(to_be_added) do
|
||||
CartsOnRail[key] = val
|
||||
end
|
||||
minetest.after(1, monitoring)
|
||||
end
|
||||
-- delay the start to prevent cart disappear into nirvana
|
||||
minetest.register_on_mods_loaded(function()
|
||||
minetest.after(10, monitoring)
|
||||
end)
|
||||
|
||||
|
||||
--
|
||||
-- API functions
|
||||
--
|
||||
|
||||
-- Return a list of carts with current position and speed.
|
||||
function minecart.get_cart_list()
|
||||
local tbl = {}
|
||||
for id, item in pairs(CartsOnRail) do
|
||||
local pos, speed = calc_pos_and_vel(item)
|
||||
tbl[#tbl+1] = {pos = pos, speed = speed, id = id}
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
local function get_cart_pos(query_pos, cart_pos)
|
||||
local dist = math.floor(vector.distance(cart_pos, query_pos))
|
||||
local station = lib.get_station_name(cart_pos)
|
||||
return station or dist
|
||||
end
|
||||
|
||||
local function get_cart_state(name, userID)
|
||||
for id, item in pairs(CartsOnRail) do
|
||||
if item.owner == name and item.userID == userID then
|
||||
return item.stopped and "stopped" or "running", item.last_pos
|
||||
end
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("mycart", {
|
||||
params = "<cart-num>",
|
||||
description = "Output cart state and position, or a list of carts, if no cart number is given.",
|
||||
func = function(name, param)
|
||||
local userID = tonumber(param)
|
||||
local query_pos = minetest.get_player_by_name(name):get_pos()
|
||||
|
||||
if userID then
|
||||
-- First check if it is a node cart at a station
|
||||
local cart_pos = NodesAtStation[name] and NodesAtStation[name][userID]
|
||||
if cart_pos then
|
||||
local pos = get_cart_pos(query_pos, cart_pos)
|
||||
return true, "Cart #"..userID.." stopped at "..pos.." "
|
||||
end
|
||||
-- Check all running carts
|
||||
local state, cart_pos = get_cart_state(name, userID)
|
||||
if state then
|
||||
local pos = get_cart_pos(query_pos, cart_pos)
|
||||
if type(pos) == "string" then
|
||||
return true, "Cart #"..userID.." stopped at "..pos.." "
|
||||
elseif state == "running" then
|
||||
return true, "Cart #"..userID.." running "..pos.." m away "
|
||||
else
|
||||
return true, "Cart #"..userID.." stopped "..pos.." m away "
|
||||
end
|
||||
end
|
||||
return false, "Cart #"..userID.." is unknown"
|
||||
else
|
||||
-- Output a list with all numbers
|
||||
local tbl = {}
|
||||
for userID, pos in pairs(NodesAtStation[name] or {}) do
|
||||
tbl[#tbl + 1] = userID
|
||||
end
|
||||
for id, item in pairs(CartsOnRail) do
|
||||
if item.owner == name then
|
||||
tbl[#tbl + 1] = item.userID
|
||||
end
|
||||
end
|
||||
return true, "List of carts: "..table.concat(tbl, ", ").." "
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
function minecart.cmnd_cart_state(name, userID)
|
||||
-- First check if it is a node cart at a station
|
||||
local pos = NodesAtStation[name] and NodesAtStation[name][userID]
|
||||
if pos then
|
||||
return "stopped"
|
||||
end
|
||||
return get_cart_state(name, userID)
|
||||
end
|
||||
|
||||
function minecart.cmnd_cart_location(name, userID, query_pos)
|
||||
-- First check if it is a node cart at a station
|
||||
local station = NodesAtStation[name] and NodesAtStation[name][userID]
|
||||
if station then
|
||||
return station
|
||||
end
|
||||
local state, cart_pos = get_cart_state(name, userID)
|
||||
if state then
|
||||
return get_cart_pos(query_pos, cart_pos)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
if minetest.global_exists("techage") then
|
||||
techage.icta_register_condition("cart_state", {
|
||||
title = "read cart state",
|
||||
formspec = {
|
||||
{
|
||||
type = "digits",
|
||||
name = "number",
|
||||
label = "cart number",
|
||||
default = "",
|
||||
},
|
||||
{
|
||||
type = "label",
|
||||
name = "lbl",
|
||||
label = "Read state from one of your carts",
|
||||
},
|
||||
},
|
||||
button = function(data, environ) -- default button label
|
||||
local number = tonumber(data.number) or 0
|
||||
return 'cart_state('..number..')'
|
||||
end,
|
||||
code = function(data, environ)
|
||||
local s = 'minecart.cmnd_cart_state("%s", %u)'
|
||||
local number = tonumber(data.number) or 0
|
||||
return string.format(s, environ.owner, number), "~= 0"
|
||||
end,
|
||||
})
|
||||
techage.icta_register_condition("cart_location", {
|
||||
title = "read cart location",
|
||||
formspec = {
|
||||
{
|
||||
type = "digits",
|
||||
name = "number",
|
||||
label = "cart number",
|
||||
default = "",
|
||||
},
|
||||
{
|
||||
type = "label",
|
||||
name = "lbl",
|
||||
label = "Read location from one of your carts",
|
||||
},
|
||||
},
|
||||
button = function(data, environ) -- default button label
|
||||
local number = tonumber(data.number) or 0
|
||||
return 'cart_loc('..number..')'
|
||||
end,
|
||||
code = function(data, environ)
|
||||
local s = 'minecart.cmnd_cart_location("%s", %u, env.pos)'
|
||||
local number = tonumber(data.number) or 0
|
||||
return string.format(s, environ.owner, number), "~= 0"
|
||||
end,
|
||||
})
|
||||
techage.lua_ctlr.register_function("cart_state", {
|
||||
cmnd = function(self, num)
|
||||
num = tonumber(num) or 0
|
||||
return minecart.cmnd_cart_state(self.meta.owner, num)
|
||||
end,
|
||||
help = " $cart_state(num)\n"..
|
||||
" Read state from one of your carts.\n"..
|
||||
' "num" is the cart number\n'..
|
||||
' example: sts = $cart_state(2)'
|
||||
})
|
||||
techage.lua_ctlr.register_function("cart_location", {
|
||||
cmnd = function(self, num)
|
||||
num = tonumber(num) or 0
|
||||
return minecart.cmnd_cart_location(self.meta.owner, num, self.meta.pos)
|
||||
end,
|
||||
help = " $cart_location(num)\n"..
|
||||
" Read location from one of your carts.\n"..
|
||||
' "num" is the cart number\n'..
|
||||
' example: sts = $cart_location(2)'
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
89
minecart/recording.lua
Normal file
89
minecart/recording.lua
Normal file
@ -0,0 +1,89 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local S = minecart.S
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
local lib = dofile(MP.."/cart_lib3.lua")
|
||||
|
||||
local CartsOnRail = minecart.CartsOnRail -- from storage.lua
|
||||
local get_route = minecart.get_route -- from storage.lua
|
||||
|
||||
--
|
||||
-- Route recording
|
||||
--
|
||||
function minecart.start_recording(self, pos)
|
||||
self.start_key = lib.get_route_key(pos, self.driver)
|
||||
if self.start_key then
|
||||
self.waypoints = {}
|
||||
self.junctions = {}
|
||||
self.recording = true
|
||||
self.next_time = minetest.get_us_time() + 1000000
|
||||
minetest.chat_send_player(self.driver, S("[minecart] Start route recording!"))
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.store_next_waypoint(self, pos, vel)
|
||||
if self.start_key and self.recording and self.driver and
|
||||
self.next_time < minetest.get_us_time() then
|
||||
self.next_time = minetest.get_us_time() + 1000000
|
||||
self.waypoints[#self.waypoints+1] = {P2S(vector.round(pos)), P2S(vector.round(vel))}
|
||||
elseif self.recording and not self.driver then
|
||||
self.recording = false
|
||||
self.waypoints = nil
|
||||
self.junctions = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- destination reached(speed == 0)
|
||||
function minecart.stop_recording(self, pos, vel, puncher)
|
||||
local dest_pos = lib.get_route_key(pos, self.driver)
|
||||
if dest_pos then
|
||||
if self.start_key ~= dest_pos then
|
||||
local route = {
|
||||
waypoints = self.waypoints,
|
||||
dest_pos = dest_pos,
|
||||
junctions = self.junctions,
|
||||
}
|
||||
minecart.store_route(self.start_key, route)
|
||||
minetest.chat_send_player(self.driver, S("[minecart] Route stored!"))
|
||||
else
|
||||
minetest.chat_send_player(self.driver, S("[minecart] Recording canceled!"))
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(self.driver, S("[minecart] Recording canceled!"))
|
||||
end
|
||||
self.recording = false
|
||||
self.waypoints = nil
|
||||
self.junctions = nil
|
||||
end
|
||||
|
||||
function minecart.set_junction(self, pos, dir, switch_keys)
|
||||
if self.junctions then
|
||||
self.junctions[P2S(vector.round(pos))] = {dir, switch_keys}
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.get_junction(self, pos, dir)
|
||||
local junctions = CartsOnRail[self.myID] and CartsOnRail[self.myID].junctions
|
||||
if junctions then
|
||||
local data = junctions[P2S(vector.round(pos))]
|
||||
if data then
|
||||
return data[1], data[2]
|
||||
end
|
||||
end
|
||||
return dir
|
||||
end
|
||||
|
@ -1,291 +0,0 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2020 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local S = minecart.S
|
||||
|
||||
local CartsOnRail = minecart.CartsOnRail
|
||||
|
||||
--
|
||||
-- Helper functions
|
||||
--
|
||||
local function get_object_id(object)
|
||||
for id, entity in pairs(minetest.luaentities) do
|
||||
if entity.object == object then
|
||||
return id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_route_key(pos, player_name)
|
||||
local pos1 = minetest.find_node_near(pos, 1, {"minecart:buffer"})
|
||||
if pos1 then
|
||||
local meta = minetest.get_meta(pos1)
|
||||
if player_name == nil or player_name == meta:get_string("owner") then
|
||||
return P2S(pos1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Recording
|
||||
--
|
||||
function minecart.add_cart_to_monitoring(obj, owner, cargo)
|
||||
--print("add_cart_to_monitoring", dump(cargo))
|
||||
local self = obj:get_luaentity()
|
||||
self.myID = get_object_id(obj)
|
||||
self.owner = owner
|
||||
local pos = self.object:get_pos()
|
||||
CartsOnRail[self.myID] = {
|
||||
start_key = get_route_key(pos),
|
||||
start_pos = pos,
|
||||
stopped = true,
|
||||
owner = owner,
|
||||
entity_name = self.name,
|
||||
cargo = cargo,
|
||||
}
|
||||
return self.myID
|
||||
end
|
||||
|
||||
function minecart.start_recording(self, pos, vel, puncher)
|
||||
-- Player punches cart to start the trip
|
||||
if puncher:get_player_name() == self.driver and vector.equals(vel, {x=0, y=0, z=0}) then
|
||||
self.start_key = get_route_key(pos, self.driver)
|
||||
if self.start_key then
|
||||
self.waypoints = {}
|
||||
self.junctions = {}
|
||||
self.recording = true
|
||||
self.next_time = minetest.get_us_time() + 1000000
|
||||
minetest.chat_send_player(self.driver, S("[minecart] Start route recording!"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.store_next_waypoint(self, pos, vel)
|
||||
if self.start_key and self.recording and self.driver and
|
||||
self.next_time < minetest.get_us_time() then
|
||||
self.next_time = minetest.get_us_time() + 1000000
|
||||
self.waypoints[#self.waypoints+1] = {P2S(vector.round(pos)), P2S(vector.round(vel))}
|
||||
|
||||
local dest_pos = get_route_key(pos, self.driver)
|
||||
if vector.equals(vel, {x=0, y=0, z=0}) and dest_pos then
|
||||
if self.start_key ~= dest_pos then
|
||||
local route = {
|
||||
waypoints = self.waypoints,
|
||||
dest_pos = dest_pos,
|
||||
junctions = self.junctions,
|
||||
}
|
||||
minecart.store_route(self.start_key, route)
|
||||
minetest.chat_send_player(self.driver, S("[minecart] Route stored!"))
|
||||
else
|
||||
minetest.chat_send_player(self.driver, S("[minecart] Recording canceled!"))
|
||||
end
|
||||
self.recording = false
|
||||
self.waypoints = nil
|
||||
self.junctions = nil
|
||||
end
|
||||
elseif self.recording and not self.driver then
|
||||
self.recording = false
|
||||
self.waypoints = nil
|
||||
self.junctions = nil
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.set_junction(self, pos, dir, switch_keys)
|
||||
local junctions = CartsOnRail[self.myID] and CartsOnRail[self.myID].junctions
|
||||
if junctions then
|
||||
if self.junctions then
|
||||
self.junctions[minetest.pos_to_string(vector.round(pos))] = {dir, switch_keys}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.get_junction(self, pos, dir)
|
||||
local junctions = CartsOnRail[self.myID] and CartsOnRail[self.myID].junctions
|
||||
if junctions then
|
||||
local data = junctions[minetest.pos_to_string(vector.round(pos))]
|
||||
if data then
|
||||
return data[1], data[2]
|
||||
end
|
||||
end
|
||||
return dir
|
||||
end
|
||||
|
||||
--
|
||||
-- Normal operation
|
||||
--
|
||||
function minecart.start_run(self, pos, vel, driver)
|
||||
if vector.equals(vel, {x=0, y=0, z=0}) then
|
||||
local start_key = get_route_key(pos)
|
||||
if not start_key then
|
||||
if driver then -- Punched from inside the cart
|
||||
-- Don't start the cart
|
||||
self.velocity = {x=0, y=0, z=0}
|
||||
minetest.chat_send_player(driver, S("[minecart] Please start at a Railway Buffer!"))
|
||||
return
|
||||
end
|
||||
-- Add also carts without route to be able to restore last pos/vel
|
||||
minetest.log("info", "[minecart] Cart "..self.myID.." started.")
|
||||
--print("start_run", dump(CartsOnRail[self.myID]))
|
||||
CartsOnRail[self.myID].stopped = false
|
||||
else -- Add cart to monitoring
|
||||
minetest.log("info", "[minecart] Cart "..self.myID.." started.")
|
||||
--print("start_run", dump(CartsOnRail[self.myID]))
|
||||
local item = CartsOnRail[self.myID]
|
||||
item.start_time = minetest.get_gametime()
|
||||
item.start_key = start_key
|
||||
item.stopped = false
|
||||
item.junctions = minecart.get_route(start_key).junctions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.attach_cargo(self, pos)
|
||||
local data = CartsOnRail[self.myID]
|
||||
if data then
|
||||
data.attached_items = {}
|
||||
for _, obj_ in pairs(minetest.get_objects_inside_radius(pos, 1)) do
|
||||
local entity = obj_:get_luaentity()
|
||||
if not obj_:is_player() and entity and entity.name == "__builtin:item" then
|
||||
obj_:remove()
|
||||
data.attached_items[#data.attached_items + 1] = entity.itemstring
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.detach_cargo(self, pos, data)
|
||||
-- Spawn loaded items again
|
||||
if data.attached_items then
|
||||
for _,item in ipairs(data.attached_items) do
|
||||
minetest.add_item(pos, ItemStack(item))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.stopped(self, pos)
|
||||
local data = CartsOnRail[self.myID]
|
||||
if data and not data.stopped then
|
||||
minecart.detach_cargo(self, pos, data)
|
||||
data.stopped = true
|
||||
data.start_key = get_route_key(pos)
|
||||
data.start_pos = pos
|
||||
data.start_time = nil
|
||||
minetest.log("info", "[minecart] Cart "..self.myID.." stopped.")
|
||||
if self.sound_handle then
|
||||
minetest.sound_stop(self.sound_handle)
|
||||
end
|
||||
return data.cargo or {} -- for node based carts
|
||||
end
|
||||
end
|
||||
|
||||
function minecart.on_dig(self)
|
||||
if self and self.myID then
|
||||
CartsOnRail[self.myID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Monitoring
|
||||
--
|
||||
local function spawn_cart(pos, vel, item)
|
||||
-- local node = minetest.get_node(pos)
|
||||
-- if not minetest.tValidCarts[node.name] then
|
||||
local pos2 = vector.round(pos)
|
||||
if carts:is_rail(pos2) or carts:is_rail({x = pos2.x, y = pos2.y-1, z = pos2.z}) then
|
||||
local obj = minetest.add_entity(pos, item.entity_name or "minecart:cart", nil)
|
||||
obj:set_velocity(vel)
|
||||
local id = minecart.add_cart_to_monitoring(obj, item.owner)
|
||||
minetest.log("info", "[minecart] Cart "..id.." spawned again.")
|
||||
return id
|
||||
end
|
||||
end
|
||||
|
||||
local function calc_pos_and_vel(item)
|
||||
if item.start_time and item.start_key then
|
||||
local run_time = minetest.get_gametime() - item.start_time
|
||||
local waypoints = minecart.get_route(item.start_key).waypoints
|
||||
local waypoint = waypoints[run_time]
|
||||
if waypoint then
|
||||
return minetest.string_to_pos(waypoint[1]), minetest.string_to_pos(waypoint[2])
|
||||
end
|
||||
end
|
||||
if item.last_pos then
|
||||
return item.last_pos, item.last_vel
|
||||
end
|
||||
return item.start_pos, {x=0, y=0, z=0}
|
||||
end
|
||||
|
||||
local function monitoring()
|
||||
local to_be_added = {}
|
||||
for key, item in pairs(CartsOnRail) do
|
||||
--print("Cart:", key, P2S(item.start_pos), item.owner)
|
||||
if not item.recording then
|
||||
local entity = minetest.luaentities[key]
|
||||
if entity then -- cart in loaded area
|
||||
local pos = entity.object:get_pos()
|
||||
local vel = entity.object:get_velocity()
|
||||
if not minetest.get_node_or_nil(pos) then -- in unloaded area
|
||||
minetest.log("info", "[minecart] Cart "..key.." virtualized.")
|
||||
if entity.sound_handle then
|
||||
minetest.sound_stop(entity.sound_handle)
|
||||
end
|
||||
if vector.equals(vel, {x=0, y=0, z=0}) then
|
||||
minecart.attach_cargo(entity, pos)
|
||||
end
|
||||
entity.object:remove()
|
||||
end
|
||||
-- store last pos from cart without route
|
||||
item.last_pos, item.last_vel = pos, vel
|
||||
else -- cart in unloaded area
|
||||
local pos, vel = calc_pos_and_vel(item)
|
||||
if pos and vel then
|
||||
if minetest.get_node_or_nil(pos) then -- in loaded area
|
||||
local id = spawn_cart(pos, vel, item)
|
||||
if id then
|
||||
to_be_added[id] = table.copy(item)
|
||||
CartsOnRail[key] = nil
|
||||
end
|
||||
end
|
||||
else
|
||||
CartsOnRail[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- table maintenance
|
||||
for key,val in pairs(to_be_added) do
|
||||
CartsOnRail[key] = val
|
||||
end
|
||||
minetest.after(1, monitoring)
|
||||
end
|
||||
minetest.after(1, monitoring)
|
||||
|
||||
minecart.calc_pos_and_vel = calc_pos_and_vel
|
||||
|
||||
--
|
||||
-- API function to get a list of cart data with current position and speed.
|
||||
--
|
||||
function minecart.get_cart_list()
|
||||
local tbl = {}
|
||||
for id, item in pairs(CartsOnRail) do
|
||||
local pos, speed = calc_pos_and_vel(item)
|
||||
tbl[#tbl+1] = {pos = pos, speed = speed, id = id}
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
-- minecart.get_route_key(pos, player_name)
|
||||
minecart.get_route_key = get_route_key
|
@ -279,6 +279,9 @@ signs_bot.register_botcommand("pause", {
|
||||
mem.steps = nil
|
||||
return signs_bot.DONE
|
||||
end
|
||||
if mem.capa then
|
||||
mem.capa = mem.capa + 1
|
||||
end
|
||||
return signs_bot.BUSY
|
||||
end,
|
||||
})
|
||||
@ -289,6 +292,9 @@ signs_bot.register_botcommand("stop", {
|
||||
num_param = 0,
|
||||
description = I("Stop the robot."),
|
||||
cmnd = function(base_pos, mem, slot)
|
||||
if mem.capa then
|
||||
mem.capa = mem.capa + 2
|
||||
end
|
||||
return signs_bot.DONE
|
||||
end,
|
||||
})
|
||||
|
@ -203,7 +203,7 @@ signs_bot.register_botcommand("place_above", {
|
||||
|
||||
local function dig_item(base_pos, robot_pos, param2, slot, route, level)
|
||||
local pos1 = lib.dest_pos(robot_pos, param2, route)
|
||||
pos1.y = pos1.y + level
|
||||
pos1.y = pos1.y + (level or 0)
|
||||
local node = lib.get_node_lvm(pos1)
|
||||
local dug_name = lib.is_simple_node(node)
|
||||
if not lib.not_protected(base_pos, pos1) then
|
||||
|
@ -233,6 +233,8 @@ local function move(mem, any_sensor)
|
||||
activate_sensor(mem.robot_pos, (mem.robot_param2 + 1) % 4)
|
||||
activate_sensor(mem.robot_pos, (mem.robot_param2 + 3) % 4)
|
||||
end
|
||||
elseif mem.capa then
|
||||
mem.capa = mem.capa + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -41,8 +41,10 @@ end
|
||||
|
||||
local function get_line_tokens(script)
|
||||
local idx = 0
|
||||
local lines = string.split(script or ""
|
||||
, "\n", true)
|
||||
script = script or ""
|
||||
script = script:gsub("\r\n", "\n")
|
||||
script = script:gsub("\r", "\n")
|
||||
local lines = string.split(script, "\n", true)
|
||||
return function()
|
||||
while idx < #lines do
|
||||
idx = idx + 1
|
||||
@ -95,6 +97,7 @@ end
|
||||
|
||||
local function pass1(tokens)
|
||||
local pc = 1
|
||||
tSymbolTbl = {}
|
||||
for _, token in ipairs(tokens) do
|
||||
if token:find("%w+:") then
|
||||
tSymbolTbl[token] = pc
|
||||
@ -129,6 +132,9 @@ end
|
||||
-- Commands
|
||||
-------------------------------------------------------------------------------
|
||||
local function register_command(cmnd_name, num_param, cmnd_func, check_func)
|
||||
assert(num_param, cmnd_name..": num_param = "..dump(num_param))
|
||||
assert(cmnd_func, cmnd_name..": cmnd_func = "..dump(cmnd_func))
|
||||
assert(check_func or num_param == 0, cmnd_name..": check_func = "..dump(check_func))
|
||||
lCmdLookup[#lCmdLookup + 1] = {num_param, cmnd_func, cmnd_name}
|
||||
tCmdDef[cmnd_name] = {
|
||||
num_param = num_param,
|
||||
@ -174,6 +180,9 @@ register_command("call", 1,
|
||||
mem.Stack[#mem.Stack + 1] = mem.pc + 2
|
||||
mem.pc = addr - 2
|
||||
return api.DONE
|
||||
end,
|
||||
function(addr)
|
||||
return tSymbolTbl[addr..":"]
|
||||
end
|
||||
)
|
||||
|
||||
@ -192,6 +201,9 @@ register_command("jump", 1,
|
||||
function(base_pos, mem, addr)
|
||||
mem.pc = addr - 2
|
||||
return api.DONE
|
||||
end,
|
||||
function(addr)
|
||||
return tSymbolTbl[addr..":"]
|
||||
end
|
||||
)
|
||||
|
||||
@ -205,14 +217,19 @@ register_command("exit", 0,
|
||||
-- API functions
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function api.register_command(cmnd_name, num_param, cmnd_func)
|
||||
register_command(cmnd_name, num_param, cmnd_func)
|
||||
function api.register_command(cmnd_name, num_param, cmnd_func, check_func)
|
||||
register_command(cmnd_name, num_param, cmnd_func, check_func)
|
||||
end
|
||||
|
||||
-- function returns: true/false, error_string, line-num
|
||||
function api.check_script(script)
|
||||
local tbl = {}
|
||||
local num_token = 0
|
||||
|
||||
-- to fill the symbol table
|
||||
local tokens = tokenizer(script)
|
||||
pass1(tokens)
|
||||
|
||||
for idx, cmnd, param1, param2, param3 in get_line_tokens(script) do
|
||||
if tCmdDef[cmnd] then
|
||||
num_token = num_token + 1 + tCmdDef[cmnd].num_param
|
||||
@ -222,7 +239,11 @@ function api.check_script(script)
|
||||
param1 = tonumber(param1) or param1
|
||||
param2 = tonumber(param2) or param2
|
||||
param3 = tonumber(param3) or param3
|
||||
if tCmdDef[cmnd].check and not tCmdDef[cmnd].check(param1, param2, param3) then
|
||||
local num_param = (param1 and 1 or 0) + (param2 and 1 or 0) + (param3 and 1 or 0)
|
||||
if tCmdDef[cmnd].num_param ~= num_param then
|
||||
return false, I("Wrong number of parameters"), idx
|
||||
end
|
||||
if tCmdDef[cmnd].num_param > 0 and not tCmdDef[cmnd].check(param1, param2, param3) then
|
||||
return false, I("Parameter error"), idx
|
||||
end
|
||||
elseif not cmnd:find("%w+:") then
|
||||
@ -275,4 +296,4 @@ function api.reset_script(base_pos, mem)
|
||||
mem.Stack = {}
|
||||
end
|
||||
|
||||
return api
|
||||
return api
|
||||
|
@ -141,6 +141,7 @@ end
|
||||
-- Check rights before node is dug or inventory is used
|
||||
function signs_bot.lib.not_protected(base_pos, pos)
|
||||
local me = M(base_pos):get_string("owner")
|
||||
minetest.load_area(pos)
|
||||
if minetest.is_protected(pos, me) then
|
||||
return false
|
||||
end
|
||||
|
@ -35,7 +35,7 @@ Textures: CC BY-SA 3.0
|
||||
### Dependencies
|
||||
Required: default, doors, bucket, stairs, screwdriver, basic_materials, tubelib2, minecart, lcdlib, safer_lua
|
||||
Recommended: signs_bot, hyperloop, compost, techpack_stairway, autobahn
|
||||
Optional: unified_inventory, wielded_light, unifieddyes, lua-mashal, lsqlite3
|
||||
Optional: unified_inventory, wielded_light, unifieddyes, lua-mashal, lsqlite3, moreores
|
||||
|
||||
|
||||
The mods `default`, `doors`, `bucket`, `stairs`, and `screwdriver` are part of Minetest Game.
|
||||
@ -88,6 +88,6 @@ to 'lsqlite3' and 'lua-marshal', but there is no way back, so:
|
||||
- 2020-05-22 V0.08 * Support for 'lua-marshal' and 'lsqlite3' added
|
||||
- 2020-05-31 V0.09 * TA4 tubes upgraded, manuals updated
|
||||
- 2020-06-04 V0.10 * minor changes and bugfixes
|
||||
|
||||
|
||||
- 2020-06-14 V0.11 * cart commands added for both controllers, support for moreores added
|
||||
- 2020-06-17 V0.12 * Ethereal support added, manual correction, tin ingot recipe bugfix
|
||||
|
||||
|
@ -42,7 +42,7 @@ local function can_dig(pos, player)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
local function formspec2()
|
||||
|
@ -197,7 +197,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
|
||||
if crd.power_netw then
|
||||
crd.power_netw:after_dig_node(pos)
|
||||
end
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
|
@ -436,7 +436,7 @@ local function on_rotate(pos, node, user, mode, new_param2)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
convert_to_chest_again(pos, oldnode, digger)
|
||||
end
|
||||
|
||||
|
@ -18,6 +18,7 @@ local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
--local M = minetest.get_meta
|
||||
|
||||
local NodeInfoCache = {}
|
||||
local NumbersToBeRecycled = {}
|
||||
local MP = minetest.get_modpath("techage")
|
||||
local techage_use_sqlite = minetest.settings:get_bool('techage_use_sqlite', false)
|
||||
|
||||
@ -210,17 +211,19 @@ function techage.add_node(pos, name)
|
||||
if item_handling_node(name) then
|
||||
Tube:after_place_node(pos)
|
||||
end
|
||||
-- store position
|
||||
return get_number(pos, true)
|
||||
local key = minetest.hash_node_position(pos)
|
||||
return NumbersToBeRecycled[key] or get_number(pos, true)
|
||||
end
|
||||
|
||||
-- Function removes the node from the techage lists.
|
||||
function techage.remove_node(pos)
|
||||
local number = get_number(pos)
|
||||
function techage.remove_node(pos, oldnode, oldmetadata)
|
||||
local number = oldmetadata and oldmetadata.fields and oldmetadata.fields.node_number
|
||||
number = number or get_number(pos)
|
||||
if number then
|
||||
local key = minetest.hash_node_position(pos)
|
||||
NumbersToBeRecycled[key] = number
|
||||
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
|
||||
if ninfo then
|
||||
backend.del_nodepos(number)
|
||||
NodeInfoCache[number] = nil
|
||||
if item_handling_node(ninfo.name) then
|
||||
Tube:after_dig_node(pos)
|
||||
|
@ -80,6 +80,9 @@ end
|
||||
local Version = storage:get_int("Version") or 0
|
||||
local NextNumber = 0
|
||||
|
||||
if Version == 0 then
|
||||
Version = 4
|
||||
end
|
||||
if Version == 3 then
|
||||
Version = 4
|
||||
NextNumber = storage:get_int("NextNumber")
|
||||
|
@ -17,6 +17,10 @@ local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
local cart = dofile(MP.."/cart_lib1.lua")
|
||||
|
||||
cart:init(true)
|
||||
|
||||
local function formspec()
|
||||
return "size[8,6]"..
|
||||
@ -31,7 +35,8 @@ end
|
||||
|
||||
local function can_dig(pos, player)
|
||||
local owner = M(pos):get_string("owner")
|
||||
if owner ~= "" and owner ~= player:get_player_name() then
|
||||
if owner ~= "" and (owner ~= player:get_player_name() or
|
||||
not minetest.check_player_privs(player:get_player_name(), "minecart")) then
|
||||
return false
|
||||
end
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
@ -91,12 +96,11 @@ minetest.register_node("techage:chest_cart", {
|
||||
end,
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
return minecart.node_on_place(itemstack, placer, pointed_thing,
|
||||
"techage:chest_cart")
|
||||
return cart.add_cart(itemstack, placer, pointed_thing, "techage:chest_cart")
|
||||
end,
|
||||
|
||||
on_punch = function(pos, node, puncher, pointed_thing)
|
||||
minecart.node_on_punch(pos, node, puncher, pointed_thing, "techage:chest_cart_entity")
|
||||
cart.node_on_punch(pos, node, puncher, pointed_thing, "techage:chest_cart_entity")
|
||||
end,
|
||||
|
||||
set_cargo = function(pos, data)
|
||||
@ -133,9 +137,9 @@ minecart.register_cart_entity("techage:chest_cart_entity", "techage:chest_cart",
|
||||
visual_size = {x=0.66, y=0.66, z=0.66},
|
||||
static_save = false,
|
||||
},
|
||||
on_activate = minecart.on_activate,
|
||||
on_punch = minecart.on_punch,
|
||||
on_step = minecart.on_step,
|
||||
on_activate = cart.on_activate,
|
||||
on_punch = cart.on_punch,
|
||||
on_step = cart.on_step,
|
||||
})
|
||||
|
||||
techage.register_node({"techage:chest_cart"}, {
|
||||
|
@ -19,6 +19,10 @@ local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local Pipe = techage.LiquidPipe
|
||||
local liquid = techage.liquid
|
||||
local MP = minetest.get_modpath("minecart")
|
||||
local cart = dofile(MP.."/cart_lib1.lua")
|
||||
|
||||
cart:init(true)
|
||||
|
||||
local CAPACITY = 100
|
||||
|
||||
@ -110,8 +114,7 @@ minetest.register_node("techage:tank_cart", {
|
||||
end,
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
return minecart.node_on_place(itemstack, placer, pointed_thing,
|
||||
"techage:tank_cart")
|
||||
return cart.add_cart(itemstack, placer, pointed_thing, "techage:tank_cart")
|
||||
end,
|
||||
|
||||
on_punch = function(pos, node, puncher, pointed_thing)
|
||||
@ -121,7 +124,7 @@ minetest.register_node("techage:tank_cart", {
|
||||
if techage.liquid.is_container_empty(wielded_item) then
|
||||
liquid.on_punch(pos, node, puncher, pointed_thing)
|
||||
else
|
||||
minecart.node_on_punch(pos, node, puncher, pointed_thing, "techage:tank_cart_entity")
|
||||
cart.node_on_punch(pos, node, puncher, pointed_thing, "techage:tank_cart_entity")
|
||||
end
|
||||
end,
|
||||
|
||||
@ -170,9 +173,9 @@ minecart.register_cart_entity("techage:tank_cart_entity", "techage:tank_cart", {
|
||||
visual_size = {x=0.66, y=0.66, z=0.66},
|
||||
static_save = false,
|
||||
},
|
||||
on_activate = minecart.on_activate,
|
||||
on_punch = minecart.on_punch,
|
||||
on_step = minecart.on_step,
|
||||
on_activate = cart.on_activate,
|
||||
on_punch = cart.on_punch,
|
||||
on_step = cart.on_step,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -267,7 +267,7 @@ minetest.register_node("techage:ta4_doser", {
|
||||
del_liquids(pos)
|
||||
end,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
Pipe:after_dig_node(pos)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
@ -46,6 +46,7 @@ techage.Items = {
|
||||
ta2_rinser = "techage:ta2_rinser_pas",
|
||||
ta2_chest = "techage:chest_ta2",
|
||||
ta2_forceload = "techage:forceload",
|
||||
ta2_driveaxle = "techage:axle",
|
||||
---------------------
|
||||
techage_ta3 = "techage_ta3.png",
|
||||
techage_ta31 = "techage_ta3b.png",
|
||||
|
@ -26,6 +26,7 @@ techage.manual_DE.aTitel = {
|
||||
"3,TA2 Zylinder /Cylinder",
|
||||
"3,TA2 Schwungrad / Flywheel",
|
||||
"3,TA2 Dampfleitungen / Steam Pipe",
|
||||
"3,TA2 Antriebsachsen / TA2 Drive Axle",
|
||||
"2,Items schieben und sortieren",
|
||||
"3,Röhren / TechAge Tube",
|
||||
"3,TA2 Schieber / Pusher",
|
||||
@ -233,6 +234,7 @@ techage.manual_DE.aText = {
|
||||
"\n"..
|
||||
"\n",
|
||||
"Baborium wird nur im Untertagebau gewonnen. Baborium findet man nur in Stein in einer Höhe zwischen -250 und -340 Meter.\n"..
|
||||
"Baborium kann nur im TA3 Industrieofen geschmolzen werden.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
@ -377,6 +379,10 @@ techage.manual_DE.aText = {
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
"Die Antriebsachsen dienen zur Kraftübertragung von der Dampfmaschine zu anderen Maschinen. Die maximale Länge einer Antriebsachse beträgt 8 Blöcke. Über Getriebeboxen können auch größere Strecken überbrückt\\, sowie Abzweigungen und Richtungswechsel realisiert werden.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
"Um Gegenstände (Items) von einer Verarbeitungsstation zur nächsten weiter zu transportieren\\, werden Schieber und Röhren verwendet. Siehe Plan.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
@ -1487,6 +1493,7 @@ techage.manual_DE.aItemName = {
|
||||
"ta2_cylinder",
|
||||
"ta2_flywheel",
|
||||
"ta2_steampipe",
|
||||
"ta2_driveaxle",
|
||||
"",
|
||||
"tube",
|
||||
"ta2_pusher",
|
||||
@ -1670,6 +1677,7 @@ techage.manual_DE.aPlanTable = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"itemtransport",
|
||||
"",
|
||||
"",
|
||||
|
@ -26,6 +26,7 @@ techage.manual_EN.aTitel = {
|
||||
"3,TA2 Cylinder",
|
||||
"3,TA2 Flywheel",
|
||||
"3,TA2 Steam Pipes",
|
||||
"3,TA2 Drive Axle / TA2 Gearbox",
|
||||
"2,Push and sort items",
|
||||
"3,TechAge Tube",
|
||||
"3,TA2 Pusher",
|
||||
@ -224,7 +225,7 @@ techage.manual_EN.aText = {
|
||||
" - Petroleum - is needed in TA3\n"..
|
||||
" - Bauxite - an aluminum ore that is needed in TA4 to produce aluminum\n"..
|
||||
"\n",
|
||||
"Meridium is an alloy of steel and mesecons crystals. Meridium ingots can be made with the coal burner from steel andesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.\n"..
|
||||
"Meridium is an alloy of steel and mesecons crystals. Meridium ingots can be made with the coal burner from steel and mesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
@ -233,6 +234,7 @@ techage.manual_EN.aText = {
|
||||
"\n"..
|
||||
"\n",
|
||||
"Baborium is only extracted in underground mining. Baborium can only be found in stone at an altitude between -250 and -340 meters.\n"..
|
||||
"Baborium can only be melted in the TA3 Industrial Furnace.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
@ -326,7 +328,7 @@ techage.manual_EN.aText = {
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
"TA1 has its own metal alloy meridium. Meridium ingots can be made with the coal burner from steel and mesecons splinters. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.\n"..
|
||||
"TA1 has its own metal alloy meridium. Meridium ingots can be made with the coal burner from steel and mesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
@ -377,6 +379,10 @@ techage.manual_EN.aText = {
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
"The drive axles are used to transmit power from the steam engine to other machines. The maximum length of a drive axis is 8 blocks. With TA2 Gearboxes\\, larger distances can be bridged\\, and branches and changes of direction can be realized.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
"In order to transport objects from one processing station to the next\\, pushers and tubes are used. See plan.\n"..
|
||||
"\n"..
|
||||
"\n"..
|
||||
@ -1477,6 +1483,7 @@ techage.manual_EN.aItemName = {
|
||||
"ta2_cylinder",
|
||||
"ta2_flywheel",
|
||||
"ta2_steampipe",
|
||||
"ta2_driveaxle",
|
||||
"",
|
||||
"tube",
|
||||
"ta2_pusher",
|
||||
@ -1660,6 +1667,7 @@ techage.manual_EN.aPlanTable = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"itemtransport",
|
||||
"",
|
||||
"",
|
||||
|
@ -25,7 +25,6 @@ techage.furnace.register_recipe({
|
||||
time = 8,
|
||||
})
|
||||
|
||||
|
||||
if techage.modified_recipes_enabled then
|
||||
techage.furnace.register_recipe({
|
||||
output = "default:bronze_ingot 4",
|
||||
@ -148,3 +147,24 @@ techage.furnace.register_recipe({
|
||||
},
|
||||
time = 4,
|
||||
})
|
||||
|
||||
if minetest.global_exists("moreores") then
|
||||
|
||||
if techage.modified_recipes_enabled then
|
||||
minetest.clear_craft({output = "moreores:mithril_ingot"})
|
||||
minetest.clear_craft({output = "moreores:silver_ingot"})
|
||||
end
|
||||
|
||||
techage.furnace.register_recipe({
|
||||
output = 'moreores:silver_ingot',
|
||||
recipe = {'moreores:silver_lump'},
|
||||
time = 2,
|
||||
})
|
||||
|
||||
techage.furnace.register_recipe({
|
||||
output = 'moreores:mithril_ingot',
|
||||
recipe = {'moreores:mithril_lump'},
|
||||
time = 5,
|
||||
})
|
||||
|
||||
end
|
||||
|
@ -688,4 +688,3 @@ techage.icta_register_action("set_filter", {
|
||||
return send_single_string(environ, data.number, "filter", payload)
|
||||
end,
|
||||
})
|
||||
|
||||
|
@ -451,8 +451,8 @@ minetest.register_node("techage:ta4_icta_controller", {
|
||||
return
|
||||
end
|
||||
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
techage.remove_node(pos)
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
end,
|
||||
|
||||
on_timer = on_timer,
|
||||
|
@ -110,8 +110,8 @@ minetest.register_node("techage:ta4_display", {
|
||||
minetest.get_node_timer(pos):start(1)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
on_timer = on_timer,
|
||||
@ -157,8 +157,8 @@ minetest.register_node("techage:ta4_displayXL", {
|
||||
minetest.get_node_timer(pos):start(2)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
on_timer = on_timer,
|
||||
|
@ -56,8 +56,8 @@ minetest.register_node("techage:ta4_signaltower", {
|
||||
end
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
|
@ -13,7 +13,7 @@
|
||||
techage = {}
|
||||
|
||||
-- Version for compatibility checks, see readme.md/history
|
||||
techage.version = 0.10
|
||||
techage.version = 0.12
|
||||
|
||||
if minetest.global_exists("tubelib") then
|
||||
minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!")
|
||||
@ -27,8 +27,8 @@ elseif minetest.global_exists("techpack") then
|
||||
elseif minetest.global_exists("tubelib2") and tubelib2.version < 1.9 then
|
||||
minetest.log("error", "[techage] Techage requires tubelib2 version 1.9 or newer!")
|
||||
return
|
||||
elseif minetest.global_exists("minecart") and minecart.version < 1.05 then
|
||||
minetest.log("error", "[techage] Techage requires minecart version 1.05 or newer!")
|
||||
elseif minetest.global_exists("minecart") and minecart.version < 1.06 then
|
||||
minetest.log("error", "[techage] Techage requires minecart version 1.06 or newer!")
|
||||
return
|
||||
elseif minetest.global_exists("lcdlib") and lcdlib.version < 1.0 then
|
||||
minetest.log("error", "[techage] Techage requires lcdlib version 1.0 or newer!")
|
||||
@ -278,6 +278,7 @@ dofile(MP.."/lua_controller/sensorchest.lua")
|
||||
dofile(MP.."/lua_controller/terminal.lua")
|
||||
|
||||
-- Items
|
||||
dofile(MP.."/items/registered_nodes.lua")
|
||||
dofile(MP.."/items/barrel.lua")
|
||||
dofile(MP.."/items/baborium.lua")
|
||||
dofile(MP.."/items/usmium.lua")
|
||||
|
@ -29,8 +29,7 @@ end
|
||||
local function num_dirt(pos)
|
||||
local pos1 = {x=pos.x-2, y=pos.y-1, z=pos.z-2}
|
||||
local pos2 = {x=pos.x+2, y=pos.y+3, z=pos.z+2}
|
||||
local nodes = minetest.find_nodes_in_area(pos1, pos2, {"default:dirt", "default:dirt_with_grass",
|
||||
"default:dirt_with_dry_grass", "default:dirt_with_snow", "techage:dirt_with_ash"})
|
||||
local nodes = minetest.find_nodes_in_area(pos1, pos2, techage.aAnyKindOfDirtBlocks)
|
||||
return #nodes
|
||||
end
|
||||
|
||||
@ -38,9 +37,18 @@ end
|
||||
local function make_dirt_with_dry_grass(pos)
|
||||
local pos1 = {x=pos.x-2, y=pos.y+3, z=pos.z-2}
|
||||
local pos2 = {x=pos.x+2, y=pos.y+3, z=pos.z+2}
|
||||
for _,p in ipairs(minetest.find_nodes_in_area(pos1, pos2, "default:dirt_with_grass")) do
|
||||
for _,p in ipairs(minetest.find_nodes_in_area(pos1, pos2, {
|
||||
"default:dirt_with_grass",
|
||||
"default:dirt_with_coniferous_litter",
|
||||
"default:dirt_with_rainforest_litter",
|
||||
})) do
|
||||
minetest.swap_node(p, {name = "default:dirt_with_dry_grass"})
|
||||
end
|
||||
if minetest.global_exists("ethereal") then
|
||||
for _,p in ipairs(minetest.find_nodes_in_area(pos1, pos2, techage.aEtherealDirts)) do
|
||||
minetest.swap_node(p, {name = "default:dirt_with_dry_grass"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- replace pile bottom nodes
|
||||
|
@ -35,9 +35,23 @@ local function push_items(pos, items)
|
||||
minetest.add_item({x=pos.x, y=pos.y-0.4, z=pos.z}, items)
|
||||
end
|
||||
|
||||
local function minecart_hopper_takeitem(pos, num)
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius({x=pos.x, y=pos.y-0.4, z=pos.z}, 0.2)) do
|
||||
local entity = obj:get_luaentity()
|
||||
if not obj:is_player() and entity and entity.name == "__builtin:item" then
|
||||
obj:remove()
|
||||
return ItemStack(entity.itemstring or "air")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function minecart_hopper_untakeitem(pos, in_dir, stack)
|
||||
push_items(pos, stack)
|
||||
end
|
||||
|
||||
local function keep_running(pos, elapsed)
|
||||
local inv = M(pos):get_inventory()
|
||||
if swap_node(pos) then
|
||||
local inv = M(pos):get_inventory()
|
||||
local src, dst
|
||||
|
||||
if inv:contains_item("src", ItemStack("techage:basalt_gravel")) then
|
||||
@ -53,6 +67,7 @@ local function keep_running(pos, elapsed)
|
||||
push_items(pos, dst)
|
||||
inv:remove_item("src", src)
|
||||
end
|
||||
local inv = M(pos):get_inventory()
|
||||
return not inv:is_empty("src")
|
||||
end
|
||||
|
||||
@ -127,6 +142,9 @@ for idx = 0,3 do
|
||||
on_construct = idx == 3 and on_construct or nil,
|
||||
on_punch = idx == 3 and on_punch or nil,
|
||||
on_timer = keep_running,
|
||||
|
||||
minecart_hopper_takeitem = minecart_hopper_takeitem,
|
||||
minecart_hopper_untakeitem = minecart_hopper_untakeitem,
|
||||
|
||||
paramtype = "light",
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
|
@ -73,8 +73,5 @@ minecart.register_inventory(
|
||||
end,
|
||||
listname = "src",
|
||||
},
|
||||
take = {
|
||||
listname = "src",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -142,6 +142,9 @@ if techage.modified_recipes_enabled then
|
||||
minetest.clear_craft({output = "default:steel_ingot"})
|
||||
minetest.clear_craft({output = "fire:flint_and_steel"})
|
||||
minetest.clear_craft({output = "bucket:bucket_empty"})
|
||||
if minetest.global_exists("moreores") then
|
||||
minetest.clear_craft({output = "moreores:silver_ingot"})
|
||||
end
|
||||
|
||||
-- add again
|
||||
minetest.register_craft({
|
||||
@ -171,6 +174,23 @@ if techage.modified_recipes_enabled then
|
||||
time = 8,
|
||||
})
|
||||
|
||||
techage.ironage_register_recipe({
|
||||
output = "default:tin_ingot 1",
|
||||
recipe = {"default:tin_lump"},
|
||||
heat = 4,
|
||||
time = 2,
|
||||
})
|
||||
|
||||
if minetest.global_exists("moreores") then
|
||||
techage.ironage_register_recipe({
|
||||
output = "moreores:silver_ingot 1",
|
||||
recipe = {"moreores:silver_lump"},
|
||||
heat = 5,
|
||||
time = 2,
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "fire:flint_and_steel",
|
||||
recipe = {
|
||||
|
@ -43,9 +43,8 @@ minetest.register_ore({
|
||||
y_max = -250,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = 'cooking',
|
||||
techage.furnace.register_recipe({
|
||||
output = 'techage:baborium_ingot',
|
||||
recipe = 'techage:baborium_lump',
|
||||
cooktime = 5,
|
||||
recipe = {'techage:baborium_lump'},
|
||||
time = 3,
|
||||
})
|
||||
|
39
techage/items/registered_nodes.lua
Normal file
39
techage/items/registered_nodes.lua
Normal file
@ -0,0 +1,39 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019 Joachim Stolberg
|
||||
|
||||
GPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Collect data of registered nodes
|
||||
|
||||
]]--
|
||||
|
||||
|
||||
techage.aEtherealDirts = {
|
||||
"ethereal:fiery_dirt",
|
||||
"ethereal:cold_dirt",
|
||||
"ethereal:crystal_dirt",
|
||||
"ethereal:gray_dirt",
|
||||
"ethereal:mushroom_dirt",
|
||||
"ethereal:prairie_dirt",
|
||||
"ethereal:grove_dirt",
|
||||
"ethereal:jungle_dirt",
|
||||
"ethereal:bamboo_dirt",
|
||||
}
|
||||
|
||||
techage.aAnyKindOfDirtBlocks = {}
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
for name, ndef in pairs(minetest.registered_nodes) do
|
||||
if string.find(name, "dirt") and
|
||||
ndef.drawtype == "normal" and
|
||||
ndef.groups.crumbly and ndef.groups.crumbly > 0 then
|
||||
techage.aAnyKindOfDirtBlocks[#techage.aAnyKindOfDirtBlocks + 1] = name
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
@ -161,7 +161,7 @@ minetest.register_node("techage:ta3_silo", {
|
||||
end,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
Pipe:after_dig_node(pos)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
liquid = tLiquid,
|
||||
networks = tNetworks,
|
||||
@ -206,7 +206,7 @@ minetest.register_node("techage:ta4_silo", {
|
||||
end,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
Pipe:after_dig_node(pos)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
liquid = tLiquid,
|
||||
networks = tNetworks,
|
||||
|
@ -103,7 +103,7 @@ minetest.register_node("techage:ta3_tank", {
|
||||
on_punch = liquid.on_punch,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
Pipe:after_dig_node(pos)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
liquid = {
|
||||
capa = CAPACITY,
|
||||
@ -161,7 +161,7 @@ minetest.register_node("techage:oiltank", {
|
||||
on_punch = liquid.on_punch,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
Pipe:after_dig_node(pos)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
liquid = {
|
||||
capa = CAPACITY * 4,
|
||||
@ -209,7 +209,7 @@ minetest.register_node("techage:ta4_tank", {
|
||||
on_punch = liquid.on_punch,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
Pipe:after_dig_node(pos)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
liquid = {
|
||||
capa = CAPACITY * 2,
|
||||
|
@ -140,7 +140,7 @@ local function techage_set_numbers(pos, numbers, player_name)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_button_off", {
|
||||
|
@ -73,7 +73,7 @@ local function techage_set_numbers(pos, numbers, player_name)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_cartdetector_off", {
|
||||
|
@ -177,8 +177,8 @@ minetest.register_node("techage:ta4_collector", {
|
||||
|
||||
on_timer = on_timer,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
|
@ -76,7 +76,7 @@ local function techage_set_numbers(pos, numbers, player_name)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
|
@ -78,8 +78,8 @@ for idx,pgn in ipairs(tPgns) do
|
||||
end
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
|
@ -105,9 +105,9 @@ minetest.register_node("techage:ta3_doorcontroller", {
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
swap_door_nodes(pos, false)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
|
@ -64,8 +64,8 @@ for idx,pgn in ipairs(tPgns) do
|
||||
end
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
|
@ -207,8 +207,8 @@ minetest.register_node("techage:ta3_logic", {
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
|
@ -135,7 +135,7 @@ minetest.register_node("techage:ta3_nodedetector_off", {
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
@ -165,7 +165,7 @@ minetest.register_node("techage:ta3_nodedetector_on", {
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
|
@ -133,7 +133,7 @@ minetest.register_node("techage:ta3_playerdetector_off", {
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
@ -168,7 +168,7 @@ minetest.register_node("techage:ta3_playerdetector_on", {
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
@ -224,7 +224,7 @@ minetest.register_node("techage:ta4_playerdetector_off", {
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
@ -273,7 +273,7 @@ minetest.register_node("techage:ta4_playerdetector_on", {
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
|
@ -72,8 +72,8 @@ minetest.register_node("techage:ta3_repeater", {
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
|
@ -228,8 +228,8 @@ minetest.register_node("techage:ta3_sequencer", {
|
||||
end
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if not nvm.running then
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
techage.remove_node(pos)
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
end,
|
||||
|
@ -54,7 +54,7 @@ minetest.register_node("techage:signal_lamp_off", {
|
||||
on_rightclick = switch_on,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
if COLORED then
|
||||
unifieddyes.after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
end
|
||||
@ -97,7 +97,7 @@ minetest.register_node("techage:signal_lamp_on", {
|
||||
after_place_node = COLORED and unifieddyes.recolor_on_place or nil,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
if COLORED then
|
||||
unifieddyes.after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
end
|
||||
|
@ -226,8 +226,8 @@ local function register_terminal(num, tiles, node_box, selection_box)
|
||||
end
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
|
@ -175,8 +175,8 @@ minetest.register_node("techage:ta3_timer", {
|
||||
|
||||
on_timer = check_rules,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
|
@ -533,8 +533,8 @@ minetest.register_node("techage:ta4_lua_controller", {
|
||||
return
|
||||
end
|
||||
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
techage.remove_node(pos)
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
end,
|
||||
|
||||
on_timer = on_timer,
|
||||
|
@ -89,7 +89,7 @@ local function can_dig(pos, player)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
local function formspec1()
|
||||
|
@ -86,8 +86,8 @@ minetest.register_node("techage:ta4_server", {
|
||||
return
|
||||
end
|
||||
techage.del_mem(pos)
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
techage.remove_node(pos)
|
||||
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||
end,
|
||||
|
||||
on_timer = function(pos, elasped)
|
||||
|
@ -173,8 +173,8 @@ minetest.register_node("techage:ta4_terminal", {
|
||||
end
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos)
|
||||
techage.remove_node(pos)
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
|
@ -26,7 +26,7 @@ Since the levels build on each other, all ages have to be run through one after
|
||||
|
||||
## Iron Age (TA1)
|
||||
|
||||
1. Search and harvest cactus to make paper and craft the Techage Construction Board. This plan is the ingame manual for all four Techage phases
|
||||
1. Search and harvest papyrus to make paper and craft the Techage Construction Board. This plan is the ingame manual for all four Techage phases
|
||||
2. Cut trees and make wood out of them
|
||||
3. Collect dirt for the charcoal burner to make charcoal
|
||||
4. Go mining and seach for ores, or
|
||||
|
@ -65,6 +65,7 @@ Usmium kommt nur als Nuggets vor und kann nur beim Waschen von Kies mit der TA2/
|
||||
### Baborium
|
||||
|
||||
Baborium wird nur im Untertagebau gewonnen. Baborium findet man nur in Stein in einer Höhe zwischen -250 und -340 Meter.
|
||||
Baborium kann nur im TA3 Industrieofen geschmolzen werden.
|
||||
|
||||
[baborium|image]
|
||||
|
||||
|
@ -50,7 +50,7 @@ Techage adds some new items to the game:
|
||||
|
||||
### Meridium
|
||||
|
||||
Meridium is an alloy of steel and mesecons crystals. Meridium ingots can be made with the coal burner from steel andesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.
|
||||
Meridium is an alloy of steel and mesecons crystals. Meridium ingots can be made with the coal burner from steel and mesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.
|
||||
|
||||
[meridium|image]
|
||||
|
||||
@ -65,6 +65,8 @@ Usmium only occurs as nuggets and can only be obtained by washing gravel with th
|
||||
### Baborium
|
||||
|
||||
Baborium is only extracted in underground mining. Baborium can only be found in stone at an altitude between -250 and -340 meters.
|
||||
Baborium can only be melted in the TA3 Industrial Furnace.
|
||||
|
||||
|
||||
[baborium|image]
|
||||
|
||||
|
@ -98,6 +98,6 @@ Make sure that the boxes are "chest_locked", otherwise someone will steal the va
|
||||
|
||||
### Meridium
|
||||
|
||||
TA1 has its own metal alloy meridium. Meridium ingots can be made with the coal burner from steel and mesecons splinters. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.
|
||||
TA1 has its own metal alloy meridium. Meridium ingots can be made with the coal burner from steel and mesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.
|
||||
|
||||
[meridium|image]
|
||||
|
@ -64,6 +64,12 @@ Teil der Dampfmaschine. Der Boiler muss mit dem Zylinder über die Dampfleitunge
|
||||
|
||||
[ta2_steampipe|image]
|
||||
|
||||
### TA2 Antriebsachsen / TA2 Drive Axle
|
||||
|
||||
Die Antriebsachsen dienen zur Kraftübertragung von der Dampfmaschine zu anderen Maschinen. Die maximale Länge einer Antriebsachse beträgt 8 Blöcke. Über Getriebeboxen können auch größere Strecken überbrückt, sowie Abzweigungen und Richtungswechsel realisiert werden.
|
||||
|
||||
[ta2_driveaxle|image]
|
||||
|
||||
|
||||
## Items schieben und sortieren
|
||||
|
||||
|
@ -65,6 +65,12 @@ Part of the steam engine. The boiler must be connected to the cylinder via the s
|
||||
[ta2_steampipe|image]
|
||||
|
||||
|
||||
### TA2 Drive Axle / TA2 Gearbox
|
||||
|
||||
The drive axles are used to transmit power from the steam engine to other machines. The maximum length of a drive axis is 8 blocks. With TA2 Gearboxes, larger distances can be bridged, and branches and changes of direction can be realized.
|
||||
|
||||
[ta2_driveaxle|image]
|
||||
|
||||
## Push and sort items
|
||||
|
||||
In order to transport objects from one processing station to the next, pushers and tubes are used. See plan.
|
||||
|
Binary file not shown.
@ -25,6 +25,7 @@
|
||||
- [TA2 Zylinder /Cylinder](./manual_ta2_DE.md#ta2-zylinder-cylinder)
|
||||
- [TA2 Schwungrad / Flywheel](./manual_ta2_DE.md#ta2-schwungrad--flywheel)
|
||||
- [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)
|
||||
- [Items schieben und sortieren](./manual_ta2_DE.md#items-schieben-und-sortieren)
|
||||
- [Röhren / TechAge Tube](./manual_ta2_DE.md#röhren--techage-tube)
|
||||
- [TA2 Schieber / Pusher](./manual_ta2_DE.md#ta2-schieber--pusher)
|
||||
|
@ -25,6 +25,7 @@
|
||||
- [TA2 Cylinder](./manual_ta2_EN.md#ta2-cylinder)
|
||||
- [TA2 Flywheel](./manual_ta2_EN.md#ta2-flywheel)
|
||||
- [TA2 Steam Pipes](./manual_ta2_EN.md#ta2-steam-pipes)
|
||||
- [TA2 Drive Axle / TA2 Gearbox](./manual_ta2_EN.md#ta2-drive-axle--ta2-gearbox)
|
||||
- [Push and sort items](./manual_ta2_EN.md#push-and-sort-items)
|
||||
- [TechAge Tube](./manual_ta2_EN.md#techage-tube)
|
||||
- [TA2 Pusher](./manual_ta2_EN.md#ta2-pusher)
|
||||
|
@ -1,4 +1,4 @@
|
||||
name = techage
|
||||
depends = default,doors,tubelib2,basic_materials,bucket,stairs,screwdriver,minecart,lcdlib,safer_lua
|
||||
optional_depends = unified_inventory,wielded_light,unifieddyes
|
||||
description = Techage, go through 4 tech ages in search of wealth and power!
|
||||
optional_depends = unified_inventory,wielded_light,unifieddyes,moreores, ethereal
|
||||
description = Techage, go through 4 tech ages in search of wealth and power!
|
||||
|
@ -72,9 +72,9 @@ local function after_place_node(pos)
|
||||
Cable:after_place_node(pos)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode)
|
||||
local function after_dig_node(pos, oldnode, oldmetadata)
|
||||
Cable:after_dig_node(pos)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
|
@ -171,14 +171,14 @@ local function after_place_node(pos, placer)
|
||||
Cable:after_place_node(pos)
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode)
|
||||
local function after_dig_node(pos, oldnode, oldmetadata)
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
if Rotors[hash] and Rotors[hash]:get_luaentity() then
|
||||
Rotors[hash]:remove()
|
||||
end
|
||||
Rotors[hash] = nil
|
||||
Cable:after_dig_node(pos)
|
||||
techage.remove_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
|
@ -12,6 +12,8 @@ read_globals = {
|
||||
|
||||
"minetest", "vector",
|
||||
"ItemStack", "datastorage",
|
||||
|
||||
"hb",
|
||||
}
|
||||
|
||||
files["callbacks.lua"].ignore = { "player", "draw_lite_mode" }
|
||||
|
@ -2,24 +2,24 @@
|
||||
|
||||
local item_names = {} -- [player_name] = { hud, dtime, itemname }
|
||||
local dlimit = 3 -- HUD element will be hidden after this many seconds
|
||||
local air_hud_mod = minetest.get_modpath("4air")
|
||||
local hud_mod = minetest.get_modpath("hud")
|
||||
local hudbars_mod = minetest.get_modpath("hudbars")
|
||||
|
||||
local function set_hud(player)
|
||||
local player_name = player:get_player_name()
|
||||
local off = {x=0, y=-70}
|
||||
if air_hud_mod or hud_mod then
|
||||
off.y = off.y - 20
|
||||
elseif hudbars_mod then
|
||||
off.y = off.y + 13
|
||||
local off = {x=0, y=-65}
|
||||
if hudbars_mod then
|
||||
-- Assume no alignment (2 per line)
|
||||
off.y = off.y - math.ceil(hb.hudbars_count / 2) * 25
|
||||
else
|
||||
off.y = off.y - 25
|
||||
end
|
||||
|
||||
item_names[player_name] = {
|
||||
hud = player:hud_add({
|
||||
hud_elem_type = "text",
|
||||
position = {x=0.5, y=1},
|
||||
offset = off,
|
||||
alignment = {x=0, y=0},
|
||||
alignment = {x=0, y=-1},
|
||||
number = 0xFFFFFF,
|
||||
text = "",
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user