Files
wnsrc/gamemodes/terrortown/gamemode/cl_radar.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

323 lines
8.4 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Traitor radar rendering
local render = render
local surface = surface
local string = string
local player = player
local math = math
RADAR = {}
RADAR.targets = {}
RADAR.enable = false
RADAR.duration = 30
RADAR.endtime = 0
RADAR.bombs = {}
RADAR.bombs_count = 0
RADAR.repeating = true
RADAR.samples = {}
RADAR.samples_count = 0
RADAR.called_corpses = {}
function RADAR:EndScan()
self.enable = false
self.endtime = CurTime()
end
function RADAR:Clear()
self:EndScan()
self.bombs = {}
self.samples = {}
self.bombs_count = 0
self.samples_count = 0
end
function RADAR:Timeout()
self:EndScan()
if self.repeating and LocalPlayer() and LocalPlayer():IsActiveSpecial() and LocalPlayer():HasEquipmentItem(EQUIP_RADAR) then
RunConsoleCommand("ttt_radar_scan")
end
end
-- cache stuff we'll be drawing
function RADAR.CacheEnts()
-- also do some corpse cleanup here
for k, corpse in pairs(RADAR.called_corpses) do
if (corpse.called + 45) < CurTime() then
RADAR.called_corpses[k] = nil -- will make # inaccurate, no big deal
end
end
if RADAR.bombs_count == 0 then return end
-- Update bomb positions for those we know about
for idx, b in pairs(RADAR.bombs) do
local ent = Entity(idx)
if IsValid(ent) then
b.pos = ent:GetPos()
end
end
end
function RADAR.Bought(is_item, id)
if is_item and id == EQUIP_RADAR then
RunConsoleCommand("ttt_radar_scan")
end
end
hook.Add("TTTBoughtItem", "RadarBoughtItem", RADAR.Bought)
local function DrawTarget(tgt, size, offset, no_shrink)
local scrpos = tgt.pos:ToScreen() -- sweet
local sz = (IsOffScreen(scrpos) and (not no_shrink)) and size/2 or size
scrpos.x = math.Clamp(scrpos.x, sz, ScrW() - sz)
scrpos.y = math.Clamp(scrpos.y, sz, ScrH() - sz)
if IsOffScreen(scrpos) then return end
surface.DrawTexturedRect(scrpos.x - sz, scrpos.y - sz, sz * 2, sz * 2)
-- Drawing full size?
if sz == size then
local text = math.ceil(LocalPlayer():GetPos():Distance(tgt.pos))
local w, h = surface.GetTextSize(text)
-- Show range to target
surface.SetTextPos(scrpos.x - w/2, scrpos.y + (offset * sz) - h/2)
surface.DrawText(text)
if tgt.t then
-- Show time
text = util.SimpleTime(tgt.t - CurTime(), "%02i:%02i")
w, h = surface.GetTextSize(text)
surface.SetTextPos(scrpos.x - w / 2, scrpos.y + sz / 2)
surface.DrawText(text)
elseif tgt.nick then
-- Show nickname
text = tgt.nick
w, h = surface.GetTextSize(text)
surface.SetTextPos(scrpos.x - w / 2, scrpos.y + sz / 2)
surface.DrawText(text)
end
end
end
local indicator = surface.GetTextureID("effects/select_ring")
local c4warn = surface.GetTextureID("vgui/ttt/icon_c4warn")
local sample_scan = surface.GetTextureID("vgui/ttt/sample_scan")
local det_beacon = surface.GetTextureID("vgui/ttt/det_beacon")
local GetPTranslation = LANG.GetParamTranslation
local FormatTime = util.SimpleTime
local near_cursor_dist = 180
function RADAR:Draw(client)
if not client then return end
surface.SetFont("HudSelectionText")
-- C4 warnings
if self.bombs_count != 0 and client:IsActiveTraitor() then
surface.SetTexture(c4warn)
surface.SetTextColor(200, 55, 55, 220)
surface.SetDrawColor(255, 255, 255, 200)
for k, bomb in pairs(self.bombs) do
DrawTarget(bomb, 24, 0, true)
end
end
-- Corpse calls
if client:IsActiveDetective() and #self.called_corpses then
surface.SetTexture(det_beacon)
surface.SetTextColor(255, 255, 255, 240)
surface.SetDrawColor(255, 255, 255, 230)
for k, corpse in pairs(self.called_corpses) do
DrawTarget(corpse, 16, 0.5)
end
end
-- Samples
if self.samples_count != 0 then
surface.SetTexture(sample_scan)
surface.SetTextColor(200, 50, 50, 255)
surface.SetDrawColor(255, 255, 255, 240)
for k, sample in pairs(self.samples) do
DrawTarget(sample, 16, 0.5, true)
end
end
-- Player radar
if (not self.enable) or (not client:IsActiveSpecial()) then return end
surface.SetTexture(indicator)
local remaining = math.max(0, RADAR.endtime - CurTime())
local alpha_base = 50 + 180 * (remaining / RADAR.duration)
local mpos = Vector(ScrW() / 2, ScrH() / 2, 0)
local role, alpha, scrpos, md
for k, tgt in pairs(RADAR.targets) do
alpha = alpha_base
scrpos = tgt.pos:ToScreen()
if not scrpos.visible then
continue
end
md = mpos:Distance(Vector(scrpos.x, scrpos.y, 0))
if md < near_cursor_dist then
alpha = math.Clamp(alpha * (md / near_cursor_dist), 40, 230)
end
role = tgt.role or ROLE_INNOCENT
if role == ROLE_TRAITOR then
surface.SetDrawColor(255, 0, 0, alpha)
surface.SetTextColor(255, 0, 0, alpha)
elseif role == ROLE_DETECTIVE then
surface.SetDrawColor(0, 0, 255, alpha)
surface.SetTextColor(0, 0, 255, alpha)
elseif role == 3 then -- decoys
surface.SetDrawColor(150, 150, 150, alpha)
surface.SetTextColor(150, 150, 150, alpha)
else
surface.SetDrawColor(0, 255, 0, alpha)
surface.SetTextColor(0, 255, 0, alpha)
end
DrawTarget(tgt, 24, 0)
end
-- Time until next scan
surface.SetFont("TabLarge")
surface.SetTextColor(255, 0, 0, 230)
local text = GetPTranslation("radar_hud", {time = FormatTime(remaining, "%02i:%02i")})
local w, h = surface.GetTextSize(text)
surface.SetTextPos(36, ScrH() - 140 - h)
surface.DrawText(text)
end
local function ReceiveC4Warn()
local idx = net.ReadUInt(16)
local armed = net.ReadBit() == 1
if armed then
local pos = net.ReadVector()
local etime = net.ReadFloat()
RADAR.bombs[idx] = {pos=pos, t=etime}
else
RADAR.bombs[idx] = nil
end
RADAR.bombs_count = table.Count(RADAR.bombs)
end
net.Receive("TTT_C4Warn", ReceiveC4Warn)
local function ReceiveCorpseCall()
local pos = net.ReadVector()
table.insert(RADAR.called_corpses, {pos = pos, called = CurTime()})
end
net.Receive("TTT_CorpseCall", ReceiveCorpseCall)
local function ReceiveRadarScan()
local num_targets = net.ReadUInt(8)
RADAR.targets = {}
for i=1, num_targets do
local r = net.ReadUInt(2)
local pos = Vector()
pos.x = net.ReadInt(15)
pos.y = net.ReadInt(15)
pos.z = net.ReadInt(15)
table.insert(RADAR.targets, {role=r, pos=pos})
end
RADAR.enable = true
RADAR.endtime = CurTime() + RADAR.duration
timer.Create("radartimeout", RADAR.duration + 1, 1,
function() RADAR:Timeout() end)
end
net.Receive("TTT_Radar", ReceiveRadarScan)
local GetTranslation = LANG.GetTranslation
function RADAR.CreateMenu(parent, frame)
local w, h = parent:GetSize()
local dform = vgui.Create("DForm", parent)
dform:SetName(GetTranslation("radar_menutitle"))
dform:StretchToParent(0,0,0,0)
dform:SetAutoSize(false)
local owned = LocalPlayer():HasEquipmentItem(EQUIP_RADAR)
if not owned then
dform:Help(GetTranslation("radar_not_owned"))
return dform
end
local bw, bh = 100, 25
local dscan = vgui.Create("DButton", dform)
dscan:SetSize(bw, bh)
dscan:SetText(GetTranslation("radar_scan"))
dscan.DoClick = function(s)
s:SetDisabled(true)
RunConsoleCommand("ttt_radar_scan")
frame:Close()
end
dform:AddItem(dscan)
local dlabel = vgui.Create("DLabel", dform)
dlabel:SetText(GetPTranslation("radar_help", {num = RADAR.duration}))
dlabel:SetWrap(true)
dlabel:SetTall(50)
dform:AddItem(dlabel)
local dcheck = vgui.Create("DCheckBoxLabel", dform)
dcheck:SetText(GetTranslation("radar_auto"))
dcheck:SetIndent(5)
dcheck:SetValue(RADAR.repeating)
dcheck.OnChange = function(s, val)
RADAR.repeating = val
end
dform:AddItem(dcheck)
dform.Think = function(s)
if RADAR.enable or not owned then
dscan:SetDisabled(true)
else
dscan:SetDisabled(false)
end
end
dform:SetVisible(true)
return dform
end