add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
if (!SH_REPORTS.ActiveReports) then
SH_REPORTS.ActiveReports = {}
end
function SH_REPORTS:ReportCreated(data)
chat.AddText(self.Style.header, "[" .. self:L("reports") .. "] ", color_white, self:L("report_received", data.reporter_name, data.reported_name, self.ReportReasons[data.reason_id])) -- 76561198398853149
if (self.NewReportSound.enabled) then
surface.PlaySound(self.NewReportSound.path)
end
self:MakeNotification(data)
self:MakePending(data)
if (!self.ActiveReports) then
self.ActiveReports = {}
end
table.insert(self.ActiveReports, data)
end
hook.Add("Think", "SH_REPORTS.Ready", function()
if (IsValid(LocalPlayer())) then
hook.Remove("Think", "SH_REPORTS.Ready")
easynet.SendToServer("SH_REPORTS.PlayerReady")
end
end)
easynet.Callback("SH_REPORTS.SendList", function(data)
local pendings = {}
for _, report in pairs (SH_REPORTS.ActiveReports) do
if (IsValid(report.pending)) then
pendings[report.id] = report.pending
end
end
SH_REPORTS.ServerTime = data.server_time
SH_REPORTS.ActiveReports = data.struct_reports
for _, report in pairs (SH_REPORTS.ActiveReports) do
report.pending = pendings[report.id]
end
SH_REPORTS:ShowReports()
end)
easynet.Callback("SH_REPORTS.MinimizeReport", function(data)
if (IsValid(_SH_REPORTS_VIEW)) then
_SH_REPORTS_VIEW:Close()
end
local report
for _, rep in pairs (SH_REPORTS.ActiveReports) do
if (rep.id == data.report_id) then
report = rep
break
end
end
if (report) then
SH_REPORTS:MakeTab(report)
end
end)
easynet.Callback("SH_REPORTS.ReportClosed", function(data)
for k, rep in pairs (SH_REPORTS.ActiveReports) do
if (rep.id == data.report_id) then
if (IsValid(rep.line)) then
rep.line:Close()
end
if (IsValid(rep.pending)) then
rep.pending:Close()
end
SH_REPORTS.ActiveReports[k] = nil
end
end
if (IsValid(_SH_REPORTS_TAB) and _SH_REPORTS_TAB.id == data.report_id) then
_SH_REPORTS_TAB:Close()
end
SH_REPORTS:ClosePendingPanel(data.report_id)
end)
easynet.Callback("SH_REPORTS.ReportClaimed", function(data)
for _, rep in pairs (SH_REPORTS.ActiveReports) do
if (rep.id == data.report_id) then
rep.admin_id = data.admin_id
if (IsValid(rep.line)) then
rep.line.claimed.avi:SetSteamID(data.admin_id)
rep.line.claimed.avi:SetVisible(true)
local admin = player.GetBySteamID64(data.admin_id)
if (IsValid(admin)) then
rep.line.claimed.name:SetTextInset(32, 0)
rep.line.claimed.name:SetContentAlignment(4)
rep.line.claimed.name:SetText(admin:Nick())
end
end
if (IsValid(rep.pending)) then
rep.pending:Close()
end
if (data.admin_id ~= LocalPlayer():SteamID64() and IsValid(rep.line) and IsValid(rep.line.delete)) then
rep.line.delete:Remove()
end
end
end
SH_REPORTS:ClosePendingPanel(data.report_id)
end)
easynet.Callback("SH_REPORTS.Notify", function(data)
-- do NOT do this
SH_REPORTS:Notify(SH_REPORTS:L(unpack(string.Explode("\t", data.msg))), nil, data.positive and SH_REPORTS.Style.success or SH_REPORTS.Style.failure)
end)
easynet.Callback("SH_REPORTS.Chat", function(data)
chat.AddText(SH_REPORTS.Style.header, "[" .. SH_REPORTS:L("reports") .. "] ", color_white, data.msg)
end)
easynet.Callback("SH_REPORTS.ReportCreated", function(data)
SH_REPORTS:ReportCreated(data)
end)
easynet.Callback("SH_REPORTS.ReportsPending", function(data)
chat.AddText(SH_REPORTS.Style.header, "[" .. SH_REPORTS:L("reports") .. "] ", color_white, SH_REPORTS:L("there_are_x_reports_pending", data.num)) -- 76561198398853124
SH_REPORTS.ActiveReports = table.Copy(data.struct_reports)
for _, report in pairs (SH_REPORTS.ActiveReports) do
SH_REPORTS:MakePending(report)
end
end)
easynet.Callback("SH_REPORTS.AdminLeft", function(data)
for _, rep in pairs (SH_REPORTS.ActiveReports) do
if (rep.id == data.report_id) then
rep.admin_id = ""
if (IsValid(rep.line)) then
rep.line.claimed.avi:SetVisible(false)
rep.line.claimed.name:SetTextInset(0, 0)
rep.line.claimed.name:SetContentAlignment(5)
rep.line.claimed.name:SetText(SH_REPORTS:L("unclaimed"))
end
end
end
end)
-- vk.com/urbanichka

View File

@@ -0,0 +1,610 @@
local function L(...) return SH_REPORTS:L(...) end
local matBack = Material("shenesis/general/back.png")
function SH_REPORTS:ShowReport(report)
if (IsValid(_SH_REPORTS_VIEW)) then
_SH_REPORTS_VIEW:Remove()
end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local m2 = m * 0.5
local ss = self:GetScreenScale()
local frame = self:MakeWindow(L"view_report")
frame:SetSize(500 * ss, 400 * ss)
frame:Center()
frame:MakePopup()
_SH_REPORTS_VIEW = frame
frame:AddHeaderButton(matBack, function()
frame:Close()
self:ShowReports()
end)
local body = vgui.Create("DPanel", frame)
body:SetDrawBackground(false)
body:DockPadding(m, m, m, m)
body:Dock(FILL)
local players = vgui.Create("DPanel", body)
players:SetDrawBackground(false)
players:SetWide(frame:GetWide() - m * 2)
players:Dock(TOP)
local lbl1 = self:QuickLabel(L"reporter", "{prefix}Large", styl.text, players)
lbl1:SetContentAlignment(7)
lbl1:SetTextInset(m2, m2)
lbl1:SetWide(frame:GetWide() * 0.5 - m2)
lbl1:Dock(LEFT)
lbl1:DockPadding(m2, lbl1:GetTall() + m * 1.5, m2, m2)
lbl1.Paint = function(me, w, h)
draw.RoundedBox(4, 0, 0, w, h, styl.inbg)
end
local avi = self:Avatar(report.reporter_id, 32, lbl1)
avi:Dock(LEFT)
avi:DockMargin(0, 0, m2, 0)
local nic = self:QuickButton(report.reporter_name, function()
SetClipboardText(report.reporter_name)
surface.PlaySound("common/bugreporter_succeeded.wav")
end, lbl1)
nic:SetContentAlignment(4)
nic:Dock(TOP)
local s1 = util.SteamIDFrom64(report.reporter_id)
local steamid = self:QuickButton(s1, function()
SetClipboardText(s1)
surface.PlaySound("common/bugreporter_succeeded.wav")
end, lbl1)
steamid:SetContentAlignment(4)
steamid:Dock(TOP)
local lbl = self:QuickLabel(L"reported_player", "{prefix}Large", styl.text, players)
lbl:SetContentAlignment(9)
lbl:SetTextInset(m2, m2)
lbl:Dock(FILL)
lbl:DockPadding(m2, lbl1:GetTall() + m * 1.5, m2, m2)
lbl.Paint = lbl1.Paint
local avi = self:Avatar(report.reported_id, 32, lbl)
avi:Dock(RIGHT)
avi:DockMargin(m2, 0, 0, 0)
local nic = self:QuickButton(report.reported_name, function()
SetClipboardText(report.reported_name)
surface.PlaySound("common/bugreporter_succeeded.wav")
end, lbl)
nic:SetContentAlignment(6)
nic:Dock(TOP)
nic.Think = function(me)
me:SetTextColor(IsValid(player.GetBySteamID64(report.reported_id)) and styl.text or styl.failure)
end
local s2 = util.SteamIDFrom64(report.reported_id)
local steamid = self:QuickButton(s2, function()
SetClipboardText(s2)
surface.PlaySound("common/bugreporter_succeeded.wav")
end, lbl)
steamid:SetContentAlignment(6)
steamid:Dock(TOP)
if (report.reported_id == "0") then
nic.Think = function() end
nic:Dock(FILL)
steamid:SetVisible(false)
avi:SetVisible(false)
end
players:SetTall(lbl1:GetTall() + m * 2.5 + 32)
local reason = self:QuickLabel(L("reason") .. ":", "{prefix}Medium", styl.text, body)
reason:Dock(TOP)
reason:DockMargin(0, m, 0, 0)
reason:DockPadding(reason:GetWide() + m2, 0, 0, 0)
local r = self:QuickEntry(self.ReportReasons[report.reason_id], reason)
r:SetEnabled(false)
r:SetContentAlignment(6)
r:Dock(FILL)
local comment = self:QuickLabel(L("comment") .. ":", "{prefix}Medium", styl.text, body)
comment:SetContentAlignment(7)
comment:Dock(FILL)
comment:DockMargin(0, m, 0, m2)
local tx = self:QuickEntry("", comment)
tx:SetEnabled(false)
tx:SetMultiline(true)
tx:SetValue(report.comment)
tx:Dock(FILL)
tx:DockMargin(0, comment:GetTall() + m2, 0, 0)
local actions = vgui.Create("DPanel", body)
actions:SetDrawBackground(false)
actions:Dock(BOTTOM)
if (self:IsAdmin(LocalPlayer())) then
if (report.admin_id == "") then
if (self.ClaimNoTeleport) then
local claim = self:QuickButton(L"claim_report", function()
easynet.SendToServer("SH_REPORTS.Claim", {id = report.id})
end, actions)
claim:Dock(LEFT)
else
local lbl = self:QuickLabel(L("claim_report") .. ":", "{prefix}Medium", styl.text, actions)
lbl:SetContentAlignment(4)
lbl:Dock(LEFT)
lbl:DockMargin(0, 0, m2, 0)
local goto = self:QuickButton(L"goto", function()
if (IsValid(player.GetBySteamID64(report.reported_id))) then
local m = self:Menu()
m:AddOption("bring_reported_player"):SetMouseInputEnabled(false)
m:AddOption("yes", function()
easynet.SendToServer("SH_REPORTS.ClaimAndTeleport", {id = report.id, bring = false, bring_reported = true /* 76561198398853124 */})
end)
m:AddOption("no", function()
easynet.SendToServer("SH_REPORTS.ClaimAndTeleport", {id = report.id, bring = false, bring_reported = false})
end)
m:Open()
else
easynet.SendToServer("SH_REPORTS.ClaimAndTeleport", {id = report.id, bring = false, bring_reported = false})
end
end, actions)
goto:Dock(LEFT)
local bring = self:QuickButton(L"bring", function()
if (IsValid(player.GetBySteamID64(report.reported_id))) then
local m = self:Menu()
m:AddOption("bring_reported_player"):SetMouseInputEnabled(false)
m:AddOption("yes", function()
easynet.SendToServer("SH_REPORTS.ClaimAndTeleport", {id = report.id, bring = true, bring_reported = true})
end)
m:AddOption("no", function()
easynet.SendToServer("SH_REPORTS.ClaimAndTeleport", {id = report.id, bring = true, bring_reported = false})
end)
m:Open()
else
easynet.SendToServer("SH_REPORTS.ClaimAndTeleport", {id = report.id, bring = true, bring_reported = false})
end
end, actions)
bring:Dock(LEFT)
bring:DockMargin(m2, 0, 0, 0)
end
if (sitsys) then
local session = self:QuickButton(L"start_sit_session", function()
easynet.SendToServer("SH_REPORTS.ClaimAndCSit", {id = report.id})
end, actions)
session:Dock(LEFT)
session:DockMargin(m2, 0, 0, 0)
end
else
local lbl = self:QuickLabel(L("claimed_by_x", ""), "{prefix}Medium", styl.text, actions)
lbl:SetContentAlignment(4)
lbl:Dock(LEFT)
lbl:DockMargin(0, 0, m2, 0)
self:GetName(report.admin_id, function(nick)
if (IsValid(lbl)) then
lbl:SetText(L("claimed_by_x", nick))
lbl:SizeToContents()
end
end)
end
end
if (report.reporter_id == LocalPlayer():SteamID64()) or (report.admin_id == "" and self.CanDeleteWhenUnclaimed) or (report.admin_id == LocalPlayer():SteamID64() /* 76561198398853149 */) then
local close = self:QuickButton(L"close_report", function()
easynet.SendToServer("SH_REPORTS.CloseReport", {id = report.id})
frame:Close()
end, actions, nil, self.Style.close_hover)
close:Dock(RIGHT)
end
frame:SetAlpha(0)
frame:AlphaTo(255, 0.1)
end
local matStats = Material("shenesis/reports/stats.png")
local matAdd = Material("shenesis/reports/add.png")
function SH_REPORTS:ShowReports()
if (IsValid(_SH_REPORTS)) then
_SH_REPORTS:Remove()
end
if (IsValid(_SH_REPORTS_VIEW)) then
_SH_REPORTS_VIEW:Remove()
end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local ss = self:GetScreenScale()
local delay = 0
if (self.ServerTime) then
delay = self.ServerTime - os.time()
end
local frame = self:MakeWindow(self:IsAdmin(LocalPlayer()) and L"report_list" or L"your_reports")
frame:SetSize(900 * ss, 600 * ss)
frame:Center()
frame:MakePopup()
_SH_REPORTS = frame
if (self.UsergroupsPerformance[LocalPlayer():GetUserGroup()]) then
local btn = frame:AddHeaderButton(matStats, function()
easynet.SendToServer("SH_REPORTS.RequestPerfReports")
frame:Close()
end)
btn:SetToolTip(L"performance_reports")
end
if (!self:IsAdmin(LocalPlayer()) or self.StaffCanReport) then
local btn = frame:AddHeaderButton(matAdd, function()
self:ShowMakeReports()
frame:Close()
end)
btn:SetToolTip(L"new_report")
end
local ilist = vgui.Create("DListView", frame)
ilist:SetSortable(false)
ilist:SetDrawBackground(false)
ilist:SetDataHeight(32)
ilist:Dock(FILL)
ilist:AddColumn(L"reporter")
ilist:AddColumn(L"reported_player")
ilist:AddColumn(L"reason")
ilist:AddColumn(L"waiting_time")
ilist:AddColumn(L"claimed")
ilist:AddColumn(L"actions")
self:PaintList(ilist)
for _, report in SortedPairsByMemberValue (self.ActiveReports, "time", true) do
local reporter = vgui.Create("DPanel", frame)
reporter:SetDrawBackground(false)
local avi = self:Avatar(report.reporter_id, 24, reporter)
avi:SetPos(4, 4)
local name = self:QuickLabel(report.reporter_name, "{prefix}Medium", styl.text, reporter)
name:Dock(FILL)
name:SetTextInset(ilist:GetDataHeight(), 0)
local reported = vgui.Create("DPanel", frame)
reported:SetDrawBackground(false)
local avi = self:Avatar(report.reported_id, 24, reported)
avi:SetPos(4, 4)
local name = self:QuickLabel(report.reported_name, "{prefix}Medium", styl.text, reported)
name:Dock(FILL)
name:SetTextInset(32, 0)
if (report.reported_id ~= "0") then
name.Think = function(me)
me:SetTextColor(IsValid(player.GetBySteamID64(report.reported_id)) and styl.text or styl.failure)
end
else
avi:SetVisible(false)
name:SetContentAlignment(5)
name:SetTextInset(0, 0)
end
local claimed = vgui.Create("DPanel", frame)
claimed:SetDrawBackground(false)
local avi = self:Avatar("", 24, claimed)
avi:SetPos(4, 4)
claimed.avi = avi
local name = self:QuickLabel(L"unclaimed", "{prefix}Medium", styl.text, claimed)
name:Dock(FILL)
name:SetTextInset(32, 0)
claimed.name = name
if (report.admin_id ~= "") then
avi:SetSteamID(report.admin_id)
self:GetName(report.admin_id, function(nick)
if (IsValid(name)) then
name:SetText(nick)
end
end)
else
avi:SetVisible(false)
name:SetContentAlignment(5)
name:SetTextInset(0, 0)
end
local actions = vgui.Create("DPanel", frame)
actions:SetDrawBackground(false)
actions:SetTall(32)
actions:DockPadding(4, 4, 4, 4)
local act_view = self:QuickButton(L"view", function() end, actions)
act_view:Dock(LEFT)
act_view:DockMargin(0, 0, 4, 0)
act_view.DoClick = function()
frame:Close()
self:ShowReport(report)
end
local act_delete
if (report.admin_id == "" and self.CanDeleteWhenUnclaimed) or (report.admin_id == LocalPlayer():SteamID64()) then
act_delete = self:QuickButton(L"close_report", function() end, actions, nil, self.Style.close_hover /* 76561198398853124 */)
act_delete:Dock(LEFT)
act_delete.DoClick = function()
easynet.SendToServer("SH_REPORTS.CloseReport", {id = report.id})
end
end
local time = self:QuickLabel("", "{prefix}Medium", styl.text, frame)
time:SetContentAlignment(5)
time.Think = function(me)
if (!me.m_fNextRefresh or RealTime() >= me.m_fNextRefresh) then
me.m_fNextRefresh = RealTime() + 5
me:SetText(self:FullFormatTime(os.time() + delay - report.time))
end
end
local line = ilist:AddLine(reporter, reported, self.ReportReasons[report.reason_id], time, claimed, actions)
-- line:SetSelectable(false)
line.claimed = claimed
line.delete = act_delete
line.Close = function(me)
me:AlphaTo(0, 0.2, nil, function()
if (!ilist.Lines[me:GetID()]) then
return end
ilist:RemoveLine(me:GetID())
end)
end
self:LineStyle(line)
for _, rep in pairs (self.ActiveReports) do
if (rep.id == report.id) then
rep.line = line
end
end
end
frame:SetAlpha(0)
frame:AlphaTo(255, 0.1)
end
function SH_REPORTS:MakeTab(report)
if (IsValid(_SH_REPORTS_TAB)) then
_SH_REPORTS_TAB:Close()
end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local m2 = m * 0.5
local rep = vgui.Create("DButton")
rep:SetText("")
rep:SetSize(160, 32 + m)
rep:SetPos(ScrW() * 0.5, ScrH())
rep:MoveToFront()
rep:DockPadding(m2, m2, m2, m2)
rep.Paint = function(me, w, h)
draw.RoundedBoxEx(4, 0, 0, w, h, styl.header, true, true, false, false)
end
rep.DoClick = function(me)
if (me.m_bClosing) then
return end
self:ShowReport(report)
end
rep.Close = function(me)
if (me.m_bClosing) then
return end
me.m_bClosing = true
me:Stop()
me:MoveTo(rep.x, ScrH(), 0.2, 0, -1, function()
me:Remove()
end)
end
rep.id = report.id
_SH_REPORTS_TAB = rep
local avi = self:Avatar(report.reporter_id, 32, rep)
avi:SetMouseInputEnabled(false)
avi:Dock(LEFT)
avi:DockMargin(0, 0, m2, 0)
local name = self:QuickLabel(L("report_of_x", report.reporter_name), "{prefix}Large", styl.text, rep)
name:Dock(FILL)
rep:SetWide(name:GetWide() + avi:GetWide() + m * 1.5)
rep:CenterHorizontal()
rep:MoveTo(rep.x, ScrH() - rep:GetTall(), 0.2)
end
function SH_REPORTS:MakeNotification(report)
if (IsValid(report.notif)) then
report.notif:Close()
end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local m2 = m * 0.5
local rep = vgui.Create("DButton")
rep:SetText("")
rep:SetSize(160, 32 + m)
rep:SetPos(ScrW() * 0.5, -rep:GetTall())
rep:MoveToFront()
rep:DockPadding(m2, m2, m2, m2)
rep.Paint = function(me, w, h)
draw.RoundedBoxEx(4, 0, 0, w, h, styl.header, false, false, true, true)
end
rep.DoClick = function(me)
if (me.m_bClosing) then
return end
self:ShowReport(report)
me:Close()
end
rep.Close = function(me)
if (me.m_bClosing) then
return end
me.m_bClosing = true
me:Stop()
me:MoveTo(rep.x, -me:GetTall(), 0.2, 0, -1, function()
me:Remove()
end)
end
report.notif = rep
local avi = self:Avatar(report.reporter_id, 32, rep)
avi:SetMouseInputEnabled(false)
avi:Dock(LEFT)
avi:DockMargin(0, 0, m2, 0)
local name = self:QuickLabel(L("report_received", report.reporter_name, report.reported_name, self.ReportReasons[report.reason_id]), "{prefix}Large", /* 76561198398853149 */ styl.text, rep)
name:Dock(FILL)
rep:SetWide(name:GetWide() + avi:GetWide() + m * 1.5)
rep:CenterHorizontal()
rep:MoveTo(rep.x, 0, 0.2, nil, nil, function()
rep:MoveTo(rep.x, -rep:GetTall(), 0.2, 7.5, nil, function()
rep:Remove()
end)
end)
end
SH_REPORTS.PendingPanels = SH_REPORTS.PendingPanels or {}
function SH_REPORTS:ClosePendingPanel(id)
local cleaned = {}
-- Clean closed reports
for k, v in pairs (self.PendingPanels) do
if (!IsValid(v)) then
continue end
local found = false
for _, rep in pairs (SH_REPORTS.ActiveReports) do
if (rep.id == v.m_iReportID) then
found = true
end
end
if (!found) or (v.m_iReportID == id) then
v:Close()
continue
end
table.insert(cleaned, v)
end
self.PendingPanels = cleaned
end
function SH_REPORTS:MakePending(report)
if (IsValid(report.pending)) then
report.pending:Remove()
end
local num = 0
for _, w in pairs (self.PendingPanels) do
if (IsValid(w) and !w.m_bClosing) then
num = num + 1
end
end
if (num >= self.PendingReportsDispNumber) then
return end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local hh = th * 0.66
local m2, m3 = m * 0.5, m * 0.66
local ss = self:GetScreenScale()
local wnd = vgui.Create("DPanel")
wnd:SetSize(300 * ss, 112 * ss)
wnd:DockPadding(m3, hh + m3, m3, m3)
wnd.Paint = function(me, w, h)
draw.RoundedBoxEx(4, 0, 0, w, hh, styl.header, true, true, false, false)
draw.RoundedBoxEx(4, 0, hh, w, h - hh, styl.inbg, false, false, true, true)
draw.SimpleText("[" .. L"unclaimed" .. "] " .. L("report_of_x", report.reporter_name), "SH_REPORTS.MediumB", m2, hh * 0.5, styl.text, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
wnd.m_iReportID = report.id
report.pending = wnd
local lbl = self:QuickLabel(L"reported_player" .. ":", "{prefix}Medium", styl.text, wnd)
lbl:Dock(TOP)
local reported = self:QuickLabel(report.reported_name, "{prefix}Medium", styl.text, lbl)
reported:Dock(RIGHT)
local lbl = self:QuickLabel(L"reason" .. ":", "{prefix}Medium", styl.text, wnd)
lbl:Dock(TOP)
lbl:DockMargin(0, m3, 0, 0)
local reason = self:QuickLabel(self.ReportReasons[report.reason_id], "{prefix}Medium", styl.text, lbl)
reason:Dock(RIGHT)
local buttons = vgui.Create("DPanel", wnd)
buttons:SetDrawBackground(false)
buttons:SetTall(20 * ss)
buttons:Dock(BOTTOM)
local close = self:QuickButton("", function()
wnd:Close()
report.ignored = true
end, buttons)
close:SetWide(buttons:GetTall())
close:Dock(LEFT)
close.m_Background = styl.close_hover
local view = self:QuickButton(L"view", function()
self:ShowReport(report)
end, buttons)
view:Dock(RIGHT)
view.m_Background = styl.header
local i = table.insert(self.PendingPanels, wnd)
wnd:SetPos(m, m + (i - 1) * wnd:GetTall() + (i - 1) * m)
wnd:SetAlpha(0)
wnd:AlphaTo(255, 0.1)
wnd.Close = function(me)
if (me.m_bClosing) then
return end
me.m_bClosing = true
me:AlphaTo(0, 0.1, 0, function()
local ma = #self.PendingPanels
table.RemoveByValue(self.PendingPanels, me)
me:Remove()
local o = 0
for j = i - 1, ma do
local w = self.PendingPanels[j]
if (IsValid(w) and w ~= me) then
w:Stop()
w:MoveTo(w.x, m + o * wnd:GetTall() + o * m, 0.2)
o = o + 1
end
end
-- Display any hidden panels
for _, r in pairs (self.ActiveReports) do
if (!IsValid(r.pending) and !r.ignored and r.admin_id == "") then
self:MakePending(r)
end
end
end)
end
end
-- vk.com/urbanichka

View File

@@ -0,0 +1,176 @@
local function L(...) return SH_REPORTS:L(...) end
local matBack = Material("shenesis/general/back.png")
function SH_REPORTS:ShowMakeReports(c, d)
if (IsValid(_SH_REPORTS_MAKE)) then
_SH_REPORTS_MAKE:Remove()
end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local m2 = m * 0.5
local ss = self:GetScreenScale()
local frame = self:MakeWindow(L"new_report")
frame:SetSize(500 * ss, 500 * ss)
frame:Center()
frame:MakePopup()
_SH_REPORTS_MAKE = frame
frame:AddHeaderButton(matBack, function()
frame:Close()
self:ShowReports()
end)
local body = vgui.Create("DPanel", frame)
body:SetDrawBackground(false)
body:Dock(FILL)
body:DockMargin(m, m, m, m)
local lbl = self:QuickLabel(L"reason" .. ":", "{prefix}Large", styl.text, body)
lbl:Dock(TOP)
local reason = self:QuickComboBox(lbl)
reason:Dock(FILL)
reason:DockMargin(lbl:GetWide() + m, 0, 0, 0)
for rid, r in pairs (self.ReportReasons) do
reason:AddChoice(r, rid)
end
local lbl = self:QuickLabel(L"player_to_report" .. ":", "{prefix}Large", styl.text, body)
lbl:Dock(TOP)
lbl:DockMargin(0, m, 0, m)
local target = self:QuickComboBox(lbl)
target:SetSortItems(false)
target:Dock(FILL)
target:DockMargin(lbl:GetWide() + m, 0, 0, 0)
local toadd = {}
for _, ply in ipairs (player.GetAll()) do
if (ply == LocalPlayer()) then
continue end
if (self:IsAdmin(ply) and !self.StaffCanBeReported) then
continue end
table.insert(toadd, {nick = ply:Nick(), steamid = ply:SteamID64()})
end
for _, d in SortedPairsByMemberValue (toadd, "nick") do
target:AddChoice(d.nick, d.steamid)
end
if (self.CanReportOther) then
target:AddChoice("[" .. L"other" .. "]", "0")
end
local p = vgui.Create("DPanel", body)
p:SetTall(64 * ss + m)
p:Dock(TOP)
p:DockPadding(m2, m2, m2, m2)
p.Paint = function(me, w, h)
draw.RoundedBox(4, 0, 0, w, h, styl.inbg)
end
local pc = vgui.Create("DPanel", p)
pc:SetPaintedManually(true)
pc:SetDrawBackground(false)
pc:Dock(FILL)
local avi = self:Avatar("", 64 * ss, pc)
avi:Dock(LEFT)
avi:DockMargin(0, 0, m2, 0)
local nick = self:QuickLabel("", "{prefix}Large", styl.text, pc)
nick:Dock(TOP)
local steamid = self:QuickLabel("", "{prefix}Medium", styl.text, pc)
steamid:Dock(TOP)
local lbl = self:QuickLabel(L"comment" .. ":" /* 76561198398853149 */, "{prefix}Large", styl.text, body)
lbl:SetContentAlignment(7)
lbl:Dock(FILL)
lbl:DockMargin(0, m, 0, 0)
local comment = self:QuickEntry("", lbl)
comment:SetValue(c or "")
comment:SetMultiline(true)
comment:Dock(FILL)
comment:DockMargin(0, lbl:GetTall() + m2, 0, 0)
local btns = vgui.Create("DPanel", body)
btns:SetDrawBackground(false)
btns:Dock(BOTTOM)
btns:DockMargin(0, m, 0, 0)
local submit = self:QuickButton(L"submit_report", function()
local name, steamid = target:GetSelected()
if (!steamid) then
self:Notify(L"select_player_first", nil, styl.failure, frame)
return
end
local _, rid = reason:GetSelected()
if (!rid) then
self:Notify(L"select_reason_first", nil, styl.failure, frame)
return
end
easynet.SendToServer("SH_REPORTS.NewReport", {
reported_name = name,
reported_id = steamid,
reason_id = rid,
comment = comment:GetValue():sub(1, self.MaxCommentLength),
})
frame:Close()
end, btns)
submit:Dock(RIGHT)
-- cbs
if (d) then
reason.OnSelect = function(me, index, value, data)
local k = self.ReasonAutoTarget[value]
if (!k) then
return end
local p = d["last" .. k]
if (IsValid(p)) then
local i
for k, v in pairs (target.Choices) do
if (v == p:Nick()) then
i = k
break
end
end
if (i) then
target:ChooseOption(p:Nick(), i)
end
end
end
end
target.OnSelect = function(me, index, value, data)
pc:SetPaintedManually(false)
pc:SetAlpha(0)
pc:AlphaTo(255, 0.2)
avi:SetVisible(data ~= "0")
avi:SetSteamID(data)
nick:SetText(value)
steamid:SetText(data ~= "0" and util.SteamIDFrom64(data) or "")
steamid:InvalidateParent(true)
end
frame:SetAlpha(0)
frame:AlphaTo(255, 0.1)
end
easynet.Callback("SH_REPORTS.QuickReport", function(data)
SH_REPORTS:ShowMakeReports(data.comment, data)
end)
-- vk.com/urbanichka

View File

@@ -0,0 +1,415 @@
local function L(...) return SH_REPORTS:L(...) end
local matBack = Material("shenesis/general/back.png")
function SH_REPORTS:ShowPerformanceReports()
if (IsValid(_SH_REPORTS_PERF)) then
_SH_REPORTS_PERF:Remove()
end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local m2 = m * 0.5
local ss = self:GetScreenScale()
local delay = 0
if (self.ServerTime) then
delay = self.ServerTime - os.time()
end
local curprep
local frame = self:MakeWindow(L"performance_reports")
frame:SetSize(800 * ss, 600 * ss)
frame:Center()
frame:MakePopup()
_SH_REPORTS_PERF = frame
frame:AddHeaderButton(matBack, function()
frame:Close()
self:ShowReports()
end)
local sel = vgui.Create("DScrollPanel", frame)
sel:SetDrawBackground(false)
sel:SetWide(140 * ss)
sel:Dock(LEFT)
sel.Paint = function(me, w, h)
draw.RoundedBoxEx(4, 0, 0, w, h, styl.inbg, false, false, true, false)
end
self:PaintScroll(sel)
local ilist_perf = vgui.Create("DListView", frame)
ilist_perf:SetVisible(false)
ilist_perf:SetSortable(false)
ilist_perf:SetDrawBackground(false)
ilist_perf:SetDataHeight(32)
ilist_perf:Dock(FILL)
ilist_perf:AddColumn(L"admin")
ilist_perf:AddColumn(L"num_claimed")
ilist_perf:AddColumn(L"num_closed")
ilist_perf:AddColumn(L"time_spent")
self:PaintList(ilist_perf)
local ilist_rating = vgui.Create("DListView", frame)
ilist_rating:SetVisible(false)
ilist_rating:SetSortable(false)
ilist_rating:SetDrawBackground(false)
ilist_rating:SetDataHeight(32)
ilist_rating:Dock(FILL)
ilist_rating:AddColumn(L"admin")
ilist_rating:AddColumn(L"rating")
self:PaintList(ilist_rating)
local ilist_history = vgui.Create("DListView", frame)
ilist_history:SetVisible(false)
ilist_history:SetSortable(false)
ilist_history:SetDrawBackground(false)
ilist_history:SetDataHeight(32)
ilist_history:Dock(FILL)
ilist_history:AddColumn(L"reporter")
ilist_history:AddColumn(L"reported_player")
ilist_history:AddColumn(L"reason")
ilist_history:AddColumn(L"admin")
ilist_history:AddColumn(L"rating")
-- ilist_history.Think = function(me)
-- local hover = vgui.GetHoveredPanel()
-- if (!IsValid(_SH_REPORTS_HIST_DETAILS)) then
-- if (!IsValid(hover) or !hover.m_HistoryReport) then
-- return end
-- _SH_REPORTS_HIST_DETAILS = NULL
-- else
-- end
-- end
self:PaintList(ilist_history)
frame.ShowStaff = function(me, staffs)
if (!ilist_perf:IsVisible()) then
return end
local i = 0
for _, info in pairs (staffs) do
local user = vgui.Create("DPanel", frame)
user:SetDrawBackground(false)
local avi = self:Avatar(info.steamid, 24, user)
avi:SetPos(4, 4)
local name = self:QuickLabel("...", "{prefix}Medium", styl.text, user)
name:Dock(FILL)
name:SetTextInset(ilist_perf:GetDataHeight(), 0)
self:GetName(info.steamid, function(nick)
if (IsValid(name)) then
name:SetText(nick)
end
end)
local line = ilist_perf:AddLine(user, info.claimed, info.closed, self:FullFormatTime(info.timespent))
line:SetAlpha(0)
line:AlphaTo(255, 0.1, 0.1 * i)
self:LineStyle(line)
i = i + 1
end
end
frame.ShowRatings = function(me, ratings)
if (!ilist_rating:IsVisible()) then
return end
ilist_rating:Clear()
local i = 0
for _, info in pairs (ratings) do
if (info.num == 0) then
continue end
local frac = info.total / info.num / 5
local tot = string.Comma(info.num)
local tx = " " .. math.Round(frac * 100) .. "% (" .. tot .. ")"
local user = vgui.Create("DPanel", frame)
user:SetDrawBackground(false)
local avi = self:Avatar(info.steamid, 24, user)
avi:SetPos(4, 4)
local name = self:QuickLabel("...", "{prefix}Medium", styl.text, user)
name:Dock(FILL)
name:SetTextInset(ilist_rating:GetDataHeight(), 0)
self:GetName(info.steamid, function(nick)
if (IsValid(name)) then
name:SetText(nick)
end
end)
local stars = vgui.Create("DPanel", frame)
stars.Paint = function(me, w, h)
local _x, _y = me:LocalToScreen(0, 0)
surface.SetFont("SH_REPORTS.Large")
local wi = surface.GetTextSize("★★★★★")
surface.SetFont("SH_REPORTS.Medium")
local wi2 = surface.GetTextSize(tx)
local wid = wi + wi2
draw.SimpleText("★★★★★", "SH_REPORTS.Large", w * 0.5 - wid * 0.5, h * 0.5, styl.inbg, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
render.SetScissorRect(_x, _y, _x + w * 0.5 - wid * 0.5 + wi * frac, _y + h, true)
draw.SimpleText("★★★★★", "SH_REPORTS.Large", w * 0.5 - wid * 0.5, h * 0.5, styl.rating, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
render.SetScissorRect(0, 0, 0, 0, false)
draw.SimpleText(tx, "SH_REPORTS.Medium", w * 0.5 - wid * 0.5 + wi, h * 0.5, styl.text, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
local line = ilist_rating:AddLine(user, stars)
line:SetAlpha(0)
line:AlphaTo(255, 0.1, 0.1 * i)
self:LineStyle(line)
i = i + 1
end
end
frame.ShowHistory = function(me, history)
if (!ilist_history:IsVisible()) then
return end
ilist_history:Clear()
local i = 0
for _, info in pairs (history) do
local reporter = vgui.Create("DPanel", frame)
reporter:SetDrawBackground(false)
local avi = self:Avatar(info.reporter, 24, reporter)
avi:SetPos(4, 4)
local name = self:QuickLabel("...", "{prefix}Medium", styl.text, reporter)
name:Dock(FILL)
name:SetTextInset(ilist_history:GetDataHeight(), 0)
self:GetName(info.reporter, function(nick)
if (IsValid(name)) then
name:SetText(nick)
end
end)
local reported = vgui.Create("DPanel", frame)
reported:SetDrawBackground(false)
local avi = self:Avatar(info.reported, 24, reported)
avi:SetPos(4, 4)
local name = self:QuickLabel("...", "{prefix}Medium", styl.text, reported)
name:Dock(FILL)
name:SetTextInset(ilist_history:GetDataHeight(), 0)
if (info.reported == "0") then
avi:SetVisible(false)
name:SetText("[" .. L"other" .. "]")
name:SetTextInset(0, 0)
name:SetContentAlignment(5)
else
self:GetName(info.reported, function(nick)
if (IsValid(name)) then
name:SetText(nick)
end
end)
end
local admin = vgui.Create("DPanel", frame)
admin:SetDrawBackground(false)
local avi = self:Avatar(info.admin, 24, admin)
avi:SetPos(4, 4)
local name = self:QuickLabel("...", "{prefix}Medium", styl.text, admin)
name:Dock(FILL)
name:SetTextInset(ilist_history:GetDataHeight(), 0)
self:GetName(info.admin, function(nick)
if (IsValid(name)) then
name:SetText(nick)
end
end)
local rating
if (info.rating > 0) then
local frac = info.rating / 5
rating = vgui.Create("DPanel", frame)
rating.Paint = function(me, w, h)
local _x, _y = me:LocalToScreen(0, 0)
surface.SetFont("SH_REPORTS.Large")
local wi = surface.GetTextSize("★★★★★")
local wid = wi
draw.SimpleText("★★★★★", "SH_REPORTS.Large", w * 0.5 - wid * 0.5, h * 0.5, styl.inbg, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
render.SetScissorRect(_x, _y, _x + w * 0.5 - wid * 0.5 + wi * frac, _y + h, true)
draw.SimpleText("★★★★★", "SH_REPORTS.Large", w * 0.5 - wid * 0.5, h * 0.5, styl.rating, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
render.SetScissorRect(0, 0, 0, 0, false)
end
end
local line = ilist_history:AddLine(reporter, reported, info.reason, admin, info.rating > 0 and rating or L"none")
line:SetAlpha(0)
line:AlphaTo(255, 0.1, 0.1 * i)
line:SetToolTip(os.date(self.TimeFormat, info.date) .. "\n\n" .. L"waiting_time" .. ": " .. self:FullFormatTime(info.waiting_time) .. "\n\n" .. L"comment" .. ":\n" .. info.comment)
self:LineStyle(line)
// HAAAAAAAAACKS
-- line.m_HistoryReport = info
-- local function RecFix(s)
-- for _, v in pairs (s:GetChildren()) do
-- v.m_HistoryReport = info
-- v.m_HistoryLine = line
-- RecFix(v)
-- end
-- end
-- RecFix(line)
i = i + 1
end
end
local function display_perf(start, prep)
if (curprep == start) then
return end
curprep = start
frame.m_iID = prep.id
ilist_perf:Clear()
ilist_perf:SetVisible(true)
ilist_rating:SetVisible(false)
ilist_history:SetVisible(false)
local ds, de = os.date(self.DateFormat, start), os.date(self.DateFormat, prep.end_time)
frame.m_Title:SetText(L"performance_reports" .. /* 76561198398853124 */ " (" .. ds .. " - " .. de .. ")")
frame.m_Title:SizeToContentsX()
if (prep.staff) then
frame:ShowStaff(prep.staff)
else
easynet.SendToServer("SH_REPORTS.RequestPerfReportStaff", {id = prep.id})
end
self:Notify(L("displaying_perf_report_from_x_to_y", ds, de), 5, styl.success, frame)
end
local btn_ratings = self:QuickButton(L"rating", function()
ilist_perf:SetVisible(false)
ilist_history:SetVisible(false)
ilist_rating:SetVisible(true)
ilist_rating:Clear()
frame.m_Title:SetText(L"performance_reports")
frame.m_Title:SizeToContentsX()
easynet.SendToServer("SH_REPORTS.RequestStaffRatings")
end, sel)
btn_ratings:SetContentAlignment(4)
btn_ratings:SetTextInset(m + 2, 0)
btn_ratings:Dock(TOP)
btn_ratings:SetTall(32 * ss)
btn_ratings.m_iRound = 0
btn_ratings.PaintOver = function(me, w, h)
if (ilist_rating:IsVisible()) then
surface.SetDrawColor(styl.header)
surface.DrawRect(0, 0, 4, h)
end
end
local btn_history = self:QuickButton(L"history", function()
ilist_perf:SetVisible(false)
ilist_rating:SetVisible(false)
ilist_history:SetVisible(true)
ilist_history:Clear()
frame.m_Title:SetText(L"performance_reports")
frame.m_Title:SizeToContentsX()
easynet.SendToServer("SH_REPORTS.RequestReportHistory")
end, sel)
btn_history:SetContentAlignment(4)
btn_history:SetTextInset(m + 2, 0)
btn_history:Dock(TOP)
btn_history:SetTall(32 * ss)
btn_history.m_iRound = 0
btn_history.PaintOver = function(me, w, h)
if (ilist_history:IsVisible()) then
surface.SetDrawColor(styl.header)
surface.DrawRect(0, 0, 4, h)
end
end
for _, prep in SortedPairs (self.CachedPerfReports, true) do
local btn = self:QuickButton(os.date(self.DateFormat, prep.start_time), function()
display_perf(prep.start_time, prep)
end, sel, nil, prep.end_time >= (os.time() + delay) and styl.success or styl.text)
btn:SetContentAlignment(4)
btn:SetTextInset(m + 2, 0)
btn:Dock(TOP)
btn:SetTall(32 * ss)
btn.m_iRound = 0
btn.PaintOver = function(me, w, h)
if (curprep == prep.start_time and ilist_perf:IsVisible()) then
surface.SetDrawColor(styl.header)
surface.DrawRect(0, 0, 4, h)
end
end
end
frame:SetAlpha(0)
frame:AlphaTo(255, 0.1)
end
easynet.Callback("SH_REPORTS.SendPerfReports", function(data)
SH_REPORTS.CachedPerfReports = data.struct_perf_reports
SH_REPORTS:ShowPerformanceReports()
end)
easynet.Callback("SH_REPORTS.SendPerfReportStaff", function(data)
if (!IsValid(_SH_REPORTS_PERF) or _SH_REPORTS_PERF.m_iID ~= data.id) then
return end
_SH_REPORTS_PERF:ShowStaff(data.struct_perf_reports_staff)
end)
easynet.Callback("SH_REPORTS.SendRatings", function(data)
if (!IsValid(_SH_REPORTS_PERF)) then
return end
_SH_REPORTS_PERF:ShowRatings(data.struct_rating)
end)
easynet.Callback("SH_REPORTS.SendHistoryList", function(data)
if (!IsValid(_SH_REPORTS_PERF)) then
return end
local steamids = data.struct_history_steamids
for _, dat in pairs (data.struct_history_list) do
dat.reporter = steamids[dat.reporter_nid].steamid
dat.reported = steamids[dat.reported_nid].steamid
dat.admin = steamids[dat.admin_nid].steamid
dat.reporter_nid = nil
dat.reported_nid = nil
dat.admin_nid = nil
end
_SH_REPORTS_PERF:ShowHistory(data.struct_history_list)
end)
-- vk.com/urbanichka

View File

@@ -0,0 +1,71 @@
local function L(...) return SH_REPORTS:L(...) end
local matStar = Material("shenesis/reports/star.png", "noclamp smooth")
function SH_REPORTS:ShowRating(report_id, admin_name)
if (IsValid(_SH_REPORTS_RATE)) then
_SH_REPORTS_RATE:Remove()
end
local styl = self.Style
local th, m = self:GetPadding(), self:GetMargin()
local m2 = m * 0.5
local ss = self:GetScreenScale()
local cur_rate = 3
local is = 64 * ss
local frame = self:MakeWindow(L"rating")
frame:SetSize(1, 144 * ss + m * 2)
frame:MakePopup()
_SH_REPORTS_RATE = frame
local stars = vgui.Create("DPanel", frame)
stars:SetDrawBackground(false)
stars:Dock(FILL)
stars:DockMargin(m, m, m, m)
for i = 1, 5 do
local st = vgui.Create("DButton", stars)
st:SetToolTip(i .. "/" .. 5)
st:SetText("")
st:SetWide(64 * ss)
st:Dock(LEFT)
st:DockMargin(0, 0, m2, 0)
st.Paint = function(me, w, h)
if (!me.m_CurColor) then
me.m_CurColor = styl.inbg
else
me.m_CurColor = self:LerpColor(FrameTime() * 20, me.m_CurColor, cur_rate >= i and styl.rating or styl.inbg)
end
surface.SetMaterial(matStar)
surface.SetDrawColor(me.m_CurColor)
surface.DrawTexturedRect(0, 0, w, h)
end
st.OnCursorEntered = function()
cur_rate = i
end
st.DoClick = function()
easynet.SendToServer("SH_REPORTS.RateAdmin", {report_id = report_id, rating = i})
frame:Close()
end
end
local lbl = self:QuickLabel(L("rate_question", admin_name), "{prefix}Large", styl.text, frame)
lbl:SetContentAlignment(5)
lbl:Dock(BOTTOM)
lbl:DockMargin(0, 0, 0, m)
frame:SetWide(math.max(400 * ss, lbl:GetWide() + m * 2))
frame:Center()
local sp = math.ceil((frame:GetWide() - (64 * ss) * 5 - m * 4) * 0.5)
stars:DockPadding(sp, 0, sp, 0)
end
easynet.Callback("SH_REPORTS.PromptRating", function(data)
SH_REPORTS:ShowRating(data.report_id, data.admin_name)
end)
-- vk.com/urbanichka

View File

@@ -0,0 +1,65 @@
SH_REPORTS.Language = {
reports = "Жалоба",
your_reports = "Ваша жалоба",
report_list = "Список жалоб",
reporter = "Подающий",
reported_player = "Обвиняемый",
reason = "Причина",
waiting_time = "Время ожидания",
claimed = "Взять?",
unclaimed = "Не взята",
new_report = "Новая жалоба",
player_to_report = "Игрок, на которого жалоба",
comment = "Комментарий",
submit_report = "Отправить жалобу",
view_report = "Посмотреть жалобы",
actions = "Действия",
goto = "К нему",
bring = "К себе",
bring_reported_player = "Телепортировать обвиняемого?",
yes = "Да",
no = "Нет",
claim_report = "Взять жалобу",
close_report = "Закрыть жалобу",
view = "Посмотреть",
start_sit_session = "Start sit session",
report_of_x = "%s's report",
claimed_by_x = "Взята %s",
other = "Другое",
none = "Нету",
performance_reports = "Производительности",
displaying_perf_report_from_x_to_y = "Отображение отчета о производительности с %s по %s.",
admin = "Админ",
num_claimed = "Взято",
num_closed = "Закрыта",
time_spent = "Прошло времени",
rating = "Оценка",
rate_question = "Как бы вы оценили работу %s?",
rate_thanks = "Спасибо за оценку!",
rate_notification = "%s поставил вам оценку %s.",
history = "История",
not_allowed_to_run_cmd = "Вам не разрешено использовать эту команду.",
report_submitted = "Ваша жалоба была отправлена. Ожидайте ответа от администратора",
report_limit_reached = "Вы достигли лимита жалоб, которые вы можете отправить!",
report_received = "Новая жалоба от %s против %s: %s",
report_claimed = "Жалоба взята!",
admin_claimed_your_report = "Администратор взял вашу жалобу!",
admin_has_disconnected = "Администратор разбирающий вашу жалобу вышел.",
report_closed = "Жалоба закрыта.",
your_report_was_closed = "Ваша жалоба была закрыта администратором.",
reporter_closed_report = "Игрок закрыл свою жалобу.",
report_already_claimed = "Эта жалоба уже взята кем-то.",
report_non_existent = "Эта жалоба не существует.",
player_has_no_reports = "У цели нету активных жалоб.",
cannot_report_self = "Вы не можете пожаловаться на самого себя.",
cannot_report_admin = "Вы не можете пожаловаться на администратора.",
cannot_report_as_admin = "Вы администратор, вы не можете подавать жалобы!",
claimed_report_still_active = "Вы уже имеете открытую жалобу.",
select_reason_first = "Выберите причину для жалобы.",
select_player_first = "Выберите игрока на которого вы жалуетесь..",
there_are_x_reports_pending = "Ожидается рассмотрения %d жалоб.",
}

View File

@@ -0,0 +1,67 @@
SH_REPORTS.Language = {
reports = "Signalement",
your_reports = "Vos signalements",
report_list = "Liste de signalements",
reporter = "Signaler",
reported_player = "Joueur signalé(e)",
reason = "Raison",
waiting_time = "Temps d'attente",
claimed = "Accepté ?",
unclaimed = "Non accepté",
new_report = "Signaler un joueur",
player_to_report = "Joueur à signaler",
comment = "Commentaire",
submit_report = "Envoyer signalement",
view_report = "Voir signalement",
actions = "Actions",
goto = "Aller à",
bring = "Ramener",
bring_reported_player = "Ramener le joueur signalé ?",
yes = "Oui",
no = "Non",
claim_report = "Accepter le signalement",
close_report = "Fermer le signalement",
view = "Voir",
start_sit_session = "Commencer une session isolée",
report_of_x = "Signalement de %s",
claimed_by_x = "Accepté par %s",
other = "Autre",
none = "Aucun",
performance_reports = "Rapports de performance",
displaying_perf_report_from_x_to_y = "Affichage des rapports de performance de %s à %s.", -- 76561198398853149
admin = "Admin",
num_claimed = "Acceptés",
num_closed = "Fermés",
time_spent = "Temps passé",
rating = "Note",
rate_question = "Comment noteriez-vous la performance de %s ?",
rate_thanks = "Merci pour votre note !",
rate_notification = "%s vous a donné une note de %s.",
history = "Historique",
not_allowed_to_run_cmd = "Vous n'êtes pas autorisé à exécuter cette commande.",
report_submitted = "Signalement soumis. Veuillez attendre la réponse d'un admin.",
report_limit_reached = "Vous avez atteint la limite de signalements soumis !",
report_received = "Nouveau signalement de %s contre %s : %s",
report_claimed = "Signalement accepté !",
admin_claimed_your_report = "Un admin a accepté votre signalement !",
admin_has_disconnected = "L'admin en charge de votre signalement s'est déconnecté.",
report_closed = "Signalement fermé.",
your_report_was_closed = "Votre signalement a é fermé par un admin.",
reporter_closed_report = "Le signaleur a fermé son signalement.",
report_already_claimed = "Ce signalement a déjà é accepté.",
report_non_existent = "Ce signalement n'existe pas.",
player_has_no_reports = "La cible n'a pas de signalements actifs.",
cannot_report_self = "Vous ne pouvez pas signaler vous-même.",
cannot_report_admin = "Vous ne pouvez pas signaler un admin.",
cannot_report_as_admin = "Vous êtes un admin ; vous ne pouvez pas signaler de joueurs !",
claimed_report_still_active = "Vous avez déjà un rapport d'accepté ; finissez-le d'abord !",
select_reason_first = "Choisissez la raison de votre signalement.",
select_player_first = "Choisissez le joueur à signaler.",
there_are_x_reports_pending = "Il y a %d signalements en attente.",
}
-- vk.com/urbanichka

View File

@@ -0,0 +1,67 @@
SH_REPORTS.Language = {
reports = "Meldungen",
your_reports = "Deine Meldungen",
report_list = "Meldungsliste",
reporter = "Melder",
reported_player = "Gemeldeter Spieler",
reason = "Grund",
waiting_time = "Wartezeit",
claimed = "Angenommen?",
unclaimed = "Nicht angenommen",
new_report = "Neue Meldung",
player_to_report = "Täter",
comment = "Kommentar",
submit_report = "Meldung einreichen",
view_report = "Meldung ansehen",
actions = "Aktionen",
goto = "Hingehen",
bring = "Herbringen",
bring_reported_player = "Den gemeldeten Spieler herbringen?",
yes = "Ja",
no = "Nein",
claim_report = "Meldung annehmen",
close_report = "Meldung schließen",
view = "Ansehen",
start_sit_session = "Sitzung starten",
report_of_x = "%ss Meldung",
claimed_by_x = "Angenommen von %s",
other = "Andere",
none = "Nichts",
performance_reports = "Leistungsberichte",
displaying_perf_report_from_x_to_y = "Leistungsberichte von %s bis %s werden dargestellt.",
admin = "Admin",
num_claimed = "Angenommen",
num_closed = "Geschlossen",
time_spent = "Zeit verbracht",
rating = "Beliebtheit",
rate_question = "Wie würden Sie %ss Performance bewerten?",
rate_thanks = "Danke für Ihre Bewertung!",
rate_notification = "%s hat Ihnen eine %s Bewertung gegeben.",
history = "Chronikeinträge",
not_allowed_to_run_cmd = "Sie haben nicht die Erlaubnis diesen Befehl auszuführen",
report_submitted = "Ihre Meldung wurde eingereicht. Bitte",
report_limit_reached = "Sie haben das Limit an Meldungen die sie erstellen können erreicht",
report_received = "Neue Meldung von %s gegen %s: %s",
report_claimed = "Meldung angenommen!",
admin_claimed_your_report = "Ein Admin hat Ihre Meldung angenommen!",
admin_has_disconnected = "Der Admin der Ihre Meldung bearbeitet hat den Server verlassen.",
report_closed = "Meldung geschlossen.",
your_report_was_closed = "Ihre Meldung wurde von einem Admin geschlossen.",
reporter_closed_report = "Der Melder hat seine Meldung geschlossen.",
report_already_claimed = "Diese Meldung wurde bereits angenommen.",
report_non_existent = "Diese Meldung existiert nicht.",
player_has_no_reports = "Spieler hat keine aktiven Meldungen.",
cannot_report_self = "Sie können sich nicht selbst melden.",
cannot_report_admin = "Sie können keinen Admin melden.",
cannot_report_as_admin = "Sie sind ein Admin; sie können keine Meldungen erstellen!",
claimed_report_still_active = "Sie haben eine Meldung bereits angenommen. Erledigen Sie diese zuerst!",
select_reason_first = "Wählen Sie einen Grund für Ihre Meldung aus.",
select_player_first = "Wählen Sie einen Spieler zum Melden aus.",
there_are_x_reports_pending = "Es sind %d Meldungen unerledigt.",
}
-- vk.com/urbanichka

View File

@@ -0,0 +1,121 @@
local base_table = SH_REPORTS
local prefix = "SH_REPORTS."
base_table.DatabaseConfig = {
host = "localhost",
user = "root",
password = "",
database = "mysql",
port = 3306,
}
function base_table:DBPrint(s)
local src = debug.getinfo(1)
local _, __, name = src.short_src:find("addons/(.-)/")
MsgC(Color(0, 200, 255), "[" .. name:upper() .. " DB] ", color_white, s, "\n")
end
function base_table:ConnectToDatabase()
local dm = self.DatabaseMode
if (dm == "mysqloo") then
require("mysqloo")
local cfg = self.DatabaseConfig
self:DBPrint("Connecting to database")
local db = mysqloo.connect(cfg.host, cfg.user, cfg.password, cfg.database, cfg.port)
db:setAutoReconnect(true)
db:setMultiStatements(true)
db.onConnected = function()
self:DBPrint("Connected to database!")
self.m_bConnectedToDB = true
if (self.DatabaseConnected) then
self:DatabaseConnected()
end
end
db.onConnectionFailed = function(me, err)
self:DBPrint("Failed to connect to database: " .. err .. "\n")
print(err)
self.m_bConnectedToDB = false
end
db:connect()
_G[prefix .. "DB"] = db
else
self:DBPrint("Defaulting to sqlite")
self.m_bConnectedToDB = true
if (self.DatabaseConnected) then
self:DatabaseConnected()
end
end
end
function base_table:IsConnectedToDB()
return self.m_bConnectedToDB
end
function base_table:Query(query, callback)
if (!self:IsConnectedToDB()) then
return end
local dm = self.DatabaseMode
callback = callback or function(q, ok, ret) end
if (dm == "mysqloo") then
local q = _G[prefix .. "DB"]:query(query)
q.onSuccess = function(me, data)
_SH_QUERY_LAST_INSERT_ID = me:lastInsert()
callback(query, true, data)
_SH_QUERY_LAST_INSERT_ID = nil
end
q.onError = function(me, err, fq)
callback(query, false, err .. " (" .. fq .. ")")
self:DBPrint(err .. " (" .. fq .. ")")
end
q:start()
else
local d = sql.Query(query)
if (d ~= false) then
callback(query, true, d or {})
else
callback(query, false, sql.LastError())
print("sqlite error (" .. query .. "): " .. sql.LastError())
end
end
end
function base_table:Escape(s)
local dm = self.DatabaseMode
if (dm == "mysqloo") then
return _G[prefix .. "DB"]:escape(s)
else
return sql.SQLStr(s, true)
end
end
function base_table:BetterQuery(query, args, callback)
for k, v in pairs (args) do
if (isstring(v)) then
v = self:Escape(v)
end
v = tostring(v)
query = query:Replace("{" .. k .. "}", "'" .. v .. "'")
query = query:Replace("[" .. k .. "]", v)
end
self:Query(query, callback)
end
hook.Add("InitPostEntity", prefix .. "ConnectToDatabase", function()
base_table:ConnectToDatabase()
end)
if (_G[prefix .. "DB"]) then
base_table.m_bConnectedToDB = _G[prefix .. "DB"]:status() == 0
end
-- vk.com/urbanichka

View File

@@ -0,0 +1,143 @@
AddCSLuaFile()
EASYNET_STRING = 1
EASYNET_FLOAT = 2
EASYNET_BOOL = 3
EASYNET_UINT8 = 4
EASYNET_UINT16 = 5
EASYNET_UINT32 = 6
EASYNET_STRUCTURES = 7
EASYNET_PLAYER = 8
module("easynet", package.seeall)
local Structures = {}
local Creating
function Start(id)
Creating = {
id = id,
nid = #Structures + 1,
args = {},
}
end
function Add(name, type)
Creating.args[name] = {id = table.Count(Creating.args) + 1, type = type}
end
function Register()
local id = Creating.id
Structures[id] = table.Copy(Creating)
if (SERVER) then
util.AddNetworkString(id)
end
end
local function read(typ, name)
if (typ == EASYNET_STRING) then
return net.ReadString()
elseif (typ == EASYNET_FLOAT) then
return net.ReadFloat()
elseif (typ == EASYNET_BOOL) then
return net.ReadBool()
elseif (typ == EASYNET_UINT8) then
return net.ReadUInt(8)
elseif (typ == EASYNET_UINT16) then
return net.ReadUInt(16)
elseif (typ == EASYNET_UINT32) then
return net.ReadUInt(32)
elseif (typ == EASYNET_STRUCTURES) then
local t = {}
local struct = Structures[name]
for i = 1, net.ReadUInt(16) do
t[i] = {}
for n, arg in SortedPairsByMemberValue (struct.args, "id") do
t[i][n] = read(arg.type, n)
end
end
return t
elseif (typ == EASYNET_PLAYER) then
return Player(net.ReadUInt(16))
end
end
function Callback(id, cb)
net.Receive(id, function(len, ply)
if (_EASYNET_DEBUG) then
print("[EasyNet][Rcv][" .. id .. "] " .. (len / 8) .. " bytes")
end
local struct = Structures[id]
local data = {}
for name, arg in SortedPairsByMemberValue (struct.args, "id") do
data[name] = read(arg.type, name)
end
cb(data, ply)
end)
end
local function write(val, typ, name)
if (typ == EASYNET_STRING) then
net.WriteString(val)
elseif (typ == EASYNET_FLOAT) then
net.WriteFloat(val)
elseif (typ == EASYNET_BOOL) then
net.WriteBool(val)
elseif (typ == EASYNET_UINT8) then
if (isstring(val)) then
val = tonumber(val) or 0
end
net.WriteUInt(val, 8)
elseif (typ == EASYNET_UINT16) then
net.WriteUInt(val, 16)
elseif (typ == EASYNET_UINT32) then
net.WriteUInt(val, 32)
elseif (typ == EASYNET_STRUCTURES) then
local struct = Structures[name]
net.WriteUInt(table.Count(val), 16)
for k, v in pairs (val) do
for n, arg in SortedPairsByMemberValue (struct.args, "id") do
write(v[n], arg.type, n)
end
end
elseif (typ == EASYNET_PLAYER) then
net.WriteUInt(IsValid(val) and val:UserID() or 0, 16)
end
end
local function prepare(id, data)
local struct = Structures[id]
net.Start(id)
for name, arg in SortedPairsByMemberValue (struct.args, "id") do
write(data[name], arg.type, name)
end
if (_EASYNET_DEBUG) then
print("[EasyNet][Send][" .. id .. "] " .. net.BytesWritten() .. " bytes")
end
end
if (SERVER) then
function Send(rec, id, data)
prepare(id, data)
net.Send(rec)
end
else
function SendToServer(id, data)
prepare(id, data)
net.SendToServer()
end
end
-- vk.com/urbanichka

View File

@@ -0,0 +1,697 @@
local base_table = SH_REPORTS
local font_prefix = "SH_REPORTS."
--
local matClose = Material("shenesis/general/close.png", "noclamp smooth")
local function get_scale()
local sc = math.Clamp(ScrH() / 1080, 0.75, 1)
if (!th) then
th = 48 * sc
m = th * 0.25
end
return sc
end
function base_table:L(s, ...)
return string.format(self.Language[s] or s, ...)
end
function base_table:GetPadding()
return th
end
function base_table:GetMargin()
return m
end
function base_table:GetScreenScale()
return get_scale()
end
function base_table:CreateFonts(scale)
local font = self.Font
local font_bold = self.FontBold
local sizes = {
[12] = "Small",
[16] = "Medium",
[20] = "Large",
[24] = "Larger",
[32] = "Largest",
[200] = "3D",
}
for s, n in pairs (sizes) do
surface.CreateFont(font_prefix .. n, {font = font, size = s * scale})
surface.CreateFont(font_prefix .. n .. "B", {font = font_bold, size = s * scale})
end
end
hook.Add("InitPostEntity", font_prefix .. "CreateFonts", function()
base_table:CreateFonts(get_scale())
end)
function base_table:MakeWindow(title)
local scale = get_scale()
local styl = self.Style
local pnl = vgui.Create("EditablePanel")
pnl.m_bDraggable = true
pnl.SetDraggable = function(me, b)
me.m_bDraggable = b
end
pnl.Paint = function(me, w, h)
if (me.m_fCreateTime) then
Derma_DrawBackgroundBlur(me, me.m_fCreateTime)
end
draw.RoundedBox(4, 0, 0, w, h, styl.bg)
end
pnl.OnClose = function() end
pnl.Close = function(me)
if (me.m_bClosing) then
return end
me.m_bClosing = true
me:AlphaTo(0, 0.1, 0, function()
me:Remove()
end)
me:OnClose()
end
local header = vgui.Create("DPanel", pnl)
header:SetTall(th)
header:Dock(TOP)
header.Paint = function(me, w, h)
draw.RoundedBoxEx(4, 0, 0, w, h, styl.header, true, true, false, false)
end
header.Think = function(me)
if (me.Hovered and pnl.m_bDraggable) then
me:SetCursor("sizeall")
end
local drag = me.m_Dragging
if (drag) then
local mx, my = math.Clamp(gui.MouseX(), 1, ScrW() - 1), math.Clamp(gui.MouseY(), 1, ScrH() - 1)
local x, y = mx - drag[1], my - drag[2]
pnl:SetPos(x, y)
end
end
header.OnMousePressed = function(me)
if (pnl.m_bDraggable) then
me.m_Dragging = {gui.MouseX() - pnl.x, gui.MouseY() - pnl.y}
me:MouseCapture(true)
end
end
header.OnMouseReleased = function(me)
me.m_Dragging = nil
me:MouseCapture(false)
end
pnl.m_Header = header
local titlelbl = self:QuickLabel(title, font_prefix .. "Larger", styl.text, header)
titlelbl:Dock(LEFT)
titlelbl:DockMargin(m, 0, 0, 0)
pnl.m_Title = titlelbl
local close = vgui.Create("DButton", header)
close:SetText("")
close:SetWide(th)
close:Dock(RIGHT)
close.Paint = function(me, w, h)
if (me.Hovered) then
draw.RoundedBoxEx(4, 0, 0, w, h, styl.close_hover, false, true, false, false)
end
if (me:IsDown()) then
draw.RoundedBoxEx(4, 0, 0, w, h, styl.hover, false, true, false, false)
end
surface.SetDrawColor(me:IsDown() and styl.text_down or styl.text)
surface.SetMaterial(matClose)
surface.DrawTexturedRectRotated(w * 0.5, h * 0.5, 16 * scale, 16 * scale, 0)
end
close.DoClick = function(me)
pnl:Close()
end
pnl.m_Close = close
pnl.AddHeaderButton = function(me, icon, callback)
local btn = vgui.Create("DButton", header)
btn:SetText("")
btn:SetWide(self:GetPadding())
btn:Dock(RIGHT)
btn.Paint = function(me, w, h)
if (me.Hovered) then
surface.SetDrawColor(styl.hover)
surface.DrawRect(0, 0, w, h)
end
surface.SetMaterial(icon)
surface.SetDrawColor(styl.text)
surface.DrawTexturedRect(w * 0.5 - 8, h * 0.5 - 8, 16, 16)
end
btn.DoClick = function()
callback()
end
return btn
end
return pnl
end
function base_table:QuickLabel(t, f, c, p)
local l = vgui.Create("DLabel", p)
l:SetText(t)
l:SetFont(f:Replace("{prefix}", font_prefix))
l:SetColor(c)
l:SizeToContents()
return l
end
function base_table:QuickButton(t, cb, p, f, c)
p:SetMouseInputEnabled(true)
local styl = self.Style
local b = vgui.Create("DButton", p)
b:SetText(t)
b:SetFont((f or "{prefix}Medium"):Replace("{prefix}", font_prefix))
b:SetColor(c or styl.text)
b:SizeToContents()
b.DoClick = function(me)
cb(me)
end
b.Paint = function(me, w, h)
local r = me.m_iRound or 4
draw.RoundedBox(r, 0, 0, w, h, me.m_Background or styl.inbg)
if (!me.m_bNoHover and me.Hovered) then
draw.RoundedBox(r, 0, 0, w, h, styl.hover)
end
if (me.IsDown and me:IsDown()) then
draw.RoundedBox(r, 0, 0, w, h, styl.hover)
end
end
return b
end
function base_table:ButtonStyle(b, f, c)
local styl = self.Style
b:SetFont((f or "{prefix}Medium"):Replace("{prefix}", font_prefix))
b:SetContentAlignment(5)
b:SetColor(c or styl.text)
b.Paint = function(me, w, h)
local r = me.m_iRound or 4
draw.RoundedBox(r, 0, 0, w, h, me.m_Background or styl.inbg)
if (!me.m_bNoHover and me.Hovered) then
draw.RoundedBox(r, 0, 0, w, h, styl.hover)
end
if (me.IsDown and me:IsDown()) then
draw.RoundedBox(r, 0, 0, w, h, styl.hover)
end
end
end
function base_table:LineStyle(l)
local styl = self.Style
for _, v in pairs (l.Columns) do
if (v.SetFont) then
v:SetContentAlignment(5)
v:SetFont(font_prefix .. "Medium")
v:SetTextColor(styl.text)
end
end
l.Paint = function(me, w, h)
if (!me:GetAltLine()) then
surface.SetAlphaMultiplier(math.min(me:GetAlpha() / 255, 0.5))
surface.SetDrawColor(styl.inbg)
surface.DrawRect(0, 0, w, h)
surface.SetAlphaMultiplier(me:GetAlpha() / 255)
end
if (me:IsSelectable() and me:IsLineSelected()) then
surface.SetDrawColor(styl.hover)
surface.DrawRect(0, 0, w, h)
elseif (me.Hovered or me:IsChildHovered()) then
surface.SetDrawColor(styl.hover2)
surface.DrawRect(0, 0, w, h)
end
end
end
function base_table:QuickEntry(tx, parent)
parent:SetMouseInputEnabled(true)
parent:SetKeyboardInputEnabled(true)
local styl = self.Style
local entry = vgui.Create("DTextEntry", parent)
entry:SetText(tx or "")
entry:SetFont(font_prefix .. "Medium")
entry:SetDrawLanguageID(false)
entry:SetUpdateOnType(true)
entry:SetTextColor(styl.text)
entry:SetHighlightColor(styl.header)
entry:SetCursorColor(styl.text)
entry.Paint = function(me, w, h)
draw.RoundedBox(4, 0, 0, w, h, styl.textentry)
me:DrawTextEntryText(me:GetTextColor(), me:GetHighlightColor(), me:GetCursorColor())
end
return entry
end
function base_table:QuickComboBox(parent)
parent:SetMouseInputEnabled(true)
local combo = vgui.Create("DComboBox", parent)
combo.m_bNoHover = true
self:ButtonStyle(combo)
combo.OldDoClick = combo.DoClick
combo.DoClick = function(me)
me:OldDoClick()
if (IsValid(me.Menu)) then
for _, v in pairs (me.Menu:GetChildren()[1]:GetChildren()) do -- sdfdsfzz
self:ButtonStyle(v)
v.m_iRound = 0
end
end
end
return combo
end
function base_table:PaintScroll(panel)
local styl = self.Style
local scr = panel.VBar or panel:GetVBar()
scr.Paint = function(_, w, h)
draw.RoundedBox(4, 0, 0, w, h, /* 76561198398853149 styl.header */ styl.bg)
end
scr.btnUp.Paint = function(_, w, h)
draw.RoundedBox(4, 2, 0, w - 4, h - 2, styl.inbg)
end
scr.btnDown.Paint = function(_, w, h)
draw.RoundedBox(4, 2, 2, w - 4, h - 2, styl.inbg)
end
scr.btnGrip.Paint = function(me, w, h)
draw.RoundedBox(4, 2, 0, w - 4, h, styl.inbg)
if (me.Hovered) then
draw.RoundedBox(4, 2, 0, w - 4, h, styl.hover2)
end
if (me.Depressed) then
draw.RoundedBox(4, 2, 0, w - 4, h, styl.hover2)
end
end
end
function base_table:PaintList(ilist)
for _, v in pairs (ilist.Columns) do
self:ButtonStyle(v.Header)
v.DraggerBar:SetVisible(false)
end
self:PaintScroll(ilist)
end
function base_table:StringRequest(title, text, callback)
local styl = self.Style
if (IsValid(_LOUNGE_STRREQ)) then
_LOUNGE_STRREQ:Remove()
end
local scale = get_scale()
local wi, he = 600 * scale, 160 * scale
local cancel = vgui.Create("DPanel")
cancel:SetDrawBackground(false)
cancel:StretchToParent(0, 0, 0, 0)
cancel:MoveToFront()
cancel:MakePopup()
local pnl = self:MakeWindow(title)
pnl:SetSize(wi, he)
pnl:Center()
pnl:MakePopup()
pnl.m_fCreateTime = SysTime()
_LOUNGE_STRREQ = pnl
cancel.OnMouseReleased = function(me, mc)
if (mc == MOUSE_LEFT) then
pnl:Close()
end
end
cancel.Think = function(me)
if (!IsValid(pnl)) then
me:Remove()
end
end
local body = vgui.Create("DPanel", pnl)
body:SetDrawBackground(false)
body:Dock(FILL)
body:DockPadding(m, m, m, m)
local tx = self:QuickLabel(text, font_prefix .. "Large", styl.text, body)
tx:SetContentAlignment(5)
tx:SetWrap(tx:GetWide() > wi - m * 2)
tx:Dock(FILL)
local apply = vgui.Create("DButton", body)
apply:SetText("OK")
apply:SetColor(styl.text)
apply:SetFont(font_prefix .. "Medium")
apply:Dock(BOTTOM)
apply.Paint = function(me, w, h)
draw.RoundedBox(4, 0, 0, w, h, styl.inbg)
if (me.Hovered) then
draw.RoundedBox(4, 0, 0, w, h, styl.hover)
end
if (me:IsDown()) then
draw.RoundedBox(4, 0, 0, w, h, styl.hover)
end
end
local entry = vgui.Create("DTextEntry", body)
entry:RequestFocus()
entry:SetFont(font_prefix .. "Medium")
entry:SetDrawLanguageID(false)
entry:Dock(BOTTOM)
entry:DockMargin(0, m, 0, m)
entry.Paint = function(me, w, h)
draw.RoundedBox(4, 0, 0, w, h, styl.textentry)
me:DrawTextEntryText(me:GetTextColor(), me:GetHighlightColor(), me:GetCursorColor())
end
entry.OnEnter = function()
apply:DoClick()
end
apply.DoClick = function()
pnl:Close()
callback(entry:GetValue())
end
pnl.OnFocusChanged = function(me, gained)
if (!gained) then
timer.Simple(0, function()
if (!IsValid(me) or vgui.GetKeyboardFocus() == entry) then
return end
me:Close()
end)
end
end
pnl:SetWide(math.max(math.min(tx:GetWide() + m * 2, pnl:GetWide()), th * 2))
pnl:CenterHorizontal()
pnl:SetAlpha(0)
pnl:AlphaTo(255, 0.1)
end
function base_table:Menu()
local styl = self.Style
if (IsValid(_LOUNGE_MENU)) then
_LOUNGE_MENU:Remove()
end
local cancel = vgui.Create("DPanel")
cancel:SetDrawBackground(false)
cancel:StretchToParent(0, 0, 0, 0)
cancel:MoveToFront()
cancel:MakePopup()
local pnl = vgui.Create("DPanel")
pnl:SetDrawBackground(false)
pnl:SetSize(20, 1)
pnl.AddOption = function(me, text, callback)
surface.SetFont(font_prefix .. "MediumB")
local wi, he = surface.GetTextSize(text)
wi = wi + m * 2
he = he + m
me:SetWide(math.max(wi, me:GetWide()))
me:SetTall(pnl:GetTall() + he)
local btn = vgui.Create("DButton", me)
btn:SetText(self:L(text))
btn:SetFont(font_prefix .. "MediumB")
btn:SetColor(styl.text)
btn:Dock(TOP)
btn:SetSize(wi, he)
btn.Paint = function(me, w, h)
surface.SetDrawColor(styl.menu)
surface.DrawRect(0, 0, w, h)
if (me.Hovered) then
surface.SetDrawColor(styl.hover)
surface.DrawRect(0, 0, w, h)
end
if (me:IsDown()) then
surface.SetDrawColor(styl.hover)
surface.DrawRect(0, 0, w, h)
end
end
btn.DoClick = function(me)
if (callback) then
callback()
end
pnl:Close()
end
return btn
end
pnl.Open = function(me)
me:SetPos(gui.MouseX(), math.min(math.max(0, ScrH() - me:GetTall()), gui.MouseY()))
me:MakePopup()
end
pnl.Close = function(me)
if (me.m_bClosing) then
return end
me.m_bClosing = true
me:AlphaTo(0, 0.1, 0, function()
me:Remove()
end)
end
_LOUNGE_MENU = pnl
cancel.OnMouseReleased = function(me, mc)
pnl:Close()
end
cancel.Think = function(me)
if (!IsValid(pnl)) then
me:Remove()
end
end
return pnl
end
function base_table:PanelPaint(name)
local styl = self.Style
local col = styl[name] or styl.bg
return function(me, w, h)
draw.RoundedBox(4, 0, 0, w, h, col)
end
end
// https://facepunch.com/showthread.php?t=1522945&p=50524545&viewfull=1#post50524545|76561198398853124
local sin, cos, rad = math.sin, math.cos, math.rad
local rad0 = rad(0)
local function DrawCircle(x, y, radius, seg)
local cir = {
{x = x, y = y}
}
for i = 0, seg do
local a = rad((i / seg) * -360)
table.insert(cir, {x = x + sin(a) * radius, y = y + cos(a) * radius})
end
table.insert(cir, {x = x + sin(rad0) * radius, y = y + cos(rad0) * radius})
surface.DrawPoly(cir)
end
function base_table:Avatar(ply, siz, par)
if (type(ply) == "Entity" and !IsValid(ply)) then
return end
if (isnumber(ply)) then
ply = tostring(ply)
end
siz = siz or 32
local hsiz = siz * 0.5
local url = "http://steamcommunity.com/profiles/" .. (isstring(ply) and ply or ply:SteamID64() or "")
par:SetMouseInputEnabled(true)
local pnl = vgui.Create("DPanel", par)
pnl:SetSize(siz, siz)
pnl:SetDrawBackground(false)
pnl.Paint = function() end
local av = vgui.Create("AvatarImage", pnl)
if (isstring(ply)) then
av:SetSteamID(ply, siz)
else
av:SetPlayer(ply, siz)
end
av:SetPaintedManually(true)
av:SetSize(siz, siz)
local btn = vgui.Create("DButton", av)
btn:SetToolTip("Click here to view " .. (isstring(ply) and "their" or ply:Nick() .. "'s") .. " Steam Profile")
btn:SetText("")
btn:Dock(FILL)
btn.Paint = function() end
btn.DoClick = function(me)
gui.OpenURL(url)
end
pnl.SetSteamID = function(me, s)
av:SetSteamID(s, siz)
url = "http://steamcommunity.com/profiles/" .. s
end
pnl.SetPlayer = function(me, p)
av:SetPlayer(p, siz)
url = "http://steamcommunity.com/profiles/" .. p:SteamID64()
end
pnl.Paint = function(me, w, h)
render.ClearStencil()
render.SetStencilEnable(true)
render.SetStencilWriteMask(1)
render.SetStencilTestMask(1)
render.SetStencilFailOperation(STENCILOPERATION_REPLACE)
render.SetStencilPassOperation(STENCILOPERATION_ZERO)
render.SetStencilZFailOperation(STENCILOPERATION_ZERO)
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_NEVER)
render.SetStencilReferenceValue(1)
draw.NoTexture()
surface.SetDrawColor(color_black)
DrawCircle(hsiz, hsiz, hsiz, hsiz)
render.SetStencilFailOperation(STENCILOPERATION_ZERO)
render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
render.SetStencilZFailOperation(STENCILOPERATION_ZERO)
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL)
render.SetStencilReferenceValue(1)
av:PaintManual()
render.SetStencilEnable(false)
render.ClearStencil()
end
return pnl
end
local c = {}
function base_table:GetName(sid, cb)
if (c[sid]) then
cb(c[sid])
return
end
for _, v in pairs (player.GetAll()) do
if (v:SteamID64() == sid) then
c[sid] = v:Nick()
cb(v:Nick())
return
end
end
steamworks.RequestPlayerInfo(sid)
timer.Simple(1, function()
local n = steamworks.GetPlayerName(sid)
c[sid] = n
cb(n)
end)
end
function base_table:Notify(msg, dur, bg, parent)
if (IsValid(_SH_NOTIFY)) then
_SH_NOTIFY:Close()
end
dur = dur or 3
bg = bg or self.Style.header
local fnt = font_prefix .. "Larger"
local w, h = ScrW(), ScrH()
if (IsValid(parent)) then
w, h = parent:GetSize()
fnt = font_prefix .. "Large"
end
local p = vgui.Create("DButton", parent)
p:MoveToFront()
p:SetText(self.Language[msg] or msg)
p:SetFont(fnt)
p:SetColor(self.Style.text)
p:SetSize(w, draw.GetFontHeight(fnt) + self:GetMargin() * 2)
p:AlignTop(h)
p.Paint = function(me, w, h)
surface.SetDrawColor(bg)
surface.DrawRect(0, 0, w, h)
end
p.Close = function(me)
if (me.m_bClosing) then
return end
me.m_bClosing = true
me:Stop()
me:MoveTo(0, h, 0.2, 0, -1, function()
me:Remove()
end)
end
p.DoClick = p.Close
_SH_NOTIFY = p
p:MoveTo(0, h - p:GetTall(), 0.2, 0, -1, function()
p:MoveTo(0, h, 0.2, dur, -1, function()
p:Remove()
end)
end)
end
function base_table:LerpColor(frac, from, to)
return Color(Lerp(frac, from.r, to.r), Lerp(frac, from.g, to.g), Lerp(frac, from.b, to.b), Lerp(frac, from.a, to.a))
end
-- vk.com/urbanichka

View File

@@ -0,0 +1,225 @@
function SH_REPORTS:GetMidnight(offset)
return os.time() - tonumber(os.date("%H")) * 3600 - tonumber(os.date("%M")) * 60 - tonumber(os.date("%S")) + 86400 * (offset or /* 76561198398853124 */ 0)
end
-- fresh from NEP
local d = {
[86400 * 31] = "mo",
[86400 * 7] = "w",
[86400] = "d",
[3600] = "h",
[60] = "min",
[1] = "s",
}
local c2 = {}
function SH_REPORTS:FullFormatTime(i)
if (c2[i]) then
return c2[i]
end
local f = i
local t = {}
for ti, s in SortedPairs(d, true) do
local f = math.floor(i / ti)
if (f > 0) then
table.insert(t, f .. s)
i = i - f * ti
end
end
t = table.concat(t, " ")
c2[f] = t
return t
end
function SH_REPORTS:IsAdmin(ply)
return self.Usergroups[ply:GetUserGroup()] ~= nil
end
-- SERVER -> CLIENT
easynet.Start("SH_REPORTS.SendList")
easynet.Add("server_time", EASYNET_UINT32)
easynet.Add("struct_reports", EASYNET_STRUCTURES)
easynet.Register()
easynet.Start("SH_REPORTS.Notify")
easynet.Add("msg", EASYNET_STRING)
easynet.Add("positive", EASYNET_BOOL)
easynet.Register()
easynet.Start("SH_REPORTS.Chat")
easynet.Add("msg", EASYNET_STRING)
easynet.Register()
easynet.Start("SH_REPORTS.ReportCreated")
easynet.Add("id", EASYNET_UINT32)
easynet.Add("reporter_id", EASYNET_STRING)
easynet.Add("reporter_name", EASYNET_STRING)
easynet.Add("reported_id", EASYNET_STRING)
easynet.Add("reported_name", EASYNET_STRING)
easynet.Add("reason_id", EASYNET_UINT8)
easynet.Add("comment", EASYNET_STRING)
easynet.Add("time", EASYNET_UINT32)
easynet.Add("admin_id", EASYNET_STRING)
easynet.Register()
easynet.Start("SH_REPORTS.ReportClaimed")
easynet.Add("report_id", EASYNET_UINT8)
easynet.Add("admin_id", EASYNET_STRING)
easynet.Register()
easynet.Start("SH_REPORTS.ReportClosed")
easynet.Add("report_id", EASYNET_UINT8)
easynet.Register()
easynet.Start("SH_REPORTS.QuickReport")
easynet.Add("comment", EASYNET_STRING)
easynet.Add("lastkiller", EASYNET_PLAYER)
easynet.Add("lastarrester", EASYNET_PLAYER)
easynet.Register()
easynet.Start("SH_REPORTS.MinimizeReport")
easynet.Add("report_id", EASYNET_UINT32)
easynet.Register()
easynet.Start("SH_REPORTS.SendPerfReports")
easynet.Add("struct_perf_reports", EASYNET_STRUCTURES)
easynet.Register()
easynet.Start("SH_REPORTS.SendPerfReportStaff")
easynet.Add("id", EASYNET_UINT32)
easynet.Add("struct_perf_reports_staff", EASYNET_STRUCTURES)
easynet.Register()
easynet.Start("SH_REPORTS.ReportsPending")
easynet.Add("num", EASYNET_UINT16)
easynet.Add("struct_reports", EASYNET_STRUCTURES)
easynet.Register()
easynet.Start("SH_REPORTS.AdminLeft")
easynet.Add("report_id", EASYNET_UINT32)
easynet.Register()
easynet.Start("SH_REPORTS.PromptRating")
easynet.Add("report_id", EASYNET_UINT32)
easynet.Add("admin_name", EASYNET_STRING)
easynet.Register()
easynet.Start("SH_REPORTS.SendRatings")
easynet.Add("struct_rating", EASYNET_STRUCTURES)
easynet.Register()
easynet.Start("SH_REPORTS.SendHistoryList")
easynet.Add("struct_history_steamids", EASYNET_STRUCTURES)
easynet.Add("struct_history_list", EASYNET_STRUCTURES)
easynet.Register()
easynet.Start("SH_REPORTS.SendReportValid")
easynet.Add("report_id", EASYNET_UINT32)
easynet.Add("valid", EASYNET_BOOL)
easynet.Register()
-- CLIENT -> SERVER
easynet.Start("SH_REPORTS.PlayerReady")
easynet.Register()
easynet.Start("SH_REPORTS.NewReport")
easynet.Add("reported_name", EASYNET_STRING)
easynet.Add("reported_id", EASYNET_STRING)
easynet.Add("reason_id", EASYNET_UINT8)
easynet.Add("comment", EASYNET_STRING)
easynet.Register()
easynet.Start("SH_REPORTS.RequestList")
easynet.Register()
easynet.Start("SH_REPORTS.ClaimAndTeleport")
easynet.Add("id", EASYNET_UINT32)
easynet.Add("bring", EASYNET_BOOL)
easynet.Add("bring_reported", EASYNET_BOOL)
easynet.Register()
easynet.Start("SH_REPORTS.Claim")
easynet.Add("id", EASYNET_UINT32)
easynet.Register()
easynet.Start("SH_REPORTS.ClaimAndCSit")
easynet.Add("id", EASYNET_UINT32)
easynet.Register()
easynet.Start("SH_REPORTS.CloseReport")
easynet.Add("id", EASYNET_UINT32)
easynet.Register()
easynet.Start("SH_REPORTS.RequestPerfReports")
easynet.Register()
easynet.Start("SH_REPORTS.RequestPerfReportStaff" /* 76561198398853149 */)
easynet.Add("id", EASYNET_UINT32)
easynet.Register()
easynet.Start("SH_REPORTS.RateAdmin")
easynet.Add("report_id", EASYNET_UINT32)
easynet.Add("rating", EASYNET_UINT8)
easynet.Register()
easynet.Start("SH_REPORTS.RequestStaffRatings")
easynet.Register()
easynet.Start("SH_REPORTS.RequestReportHistory")
easynet.Register()
easynet.Start("SH_REPORTS.RequestReportValid")
easynet.Add("report_id", EASYNET_UINT32)
easynet.Register()
-- STRUCTURES
easynet.Start("struct_reports")
easynet.Add("id", EASYNET_UINT32)
easynet.Add("reporter_id", EASYNET_STRING)
easynet.Add("reporter_name", EASYNET_STRING)
easynet.Add("reported_id", EASYNET_STRING)
easynet.Add("reported_name", EASYNET_STRING)
easynet.Add("reason_id", EASYNET_UINT8)
easynet.Add("comment", EASYNET_STRING)
easynet.Add("time", EASYNET_UINT32)
easynet.Add("admin_id", EASYNET_STRING)
easynet.Register()
easynet.Start("struct_perf_reports")
easynet.Add("id", EASYNET_UINT32)
easynet.Add("start_time", EASYNET_UINT32)
easynet.Add("end_time", EASYNET_UINT32)
easynet.Register()
easynet.Start("struct_perf_reports_staff")
easynet.Add("steamid", EASYNET_STRING)
easynet.Add("claimed", EASYNET_UINT16)
easynet.Add("closed", EASYNET_UINT16)
easynet.Add("timespent", EASYNET_UINT16)
easynet.Register()
easynet.Start("struct_rating")
easynet.Add("steamid", EASYNET_STRING)
easynet.Add("total", EASYNET_UINT32)
easynet.Add("num", EASYNET_UINT16)
easynet.Register()
easynet.Start("struct_history_steamids")
easynet.Add("steamid", EASYNET_STRING)
easynet.Register()
easynet.Start("struct_history_list")
easynet.Add("report_id", EASYNET_UINT32)
easynet.Add("reporter_nid", EASYNET_UINT16)
easynet.Add("reported_nid", EASYNET_UINT16)
easynet.Add("reason", EASYNET_STRING)
easynet.Add("comment", EASYNET_STRING)
easynet.Add("rating", EASYNET_UINT8)
easynet.Add("date", EASYNET_UINT32)
easynet.Add("waiting_time", EASYNET_UINT16)
easynet.Add("admin_nid", EASYNET_UINT16)
easynet.Register()
-- vk.com/urbanichka

View File

@@ -0,0 +1,973 @@
if (!SH_REPORTS.ActiveReports) then
SH_REPORTS.ActiveReports = {}
SH_REPORTS.UniqueID = 0
SH_REPORTS.InsertSQL = "INSERT IGNORE INTO"
end
if (SH_REPORTS.UseWorkshop) then
-- resource.AddWorkshop("1141886968")
else
resource.AddFile("materials/shenesis/general/back.png")
resource.AddFile("materials/shenesis/general/close.png")
resource.AddFile("materials/shenesis/reports/add.png")
resource.AddFile("materials/shenesis/reports/stats.png")
resource.AddFile("materials/shenesis/reports/star.png")
resource.AddFile("resource/fonts/circular.ttf")
resource.AddFile("resource/fonts/circular_bold.ttf")
end
function SH_REPORTS:DatabaseConnected()
if (self.DatabaseMode == "mysqloo") then
self:Query("SHOW TABLES LIKE 'sh_reports_performance'", function(q, ok, data)
if (!ok) or (data and table.Count(data) > 0) then
self:PostDatabaseConnected()
return
end
self:Query([[
CREATE TABLE `sh_reports_performance` (
`steamid` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`claimed` int(10) unsigned DEFAULT '0',
`closed` int(10) unsigned DEFAULT '0',
`timespent` int(10) unsigned DEFAULT '0',
`report_id` int(10) unsigned DEFAULT '0',
UNIQUE KEY `steamid_UNIQUE` (`steamid`,`report_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `sh_reports_performance_reports` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`start_time` int(10) unsigned DEFAULT '0',
`end_time` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
]], function(q2, ok2, data2)
self:DBPrint("Creating sh_reports_performance and sh_reports_performance_reports: " .. tostring(ok2) .. " (" .. tostring(data2) /* 76561198398853149 */ .. ")")
self:PostDatabaseConnected()
end)
end)
self:Query("SHOW TABLES LIKE 'sh_reports_performance_ratings'", function(q, ok, data)
if (!ok) or (data and table.Count(data) > 0) then
return end
self:Query([[
CREATE TABLE `sh_reports_performance_ratings` (
`steamid` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`total` int(10) unsigned DEFAULT '0',
`num` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`steamid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
]], function(q2, ok2, data2)
self:DBPrint("Creating sh_reports_performance_ratings: " .. tostring(ok2) .. " (" .. tostring(data2) /* 76561198398853124 */ .. ")")
end)
end)
self:Query("SHOW TABLES LIKE 'sh_reports_performance_history'", function(q, ok, data)
if (!ok) or (data and table.Count(data) > 0) then
return end
self:Query([[
CREATE TABLE `sh_reports_performance_history` (
`id` int(10) unsigned NOT NULL,
`reporter` varchar(64) NOT NULL,
`reported` varchar(64) NOT NULL,
`reason` varchar(256),
`comment` varchar(2048),
`waiting_time` int(10) unsigned DEFAULT '0',
`date` int(10) unsigned DEFAULT '0',
`admin` varchar(64) NOT NULL,
`rating` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
]], function(q2, ok2, data2)
self:DBPrint("Creating sh_reports_performance_history: " .. tostring(ok2) .. " (" .. tostring(data2) .. ")")
end)
end)
else
local function CreateTable(name, query)
if (!sql.TableExists(name)) then
sql.Query([[
CREATE TABLE `]] .. name .. [[` (]] .. query .. [[)
]])
self:DBPrint("Creating " .. name .. ": " .. tostring(sql.TableExists(name)))
end
end
CreateTable("sh_reports_performance", [[
`steamid` varchar(64) NOT NULL,
`claimed` int(10) DEFAULT '0',
`closed` int(10) DEFAULT '0',
`timespent` int(10) DEFAULT '0',
`report_id` int(10) DEFAULT '0',
UNIQUE(steamid, report_id) ON CONFLICT IGNORE
]])
CreateTable("sh_reports_performance_reports", [[
`id` int(10) NOT NULL PRIMARY KEY,
`start_time` int(10) DEFAULT '0',
`end_time` int(10) DEFAULT '0'
]])
CreateTable("sh_reports_performance_ratings", [[
`steamid` varchar(64) NOT NULL PRIMARY KEY,
`total` int(10) DEFAULT '0',
`num` int(10) DEFAULT '0'
]])
CreateTable("sh_reports_performance_history", [[
`id` int(10) NOT NULL PRIMARY KEY,
`reporter` varchar(64) NOT NULL,
`reported` varchar(64) NOT NULL,
`reason` varchar(256),
`comment` varchar(2048),
`waiting_time` int(10) DEFAULT '0',
`date` int(10) DEFAULT '0',
`admin` varchar(64) NOT NULL,
`rating` int(5) DEFAULT '0'
]])
self.InsertSQL = "INSERT OR IGNORE INTO"
self:PostDatabaseConnected()
end
end
function SH_REPORTS:PostDatabaseConnected()
self:BetterQuery("SELECT * FROM sh_reports_performance_reports WHERE {time} < end_time ORDER BY id DESC", {time = os.time()}, function(q, ok, data)
if (!ok) then
return end
if (data and #data > 0) then
local d = table.Copy(data[1])
d.id = tonumber(d.id)
d.start_time = tonumber(d.start_time)
d.end_time = tonumber(d.end_time)
self.CurrentPerfReport = d
self:DBPrint("Using performance report #" .. d.id .. ". It will last until " .. os.date(self.DateFormat, d.end_time) .. " 00:00.")
else
self:DBPrint("Creating new performance report as none were found.")
self:CreatePerformanceReport()
end
end)
if (self.StorageExpiryTime > 0) then
self:BetterQuery("DELETE FROM sh_reports_performance_history WHERE {time} > date", {time = os.time() - self.StorageExpiryTime})
end
end
function SH_REPORTS:CreatePerformanceReport()
local days = 1
if (self.PerformanceFrequency == "weekly") then
days = 7 - tonumber(os.date("%w")) + self.PerformanceWeekDay
elseif (self.PerformanceFrequency == "monthly") then
days = 31
end
local mthen = self:GetMidnight(days)
self:Query("SELECT id FROM sh_reports_performance_reports", function(q, ok, data)
if (!ok) then
return end
local d = {id = table.Count(data) + 1, start_time = os.time(), end_time = mthen}
self.CurrentPerfReport = d
self:BetterQuery([[
INSERT INTO sh_reports_performance_reports (id, start_time, end_time)
VALUES ({id}, {start_time}, {end_time})
]], d)
self:DBPrint("Created performance report #" .. d.id .. ". It will last until " .. os.date(self.DateFormat, mthen) .. " 00:00.")
end)
self.CachedPerfReports = nil
end
function SH_REPORTS:NewReport(ply, data)
if (self:IsAdmin(ply) and !self.StaffCanReport) then
self:Notify(ply, "cannot_report_as_admin", false)
return
end
if (data.reporter_id == data.reported_id) then
self:Notify(ply, "cannot_report_self", false)
return
end
local target = player.GetBySteamID64(data.reported_id)
if (IsValid(target) and self:IsAdmin(target) and !self.StaffCanBeReported) then
self:Notify(ply, "cannot_report_admin", false)
return
end
local sid = ply:SteamID64()
if (table.Count(self:GetAllReports(sid)) >= self.MaxReportsPerPlayer) then
self:Notify(ply, "report_limit_reached", false)
return
end
if (data.reported_id == "0" and !self.CanReportOther) then
return end
self.UniqueID = self.UniqueID + 1
data.id = self.UniqueID
self.ActiveReports[data.id] = table.Copy(data)
self:Notify(ply, "report_submitted", true)
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> reported [#" .. data.id .. "] " .. data.reported_name .. " <" .. util.SteamIDFrom64(data.reported_id /* 76561198398853124 */) .. "> for " .. self.ReportReasons[data.reason_id])
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportCreated", data)
end
function SH_REPORTS:PlayerSay(ply, str)
local text = str:Replace("!", "/"):lower():Trim()
if (self.AdminCommands[text]) then
self:ShowReports(ply)
return ""
end
if (self.ReportCommands[text]) then
if (!self:IsAdmin(ply) or self.StaffCanReport) then
easynet.Send(ply, "SH_REPORTS.QuickReport", {comment = "", lastkiller = ply.SH_LastKiller, lastarrester = ply.SH_LastArrester})
else
self:Notify(ply, "cannot_report_as_admin", false)
end
return ""
end
if (self.EnableQuickReport and !self:IsAdmin(ply) and text:StartWith("@")) then
easynet.Send(ply, "SH_REPORTS.QuickReport", {comment = str:sub(2), lastkiller = ply.SH_LastKiller, lastarrester = ply.SH_LastArrester})
return ""
end
if (text == "/reportstats") then
if (self:IsAdmin(ply)) then
self:BetterQuery("SELECT * FROM sh_reports_performance WHERE steamid = {steamid}", {steamid = ply:SteamID64()}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
local claimed = 0
local closed = 0
for _, d in pairs (data) do
claimed = claimed + tonumber(d.claimed)
closed = closed + tonumber(d.closed)
end
ply:ChatPrint("Reports claimed: " .. string.Comma(claimed) .. " | Reports closed: " .. string.Comma(closed))
end)
end
return ""
end
end
function SH_REPORTS:ShowReports(ply)
local tosend = {}
if (self:IsAdmin(ply)) then -- If admin, send all reports, if not only send own
tosend = self:GetAllReports()
else
tosend = self:GetAllReports(ply:SteamID64())
end
easynet.Send(ply, "SH_REPORTS.SendList", {
server_time = os.time(),
struct_reports = tosend,
})
end
local function SendPerfReports(ply, preps)
easynet.Send(ply, "SH_REPORTS.SendPerfReports", {
struct_perf_reports = preps
})
end
function SH_REPORTS:ShowPerformanceReports(ply)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
if (self.CachedPerfReports) then
SendPerfReports(ply, self.CachedPerfReports)
else
self:BetterQuery("SELECT * FROM sh_reports_performance_reports", {time = os.time()}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
local d = {}
for k, v in pairs (data) do
d[tonumber(v.id)] = v
end
self.CachedPerfReports = d
if (IsValid(ply)) then
SendPerfReports(ply, d)
end
end)
end
end
function SH_REPORTS:RequestPerfReportStaff(ply, id)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
self:BetterQuery("SELECT steamid, claimed, closed, timespent FROM sh_reports_performance WHERE report_id = {id}" /* 76561198398853149 */, {id = id}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
for k, v in pairs (data) do
v.claimed = tonumber(v.claimed) or 0
v.closed = tonumber(v.closed) or 0
v.timespent = tonumber(v.timespent) or 0
end
easynet.Send(ply, "SH_REPORTS.SendPerfReportStaff", {
id = id,
struct_perf_reports_staff = data
})
end)
end
function SH_REPORTS:RequestStaffRatings(ply)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
self:BetterQuery("SELECT steamid, num, total FROM sh_reports_performance_ratings" /* 76561198398853124 */, {}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
easynet.Send(ply, "SH_REPORTS.SendRatings", {
struct_rating = data
})
end)
end
function SH_REPORTS:RequestReportHistory(ply)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
self:BetterQuery("SELECT * FROM sh_reports_performance_history", {}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
-- Factorize the SteamID's to save on bytes
local t_steamids = {}
local t = {}
for _, dat in pairs (data) do
t[tonumber(dat.id)] = dat
t_steamids[dat.reporter] = true
t_steamids[dat.reported] = true
t_steamids[dat.admin] = true
end
local steamids = {}
for steamid in pairs (t_steamids) do
t_steamids[steamid] = table.insert(steamids, {steamid = steamid})
end
local t_list = {}
for id, dat in pairs (t) do
table.insert(t_list, {
report_id = tonumber(dat.id),
reporter_nid = t_steamids[dat.reporter],
reported_nid = t_steamids[dat.reported],
reason = dat.reason,
comment = dat.comment,
rating = dat.rating,
date = dat.date,
waiting_time = dat.waiting_time,
admin_nid = t_steamids[dat.admin],
})
end
easynet.Send(ply, "SH_REPORTS.SendHistoryList", {
struct_history_steamids = steamids,
struct_history_list = t_list,
})
end)
end
function SH_REPORTS:ClaimReport(admin, report)
local sid = admin:SteamID64()
for _, rep in pairs (self:GetAllReports()) do
if (rep.admin_id == sid) then
self:Notify(admin, "claimed_report_still_active", false)
return false
end
end
if (report.admin_id ~= "") then
return false
end
report.claim_time = os.time()
report.admin_id = sid
self:Notify(player.GetBySteamID64(report.reporter_id), "admin_claimed_your_report", true)
easynet.Send(admin, "SH_REPORTS.MinimizeReport", {report_id = report.id})
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportClaimed", {report_id = report.id, admin_id = report.admin_id})
if (self.CurrentPerfReport) and (!report.is_admin or self.AdminReportsCount) then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance (steamid, report_id)
VALUES ({steamid}, {report_id});
UPDATE sh_reports_performance SET claimed = claimed + 1
WHERE steamid = {steamid} AND report_id = {report_id}
]], {steamid = admin:SteamID64(), report_id = self.CurrentPerfReport.id})
end
return true
end
function SH_REPORTS:ClaimAndTeleport(admin, id, bring, bring_reported)
if (!self:IsAdmin(admin)) then
self:Notify(admin, "not_allowed_to_run_cmd", false)
return
end
local report = self:FindReport(id)
if (!report) then
self:Notify(admin, "report_non_existent", false)
return
end
if (self.ClaimNoTeleport) then
return end
local target = player.GetBySteamID64(report.reporter_id)
if (!IsValid(target)) then
return end
if (!self:ClaimReport(admin, report)) then
return end
admin.SH_PosBeforeReport = admin:GetPos()
target.SH_PosBeforeReport = target:GetPos()
if (self.UseULXCommands) then
-- Bad idea? ULX sucks anyways
if (bring) then
ulx.bring(admin, {target})
else
ulx.goto(admin, target)
end
if (bring_reported) then
local reported = player.GetBySteamID64(report.reported_id)
if (IsValid(reported)) then
reported.SH_PosBeforeReport = reported:GetPos()
if (bring) then
ulx.bring(admin, {reported})
else
ulx.send(admin, reported, target)
end
end
end
else
local a, b = admin, target
if (bring) then
a, b = target, admin
end
self:TeleportPlayer(a, b:GetPos())
if (bring_reported) then
local reported = player.GetBySteamID64(report.reported_id)
if (IsValid(reported)) then
reported.SH_PosBeforeReport = reported:GetPos()
self:TeleportPlayer(reported, b:GetPos())
end
end
end
self:Log(admin:Nick() .. " <" .. admin:SteamID() .. "> claimed " .. target:Nick() .. "'s <" .. target:SteamID() .. "> report [#" .. id .. "]")
end
function SH_REPORTS:ClaimAndCSit(admin, id)
if (!csitsystem) then
return end
if (!self:IsAdmin(admin)) then
self:Notify(admin, "not_allowed_to_run_cmd", false)
return
end
local report = self:FindReport(id)
if (!report) then
self:Notify(admin, "report_non_existent", false)
return
end
local target = player.GetBySteamID64(report.reporter_id)
if (!IsValid(target)) then
return end
if (!self:ClaimReport(admin, report)) then
return end
admin.SH_PosBeforeReport = admin:GetPos()
target.SH_PosBeforeReport = target:GetPos()
report.sit_id = csitsystem.HandOver(admin, target, player.GetBySteamID64(report.reported_id))
self:Log(admin:Nick() .. " <" .. admin:SteamID() .. "> claimed " .. target:Nick() .. "'s <" .. target:SteamID() .. "> report [#" .. id .. "] and started a sit")
-- self:CloseReport(admin, id)
end
function SH_REPORTS:CloseReport(ply, id)
local report = self:FindReport(id)
if (!report) then
self:Notify(ply, "report_non_existent", false)
return
end
local sid = ply:SteamID64()
if (self:IsAdmin(ply) and ((report.admin_id == "" and self.CanDeleteWhenUnclaimed) or report.admin_id == sid)) or (report.reporter_id == sid) then
self.ActiveReports[id] = nil
self:Notify(ply, "report_closed", true)
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportClosed", {report_id = id})
local target = player.GetBySteamID64(report.reporter_id)
local admin = player.GetBySteamID64(report.admin_id)
if (IsValid(target)) then
if (report.reporter_id ~= sid) then
self:Notify(target, "your_report_was_closed", true)
elseif (report.admin_id ~= "") then
if (IsValid(admin) and admin ~= ply) then
self:Notify(admin, "reporter_closed_report", true)
end
end
easynet.Send(target, "SH_REPORTS.ReportClosed", {report_id = id})
end
if (!report.is_admin or self.AdminReportsCount) then
if (report.admin_id ~= "") then
local claim_time = os.time() - report.claim_time
if (self.CurrentPerfReport) then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance (steamid, report_id, timespent)
VALUES ({steamid}, {report_id}, {timespent});
UPDATE sh_reports_performance SET closed = closed + 1, timespent = timespent + {timespent}
WHERE steamid = {steamid} AND report_id = {report_id}
]], {steamid = report.admin_id, report_id = self.CurrentPerfReport.id, timespent = claim_time})
end
if (sid == report.reporter_id) then
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed their own report [#" .. id .. "]")
else
if (IsValid(target) and self.AskRating) then
if (!target.SH_ReportsCompleted) then
target.SH_ReportsCompleted = {}
end
target.SH_ReportsCompleted[id] = ply:SteamID64()
easynet.Send(target, "SH_REPORTS.PromptRating", {report_id = id, admin_name = ply:Nick()})
end
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed the report [#" .. id .. "] from " .. report.reporter_name .. "<" .. util.SteamIDFrom64(report.reporter_id) .. ">")
end
elseif (self:IsAdmin(ply)) then
if (self.CurrentPerfReport) then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance (steamid, report_id)
VALUES ({steamid}, {report_id});
UPDATE sh_reports_performance SET closed = closed + 1
WHERE steamid = {steamid} AND report_id = {report_id}
]], {steamid = sid, report_id = self.CurrentPerfReport.id})
end
if (sid == report.reporter_id) then
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed their own UNCLAIMED report [#" .. id .. "]")
else
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed the UNCLAIMED report [#" .. id .. "] from " .. report.reporter_name .. "<" .. util.SteamIDFrom64(report.reporter_id) .. ">")
end
end
end
if (report.admin_id ~= "") then
if (report.sit_id) then
csitsystem.EndSit(report.sit_id)
end
if (self.TeleportPlayersBack) then
if (IsValid(target)) then
self:ReturnPlayer(target)
end
local admin = player.GetBySteamID64(report.admin_id)
if (IsValid(admin)) then
self:ReturnPlayer(admin)
end
local reported = player.GetBySteamID64(report.reported_id)
if (IsValid(reported)) then
self:ReturnPlayer(reported)
end
end
if (self.StoreCompletedReports ~= "none") then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance_history (id, reporter, reported, reason, comment, waiting_time, date, admin)
VALUES ({id}, {reporter}, {reported}, {reason}, {comment}, {waiting_time}, {date}, {admin});
]], {id = id, reporter = report.reporter_id, reported = report.reported_id, reason = self.ReportReasons[report.reason_id], comment = report.comment, waiting_time = os.time() - report.time, date = os.time(), admin = report.admin_id})
end
end
else
self:Notify(ply, "not_allowed_to_run_cmd", false)
end
end
function SH_REPORTS:RateAdmin(ply, report_id, rating)
if (!ply.SH_ReportsCompleted or !ply.SH_ReportsCompleted[report_id]) then
self:Notify(ply, "report_non_existent", false)
return
end
local admin_id = ply.SH_ReportsCompleted[report_id]
rating = math.Clamp(rating, 1, 5)
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance_ratings (steamid, total, num)
VALUES ({steamid}, 0, 0);
UPDATE sh_reports_performance_ratings SET total = total + {rating}, num = num + 1
WHERE steamid = {steamid}
]], {steamid = admin_id, rating = rating})
if (self.StoreCompletedReports ~= "none") then
self:BetterQuery([[
UPDATE sh_reports_performance_history SET rating = {rating}
WHERE id = {id}
]], {id = report_id, rating = rating})
end
if (self.NotifyRating) then
local admin = player.GetBySteamID64(admin_id)
if (IsValid(admin)) then
local rstr = ""
for i = 1, 5 do
rstr = rstr .. (rating >= i and "" or "")
end
self:Notify(admin, "rate_notification\t" .. ply:Nick() .. "\t" .. rstr, rating >= 3)
end
end
ply.SH_ReportsCompleted[report_id] = nil
self:Notify(ply, "rate_thanks", true)
end
function SH_REPORTS:PlayerReady(ply)
if (self.NotifyAdminsOnConnect and self:IsAdmin(ply)) then
local num = 0
local pending = {}
for id, report in pairs (self:GetAllReports()) do
if (report.admin_id == "") then
num = num + 1
table.insert(pending, report)
end
end
if (num > 0) then
easynet.Send(ply, "SH_REPORTS.ReportsPending", {num = num, struct_reports = pending})
end
end
end
function SH_REPORTS:PlayerDisconnected(ply)
local sid = ply:SteamID64()
for id, report in pairs (self:GetAllReports()) do
if (report.reporter_id == sid) then
self.ActiveReports[id] = nil
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportClosed", {report_id = id})
local admin = player.GetBySteamID64(report.admin_id)
if (IsValid(admin)) then
self:Notify(admin, "reporter_closed_report", false)
end
elseif (self:IsAdmin(ply) and report.admin_id == sid) then
report.admin_id = ""
easynet.Send(self:GetStaff(), "SH_REPORTS.AdminLeft", {report_id = id})
local reporter = player.GetBySteamID64(report.reporter_id)
if (IsValid(reporter)) then
easynet.Send(reporter, "SH_REPORTS.AdminLeft", {report_id = id})
self:Notify(reporter, "admin_has_disconnected", false)
end
end
end
end
function SH_REPORTS:ReturnPlayer(ply)
if (!ply.SH_PosBeforeReport) then
return end
ply:SetPos(ply.SH_PosBeforeReport)
ply.SH_PosBeforeReport = nil
end
function SH_REPORTS:MidnightCheck()
local perf = self.CurrentPerfReport
if (!perf) then
return end
if (os.time() >= perf.end_time) then
self:DBPrint("Current performance report #" .. perf.id .. " expired, creating new one..")
self:CreatePerformanceReport()
end
end
function SH_REPORTS:Notify(ply, msg, good)
easynet.Send(ply, "SH_REPORTS.Notify", {msg = msg, positive = good})
end
function SH_REPORTS:GetStaff(ply)
local t = {}
for _, v in ipairs (player.GetAll()) do
if (self:IsAdmin(v)) then
table.insert(t, v)
end
end
return t
end
local function CheckObstruction(ply, pos)
local t = {
start = pos,
endpos = pos + Vector(0, 0, 72),
mins = Vector(-16, -16, 0),
maxs = Vector(16, 16, 4),
filter = ply
}
return bit.band(util.PointContents(pos), CONTENTS_SOLID) > 0 or util.TraceHull(t).Hit
end
local coords = {
Vector(48, 0, 0),
Vector(-48, 0, 0),
Vector(0, 48, 0),
Vector(0, -48, 0),
Vector(48, 48, 0),
Vector(-48, 48, 0),
Vector(48, -48, 0),
Vector(-48, -48, 0),
}
function SH_REPORTS:TeleportPlayer(ply, pos, exact)
if (!exact) then
if (CheckObstruction(ply, pos)) then
for _, c in ipairs (coords) do
if (!util.TraceLine({start = pos, endpos = pos + c, filter = ents.GetAll()}).Hit and !CheckObstruction(ply, pos + c /* 76561198398853124 */)) then
pos = pos + c
break
end
end
end
end
ply.SH_PositionBeforeTeleport = ply:GetPos()
ply:SetPos(pos)
end
function SH_REPORTS:FindReport(id)
return self.ActiveReports[id]
end
function SH_REPORTS:GetAllReports(author)
local t = {}
for id, report in pairs (self.ActiveReports) do
if (author and report.reporter_id ~= author) then
continue end
t[id] = report
end
return t
end
function SH_REPORTS:Log(s)
if (!self.UseServerLog) then
return end
ServerLog(s .. "\n")
end
local function GetPerformanceReport(date, preps)
for id, ps in pairs (preps) do
if (date >= ps[1] and date <= ps[2]) then
return id
end
end
end
function SH_REPORTS:RebuildPerformance()
local preps = {}
self:BetterQuery("SELECT * FROM sh_reports_performance_reports", {}, function(q, ok, data)
for k, v in pairs (data) do
preps[tonumber(v.id)] = {tonumber(v.start_time), tonumber(v.end_time)}
end
self:BetterQuery("SELECT * FROM sh_reports_performance_history", {}, function(q, ok, data)
local staffreps = {}
for _, rep in SortedPairsByMemberValue (data, "date") do
local admin = tostring(rep.admin)
staffreps[admin] = staffreps[admin] or {}
table.insert(staffreps[admin], rep)
end
local staffpreps = {}
for sid, reps in pairs (staffreps) do
staffpreps[sid] = {}
for _, rep in pairs (reps) do
local prepid = GetPerformanceReport(tonumber(rep.date), preps)
staffpreps[sid][prepid] = staffpreps[sid][prepid] or {}
table.insert(staffpreps[sid][prepid], rep)
end
end
for sid, preps in pairs (staffpreps) do
for prepid, reps in pairs (preps) do
local claimed, closed, timespent = 0, 0, 0
for _, rep in pairs (reps) do
claimed = claimed + 1
closed = closed + 1
timespent = timespent + tonumber(rep.waiting_time)
end
self:BetterQuery("SELECT * FROM sh_reports_performance WHERE steamid = {steamid} AND report_id = {prepid}", {steamid = sid, prepid = prepid}, function(q, ok, data)
if (data and data[1]) then
self:BetterQuery("UPDATE sh_reports_performance SET claimed = {claimed}, closed = {closed}, timespent = {timespent} WHERE steamid = {steamid} AND report_id = {prepid}", {claimed = claimed, closed = closed, timespent = timespent, steamid = sid, prepid = prepid})
else
self:BetterQuery("INSERT INTO sh_reports_performance (steamid, claimed, closed, timespent, report_id) VALUES ({steamid}, {claimed}, {closed}, {timespent}, {prepid})", {claimed = claimed, closed = closed, timespent = timespent, steamid = sid, prepid = prepid})
end
end)
end
end
end)
end)
end
hook.Add("PlayerDisconnected", "SH_REPORTS.PlayerDisconnected", function(ply)
SH_REPORTS:PlayerDisconnected(ply)
end)
hook.Add("PlayerSay", "SH_REPORTS.PlayerSay", function(ply, str)
local r = SH_REPORTS:PlayerSay(ply, str)
if (r) then
return r
end
end)
hook.Add("DoPlayerDeath", "SH_REPORTS.DoPlayerDeath", function(ply, atk, dmginfo)
if (IsValid(atk) and atk:IsPlayer() and atk ~= ply) then
ply.SH_LastKiller = atk
end
end)
hook.Add("playerArrested", "SH_REPORTS.playerArrested", function(ply, time, arrester)
if (IsValid(arrester) and arrester:IsPlayer() and arrester ~= ply) then
ply.SH_LastArrester = arrester
end
end)
hook.Add("PlayerButtonDown", "SH_REPORTS.PlayerButtonDown", function(ply, btn)
if (!IsFirstTimePredicted()) then
return end
if (btn == SH_REPORTS.ReportKey) then
if (!SH_REPORTS:IsAdmin(ply) or SH_REPORTS.StaffCanReport) then
easynet.Send(ply, "SH_REPORTS.QuickReport", {comment = "", lastkiller = ply.SH_LastKiller, lastarrester = ply.SH_LastArrester})
else
SH_REPORTS:Notify(ply, "cannot_report_as_admin", false)
end
elseif (btn == SH_REPORTS.ReportsKey) then
SH_REPORTS:ShowReports(ply)
end
end)
timer.Create("SH_REPORTS.MidnightCheck", 1, 0, function()
SH_REPORTS:MidnightCheck()
end)
easynet.Callback("SH_REPORTS.NewReport", function(data, ply)
local report = data
data.reporter_name = ply:Nick()
data.reporter_id = ply:SteamID64()
data.time = os.time()
data.admin_id = ""
data.comment = data.comment:sub(1, SH_REPORTS.MaxCommentLength)
data.is_admin = SH_REPORTS:IsAdmin(ply)
SH_REPORTS:NewReport(ply, data)
end)
easynet.Callback("SH_REPORTS.Claim", function(data, ply)
if (!SH_REPORTS:IsAdmin(ply)) then
SH_REPORTS:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
local report = SH_REPORTS:FindReport(data.id)
if (!report) then
SH_REPORTS:Notify(ply, "report_non_existent", false)
return
end
SH_REPORTS:ClaimReport(ply, report)
end)
easynet.Callback("SH_REPORTS.ClaimAndTeleport", function(data, ply)
SH_REPORTS:ClaimAndTeleport(ply, data.id, data.bring, data.bring_reported)
end)
easynet.Callback("SH_REPORTS.ClaimAndCSit", function(data, ply)
SH_REPORTS:ClaimAndCSit(ply, data.id)
end)
easynet.Callback("SH_REPORTS.CloseReport", function(data, ply)
SH_REPORTS:CloseReport(ply, data.id)
end)
easynet.Callback("SH_REPORTS.RequestPerfReports", function(data, ply)
SH_REPORTS:ShowPerformanceReports(ply)
end)
easynet.Callback("SH_REPORTS.RequestPerfReportStaff", function(data, ply)
SH_REPORTS:RequestPerfReportStaff(ply, data.id)
end)
easynet.Callback("SH_REPORTS.PlayerReady", function(data, ply)
SH_REPORTS:PlayerReady(ply)
end)
easynet.Callback("SH_REPORTS.RateAdmin", function(data, ply)
SH_REPORTS:RateAdmin(ply, data.report_id, data.rating)
end)
easynet.Callback("SH_REPORTS.RequestStaffRatings", function(data, ply)
SH_REPORTS:RequestStaffRatings(ply)
end)
easynet.Callback("SH_REPORTS.RequestReportHistory", function(data, ply)
SH_REPORTS:RequestReportHistory(ply)
end)
-- vk.com/urbanichka