v2.0 Completely restructured, protection areas removed

This commit is contained in:
Joachim Stolberg 2019-09-19 21:40:16 +02:00
parent 5f692ee6c4
commit 045ffd4f77
3 changed files with 179 additions and 528 deletions

@ -7,7 +7,6 @@ Download: ![GitHub](https://github.com/minetest-mods/towercrane/archive/master.z
The crane can be completely assembled by setting only the base block.
The size of the crane (which is the construction area) and the rope length can be configured.
The owner of the crane gets automatically area protection over the complete construction area (therefore the area Mod is required).
![Tower Crane](https://github.com/minetest-mods/towercrane/blob/master/towercrane640.png)
@ -16,7 +15,7 @@ The owner of the crane gets automatically area protection over the complete cons
* Place the crane base block.
The crane arm will later be build in the same direction you are currently looking
* Right-click the crane base block and set the crane dimensions in height and width (between 8 and 24 by default).
* Right-click the crane base block and set the crane dimensions in height and width (between 8 and 32 by default).
The crane will be build according to this settings.
If there is not enough free space for the crane mast/arm or the potential construction area of the
crane intersects a protected area from another player, the crane will not be build.
@ -24,16 +23,35 @@ The owner of the crane gets automatically area protection over the complete cons
* Right-click the crane switch block to switch to fly privs. The player will be placed in front of the crane.
* To remove the crane, destroy the base block.
**Hint:** The protection area of the crane will also be removed.
In order to protect your building again, you have to use the normal chat commands.
## Dependencies
default
areas (optional)
# License
Copyright (C) 2017 Joachim Stolberg
Copyright (C) 2017-2019 Joachim Stolberg
Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt
Textures: CC0
# History:
* 2017-06-04 v0.01 first version
* 2017-06-06 v0.02 Hook bugfix
* 2017-06-07 v0.03 fixed 2 bugs, added config.lua and sound
* 2017-06-08 v0.04 recipe and rope length now configurable
* 2017-06-10 v0.05 resizing bugfix, area protection added
* 2017-07-11 v0.06 fixed the space check bug, settingtypes added
* 2017-07-16 v0.07 crane remove bug fix
* 2017-07-16 v0.08 player times out bugfix
* 2017-08-19 v0.09 crane protection area to prevent crane clusters
* 2017-08-27 v0.10 hook instance and sound switch off bug fixes
* 2017-09-09 v0.11 further player bugfixes
* 2017-09-24 v0.12 Switched from entity hook model to real fly privs
* 2017-10-17 v0.13 Area protection bugfix
* 2017-11-01 v0.14 Crane handing over bugfix
* 2017-11-07 v0.15 Working zone is now restricted to areas with necessary rights
* 2018-02-27 v0.16 "fly privs" bug fixed (issue #2)
* 2018-04-12 v0.17 "area owner changed" bug fixed (issue #3)
* 2018-05-28 v1.0 Mod released
* 2019-09-08 v2.0 Completely restructured, protection areas removed

@ -1,2 +1 @@
default
areas?

676
init.lua

@ -3,215 +3,77 @@
Tower Crane Mod
===============
v1.0 by JoSt
Copyright (C) 2017-2018 Joachim Stolberg
Copyright (C) 2017-2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
History:
2017-06-04 v0.01 first version
2017-06-06 v0.02 Hook bugfix
2017-06-07 v0.03 fixed 2 bugs, added config.lua and sound
2017-06-08 v0.04 recipe and rope length now configurable
2017-06-10 v0.05 resizing bugfix, area protection added
2017-07-11 v0.06 fixed the space check bug, settingtypes added
2017-07-16 v0.07 crane remove bug fix
2017-07-16 v0.08 player times out bugfix
2017-08-19 v0.09 crane protection area to prevent crane clusters
2017-08-27 v0.10 hook instance and sound switch off bug fixes
2017-09-09 v0.11 further player bugfixes
2017-09-24 v0.12 Switched from entity hook model to real fly privs
2017-10-17 v0.13 Area protection bugfix
2017-11-01 v0.14 Crane handing over bugfix
2017-11-07 v0.15 Working zone is now restricted to areas with necessary rights
2018-02-27 v0.16 "fly privs" bug fixed (issue #2)
2018-04-12 v0.17 "area owner changed" bug fixed (issue #3)
2018-05-28 v1.0 Mod released
Nodes Meta data
+--------+
| | - last_known_pos as "(x,y,z)"
| switch | - last_used
| | - running
+--------+
+--------+
| | - owner
| base | - width
| | - height
+--------+ - dir as "(0,0,1)"
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
-- crane minimum size
MIN_SIZE = 8
local MIN_SIZE = 8
towercrane = {}
dofile(minetest.get_modpath("towercrane") .. "/config.lua")
towercrane.S = minetest.get_translator("towercrane")
local S = towercrane.S
local MP = minetest.get_modpath("towercrane")
dofile(MP.."/config.lua")
dofile(MP.."/control.lua")
-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
local function chat(owner, text)
if owner ~= nil then
minetest.chat_send_player(owner, "[Tower Crane] "..text)
end
end
-- To prevent race condition crashes
local Currently_left_the_game = nil
--##################################################################################################
--## Construction Area
--##################################################################################################
-- Areas = {
-- pos_key = {owner="...", pos1=pos, pos2=pos},
-- }
local storage = minetest.get_mod_storage()
local Areas = minetest.deserialize(storage:get_string("Areas")) or {}
local function update_mod_storage()
storage:set_string("Areas", minetest.serialize(Areas))
local function formspec(height, width)
local text = ""
if height and width then
text = height..","..width
end
return "size[5,4]"..
"label[0,0;"..S("Construction area size").."]" ..
"field[1,1.5;3,1;size;height,width;"..text.."]" ..
"button_exit[1,2;2,1;exit;"..S("Build").."]"
end
minetest.register_on_shutdown(function()
update_mod_storage()
end)
----------------------------------------------------------------------------------------------------
-- The same player can't place a crane within the same protection area
----------------------------------------------------------------------------------------------------
local function no_area_violation(owner, pos)
local res = true
local px, py, pz = pos.x, pos.y, pos.z
for key, area in pairs(Areas) do
if owner == area.owner then
local pos1, pos2 = area.pos1, area.pos2
if (px >= pos1.x and px <= pos2.x) and (py >= pos1.y and py <= pos2.y) and
(pz >= pos1.z and pz <= pos2.z) then
res = false
break
local function get_node_lvm(pos)
local node = minetest.get_node_or_nil(pos)
if node then
return node
end
end
end
return res
local vm = minetest.get_voxel_manip()
local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
local data = vm:get_data()
local param2_data = vm:get_param2_data()
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
local idx = area:indexp(pos)
node = {
name = minetest.get_name_from_content_id(data[idx]),
param2 = param2_data[idx]
}
return node
end
local function store_crane_data(owner, pos, pos1, pos2)
-- normalize x/z so that pos2 > pos1
if pos2.x < pos1.x then
pos2.x, pos1.x = pos1.x, pos2.x
end
if pos2.z < pos1.z then
pos2.z, pos1.z = pos1.z, pos2.z
end
-- store data
local key = minetest.pos_to_string(pos)
Areas[key] = {owner=owner, pos1=pos1, pos2=pos2}
update_mod_storage()
end
local function remove_crane_data(pos)
local key = minetest.pos_to_string(pos)
Areas[key] = nil
update_mod_storage()
end
--##################################################################################################
--## Tower Crane Hook (player)
--##################################################################################################
-- give/take player the necessary privs/physics
local function fly_privs(pos, player, enable)
local privs = minetest.get_player_privs(player:get_player_name())
local physics = player:get_physics_override()
if privs and physics then
if enable == true then
local spos = minetest.pos_to_string(pos)
player:set_attribute("tower_crane_active", spos)
privs["fly"] = true
privs["fast"] = nil
physics.speed = 0.7
else
privs["fast"] = minetest.deserialize(player:get_attribute("tower_crane_store_fast"))
privs["fly"] = minetest.deserialize(player:get_attribute("tower_crane_store_fly"))
physics.speed = minetest.deserialize(player:get_attribute("tower_crane_store_speed"))
player:set_attribute("tower_crane_active", nil)
end
player:set_physics_override(physics)
minetest.set_player_privs(player:get_player_name(), privs)
end
end
-- Normalize the player privs
local function remove_hook(pos, player)
if player then
if pos then
local meta = minetest.get_meta(pos)
meta:set_int("running", 0)
end
fly_privs(pos, player, nil)
end
end
local function control_player(pos, pos1, pos2, player_name)
if player_name == Currently_left_the_game then
Currently_left_the_game = nil
return
end
local player = minetest.get_player_by_name(player_name)
if player then
local meta = minetest.get_meta(pos)
local running = meta:get_int("running")
if running == 1 then
-- check if outside of the construction area
local correction = false
local pl_pos = player:getpos()
if pl_pos then
if pl_pos.x < pos1.x then pl_pos.x = pos1.x; correction = true end
if pl_pos.x > pos2.x then pl_pos.x = pos2.x; correction = true end
if pl_pos.y < pos1.y then pl_pos.y = pos1.y; correction = true end
if pl_pos.y > pos2.y then pl_pos.y = pos2.y; correction = true end
if pl_pos.z < pos1.z then pl_pos.z = pos1.z; correction = true end
if pl_pos.z > pos2.z then pl_pos.z = pos2.z; correction = true end
-- check if a protected area is violated
if correction == false and minetest.is_protected(pl_pos, player_name) then
chat(player_name, "Area is protected.")
correction = true
end
if correction == true then
local last_pos = minetest.string_to_pos(meta:get_string("last_known_pos"))
if last_pos then
player:set_pos(last_pos)
end
else -- store last known correct position
meta:set_string("last_known_pos", minetest.pos_to_string(pl_pos))
end
minetest.after(1, control_player, pos, pos1, pos2, player_name)
else
remove_hook(pos, player)
end
else
remove_hook(pos, player)
end
else
local meta = minetest.get_meta(pos)
meta:set_int("running", 0)
end
end
-- Place the player in front of the base and give fly privs
local function place_hook(pos, dir, player, pos1, pos2)
if player then
local switch_pos = {x=pos.x, y=pos.y, z=pos.z}
local meta = minetest.get_meta(switch_pos)
meta:set_int("running", 1)
-- set privs
fly_privs(pos, player, true)
-- place the player
pos.y = pos.y - 1
pos.x = pos.x + dir.x
pos.z = pos.z + dir.z
player:set_pos(pos)
meta:set_string("last_known_pos", minetest.pos_to_string(pos))
-- control player every second
minetest.after(1, control_player, switch_pos, pos1, pos2, player:get_player_name())
end
end
--##################################################################################################
--## Tower Crane
--##################################################################################################
local function turnright(dir)
local facedir = minetest.dir_to_facedir(dir)
return minetest.facedir_to_dir((facedir + 1) % 4)
@ -222,14 +84,29 @@ local function turnleft(dir)
return minetest.facedir_to_dir((facedir + 3) % 4)
end
----------------------------------------------------------------------------------------------------
-- pos is the base position
local function is_crane_running(pos)
local switch_pos = {x=pos.x, y=pos.y+1, z=pos.z}
return towercrane.is_crane_running(switch_pos)
end
local function get_crane_data(pos)
local meta = minetest.get_meta(pos)
local dir = S2P(meta:get_string("dir"))
local owner = meta:get_string("owner")
local height = meta:get_int("height")
local width = meta:get_int("width")
if dir and height > 0 and width > 0 and owner ~= "" then
return {dir = dir, height = height, width = width, owner = owner}
end
end
-- generic function for contruction and removement
----------------------------------------------------------------------------------------------------
local function crane_body_plan(pos, dir, height, width, clbk, tArg)
pos.y = pos.y + 1
clbk(pos, "towercrane:mast_ctrl_off", tArg)
for i = 1,height+1 do
for _ = 1,height+1 do
pos.y = pos.y + 1
clbk(pos, "towercrane:mast", tArg)
end
@ -258,102 +135,59 @@ local function crane_body_plan(pos, dir, height, width, clbk, tArg)
end
end
----------------------------------------------------------------------------------------------------
-- Check space are protection for mast and arm
----------------------------------------------------------------------------------------------------
-- Check space and protection for the crane
local function check_space(pos, dir, height, width, owner)
local remove = function(pos, node_name, tArg)
local check = function(pos, node_name, tArg)
if minetest.get_node(pos).name ~= "air" then
tArg.res = false
elseif minetest.is_protected(pos, tArg.owner) then
tArg.res = false
end
end
local tArg = {res = true, owner = owner}
crane_body_plan(pos, dir, height, width, remove, tArg)
crane_body_plan(table.copy(pos), dir, height, width, check, tArg)
return tArg.res
end
----------------------------------------------------------------------------------------------------
-- Constuct mast and arm
----------------------------------------------------------------------------------------------------
local function construct_crane(pos, dir, height, width, owner)
local function construct_crane(pos, dir, height, width)
local add = function(pos, node_name, tArg)
minetest.add_node(pos, {name=node_name, param2=minetest.dir_to_facedir(tArg.dir)})
minetest.add_node(pos, {
name = node_name,
param2 = minetest.dir_to_facedir(tArg.dir)})
end
local tArg = {dir = dir}
crane_body_plan(table.copy(pos), dir, height, width, add, tArg)
pos.y = pos.y + 1
local meta = minetest.get_meta(pos)
meta:set_string("dir", minetest.pos_to_string(dir))
meta:set_string("owner", owner)
meta:set_int("height", height or 0)
meta:set_int("width", width or 0)
end
----------------------------------------------------------------------------------------------------
-- Remove the crane
----------------------------------------------------------------------------------------------------
local function remove_crane(pos, dir, height, width)
local remove = function(pos, node_name, tArg)
if minetest.get_node(pos).name == node_name or
minetest.get_node(pos).name == "towercrane:mast_ctrl_on" then
local node = get_node_lvm(pos)
if node.name == node_name or node.name == "towercrane:mast_ctrl_on" then
minetest.remove_node(pos)
end
end
crane_body_plan(table.copy(pos), dir, height, width, remove, {})
end
----------------------------------------------------------------------------------------------------
-- Calculate and set the protection area (pos1, pos2)
----------------------------------------------------------------------------------------------------
local function protect_area(pos, dir, height, width, owner)
if not areas then return 0 end
-- pos1 = close/right/below
dir = turnright(dir)
dir = turnright(dir)
local pos1 = vector.add(pos, vector.multiply(dir, 2))
dir = turnleft(dir)
pos1 = vector.add(pos1, vector.multiply(dir, width/2))
dir = turnleft(dir)
pos1.y = pos.y - 2
-- pos2 = far/left/above
local pos2 = vector.add(pos1, vector.multiply(dir, width+2))
dir = turnleft(dir)
pos2 = vector.add(pos2, vector.multiply(dir, width))
pos2.y = pos.y + 2 + height
store_crane_data(owner, pos, pos1, pos2)
-- add area
local canAdd, errMsg = areas:canPlayerAddArea(pos1, pos2, owner)
if canAdd then
local id = areas:add(owner, "Construction site", pos1, pos2, nil)
areas:save()
return id
-- pos is the base position
local function is_my_crane(pos, player)
if minetest.check_player_privs(player, "server") then
return true
end
return nil
-- check protection
local player_name = player and player:get_player_name() or ""
if minetest.is_protected(pos, player_name) then
return false
end
-- check owner
local meta = minetest.get_meta(pos)
if not meta or player_name ~= meta:get_string("owner") then
return false
end
return true
end
----------------------------------------------------------------------------------------------------
-- Remove the protection area
----------------------------------------------------------------------------------------------------
local function remove_area(id, owner)
if not areas then return end
if areas:isAreaOwner(id, owner) then
areas:remove(id)
areas:save()
end
end
----------------------------------------------------------------------------------------------------
-- Check user input (height, width)
----------------------------------------------------------------------------------------------------
local function check_input(fields)
local size = string.split(fields.size, ",")
if #size == 2 then
@ -370,11 +204,42 @@ local function check_input(fields)
return 0, 0
end
----------------------------------------------------------------------------------------------------
-- Register Crane base
----------------------------------------------------------------------------------------------------
-- pos is the base position
function towercrane.get_crane_down(pos)
local data = get_crane_data(pos)
if data then
remove_crane(pos, data.dir, data.height, data.width)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formspec(data.height, data.width))
end
end
local function build_crane_up(pos, owner, height, width)
if height > 0 and width > 0 then
local meta = minetest.get_meta(pos)
local dir = S2P(meta:get_string("dir"))
if dir then
if check_space(pos, dir, height, width, owner) then
construct_crane(pos, dir, height, width)
meta:set_int("height", height)
meta:set_int("width", width)
meta:set_string("infotext", S("Owner")..": "..owner..
", "..S("Crane size")..": "..height..","..width)
meta:set_string("formspec", formspec(height, width))
else
chat(owner, S("Area is protected or too less space for the crane!"))
end
end
else
chat(owner, S("Invalid input!"))
end
end
-------------------------------------------------------------------------------
-- Nodes
-------------------------------------------------------------------------------
minetest.register_node("towercrane:base", {
description = "Tower Crane Base",
description = S("Tower Crane Base"),
inventory_image = "towercrane_invent.png",
tiles = {
"towercrane_base_top.png",
@ -387,7 +252,7 @@ minetest.register_node("towercrane:base", {
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
sounds = default.node_sound_stone_defaults(),
sounds = default.node_sound_metal_defaults(),
is_ground_content = false,
groups = {cracky=2},
@ -396,118 +261,53 @@ minetest.register_node("towercrane:base", {
local meta = minetest.get_meta(pos)
local owner = placer:get_player_name()
meta:set_string("owner", owner)
local formspec = "size[5,4]"..
"label[0,0;Construction area size]" ..
"field[1,1.5;3,1;size;height,width;]" ..
"button_exit[1,2;2,1;exit;Save]"
meta:set_string("formspec", formspec)
meta:set_string("formspec", formspec())
local fdir = minetest.dir_to_facedir(placer:get_look_dir(), false)
local dir = minetest.facedir_to_dir(fdir)
meta:set_string("dir", minetest.pos_to_string(dir))
meta:set_string("dir", P2S(dir))
end,
-- evaluate user input (height, width), destroyed old crane and build a new one with
-- evaluate user input (height, width),
-- destroy old crane and build a new one with
-- the given size
on_receive_fields = function(pos, formname, fields, player)
local switch_pos = {x=pos.x, y=pos.y+1, z=pos.z}
if fields.size == nil then
return
end
local meta = minetest.get_meta(switch_pos)
local running = meta:get_int("running")
if running == 1 then
if is_crane_running(pos) then
return
end
meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
local dir = minetest.string_to_pos(meta:get_string("dir"))
local height = meta:get_int("height")
local width = meta:get_int("width")
local id = meta:get_int("id")
if not player or not player:is_player() then
if not is_my_crane(pos, player) then
return
end
if player:get_player_name() ~= owner then
return
end
-- destroy area and crane
if dir ~= nil and height ~= nil and width ~= nil then
remove_crane_data(pos)
remove_area(id, owner)
remove_crane(table.copy(pos), dir, height, width)
end
-- evaluate user input
height, width = check_input(fields)
if height ~= 0 then
meta:set_int("height", height)
meta:set_int("width", width)
meta:set_string("infotext", "Owner: ".. owner ..", Crane size: " .. height .. "," .. width)
if no_area_violation(owner, pos) then
if dir ~= nil then
if check_space(table.copy(pos), dir, height, width, owner) then
-- add protection area
meta:set_int("id", protect_area(table.copy(pos), table.copy(dir), height, width, owner) or 0)
construct_crane(table.copy(pos), table.copy(dir), height, width, owner)
else
chat(owner, "area is protected or too less space to raise up the crane!")
end
end
else
chat(owner, "Too less distance to your other crane(s)!")
end
else
chat(owner, "Invalid input!")
end
-- destroy old crane
towercrane.get_crane_down(pos)
-- evaluate user input and build new
local height, width = check_input(fields)
build_crane_up(pos, player:get_player_name(), height, width)
end,
can_dig = function(pos, player)
local switch_pos = {x=pos.x, y=pos.y+1, z=pos.z}
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if player:get_player_name() ~= owner and
not minetest.check_player_privs(player:get_player_name(), "creative") then
if minetest.check_player_privs(player, "server") then
return true
end
if is_crane_running(pos) then
return false
end
meta = minetest.get_meta(switch_pos)
local running = meta:get_int("running")
if running == 1 then
if not is_my_crane(pos, player) then
return false
end
return true
end,
-- remove mast and arm if base gets destroyed
on_destruct = function(pos)
local meta = minetest.get_meta(pos)
local dir = minetest.string_to_pos(meta:get_string("dir"))
local height = meta:get_int("height")
local width = meta:get_int("width")
local id = meta:get_int("id")
local owner = meta:get_string("owner")
-- remove protection area
if id ~= nil then
remove_area(id, owner)
end
-- remove crane
if dir ~= nil and height ~= nil and width ~= nil then
remove_crane_data(pos)
remove_crane(pos, dir, height, width)
end
-- remove hook
local player = minetest.get_player_by_name(owner)
towercrane.get_crane_down(pos)
end,
})
----------------------------------------------------------------------------------------------------
-- Register Crane balance
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:balance", {
description = "Tower Crane Balance",
description = S("Tower Crane Balance"),
tiles = {
"towercrane_base.png",
"towercrane_base.png",
@ -523,11 +323,8 @@ minetest.register_node("towercrane:balance", {
groups = {crumbly=0, not_in_creative_inventory=1},
})
----------------------------------------------------------------------------------------------------
-- Register Crane mast
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:mast", {
description = "Tower Crane Mast",
description = S("Tower Crane Mast"),
drawtype = "glasslike_framed",
tiles = {
"towercrane_mast.png",
@ -544,150 +341,8 @@ minetest.register_node("towercrane:mast", {
groups = {crumbly=0, not_in_creative_inventory=1},
})
----------------------------------------------------------------------------------------------------
-- Register Crane Switch (on)
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:mast_ctrl_on", {
description = "Tower Crane Mast Ctrl On",
drawtype = "node",
tiles = {
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl_on.png",
"towercrane_mast_ctrl_on.png",
},
-- switch the crane OFF
on_rightclick = function (pos, node, clicker)
local meta = minetest.get_meta(pos)
if not clicker or not clicker:is_player() then
return
end
if clicker:get_player_name() ~= meta:get_string("owner") then
return
end
-- Check if this is the wrong crane
local spos = minetest.pos_to_string(pos)
if clicker:get_attribute("tower_crane_active") ~= nil
and clicker:get_attribute("tower_crane_active") ~= spos then
return
end
node.name = "towercrane:mast_ctrl_off"
minetest.swap_node(pos, node)
remove_hook(pos, clicker)
end,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Switch crane on/off")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
local owner = placer:get_player_name()
meta:set_string("owner", owner)
end,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly=0, not_in_creative_inventory=1},
})
----------------------------------------------------------------------------------------------------
-- Register Crane Switch (off)
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:mast_ctrl_off", {
description = "Tower Crane Mast Ctrl Off",
drawtype = "node",
tiles = {
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl.png",
"towercrane_mast_ctrl_off.png",
"towercrane_mast_ctrl_off.png",
},
-- switch the crane ON
on_rightclick = function (pos, node, clicker)
-- calculate the construction area, and place the hook
local meta = minetest.get_meta(pos)
-- only the owner is allowed to switch
if not clicker or not clicker:is_player() then
return
end
if clicker:get_player_name() ~= meta:get_string("owner") then
return
end
-- prevent handing over to the next crane
if clicker:get_attribute("tower_crane_active") ~= nil then
return
end
-- swap to the other node
node.name = "towercrane:mast_ctrl_on"
minetest.swap_node(pos, node)
local dir = minetest.string_to_pos(meta:get_string("dir"))
if pos ~= nil and dir ~= nil then
--
-- calculate the construction area dimension (pos1, pos2)
--
local height = meta:get_int("height")
local width = meta:get_int("width")
-- pos1 = close/right/below
dir = turnright(dir)
local pos1 = vector.add(pos, vector.multiply(dir, width/2))
dir = turnleft(dir)
pos1 = vector.add(pos1, vector.multiply(dir, 1))
pos1.y = pos.y - 2 + height - towercrane.rope_length
-- pos2 = far/left/above
local pos2 = vector.add(pos1, vector.multiply(dir, width-1))
dir = turnleft(dir)
pos2 = vector.add(pos2, vector.multiply(dir, width))
pos2.y = pos.y - 3 + height
-- normalize x/z so that pos2 > pos1
if pos2.x < pos1.x then
pos2.x, pos1.x = pos1.x, pos2.x
end
if pos2.z < pos1.z then
pos2.z, pos1.z = pos1.z, pos2.z
end
dir = minetest.string_to_pos(meta:get_string("dir"))
place_hook(pos, dir, clicker, pos1, pos2)
end
end,
on_construct = function(pos)
-- add infotext
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Switch crane on/off")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
-- store owner for dig protection
local meta = minetest.get_meta(pos)
local owner = placer:get_player_name()
meta:set_string("owner", owner)
end,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly=0, not_in_creative_inventory=1},
})
----------------------------------------------------------------------------------------------------
-- Register Crane arm 1
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:arm", {
description = "Tower Crane Arm",
description = S("Tower Crane Arm"),
drawtype = "glasslike_framed",
tiles = {
"towercrane_arm.png",
@ -704,11 +359,8 @@ minetest.register_node("towercrane:arm", {
groups = {crumbly=0, not_in_creative_inventory=1},
})
----------------------------------------------------------------------------------------------------
-- Register Crane arm 2
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:arm2", {
description = "Tower Crane Arm2",
description = S("Tower Crane Arm2"),
drawtype = "glasslike_framed",
tiles = {
"towercrane_arm2.png",
@ -725,10 +377,6 @@ minetest.register_node("towercrane:arm2", {
groups = {crumbly=0, not_in_creative_inventory=1},
})
----------------------------------------------------------------------------------------------------
-- Register Recipe
----------------------------------------------------------------------------------------------------
if towercrane.recipe then
minetest.register_craft({
output = "towercrane:base",
@ -740,25 +388,11 @@ if towercrane.recipe then
})
end
-- store standard player privs
minetest.register_on_joinplayer(function(player)
local privs = minetest.get_player_privs(player:get_player_name())
local physics = player:get_physics_override()
-- player still hanging on the crane?
if player:get_attribute("tower_crane_active") ~= nil then
fly_privs(nil, player, nil)
else
-- store the player privs default values
player:set_attribute("tower_crane_store_fast", minetest.serialize(privs["fast"]))
player:set_attribute("tower_crane_store_fly", minetest.serialize(privs["fly"]))
player:set_attribute("tower_crane_store_speed", minetest.serialize(physics.speed))
end
end)
-- switch back to normal player privs
minetest.register_on_leaveplayer(function(player, timed_out)
remove_hook(nil, player)
Currently_left_the_game = player:get_player_name()
end)
-------------------------------------------------------------------------------
-- export
-------------------------------------------------------------------------------
towercrane.turnright = turnright
towercrane.turnleft = turnleft
towercrane.is_my_crane = is_my_crane
towercrane.get_crane_data = get_crane_data