diff --git a/README.md b/README.md index 63aee09..ef01776 100644 --- a/README.md +++ b/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 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 diff --git a/depends.txt b/depends.txt index 0c9f73e..4ad96d5 100644 --- a/depends.txt +++ b/depends.txt @@ -1,2 +1 @@ default -areas? \ No newline at end of file diff --git a/init.lua b/init.lua index b6be54c..c39a32f 100644 --- a/init.lua +++ b/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 - end - end +local function get_node_lvm(pos) + local node = minetest.get_node_or_nil(pos) + if node then + return node 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