331 lines
8.0 KiB
Lua
331 lines
8.0 KiB
Lua
-- LTS: Last Team Standing. Try to not die!
|
|
--[[
|
|
This file is part of Ice Lua Components.
|
|
|
|
Ice Lua Components is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Ice Lua Components is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with Ice Lua Components. If not, see <http://www.gnu.org/licenses/>.
|
|
]]
|
|
|
|
MODE_LTS_STARTTIME = MODE_LTS_STARTTIME or 5
|
|
MODE_LTS_ROUNDTIME = MODE_LTS_ROUNDTIME or 90 -- 90 works well for small games on 256x256 maps
|
|
|
|
local t_start = nil
|
|
local t_end = nil
|
|
local t_start_rem = nil
|
|
|
|
local lts_borders = nil
|
|
|
|
local t_border = nil
|
|
|
|
PKT_LTS_SET_TIMER = network.sys_alloc_packet()
|
|
network.sys_handle_s2c(PKT_LTS_SET_TIMER, "h", function (neth, cli, plr, sec_current, time, pkt)
|
|
if time < 0 then
|
|
t_start_rem = nil
|
|
else
|
|
t_start_rem = time
|
|
end
|
|
t_border = nil
|
|
end)
|
|
|
|
local function winning_team()
|
|
local i
|
|
local tpl = nil
|
|
|
|
for i=1,players.max do
|
|
if players[i] and players[i].alive then
|
|
tpl = tpl or players[i].team
|
|
if players[i].team ~= tpl then
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
|
|
return tpl or -1
|
|
end
|
|
|
|
local function can_start_round()
|
|
local i
|
|
local tpl = nil
|
|
|
|
for i=1,players.max do
|
|
if players[i] then
|
|
tpl = tpl or players[i].team
|
|
if players[i].team ~= tpl then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local function respawn_all()
|
|
if not server then return end
|
|
local i
|
|
for i=1,players.max do
|
|
if players[i] then
|
|
players[i].spawn()
|
|
net_broadcast(nil, common.net_pack("BBfffBB",
|
|
PKT_PLR_SPAWN, i,
|
|
players[i].x, players[i].y, players[i].z,
|
|
players[i].angy*128/math.pi, players[i].angx*256/math.pi))
|
|
end
|
|
end
|
|
if can_start_round() then
|
|
net_broadcast(nil, common.net_pack("Bh",
|
|
PKT_LTS_SET_TIMER, t_start_rem))
|
|
end
|
|
end
|
|
|
|
function mode_reset()
|
|
local i
|
|
respawn_all()
|
|
for i=0,teams.max do
|
|
if teams[i] ~= nil then
|
|
teams[i].score = 0
|
|
net_broadcast(nil, common.net_pack("Bbh", PKT_TEAM_SCORE, i, teams[i].score))
|
|
end
|
|
end
|
|
end
|
|
|
|
function mode_create_server()
|
|
TEAM_SCORE_LIMIT = TEAM_SCORE_LIMIT_CTF
|
|
end
|
|
|
|
function mode_create_client()
|
|
TEAM_SCORE_LIMIT = TEAM_SCORE_LIMIT_CTF
|
|
|
|
if not lts_borders then
|
|
local r,g,b
|
|
r,g,b = 255,64,64
|
|
xlen, ylen, zlen = common.map_get_dims()
|
|
lts_borders = {
|
|
new_border(-1, -1, -1, 1, 0, 0, r,g,b),
|
|
new_border(xlen+1, ylen+1, zlen+1, 1, 0, 0, r,g,b),
|
|
new_border(-1, -1, -1, 0, 0, 1, r,g,b),
|
|
new_border(xlen+1, ylen+1, zlen+1, 0, 0, 1, r,g,b),
|
|
}
|
|
|
|
local i
|
|
for i=1,#lts_borders do
|
|
borders[#borders+1] = lts_borders[i]
|
|
end
|
|
end
|
|
end
|
|
|
|
function mode_relay_items(plr, neth)
|
|
if t_start_rem then
|
|
net_broadcast(nil, common.net_pack("Bh",
|
|
PKT_LTS_SET_TIMER, math.ceil(t_start_rem)))
|
|
end
|
|
end
|
|
|
|
local function tally_counts(timeup)
|
|
if t_start ~= true then return nil end
|
|
local team = winning_team()
|
|
if team or timeup then
|
|
if timeup then
|
|
local tscores = {}
|
|
local i
|
|
for i=1,players.max do
|
|
local p = players[i]
|
|
if p and p.alive then
|
|
local team = p.team
|
|
tscores[team] = tscores[team] or 0
|
|
tscores[team] = tscores[team] + 1
|
|
end
|
|
end
|
|
local lgval = nil
|
|
local lgidx = nil
|
|
local k,v
|
|
for k,v in pairs(tscores) do
|
|
if lgidx == nil or v > lgval then
|
|
lgidx = k
|
|
lgval = v
|
|
elseif v == lgval then
|
|
lgidx = nil
|
|
end
|
|
end
|
|
|
|
team = lgidx or -1
|
|
end
|
|
|
|
if team == -1 then
|
|
net_broadcast(nil, common.net_pack("BIz", PKT_CHAT_ADD_TEXT, 0xFF800000,
|
|
"* Round ended in a tie :("))
|
|
else
|
|
teams[team].score = teams[team].score + 1
|
|
net_broadcast(nil, common.net_pack("Bbh", PKT_TEAM_SCORE, team, teams[team].score))
|
|
net_broadcast(nil, common.net_pack("BIz", PKT_CHAT_ADD_TEXT, 0xFF800000,
|
|
"* "..teams[team].name.." has won the round!"))
|
|
local i
|
|
for i=1,players.max do
|
|
local p = players[i]
|
|
if p and p.alive and p.team == team then
|
|
p.score = p.score + 10
|
|
p.update_score()
|
|
end
|
|
end
|
|
end
|
|
t_start = nil
|
|
t_end = nil
|
|
net_broadcast(nil, common.net_pack("Bh",
|
|
PKT_LTS_SET_TIMER, -1))
|
|
end
|
|
end
|
|
|
|
if server then
|
|
local s_pkt_offer = network.sys_tab_handlers[PKT_PLR_OFFER].f
|
|
network.sys_tab_handlers[PKT_PLR_OFFER].f = function (neth, cli, plr, sec_current, tidx, wpn, name, pkt, ...)
|
|
local ret = s_pkt_offer(neth, cli, plr, sec_current, tidx, wpn, name, pkt, ...)
|
|
if not plr then
|
|
plr = players[cli.plrid]
|
|
if plr and plr.alive then
|
|
plr.deaths = plr.deaths - 1
|
|
plr.set_health_damage(0, 0xFF800000, plr.name.." awaits the next round", nil)
|
|
end
|
|
end
|
|
return ret
|
|
end
|
|
end
|
|
|
|
local s_new_player = new_player
|
|
function new_player(...)
|
|
local this = s_new_player(...)
|
|
|
|
local s_tick = this.tick
|
|
function this.tick(sec_current, sec_delta, ...)
|
|
local ret = s_tick(sec_current, sec_delta, ...)
|
|
this.t_respawn = nil
|
|
if server then
|
|
-- note, total hack. the server really needs an event system. --GM
|
|
if t_start == nil then
|
|
if can_start_round() then
|
|
t_start = sec_current + MODE_LTS_STARTTIME
|
|
end
|
|
elseif t_start ~= true and t_start <= sec_current then
|
|
net_broadcast(nil, common.net_pack("Bh",
|
|
PKT_LTS_SET_TIMER, -1))
|
|
t_start = true
|
|
t_end = sec_current + MODE_LTS_ROUNDTIME
|
|
respawn_all()
|
|
elseif t_start ~= true then
|
|
local oldrem = t_start_rem
|
|
t_start_rem = math.ceil(t_start - sec_current)
|
|
if t_start_rem ~= oldrem then
|
|
net_broadcast(nil, common.net_pack("Bh",
|
|
PKT_LTS_SET_TIMER, t_start_rem))
|
|
end
|
|
elseif t_end and sec_current >= t_end then
|
|
tally_counts(true)
|
|
elseif t_end then
|
|
local oldrem = t_start_rem
|
|
t_start_rem = math.ceil(t_end - sec_current)
|
|
if t_start_rem ~= oldrem then
|
|
net_broadcast(nil, common.net_pack("Bh",
|
|
PKT_LTS_SET_TIMER, t_start_rem))
|
|
end
|
|
end
|
|
t_border = t_end
|
|
end
|
|
if client then
|
|
-- also a total hack
|
|
if (not t_border) and t_start_rem then
|
|
t_border = sec_current + t_start_rem
|
|
end
|
|
end
|
|
if t_border then
|
|
local xlen, ylen, zlen
|
|
xlen, ylen, zlen = common.map_get_dims()
|
|
local xmin,zmin
|
|
local xmax,zmax
|
|
local xmid,zmid
|
|
local timeleft = t_border - sec_current
|
|
local lenoffs = 16 + ((server and 4) or 0)
|
|
local xoffs = lenoffs + 1.5/MODE_LTS_ROUNDTIME*xlen/2*timeleft
|
|
local zoffs = lenoffs + 1.5/MODE_LTS_ROUNDTIME*zlen/2*timeleft
|
|
xmid,zmid = xlen/2,zlen/2
|
|
xmin,zmin = xmid-xoffs, zmid-zoffs
|
|
xmax,zmax = xmid+xoffs, zmid+zoffs
|
|
if server and this.alive then
|
|
if this.x < xmin or this.z < zmin or this.x > xmax or this.z > zmax then
|
|
this.set_health_damage(0, 0xFF800000, this.name.." got a bit bordered", nil)
|
|
end
|
|
end
|
|
if client then
|
|
local i
|
|
for i=1,#lts_borders,2 do
|
|
local bmin = lts_borders[i]
|
|
local bmax = lts_borders[i+1]
|
|
bmin.x, bmin.z = xmin, zmin
|
|
bmax.x, bmax.z = xmax, zmax
|
|
end
|
|
end
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
local s_create_hud = this.create_hud
|
|
function this.create_hud(...)
|
|
local ret = s_create_hud(...)
|
|
|
|
this.round_start_text = scene.textfield{
|
|
font=font_digits,
|
|
text="",
|
|
color=0xFFFFA1A1,
|
|
align_x=0.5,
|
|
align_y=0,
|
|
x = screen_width/2,
|
|
y = screen_height-96}
|
|
|
|
local function round_start_update(options)
|
|
if t_start_rem then
|
|
this.round_start_text.text = ""..t_start_rem
|
|
else
|
|
this.round_start_text.text = ""
|
|
end
|
|
end
|
|
|
|
this.round_start_text.add_listener(GE_DELTA_TIME, round_start_update)
|
|
this.scene.root.add_child(this.round_start_text)
|
|
|
|
this.scene.root.remove_child(this.respawn_msg)
|
|
|
|
return ret
|
|
end
|
|
|
|
local s_on_disconnect = this.on_disconnect
|
|
function this.on_disconnect(...)
|
|
local ret = s_on_disconnect(...)
|
|
if server then
|
|
this.alive = false
|
|
tally_counts()
|
|
end
|
|
return ret
|
|
end
|
|
|
|
local s_on_death = this.on_death
|
|
function this.on_death(...)
|
|
local ret = s_on_death(...)
|
|
if server then
|
|
this.alive = false
|
|
tally_counts()
|
|
end
|
|
return ret
|
|
end
|
|
|
|
return this
|
|
end
|
|
|