Add ctf_pvp_engine mods directly in the repo
242
mods/ctf_pvp_engine/ctf_flag/api.lua
Normal file
|
@ -0,0 +1,242 @@
|
|||
ctf_flag.registered_on_capture = {}
|
||||
function ctf_flag.register_on_capture(func)
|
||||
if ctf._mt_loaded then
|
||||
error("You can't register callbacks at game time!")
|
||||
end
|
||||
table.insert(ctf_flag.registered_on_capture, func)
|
||||
end
|
||||
|
||||
ctf_flag.registered_on_pick_up = {}
|
||||
function ctf_flag.register_on_pick_up(func)
|
||||
if ctf._mt_loaded then
|
||||
error("You can't register callbacks at game time!")
|
||||
end
|
||||
table.insert(ctf_flag.registered_on_pick_up, func)
|
||||
end
|
||||
|
||||
ctf_flag.registered_on_drop = {}
|
||||
function ctf_flag.register_on_drop(func)
|
||||
if ctf._mt_loaded then
|
||||
error("You can't register callbacks at game time!")
|
||||
end
|
||||
table.insert(ctf_flag.registered_on_drop, func)
|
||||
end
|
||||
|
||||
ctf_flag.registered_on_precapture = {}
|
||||
function ctf_flag.register_on_precapture(func)
|
||||
if ctf._mt_loaded then
|
||||
error("You can't register callbacks at game time!")
|
||||
end
|
||||
table.insert(ctf_flag.registered_on_precapture, func)
|
||||
end
|
||||
|
||||
ctf_flag.registered_on_prepick_up = {}
|
||||
function ctf_flag.register_on_prepick_up(func)
|
||||
if ctf._mt_loaded then
|
||||
error("You can't register callbacks at game time!")
|
||||
end
|
||||
table.insert(ctf_flag.registered_on_prepick_up, func)
|
||||
end
|
||||
|
||||
function ctf_flag.collect_claimed()
|
||||
local claimed = {}
|
||||
for _, team in pairs(ctf.teams) do
|
||||
for i = 1, #team.flags do
|
||||
if team.flags[i].claimed then
|
||||
table.insert(claimed, team.flags[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
return claimed
|
||||
end
|
||||
|
||||
function ctf_flag.get_claimed_by_player(name)
|
||||
local claimed = ctf_flag.collect_claimed()
|
||||
for _, flag in pairs(claimed) do
|
||||
if flag.claimed.player == name then
|
||||
return name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ctf_flag.player_drop_flag(name)
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
|
||||
local claimed = ctf_flag.collect_claimed()
|
||||
for i = 1, #claimed do
|
||||
local flag = claimed[i]
|
||||
if flag.claimed.player == name then
|
||||
flag.claimed = nil
|
||||
|
||||
local flag_name = ""
|
||||
if flag.name then
|
||||
flag_name = flag.name .. " "
|
||||
end
|
||||
flag_name = flag.team .. "'s " .. flag_name .. "flag"
|
||||
|
||||
ctf.hud.updateAll()
|
||||
|
||||
ctf.action("flag", name .. " dropped " .. flag_name)
|
||||
minetest.chat_send_all(flag_name.." has returned.")
|
||||
|
||||
for i = 1, #ctf_flag.registered_on_drop do
|
||||
ctf_flag.registered_on_drop[i](name, flag)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add a flag to a team
|
||||
function ctf_flag.add(team, pos)
|
||||
if not team or team == "" then
|
||||
return
|
||||
end
|
||||
|
||||
ctf.log("flag", "Adding flag to " .. team .. " at (" .. pos.x ..
|
||||
", " .. pos.y .. ", " .. pos.z .. ")")
|
||||
|
||||
if not ctf.team(team).flags then
|
||||
ctf.team(team).flags = {}
|
||||
end
|
||||
|
||||
pos.team = team
|
||||
table.insert(ctf.team(team).flags,pos)
|
||||
ctf.needs_save = true
|
||||
end
|
||||
|
||||
function ctf_flag.update(pos)
|
||||
if minetest.get_node(pos).name ~= "ctf_flag:flag" then
|
||||
return
|
||||
end
|
||||
|
||||
local top = {x=pos.x,y=pos.y+1,z=pos.z}
|
||||
local flagmeta = minetest.get_meta(pos)
|
||||
|
||||
if not flagmeta then
|
||||
return
|
||||
end
|
||||
|
||||
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.set_node(pos,{name="air"})
|
||||
minetest.set_node(top,{name="air"})
|
||||
return
|
||||
end
|
||||
local topmeta = minetest.get_meta(top)
|
||||
local flag_name = flag_team_data.name
|
||||
if flag_name and flag_name ~= "" then
|
||||
flagmeta:set_string("infotext", flag_name.." - "..flag_team_data.team)
|
||||
else
|
||||
flagmeta:set_string("infotext", flag_team_data.team.."'s flag")
|
||||
end
|
||||
|
||||
if not ctf.team(flag_team_data.team).data.color then
|
||||
ctf.team(flag_team_data.team).data.color = "red"
|
||||
ctf.needs_save = true
|
||||
end
|
||||
|
||||
if flag_team_data.claimed then
|
||||
minetest.set_node(top,{name="ctf_flag:flag_captured_top"})
|
||||
else
|
||||
minetest.set_node(top,{name="ctf_flag:flag_top_"..ctf.team(flag_team_data.team).data.color})
|
||||
end
|
||||
|
||||
topmeta = minetest.get_meta(top)
|
||||
if flag_name and flag_name ~= "" then
|
||||
topmeta:set_string("infotext", flag_name.." - "..flag_team_data.team)
|
||||
else
|
||||
topmeta:set_string("infotext", flag_team_data.team.."'s flag")
|
||||
end
|
||||
end
|
||||
|
||||
function ctf_flag.flag_tick(pos)
|
||||
ctf_flag.update(pos)
|
||||
minetest.get_node_timer(pos):start(5)
|
||||
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
|
||||
|
||||
ctf.log("flag", "Deleting flag from " .. team .. " at (" .. pos.x ..
|
||||
", " .. pos.y .. ", " .. pos.z .. ")")
|
||||
|
||||
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.assert_flag(flag)
|
||||
minetest.get_voxel_manip(flag, { x = flag.x + 1, y = flag.y + 1, z = flag.z + 1})
|
||||
local nodename = minetest.get_node(flag).name
|
||||
if nodename ~= "ctf_flag:flag" then
|
||||
ctf.log("flag", flag.team .. " has wrong node at flag position, " .. nodename .. ", correcting...")
|
||||
minetest.set_node(flag, { name = "ctf_flag:flag"})
|
||||
ctf_flag.update(flag)
|
||||
end
|
||||
end
|
||||
|
||||
function ctf_flag.assert_flags()
|
||||
for tname, team in pairs(ctf.teams) do
|
||||
ctf_flag.assert_flags_team(tname)
|
||||
end
|
||||
end
|
||||
|
||||
function ctf_flag.assert_flags_team(tname)
|
||||
local team = ctf.team(tname)
|
||||
if not tname or not team then
|
||||
return false
|
||||
end
|
||||
|
||||
if not team.flags then
|
||||
team.flags = {}
|
||||
end
|
||||
|
||||
for i=1, #team.flags do
|
||||
ctf_flag.assert_flag(team.flags[i])
|
||||
end
|
||||
end
|
3
mods/ctf_pvp_engine/ctf_flag/depends.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
ctf
|
||||
ctf_colors
|
||||
chatplus?
|
253
mods/ctf_pvp_engine/ctf_flag/flag_func.lua
Normal file
|
@ -0,0 +1,253 @@
|
|||
local function do_capture(attname, flag, returned)
|
||||
local team = flag.team
|
||||
local attacker = ctf.player(attname)
|
||||
|
||||
local flag_name = ""
|
||||
if flag.name then
|
||||
flag_name = flag.name .. " "
|
||||
end
|
||||
flag_name = team .. "'s " .. flag_name .. "flag"
|
||||
|
||||
|
||||
if ctf.setting("flag.capture_take") and not returned then
|
||||
for i = 1, #ctf_flag.registered_on_prepick_up do
|
||||
if not ctf_flag.registered_on_prepick_up[i](attname, flag) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
minetest.chat_send_all(flag_name.." has been picked up by "..
|
||||
attname.." (team "..attacker.team..")")
|
||||
|
||||
ctf.action("flag", attname .. " picked up " .. flag_name)
|
||||
|
||||
-- Post to flag owner's board
|
||||
ctf.post(team, {
|
||||
msg = flag_name .. " has been taken by " .. attname .. " of ".. attacker.team,
|
||||
icon="flag_red" })
|
||||
|
||||
-- Post to attacker's board
|
||||
ctf.post(attacker.team, {
|
||||
msg = attname .. " snatched '" .. flag_name .. "' from " .. team,
|
||||
icon="flag_green"})
|
||||
|
||||
-- Add to claimed list
|
||||
flag.claimed = {
|
||||
team = attacker.team,
|
||||
player = attname
|
||||
}
|
||||
|
||||
ctf.hud.updateAll()
|
||||
|
||||
ctf_flag.update(flag)
|
||||
|
||||
for i = 1, #ctf_flag.registered_on_pick_up do
|
||||
ctf_flag.registered_on_pick_up[i](attname, flag)
|
||||
end
|
||||
else
|
||||
for i = 1, #ctf_flag.registered_on_precapture do
|
||||
if not ctf_flag.registered_on_precapture[i](attname, flag) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
minetest.chat_send_all(flag_name.." has been captured "..
|
||||
" by "..attname.." (team "..attacker.team..")")
|
||||
|
||||
ctf.action("flag", attname .. " captured " .. flag_name)
|
||||
|
||||
-- Post to flag owner's board
|
||||
ctf.post(team, {
|
||||
msg = flag_name .. " has been captured by " .. attacker.team,
|
||||
icon="flag_red"})
|
||||
|
||||
-- Post to attacker's board
|
||||
ctf.post(attacker.team, {
|
||||
msg = attname .. " captured '" .. flag_name .. "' from " .. team,
|
||||
icon="flag_green"})
|
||||
|
||||
-- Take flag
|
||||
if ctf.setting("flag.allow_multiple") then
|
||||
ctf_flag.delete(team, vector.new(flag))
|
||||
ctf_flag.add(attacker.team, vector.new(flag))
|
||||
else
|
||||
minetest.set_node(pos,{name="air"})
|
||||
ctf_flag.delete(team,pos)
|
||||
end
|
||||
|
||||
for i = 1, #ctf_flag.registered_on_capture do
|
||||
ctf_flag.registered_on_capture[i](attname, flag)
|
||||
end
|
||||
end
|
||||
|
||||
ctf.needs_save = true
|
||||
end
|
||||
|
||||
local function player_drop_flag(player)
|
||||
return ctf_flag.player_drop_flag(player:get_player_name())
|
||||
end
|
||||
minetest.register_on_dieplayer(player_drop_flag)
|
||||
minetest.register_on_leaveplayer(player_drop_flag)
|
||||
|
||||
|
||||
ctf_flag = {
|
||||
on_punch_top = function(pos, node, puncher)
|
||||
pos.y = pos.y - 1
|
||||
ctf_flag.on_punch(pos, node, puncher)
|
||||
end,
|
||||
on_rightclick_top = function(pos, node, clicker)
|
||||
pos.y = pos.y - 1
|
||||
ctf_flag.on_rightclick(pos, node, clicker)
|
||||
end,
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
local name = clicker:get_player_name()
|
||||
local flag = ctf_flag.get(pos)
|
||||
if not flag then
|
||||
return
|
||||
end
|
||||
|
||||
if flag.claimed then
|
||||
if ctf.setting("flag.capture_take") then
|
||||
minetest.chat_send_player(name, "This flag has been taken by "..flag.claimed.player)
|
||||
minetest.chat_send_player(name, "who is a member of team "..flag.claimed.team)
|
||||
return
|
||||
else
|
||||
minetest.chat_send_player(name, "Oops! This flag should not be captured. Reverting...")
|
||||
flag.claimed = nil
|
||||
end
|
||||
end
|
||||
ctf.gui.flag_board(name, pos)
|
||||
end,
|
||||
on_punch = function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
if not puncher or not name then
|
||||
return
|
||||
end
|
||||
|
||||
local flag = ctf_flag.get(pos)
|
||||
if not flag then
|
||||
return
|
||||
end
|
||||
|
||||
if flag.claimed then
|
||||
if ctf.setting("flag.capture_take") then
|
||||
minetest.chat_send_player(name, "This flag has been taken by " .. flag.claimed.player)
|
||||
minetest.chat_send_player(name, "who is a member of team " .. flag.claimed.team)
|
||||
return
|
||||
else
|
||||
minetest.chat_send_player(name, "Oops! This flag should not be captured. Reverting.")
|
||||
flag.claimed = nil
|
||||
end
|
||||
end
|
||||
|
||||
local team = flag.team
|
||||
if not team then
|
||||
return
|
||||
end
|
||||
|
||||
if ctf.team(team) and ctf.player(name).team then
|
||||
if ctf.player(name).team == team then
|
||||
-- Clicking on their team's flag
|
||||
if ctf.setting("flag.capture_take") then
|
||||
ctf_flag._flagret(name)
|
||||
end
|
||||
else
|
||||
-- Clicked on another team's flag
|
||||
local diplo = ctf.diplo.get(team, ctf.player(name).team) or
|
||||
ctf.setting("default_diplo_state")
|
||||
|
||||
if diplo ~= "war" then
|
||||
minetest.chat_send_player(name, "You are at peace with this team!")
|
||||
return
|
||||
end
|
||||
|
||||
do_capture(name, flag)
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(name, "You are not part of a team!")
|
||||
end
|
||||
end,
|
||||
_flagret = function(name)
|
||||
local claimed = ctf_flag.collect_claimed()
|
||||
for i = 1, #claimed do
|
||||
local flag = claimed[i]
|
||||
if flag.claimed.player == name then
|
||||
do_capture(name, flag, true)
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", "Unowned flag")
|
||||
minetest.get_node_timer(pos):start(5)
|
||||
end,
|
||||
after_place_node = function(pos, placer)
|
||||
local name = placer:get_player_name()
|
||||
if not pos or not name then
|
||||
minetest.set_node(pos, {name="air"})
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
if not meta then
|
||||
minetest.set_node(pos, {name="air"})
|
||||
return
|
||||
end
|
||||
|
||||
local tplayer = ctf.player_or_nil(name)
|
||||
if tplayer and ctf.team(tplayer.team) then
|
||||
if not minetest.check_player_privs(name, {ctf_place_flag=true}) then
|
||||
minetest.chat_send_player(name, "You're not allowed to place flags! Reported to admin for investigation.")
|
||||
minetest.set_node(pos, {name="air"})
|
||||
if minetest.global_exists("chatplus") then
|
||||
chatplus.send_mail("*SERVER*", minetest.settings:get("name"),
|
||||
"player " .. name .. " attempted to place flag!")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local tname = tplayer.team
|
||||
local team = ctf.team(tplayer.team)
|
||||
meta:set_string("infotext", tname.."'s flag")
|
||||
|
||||
-- add flag
|
||||
ctf_flag.add(tname, pos)
|
||||
|
||||
-- TODO: fix this hackiness
|
||||
if team.spawn and not ctf.setting("flag.allow_multiple") and
|
||||
minetest.get_node(team.spawn).name == "ctf_flag:flag" then
|
||||
-- send message
|
||||
minetest.chat_send_all(tname .. "'s flag has been moved")
|
||||
minetest.set_node(team.spawn, {name="air"})
|
||||
minetest.set_node({
|
||||
x = team.spawn.x,
|
||||
y = team.spawn.y+1,
|
||||
z = team.spawn.z
|
||||
}, {name="air"})
|
||||
team.spawn = pos
|
||||
end
|
||||
|
||||
ctf.needs_save = true
|
||||
|
||||
local pos2 = {
|
||||
x = pos.x,
|
||||
y = pos.y + 1,
|
||||
z = pos.z
|
||||
}
|
||||
|
||||
if not team.data.color then
|
||||
team.data.color = "red"
|
||||
ctf.needs_save = true
|
||||
end
|
||||
|
||||
minetest.set_node(pos2, {name="ctf_flag:flag_top_"..team.data.color})
|
||||
|
||||
local meta2 = minetest.get_meta(pos2)
|
||||
|
||||
meta2:set_string("infotext", tname.."'s flag")
|
||||
else
|
||||
minetest.chat_send_player(name, "You are not part of a team!")
|
||||
minetest.set_node(pos, {name="air"})
|
||||
end
|
||||
end
|
||||
}
|
90
mods/ctf_pvp_engine/ctf_flag/flags.lua
Normal file
|
@ -0,0 +1,90 @@
|
|||
-- The flag
|
||||
minetest.register_node("ctf_flag:flag", {
|
||||
description = "Flag",
|
||||
drawtype="nodebox",
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
inventory_image = "flag_silver2.png",
|
||||
tiles = {
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png"
|
||||
},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{0.250000,-0.500000,0.000000,0.312500,0.500000,0.062500}
|
||||
}
|
||||
},
|
||||
groups = {immortal=1,is_flag=1,flag_bottom=1},
|
||||
on_punch = ctf_flag.on_punch,
|
||||
on_rightclick = ctf_flag.on_rightclick,
|
||||
on_construct = ctf_flag.on_construct,
|
||||
after_place_node = ctf_flag.after_place_node,
|
||||
on_timer = ctf_flag.flag_tick
|
||||
})
|
||||
|
||||
for color, _ in pairs(ctf.flag_colors) do
|
||||
minetest.register_node("ctf_flag:flag_top_"..color,{
|
||||
description = "You are not meant to have this! - flag top",
|
||||
drawtype="nodebox",
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"flag_"..color.."2.png",
|
||||
"flag_"..color..".png"
|
||||
},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{0.250000,-0.500000,0.000000,0.312500,0.500000,0.062500},
|
||||
{-0.5,0,0.000000,0.250000,0.500000,0.062500}
|
||||
}
|
||||
},
|
||||
groups = {immortal=1,is_flag=1,flag_top=1,not_in_creative_inventory=1},
|
||||
on_punch = ctf_flag.on_punch_top,
|
||||
on_rightclick = ctf_flag.on_rightclick_top
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_node("ctf_flag:flag_captured_top",{
|
||||
description = "You are not meant to have this! - flag captured",
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png",
|
||||
"default_wood.png"
|
||||
},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{0.250000,-0.500000,0.000000,0.312500,0.500000,0.062500}
|
||||
}
|
||||
},
|
||||
groups = {immortal=1,is_flag=1,flag_top=1,not_in_creative_inventory=1},
|
||||
on_punch = ctf_flag.on_punch_top,
|
||||
on_rightclick = ctf_flag.on_rightclick_top
|
||||
})
|
||||
|
||||
if ctf.setting("flag.crafting") then
|
||||
minetest.register_craft({
|
||||
output = "ctf_flag:flag",
|
||||
recipe = {
|
||||
{"default:stick", "group:wool"},
|
||||
{"default:stick", "",},
|
||||
{"default:stick", ""}
|
||||
}
|
||||
})
|
||||
end
|
184
mods/ctf_pvp_engine/ctf_flag/gui.lua
Normal file
|
@ -0,0 +1,184 @@
|
|||
-- Team interface
|
||||
ctf.gui.register_tab("flags", "Flags", function(name, team)
|
||||
local result = ""
|
||||
local t = ctf.team(team)
|
||||
|
||||
if not t then
|
||||
return
|
||||
end
|
||||
|
||||
local x = 1
|
||||
local y = 2
|
||||
result = result .. "label[1,1;Click a flag button to go there]"
|
||||
|
||||
if ctf.setting("gui.team.teleport_to_spawn") and minetest.get_setting("static_spawnpoint") then
|
||||
local x,y,z = string.match(minetest.get_setting("static_spawnpoint"), "(%d+),(%d+),(%d+)")
|
||||
|
||||
result = result ..
|
||||
"button[" .. x .. "," .. y .. ";2,1;goto_"
|
||||
..f.x.."_"..f.y.."_"..f.z..";"
|
||||
|
||||
result = result .. "Spawn]"
|
||||
x = x + 2
|
||||
end
|
||||
|
||||
for i=1, #t.flags do
|
||||
local f = t.flags[i]
|
||||
|
||||
if x > 8 then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y > 6 then
|
||||
break
|
||||
end
|
||||
|
||||
result = result ..
|
||||
"button[" .. x .. "," .. y .. ";2,1;goto_"
|
||||
..f.x.."_"..f.y.."_"..f.z..";"
|
||||
|
||||
if f.name then
|
||||
result = result .. f.name .. "]"
|
||||
else
|
||||
result = result .. "("..f.x..","..f.y..","..f.z..")]"
|
||||
end
|
||||
|
||||
x = x + 2
|
||||
end
|
||||
|
||||
minetest.show_formspec(name, "ctf:flags",
|
||||
"size[10,7]"..
|
||||
ctf.gui.get_tabs(name,team)..
|
||||
result)
|
||||
end)
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
-- Todo: fix security issue here
|
||||
-- local name = player:get_player_name()
|
||||
-- if formname == "ctf:flags" then
|
||||
-- for key, field in pairs(fields) do
|
||||
-- local x,y,z = string.match(key, "goto_([%d-]+)_([%d-]+)_([%d-]+)")
|
||||
-- if x and y and z then
|
||||
-- player:setpos({ x=tonumber(x), y=tonumber(y), z=tonumber(z) })
|
||||
-- return true
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
end)
|
||||
|
||||
-- Flag interface
|
||||
function ctf.gui.flag_board(name, pos)
|
||||
local flag = ctf_flag.get(pos)
|
||||
if not flag then
|
||||
return
|
||||
end
|
||||
|
||||
local team = flag.team
|
||||
if not team then
|
||||
return
|
||||
end
|
||||
|
||||
if not ctf.can_mod(name, team) then
|
||||
if ctf.player(name).team and ctf.player(name).team == team then
|
||||
ctf.gui.show(name)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
ctf.log("gui", name .. " views flag board")
|
||||
|
||||
local flag_name = flag.name
|
||||
|
||||
if not ctf.setting("flag.names") then
|
||||
flag.name = nil
|
||||
return
|
||||
end
|
||||
|
||||
if not ctf.setting("gui") then
|
||||
return
|
||||
end
|
||||
|
||||
if not flag_name then
|
||||
flag_name = ""
|
||||
end
|
||||
|
||||
if not ctf.gui.flag_data then
|
||||
ctf.gui.flag_data = {}
|
||||
end
|
||||
|
||||
ctf.gui.flag_data[name] = {pos=pos}
|
||||
|
||||
minetest.show_formspec(name, "ctf:flag_board",
|
||||
"size[6,3]"..
|
||||
"field[1,1;4,1;flag_name;Flag Name;"..flag_name.."]"..
|
||||
"button_exit[1,2;2,1;save;Save]"..
|
||||
"button_exit[3,2;2,1;delete;Delete]"
|
||||
)
|
||||
end
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
local name = player:get_player_name()
|
||||
|
||||
if not formname=="ctf:flag_board" then
|
||||
return false
|
||||
end
|
||||
|
||||
if fields.save and fields.flag_name then
|
||||
local flag = ctf_flag.get(ctf.gui.flag_data[name].pos)
|
||||
if not flag then
|
||||
return false
|
||||
end
|
||||
|
||||
local team = flag.team
|
||||
if not team then
|
||||
return false
|
||||
end
|
||||
|
||||
if ctf.can_mod(name,team) == false then
|
||||
return false
|
||||
end
|
||||
|
||||
local flag_name = flag.name
|
||||
if not flag_name then
|
||||
flag_name = ""
|
||||
end
|
||||
|
||||
flag.name = fields.flag_name
|
||||
|
||||
local msg = flag_name.." was renamed to "..fields.flag_name
|
||||
|
||||
if flag_name=="" then
|
||||
msg = "A flag was named "..fields.flag_name.." at ("..ctf.gui.flag_data[name].pos.x..","..ctf.gui.flag_data[name].pos.z..")"
|
||||
end
|
||||
|
||||
ctf.post(team,{msg=msg,icon="flag_info"})
|
||||
|
||||
return true
|
||||
elseif fields.delete then
|
||||
local pos = ctf.gui.flag_data[name].pos
|
||||
|
||||
local flag = ctf_flag.get(ctf.gui.flag_data[name].pos)
|
||||
|
||||
if not flag then
|
||||
return
|
||||
end
|
||||
|
||||
local team = flag.team
|
||||
if not team then
|
||||
return
|
||||
end
|
||||
|
||||
if ctf.can_mod(name,team) == false then
|
||||
return false
|
||||
end
|
||||
|
||||
ctf_flag.delete(team,pos)
|
||||
|
||||
minetest.set_node(pos,{name="air"})
|
||||
pos.y=pos.y+1
|
||||
minetest.set_node(pos,{name="air"})
|
||||
player:get_inventory():add_item("main", "ctf_flag:flag")
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
102
mods/ctf_pvp_engine/ctf_flag/hud.lua
Normal file
|
@ -0,0 +1,102 @@
|
|||
-- TODO: delete flags if they are removed (ctf.next, or captured)
|
||||
ctf.hud.register_part(function(player, name, tplayer)
|
||||
if ctf.setting("flag.waypoints") then
|
||||
for tname, team in pairs(ctf.teams) do
|
||||
for _, flag in pairs(team.flags) do
|
||||
local hud = "ctf:hud_" .. tname
|
||||
local flag_name = flag.name or tname .. "'s base"
|
||||
local color = ctf.flag_colors[team.data.color]
|
||||
if not color then
|
||||
color = "0x000000"
|
||||
end
|
||||
|
||||
if ctf.hud:exists(player, hud) then
|
||||
ctf.hud:change(player, hud, "world_pos", {
|
||||
x = flag.x,
|
||||
y = flag.y,
|
||||
z = flag.z
|
||||
})
|
||||
else
|
||||
ctf.hud:add(player, hud, {
|
||||
hud_elem_type = "waypoint",
|
||||
name = flag_name,
|
||||
number = color,
|
||||
world_pos = {
|
||||
x = flag.x,
|
||||
y = flag.y,
|
||||
z = flag.z
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
ctf.hud.register_part(function(player, name, tplayer)
|
||||
-- Check all flags
|
||||
local alert = nil
|
||||
local color = "0xFFFFFF"
|
||||
if ctf.setting("flag.alerts") then
|
||||
if ctf.setting("flag.alerts.neutral_alert") then
|
||||
alert = "Punch the enemy flag! Protect your flag!"
|
||||
end
|
||||
local claimed = ctf_flag.collect_claimed()
|
||||
local enemyHolder = nil
|
||||
local teamHolder = nil
|
||||
for _, flag in pairs(claimed) do
|
||||
if flag.team == tplayer.team then
|
||||
enemyHolder = flag.claimed.player
|
||||
else
|
||||
teamHolder = flag.claimed.player
|
||||
end
|
||||
end
|
||||
|
||||
if teamHolder == name then
|
||||
if enemyHolder then
|
||||
alert = "You can't capture the flag until " .. enemyHolder .. " is killed!"
|
||||
color = "0xFF0000"
|
||||
else
|
||||
alert = "You've got the flag! Run back and punch your flag!"
|
||||
color = "0xFF0000"
|
||||
end
|
||||
elseif teamHolder then
|
||||
if enemyHolder then
|
||||
alert = "Kill " .. enemyHolder .. " to allow " .. teamHolder .. " to capture the flag!"
|
||||
color = "0xFF0000"
|
||||
else
|
||||
alert = "Protect " .. teamHolder .. ", they've got the enemy flag!"
|
||||
color = "0xFF0000"
|
||||
end
|
||||
elseif enemyHolder then
|
||||
alert = "Kill " .. enemyHolder .. ", they've got your flag!"
|
||||
color = "0xFF0000"
|
||||
end
|
||||
end
|
||||
|
||||
-- Display alert
|
||||
if alert then
|
||||
if ctf.hud:exists(player, "ctf:hud_team_alert") then
|
||||
ctf.hud:change(player, "ctf:hud_team_alert", "text", alert)
|
||||
ctf.hud:change(player, "ctf:hud_team_alert", "number", color)
|
||||
else
|
||||
local y
|
||||
if ctf.setting("hud.teamname") then
|
||||
y = 50
|
||||
else
|
||||
y = 20
|
||||
end
|
||||
ctf.hud:add(player, "ctf:hud_team_alert", {
|
||||
hud_elem_type = "text",
|
||||
position = {x = 1, y = 0},
|
||||
scale = {x = 100, y = 100},
|
||||
text = alert,
|
||||
number = color,
|
||||
offset = {x = -10, y = y},
|
||||
alignment = {x = -1, y = 0}
|
||||
})
|
||||
end
|
||||
else
|
||||
ctf.hud:remove(player, "ctf:hud_team_alert")
|
||||
end
|
||||
end)
|
146
mods/ctf_pvp_engine/ctf_flag/init.lua
Normal file
|
@ -0,0 +1,146 @@
|
|||
-- Initialise
|
||||
ctf.register_on_init(function()
|
||||
ctf.log("flag", "Initialising...")
|
||||
ctf._set("flag.allow_multiple", true)
|
||||
ctf._set("flag.capture_take", false)
|
||||
ctf._set("flag.names", true)
|
||||
ctf._set("flag.waypoints", true)
|
||||
ctf._set("flag.protect_distance", 25)
|
||||
ctf._set("flag.nobuild_radius", 3)
|
||||
ctf._set("flag.drop_time", 7*60)
|
||||
ctf._set("flag.drop_warn_time", 60)
|
||||
ctf._set("flag.crafting", false)
|
||||
ctf._set("flag.alerts", true)
|
||||
ctf._set("flag.alerts.neutral_alert", true)
|
||||
ctf._set("gui.team.teleport_to_flag", true)
|
||||
ctf._set("gui.team.teleport_to_spawn", false)
|
||||
end)
|
||||
|
||||
minetest.register_privilege("ctf_place_flag", {
|
||||
description = "can place flag"
|
||||
})
|
||||
|
||||
dofile(minetest.get_modpath("ctf_flag") .. "/hud.lua")
|
||||
dofile(minetest.get_modpath("ctf_flag") .. "/gui.lua")
|
||||
dofile(minetest.get_modpath("ctf_flag") .. "/flag_func.lua")
|
||||
dofile(minetest.get_modpath("ctf_flag") .. "/api.lua")
|
||||
dofile(minetest.get_modpath("ctf_flag") .. "/flags.lua")
|
||||
|
||||
ctf.register_on_new_team(function(team)
|
||||
team.flags = {}
|
||||
end)
|
||||
|
||||
function ctf_flag.get_nearest(pos)
|
||||
local closest = 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_distSQ = distSQ
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return closest, closest_distSQ
|
||||
end
|
||||
|
||||
function ctf_flag.get_nearest_team_dist(pos)
|
||||
local flag, distSQ = ctf_flag.get_nearest(pos)
|
||||
if flag then
|
||||
return flag.team, distSQ
|
||||
end
|
||||
end
|
||||
|
||||
ctf.register_on_territory_query(ctf_flag.get_nearest_team_dist)
|
||||
|
||||
function ctf.get_spawn(team)
|
||||
if not ctf.team(team) then
|
||||
return nil
|
||||
end
|
||||
|
||||
if ctf.team(team).spawn then
|
||||
return ctf.team(team).spawn
|
||||
end
|
||||
|
||||
-- Get spawn from first flag
|
||||
ctf_flag.assert_flags(team)
|
||||
if #ctf.team(team).flags > 0 then
|
||||
return ctf.team(team).flags[1]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Add minimum build range
|
||||
local old_is_protected = minetest.is_protected
|
||||
local r = ctf.setting("flag.nobuild_radius")
|
||||
local rs = r * r
|
||||
function minetest.is_protected(pos, name)
|
||||
if r <= 0 or rs == 0 then
|
||||
return old_is_protected(pos, name)
|
||||
end
|
||||
|
||||
local flag, distSQ = ctf_flag.get_nearest(pos)
|
||||
if flag and pos.y >= flag.y - 1 and distSQ < rs then
|
||||
minetest.chat_send_player(name,
|
||||
"Too close to the flag to build! Leave at least " .. r .. " blocks around the flag.")
|
||||
return true
|
||||
else
|
||||
return old_is_protected(pos, name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Play sound
|
||||
ctf_flag.register_on_pick_up(function(attname, flag)
|
||||
local vteam = ctf.team(flag.team)
|
||||
for name, player in pairs(vteam.players) do
|
||||
minetest.sound_play({name="trumpet_lose"}, {
|
||||
to_player = name,
|
||||
gain = 1.0, -- default
|
||||
})
|
||||
end
|
||||
|
||||
local ateam = ctf.team(ctf.player(attname).team)
|
||||
for name, player in pairs(ateam.players) do
|
||||
minetest.sound_play({name="trumpet_win"}, {
|
||||
to_player = name,
|
||||
gain = 1.0, -- default
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
-- Drop after time
|
||||
local pickup_times = {}
|
||||
ctf_flag.register_on_pick_up(function(attname, flag)
|
||||
pickup_times[attname] = minetest.get_gametime()
|
||||
end)
|
||||
ctf_flag.register_on_drop(function(attname, flag)
|
||||
pickup_times[attname] = nil
|
||||
end)
|
||||
ctf_flag.register_on_capture(function(attname, flag)
|
||||
pickup_times[attname] = nil
|
||||
end)
|
||||
ctf.register_on_new_game(function()
|
||||
pickup_times = {}
|
||||
end)
|
||||
local function update_flag_drops()
|
||||
local time = minetest.get_gametime()
|
||||
local drop_time = ctf.setting("flag.drop_time")
|
||||
for name, start in pairs(pickup_times) do
|
||||
local remaining = drop_time - time + start
|
||||
if remaining < 0 then
|
||||
ctf_flag.player_drop_flag(name)
|
||||
minetest.chat_send_player(name, "You took too long to capture the flag, so it returned!")
|
||||
elseif remaining < ctf.setting("flag.drop_warn_time") then
|
||||
minetest.chat_send_player(name, "You have " .. remaining ..
|
||||
" seconds to capture the flag before it returns.")
|
||||
end
|
||||
end
|
||||
minetest.after(5, update_flag_drops)
|
||||
end
|
||||
minetest.after(5, update_flag_drops)
|
BIN
mods/ctf_pvp_engine/ctf_flag/sounds/trumpet_lose.ogg
Normal file
BIN
mods/ctf_pvp_engine/ctf_flag/sounds/trumpet_win.ogg
Normal file
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_black.png
Normal file
After Width: | Height: | Size: 601 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_black2.png
Normal file
After Width: | Height: | Size: 598 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_blue.png
Normal file
After Width: | Height: | Size: 776 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_blue2.png
Normal file
After Width: | Height: | Size: 732 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_cyan.png
Normal file
After Width: | Height: | Size: 666 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_cyan2.png
Normal file
After Width: | Height: | Size: 676 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_gold.png
Normal file
After Width: | Height: | Size: 618 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_gold2.png
Normal file
After Width: | Height: | Size: 625 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_gray.png
Normal file
After Width: | Height: | Size: 549 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_gray2.png
Normal file
After Width: | Height: | Size: 571 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_green.png
Normal file
After Width: | Height: | Size: 826 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_green2.png
Normal file
After Width: | Height: | Size: 775 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_orange.png
Normal file
After Width: | Height: | Size: 632 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_orange2.png
Normal file
After Width: | Height: | Size: 635 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_pink.png
Normal file
After Width: | Height: | Size: 690 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_pink2.png
Normal file
After Width: | Height: | Size: 688 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_purple.png
Normal file
After Width: | Height: | Size: 622 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_purple2.png
Normal file
After Width: | Height: | Size: 616 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_red.png
Normal file
After Width: | Height: | Size: 812 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_red2.png
Normal file
After Width: | Height: | Size: 874 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_silver.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_silver2.png
Normal file
After Width: | Height: | Size: 567 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_yellow.png
Normal file
After Width: | Height: | Size: 657 B |
BIN
mods/ctf_pvp_engine/ctf_flag/textures/flag_yellow2.png
Normal file
After Width: | Height: | Size: 671 B |