447 lines
13 KiB
Lua
447 lines
13 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local include, nodecore, minetest
|
|
= include, nodecore, minetest
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
local modname = minetest.get_current_modname()
|
|
|
|
ctf = {}
|
|
|
|
local cfg = include("config")
|
|
local teams = cfg.teams
|
|
|
|
local CRYSTALS_PER_TEAM = cfg.CRYSTALS_PER_TEAM
|
|
local PLAYERS_PER_TEAM = cfg.PLAYERS_PER_TEAM
|
|
local SPAWNPOINT = cfg.SPAWNPOINT
|
|
local SPAWN_OFFSET = cfg.SPAWN_OFFSET
|
|
local FIELD_RADIUS = cfg.FIELD_RADIUS
|
|
local BORDER_RADIUS = cfg.BORDER_RADIUS
|
|
local SPAWN_DIST = cfg.SPAWN_DIST
|
|
local TEAM_DIST = cfg.TEAM_DIST
|
|
local PLAYER_DIST = cfg.PLAYER_DIST
|
|
local SPAWNFALL_LIMIT = cfg.SPAWNFALL_LIMIT
|
|
local TELEPORT_ROOM = cfg.TELEPORT_ROOM
|
|
|
|
ctf.player_count = 0
|
|
ctf.voted_count = 0
|
|
ctf.players = {}
|
|
ctf.teams = {}
|
|
ctf.started = false
|
|
ctf.starting = false
|
|
ctf.ended = false
|
|
|
|
do
|
|
|
|
local f = math.floor
|
|
|
|
local function sign(x)
|
|
return x > 0 and 1 or (x < 0 and -1 or 0)
|
|
end
|
|
|
|
function ctf.spawn(name,pos,call)
|
|
local ref = minetest.get_player_by_name(name)
|
|
ref:set_pos(TELEPORT_ROOM)
|
|
pos = {x=f(pos.x),y=f(pos.y),z=f(pos.z)}
|
|
call = call or function()end
|
|
local limit = SPAWNFALL_LIMIT
|
|
minetest.chat_send_player(name,"<TELEPORT> Configuring transportation processor...")
|
|
minetest.emerge_area({x=pos.x,y=pos.y-limit,z=pos.z},{x=pos.x,y=pos.y+limit,z=pos.z},function(bp,act,crem)
|
|
if crem > 0 then return end
|
|
minetest.chat_send_player(name,"<TELEPORT> Done. Sending transport coordinates...")
|
|
local off = 0
|
|
while off > -limit do
|
|
if minetest.get_node({x=pos.x,y=pos.y+off,z=pos.z}).name ~= "air" then
|
|
off = off + 1
|
|
break
|
|
end
|
|
off = off - 1
|
|
end
|
|
while off < limit do
|
|
if minetest.get_node({x=pos.x,y=pos.y+off,z=pos.z}).name == "air" then
|
|
break
|
|
end
|
|
off = off + 1
|
|
end
|
|
local apos = {x=pos.x,y=pos.y+off,z=pos.z}
|
|
local ref = minetest.get_player_by_name(name)
|
|
if ref then
|
|
ref:set_pos(apos)
|
|
call(ref,apos)
|
|
end
|
|
end)
|
|
end
|
|
|
|
end
|
|
|
|
minetest.register_on_chat_message(function(name, message)
|
|
local team = ctf.players[name].team
|
|
if team and ctf.teams[team] and ctf.started and not ctf.ended then
|
|
if message:sub(1,1) ~= "." then
|
|
local msg = minetest.format_chat_message(name,message)
|
|
minetest.chat_send_all(msg)
|
|
else
|
|
local msg = minetest.colorize(teams[team].colorstr, minetest.format_chat_message(name,message:sub(2)))
|
|
for k,v in pairs(ctf.teams[team].players) do
|
|
minetest.chat_send_player(k,msg)
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
end)
|
|
|
|
minetest.register_chatcommand("vote",{
|
|
desc = "Vote to end the game",
|
|
privs = {interact = true},
|
|
func = function(name,param)
|
|
local pl = ctf.players[name]
|
|
pl.voted = not pl.voted
|
|
ctf.voted_count = pl.voted and (ctf.voted_count+1) or (ctf.voted_count-1)
|
|
if pl.voted then
|
|
minetest.chat_send_player(name,"You vote to end the game")
|
|
else
|
|
minetest.chat_send_player(name,"You vote to NOT end the game")
|
|
end
|
|
end
|
|
})
|
|
|
|
include("node")
|
|
ctf.crystals(teams)
|
|
|
|
local bar_c = minetest.get_content_id(modname..":barrier")
|
|
local air_c = minetest.get_content_id("air")
|
|
|
|
local abs = math.abs
|
|
local function distance(a,b)
|
|
return math.max(abs(a.x-b.x),abs(a.z-b.z))
|
|
end
|
|
|
|
minetest.register_on_generated(function(minp,maxp,seed)
|
|
if vector.distance(TELEPORT_ROOM,vector.divide(vector.add(minp,maxp),2)) < 2000 then
|
|
local vm,mip,map = minetest.get_mapgen_object("voxelmanip")
|
|
local ar = VoxelArea:new{MinEdge=mip,MaxEdge=map}
|
|
local d = vm:get_data()
|
|
for x=minp.x,maxp.x do
|
|
for y=minp.y,maxp.y do
|
|
for z=minp.z,maxp.z do
|
|
local i = ar:index(x,y,z)
|
|
if vector.distance({x=x,y=y,z=z},TELEPORT_ROOM) > math.random(8,10) then
|
|
d[i] = bar_c
|
|
else
|
|
d[i] = air_c
|
|
end
|
|
end
|
|
end
|
|
end
|
|
vm:set_data(d)
|
|
vm:write_to_map()
|
|
else
|
|
if distance(vector.divide(vector.add(minp,maxp),2),ctf.spawnpoint) > FIELD_RADIUS then
|
|
local vm,mip,map = minetest.get_mapgen_object("voxelmanip")
|
|
local ar = VoxelArea:new{MinEdge=mip,MaxEdge=map}
|
|
local d = vm:get_data()
|
|
for x=minp.x,maxp.x do
|
|
for y=minp.y,maxp.y do
|
|
for z=minp.z,maxp.z do
|
|
local i = ar:index(x,y,z)
|
|
d[i] = bar_c
|
|
end
|
|
end
|
|
end
|
|
vm:set_data(d)
|
|
vm:write_to_map()
|
|
end
|
|
end
|
|
end)
|
|
|
|
function ctf.set_team_text(name)
|
|
local pl = ctf.players[name]
|
|
assert(pl)
|
|
local team = teams[pl.team]
|
|
print(pl.team,team)
|
|
ctf.set_text(name,"You're member of "..tostring(team.desc).." team\n",team.colornum)
|
|
end
|
|
|
|
function ctf.join(team,name)
|
|
if ctf.players[name].team and ctf.teams[ctf.players[name].team].players[name] then
|
|
ctf.teams[ctf.players[name].team].players[name] = nil
|
|
end
|
|
ctf.teams[team].players[name] = true
|
|
ctf.players[name].team = team
|
|
end
|
|
|
|
function ctf.dist_player(name)
|
|
local m,t = math.huge,nil
|
|
for team,teamd in pairs(ctf.teams) do
|
|
local c = 0
|
|
for namee,bool in pairs(teamd.players) do
|
|
if bool and namee ~= name then
|
|
c=c+1
|
|
end
|
|
end
|
|
if c < m or (c == m and math.random()>0.5) then
|
|
m = c
|
|
t = team
|
|
end
|
|
end
|
|
ctf.join(t,name)
|
|
end
|
|
|
|
minetest.register_on_joinplayer(function(ref)
|
|
local name = ref:get_player_name()
|
|
local id = ref:hud_add{
|
|
name = "stat",
|
|
text = "Game is not started yet\nWaiting for more players to begin",
|
|
number = 0xFFFFFF,
|
|
alignment = {x=-1,y=1},
|
|
offset = {x=-20,y=20},
|
|
position = {x=1,y=0},
|
|
}
|
|
ctf.players[name] = {}
|
|
ctf.players[name].hud = {stat = id}
|
|
ctf.player_count = ctf.player_count + 1
|
|
ctf.explode_inv(ref)
|
|
|
|
minetest.after(1,function()
|
|
if ctf.started then
|
|
ctf.dist_player(name)
|
|
ctf.set_team_text(name)
|
|
local pls = {}
|
|
for k,v in pairs(ctf.teams[ctf.players[name].team].players) do
|
|
if v and k ~= name then
|
|
table.insert(pls,minetest.get_player_by_name(k):get_pos())
|
|
end
|
|
end
|
|
if #pls > 0 then
|
|
ctf.spawn(name,pls[math.random(1,#pls)])
|
|
else
|
|
ctf.spawn(name,vector.add(ctf.spawnpoint,SPAWN_OFFSET))
|
|
end
|
|
else
|
|
ctf.spawn(name,vector.add(ctf.spawnpoint,SPAWN_OFFSET))
|
|
end
|
|
end)
|
|
end)
|
|
|
|
function ctf.explode_inv(ref)
|
|
local inv = ref:get_inventory()
|
|
local pos = ref:get_pos()
|
|
local list = inv:get_list("main")
|
|
inv:set_list("main",{})
|
|
for k,v in pairs(list) do
|
|
if not nodecore.item_is_virtual(v) and not v:is_empty() then
|
|
nodecore.item_eject(pos,v,5)
|
|
end
|
|
end
|
|
end
|
|
|
|
function ctf.set_text(name,text,colornum)
|
|
local pl = ctf.players[name]
|
|
if pl and pl.hud then
|
|
local ref = minetest.get_player_by_name(name)
|
|
ref:hud_change(pl.hud.stat,"text",text)
|
|
ref:hud_change(pl.hud.stat,"number",colornum or 0xFFFFFF)
|
|
end
|
|
end
|
|
|
|
minetest.register_on_leaveplayer(function(ref)
|
|
local name = ref:get_player_name()
|
|
if ctf.players[name].team and ctf.teams[ctf.players[name].team] then
|
|
ctf.teams[ctf.players[name].team].players[name] = nil
|
|
end
|
|
if ctf.players[name].voted then
|
|
ctf.voted_count = ctf.voted_count-1
|
|
end
|
|
if ctf.starting == math.huge then
|
|
ctf.starting = -math.huge
|
|
end
|
|
ctf.players[name] = nil
|
|
ctf.explode_inv(ref)
|
|
ctf.player_count = ctf.player_count - 1
|
|
end)
|
|
|
|
function ur(n)
|
|
return (math.random()-0.5)*n
|
|
end
|
|
|
|
do
|
|
local z = SPAWN_DIST
|
|
local pos = vector.add(SPAWNPOINT,{x=ur(z),y=0,z=ur(z)})
|
|
ctf.spawnpoint = pos
|
|
end
|
|
|
|
function ctf.start()
|
|
if ctf.starting == math.huge or ctf.starting == -math.huge then
|
|
return
|
|
end
|
|
if ctf.started or ctf.ended then
|
|
return
|
|
end
|
|
for k,v in pairs(ctf.players) do
|
|
if v.voted then
|
|
v.voted = false
|
|
ctf.voted_count = ctf.voted_count - 1
|
|
end
|
|
end
|
|
ctf.ended = false
|
|
local tc = math.max(2,math.floor(ctf.player_count/PLAYERS_PER_TEAM))
|
|
if ctf.player_count >= 2 and not ctf.starting then
|
|
ctf.starting = minetest.get_server_uptime()+10
|
|
minetest.chat_send_all("<INFO> Enough players are here! Starting in 10 seconds")
|
|
elseif ctf.starting and not (ctf.player_count >= 2) then
|
|
ctf.starting = false
|
|
minetest.chat_send_all("<INFO> Not enough players now. Aborting.")
|
|
end
|
|
if ctf.starting and minetest.get_server_uptime() >= ctf.starting then
|
|
ctf.starting = math.huge
|
|
minetest.chat_send_all("<TELEPORT + INFO> CONFIGURING TRANSPORTATION PROCCESSORS FOR EVERYONE . . .")
|
|
local c = 0
|
|
ctf.teams = {}
|
|
for k,v in pairs(teams) do
|
|
c=c+1
|
|
ctf.teams[k] = {players = {},score = CRYSTALS_PER_TEAM}
|
|
if c >= tc then
|
|
break
|
|
end
|
|
end
|
|
for name,pl in pairs(ctf.players) do
|
|
ctf.explode_inv(minetest.get_player_by_name(name))
|
|
ctf.dist_player(name)
|
|
ctf.set_team_text(name)
|
|
end
|
|
local z = SPAWN_DIST
|
|
local pos = vector.add(SPAWNPOINT,{x=ur(z),y=0,z=ur(z)})
|
|
ctf.spawnpoint = pos
|
|
pos = vector.add(pos,SPAWN_OFFSET)
|
|
local pc = 0
|
|
local call = function(ref,pos)
|
|
pc = pc + 1
|
|
if pc < ctf.player_count then return end
|
|
if ctf.starting == -math.huge then
|
|
minetest.chat_send_all("<TELEPORT + INFO> SOMEONE LEFT DURING CONFIGURATION. ABORTING")
|
|
ctf.teams = {}
|
|
for k,v in pairs(ctf.players) do
|
|
v.team = nil
|
|
end
|
|
ctf.starting = false
|
|
ctf.started = false
|
|
ctf.ended = false
|
|
return
|
|
end
|
|
ctf.starting = false
|
|
ctf.started = true
|
|
minetest.chat_send_all("<INFO> The game begins!")
|
|
for tname,team in pairs(ctf.teams) do
|
|
local crystals = CRYSTALS_PER_TEAM
|
|
while crystals > 0 do
|
|
local b = false
|
|
for name in pairs(team.players) do
|
|
local ref = minetest.get_player_by_name(name)
|
|
if crystals > 0 then
|
|
crystals = crystals - 1
|
|
b=true
|
|
ref:get_inventory():add_item("main",modname..":crystal_"..tname)
|
|
else
|
|
break
|
|
end
|
|
end
|
|
if not b then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
for tname,team in pairs(ctf.teams) do
|
|
local x = TEAM_DIST
|
|
local pos = vector.add(pos,{x=ur(x),y=0,z=ur(x)})
|
|
for name in pairs(team.players) do
|
|
local y = PLAYER_DIST
|
|
local pos = vector.add(pos,{x=ur(y),y=0,z=ur(y)})
|
|
local ref = minetest.get_player_by_name(name)
|
|
ctf.spawn(name,pos,call)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
do
|
|
local f
|
|
function f()
|
|
minetest.emerge_area(vector.subtract(TELEPORT_ROOM,{x=20,y=20,z=20}),vector.add(TELEPORT_ROOM,{x=20,y=20,z=20}))
|
|
minetest.after(5,f)
|
|
end
|
|
f()
|
|
end
|
|
|
|
do
|
|
local f
|
|
function f()
|
|
ctf.start()
|
|
for name,pl in pairs(ctf.players) do
|
|
if not minetest.check_player_privs(name,{server = true}) then
|
|
if not pl.team then
|
|
ctf.explode_inv(minetest.get_player_by_name(name))
|
|
local privs = minetest.get_player_privs(name)
|
|
privs.fast = true
|
|
privs.fly = true
|
|
privs.interact = nil
|
|
minetest.set_player_privs(name,privs)
|
|
else
|
|
local privs = minetest.get_player_privs(name)
|
|
privs.fast = nil
|
|
privs.fly = nil
|
|
privs.interact = true
|
|
minetest.set_player_privs(name,privs)
|
|
end
|
|
end
|
|
end
|
|
if ctf.started and not ctf.ended then
|
|
ctf.check_win()
|
|
elseif ctf.voted_count > 0 then
|
|
for k,v in pairs(ctf.players) do
|
|
if v.voted then
|
|
v.voted = false
|
|
ctf.voted_count = ctf.voted_count - 1
|
|
end
|
|
end
|
|
end
|
|
minetest.after(1,f)
|
|
end
|
|
minetest.after(1,f)
|
|
end
|
|
|
|
function ctf.check_win()
|
|
for name,team in pairs(ctf.teams) do
|
|
if team.score <= 0 then
|
|
ctf.teams[name] = nil
|
|
for pname,pl in pairs(team.players) do
|
|
ctf.set_text(pname,":(\nYour team lost.",teams[name].colornum)
|
|
end
|
|
minetest.chat_send_all("<INFO> "..teams[name].desc.." team lost!")
|
|
end
|
|
end
|
|
local c = 0
|
|
for k,v in pairs(ctf.teams) do if v then c=c+1 end end
|
|
local vout = (ctf.voted_count/ctf.player_count) >= 0.5
|
|
if c == 1 or vout then
|
|
ctf.ended = true
|
|
if c == 1 then
|
|
local name,team = next(ctf.teams)
|
|
minetest.chat_send_all("<INFO> "..teams[name].desc.." team won!")
|
|
for pname,pl in pairs(team.players) do
|
|
ctf.set_text(pname,":D\nYour team won!",teams[name].colornum)
|
|
end
|
|
elseif vout then
|
|
minetest.chat_send_all("<INFO> Majority of players voted to end the game")
|
|
for k,v in pairs(ctf.players) do
|
|
ctf.set_text(k,"Game is not started yet\nWaiting for more players to begin")
|
|
end
|
|
end
|
|
minetest.chat_send_all("<INFO> The game is finished")
|
|
ctf.teams = {}
|
|
for k,v in pairs(ctf.players) do
|
|
v.team = nil
|
|
end
|
|
minetest.after(3,function()ctf.started = false ctf.ended = false end)
|
|
end
|
|
end
|