Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Real-time editor
Hide unchanged lines
Disable line wrap
Layout
Split
Unified
Diff precision
Smart
Word
Char
Syntax highlighting
Choose syntax
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
Untitled diff
Created
10 years ago
Diff never expires
Clear
Export
Share
Explain
30 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
503 lines
Copy
35 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
509 lines
Copy
-- Body search popup
-- Body search popup
local T = LANG.GetTranslation
local T = LANG.GetTranslation
local PT = LANG.GetParamTranslation
local PT = LANG.GetParamTranslation
local is_dmg = util.BitSet
local is_dmg = util.BitSet
Copy
Copied
Copy
Copied
local dtt = { search_dmg_crush = DMG_CRUSH, search_dmg_bullet = DMG_BULLET, search_dmg_fall = DMG_FALL,
search_dmg_boom = DMG_BLAST, search_dmg_club = DMG_CLUB, search_dmg_drown = DMG_DROWN, search_dmg_stab = DMG_SLASH,
search_dmg_burn = DMG_BURN, search_dmg_tele = DMG_SONIC, search_dmg_car = DMG_VEHICLE }
-- "From his body you can tell XXX"
-- "From his body you can tell XXX"
local function DmgToText(d)
local function DmgToText(d)
Copy
Copied
Copy
Copied
for k, v in pairs(dtt) do
if is_dmg(d,
DMG_CRUSH
) then
if is_dmg(d,
v
) then
return T("search_dmg_crush")
return T(k)
elseif is_dmg(d, DMG_BULLET) then
end
return T("search_dmg_bullet")
end
elseif is_dmg(d, DMG_FALL) then
if is_dmg(d,
DMG_DIRECT) then
return T("search_dmg_fall")
elseif is_dmg(d, DMG_BLAST) then
return T("search_dmg_boom")
elseif is_dmg(d, DMG_CLUB) then
return T("search_dmg_club")
elseif is_dmg(d, DMG_DROWN) then
return T("search_dmg_drown")
elseif is_dmg(d, DMG_SLASH) then
return T("search_dmg_stab")
elseif is_dmg(d, DMG_BURN) or is_dmg(d,
DMG_DIRECT) then
return T("search_dmg_burn")
return T("search_dmg_burn")
Copy
Copied
Copy
Copied
elseif is_dmg(d, DMG_SONIC) then
return T("search_dmg_tele")
elseif is_dmg(d, DMG_VEHICLE) then
return T("search_dmg_car")
else
return T("search_dmg_other")
end
end
Copy
Copied
Copy
Copied
return T("search_dmg_other")
end
end
-- Info type to icon mapping
-- Info type to icon mapping
-- Some icons have different appearances based on the data value. These have a
-- Some icons have different appearances based on the data value. These have a
-- separate table inside the TypeToMat table.
-- separate table inside the TypeToMat table.
-- Those that have a lot of possible data values are defined separately, either
-- Those that have a lot of possible data values are defined separately, either
-- as a function or a table.
-- as a function or a table.
Copy
Copied
Copy
Copied
local dtm = { bullet = DMG_BULLET, rock = DMG_CRUSH, splode = DMG_BLAST, fall = DMG_FALL, fire = DMG_BURN }
local function DmgToMat(d)
local function DmgToMat(d)
Copy
Copied
Copy
Copied
for k, v in pairs(dtm) do
if is_dmg(d,
DMG_BULLET
) then
if is_dmg(d,
v
) then
return "bullet"
return k
elseif is_dmg(d, DMG_CRUSH) then
end
return "rock"
end
elseif is_dmg(d, DMG_BLAST) then
if
is_dmg(d,
DMG_DIRECT) then
return "splode"
elseif is_dmg(d, DMG_FALL) then
return "fall"
elseif
is_dmg(d,
DMG_BURN) or is_dmg(d,
DMG_DIRECT) then
return "fire"
return "fire"
else
else
return "skull"
return "skull"
end
end
end
end
local function WeaponToIcon(d)
local function WeaponToIcon(d)
local wep = util.WeaponForClass(d)
local wep = util.WeaponForClass(d)
Copy
Copied
Copy
Copied
return wep and wep.Icon or "
vgui
/ttt/icon_nades"
return wep and wep.Icon or "
VGUI
/ttt/icon_nades"
end
end
local TypeToMat = {
local TypeToMat = {
nick="id",
nick="id",
words="halp",
words="halp",
eq_armor="armor",
eq_armor="armor",
eq_radar="radar",
eq_radar="radar",
eq_disg="disguise",
eq_disg="disguise",
role={[ROLE_TRAITOR]="traitor", [ROLE_DETECTIVE]="det", [ROLE_INNOCENT]="inno"},
role={[ROLE_TRAITOR]="traitor", [ROLE_DETECTIVE]="det", [ROLE_INNOCENT]="inno"},
c4="code",
c4="code",
dmg=DmgToMat,
dmg=DmgToMat,
wep=WeaponToIcon,
wep=WeaponToIcon,
head="head",
head="head",
dtime="time",
dtime="time",
stime="wtester",
stime="wtester",
lastid="lastid",
lastid="lastid",
kills="list"
kills="list"
Copy
Copied
Copy
Copied
}
}
;
-- Accessor for better fail handling
-- Accessor for better fail handling
local function IconForInfoType(t, data)
local function IconForInfoType(t, data)
Copy
Copied
Copy
Copied
local base = "
vgui
/ttt/icon_"
local base = "
VGUI
/ttt/icon_"
local mat = TypeToMat[t]
local mat = TypeToMat[t]
if type(mat) == "table" then
if type(mat) == "table" then
mat = mat[data]
mat = mat[data]
elseif type(mat) == "function" then
elseif type(mat) == "function" then
mat = mat(data)
mat = mat(data)
end
end
if not mat then
if not mat then
mat = TypeToMat["nick"]
mat = TypeToMat["nick"]
end
end
-- ugly special casing for weapons, because they are more likely to be
-- ugly special casing for weapons, because they are more likely to be
-- customized and hence need more freedom in their icon filename
-- customized and hence need more freedom in their icon filename
if t != "wep" then
if t != "wep" then
return base .. mat
return base .. mat
else
else
return mat
return mat
end
end
end
end
function PreprocSearch(raw)
function PreprocSearch(raw)
local search = {}
local search = {}
for t, d in pairs(raw) do
for t, d in pairs(raw) do
search[t] = {img=nil, text="", p=10}
search[t] = {img=nil, text="", p=10}
if t == "nick" then
if t == "nick" then
search[t].text = PT("search_nick", {player = d})
search[t].text = PT("search_nick", {player = d})
search[t].p = 1
search[t].p = 1
search[t].nick = d
search[t].nick = d
elseif t == "role" then
elseif t == "role" then
if d == ROLE_TRAITOR then
if d == ROLE_TRAITOR then
search[t].text = T("search_role_t")
search[t].text = T("search_role_t")
elseif d == ROLE_DETECTIVE then
elseif d == ROLE_DETECTIVE then
search[t].text = T("search_role_d")
search[t].text = T("search_role_d")
else
else
search[t].text = T("search_role_i")
search[t].text = T("search_role_i")
end
end
search[t].p = 2
search[t].p = 2
elseif t == "words" then
elseif t == "words" then
if d != "" then
if d != "" then
-- only append "--" if there's no ending interpunction
-- only append "--" if there's no ending interpunction
local final = string.match(d, "[\\.\\!\\?]$") != nil
local final = string.match(d, "[\\.\\!\\?]$") != nil
search[t].text = PT("search_words", {lastwords = d .. (final and "" or "--.")})
search[t].text = PT("search_words", {lastwords = d .. (final and "" or "--.")})
end
end
elseif t == "eq_armor" then
elseif t == "eq_armor" then
if d then
if d then
search[t].text = T("search_armor")
search[t].text = T("search_armor")
search[t].p = 17
search[t].p = 17
end
end
elseif t == "eq_disg" then
elseif t == "eq_disg" then
if d then
if d then
search[t].text = T("search_disg")
search[t].text = T("search_disg")
search[t].p = 18
search[t].p = 18
end
end
elseif t == "eq_radar" then
elseif t == "eq_radar" then
if d then
if d then
search[t].text = T("search_radar")
search[t].text = T("search_radar")
search[t].p = 19
search[t].p = 19
end
end
elseif t == "c4" then
elseif t == "c4" then
if d > 0 then
if d > 0 then
search[t].text= PT("search_c4", {num = d})
search[t].text= PT("search_c4", {num = d})
end
end
elseif t == "dmg" then
elseif t == "dmg" then
search[t].text = DmgToText(d)
search[t].text = DmgToText(d)
search[t].p = 12
search[t].p = 12
elseif t == "wep" then
elseif t == "wep" then
local wep = util.WeaponForClass(d)
local wep = util.WeaponForClass(d)
local wname = wep and LANG.TryTranslation(wep.PrintName)
local wname = wep and LANG.TryTranslation(wep.PrintName)
if wname then
if wname then
search[t].text = PT("search_weapon", {weapon = wname})
search[t].text = PT("search_weapon", {weapon = wname})
end
end
elseif t == "head" then
elseif t == "head" then
if d then
if d then
search[t].text = T("search_head")
search[t].text = T("search_head")
end
end
search[t].p = 15
search[t].p = 15
elseif t == "dtime" then
elseif t == "dtime" then
if d != 0 then
if d != 0 then
local ftime = util.SimpleTime(d, "%02i:%02i")
local ftime = util.SimpleTime(d, "%02i:%02i")
search[t].text = PT("search_time", {time = ftime})
search[t].text = PT("search_time", {time = ftime})
search[t].text_icon = ftime
search[t].text_icon = ftime
search[t].p = 8
search[t].p = 8
end
end
elseif t == "stime" then
elseif t == "stime" then
if d > 0 then
if d > 0 then
local ftime = util.SimpleTime(d, "%02i:%02i")
local ftime = util.SimpleTime(d, "%02i:%02i")
search[t].text = PT("search_dna", {time = ftime})
search[t].text = PT("search_dna", {time = ftime})
search[t].text_icon = ftime
search[t].text_icon = ftime
end
end
elseif t == "kills" then
elseif t == "kills" then
local num = table.Count(d)
local num = table.Count(d)
if num == 1 then
if num == 1 then
local vic = Entity(d[1])
local vic = Entity(d[1])
local dc = d[1] == -1 -- disconnected
local dc = d[1] == -1 -- disconnected
if dc or (IsValid(vic) and vic:IsPlayer()) then
if dc or (IsValid(vic) and vic:IsPlayer()) then
search[t].text = PT("search_kills1", {player = (dc and "<Disconnected>" or vic:Nick())})
search[t].text = PT("search_kills1", {player = (dc and "<Disconnected>" or vic:Nick())})
end
end
elseif num > 1 then
elseif num > 1 then
local txt = T("search_kills2") .. "\n"
local txt = T("search_kills2") .. "\n"
local nicks = {}
local nicks = {}
for k, idx in pairs(d) do
for k, idx in pairs(d) do
local vic = Entity(idx)
local vic = Entity(idx)
local dc = idx == -1
local dc = idx == -1
if dc or (IsValid(vic) and vic:IsPlayer()) then
if dc or (IsValid(vic) and vic:IsPlayer()) then
table.insert(nicks, (dc and "<Disconnected>" or vic:Nick()))
table.insert(nicks, (dc and "<Disconnected>" or vic:Nick()))
end
end
end
end
local last = #nicks
local last = #nicks
txt = txt .. table.concat(nicks, "\n", 1, last)
txt = txt .. table.concat(nicks, "\n", 1, last)
search[t].text = txt
search[t].text = txt
end
end
search[t].p = 30
search[t].p = 30
elseif t == "lastid" then
elseif t == "lastid" then
if d and d.idx != -1 then
if d and d.idx != -1 then
local ent = Entity(d.idx)
local ent = Entity(d.idx)
if IsValid(ent) and ent:IsPlayer() then
if IsValid(ent) and ent:IsPlayer() then
search[t].text = PT("search_eyes", {player = ent:Nick()})
search[t].text = PT("search_eyes", {player = ent:Nick()})
search[t].ply = ent
search[t].ply = ent
end
end
end
end
else
else
-- Not matching a type, so don't display
-- Not matching a type, so don't display
search[t] = nil
search[t] = nil
end
end
-- anything matching a type but not given a text should be removed
-- anything matching a type but not given a text should be removed
if search[t] and search[t].text == "" then
if search[t] and search[t].text == "" then
search[t] = nil
search[t] = nil
end
end
-- if there's still something here, we'll be showing it, so find an icon
-- if there's still something here, we'll be showing it, so find an icon
if search[t] then
if search[t] then
search[t].img = IconForInfoType(t, d)
search[t].img = IconForInfoType(t, d)
end
end
end
end
Copy
Copied
Copy
Copied
hook.Call("TTTBodySearchPopulate", nil, search, raw)
return search
return search
end
end
-- Returns a function meant to override OnActivePanelChanged, which modifies
-- Returns a function meant to override OnActivePanelChanged, which modifies
-- dactive and dtext based on the search information that is associated with the
-- dactive and dtext based on the search information that is associated with the
-- newly selected panel
-- newly selected panel
local function SearchInfoController(search, dactive, dtext)
local function SearchInfoController(search, dactive, dtext)
return function(s, pold, pnew)
return function(s, pold, pnew)
local t = pnew.info_type
local t = pnew.info_type
local data = search[t]
local data = search[t]
if not data then
if not data then
ErrorNoHalt("Search: data not found", t, data,"\n")
ErrorNoHalt("Search: data not found", t, data,"\n")
return
return
end
end
-- If wrapping is on, the Label's SizeToContentsY misbehaves for
-- If wrapping is on, the Label's SizeToContentsY misbehaves for
-- text that does not need wrapping. I long ago stopped wondering
-- text that does not need wrapping. I long ago stopped wondering
-- "why" when it comes to VGUI. Apply hack, move on.
-- "why" when it comes to VGUI. Apply hack, move on.
dtext:GetLabel():SetWrap(#data.text > 50)
dtext:GetLabel():SetWrap(#data.text > 50)
dtext:SetText(data.text)
dtext:SetText(data.text)
dactive:SetImage(data.img)
dactive:SetImage(data.img)
end
end
end
end
local function ShowSearchScreen(search_raw)
local function ShowSearchScreen(search_raw)
local client = LocalPlayer()
local client = LocalPlayer()
if not IsValid(client) then return end
if not IsValid(client) then return end
local m = 8
local m = 8
local bw, bh = 100, 25
local bw, bh = 100, 25
local w, h = 410, 260
local w, h = 410, 260
local rw, rh = (w - m*2), (h - 25 - m*2)
local rw, rh = (w - m*2), (h - 25 - m*2)
local rx, ry = 0, 0
local rx, ry = 0, 0
local rows = 1
local rows = 1
local listw, listh = rw, (64 * rows + 6)
local listw, listh = rw, (64 * rows + 6)
local listx, listy = rx, ry
local listx, listy = rx, ry
ry = ry + listh + m*2
ry = ry + listh + m*2
rx = m
rx = m
local descw, desch = rw - m*2, 80
local descw, desch = rw - m*2, 80
local descx, descy = rx, ry
local descx, descy = rx, ry
ry = ry + desch + m
ry = ry + desch + m
local butx, buty = rx, ry
local butx, buty = rx, ry
local dframe = vgui.Create("DFrame")
local dframe = vgui.Create("DFrame")
dframe:SetSize(w, h)
dframe:SetSize(w, h)
dframe:Center()
dframe:Center()
dframe:SetTitle(T("search_title") .. " - " .. search_raw.nick or "???")
dframe:SetTitle(T("search_title") .. " - " .. search_raw.nick or "???")
dframe:SetVisible(true)
dframe:SetVisible(true)
dframe:ShowCloseButton(true)
dframe:ShowCloseButton(true)
dframe:SetMouseInputEnabled(true)
dframe:SetMouseInputEnabled(true)
dframe:SetKeyboardInputEnabled(true)
dframe:SetKeyboardInputEnabled(true)
dframe:SetDeleteOnClose(true)
dframe:SetDeleteOnClose(true)
dframe.OnKeyCodePressed = util.BasicKeyHandler
dframe.OnKeyCodePressed = util.BasicKeyHandler
-- contents wrapper
-- contents wrapper
local dcont = vgui.Create("DPanel", dframe)
local dcont = vgui.Create("DPanel", dframe)
dcont:SetPaintBackground(false)
dcont:SetPaintBackground(false)
dcont:SetSize(rw, rh)
dcont:SetSize(rw, rh)
dcont:SetPos(m, 25 + m)
dcont:SetPos(m, 25 + m)
-- icon list
-- icon list
local dlist = vgui.Create("DPanelSelect", dcont)
local dlist = vgui.Create("DPanelSelect", dcont)
dlist:SetPos(listx, listy)
dlist:SetPos(listx, listy)
dlist:SetSize(listw, listh)
dlist:SetSize(listw, listh)
dlist:EnableHorizontal(true)
dlist:EnableHorizontal(true)
dlist:SetSpacing(1)
dlist:SetSpacing(1)
dlist:SetPadding(2)
dlist:SetPadding(2)
if dlist.VBar then
if dlist.VBar then
dlist.VBar:Remove()
dlist.VBar:Remove()
dlist.VBar = nil
dlist.VBar = nil
end
end
-- description area
-- description area
local dscroll = vgui.Create("DHorizontalScroller", dlist)
local dscroll = vgui.Create("DHorizontalScroller", dlist)
dscroll:StretchToParent(3,3,3,3)
dscroll:StretchToParent(3,3,3,3)
local ddesc = vgui.Create("ColoredBox", dcont)
local ddesc = vgui.Create("ColoredBox", dcont)
ddesc:SetColor(Color(50, 50, 50))
ddesc:SetColor(Color(50, 50, 50))
ddesc:SetName(T("search_info"))
ddesc:SetName(T("search_info"))
ddesc:SetPos(descx, descy)
ddesc:SetPos(descx, descy)
ddesc:SetSize(descw, desch)
ddesc:SetSize(descw, desch)
local dactive = vgui.Create("DImage", ddesc)
local dactive = vgui.Create("DImage", ddesc)
Copy
Copied
Copy
Copied
dactive:SetImage("
vgui
/ttt/icon_id")
dactive:SetImage("
VGUI
/ttt/icon_id")
dactive:SetPos(m, m)
dactive:SetPos(m, m)
dactive:SetSize(64, 64)
dactive:SetSize(64, 64)
local dtext = vgui.Create("ScrollLabel", ddesc)
local dtext = vgui.Create("ScrollLabel", ddesc)
dtext:SetSize(descw - 120, desch - m*2)
dtext:SetSize(descw - 120, desch - m*2)
dtext:MoveRightOf(dactive, m*2)
dtext:MoveRightOf(dactive, m*2)
dtext:AlignTop(m)
dtext:AlignTop(m)
dtext:SetText("...")
dtext:SetText("...")
-- buttons
-- buttons
local by = rh - bh - (m/2)
local by = rh - bh - (m/2)
local dident = vgui.Create("DButton", dcont)
local dident = vgui.Create("DButton", dcont)
dident:SetPos(m, by)
dident:SetPos(m, by)
dident:SetSize(bw,bh)
dident:SetSize(bw,bh)
dident:SetText(T("search_confirm"))
dident:SetText(T("search_confirm"))
local id = search_raw.eidx + search_raw.dtime
local id = search_raw.eidx + search_raw.dtime
dident.DoClick = function() RunConsoleCommand("ttt_confirm_death", search_raw.eidx, id) end
dident.DoClick = function() RunConsoleCommand("ttt_confirm_death", search_raw.eidx, id) end
dident:SetDisabled(client:IsSpec() or (not client:KeyDownLast(IN_WALK)))
dident:SetDisabled(client:IsSpec() or (not client:KeyDownLast(IN_WALK)))
local dcall = vgui.Create("DButton", dcont)
local dcall = vgui.Create("DButton", dcont)
dcall:SetPos(m*2 + bw, by)
dcall:SetPos(m*2 + bw, by)
dcall:SetSize(bw, bh)
dcall:SetSize(bw, bh)
dcall:SetText(T("search_call"))
dcall:SetText(T("search_call"))
dcall.DoClick = function(s)
dcall.DoClick = function(s)
client.called_corpses = client.called_corpses or {}
client.called_corpses = client.called_corpses or {}
table.insert(client.called_corpses, search_raw.eidx)
table.insert(client.called_corpses, search_raw.eidx)
s:SetDisabled(true)
s:SetDisabled(true)
RunConsoleCommand("ttt_call_detective", search_raw.eidx)
RunConsoleCommand("ttt_call_detective", search_raw.eidx)
end
end
dcall:SetDisabled(client:IsSpec() or table.HasValue(client.called_corpses or {}, search_raw.eidx))
dcall:SetDisabled(client:IsSpec() or table.HasValue(client.called_corpses or {}, search_raw.eidx))
local dconfirm = vgui.Create("DButton", dcont)
local dconfirm = vgui.Create("DButton", dcont)
dconfirm:SetPos(rw - m - bw, by)
dconfirm:SetPos(rw - m - bw, by)
dconfirm:SetSize(bw, bh)
dconfirm:SetSize(bw, bh)
dconfirm:SetText(T("close"))
dconfirm:SetText(T("close"))
dconfirm.DoClick = function() dframe:Close() end
dconfirm.DoClick = function() dframe:Close() end
-- Finalize search data, prune stuff that won't be shown etc
-- Finalize search data, prune stuff that won't be shown etc
-- search is a table of tables that have an img and text key
-- search is a table of tables that have an img and text key
local search = PreprocSearch(search_raw)
local search = PreprocSearch(search_raw)
-- Install info controller that will link up the icons to the text etc
-- Install info controller that will link up the icons to the text etc
dlist.OnActivePanelChanged = SearchInfoController(search, dactive, dtext)
dlist.OnActivePanelChanged = SearchInfoController(search, dactive, dtext)
-- Create table of SimpleIcons, each standing for a piece of search
-- Create table of SimpleIcons, each standing for a piece of search
-- information.
-- information.
local start_icon = nil
local start_icon = nil
for t, info in SortedPairsByMemberValue(search, "p") do
for t, info in SortedPairsByMemberValue(search, "p") do
local ic = nil
local ic = nil
-- Certain items need a special icon conveying additional information
-- Certain items need a special icon conveying additional information
if t == "nick" then
if t == "nick" then
local name = info.nick
local name = info.nick
local avply = IsValid(search_raw.owner) and search_raw.owner or nil
local avply = IsValid(search_raw.owner) and search_raw.owner or nil
Copy
Copied
Copy
Copied
ic = vgui.Create("SimpleIcon
Avatar
", dlist)
ic = vgui.Create("SimpleIcon
", dlist)
ic:SetPlayer(avply)
ic:SetPlayer(avply)
start_icon = ic
start_icon = ic
elseif t == "lastid" then
elseif t == "lastid" then
ic = vgui.Create("SimpleIconAvatar", dlist)
ic = vgui.Create("SimpleIconAvatar", dlist)
ic:SetPlayer(info.ply)
ic:SetPlayer(info.ply)
ic:SetAvatarSize(24)
ic:SetAvatarSize(24)
elseif info.text_icon then
elseif info.text_icon then
ic = vgui.Create("SimpleIconLabelled", dlist)
ic = vgui.Create("SimpleIconLabelled", dlist)
ic:SetIconText(info.text_icon)
ic:SetIconText(info.text_icon)
else
else
ic = vgui.Create("SimpleIcon", dlist)
ic = vgui.Create("SimpleIcon", dlist)
end
end
ic:SetIconSize(64)
ic:SetIconSize(64)
ic:SetIcon(info.img)
ic:SetIcon(info.img)
ic.info_type = t
ic.info_type = t
dlist:AddPanel(ic)
dlist:AddPanel(ic)
dscroll:AddPanel(ic)
dscroll:AddPanel(ic)
end
end
dlist:SelectPanel(start_icon)
dlist:SelectPanel(start_icon)
dframe:MakePopup()
dframe:MakePopup()
end
end
local function StoreSearchResult(search)
local function StoreSearchResult(search)
if search.owner then
if search.owner then
-- if existing result was not ours, it was detective's, and should not
-- if existing result was not ours, it was detective's, and should not
-- be overwritten
-- be overwritten
local ply = search.owner
local ply = search.owner
if (not ply.search_result) or ply.search_result.show then
if (not ply.search_result) or ply.search_result.show then
ply.search_result = search
ply.search_result = search
-- this is useful for targetid
-- this is useful for targetid
local rag = Entity(search.eidx)
local rag = Entity(search.eidx)
if IsValid(rag) then
if IsValid(rag) then
rag.search_result = search
rag.search_result = search
end
end
end
end
end
end
end
end
local function bitsRequired(num)
local function bitsRequired(num)
local bits, max = 0, 1
local bits, max = 0, 1
while max <= num do
while max <= num do
bits = bits + 1
bits = bits + 1
max = max + max
max = max + max
end
end
return bits
return bits
end
end
local search = {}
local search = {}
local function ReceiveRagdollSearch()
local function ReceiveRagdollSearch()
search = {}
search = {}
-- Basic info
-- Basic info
search.eidx = net.ReadUInt(16)
search.eidx = net.ReadUInt(16)
search.owner = Entity(net.ReadUInt(8))
search.owner = Entity(net.ReadUInt(8))
if not (IsValid(search.owner) and search.owner:IsPlayer() and (not search.owner:Alive())) then
if not (IsValid(search.owner) and search.owner:IsPlayer() and (not search.owner:Alive())) then
search.owner = nil
search.owner = nil
end
end
search.nick = net.ReadString()
search.nick = net.ReadString()
-- Equipment
-- Equipment
local eq = net.ReadUInt(16)
local eq = net.ReadUInt(16)
-- All equipment pieces get their own icon
-- All equipment pieces get their own icon
search.eq_armor = util.BitSet(eq, EQUIP_ARMOR)
search.eq_armor = util.BitSet(eq, EQUIP_ARMOR)
search.eq_radar = util.BitSet(eq, EQUIP_RADAR)
search.eq_radar = util.BitSet(eq, EQUIP_RADAR)
search.eq_disg = util.BitSet(eq, EQUIP_DISGUISE)
search.eq_disg = util.BitSet(eq, EQUIP_DISGUISE)
-- Traitor things
-- Traitor things
search.role = net.ReadUInt(2)
search.role = net.ReadUInt(2)
search.c4 = net.ReadInt(bitsRequired(C4_WIRE_COUNT) + 1)
search.c4 = net.ReadInt(bitsRequired(C4_WIRE_COUNT) + 1)
-- Kill info
-- Kill info
search.dmg = net.ReadUInt(30)
search.dmg = net.ReadUInt(30)
search.wep = net.ReadString()
search.wep = net.ReadString()
search.head = net.ReadBit() == 1
search.head = net.ReadBit() == 1
search.dtime = net.ReadInt(16)
search.dtime = net.ReadInt(16)
search.stime = net.ReadInt(16)
search.stime = net.ReadInt(16)
-- Players killed
-- Players killed
local num_kills = net.ReadUInt(8)
local num_kills = net.ReadUInt(8)
if num_kills > 0 then
if num_kills > 0 then
search.kills = {}
search.kills = {}
for i=1,num_kills do
for i=1,num_kills do
table.insert(search.kills, net.ReadUInt(8))
table.insert(search.kills, net.ReadUInt(8))
end
end
else
else
search.kills = nil
search.kills = nil
end
end
search.lastid = {idx=net.ReadUInt(8)}
search.lastid = {idx=net.ReadUInt(8)}
-- should we show a menu for this result?
-- should we show a menu for this result?
search.finder = net.ReadUInt(8)
search.finder = net.ReadUInt(8)
search.show = (LocalPlayer():EntIndex() == search.finder)
search.show = (LocalPlayer():EntIndex() == search.finder)
--
--
-- last words
-- last words
--
--
local words = net.ReadString()
local words = net.ReadString()
search.words = (words ~= "") and words or nil
search.words = (words ~= "") and words or nil
Copy
Copied
Copy
Copied
hook.Call("TTTBodySearchEquipment", nil, search, eq)
if search.show then
if search.show then
ShowSearchScreen(search)
ShowSearchScreen(search)
end
end
StoreSearchResult(search)
StoreSearchResult(search)
search = nil
search = nil
end
end
net.Receive("TTT_RagdollSearch", ReceiveRagdollSearch)
net.Receive("TTT_RagdollSearch", ReceiveRagdollSearch)
Copy
Copied
Copy
Copied
Saved diffs
Original text
Open file
-- Body search popup local T = LANG.GetTranslation local PT = LANG.GetParamTranslation local is_dmg = util.BitSet local dtt = { search_dmg_crush = DMG_CRUSH, search_dmg_bullet = DMG_BULLET, search_dmg_fall = DMG_FALL, search_dmg_boom = DMG_BLAST, search_dmg_club = DMG_CLUB, search_dmg_drown = DMG_DROWN, search_dmg_stab = DMG_SLASH, search_dmg_burn = DMG_BURN, search_dmg_tele = DMG_SONIC, search_dmg_car = DMG_VEHICLE } -- "From his body you can tell XXX" local function DmgToText(d) for k, v in pairs(dtt) do if is_dmg(d, v) then return T(k) end end if is_dmg(d, DMG_DIRECT) then return T("search_dmg_burn") end return T("search_dmg_other") end -- Info type to icon mapping -- Some icons have different appearances based on the data value. These have a -- separate table inside the TypeToMat table. -- Those that have a lot of possible data values are defined separately, either -- as a function or a table. local dtm = { bullet = DMG_BULLET, rock = DMG_CRUSH, splode = DMG_BLAST, fall = DMG_FALL, fire = DMG_BURN } local function DmgToMat(d) for k, v in pairs(dtm) do if is_dmg(d, v) then return k end end if is_dmg(d, DMG_DIRECT) then return "fire" else return "skull" end end local function WeaponToIcon(d) local wep = util.WeaponForClass(d) return wep and wep.Icon or "vgui/ttt/icon_nades" end local TypeToMat = { nick="id", words="halp", eq_armor="armor", eq_radar="radar", eq_disg="disguise", role={[ROLE_TRAITOR]="traitor", [ROLE_DETECTIVE]="det", [ROLE_INNOCENT]="inno"}, c4="code", dmg=DmgToMat, wep=WeaponToIcon, head="head", dtime="time", stime="wtester", lastid="lastid", kills="list" } -- Accessor for better fail handling local function IconForInfoType(t, data) local base = "vgui/ttt/icon_" local mat = TypeToMat[t] if type(mat) == "table" then mat = mat[data] elseif type(mat) == "function" then mat = mat(data) end if not mat then mat = TypeToMat["nick"] end -- ugly special casing for weapons, because they are more likely to be -- customized and hence need more freedom in their icon filename if t != "wep" then return base .. mat else return mat end end function PreprocSearch(raw) local search = {} for t, d in pairs(raw) do search[t] = {img=nil, text="", p=10} if t == "nick" then search[t].text = PT("search_nick", {player = d}) search[t].p = 1 search[t].nick = d elseif t == "role" then if d == ROLE_TRAITOR then search[t].text = T("search_role_t") elseif d == ROLE_DETECTIVE then search[t].text = T("search_role_d") else search[t].text = T("search_role_i") end search[t].p = 2 elseif t == "words" then if d != "" then -- only append "--" if there's no ending interpunction local final = string.match(d, "[\\.\\!\\?]$") != nil search[t].text = PT("search_words", {lastwords = d .. (final and "" or "--.")}) end elseif t == "eq_armor" then if d then search[t].text = T("search_armor") search[t].p = 17 end elseif t == "eq_disg" then if d then search[t].text = T("search_disg") search[t].p = 18 end elseif t == "eq_radar" then if d then search[t].text = T("search_radar") search[t].p = 19 end elseif t == "c4" then if d > 0 then search[t].text= PT("search_c4", {num = d}) end elseif t == "dmg" then search[t].text = DmgToText(d) search[t].p = 12 elseif t == "wep" then local wep = util.WeaponForClass(d) local wname = wep and LANG.TryTranslation(wep.PrintName) if wname then search[t].text = PT("search_weapon", {weapon = wname}) end elseif t == "head" then if d then search[t].text = T("search_head") end search[t].p = 15 elseif t == "dtime" then if d != 0 then local ftime = util.SimpleTime(d, "%02i:%02i") search[t].text = PT("search_time", {time = ftime}) search[t].text_icon = ftime search[t].p = 8 end elseif t == "stime" then if d > 0 then local ftime = util.SimpleTime(d, "%02i:%02i") search[t].text = PT("search_dna", {time = ftime}) search[t].text_icon = ftime end elseif t == "kills" then local num = table.Count(d) if num == 1 then local vic = Entity(d[1]) local dc = d[1] == -1 -- disconnected if dc or (IsValid(vic) and vic:IsPlayer()) then search[t].text = PT("search_kills1", {player = (dc and "<Disconnected>" or vic:Nick())}) end elseif num > 1 then local txt = T("search_kills2") .. "\n" local nicks = {} for k, idx in pairs(d) do local vic = Entity(idx) local dc = idx == -1 if dc or (IsValid(vic) and vic:IsPlayer()) then table.insert(nicks, (dc and "<Disconnected>" or vic:Nick())) end end local last = #nicks txt = txt .. table.concat(nicks, "\n", 1, last) search[t].text = txt end search[t].p = 30 elseif t == "lastid" then if d and d.idx != -1 then local ent = Entity(d.idx) if IsValid(ent) and ent:IsPlayer() then search[t].text = PT("search_eyes", {player = ent:Nick()}) search[t].ply = ent end end else -- Not matching a type, so don't display search[t] = nil end -- anything matching a type but not given a text should be removed if search[t] and search[t].text == "" then search[t] = nil end -- if there's still something here, we'll be showing it, so find an icon if search[t] then search[t].img = IconForInfoType(t, d) end end hook.Call("TTTBodySearchPopulate", nil, search, raw) return search end -- Returns a function meant to override OnActivePanelChanged, which modifies -- dactive and dtext based on the search information that is associated with the -- newly selected panel local function SearchInfoController(search, dactive, dtext) return function(s, pold, pnew) local t = pnew.info_type local data = search[t] if not data then ErrorNoHalt("Search: data not found", t, data,"\n") return end -- If wrapping is on, the Label's SizeToContentsY misbehaves for -- text that does not need wrapping. I long ago stopped wondering -- "why" when it comes to VGUI. Apply hack, move on. dtext:GetLabel():SetWrap(#data.text > 50) dtext:SetText(data.text) dactive:SetImage(data.img) end end local function ShowSearchScreen(search_raw) local client = LocalPlayer() if not IsValid(client) then return end local m = 8 local bw, bh = 100, 25 local w, h = 410, 260 local rw, rh = (w - m*2), (h - 25 - m*2) local rx, ry = 0, 0 local rows = 1 local listw, listh = rw, (64 * rows + 6) local listx, listy = rx, ry ry = ry + listh + m*2 rx = m local descw, desch = rw - m*2, 80 local descx, descy = rx, ry ry = ry + desch + m local butx, buty = rx, ry local dframe = vgui.Create("DFrame") dframe:SetSize(w, h) dframe:Center() dframe:SetTitle(T("search_title") .. " - " .. search_raw.nick or "???") dframe:SetVisible(true) dframe:ShowCloseButton(true) dframe:SetMouseInputEnabled(true) dframe:SetKeyboardInputEnabled(true) dframe:SetDeleteOnClose(true) dframe.OnKeyCodePressed = util.BasicKeyHandler -- contents wrapper local dcont = vgui.Create("DPanel", dframe) dcont:SetPaintBackground(false) dcont:SetSize(rw, rh) dcont:SetPos(m, 25 + m) -- icon list local dlist = vgui.Create("DPanelSelect", dcont) dlist:SetPos(listx, listy) dlist:SetSize(listw, listh) dlist:EnableHorizontal(true) dlist:SetSpacing(1) dlist:SetPadding(2) if dlist.VBar then dlist.VBar:Remove() dlist.VBar = nil end -- description area local dscroll = vgui.Create("DHorizontalScroller", dlist) dscroll:StretchToParent(3,3,3,3) local ddesc = vgui.Create("ColoredBox", dcont) ddesc:SetColor(Color(50, 50, 50)) ddesc:SetName(T("search_info")) ddesc:SetPos(descx, descy) ddesc:SetSize(descw, desch) local dactive = vgui.Create("DImage", ddesc) dactive:SetImage("vgui/ttt/icon_id") dactive:SetPos(m, m) dactive:SetSize(64, 64) local dtext = vgui.Create("ScrollLabel", ddesc) dtext:SetSize(descw - 120, desch - m*2) dtext:MoveRightOf(dactive, m*2) dtext:AlignTop(m) dtext:SetText("...") -- buttons local by = rh - bh - (m/2) local dident = vgui.Create("DButton", dcont) dident:SetPos(m, by) dident:SetSize(bw,bh) dident:SetText(T("search_confirm")) local id = search_raw.eidx + search_raw.dtime dident.DoClick = function() RunConsoleCommand("ttt_confirm_death", search_raw.eidx, id) end dident:SetDisabled(client:IsSpec() or (not client:KeyDownLast(IN_WALK))) local dcall = vgui.Create("DButton", dcont) dcall:SetPos(m*2 + bw, by) dcall:SetSize(bw, bh) dcall:SetText(T("search_call")) dcall.DoClick = function(s) client.called_corpses = client.called_corpses or {} table.insert(client.called_corpses, search_raw.eidx) s:SetDisabled(true) RunConsoleCommand("ttt_call_detective", search_raw.eidx) end dcall:SetDisabled(client:IsSpec() or table.HasValue(client.called_corpses or {}, search_raw.eidx)) local dconfirm = vgui.Create("DButton", dcont) dconfirm:SetPos(rw - m - bw, by) dconfirm:SetSize(bw, bh) dconfirm:SetText(T("close")) dconfirm.DoClick = function() dframe:Close() end -- Finalize search data, prune stuff that won't be shown etc -- search is a table of tables that have an img and text key local search = PreprocSearch(search_raw) -- Install info controller that will link up the icons to the text etc dlist.OnActivePanelChanged = SearchInfoController(search, dactive, dtext) -- Create table of SimpleIcons, each standing for a piece of search -- information. local start_icon = nil for t, info in SortedPairsByMemberValue(search, "p") do local ic = nil -- Certain items need a special icon conveying additional information if t == "nick" then local name = info.nick local avply = IsValid(search_raw.owner) and search_raw.owner or nil ic = vgui.Create("SimpleIconAvatar", dlist) ic:SetPlayer(avply) start_icon = ic elseif t == "lastid" then ic = vgui.Create("SimpleIconAvatar", dlist) ic:SetPlayer(info.ply) ic:SetAvatarSize(24) elseif info.text_icon then ic = vgui.Create("SimpleIconLabelled", dlist) ic:SetIconText(info.text_icon) else ic = vgui.Create("SimpleIcon", dlist) end ic:SetIconSize(64) ic:SetIcon(info.img) ic.info_type = t dlist:AddPanel(ic) dscroll:AddPanel(ic) end dlist:SelectPanel(start_icon) dframe:MakePopup() end local function StoreSearchResult(search) if search.owner then -- if existing result was not ours, it was detective's, and should not -- be overwritten local ply = search.owner if (not ply.search_result) or ply.search_result.show then ply.search_result = search -- this is useful for targetid local rag = Entity(search.eidx) if IsValid(rag) then rag.search_result = search end end end end local function bitsRequired(num) local bits, max = 0, 1 while max <= num do bits = bits + 1 max = max + max end return bits end local search = {} local function ReceiveRagdollSearch() search = {} -- Basic info search.eidx = net.ReadUInt(16) search.owner = Entity(net.ReadUInt(8)) if not (IsValid(search.owner) and search.owner:IsPlayer() and (not search.owner:Alive())) then search.owner = nil end search.nick = net.ReadString() -- Equipment local eq = net.ReadUInt(16) -- All equipment pieces get their own icon search.eq_armor = util.BitSet(eq, EQUIP_ARMOR) search.eq_radar = util.BitSet(eq, EQUIP_RADAR) search.eq_disg = util.BitSet(eq, EQUIP_DISGUISE) -- Traitor things search.role = net.ReadUInt(2) search.c4 = net.ReadInt(bitsRequired(C4_WIRE_COUNT) + 1) -- Kill info search.dmg = net.ReadUInt(30) search.wep = net.ReadString() search.head = net.ReadBit() == 1 search.dtime = net.ReadInt(16) search.stime = net.ReadInt(16) -- Players killed local num_kills = net.ReadUInt(8) if num_kills > 0 then search.kills = {} for i=1,num_kills do table.insert(search.kills, net.ReadUInt(8)) end else search.kills = nil end search.lastid = {idx=net.ReadUInt(8)} -- should we show a menu for this result? search.finder = net.ReadUInt(8) search.show = (LocalPlayer():EntIndex() == search.finder) -- -- last words -- local words = net.ReadString() search.words = (words ~= "") and words or nil hook.Call("TTTBodySearchEquipment", nil, search, eq) if search.show then ShowSearchScreen(search) end StoreSearchResult(search) search = nil end net.Receive("TTT_RagdollSearch", ReceiveRagdollSearch)
Changed text
Open file
-- Body search popup local T = LANG.GetTranslation local PT = LANG.GetParamTranslation local is_dmg = util.BitSet -- "From his body you can tell XXX" local function DmgToText(d) if is_dmg(d, DMG_CRUSH) then return T("search_dmg_crush") elseif is_dmg(d, DMG_BULLET) then return T("search_dmg_bullet") elseif is_dmg(d, DMG_FALL) then return T("search_dmg_fall") elseif is_dmg(d, DMG_BLAST) then return T("search_dmg_boom") elseif is_dmg(d, DMG_CLUB) then return T("search_dmg_club") elseif is_dmg(d, DMG_DROWN) then return T("search_dmg_drown") elseif is_dmg(d, DMG_SLASH) then return T("search_dmg_stab") elseif is_dmg(d, DMG_BURN) or is_dmg(d, DMG_DIRECT) then return T("search_dmg_burn") elseif is_dmg(d, DMG_SONIC) then return T("search_dmg_tele") elseif is_dmg(d, DMG_VEHICLE) then return T("search_dmg_car") else return T("search_dmg_other") end end -- Info type to icon mapping -- Some icons have different appearances based on the data value. These have a -- separate table inside the TypeToMat table. -- Those that have a lot of possible data values are defined separately, either -- as a function or a table. local function DmgToMat(d) if is_dmg(d, DMG_BULLET) then return "bullet" elseif is_dmg(d, DMG_CRUSH) then return "rock" elseif is_dmg(d, DMG_BLAST) then return "splode" elseif is_dmg(d, DMG_FALL) then return "fall" elseif is_dmg(d, DMG_BURN) or is_dmg(d, DMG_DIRECT) then return "fire" else return "skull" end end local function WeaponToIcon(d) local wep = util.WeaponForClass(d) return wep and wep.Icon or "VGUI/ttt/icon_nades" end local TypeToMat = { nick="id", words="halp", eq_armor="armor", eq_radar="radar", eq_disg="disguise", role={[ROLE_TRAITOR]="traitor", [ROLE_DETECTIVE]="det", [ROLE_INNOCENT]="inno"}, c4="code", dmg=DmgToMat, wep=WeaponToIcon, head="head", dtime="time", stime="wtester", lastid="lastid", kills="list" }; -- Accessor for better fail handling local function IconForInfoType(t, data) local base = "VGUI/ttt/icon_" local mat = TypeToMat[t] if type(mat) == "table" then mat = mat[data] elseif type(mat) == "function" then mat = mat(data) end if not mat then mat = TypeToMat["nick"] end -- ugly special casing for weapons, because they are more likely to be -- customized and hence need more freedom in their icon filename if t != "wep" then return base .. mat else return mat end end function PreprocSearch(raw) local search = {} for t, d in pairs(raw) do search[t] = {img=nil, text="", p=10} if t == "nick" then search[t].text = PT("search_nick", {player = d}) search[t].p = 1 search[t].nick = d elseif t == "role" then if d == ROLE_TRAITOR then search[t].text = T("search_role_t") elseif d == ROLE_DETECTIVE then search[t].text = T("search_role_d") else search[t].text = T("search_role_i") end search[t].p = 2 elseif t == "words" then if d != "" then -- only append "--" if there's no ending interpunction local final = string.match(d, "[\\.\\!\\?]$") != nil search[t].text = PT("search_words", {lastwords = d .. (final and "" or "--.")}) end elseif t == "eq_armor" then if d then search[t].text = T("search_armor") search[t].p = 17 end elseif t == "eq_disg" then if d then search[t].text = T("search_disg") search[t].p = 18 end elseif t == "eq_radar" then if d then search[t].text = T("search_radar") search[t].p = 19 end elseif t == "c4" then if d > 0 then search[t].text= PT("search_c4", {num = d}) end elseif t == "dmg" then search[t].text = DmgToText(d) search[t].p = 12 elseif t == "wep" then local wep = util.WeaponForClass(d) local wname = wep and LANG.TryTranslation(wep.PrintName) if wname then search[t].text = PT("search_weapon", {weapon = wname}) end elseif t == "head" then if d then search[t].text = T("search_head") end search[t].p = 15 elseif t == "dtime" then if d != 0 then local ftime = util.SimpleTime(d, "%02i:%02i") search[t].text = PT("search_time", {time = ftime}) search[t].text_icon = ftime search[t].p = 8 end elseif t == "stime" then if d > 0 then local ftime = util.SimpleTime(d, "%02i:%02i") search[t].text = PT("search_dna", {time = ftime}) search[t].text_icon = ftime end elseif t == "kills" then local num = table.Count(d) if num == 1 then local vic = Entity(d[1]) local dc = d[1] == -1 -- disconnected if dc or (IsValid(vic) and vic:IsPlayer()) then search[t].text = PT("search_kills1", {player = (dc and "<Disconnected>" or vic:Nick())}) end elseif num > 1 then local txt = T("search_kills2") .. "\n" local nicks = {} for k, idx in pairs(d) do local vic = Entity(idx) local dc = idx == -1 if dc or (IsValid(vic) and vic:IsPlayer()) then table.insert(nicks, (dc and "<Disconnected>" or vic:Nick())) end end local last = #nicks txt = txt .. table.concat(nicks, "\n", 1, last) search[t].text = txt end search[t].p = 30 elseif t == "lastid" then if d and d.idx != -1 then local ent = Entity(d.idx) if IsValid(ent) and ent:IsPlayer() then search[t].text = PT("search_eyes", {player = ent:Nick()}) search[t].ply = ent end end else -- Not matching a type, so don't display search[t] = nil end -- anything matching a type but not given a text should be removed if search[t] and search[t].text == "" then search[t] = nil end -- if there's still something here, we'll be showing it, so find an icon if search[t] then search[t].img = IconForInfoType(t, d) end end return search end -- Returns a function meant to override OnActivePanelChanged, which modifies -- dactive and dtext based on the search information that is associated with the -- newly selected panel local function SearchInfoController(search, dactive, dtext) return function(s, pold, pnew) local t = pnew.info_type local data = search[t] if not data then ErrorNoHalt("Search: data not found", t, data,"\n") return end -- If wrapping is on, the Label's SizeToContentsY misbehaves for -- text that does not need wrapping. I long ago stopped wondering -- "why" when it comes to VGUI. Apply hack, move on. dtext:GetLabel():SetWrap(#data.text > 50) dtext:SetText(data.text) dactive:SetImage(data.img) end end local function ShowSearchScreen(search_raw) local client = LocalPlayer() if not IsValid(client) then return end local m = 8 local bw, bh = 100, 25 local w, h = 410, 260 local rw, rh = (w - m*2), (h - 25 - m*2) local rx, ry = 0, 0 local rows = 1 local listw, listh = rw, (64 * rows + 6) local listx, listy = rx, ry ry = ry + listh + m*2 rx = m local descw, desch = rw - m*2, 80 local descx, descy = rx, ry ry = ry + desch + m local butx, buty = rx, ry local dframe = vgui.Create("DFrame") dframe:SetSize(w, h) dframe:Center() dframe:SetTitle(T("search_title") .. " - " .. search_raw.nick or "???") dframe:SetVisible(true) dframe:ShowCloseButton(true) dframe:SetMouseInputEnabled(true) dframe:SetKeyboardInputEnabled(true) dframe:SetDeleteOnClose(true) dframe.OnKeyCodePressed = util.BasicKeyHandler -- contents wrapper local dcont = vgui.Create("DPanel", dframe) dcont:SetPaintBackground(false) dcont:SetSize(rw, rh) dcont:SetPos(m, 25 + m) -- icon list local dlist = vgui.Create("DPanelSelect", dcont) dlist:SetPos(listx, listy) dlist:SetSize(listw, listh) dlist:EnableHorizontal(true) dlist:SetSpacing(1) dlist:SetPadding(2) if dlist.VBar then dlist.VBar:Remove() dlist.VBar = nil end -- description area local dscroll = vgui.Create("DHorizontalScroller", dlist) dscroll:StretchToParent(3,3,3,3) local ddesc = vgui.Create("ColoredBox", dcont) ddesc:SetColor(Color(50, 50, 50)) ddesc:SetName(T("search_info")) ddesc:SetPos(descx, descy) ddesc:SetSize(descw, desch) local dactive = vgui.Create("DImage", ddesc) dactive:SetImage("VGUI/ttt/icon_id") dactive:SetPos(m, m) dactive:SetSize(64, 64) local dtext = vgui.Create("ScrollLabel", ddesc) dtext:SetSize(descw - 120, desch - m*2) dtext:MoveRightOf(dactive, m*2) dtext:AlignTop(m) dtext:SetText("...") -- buttons local by = rh - bh - (m/2) local dident = vgui.Create("DButton", dcont) dident:SetPos(m, by) dident:SetSize(bw,bh) dident:SetText(T("search_confirm")) local id = search_raw.eidx + search_raw.dtime dident.DoClick = function() RunConsoleCommand("ttt_confirm_death", search_raw.eidx, id) end dident:SetDisabled(client:IsSpec() or (not client:KeyDownLast(IN_WALK))) local dcall = vgui.Create("DButton", dcont) dcall:SetPos(m*2 + bw, by) dcall:SetSize(bw, bh) dcall:SetText(T("search_call")) dcall.DoClick = function(s) client.called_corpses = client.called_corpses or {} table.insert(client.called_corpses, search_raw.eidx) s:SetDisabled(true) RunConsoleCommand("ttt_call_detective", search_raw.eidx) end dcall:SetDisabled(client:IsSpec() or table.HasValue(client.called_corpses or {}, search_raw.eidx)) local dconfirm = vgui.Create("DButton", dcont) dconfirm:SetPos(rw - m - bw, by) dconfirm:SetSize(bw, bh) dconfirm:SetText(T("close")) dconfirm.DoClick = function() dframe:Close() end -- Finalize search data, prune stuff that won't be shown etc -- search is a table of tables that have an img and text key local search = PreprocSearch(search_raw) -- Install info controller that will link up the icons to the text etc dlist.OnActivePanelChanged = SearchInfoController(search, dactive, dtext) -- Create table of SimpleIcons, each standing for a piece of search -- information. local start_icon = nil for t, info in SortedPairsByMemberValue(search, "p") do local ic = nil -- Certain items need a special icon conveying additional information if t == "nick" then local name = info.nick local avply = IsValid(search_raw.owner) and search_raw.owner or nil ic = vgui.Create("SimpleIcon", dlist) ic:SetPlayer(avply) start_icon = ic elseif t == "lastid" then ic = vgui.Create("SimpleIconAvatar", dlist) ic:SetPlayer(info.ply) ic:SetAvatarSize(24) elseif info.text_icon then ic = vgui.Create("SimpleIconLabelled", dlist) ic:SetIconText(info.text_icon) else ic = vgui.Create("SimpleIcon", dlist) end ic:SetIconSize(64) ic:SetIcon(info.img) ic.info_type = t dlist:AddPanel(ic) dscroll:AddPanel(ic) end dlist:SelectPanel(start_icon) dframe:MakePopup() end local function StoreSearchResult(search) if search.owner then -- if existing result was not ours, it was detective's, and should not -- be overwritten local ply = search.owner if (not ply.search_result) or ply.search_result.show then ply.search_result = search -- this is useful for targetid local rag = Entity(search.eidx) if IsValid(rag) then rag.search_result = search end end end end local function bitsRequired(num) local bits, max = 0, 1 while max <= num do bits = bits + 1 max = max + max end return bits end local search = {} local function ReceiveRagdollSearch() search = {} -- Basic info search.eidx = net.ReadUInt(16) search.owner = Entity(net.ReadUInt(8)) if not (IsValid(search.owner) and search.owner:IsPlayer() and (not search.owner:Alive())) then search.owner = nil end search.nick = net.ReadString() -- Equipment local eq = net.ReadUInt(16) -- All equipment pieces get their own icon search.eq_armor = util.BitSet(eq, EQUIP_ARMOR) search.eq_radar = util.BitSet(eq, EQUIP_RADAR) search.eq_disg = util.BitSet(eq, EQUIP_DISGUISE) -- Traitor things search.role = net.ReadUInt(2) search.c4 = net.ReadInt(bitsRequired(C4_WIRE_COUNT) + 1) -- Kill info search.dmg = net.ReadUInt(30) search.wep = net.ReadString() search.head = net.ReadBit() == 1 search.dtime = net.ReadInt(16) search.stime = net.ReadInt(16) -- Players killed local num_kills = net.ReadUInt(8) if num_kills > 0 then search.kills = {} for i=1,num_kills do table.insert(search.kills, net.ReadUInt(8)) end else search.kills = nil end search.lastid = {idx=net.ReadUInt(8)} -- should we show a menu for this result? search.finder = net.ReadUInt(8) search.show = (LocalPlayer():EntIndex() == search.finder) -- -- last words -- local words = net.ReadString() search.words = (words ~= "") and words or nil if search.show then ShowSearchScreen(search) end StoreSearchResult(search) search = nil end net.Receive("TTT_RagdollSearch", ReceiveRagdollSearch)
Find difference