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 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 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) ![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. * Place the crane base block.
The crane arm will later be build in the same direction you are currently looking 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. 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 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. 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. * 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. * 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 ## Dependencies
default default
areas (optional)
# License # 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 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 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 default
areas?

676
init.lua

@ -3,214 +3,76 @@
Tower Crane Mod Tower Crane Mod
=============== ===============
v1.0 by JoSt Copyright (C) 2017-2019 Joachim Stolberg
Copyright (C) 2017-2018 Joachim Stolberg
LGPLv2.1+ LGPLv2.1+
See LICENSE.txt for more information 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 -- crane minimum size
MIN_SIZE = 8 local MIN_SIZE = 8
towercrane = {} 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) local function chat(owner, text)
if owner ~= nil then if owner ~= nil then
minetest.chat_send_player(owner, "[Tower Crane] "..text) minetest.chat_send_player(owner, "[Tower Crane] "..text)
end end
end end
-- To prevent race condition crashes local function formspec(height, width)
local Currently_left_the_game = nil local text = ""
if height and width then
--################################################################################################## text = height..","..width
--## Construction Area end
--################################################################################################## return "size[5,4]"..
"label[0,0;"..S("Construction area size").."]" ..
-- Areas = { "field[1,1.5;3,1;size;height,width;"..text.."]" ..
-- pos_key = {owner="...", pos1=pos, pos2=pos}, "button_exit[1,2;2,1;exit;"..S("Build").."]"
-- }
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))
end end
minetest.register_on_shutdown(function() local function get_node_lvm(pos)
update_mod_storage() local node = minetest.get_node_or_nil(pos)
end) if node then
return node
----------------------------------------------------------------------------------------------------
-- 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
end end
local vm = minetest.get_voxel_manip()
local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
local data = vm:get_data()
local param2_data = vm:get_param2_data()
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
local idx = area:indexp(pos)
node = {
name = minetest.get_name_from_content_id(data[idx]),
param2 = param2_data[idx]
}
return node
end end
end
return res
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 function turnright(dir)
local facedir = minetest.dir_to_facedir(dir) local facedir = minetest.dir_to_facedir(dir)
@ -222,14 +84,29 @@ local function turnleft(dir)
return minetest.facedir_to_dir((facedir + 3) % 4) return minetest.facedir_to_dir((facedir + 3) % 4)
end 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 -- generic function for contruction and removement
----------------------------------------------------------------------------------------------------
local function crane_body_plan(pos, dir, height, width, clbk, tArg) local function crane_body_plan(pos, dir, height, width, clbk, tArg)
pos.y = pos.y + 1 pos.y = pos.y + 1
clbk(pos, "towercrane:mast_ctrl_off", tArg) clbk(pos, "towercrane:mast_ctrl_off", tArg)
for i = 1,height+1 do for _ = 1,height+1 do
pos.y = pos.y + 1 pos.y = pos.y + 1
clbk(pos, "towercrane:mast", tArg) clbk(pos, "towercrane:mast", tArg)
end end
@ -258,102 +135,59 @@ local function crane_body_plan(pos, dir, height, width, clbk, tArg)
end end
end end
---------------------------------------------------------------------------------------------------- -- Check space and protection for the crane
-- Check space are protection for mast and arm
----------------------------------------------------------------------------------------------------
local function check_space(pos, dir, height, width, owner) 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 if minetest.get_node(pos).name ~= "air" then
tArg.res = false tArg.res = false
elseif minetest.is_protected(pos, tArg.owner) then elseif minetest.is_protected(pos, tArg.owner) then
tArg.res = false tArg.res = false
end end
end end
local tArg = {res = true, owner = owner} 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 return tArg.res
end end
---------------------------------------------------------------------------------------------------- local function construct_crane(pos, dir, height, width)
-- Constuct mast and arm
----------------------------------------------------------------------------------------------------
local function construct_crane(pos, dir, height, width, owner)
local add = function(pos, node_name, tArg) 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 end
local tArg = {dir = dir} local tArg = {dir = dir}
crane_body_plan(table.copy(pos), dir, height, width, add, tArg) 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 end
----------------------------------------------------------------------------------------------------
-- Remove the crane
----------------------------------------------------------------------------------------------------
local function remove_crane(pos, dir, height, width) local function remove_crane(pos, dir, height, width)
local remove = function(pos, node_name, tArg) local remove = function(pos, node_name, tArg)
if minetest.get_node(pos).name == node_name or local node = get_node_lvm(pos)
minetest.get_node(pos).name == "towercrane:mast_ctrl_on" then if node.name == node_name or node.name == "towercrane:mast_ctrl_on" then
minetest.remove_node(pos) minetest.remove_node(pos)
end end
end end
crane_body_plan(table.copy(pos), dir, height, width, remove, {}) crane_body_plan(table.copy(pos), dir, height, width, remove, {})
end end
---------------------------------------------------------------------------------------------------- -- pos is the base position
-- Calculate and set the protection area (pos1, pos2) local function is_my_crane(pos, player)
---------------------------------------------------------------------------------------------------- if minetest.check_player_privs(player, "server") then
local function protect_area(pos, dir, height, width, owner) return true
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
end 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 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) -- Check user input (height, width)
----------------------------------------------------------------------------------------------------
local function check_input(fields) local function check_input(fields)
local size = string.split(fields.size, ",") local size = string.split(fields.size, ",")
if #size == 2 then if #size == 2 then
@ -370,11 +204,42 @@ local function check_input(fields)
return 0, 0 return 0, 0
end end
---------------------------------------------------------------------------------------------------- -- pos is the base position
-- Register Crane base 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", { minetest.register_node("towercrane:base", {
description = "Tower Crane Base", description = S("Tower Crane Base"),
inventory_image = "towercrane_invent.png", inventory_image = "towercrane_invent.png",
tiles = { tiles = {
"towercrane_base_top.png", "towercrane_base_top.png",
@ -387,7 +252,7 @@ minetest.register_node("towercrane:base", {
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
sunlight_propagates = true, sunlight_propagates = true,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_metal_defaults(),
is_ground_content = false, is_ground_content = false,
groups = {cracky=2}, groups = {cracky=2},
@ -396,118 +261,53 @@ minetest.register_node("towercrane:base", {
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local owner = placer:get_player_name() local owner = placer:get_player_name()
meta:set_string("owner", owner) meta:set_string("owner", owner)
local formspec = "size[5,4]".. meta:set_string("formspec", formspec())
"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)
local fdir = minetest.dir_to_facedir(placer:get_look_dir(), false) local fdir = minetest.dir_to_facedir(placer:get_look_dir(), false)
local dir = minetest.facedir_to_dir(fdir) local dir = minetest.facedir_to_dir(fdir)
meta:set_string("dir", minetest.pos_to_string(dir)) meta:set_string("dir", P2S(dir))
end, 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 -- the given size
on_receive_fields = function(pos, formname, fields, player) 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 if fields.size == nil then
return return
end end
local meta = minetest.get_meta(switch_pos) if is_crane_running(pos) then
local running = meta:get_int("running")
if running == 1 then
return return
end end
if not is_my_crane(pos, player) then
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
return return
end end
if player:get_player_name() ~= owner then -- destroy old crane
return towercrane.get_crane_down(pos)
end -- evaluate user input and build new
-- destroy area and crane local height, width = check_input(fields)
if dir ~= nil and height ~= nil and width ~= nil then build_crane_up(pos, player:get_player_name(), height, width)
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
end, end,
can_dig = function(pos, player) can_dig = function(pos, player)
local switch_pos = {x=pos.x, y=pos.y+1, z=pos.z} if minetest.check_player_privs(player, "server") then
local meta = minetest.get_meta(pos) return true
local owner = meta:get_string("owner") end
if player:get_player_name() ~= owner and if is_crane_running(pos) then
not minetest.check_player_privs(player:get_player_name(), "creative") then
return false return false
end end
meta = minetest.get_meta(switch_pos) if not is_my_crane(pos, player) then
local running = meta:get_int("running")
if running == 1 then
return false return false
end end
return true return true
end, end,
-- remove mast and arm if base gets destroyed
on_destruct = function(pos) on_destruct = function(pos)
local meta = minetest.get_meta(pos) towercrane.get_crane_down(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)
end, end,
}) })
----------------------------------------------------------------------------------------------------
-- Register Crane balance
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:balance", { minetest.register_node("towercrane:balance", {
description = "Tower Crane Balance", description = S("Tower Crane Balance"),
tiles = { tiles = {
"towercrane_base.png", "towercrane_base.png",
"towercrane_base.png", "towercrane_base.png",
@ -523,11 +323,8 @@ minetest.register_node("towercrane:balance", {
groups = {crumbly=0, not_in_creative_inventory=1}, groups = {crumbly=0, not_in_creative_inventory=1},
}) })
----------------------------------------------------------------------------------------------------
-- Register Crane mast
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:mast", { minetest.register_node("towercrane:mast", {
description = "Tower Crane Mast", description = S("Tower Crane Mast"),
drawtype = "glasslike_framed", drawtype = "glasslike_framed",
tiles = { tiles = {
"towercrane_mast.png", "towercrane_mast.png",
@ -544,150 +341,8 @@ minetest.register_node("towercrane:mast", {
groups = {crumbly=0, not_in_creative_inventory=1}, 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", { minetest.register_node("towercrane:arm", {
description = "Tower Crane Arm", description = S("Tower Crane Arm"),
drawtype = "glasslike_framed", drawtype = "glasslike_framed",
tiles = { tiles = {
"towercrane_arm.png", "towercrane_arm.png",
@ -704,11 +359,8 @@ minetest.register_node("towercrane:arm", {
groups = {crumbly=0, not_in_creative_inventory=1}, groups = {crumbly=0, not_in_creative_inventory=1},
}) })
----------------------------------------------------------------------------------------------------
-- Register Crane arm 2
----------------------------------------------------------------------------------------------------
minetest.register_node("towercrane:arm2", { minetest.register_node("towercrane:arm2", {
description = "Tower Crane Arm2", description = S("Tower Crane Arm2"),
drawtype = "glasslike_framed", drawtype = "glasslike_framed",
tiles = { tiles = {
"towercrane_arm2.png", "towercrane_arm2.png",
@ -725,10 +377,6 @@ minetest.register_node("towercrane:arm2", {
groups = {crumbly=0, not_in_creative_inventory=1}, groups = {crumbly=0, not_in_creative_inventory=1},
}) })
----------------------------------------------------------------------------------------------------
-- Register Recipe
----------------------------------------------------------------------------------------------------
if towercrane.recipe then if towercrane.recipe then
minetest.register_craft({ minetest.register_craft({
output = "towercrane:base", output = "towercrane:base",
@ -740,25 +388,11 @@ if towercrane.recipe then
}) })
end end
-- store standard player privs -------------------------------------------------------------------------------
minetest.register_on_joinplayer(function(player) -- export
local privs = minetest.get_player_privs(player:get_player_name()) -------------------------------------------------------------------------------
local physics = player:get_physics_override() towercrane.turnright = turnright
-- player still hanging on the crane? towercrane.turnleft = turnleft
if player:get_attribute("tower_crane_active") ~= nil then towercrane.is_my_crane = is_my_crane
fly_privs(nil, player, nil) towercrane.get_crane_data = get_crane_data
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)