diff --git a/mods/capturetheflag/ctf/area.lua b/mods/capturetheflag/ctf/area.lua index 5d7a3f2..f5bf7e8 100644 --- a/mods/capturetheflag/ctf/area.lua +++ b/mods/capturetheflag/ctf/area.lua @@ -1,133 +1,33 @@ ctf.area = {} --- add a flag to a team -function ctf.area.add_flag(team,pos) - if not team or team == "" then - return - end - - if not ctf.team(team).flags then - ctf.team(team).flags = {} - end - - pos.team = team - table.insert(ctf.team(team).flags,pos) - ctf.save() -end - --- get a flag from a team -function ctf.area.get_flag(pos) - if not pos then - return - end - - local result = nil - for _, team in pairs(ctf.teams) do - for i = 1, #team.flags do - if ( - team.flags[i].x == pos.x and - team.flags[i].y == pos.y and - team.flags[i].z == pos.z - ) then - if result then - minetest.chat_send_all("[CTF ERROR] Multiple teams have same flag. Please report this to the server operator / admin") - print("CTF ERROR DATA") - print("Multiple teams have same flag.") - print("This is a sign of ctf.txt corruption.") - print("----------------") - print(dump(result)) - print(dump(team.flags[i])) - print("----------------") - else - result = team.flags[i] - end +function ctf.area.get_territory_owner(pos) + local largest = nil + local largest_weight = 0 + for i = 1, #ctf.registered_on_territory_query do + local team, weight = ctf.registered_on_territory_query[i](pos) + if team and weight then + if weight == -1 then + return team + end + if weight > largest_weight then + largest = team + largest_weight = weight end end end - return result -end - --- delete a flag from a team -function ctf.area.delete_flag(team, pos) - if not team or team == "" then - return - end - - for i = 1, #ctf.team(team).flags do - if ( - ctf.team(team).flags[i].x == pos.x and - ctf.team(team).flags[i].y == pos.y and - ctf.team(team).flags[i].z == pos.z - ) then - table.remove(ctf.team(team).flags,i) - return - end - end -end - --- Gets the nearest flag in a 25 metre radius block -function ctf.area.nearest_flag(pos) - if not pos then - ctf.error("No position provided to nearest_flag()") - return nil - end - - local nodes = minetest.find_nodes_in_area( - { - x = pos.x - ctf.setting("flag.protect_distance"), - y = pos.y - ctf.setting("flag.protect_distance"), - z = pos.z - ctf.setting("flag.protect_distance") - }, - { - x = pos.x + ctf.setting("flag.protect_distance"), - y = pos.y + ctf.setting("flag.protect_distance"), - z = pos.z + ctf.setting("flag.protect_distance") - }, - {"group:is_flag"} - ) - - if nodes then - local closest = nil - local _dis = 1000 - - for a = 1, #nodes do - local this_dis = vector.distance(pos, nodes[a]) - if this_dis < _dis then - closest = nodes[a] - _dis = this_dis - end - end - - return closest - end - - return nil -end - --- gets the name of the owner of that location -function ctf.area.get_area(pos) - local closest = ctf.area.nearest_flag(pos) - if not closest then - return nil - end - local flag = ctf.area.get_flag(closest) - - if flag then - return flag.team - end - return nil + return largest end -- updates the spawn position for a team function ctf.area.get_spawn(team) - ctf.area.asset_flags(team) + ctf_flag.asset_flags(team) if not ctf.team(team) then return nil end if ctf.team(team).spawn and minetest.env:get_node(ctf.team(team).spawn).name == "ctf:flag" then - local flag = ctf.area.get_flag(ctf.team(team).spawn) + local flag = ctf_flag.get(ctf.team(team).spawn) if not flag then return nil @@ -148,24 +48,6 @@ function ctf.area.get_spawn(team) end end -function ctf.area.asset_flags(team) - --[[ - if not team or not ctf.team(team) then - return false - end - - ctf.log("utils", "Checking the flags of "..team) - - local tmp = ctf.team(team).flags - local get_res = minetest.env:get_node(tmp[i]) - for i=1,#tmp do - if tmp[i] and (not get_res or not get_res.name == "ctf:flag") then - ctf.log("utils", "Replacing flag...") - -- TODO: ctf.area.asset_flags - end - end]]-- -end - minetest.register_on_respawnplayer(function(player) if player and ctf.player(player:get_player_name()) then local team = ctf.player(player:get_player_name()).team diff --git a/mods/capturetheflag/ctf/core.lua b/mods/capturetheflag/ctf/core.lua index fb3c35b..d787485 100644 --- a/mods/capturetheflag/ctf/core.lua +++ b/mods/capturetheflag/ctf/core.lua @@ -15,6 +15,17 @@ ctf.registered_on_new_team = {} function ctf.register_on_new_team(func) table.insert(ctf.registered_on_new_team, func) end +ctf.registered_on_territory_query = {} +function ctf.register_on_territory_query(func) + table.insert(ctf.registered_on_territory_query, func) +end + +function vector.distanceSQ(p1, p2) + local x = p1.x - p2.x + local y = p1.y - p2.y + local z = p1.z - p2.z + return x*x + y*y + z*z +end diff --git a/mods/capturetheflag/ctf_flag/flag_func.lua b/mods/capturetheflag/ctf_flag/flag_func.lua index 5468fae..af0d879 100644 --- a/mods/capturetheflag/ctf_flag/flag_func.lua +++ b/mods/capturetheflag/ctf_flag/flag_func.lua @@ -7,7 +7,7 @@ ctf_flag = { on_rightclick_top = function(pos, node, clicker) pos.y=pos.y-1 - local flag = ctf.area.get_flag(pos) + local flag = ctf_flag.get(pos) if not flag then return end @@ -26,7 +26,7 @@ ctf_flag = { ctf.gui.flag_board(clicker:get_player_name(),pos) end, on_rightclick = function(pos, node, clicker) - local flag = ctf.area.get_flag(pos) + local flag = ctf_flag.get(pos) if not flag then return end @@ -49,7 +49,7 @@ ctf_flag = { return end - local flag = ctf.area.get_flag(pos) + local flag = ctf_flag.get(pos) if not flag then return end @@ -111,11 +111,11 @@ ctf_flag = { end ctf.team(team).spawn = nil if ctf.setting("flag.allow_multiple") == true then - ctf.area.delete_flag(team,pos) - ctf.area.add_flag(ctf.player(player).team,pos) + ctf_flag.delete(team,pos) + ctf_flag.add(ctf.player(player).team,pos) else minetest.env:set_node(pos,{name="air"}) - ctf.area.delete_flag(team,pos) + ctf_flag.delete(team,pos) end end ctf.save() @@ -148,11 +148,11 @@ ctf_flag = { fteam.spawn = nil local fpos = {x=ctf.claimed[i].x,y=ctf.claimed[i].y,z=ctf.claimed[i].z} if ctf.setting("flag.allow_multiple") == true then - ctf.area.delete_flag(fteam.data.name,fpos) - ctf.area.add_flag(ctf.claimed[i].claimed.team,fpos) + ctf_flag.delete(fteam.data.name,fpos) + ctf_flag.add(ctf.claimed[i].claimed.team,fpos) else minetest.env:set_node(fpos,{name="air"}) - ctf.area.delete_flag(fteam.data.name,fpos) + ctf_flag.delete(fteam.data.name,fpos) end ctf.collect_claimed() end @@ -178,7 +178,7 @@ ctf_flag = { meta:set_string("infotext", team.."'s flag") -- add flag - ctf.area.add_flag(team,pos) + ctf_flag.add(team, pos) if ctf.teams[team].spawn and minetest.env:get_node(ctf.teams[team].spawn).name == "ctf_flag:flag" then if not ctf.setting("flag.allow_multiple") then @@ -199,23 +199,23 @@ ctf_flag = { ctf.save() local pos2 = { - x=pos.x, - y=pos.y+1, - z=pos.z - } + x = pos.x, + y = pos.y+1, + z = pos.z + } if not ctf.team(team).data.color then ctf.team(team).data.color = "red" ctf.save() end - minetest.env:set_node(pos2,{name="ctf_flag:flag_top_"..ctf.team(team).data.color}) + minetest.env:set_node(pos2, {name="ctf_flag:flag_top_"..ctf.team(team).data.color}) local meta2 = minetest.env:get_meta(pos2) meta2:set_string("infotext", team.."'s flag") else - minetest.chat_send_player(placer:get_player_name(),"You are not part of a team!") + minetest.chat_send_player(placer:get_player_name(), "You are not part of a team!") minetest.env:set_node(pos,{name="air"}) end end diff --git a/mods/capturetheflag/ctf_flag/gui.lua b/mods/capturetheflag/ctf_flag/gui.lua index 7ca33d2..bd0d6bb 100644 --- a/mods/capturetheflag/ctf_flag/gui.lua +++ b/mods/capturetheflag/ctf_flag/gui.lua @@ -70,7 +70,7 @@ end) -- Flag interface function ctf.gui.flag_board(name,pos) ctf.log("gui", name .. " views flag board") - local flag = ctf.area.get_flag(pos) + local flag = ctf_flag.get(pos) if not flag then return end @@ -123,7 +123,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end if fields.save and fields.flag_name then - local flag = ctf.area.get_flag(ctf.gui.flag_data[name].pos) + local flag = ctf_flag.get(ctf.gui.flag_data[name].pos) if not flag then return false end @@ -156,7 +156,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) elseif fields.delete then local pos = ctf.gui.flag_data[name].pos - local flag = ctf.area.get_flag(ctf.gui.flag_data[name].pos) + local flag = ctf_flag.get(ctf.gui.flag_data[name].pos) if not flag then return @@ -171,7 +171,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) return false end - ctf.area.delete_flag(team,pos) + ctf_flag.delete(team,pos) minetest.env:set_node(pos,{name="air"}) pos.y=pos.y+1 diff --git a/mods/capturetheflag/ctf_flag/init.lua b/mods/capturetheflag/ctf_flag/init.lua index f9d6044..de430c9 100644 --- a/mods/capturetheflag/ctf_flag/init.lua +++ b/mods/capturetheflag/ctf_flag/init.lua @@ -9,10 +9,113 @@ init() ctf.register_on_new_team(function(team) team.flags = {} end) +ctf.register_on_territory_query(function(pos) + local closest = nil + local closest_team = nil + local closest_distSQ = 1000000 + local pd = ctf.setting("flag.protect_distance") + local pdSQ = pd * pd + + for tname, team in pairs(ctf.teams) do + for i = 1, #team.flags do + local distSQ = vector.distanceSQ(pos, team.flags[i]) + if distSQ < pdSQ and distSQ < closest_distSQ then + closest = team.flags[i] + closest_team = tname + closest_distSQ = distSQ + end + end + end + + return closest_team, closest_distSQ +end) ctf_flag = {} dofile(minetest.get_modpath("ctf_flag") .. "/gui.lua") dofile(minetest.get_modpath("ctf_flag") .. "/flag_func.lua") +-- add a flag to a team +function ctf_flag.add(team, pos) + if not team or team == "" then + return + end + + if not ctf.team(team).flags then + ctf.team(team).flags = {} + end + + pos.team = team + table.insert(ctf.team(team).flags,pos) + ctf.save() +end + +-- get a flag from a team +function ctf_flag.get(pos) + if not pos then + return + end + + local result = nil + for _, team in pairs(ctf.teams) do + for i = 1, #team.flags do + if ( + team.flags[i].x == pos.x and + team.flags[i].y == pos.y and + team.flags[i].z == pos.z + ) then + if result then + minetest.chat_send_all("[CTF ERROR] Multiple teams have same flag. Please report this to the server operator / admin") + print("CTF ERROR DATA") + print("Multiple teams have same flag.") + print("This is a sign of ctf.txt corruption.") + print("----------------") + print(dump(result)) + print(dump(team.flags[i])) + print("----------------") + else + result = team.flags[i] + end + end + end + end + return result +end + +-- delete a flag from a team +function ctf_flag.delete(team, pos) + if not team or team == "" then + return + end + + for i = 1, #ctf.team(team).flags do + if ( + ctf.team(team).flags[i].x == pos.x and + ctf.team(team).flags[i].y == pos.y and + ctf.team(team).flags[i].z == pos.z + ) then + table.remove(ctf.team(team).flags,i) + return + end + end +end + +function ctf_flag.asset_flags(team) + --[[ + if not team or not ctf.team(team) then + return false + end + + ctf.log("utils", "Checking the flags of "..team) + + local tmp = ctf.team(team).flags + local get_res = minetest.env:get_node(tmp[i]) + for i=1,#tmp do + if tmp[i] and (not get_res or not get_res.name == "ctf:flag") then + ctf.log("utils", "Replacing flag...") + -- TODO: ctf_flag.asset_flags + end + end]]-- +end + -- The flag minetest.register_node("ctf_flag:flag", { description = "Flag", @@ -108,7 +211,7 @@ minetest.register_abm({ return end - local flag_team_data = ctf.area.get_flag(pos) + local flag_team_data = ctf_flag.get(pos) if not flag_team_data or not ctf.team(flag_team_data.team)then ctf.log("flag", "Flag does not exist! Deleting nodes. "..dump(pos)) minetest.env:set_node(pos,{name="air"}) diff --git a/mods/capturetheflag/ctf_protect/init.lua b/mods/capturetheflag/ctf_protect/init.lua index bcc1027..40624dc 100644 --- a/mods/capturetheflag/ctf_protect/init.lua +++ b/mods/capturetheflag/ctf_protect/init.lua @@ -2,18 +2,16 @@ local old_is_protected = minetest.is_protected function minetest.is_protected(pos, name) - local team = ctf.area.get_area(pos) + local team = ctf.area.get_territory_owner(pos) - if not team then + if not team or not ctf.team(team) then return old_is_protected(pos, name) end - if ctf.players and ctf.player(name) and ctf.player(name).team then - if ctf.player(name).team == team then - return old_is_protected(pos, name) - end + if ctf.player(name).team == team then + return old_is_protected(pos, name) + else + minetest.chat_send_player(name, "You cannot dig on team "..team.."'s land") + return true end - - minetest.chat_send_player(name, "You cannot dig on team "..team.."'s land") - return true end diff --git a/mods/capturetheflag/ctf_turret/init.lua b/mods/capturetheflag/ctf_turret/init.lua index 2e53d95..099e53f 100644 --- a/mods/capturetheflag/ctf_turret/init.lua +++ b/mods/capturetheflag/ctf_turret/init.lua @@ -60,7 +60,7 @@ if ctf.setting("turrets") then return end - local app = ctf.area.get_area(pos) + local app = ctf.area.get_territory_owner(pos) if app and app~=team then team = app meta:set_string("team",team)