-- 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," 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," 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(" 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(" 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(" 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(" 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(" 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(" "..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(" "..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(" 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(" 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