mirror of
https://github.com/minetest-mods/towercrane.git
synced 2024-11-22 15:23:51 +01:00
v2.0 Completely restructured, protection areas removed
This commit is contained in:
parent
5f692ee6c4
commit
045ffd4f77
30
README.md
30
README.md
@ -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
676
init.lua
@ -3,215 +3,77 @@
|
|||||||
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
|
|
||||||
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
|
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)
|
||||||
return minetest.facedir_to_dir((facedir + 1) % 4)
|
return minetest.facedir_to_dir((facedir + 1) % 4)
|
||||||
@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user