This commit is contained in:
lifestorm
2024-08-05 18:40:29 +03:00
parent 9f505a0646
commit c6d9b6f580
8044 changed files with 1853472 additions and 21 deletions

View File

@@ -0,0 +1,27 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
netstream.Hook("SetLinkedUpdateCL", function(update)
ix.data.Set("CameraConsoleLinkedUpdate", update)
end)
netstream.Hook("SetConsoleUpdates", function(updates)
if (IsValid(ix.gui.consolePanel)) then
ix.gui.consolePanel.updates = updates
end
end)
netstream.Hook("CloseConsole", function(updates)
if (IsValid(ix.gui.consolePanel)) then
ix.gui.consolePanel:TurnOff()
ix.gui.consolePanel:Remove()
end
end)

View File

@@ -0,0 +1,421 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Shared localization panel/hooks
local cameraActive = false
local combineOverlay = false
local cameraNumber = 1
local ButtonColor = Color(248, 248, 255)
local BackgroundColor = Color(0, 0, 0, 250)
local cameraLock = false
local cameras = {}
local cameraCount = #cameras
local PLUGIN = PLUGIN
surface.CreateFont( "CameraFont", {
font = "DebugFixed",
size = SScaleMin(50 / 3),
weight = 50,
blursize = 0,
scanlines = 50,
} )
-- Console Panel
local PANEL = {}
function PANEL:Init()
self:SetSize(SScaleMin(400 / 3), SScaleMin(300 / 3))
self:Center()
self:MakePopup()
Schema:AllowMessage(self)
self.Paint = function(_, w, h)
draw.RoundedBox( 8, 0, 0, w, h, BackgroundColor )
end
self.topPanel = self:Add("Panel")
self.topPanel:Dock(TOP)
self.topPanel:SetTall(SScaleMin(20 / 3))
self.topPanel:DockMargin(SScaleMin(10 / 3), SScaleMin(10 / 3), SScaleMin(10 / 3), SScaleMin(10 / 3))
local line = self:Add("DShape")
line:SetType("Rect")
line:Dock(TOP)
line:SetTall(1)
line:SetColor(color_white)
line:DockMargin(SScaleMin(10 / 3), 0, SScaleMin(10 / 3), SScaleMin(10 / 3))
self:GetAllCameras()
self:CreateCloseButton()
self:CreateTitle()
self:CreateButtons()
end
function PANEL:CreateCloseButton()
local close = self.topPanel:Add("DButton")
close:Dock(RIGHT)
close:SetWide(SScaleMin(20 / 3))
close:SetText("")
close.Paint = function(_, w, h)
surface.SetDrawColor(color_white)
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/tabmenu/navicons/exit-grey.png"))
surface.DrawTexturedRect(0, 0, w, h)
end
close.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
self:TurnOff()
self:Remove()
end
end
function PANEL:CreateTitle()
local combineText = self.topPanel:Add("DLabel")
combineText:Dock(LEFT)
combineText:SetFont("DebugFixedRadio")
combineText:SetText(">:: ")
combineText:SetContentAlignment(4)
combineText:SizeToContents()
self.title = self.topPanel:Add("DLabel")
self.title:Dock(LEFT)
self.title:SetFont("DebugFixedRadio")
self.title:SetText("COMMAND CONSOLE")
self.title:SetContentAlignment(4)
self.title:SizeToContents()
end
function PANEL:CreateButtons()
netstream.Start("GetLinkedUpdate")
self.buttonlist = {}
self.buttongrid = self:Add("DGrid")
self.buttongrid:Dock(FILL)
self.buttongrid:DockMargin(SScaleMin(10 / 3), 0, SScaleMin(10 / 3), 0)
self.buttongrid:SetCols(1)
self.buttongrid:SetColWide(self:GetWide() - SScaleMin(20 / 3))
self.buttongrid:SetRowHeight( SScaleMin(50 / 3) )
local function CreateButton(parent, text, bAddToButtonList)
parent:SetText(string.utf8upper(text))
parent:SetSize(self:GetWide() - SScaleMin(20 / 3), SScaleMin(40 / 3))
parent:SetTextColor(color_black)
parent:SetFont("DebugFixedRadio")
parent.Paint = function(_, w, h)
draw.RoundedBox( 8, 0, 0, w, h, ButtonColor )
end
if bAddToButtonList then
self.buttongrid:AddItem(parent)
self:AddToButtonList(parent)
end
end
self.thirdperson = false
local cameraButton = vgui.Create("DButton")
CreateButton(cameraButton, "cameras", true)
cameraButton.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
if cameraCount >= 1 then
cameraActive = true
combineOverlay = true
if ix.option.Get("thirdpersonEnabled") then
self.thirdperson = true
ix.option.Set("thirdpersonEnabled", false)
end
self:SetVisible(false)
self:CreateCameraUI()
self:AddPVS()
end
end
local character = LocalPlayer():GetCharacter()
local class = character:GetClass()
if (class == CLASS_CP_CMD or class == CLASS_CP_CPT or class == CLASS_CP_RL or class == CLASS_OVERSEER or class == CLASS_OW_SCANNER) then
netstream.Start("GetConsoleUpdates", self.entity)
local addLink = vgui.Create("DButton")
CreateButton(addLink, "link update", true)
addLink.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
local chooseUpdatePanel = vgui.Create("DFrame")
chooseUpdatePanel:SetSize(SScaleMin(300 / 3), SScaleMin(500 / 3))
chooseUpdatePanel:Center()
chooseUpdatePanel:SetTitle("Choose Update")
DFrameFixer(chooseUpdatePanel)
local scrollPanel = chooseUpdatePanel:Add("DScrollPanel")
scrollPanel:Dock(FILL)
for _, v in pairs(self.updates) do
local button = scrollPanel:Add("DButton")
button:Dock(TOP)
button:SetTall(SScaleMin(50 / 3))
button:SetFont("DebugFixedRadio")
button:SetText(string.utf8sub( v.update_text, 1, 20 ).."... - "..v.update_poster)
button.Paint = function(_, w, h)
surface.SetDrawColor(Color(0, 0, 0, 100))
surface.DrawRect(0, 0, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawOutlinedRect(0, 0, w, h)
end
button.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
netstream.Start("SetLinkedUpdate", self.entity, v.update_text)
chooseUpdatePanel:Remove()
end
end
end
end
local updates = vgui.Create("DButton")
CreateButton(updates, "updates", true)
updates.DoClick = function()
if !ix.data.Get("CameraConsoleLinkedUpdate") then
LocalPlayer():NotifyLocalized("No linked update")
return
end
local updatePanel = vgui.Create("DFrame")
updatePanel:SetSize(SScaleMin(600 / 3), SScaleMin(700 / 3))
updatePanel:Center()
updatePanel:MakePopup()
Schema:AllowMessage(updatePanel)
updatePanel:SetTitle("Update")
DFrameFixer(updatePanel)
updatePanel.lblTitle:SetFont("MenuFontNoClamp")
updatePanel.lblTitle:SizeToContents()
local htmlPanel = updatePanel:Add("HTML")
htmlPanel:Dock(FILL)
local string = "<p style='font-family: Open Sans; font-size: "..tostring(SScaleMin(13 / 3)).."; color: rgb(41,243,229);'>"..tostring(ix.data.Get("CameraConsoleLinkedUpdate")).."</p>"
if istable(ix.data.Get("CameraConsoleLinkedUpdate")) then
if table.IsEmpty(ix.data.Get("CameraConsoleLinkedUpdate")) then
string = "<p style='font-family: Open Sans; font-size: "..tostring(SScaleMin(13 / 3)).."; color: rgb(41,243,229);'>No updates.</p>"
end
end
local html = string.Replace(string, "\n", "<br>")
htmlPanel:SetHTML(html)
htmlPanel.Paint = function(_, w, h)
surface.SetDrawColor(40, 88, 115, 75)
surface.DrawRect(0, 0, w, h)
end
end
end
netstream.Hook("ReplyCrimeReports", function(crimes)
if ix.gui.datapadCrimes and IsValid(ix.gui.datapadCrimes) then
ix.gui.datapadCrimes:CreateCrimes(crimes)
end
end)
function PANEL:CreateCameraUI()
local cameraPanel = vgui.Create( "Panel" )
cameraPanel:SetPos( ScrW() / 2 + SScaleMin(350 / 3), ScrH() / 2 + SScaleMin(280 / 3))
cameraPanel:SetSize( SScaleMin(200 / 3), SScaleMin(100 / 3) )
cameraPanel:MakePopup()
Schema:AllowMessage(cameraPanel)
local CameraUI3 = vgui.Create( "Panel", cameraPanel )
CameraUI3:SetPos( ScrW() / 2 + SScaleMin(350 / 3), ScrH() / 2 + SScaleMin(110 / 3))
CameraUI3:SetSize( SScaleMin(200 / 3), SScaleMin(150 / 3) )
local back = cameraPanel:Add("DButton")
back:Dock(TOP)
back:SetTextColor(color_black)
back:SetTall(SScaleMin(20 / 3))
back:SetFont("DebugFixedRadio")
back:SetText("Back")
back.Paint = function(_, w, h)
surface.SetDrawColor(color_white)
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/tabmenu/navicons/exit-grey.png"))
surface.DrawTexturedRect(0, 0, w, h)
end
back.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
self:CameraOff()
cameraPanel:Remove()
self:SetVisible(true)
if self.thirdperson then
ix.option.Set("thirdpersonEnabled", true)
end
end
local nextCamera = vgui.Create( "DButton", cameraPanel )
nextCamera:SetText( "Next" )
nextCamera:SetFont("DebugFixedRadio")
nextCamera:SetTextColor( Color(0, 0, 0, 255) )
nextCamera:SetPos( SScaleMin(105 / 3), SScaleMin(30 / 3) )
nextCamera:SetSize( SScaleMin(75 / 3), SScaleMin(25 / 3) )
nextCamera.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
if cameraNumber < cameraCount then
cameraNumber = cameraNumber + 1
self:AddPVS()
end
end
local previousCamera = vgui.Create( "DButton", cameraPanel )
previousCamera:SetText( "Previous" )
previousCamera:SetFont("DebugFixedRadio")
previousCamera:SetTextColor( Color(0, 0, 0, 255) )
previousCamera:SetPos( SScaleMin(20 / 3), SScaleMin(30 / 3) )
previousCamera:SetSize( SScaleMin(75 / 3), SScaleMin(25 / 3) )
previousCamera.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
if cameraNumber > 1 then
cameraNumber = cameraNumber - 1
self:AddPVS()
end
end
local LockCamera = vgui.Create( "DButton", cameraPanel )
LockCamera:SetText( "Lock" )
LockCamera:SetFont("DebugFixedRadio")
LockCamera:SetTextColor( Color(0, 0, 0, 255) )
LockCamera:SetPos( SScaleMin(20 / 3), SScaleMin(60 / 3) )
LockCamera:SetSize( SScaleMin(75 / 3), SScaleMin(25 / 3) )
LockCamera.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
cameraLock = !cameraLock
end
local List = vgui.Create( "DPanelList", CameraUI3 )
List:SetSize(SScaleMin(190 / 3), SScaleMin(120 / 3))
List:SetSpacing( SScaleMin(5 / 3) )
List:SetPos(SScaleMin(5 / 3), SScaleMin(15 / 3))
List:EnableHorizontal( false )
List:EnableVerticalScrollbar( true )
for k, _ in pairs(cameras) do
local Spawnd = vgui.Create("DButton", List)
Spawnd:SetText("Camera "..k)
Spawnd:SetFont("DebugFixedRadio")
Spawnd:SetTextColor( Color(0, 0, 0, 255) )
Spawnd:SetSize( SScaleMin(75 / 3), SScaleMin(25 / 3) )
Spawnd.DoClick = function()
surface.PlaySound("helix/ui/press.wav")
cameraNumber = k
self:AddPVS()
end
Spawnd.Paint = function()
draw.RoundedBox( 8, 0, 0, Spawnd:GetWide(), Spawnd:GetTall(), ButtonColor )
end
List:AddItem( Spawnd )
end
local Elements = { cameraPanel; CameraUI3; back; nextCamera; previousCamera; LockCamera}
for k,v in pairs(Elements) do
if k > 2 then
v.Paint = function()
draw.RoundedBox( 8, 0, 0, v:GetWide(), v:GetTall(), ButtonColor )
end
else
v.Paint = function()
draw.RoundedBox( 8, 0, 0, v:GetWide(), v:GetTall(), BackgroundColor )
end
end
end
end
function PANEL:AddToButtonList(button)
if button then
if self.buttonlist then
if istable(self.buttonlist) then
table.insert(self.buttonlist, button)
end
end
end
end
function PANEL:CameraOff()
cameraActive = false
combineOverlay = false
cameraNumber = 1
cameraLock = false
end
function PANEL:TurnOff()
netstream.Start("CloseConsole", self.entity)
end
function PANEL:AddPVS()
netstream.Start("SetConsoleCameraPos", self.entity, cameras[cameraNumber])
end
function PANEL:GetAllCameras()
if !table.IsEmpty(cameras) then
table.Empty(cameras)
end
for _, v in pairs(ents.GetAll()) do
if (v:GetClass() == "npc_combine_camera" or v:GetClass() == "npc_turret_ceiling") then
table.insert(cameras, v)
end
end
cameraCount = #cameras
end
vgui.Register("ConsolePanel", PANEL, "Panel")
-- Hooks
local function DrawCombineOverlay()
if combineOverlay then
DrawMaterialOverlay( "effects/combine_binocoverlay.vmt", 0.1 )
surface.SetTextColor( 255, 0, 0, 255 )
surface.SetTextPos( SScaleMin(100 / 3), SScaleMin(75 / 3) )
surface.SetFont("CameraFont")
surface.DrawText( "Camera ".. cameraNumber )
end
end
hook.Add( "RenderScreenspaceEffects", "ConsoleCameraOverlay", DrawCombineOverlay )
local function CalculateConsoleCameraView( client, pos, angles, fov )
if cameraActive then
if cameraCount >= 1 then
if cameras[cameraNumber]:IsValid() then
local BoneIndex = cameras[cameraNumber]:LookupAttachment("eyes")
local Bone = cameras[cameraNumber]:GetAttachment( BoneIndex )
local view = {}
if cameraLock == false then
view.origin = Bone.Pos + cameras[cameraNumber]:GetForward() * 6
view.angles = Bone.Ang
view.fov = fov
view.vm_origin = LocalPlayer():GetForward() * -100
else
view.origin = cameras[cameraNumber]:GetPos() + cameras[cameraNumber]:GetUp() * -50 + cameras[cameraNumber]:GetForward() * 30
view.angles = cameras[cameraNumber]:GetAngles() + Angle(10,0,0)
view.fov = fov
view.vm_origin = LocalPlayer():GetForward() * -100
end
return view
end
end
end
end
hook.Add( "CalcView", "CalculateConsoleCameraView", CalculateConsoleCameraView )

View File

@@ -0,0 +1,12 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ix.util.IncludeDir("ixhl2rp/plugins/combineutilities/consoles/derma", true)

View File

@@ -0,0 +1,70 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
netstream.Hook("SetLinkedUpdate", function(client, console, update)
if (IsValid(console) and console:GetClass() == "ix_console" and console.user == client) then
local character = client:GetCharacter()
if (character:GetClass() != CLASS_CP_CMD and character:GetClass() != CLASS_CP_CPT and character:GetClass() != CLASS_CP_RL and character:GetClass() != CLASS_OVERSEER) then
return
end
ix.data.Set("CameraConsoleLinkedUpdate", update)
netstream.Start(client, "SetLinkedUpdateCL", update)
end
end)
netstream.Hook("GetLinkedUpdate", function(client)
if !client:GetActiveCombineSuit() then
return false
end
local update = ix.data.Get("CameraConsoleLinkedUpdate", {})
netstream.Start(client, "SetLinkedUpdateCL", update)
end)
-- Netstream Hooks
netstream.Hook("CloseConsole", function(client, console)
if (IsValid(console) and console:GetClass() == "ix_console" and console.user == client) then
console:CloseConsole()
end
end)
netstream.Hook("SetConsoleCameraPos", function(client, console, entity)
if !client:GetActiveCombineSuit() then
return false
end
if (IsValid(console) and console:GetClass() == "ix_console" and console.user == client) then
client.currentCamera = entity
end
end)
netstream.Hook("GetConsoleUpdates", function(client)
local character = client:GetCharacter()
local class = character:GetClass()
if (class == CLASS_CP_CPT or class == CLASS_OVERSEER or class == CLASS_OW_SCANNER) then
PLUGIN:GetConsoleUpdates(client)
timer.Simple(0.05, function()
netstream.Start(client, "SetConsoleUpdates", PLUGIN.updatelist)
end)
end
end)
local function CloseConsole(client)
if (IsValid(client.ixConsole)) then
client.ixConsole:CloseConsole()
netstream.Start(client, "CloseConsole")
end
end
hook.Add("PlayerDisconnected", "ixConsoleCloseOnDisconnect", CloseConsole)
hook.Add("PlayerLoadedCharacter", "ixConsoleCloseOnCharSwap", CloseConsole)
hook.Add("PlayerDeath", "ixConsoleCloseOnDeath", CloseConsole)

View File

@@ -0,0 +1,60 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
local ix = ix
include('shared.lua')
netstream.Hook("OpenComputer", function(activeComputer, activeComputerUsers, activeComputerNotes, groupmessages, hasDiskInserted)
LocalPlayer().activeComputer = activeComputer
LocalPlayer().activeComputer.hasDiskInserted = hasDiskInserted
LocalPlayer().activeComputerUsers = activeComputerUsers
LocalPlayer().activeComputerNotes = activeComputerNotes
netstream.Start("SyncStoredNewspapers")
local base = vgui.Create("CitizenComputer")
ix.gui.medicalComputer.groupMessages = groupmessages or {}
end)
-- function ENT:Draw()
-- self:DrawModel()
-- local ang = self:GetAngles()
-- local pos = self:GetPos() + ang:Up() * 12 + ang:Right() * 10 + ang:Forward() * 11.75
-- ang:RotateAroundAxis(ang:Right(), -85.6)
-- ang:RotateAroundAxis(ang:Up(), 90)
-- local width, height = 200, 170
-- local display = self.Displays[self:GetDisplay()] or self.Displays[6]
-- cam.Start3D2D( pos, ang, 0.1 )
-- render.PushFilterMin(TEXFILTER.NONE)
-- render.PushFilterMag(TEXFILTER.NONE)
-- surface.SetDrawColor( Color( 16, 16, 16, 240 ) )
-- surface.DrawRect( 0, 0, width, height )
-- surface.SetDrawColor( Color( 255, 255, 255, 16 ) )
-- surface.DrawRect( 10, height / 2 + math.sin( CurTime() * 4 ) * height / 2.5, width - 22, 1 )
-- local alpha = 191 + 64 * math.sin( CurTime() * 4 )
-- local color = ColorAlpha(display[2], alpha)
-- draw.SimpleText( "Computer", "MenuFont", width / 2, 25, Color( 255, 255, 255, alpha ), TEXT_ALIGN_CENTER )
-- draw.SimpleText( display[1], "MenuFont", width / 2, height - 35, Color( 255, 255, 180, alpha ), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
-- render.PopFilterMin()
-- render.PopFilterMag()
-- cam.End3D2D()
-- end

View File

@@ -0,0 +1,73 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local timer = timer
local IsValid = IsValid
AddCSLuaFile( "cl_init.lua" ) -- Make sure clientside
AddCSLuaFile( "shared.lua" ) -- and shared scripts are sent.
include("shared.lua")
function ENT:SetProperSkin()
self:SetSkin(0)
end
function ENT:SaveMedicalComputers()
ix.saveEnts:SaveEntity(self)
end
function ENT:Use(client)
if (client.CantPlace) then
client:NotifyLocalized("You need to wait before you can use this!")
return false
end
client.CantPlace = true
timer.Simple(3, function()
if (client) then
client.CantPlace = false
end
end)
if (self:GetNWInt("owner") == nil) then
self:SetNWInt("owner", client:GetCharacter():GetID())
end
if (!self.canUse) then
return
end
self:EmitSound( "buttons/button1.wav" )
self.canUse = false
if (client:GetCharacter():GetGroup()) then
self:GetGroupInformation(client, client:GetCharacter(), true)
else
netstream.Start(client, "OpenComputer", self, self.users, self.notes, false, self.hasDiskInserted)
end
self:SetDisplay(2)
local uniqueID = "computer_"..self:EntIndex().."_charcheck"
timer.Create(uniqueID, 10, 0, function()
if (!IsValid(self)) then
timer.Remove(uniqueID)
return
elseif (!IsValid(client) or !client:GetCharacter()) then
self.canUse = true
self:SetDisplay(1)
timer.Remove(uniqueID)
end
end)
end

View File

@@ -0,0 +1,22 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ENT.Type = "anim"
ENT.Author = "Fruity"
ENT.Base = "ix_medical_computer"
ENT.PrintName = "Computer"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true

View File

@@ -0,0 +1,43 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
include('shared.lua')
function ENT:Draw()
self:DrawModel() -- Draw the model
local ang = self:GetAngles()
local pos = self:GetPos() + ang:Up() * 48 + ang:Right() * 9.8 + ang:Forward() * -2.38
ang:RotateAroundAxis(ang:Right(), -90)
ang:RotateAroundAxis(ang:Up(), 90)
ang:RotateAroundAxis( ang:Forward(), -48 )
cam.Start3D2D( pos, ang, 0.1 )
local width, height = 155, 80
surface.SetDrawColor( Color( 255, 255, 255, 16 ) )
surface.DrawRect( 0, height / 2 + math.sin( CurTime() * 4 ) * height / 2, width, 1 )
local alpha = 191 + 64 * math.sin( CurTime() * 4 )
draw.SimpleText( "Command Console", "MenuFont", width / 2, 15, Color( 255, 255, 255, alpha ), TEXT_ALIGN_CENTER )
draw.SimpleText( "Waiting for user", "MenuFont", width / 2, height - 25, Color( 255, 255, 180, alpha ), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
cam.End3D2D()
end
netstream.Hook("OpenConsoleGUI", function(entity)
ix.gui.consolePanel = vgui.Create("ConsolePanel")
ix.gui.consolePanel.entity = entity
end)

View File

@@ -0,0 +1,156 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
AddCSLuaFile( "cl_init.lua" ) -- Make sure clientside
AddCSLuaFile( "shared.lua" ) -- and shared scripts are sent.
include('shared.lua')
function ENT:Initialize()
self:SetModel( "models/props_combine/combine_interface001.mdl" )
self:SetSubMaterial(1, "phoenix_storms/black_chrome")
self:SetSolid(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:PhysicsInit( SOLID_VPHYSICS )
self:SetUseType(SIMPLE_USE)
self.canUse = true
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Wake()
end
if table.Count(ents.FindByClass("ix_console")) == 1 then
self:SetName("ix_console_master")
end
ix.saveEnts:SaveEntity(self)
end
function ENT:Use(client)
if (self.canUse) then
if ((!IsValid(self.user) or self.user == client) and client:GetActiveCombineSuit()) then
self.user = client
client.ixConsole = self
self:EmitSound("buttons/button19.wav", 75)
netstream.Start(client, "OpenConsoleGUI", self)
ix.combineNotify:AddNotification("LOG:// Command Console accessed by " .. client:GetCombineTag(), nil, client)
else
self.canUse = false
self:EmitSound("buttons/button8.wav", 75)
timer.Simple(1, function()
self.canUse = true
end)
end
end
end
function ENT:AcceptInput(input, activator, caller, data)
if (!caller.lastTarget or caller.lastTarget != activator) then
caller.lastTarget = activator
end
if (input == "Alert" and self:GetName() == "ix_console_master") then
local character = activator:GetCharacter()
if (activator:IsPlayer() and character and character:GetGenericdata() and !isnumber(character:GetGenericdata())) then
local genericData = character:GetGenericdata()
local cid = character:GetCid() or "N/A"
local name = string.utf8upper(character:GetName()) or "N/A"
if (genericData.anticitizen) then
if (genericData.anticitizen == true) then
caller:Fire("SetAngry", 0, 0)
ix.combineNotify:AddImportantNotification("WRN:// Visual on Anti-Citizen " .. name .. ", #" .. cid, nil, activator, activator:GetPos())
end
end
if (genericData.bol) then
if (genericData.bol == true) then
caller:Fire("SetAngry", 0, 0)
ix.combineNotify:AddImportantNotification("WRN:// Visual on BOL Suspect " .. name .. ", #" .. cid, Color(255, 255, 0, 255), activator, activator:GetPos())
end
end
if (activator:Team() == FACTION_VORT and character:GetBackground() != "Biotic" and character:GetBackground() != "Collaborator") then
local items = character:GetInventory():GetItems()
local shackles = false
local hooks = false
local collar = false
for itemID, itemData in pairs(items) do
if (ix.item.instances[itemID]:GetData("equip")) then
if (ix.item.instances[itemID].uniqueID == "vortigaunt_slave_shackles_fake") then
shackles = true
elseif (ix.item.instances[itemID].uniqueID == "vortigaunt_slave_hooks_fake") then
hooks = true
elseif (ix.item.instances[itemID].uniqueID == "vortigaunt_slave_collar_fake") then
collar = true
end
end
end
if (!shackles or !hooks or !collar) then
caller:Fire("SetAngry", 0, 0)
ix.combineNotify:AddImportantNotification("WRN:// Visual on Outland Biotic #" .. cid, Color(255, 0, 0, 255), activator, activator:GetPos())
end
end
end
if (activator:IsPlayer() and activator:IsRunning()) then
caller:Fire("SetAngry", 0, 0)
end
end
end
function ENT:OnRemove()
if IsValid(self.user) then
self.user.currentCamera = nil
end
self.user = nil
end
function ENT:CloseConsole()
if (IsValid(self.user)) then
self.user.currentCamera = nil
end
self.user = nil
end
-- Hooks
local function SetupCameraVis(client, entity)
if IsValid(client.currentCamera) then
AddOriginToPVS(client.currentCamera:GetPos())
end
end
hook.Add("SetupPlayerVisibility", "ConsoleCameraVisual", SetupCameraVis)
local function OnCameraCreated(entity)
if !entity or entity and !IsValid(entity) then return end
if (entity:GetClass() == "npc_combine_camera") then
timer.Simple(1, function()
if !entity or entity and !IsValid(entity) then return end
entity:SetHealth(100)
end)
entity:Fire("AddOutput", "OnFoundEnemy ix_console:Alert")
--ix.saveEnts:SaveEntity(entity)
end
end
hook.Add("OnEntityCreated", "OnCameraCreated", OnCameraCreated)

View File

@@ -0,0 +1,28 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ENT.Type = "anim"
ENT.Base = "base_gmodentity"
ENT.PrintName = "Console"
ENT.Author = "Fruity"
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = "Fruitybooty"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true

View File

@@ -0,0 +1,91 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
include('shared.lua')
netstream.Hook("OpenMedicalComputer", function(activeComputer, activeComputerUsers, activeComputerNotes, groupmessages, hasDiskInserted)
LocalPlayer().activeComputer = activeComputer
LocalPlayer().activeComputer.hasDiskInserted = hasDiskInserted
LocalPlayer().activeComputerUsers = activeComputerUsers
LocalPlayer().activeComputerNotes = activeComputerNotes
netstream.Start("SyncStoredNewspapers")
ix.gui.medicalComputer = vgui.Create("MedicalComputerBase")
ix.gui.medicalComputer.groupMessages = groupmessages or {}
end)
netstream.Hook("SyncStoredNewspapersClient", function(stored)
local writingPlugin = ix.plugin.list["writing"]
writingPlugin.storedNewspapers = stored
end)
netstream.Hook("createMedicalRecords", function(table, resultName, searchname, resultID)
LocalPlayer().activeComputerRecords = table
LocalPlayer().activeComputerResultName = resultName
LocalPlayer().activeComputerSearchName = searchname
LocalPlayer().activeComputerResultID = resultID
end)
function ENT:Initialize()
self:StartShittyComputerSound()
end
function ENT:StartShittyComputerSound()
local uniqueID = "MedicalAmbientSound_"..self:EntIndex()
local time = 1
timer.Simple(1, function()
timer.Adjust(uniqueID, 8)
end)
timer.Create(uniqueID, time, 0, function()
if (IsValid(self)) then
self:EmitSound( "willardnetworks/datapad/computerloop.wav", 65, 100, 0.15)
else
timer.Remove(uniqueID)
end
end)
end
-- function ENT:Draw()
-- self:DrawModel()
-- local ang = self:GetAngles()
-- local pos = self:GetPos() + ang:Up() * 12 + ang:Right() * 10 + ang:Forward() * 11.75
-- ang:RotateAroundAxis(ang:Right(), -85.6)
-- ang:RotateAroundAxis(ang:Up(), 90)
-- local width, height = 200, 170
-- local display = self.Displays[self:GetDisplay()] or self.Displays[6]
-- cam.Start3D2D( pos, ang, 0.1 )
-- render.PushFilterMin(TEXFILTER.NONE)
-- render.PushFilterMag(TEXFILTER.NONE)
-- surface.SetDrawColor( Color( 16, 16, 16, 240 ) )
-- surface.DrawRect( 0, 0, width, height )
-- surface.SetDrawColor( Color( 255, 255, 255, 16 ) )
-- surface.DrawRect( 10, height / 2 + math.sin( CurTime() * 4 ) * height / 2.5, width - 22, 1 )
-- local alpha = 191 + 64 * math.sin( CurTime() * 4 )
-- draw.SimpleText( "Medical Computer", "MenuFont", width / 2, 25, Color( 255, 255, 255, alpha ), TEXT_ALIGN_CENTER )
-- draw.SimpleText( display[1], "MenuFont", width / 2, height - 35, Color( 255, 255, 180, alpha ), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
-- render.PopFilterMin()
-- render.PopFilterMag()
-- cam.End3D2D()
-- end

View File

@@ -0,0 +1,395 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
AddCSLuaFile( "cl_init.lua" ) -- Make sure clientside
AddCSLuaFile( "shared.lua" ) -- and shared scripts are sent.
include('shared.lua')
util.AddNetworkString( "TypeSound" )
util.AddNetworkString( "ClickSound" )
function ENT:Initialize()
self:SetModel("models/willardnetworks/props/willard_computer.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:PhysicsInit( SOLID_VPHYSICS )
self:DrawShadow(false)
self:SetUseType(SIMPLE_USE)
self:SetDisplay(1)
local physics = self:GetPhysicsObject()
physics:EnableMotion(true)
physics:Wake()
timer.Simple(1, function()
if IsValid(self) and physics then
physics:EnableMotion(false)
end
end)
self.canUse = true
self.users = {}
self.notes = {}
self:SaveMedicalComputers()
-- self:SpawnProps()
self:SetProperSkin()
self.hasDiskInserted = false
end
function ENT:SetProperSkin()
self:SetSkin(1)
end
function ENT:SaveMedicalComputers()
ix.saveEnts:SaveEntity(self)
end
function ENT:CloseMedicalComputer()
self:SetDisplay(3)
self:EmitSound("ambient/machines/combine_terminal_idle1.wav")
timer.Remove("computer_"..self:EntIndex().."_charcheck")
timer.Simple(2, function()
if IsValid(self) then
self:SetDisplay(1)
self.canUse = true
end
end)
end
-- function ENT:SpawnProps()
-- local rightFrom = Vector(-20 * self:GetRight(), 0, 0)
-- local leftFrom = Vector(20 * self:GetRight(), 0, 0)
-- local forwardFrom = Vector(20 * self:GetForward(), 0, 0)
-- local aBitDown = Vector(0, 0, 3)
-- local cabinet = ents.Create("prop_dynamic")
-- cabinet:SetPos(self:GetPos() + leftFrom - aBitDown)
-- cabinet:SetAngles(self:GetAngles())
-- cabinet:SetModel("models/props_lab/harddrive02.mdl")
-- cabinet:Activate()
-- cabinet:SetParent(self)
-- cabinet:Spawn()
-- cabinet:DeleteOnRemove(self)
-- local keyboard = ents.Create("prop_dynamic")
-- keyboard:SetPos(self:GetPos() + forwardFrom - (aBitDown * 4.5))
-- keyboard:SetAngles(self:GetAngles())
-- keyboard:SetModel("models/props_c17/computer01_keyboard.mdl")
-- keyboard:Activate()
-- keyboard:SetParent(self)
-- keyboard:Spawn()
-- keyboard:DeleteOnRemove(self)
-- local mouse = ents.Create("prop_dynamic")
-- mouse:SetPos(self:GetPos() + forwardFrom + rightFrom - (aBitDown * 4.3))
-- mouse:SetAngles(self:GetAngles() + Angle(20, -80, 0))
-- mouse:SetModel("models/gibs/shield_scanner_gib1.mdl")
-- mouse:SetMaterial("phoenix_storms/dome")
-- mouse:Activate()
-- mouse:SetParent(self)
-- mouse:Spawn()
-- mouse:DeleteOnRemove(self)
-- end
function ENT:GetGroupInformation(client, character, bNormal)
self.groupmessages = {}
self.groupmessages["messages"] = {}
self.groupmessages["replies"] = {}
local messageQuery = mysql:Select("ix_comgroupmessages")
messageQuery:Select("message_id")
messageQuery:Select("message_text")
messageQuery:Select("message_date")
messageQuery:Select("message_poster")
messageQuery:Select("message_groupid")
messageQuery:Where("message_groupid", character:GetGroupID())
messageQuery:Callback(function(result)
self.groupmessages["messages"] = result or {}
local replyQuery = mysql:Select("ix_comgroupreplies")
replyQuery:Select("reply_id")
replyQuery:Select("reply_text")
replyQuery:Select("reply_date")
replyQuery:Select("reply_poster")
replyQuery:Select("reply_parent")
replyQuery:Select("reply_groupid")
replyQuery:Where("reply_groupid", character:GetGroupID())
replyQuery:Callback(function(result2)
self.groupmessages["replies"] = result2 or {}
if !bNormal then
netstream.Start(client, "OpenMedicalComputer", self, self.users, self.notes, self.groupmessages, self.hasDiskInserted)
else
netstream.Start(client, "OpenComputer", self, self.users, self.notes, self.groupmessages, self.hasDiskInserted)
end
end)
replyQuery:Execute()
end)
messageQuery:Execute()
end
function ENT:Use(client)
if (client.CantPlace) then
client:NotifyLocalized("You need to wait before you can use this!")
return false
end
client.CantPlace = true
timer.Simple(3, function()
if (client) then
client.CantPlace = false
end
end)
local character = client:GetCharacter()
if (self:GetNWInt("owner") == nil) then
self:SetNWInt("owner", character:GetID())
end
if !self.canUse then
return
end
self:EmitSound( "buttons/button1.wav" )
self.canUse = false
if (character:GetGroup()) then
self:GetGroupInformation(client, character, false)
else
netstream.Start(client, "OpenMedicalComputer", self, self.users, self.notes, false, self.hasDiskInserted)
end
self:SetDisplay(2)
local uniqueID = "computer_"..self:EntIndex().."_charcheck"
timer.Create(uniqueID, 10, 0, function()
if (!IsValid(self)) then
timer.Remove(uniqueID)
return
elseif (!IsValid(client) or !client:GetCharacter()) then
self.canUse = true
self:SetDisplay(1)
timer.Remove(uniqueID)
end
end)
end
function ENT:AddUser(cid)
if (self.users) then
if (istable(self.users)) then
table.insert(self.users, cid)
end
end
end
function ENT:AddNote(name, text, headline)
self.notes[#self.notes + 1] = {
text = text,
headline = headline,
date = ix.date.GetFormatted("%d/%m/%Y"),
poster = name
}
end
function ENT:UpdateNote(name, text, headline, key)
if !text then self.notes[key] = nil return end
self.notes[key] = {
text = text,
headline = headline,
date = ix.date.GetFormatted("%d/%m/%Y"),
poster = name
}
end
function ENT:OnRemove()
if timer.Exists("MedicalAmbientSound_"..self:EntIndex()) then
timer.Remove("MedicalAmbientSound_"..self:EntIndex())
end
end
function ENT:CheckIfUserHasAccess(client)
if client:HasActiveCombineSuit() then return true end
local character = client:GetCharacter()
local inventory = character:GetInventory()
local invItems = inventory:GetItems()
for _, v in pairs(self.users) do
for _, v2 in pairs(invItems) do
if v2.uniqueID != "id_card" then
continue
end
if tostring(v) == tostring(v2:GetData("cid")) then
return true
end
end
end
client:Notify("You do not have access or you are not wearing a combine suit.")
return false
end
netstream.Hook("AddComputerUser", function(client, activeComputer, cid)
if table.IsEmpty(activeComputer.users) then activeComputer:AddUser(cid) return end
if activeComputer:CheckIfUserHasAccess(client) then
activeComputer:AddUser(cid)
else
return false
end
end)
netstream.Hook("searchMedicalFile", function(client, searchname, activeComputer)
if !activeComputer:CheckIfUserHasAccess(client) then
return false
end
local curTime = CurTime()
if (client.nextSearchMedicalFile and client.nextSearchMedicalFile > curTime) then
return
end
client.nextSearchMedicalFile = curTime + 2
local query = mysql:Select("ix_characters")
query:Select("id")
query:Select("name")
query:Select("cid")
query:WhereLike(((tonumber(searchname) != nil and string.utf8len( searchname ) <= 5) and "cid" or "name"), searchname)
query:Where("schema", Schema and Schema.folder or "helix")
query:Limit(1)
query:Callback(function(result)
if (!istable(result)) then
netstream.Start(client, "createMedicalRecords", false, false, false, false)
return
end
if not result[1] then
netstream.Start(client, "createMedicalRecords", false, false, false, false)
return
end
local dataQuery = mysql:Select("ix_characters_data")
dataQuery:Select("data")
dataQuery:Where("id", result[1].id)
dataQuery:Where("key", "datafilemedicalrecords")
dataQuery:Callback(function(dataResult)
if (!istable(dataResult)) then
netstream.Start(client, "createMedicalRecords", false, false, false, false)
return
end
if not dataResult[1] then
netstream.Start(client, "createMedicalRecords", false, false, false, false)
return
end
local medicalrecords = util.JSONToTable(dataResult[1].data or "")
timer.Simple(0.05, function()
netstream.Start(client, "createMedicalRecords", medicalrecords, result[1].name, searchname, result[1].id)
end)
end)
dataQuery:Execute()
end)
query:Execute()
end)
netstream.Hook("MedicalComputerAddRecord", function(client, id, posterName, text, activeComputer)
if !activeComputer:CheckIfUserHasAccess(client) then
return false
end
id = tonumber(id)
local dataQuery = mysql:Select("ix_characters_data")
dataQuery:Select("data")
dataQuery:Where("id", id)
dataQuery:Where("key", "datafilemedicalrecords")
dataQuery:Callback(function(dataResult)
if (!istable(dataResult)) then
return
end
if not dataResult[1] then
return
end
local medicalrecords = util.JSONToTable(dataResult[1].data or "")
medicalrecords[#medicalrecords + 1] = {
text = text,
date = os.date("%d/%m/%Y"),
poster = posterName
}
if (ix.char.loaded[id]) then
ix.char.loaded[id]:SetDatafilemedicalrecords(medicalrecords)
ix.char.loaded[id]:Save()
else
local updateQuery = mysql:Update("ix_characters_data")
updateQuery:Update("data", util.TableToJSON(medicalrecords))
updateQuery:Where("id", id)
updateQuery:Where("key", "datafilemedicalrecords")
updateQuery:Execute()
end
end)
dataQuery:Execute()
end)
netstream.Hook("MedicalComputerAddNote", function(client, activeComputer, posterName, text, headline)
if !activeComputer:CheckIfUserHasAccess(client) then
return false
end
activeComputer:AddNote(posterName, text, headline)
end)
netstream.Hook("MedicalComputerUpdateNote", function(client, activeComputer, posterName, text, headline, key)
if !activeComputer:CheckIfUserHasAccess(client) then
return false
end
activeComputer:UpdateNote(posterName, text, headline, key)
end)
net.Receive( "TypeSound", function( length, client )
client:EmitSound(string.format( "ambient/machines/keyboard%d_clicks.wav", math.random( 6 ) ),75)
end )
net.Receive( "ClickSound", function( length, client )
client:EmitSound("willardnetworks/datapad/mouseclick.wav", 75)
end )
netstream.Hook("CloseMedicalComputer", function(client, activeComputer)
if activeComputer then
activeComputer:CloseMedicalComputer()
end
end)
netstream.Hook("SyncStoredNewspapers", function(client)
local writingPlugin = ix.plugin.list["writing"]
local storedNewspapers = writingPlugin.storedNewspapers
netstream.Start(client, "SyncStoredNewspapersClient", storedNewspapers)
end)

View File

@@ -0,0 +1,32 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ENT.Type = "anim"
ENT.Author = "Fruity"
ENT.PrintName = "Medical Computer"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
ENT.Displays = {
[1] = {"WAITING FOR USER", Color( 255, 255, 180 ), true},
[2] = {"RETRIEVING INFO", Color(0, 255, 0)},
[3] = {"RELOADING", Color(255, 200, 0)},
[4] = {"OFFLINE", Color(255, 0, 0), true}
}
function ENT:SetupDataTables()
self:NetworkVar("Int", 0, "Display")
end

View File

@@ -0,0 +1,82 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
include('shared.lua')
netstream.Hook("OpenTerminal", function(idCardId, genericData, activeCID, credits, entity, messages)
LocalPlayer().idCardId = idCardId
LocalPlayer().idCardCredits = credits
LocalPlayer().activeTerminal = entity
LocalPlayer().genericData = genericData
LocalPlayer().activeCID = activeCID
if istable(messages) then
LocalPlayer().messageList = messages
else
messages = {}
LocalPlayer().messageList = messages
end
vgui.Create("ixTerminal")
end)
netstream.Hook("OpenCIDSelectorTerminal", function(entity)
LocalPlayer().activeTerminal = entity
local cidSelector = vgui.Create("CIDSelector")
cidSelector.activeEntity = entity
cidSelector.ExitCallback = function()
netstream.Start("ClosePanelsTerminal", LocalPlayer().activeTerminal)
LocalPlayer().activeTerminal = nil
LocalPlayer().genericData = nil
LocalPlayer().activeCID = nil
LocalPlayer().messageList = nil
end
cidSelector.SelectCallback = function(idCardID, cid, cidName, entity)
netstream.Start("SelectCIDTerminal", idCardID, cid, cidName, entity)
end
end)
function ENT:Draw()
self:DrawModel()
local width, height = 200, 120
local ang = self:GetAngles()
local pos = self:GetPos() + ang:Up() * 31.2 + ang:Right() * 13 + ang:Forward() * 3.1
ang:RotateAroundAxis(ang:Right(), 94)
ang:RotateAroundAxis(ang:Up(), 90)
ang:RotateAroundAxis(ang:Forward(), 180)
local display = self.Displays[self:GetDisplay()] or self.Displays[6]
cam.Start3D2D( pos, ang, 0.1 )
render.PushFilterMin(TEXFILTER.NONE)
render.PushFilterMag(TEXFILTER.NONE)
surface.SetDrawColor( Color( 16, 16, 16, 140 ) )
surface.DrawRect( 0, 0, width, height )
surface.SetDrawColor( Color( 255, 255, 255, 16 ) )
surface.DrawRect( 0, height / 2 + math.sin( CurTime() * 4 ) * height / 2, width, 1 )
local alpha = 191 + 64 * math.sin( CurTime() * 4 )
local color = ColorAlpha(display[2], alpha)
draw.SimpleText( "Citizen Terminal", "MenuFont", width / 2, 25, Color( 255, 255, 255, alpha ), TEXT_ALIGN_CENTER )
draw.SimpleText(display[1], "MenuFont", width / 2, height * 0.5, color, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
render.PopFilterMin()
render.PopFilterMag()
cam.End3D2D()
end

View File

@@ -0,0 +1,452 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
AddCSLuaFile( "cl_init.lua" ) -- Make sure clientside
AddCSLuaFile( "shared.lua" ) -- and shared scripts are sent.
include('shared.lua')
function ENT:Initialize()
self:SetModel(self.model)
self:SetSolid(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:PhysicsInit( SOLID_VPHYSICS )
self:DrawShadow(false)
self:SetUseType(SIMPLE_USE)
self:SetDisplay(1)
local physics = self:GetPhysicsObject()
if (physics) then
physics:EnableMotion(false)
physics:Wake()
end
self.canUse = true
self:SaveTerminalLocations()
self:OnInitialize()
end
function ENT:OnInitialize()
end
function ENT:SaveTerminalLocations()
ix.saveEnts:SaveEntity(self)
end
function ENT:CheckGlobalUse(client)
if client.CantPlace then
client:NotifyLocalized("You need to wait before you can use this!")
return false
end
client.CantPlace = true
timer.Simple(3, function()
if client then
client.CantPlace = false
end
end)
return true
end
function ENT:CheckLocalUse(client)
if (!self.canUse and IsValid(self.activePlayer) and self.activePlayer:GetCharacter() == self.activeCharacter) then
return false
else
self.canUse = false
self.activePlayer = client
self.activeCharacter = client:GetCharacter()
return true
end
end
function ENT:Use(client)
if !self:CheckGlobalUse(client) then
return false
end
if !self:CheckLocalUse(client) then
return false
end
self:OnUse(client)
end
function ENT:OnUse(client)
self:CheckForCID(client)
end
function ENT:SetGroups(bUse)
if bUse then
self:SetBodygroup(2, 1)
self:SetSkin(1)
else
self:SetBodygroup(2, 0)
self:SetSkin(0)
end
end
function ENT:CheckForCID(client)
if (ix.config.Get("creditsNoConnection")) then
self.canUse = false
self:SetGroups(true)
self:SetDisplay(2)
self:EmitSound("buttons/button4.wav")
timer.Simple(10, function()
if (!IsValid(self)) then return end
self:SetDisplay(5)
self:EmitSound("hl1/fvox/buzz.wav", 60, 100, 0.5)
timer.Simple(5, function()
if (!IsValid(self)) then return end
self.canUse = true
self:SetDisplay(1)
self:SetGroups(false)
end)
end)
return
end
local idCards = self.activeCharacter:GetInventory():GetItemsByUniqueID("id_card")
if (#idCards > 1) then
self:OpenCIDSelector(client)
return
end
if (#idCards == 1) then
self:SetGroups(true)
idCards[1]:LoadOwnerGenericData(self.OpenTerminal, self.OpenTerminalFail, client, self)
else
self.canUse = false
self:EmitSound("buttons/button2.wav")
timer.Simple(1, function()
if (IsValid(self)) then
self.canUse = true
end
end)
end
end
function ENT:OpenCIDSelector(client)
netstream.Start(client, "OpenCIDSelectorTerminal", self)
end
netstream.Hook("SelectCIDTerminal", function(client, idCardID, _, _, activeTerminal)
if (IsValid(activeTerminal)) then
local idCard = ix.item.instances[idCardID]
if (!idCard) then
activeTerminal.OpenTerminalFail(nil, client, activeTerminal)
else
idCard:LoadOwnerGenericData(activeTerminal.OpenTerminal, activeTerminal.OpenTerminalFail, client, activeTerminal)
end
end
end)
netstream.Hook("ClosePanelsTerminal", function(client, activeTerminal)
if (IsValid(activeTerminal)) then
activeTerminal.OpenTerminalFail(nil, client, activeTerminal)
end
activeTerminal.genericDataCredits = nil
activeTerminal.genericDataCommunion = nil
activeTerminal.activeCID = nil
end)
function ENT.OpenTerminalFail(idCard, client, activeTerminal)
if (!IsValid(activeTerminal)) then return end
activeTerminal:SetDisplay(4)
activeTerminal:EmitSound("ambient/machines/combine_terminal_idle1.wav")
activeTerminal:SetGroups(false)
timer.Simple(2, function()
if IsValid(activeTerminal) then
activeTerminal:SetDisplay(1)
activeTerminal.canUse = true
end
end)
end
function ENT.OpenTerminal(idCard, genericData, client, activeTerminal)
if (!IsValid(activeTerminal)) then return end
activeTerminal:SetGroups(true)
activeTerminal:EmitSound("buttons/button4.wav")
activeTerminal:SetDisplay(2)
if (activeTerminal:CheckForVerdicts(client, idCard, genericData)) then
timer.Simple(2, function()
if table.IsEmpty(genericData) then
activeTerminal:SetDisplay(8)
activeTerminal:EmitSound("buttons/button2.wav")
timer.Simple(2, function()
if IsValid(activeTerminal) then
activeTerminal:SetDisplay(1)
activeTerminal.canUse = true
end
end)
else
activeTerminal:OnSuccess(idCard, genericData, client)
end
end)
end
end
function ENT:IsSocialOrCohesion(character, genericData)
if (character:IsVortigaunt()) then
if (genericData.cohesionPoints) then
return genericData.cohesionPoints
else
return genericData.socialCredits
end
else
return genericData.socialCredits
end
end
function ENT:OnSuccess(idCard, genericData, client)
local character = client:GetCharacter()
self:SetDisplay(7)
self:EmitSound("ambient/machines/combine_terminal_idle3.wav")
self.genericDataCommunion = genericData.bypassCommunion
self.activeCID = idCard:GetData("cid")
genericData.socialCredits = !genericData.combine and math.Clamp(tonumber(self:IsSocialOrCohesion(character, genericData)), 0, 200) or tonumber(self:IsSocialOrCohesion(character, genericData))
self.genericDataCredits = genericData.socialCredits
local query = mysql:Select("ix_camessaging")
query:Select("message_cid")
query:Select("message_text")
query:Select("message_date")
query:Select("message_poster")
query:Select("message_reply")
query:Where("message_cid", idCard:GetData("cid"))
query:Callback(function(result)
if (character:IsVortigaunt()) then
if (genericData.cid or character:GetBackground() == "Collaborator") then
ix.combineNotify:AddNotification("LOG:// Subject " .. string.upper("biotic asset identification card:") .. " #" .. genericData.cid .. " used Civil Terminal", nil, client)
else
ix.combineNotify:AddNotification("LOG:// Subject " .. string.upper("biotic asset collar:") .. " #" .. character:GetCollarID() .. " used Civil Terminal", nil, client)
end
else
ix.combineNotify:AddNotification("LOG:// Subject '" .. genericData.name .. "' used Civil Terminal", nil, client)
end
if (!istable(result)) then
netstream.Start(client, "OpenTerminal", idCard:GetID(), genericData, idCard:GetData("cid"), idCard:GetCredits(), self)
return
end
netstream.Start(client, "OpenTerminal", idCard:GetID(), genericData, idCard:GetData("cid"), idCard:GetCredits(), self, result)
end)
query:Execute()
end
function ENT:CheckForVerdicts(client, idCard, genericData)
if (idCard:GetData("active", false) == false) then
self:CreateCombineAlert(client, "WRN:// Inactive Identification Card #" .. idCard:GetData("cid", 00000) .. " usage attempt detected")
self:SetDisplay(8)
timer.Simple(1.5, function()
if self then
self.OpenTerminalFail(nil, client, self)
end
end)
return
end
local isBOL = genericData.bol
local isAC = genericData.anticitizen
if (isBOL or isAC) then
local text = isBOL and "BOL Suspect" or "Anti-Citizen"
self:CreateCombineAlert(client, "WRN:// " .. text .. " Identification Card activity detected")
if isAC then
self:SetDisplay(8)
timer.Simple(1.5, function()
if self then
self.OpenTerminalFail(nil, client, self)
end
end)
end
return !isAC -- stop if isAC, continue for isBOL
end
return true
end
function ENT:CreateCombineAlert(client, message)
ix.combineNotify:AddImportantNotification(message, nil, client, self:GetPos())
end
function ENT.CheckIdCardCoupon(idCard, genericData, client, entity, couponAmount)
local character = client:GetCharacter()
if entity:IDCardCheck(idCard, genericData, client, entity) then
entity:EmitSound("ambient/levels/labs/coinslot1.wav")
if (ix.config.Get("creditsNoConnection")) then
entity:SetDisplay(2)
entity.canUse = false
timer.Simple(10, function()
if (!IsValid(entity)) then return end
entity:SetDisplay(5)
entity:EmitSound("buttons/combine_button_locked.wav")
timer.Simple(5, function()
if (!IsValid(entity)) then return end
entity:SetDisplay(1)
entity.canUse = true
end)
timer.Simple(2, function()
if (!IsValid(entity)) then return end
entity:EmitSound("ambient/levels/labs/coinslot1.wav")
end)
end)
return
end
timer.Simple(1, function()
if IsValid(entity) then
entity:EmitSound("Friends/friend_online.wav")
end
end)
entity:SetDisplay(2)
entity.canUse = false
timer.Simple(2, function()
if IsValid(entity) then
if ix.city.main:HasCredits(couponAmount) then
entity:EmitSound("Friends/friend_join.wav")
entity:SetDisplay(4)
idCard:GiveCredits(couponAmount, "Rations", "Ration Coupon")
ix.city.main:TakeCredits(couponAmount)
else
entity:SetDisplay(2)
entity.canUse = false
timer.Simple(10, function()
if (!IsValid(entity)) then return end
entity:SetDisplay(5)
entity:EmitSound("buttons/combine_button_locked.wav")
timer.Simple(5, function()
if (!IsValid(entity)) then return end
entity:SetDisplay(1)
entity.canUse = true
end)
timer.Simple(2, function()
if (!IsValid(entity)) then return end
entity:EmitSound("ambient/levels/labs/coinslot1.wav")
end)
end)
return
end
if ix.item.instances[client.ixCouponUsed] then
ix.item.instances[client.ixCouponUsed]:Remove()
end
client.ixCouponUsed = nil
ix.log.Add(client, "rationsCoupon", couponAmount)
timer.Simple(2, function()
if IsValid(entity) then
entity:SetDisplay(1)
entity.canUse = true
end
end)
end
end)
end
end
function ENT.CheckIdError(idCard, client, entity)
entity:DisplayError(INVALID_CID)
client.ixCouponUsed = nil
end
function ENT:IDCardCheck(idCard, genericData, client, entity)
if (idCard:GetData("active", false) == false) then
entity:CreateCombineAlert(client, "WRN:// Inactive Identification Card #" .. idCard:GetData("cid", 00000) .. " usage attempt detected", FREQ_LIMIT)
return false
end
local isBOL = genericData.bol
local isAC = genericData.anticitizen
if (isBOL or isAC) then
local text = isBOL and "BOL Suspect" or "Anti-Citizen"
entity:CreateCombineAlert(client, "WRN:// " .. text .. " Identification Card activity detected", isAC and FREQ_LIMIT)
-- only halt if isAC, allow it to continue for BOL
if (isAC) then
return false
end
end
return true
end
netstream.Hook("AddCAMessage", function(client, name, cid, text, activeTerminal)
if !text or !name or !cid then return false end
if cid != activeTerminal.activeCID then
return false
end
if activeTerminal.genericDataCredits < ix.config.Get("communionSCRequirement", 150) and !activeTerminal.genericDataCommunion then
return false
end
local timestamp = os.date( "%d.%m.%Y" )
local queryObj = mysql:Insert("ix_camessaging")
queryObj:Insert("message_poster", name)
queryObj:Insert("message_text", text)
queryObj:Insert("message_date", timestamp)
queryObj:Insert("message_cid", cid)
queryObj:Execute()
ix.combineNotify:AddNotification("LOG:// Subject '" .. name .. "' sent a message via terminal communion", nil, client)
for _, v in pairs(player.GetAll()) do
if !IsValid(v) then continue end
local character = v:GetCharacter()
if !character then continue end
local inventory = character:GetInventory()
if !inventory:HasItem("capda") then continue end
v:Notify("Someone just sent a message via terminal communion!")
end
end)
netstream.Hook("RemoveCAMessage", function(client, id)
if !id then return false end
if !client:GetCharacter():GetFaction() != FACTION_ADMIN then return false end
local queryObj = mysql:Delete("ix_camessaging")
queryObj:Where("message_id", id)
queryObj:Execute()
end)
netstream.Hook("BreakAttemptSpottedTerminal", function(client, name, cid, activeTerminal)
if cid != activeTerminal.activeCID then
return false
end
ix.combineNotify:AddImportantNotification("WRN:// Attempted 51b; Threat to Property", nil, client, client:GetPos())
end)

View File

@@ -0,0 +1,43 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ENT.Type = "anim"
ENT.PrintName = "Citizen Terminal"
ENT.Author = "Fruity"
ENT.Contact = "Willard Networks"
ENT.Purpose = "View datafile info and more via entity."
ENT.Instructions = "Press E"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
ENT.model = "models/willardnetworks/props/civilterminal7.mdl"
ENT.canMalfunction = true
ENT.Displays = {
[1] = {"WAITING FOR ID", Color( 255, 255, 180 ), true},
[2] = {"CHECKING", Color(255, 200, 0)},
[3] = {"RETRIEVING INFO", Color(0, 255, 0)},
[4] = {"RELOADING", Color(255, 200, 0)},
[5] = {"OFFLINE", Color(255, 0, 0), true},
[6] = {"WAITING FOR ID", Color( 255, 255, 180 )},
[7] = {"PREPARING", Color(0, 255, 0)},
[8] = {"NO INFO", Color(0, 255, 0)}
}
function ENT:SetupDataTables()
self:NetworkVar("Int", 0, "Display")
end

View File

@@ -0,0 +1,606 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
if (SERVER) then
AddCSLuaFile("shared.lua")
end
SWEP.PrintName = "Combine Datapad"
SWEP.Category = "Half-Life 2"
SWEP.Spawnable= true
SWEP.AdminSpawnable= true
SWEP.AdminOnly = false
SWEP.ViewModelFOV = 70
SWEP.ViewModel = "models/weapons/c_slam.mdl"
SWEP.WorldModel = "models/weapons/w_slam.mdl"
SWEP.ShowViewModel = false
SWEP.ShowWorldModel = false
SWEP.ViewModelFlip = false
SWEP.BobScale = 1
SWEP.SwayScale = 0
SWEP.AutoSwitchTo = false
SWEP.AutoSwitchFrom = false
SWEP.Weight = 0
SWEP.Slot = 0
SWEP.SlotPos = 1
SWEP.UseHands = true
SWEP.FireWhenLowered = true
SWEP.FiresUnderwater = true
SWEP.DrawAmmo = false
SWEP.CSMuzzleFlashes = 1
SWEP.Base = "weapon_base"
SWEP.IsAlwaysRaised = true
SWEP.HoldType = "knife"
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = ""
SWEP.Primary.Damage = 5
SWEP.Primary.Delay = 0.75
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = ""
SWEP.Secondary.Delay = 0.5
SWEP.MaxOffFlat = 80 -- Maximum degrees off of flat to be.
SWEP.LastFire = 0
SWEP.IronSightsPos = Vector(0, 0, 0)
SWEP.IronSightsAng = Vector(0, 0, 0)
SWEP.ViewModelBoneMods = {
["Slam_base"] = { scale = Vector(0.001, 0.001, 0.001), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
["Detonator"] = { scale = Vector(0.001, 0.001, 0.001), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) }
}
SWEP.VElements = {
["v_element"] = { type = "Model", model = "models/fruity/tablet/tablet_sfm.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(7.068, 2.714, -1.198), angle = Angle(75.973, -119.392, 180), size = Vector(1, 1, 2), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 3, bodygroup = {} }
}
SWEP.WElements = {
["w_element"] = { type = "Model", model = "models/fruity/tablet/tablet_sfm.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3.901, 5.111, -0.477), angle = Angle(36.905, -180, -178.631), size = Vector(0.8, 0.8, 0.8), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 3, bodygroup = {} }
}
function SWEP:Initialize()
self:SetHoldType( self.HoldType )
if CLIENT then
-- Create a new table for every weapon instance
self.VElements = table.FullCopy( self.VElements )
self.WElements = table.FullCopy( self.WElements )
self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
self:SetHoldType( self.HoldType )
self:CreateModels(self.VElements) -- create viewmodels
self:CreateModels(self.WElements) -- create worldmodels
-- init view model bone build function
if IsValid(self.Owner) then
local vm = self.Owner:GetViewModel()
if IsValid(vm) then
self:ResetBonePositions(vm)
-- Init viewmodel visibility
if (self.ShowViewModel == nil or self.ShowViewModel) then
vm:SetColor(Color(255,255,255,255))
else
-- we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
vm:SetColor(Color(255,255,255,1))
-- ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
-- however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
vm:SetMaterial("Debug/hsv")
end
end
end
end
end
----------------------------------------------------
if CLIENT then
SWEP.vRenderOrder = nil
function SWEP:ViewModelDrawn()
local vm = self.Owner:GetViewModel()
if !IsValid(vm) then return end
if (!self.VElements) then return end
self:UpdateBonePositions(vm)
if (!self.vRenderOrder) then
-- we build a render order because sprites need to be drawn after models
self.vRenderOrder = {}
for k, v in pairs( self.VElements ) do
if (v.type == "Model") then
table.insert(self.vRenderOrder, 1, k)
elseif (v.type == "Sprite" or v.type == "Quad") then
table.insert(self.vRenderOrder, k)
end
end
end
for _, name in ipairs( self.vRenderOrder ) do
local v = self.VElements[name]
if (!v) then self.vRenderOrder = nil break end
if (v.hide) then continue end
local model = v.modelEnt
local sprite = v.spriteMaterial
if (!v.bone) then continue end
local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
if (!pos) then continue end
if (v.type == "Model" and IsValid(model)) then
model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
model:SetAngles(ang)
--model:SetModelScale(v.size)
local matrix = Matrix()
matrix:Scale(v.size)
model:EnableMatrix( "RenderMultiply", matrix )
if (v.material == "") then
model:SetMaterial("")
elseif (model:GetMaterial() != v.material) then
model:SetMaterial( v.material )
end
if IsValid(PLUGIN.updates) and PLUGIN.updates:IsVisible() then
model:SetSkin(3)
elseif IsValid(PLUGIN.viewLogs) and PLUGIN.viewLogs:IsVisible() then
model:SetSkin(5)
elseif IsValid(PLUGIN.viewLog) and PLUGIN.viewLog:IsVisible() then
model:SetSkin(6)
elseif IsValid(PLUGIN.editupdates) and PLUGIN.editupdates:IsVisible() then
model:SetSkin(7)
elseif (IsValid(PLUGIN.editUpdate) and PLUGIN.editUpdate:IsVisible()) or (IsValid(PLUGIN.newUpdate) and PLUGIN.newUpdate:IsVisible()) then
model:SetSkin(10)
elseif IsValid(PLUGIN.verdictCodes) and PLUGIN.verdictCodes:IsVisible() then
model:SetSkin(11)
elseif IsValid(PLUGIN.communicationCodes) and PLUGIN.communicationCodes:IsVisible() then
model:SetSkin(12)
elseif IsValid(PLUGIN.datafileInfo) and PLUGIN.datafileInfo:IsVisible() then
model:SetSkin(4)
elseif IsValid(PLUGIN.viewEntryLogs) and PLUGIN.viewEntryLogs:IsVisible() then
model:SetSkin(13)
elseif IsValid(PLUGIN.violationsTitleSubframe) and PLUGIN.violationsTitleSubframe:IsVisible() then
model:SetSkin(16)
else
model:SetSkin(0)
end
if (v.bodygroup) then
for k, v1 in pairs( v.bodygroup ) do
if (model:GetBodygroup(k) != v1) then
model:SetBodygroup(k, v1)
end
end
end
if (v.surpresslightning) then
render.SuppressEngineLighting(true)
end
render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
render.SetBlend(v.color.a/255)
model:DrawModel()
render.SetBlend(1)
render.SetColorModulation(1, 1, 1)
if (v.surpresslightning) then
render.SuppressEngineLighting(false)
end
elseif (v.type == "Sprite" and sprite) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
render.SetMaterial(sprite)
render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
elseif (v.type == "Quad" and v.draw_func) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
cam.Start3D2D(drawpos, ang, v.size)
v.draw_func( self )
cam.End3D2D()
end
end
end
SWEP.wRenderOrder = nil
function SWEP:DrawWorldModel()
if (self.ShowWorldModel == nil or self.ShowWorldModel) then
self:DrawModel()
end
if (!self.WElements) then return end
if (!self.wRenderOrder) then
self.wRenderOrder = {}
for k, v in pairs( self.WElements ) do
if (v.type == "Model") then
table.insert(self.wRenderOrder, 1, k)
elseif (v.type == "Sprite" or v.type == "Quad") then
table.insert(self.wRenderOrder, k)
end
end
end
local bone_ent
if (IsValid(self.Owner)) then
bone_ent = self.Owner
else
-- when the weapon is dropped
bone_ent = self
end
for _, name in pairs( self.wRenderOrder ) do
local v = self.WElements[name]
if (!v) then self.wRenderOrder = nil break end
if (v.hide) then continue end
local pos, ang
if (v.bone) then
pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
else
pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
end
if (!pos) then continue end
local model = v.modelEnt
local sprite = v.spriteMaterial
if (v.type == "Model" and IsValid(model)) then
model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
model:SetAngles(ang)
--model:SetModelScale(v.size)
local matrix = Matrix()
matrix:Scale(v.size)
model:EnableMatrix( "RenderMultiply", matrix )
if (v.material == "") then
model:SetMaterial("")
elseif (model:GetMaterial() != v.material) then
model:SetMaterial( v.material )
end
if IsValid(PLUGIN.updates) and PLUGIN.updates:IsVisible() then
model:SetSkin(3)
elseif IsValid(PLUGIN.viewLogs) and PLUGIN.viewLogs:IsVisible() then
model:SetSkin(5)
elseif IsValid(PLUGIN.viewLog) and PLUGIN.viewLog:IsVisible() then
model:SetSkin(6)
elseif IsValid(PLUGIN.editupdates) and PLUGIN.editupdates:IsVisible() then
model:SetSkin(7)
elseif (IsValid(PLUGIN.editUpdate) and PLUGIN.editUpdate:IsVisible()) or (IsValid(PLUGIN.newUpdate) and PLUGIN.newUpdate:IsVisible()) then
model:SetSkin(10)
elseif IsValid(PLUGIN.verdictCodes) and PLUGIN.verdictCodes:IsVisible() then
model:SetSkin(11)
elseif IsValid(PLUGIN.communicationCodes) and PLUGIN.communicationCodes:IsVisible() then
model:SetSkin(12)
elseif IsValid(PLUGIN.datafileInfo) and PLUGIN.datafileInfo:IsVisible() then
model:SetSkin(4)
elseif IsValid(PLUGIN.viewEntryLogs) and PLUGIN.viewEntryLogs:IsVisible() then
model:SetSkin(13)
elseif IsValid(PLUGIN.violationsTitleSubframe) and PLUGIN.violationsTitleSubframe:IsVisible() then
model:SetSkin(16)
else
model:SetSkin(0)
end
if (v.bodygroup) then
for k, v1 in pairs( v.bodygroup ) do
if (model:GetBodygroup(k) != v1) then
model:SetBodygroup(k, v1)
end
end
end
if (v.surpresslightning) then
render.SuppressEngineLighting(true)
end
render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
render.SetBlend(v.color.a/255)
model:DrawModel()
render.SetBlend(1)
render.SetColorModulation(1, 1, 1)
if (v.surpresslightning) then
render.SuppressEngineLighting(false)
end
elseif (v.type == "Sprite" and sprite) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
render.SetMaterial(sprite)
render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
elseif (v.type == "Quad" and v.draw_func) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
cam.Start3D2D(drawpos, ang, v.size)
v.draw_func( self )
cam.End3D2D()
end
end
end
function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
local bone, pos, ang
if (tab.rel and tab.rel != "") then
local v = basetab[tab.rel]
if (!v) then return end
pos, ang = self:GetBoneOrientation( basetab, v, ent )
if (!pos) then return end
pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
else
bone = ent:LookupBone(bone_override or tab.bone)
if (!bone) then return end
pos, ang = Vector(0,0,0), Angle(0,0,0)
local m = ent:GetBoneMatrix(bone)
if (m) then
pos, ang = m:GetTranslation(), m:GetAngles()
end
if (IsValid(self.Owner) and self.Owner:IsPlayer() and
ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
ang.r = -ang.r -- Fixes mirrored models
end
end
return pos, ang
end
function SWEP:CreateModels( tab )
if (!tab) then return end
for _, v in pairs( tab ) do
if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
if (IsValid(v.modelEnt)) then
v.modelEnt:SetPos(self:GetPos())
v.modelEnt:SetAngles(self:GetAngles())
v.modelEnt:SetParent(self)
v.modelEnt:SetNoDraw(true)
v.createdModel = v.model
else
v.modelEnt = nil
end
elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
local name = v.sprite.."-"
local params = { ["$basetexture"] = v.sprite }
-- make sure we create a unique name based on the selected options
local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
for _, j in pairs( tocheck ) do
if (v[j]) then
params["$"..j] = 1
name = name.."1"
else
name = name.."0"
end
end
v.createdSprite = v.sprite
v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
end
end
end
local allbones
local hasGarryFixedBoneScalingYet = false
function SWEP:UpdateBonePositions(vm)
if self.ViewModelBoneMods then
if (!vm:GetBoneCount()) then return end
-- !! WORKAROUND !! --
-- We need to check all model names :/
local loopthrough = self.ViewModelBoneMods
if (!hasGarryFixedBoneScalingYet) then
allbones = {}
for i=0, vm:GetBoneCount() do
local bonename = vm:GetBoneName(i)
if (self.ViewModelBoneMods[bonename]) then
allbones[bonename] = self.ViewModelBoneMods[bonename]
else
allbones[bonename] = {
scale = Vector(1,1,1),
pos = Vector(0,0,0),
angle = Angle(0,0,0)
}
end
end
loopthrough = allbones
end
-- !! ----------- !! --
for k, v in pairs( loopthrough ) do
local bone = vm:LookupBone(k)
if (!bone) then continue end
-- !! WORKAROUND !! --
local s = Vector(v.scale.x,v.scale.y,v.scale.z)
local p = Vector(v.pos.x,v.pos.y,v.pos.z)
local ms = Vector(1,1,1)
if (!hasGarryFixedBoneScalingYet) then
local cur = vm:GetBoneParent(bone)
while(cur >= 0) do
local pscale = loopthrough[vm:GetBoneName(cur)].scale
ms = ms * pscale
cur = vm:GetBoneParent(cur)
end
end
s = s * ms
-- !! ----------- !! --
if vm:GetManipulateBoneScale(bone) != s then
vm:ManipulateBoneScale( bone, s )
end
if vm:GetManipulateBoneAngles(bone) != v.angle then
vm:ManipulateBoneAngles( bone, v.angle )
end
if vm:GetManipulateBonePosition(bone) != p then
vm:ManipulateBonePosition( bone, p )
end
end
else
self:ResetBonePositions(vm)
end
end
function SWEP:ResetBonePositions(vm)
if (!vm:GetBoneCount()) then return end
for i=0, vm:GetBoneCount() do
vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
end
end
--luacheck: ignore 122
function table.FullCopy( tab )
if (!tab) then return nil end
local res = {}
for k, v in pairs( tab ) do
if (type(v) == "table") then
res[k] = table.FullCopy(v)
elseif (type(v) == "Vector") then
res[k] = Vector(v.x, v.y, v.z)
elseif (type(v) == "Angle") then
res[k] = Angle(v.p, v.y, v.r)
else
res[k] = v
end
end
return res
end
end
----------------------------------------------------
function SWEP:OnRemove()
end
function SWEP:Deploy()
--if !IsValid(self.Owner.C4s) then self.Owner.C4s = {} end
self.Weapon:SendWeaponAnim(ACT_SLAM_TRIPMINE_DRAW)
end
function SWEP:PrimaryAttack()
self:EmitSound( "UI/buttonclick.wav" )
self:SetNextPrimaryFire( CurTime()+2 )
if SERVER and IsFirstTimePredicted() then
if (PLUGIN:HasAccessToDatafile(self.Owner)) then
PLUGIN:Refresh(self.Owner)
else
self.Owner:NotifyLocalized("You do not have access to the datapad")
end
end
end
function SWEP:SecondaryAttack()
end
function SWEP:Holster()
if CLIENT and IsValid(self.Owner) then
local vm = self.Owner:GetViewModel()
if IsValid(vm) then
self:ResetBonePositions(vm)
end
end
return true
end
function SWEP:OnRemove()
self:Holster()
end

View File

@@ -0,0 +1,61 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ITEM.name = "Citizen Computer"
ITEM.uniqueID = "cit_computer"
ITEM.model = "models/willardnetworks/props/willard_computer.mdl"
ITEM.width = 2
ITEM.height = 2
ITEM.description = "A computer that can save notes and lock to users."
ITEM.category = "Technology"
ITEM.functions.Place = {
OnRun = function(itemTable)
local client = itemTable.player
local entity = ents.Create("ix_computer")
local trace = client:GetEyeTraceNoCursor()
if (trace.HitPos:Distance( client:GetShootPos() ) <= 192) and !client.CantPlace then
entity:SetPos(trace.HitPos + Vector( 0, 0, 17 ))
entity:Spawn()
entity:SetNWInt("owner", client:GetCharacter():GetID())
client.CantPlace = true
if itemTable:GetData("users") then
entity.users = itemTable:GetData("users")
end
if itemTable:GetData("notes") then
entity.notes = itemTable:GetData("notes")
end
if (IsValid(entity)) then
entity:SetAngles(Angle(0, client:EyeAngles().yaw + 180, 0))
end
ix.saveEnts:SaveEntity(entity)
timer.Simple(3, function()
if client then
client.CantPlace = false
end
end)
elseif client.CantPlace then
client:NotifyLocalized("You cannot place this right now!")
return false
else
client:NotifyLocalized("You cannot place it that far away!..")
return false
end
end
}

View File

@@ -0,0 +1,69 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ITEM.name = "Floppy Disk"
ITEM.model = "models/props/cs_office/computer_caseb_p9a.mdl"
ITEM.skin = 1
ITEM.width = 1
ITEM.height = 1
ITEM.description = "Disk storage composed of a thin and flexible disk of a magnetic storage, used for information load."
ITEM.category = "Technology"
function ITEM:GetName()
if self:GetData("customName", false) then
return self:GetData("customName", false)
end
return self.name
end
ITEM.functions.Place = {
name = "Insert Into Computer",
tip = "equipTip",
icon = "icon16/link_add.png",
OnRun = function(itemTable)
if (SERVER) then
local client = itemTable.player
PLUGIN:InsertDisk(client, itemTable)
return false
end
end,
OnCanRun = function(itemTable)
if IsValid(itemTable.entity) then return false end
end
}
function ITEM:OnTransferred(curInv, inventory)
if (SERVER) then
if self.computer and IsValid(self.computer) then
self.computer.hasDiskInserted = nil
end
end
end
ITEM.functions.Name = {
name = "Name Disk",
tip = "equipTip",
icon = "icon16/link_add.png",
OnRun = function(itemTable)
if (SERVER) then
local client = itemTable.player
if !client then return end
netstream.Start(client, "SetFloppyDiskName", itemTable:GetData("customName", false), itemTable.id, itemTable:GetData("password", false))
end
return false
end
}

View File

@@ -0,0 +1,62 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ITEM.name = "Medical Computer"
ITEM.uniqueID = "med_computer"
ITEM.model = "models/willardnetworks/props/willard_computer.mdl"
ITEM.skin = 1
ITEM.width = 2
ITEM.height = 2
ITEM.description = "A medical computer that can review medical files."
ITEM.category = "Technology"
ITEM.functions.Place = {
OnRun = function(itemTable)
local client = itemTable.player
local entity = ents.Create("ix_medical_computer")
local trace = client:GetEyeTraceNoCursor()
if (trace.HitPos:Distance( client:GetShootPos() ) <= 192) and !client.CantPlace then
entity:SetPos(trace.HitPos + Vector( 0, 0, 17 ))
entity:Spawn()
entity:SetNWInt("owner", client:GetCharacter():GetID())
client.CantPlace = true
if itemTable:GetData("users") then
entity.users = itemTable:GetData("users")
end
if itemTable:GetData("notes") then
entity.notes = itemTable:GetData("notes")
end
if (IsValid(entity)) then
entity:SetAngles(Angle(0, client:EyeAngles().yaw + 180, 0))
end
ix.saveEnts:SaveEntity(entity)
timer.Simple(3, function()
if client then
client.CantPlace = false
end
end)
elseif client.CantPlace then
client:NotifyLocalized("You cannot place this right now!")
return false
else
client:NotifyLocalized("You cannot place it that far away!..")
return false
end
end
}

View File

@@ -0,0 +1,19 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ITEM.name = "Civil Administration PDA"
ITEM.description = "Civil Administration PDA."
ITEM.model = "models/fruity/pda.mdl"
ITEM.class = "weapon_capda"
ITEM.weaponCategory = "pda"
ITEM.category = "Combine"
ITEM.width = 1
ITEM.height = 1
ITEM.KeepOnDeath = true

View File

@@ -0,0 +1,19 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ITEM.name = "Combine PDA"
ITEM.description = "A combine issued PDA made for local Civil Protection Officers."
ITEM.model = "models/fruity/tablet/tablet_sfm.mdl"
ITEM.class = "weapon_datapad"
ITEM.weaponCategory = "pda"
ITEM.category = "Combine"
ITEM.width = 1
ITEM.height = 1
ITEM.KeepOnDeath = true

View File

@@ -0,0 +1,61 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
LANGUAGE = {
TeamName = "PT-%s",
TeamStatus = "PT-%s %s",
TeamMemberStatus = "MEMBER",
TeamOwnerStatus = "LEADER",
tabProtectionTeam = "Protection Team",
tabCreateTeam = "CREATE PT",
tabJoinTeam = "JOIN PT",
tabLeaveTeam = "LEAVE PT",
TeamTransferOwner = "Transfer Lead",
TeamKickMember = "Kick Member",
TeamReassign = "Reassign Index",
CannotUseTeamCommands = "You cannot use PT commands!",
CannotPromoteTeamMembers = "You cannot promote PT members!",
CannotKickTeamMembers = "You cannot kick PT members!",
CannotReassignTeamIndex = "You cannot reassign PT index!",
NoCurrentTeam = "You are not apart of a PT!",
TargetNoCurrentTeam = "The person you are trying to promote is not apart of a PT!",
TargetNotSameTeam = "The person you are trying to promote is not apart of the same PT!",
TeamMustClamp = "You must provide a number between 1-99!",
TeamMustLeave = "You must leave your current PT before joining a new one!",
TeamAlreadyHasOwner = "There is already a PT lead!",
TeamAlreadyExists = "A PT with index '%s' already exists!",
TeamNonExistent = "PT '%s' doesn't exist!",
AlreadyHasTeam = "You are already apart of a PT!",
KickedFromTeam = "You've kicked %s from the PT.",
TeamCreated = "PT '%s' successfully created.",
TeamReassigned = "PT '%s' successfully reassigned to '%s'.",
TeamOwnerSet = "The new PT lead has been set to %s.",
TeamOwnerAssume = "You've assumed PT lead.",
JoinedTeam = "Successfully joined PT '%s'.",
LeftTeam = "Successfully left PT '%s'.",
cmdCreatePTDesc = "Enter the number index for your new Protection Team. (1-99)",
cmdReassignPTDesc = "Enter a new number index for your current Squad. (1-99)",
cmdPTCreate = "Create a Protection Team.",
cmdPTLeave = "Leave your Protection Team.",
cmdPTLead = "Promote a PT member to PT lead or assume the lead position.",
cmdPTKick = "Kick a PT member.",
cmdPTReassign = "Reassign PT number index.",
cmdPTJoin = "Join a Protection Team."
}

View File

@@ -0,0 +1,51 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
LANGUAGE = {
TeamOwnerStatus = "LÍDER",
tabProtectionTeam = "Equipo de Protección",
TeamMemberStatus = "MIEMBRO",
CannotUseTeamCommands = "¡No puedes usar comandos de EP!",
CannotReassignTeamIndex = "¡No puedes reasignar el índice del EP!",
tabJoinTeam = "UNIRSE A EP",
cmdCreatePTDesc = "Introduce el número de índice para tu Equipo de Protección. (1-99)",
TeamKickMember = "Expulsar Miembro",
NoCurrentTeam = "¡No eres parte de un EP!",
tabCreateTeam = "CREAR EQUIPO DE PROTECCIÓN",
TeamTransferOwner = "Transferir Liderazgo",
tabLeaveTeam = "SALIR DE UN EP",
CannotPromoteTeamMembers = "¡No puedes ascender a los miembros del EP!",
cmdReassignPTDesc = "Introduce un nuevo número de índice para tu Escuadrón actual. (1-99)",
CannotKickTeamMembers = "¡No puedes expulsar a miembros del EP!",
TeamMustClamp = "¡Debes introducir un número entre 1-99!",
TeamReassign = "Reasignar índice",
cmdPTCreate = "Crea un Equipo de Protección.",
cmdPTJoin = "Unirse a un Equipo de Protección.",
cmdPTLeave = "Salir de tu Equipo de Protección.",
AlreadyHasTeam = "¡Ya eres miembro de un EP!",
TeamOwnerSet = "El nuevo líder del EP se ha cambiado a %s.",
TeamNonExistent = "¡El EP '%s' no existe!",
LeftTeam = "Has salido con éxito del EP '%s'.",
TargetNotSameTeam = "¡La persona a la que intentas ascender no pertenece al mismo EP!",
TeamOwnerAssume = "Has asumido el liderazgo del EP.",
TeamReassigned = "EP '%s' reasignado con éxito a '%s'.",
JoinedTeam = "Incorporado con éxito al EP '%s'.",
cmdPTLead = "Ascender a un miembro del EP a líder del EP o asumir la posición de líder.",
TeamMustLeave = "¡Debes abandonar tu EP actual antes de entrar en uno nuevo!",
KickedFromTeam = "Has echado a %s del EP.",
cmdPTKick = "Expulsar a un miembro del EP.",
TargetNoCurrentTeam = "¡La persona que estás intentando ascender no es parte de un EP!",
TeamAlreadyHasOwner = "¡Ya hay un líder de EP!",
TeamAlreadyExists = "¡Un EP con índice '%s' ya existe!",
TeamCreated = "EP '%s' creado con éxito.",
TeamName = "EP-%s",
cmdPTReassign = "Reasignar índice numérico del EP.",
TeamStatus = "EP-%s %s"
}

View File

@@ -0,0 +1,55 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ix.permits = ix.permits or {}
ix.permits.list = ix.permits.list or {}
function ix.permits.add(permit)
permit = string.utf8lower(permit)
ix.permits.list[permit] = true
end
function ix.permits.get()
return ix.permits.list or {}
end
function ix.permits.isEnded(validUntil)
if os.time() > validUntil then
return true
end
return false
end
do
local CHAR = ix.meta.character
function CHAR:HasPermit(permit)
permit = string.utf8lower(permit)
local permits = self:GetGenericdata().permits or {}
if (permits[permit]) and permits[permit] == true then
return true
end
if (isnumber(permits[permit])) and !ix.permits.isEnded(permits[permit]) then
return true
end
return false
end
function CHAR:GetPermits()
return self:GetGenericdata().permits
end
end

View File

@@ -0,0 +1,51 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
do
local CHAR = ix.meta.character
function CHAR:SetPermitUnlimited(permit)
self:SetPermit(permit, true)
end
function CHAR:DisablePermit(permit)
self:SetPermit(permit, false)
end
function CHAR:SetPermit(permit, weeks)
-- If weeks is true then it would be unlimited
local endTimeStamp = !isbool(weeks) and (os.time() + 3600 * 24 * 7 * weeks) or true
permit = string.utf8lower(permit)
local genericdata = self:GetGenericdata()
if !genericdata.permits then
genericdata.permits = {}
end
if !istable(genericdata.permits) then
genericdata.permits = {}
end
if !weeks then
genericdata.permits[permit] = nil
else
genericdata.permits[permit] = endTimeStamp
end
if (!genericdata.permits[permit]) then
genericdata.permits[permit] = nil
end
self:SetGenericdata(genericdata)
end
end

View File

@@ -0,0 +1,44 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
netstream.Hook("SetDatafileLoyaltyPoints", function(target, amount)
netstream.Start("SetDatafileLoyaltyPointsServer", target, amount)
end)
netstream.Hook("OpenDatafileCl", function(table)
if !PLUGIN.contentSubframe then return end
if !IsValid(PLUGIN.contentSubframe) then return end
PLUGIN.file = table
if !PLUGIN.file or PLUGIN.file and istable(PLUGIN.file) and !PLUGIN.file.genericdata then
if !PLUGIN.file then return end
if istable(PLUGIN.file) and PLUGIN.file["charID"] then
if CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Basic Admin Commands") then
Derma_Query("Something went wrong with the datafile of this individual", "Do you want to reset the datafile of charID: "..PLUGIN.file["charID"].."?",
"Confirm Operation", function()
netstream.Start("ResetDatafileToDefault", PLUGIN.file["charID"])
end, "Cancel")
end
end
return
end
for _, v in pairs(PLUGIN.contentSubframe:GetChildren()) do
v:SetVisible(false)
end
PLUGIN.datafileInfo = vgui.Create("ixDatafileInfo", PLUGIN.contentSubframe)
PLUGIN.datafileFunctions = vgui.Create("ixDatafileFunctions", PLUGIN.contentSubframe)
end)

View File

@@ -0,0 +1,37 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
function PLUGIN:LoadFonts(font, genericFont)
surface.CreateFont( "DatapadTitle", {
font = "Open Sans Bold", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name
extended = false,
size = SScaleMin(32 / 3),
weight = 550,
antialias = true,
} )
end
netstream.Hook("OpenPDA", function(table, text)
if IsValid(PLUGIN.ixDatapad) then
PLUGIN.ixDatapad:Remove()
end
PLUGIN.updatelist = table
PLUGIN.ixDatapad = vgui.Create("ixDatafilePDA")
surface.PlaySound("willardnetworks/datapad/open.wav")
if (text != nil) then
PLUGIN.functions:SetVisible(false)
PLUGIN.searchProfiles = vgui.Create("ixDatapadSearchProfiles", PLUGIN.contentSubframe)
PLUGIN.searchEntry:SetValue(text)
PLUGIN.searchButton:DoClick()
end
end)

View File

@@ -0,0 +1,31 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PANEL = {}
function PANEL:Init()
self:SetSize(ScrW(), ScrH())
ix.gui.medicalComputer = self:Add("MedicalComputerBase")
end
function PANEL:Think()
if !IsValid(ix.gui.medicalComputer) then
self:Remove()
end
if IsValid(ix.gui.medicalComputer.functionsPanel) then
if IsValid(ix.gui.medicalComputer.functionsPanel.medicalButton) then
ix.gui.medicalComputer.functionsPanel.medicalButton:Remove()
end
end
end
vgui.Register("CitizenComputer", PANEL, "EditablePanel")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
PLUGIN.file = {}
ix.flag.Add("T", "Bypass PDA Transaction Logs.")
ix.config.Add("TransactionLogDaysDatafile", 14, "How many days to show transaction logs for.", nil, {
data = {min = 1, max = 31},
category = "Datafile"
})
ix.command.Add("SetDatafilePoints", {
description = "Set datafile loyalty points.",
adminOnly = true,
arguments = {
ix.type.character,
ix.type.number
},
OnRun = function(self, client, target, amount)
if (target) then
local genericData = target:GetGenericdata()
if genericData.socialCredits then
genericData.socialCredits = !genericData.combine and math.Clamp(amount, 0, 200) or amount
target:SetGenericdata(genericData)
target:Save()
end
client:NotifyLocalized("Set "..target.player:Name().."'s points to "..amount)
end
end
})
ix.command.Add("Datafile", {
description = "Open datafile as Overwatch or OTA.",
OnCheckAccess = function(self, client)
local faction = ix.faction.Get(client:Team())
if (faction.alwaysDatafile or client:GetCharacter():HasFlags("U")) then
return true
elseif (client:HasActiveCombineSuit() and client:GetCharacter():GetInventory():HasItem("pda")) then
return true
end
return false
end,
arguments = {
ix.type.string
},
OnRun = function(self, client, text)
if (self:OnCheckAccess(client)) then
PLUGIN:Refresh(client, text)
else
client:NotifyLocalized("You do not have access to the datapad")
end
end
})
ix.char.RegisterVar("genericdata", {
field = "genericdata",
fieldType = ix.type.text,
default = {},
bNoDisplay = true,
isLocal = true,
OnSet = function(self, value)
local client = self:GetPlayer()
if (IsValid(client)) then
self.vars.genericdata = value
net.Start("ixCharacterVarChanged")
net.WriteUInt(self:GetID(), 32)
net.WriteString("genericdata")
net.WriteType(self.vars.genericdata)
net.Send(client)
end
end,
OnGet = function(self, default)
local genericdata = self.vars.genericdata
return genericdata
end,
OnAdjust = function(self, client, data, value, newData)
newData.genericdata = value
end
})
ix.char.RegisterVar("datafilelogs", {
field = "datafilelogs",
fieldType = ix.type.text,
default = {},
bNoDisplay = true,
bNoNetworking = true,
})
ix.char.RegisterVar("datafileviolations", {
field = "datafileviolations",
fieldType = ix.type.text,
default = {},
bNoDisplay = true,
bNoNetworking = true,
})
ix.char.RegisterVar("datafilemedicalrecords", {
field = "datafilemedicalrecords",
fieldType = ix.type.text,
default = {},
bNoDisplay = true,
bNoNetworking = true,
})
ix.char.RegisterVar("datapadnotes", {
field = "datapadnotes",
fieldType = ix.type.text,
default = "",
bNoDisplay = true,
bNoNetworking = true,
OnSet = function(self, value)
self.vars.datapadnotes = value
end,
OnGet = function(self, default)
local datapadnotes = self.vars.datapadnotes
return datapadnotes
end,
OnAdjust = function(self, client, data, value, newData)
newData.datapadnotes = value
end
})

View File

@@ -0,0 +1,15 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
PLUGIN.updatelist = {}
ix.util.IncludeDir("ixhl2rp/plugins/combineutilities/pda/derma", true)

View File

@@ -0,0 +1,530 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
local datafields = {"genericdata", "datafilelogs", "datafileviolations", "datafilemedicalrecords"}
function PLUGIN:SendFile(client, file)
timer.Simple(0.05, function()
netstream.Start(client, "OpenDatafileCl", file)
end)
end
-- Include new required data to datafiles of old characters
function PLUGIN:UpdateOldVortData(character, genericdata)
if (!character or !istable(genericdata)) then return end
genericdata.collarID = character:GetCollarID() or "N/A"
genericdata.cohesionPoints = genericdata.socialCredits or 0
genericdata.cohesionPointsDate = ix.config.Get("day").."/"..ix.config.Get("month").."/"..ix.config.Get("year")
genericdata.nulled = "INACTIVE"
genericdata.cid = "N/A"
genericdata.name = nil
if (character:HasFlags("N") or character:GetBackground() == "Collaborator") then
genericdata.nulled = "ACTIVE"
end
for _, v in pairs(character:GetInventory():GetItems()) do
if (table.HasValue({"Vortigaunt Collar", "Vortigaunt Collar (fake)"}, v.name) and v:GetData("equip") == true) then
if (v:GetData("collarID", nil) and v:GetData("sterilizedCredits", nil)) then
genericdata.cohesionPoints = v:GetData("sterilizedCredits", 0)
end
end
end
character:SetGenericdata(genericdata)
character:Save()
character:GetPlayer():Notify("New format successfully applied to your datafile.")
end
-- Search the collarID through the database
function PLUGIN:LookUpCollarID(client, id, bNotify)
if (!client or !id) then return end
id = string.sub(id, 2)
local query = mysql:Select("ix_characters")
query:Select("name")
query:Select("faction")
query:Select("id")
query:Select("collarID")
query:Select("background")
query:Where("collarID", id)
query:Where("schema", Schema and Schema.folder or "helix")
query:Callback(function(result)
if (!istable(result) or #result == 0) then
return
end
local resultFactionString = result[1].faction
if (resultFactionString != "vortigaunt") then
return
end
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:Where("id", result[1].id)
dataSelect:WhereIn("key", datafields)
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
local file = {}
for _, v in ipairs(dataSelectResult) do
file[v.key] = util.JSONToTable(v.data or "")
file["charID"] = result[1].id
if (v.key == "genericdata") then
if file[v.key].name != result[1].name then
file[v.key].name = result[1].name
local updateQuery = mysql:Update("ix_characters_data")
updateQuery:Update("data", util.TableToJSON(file[v.key]) or "")
updateQuery:Where("id", result[1].id)
updateQuery:Where("key", "genericdata")
updateQuery:Execute()
end
end
end
if (bNotify) then
local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())
ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset:") .. " #" .. result[1].collarID)
end
self:SendFile(client, file)
end)
dataSelect:Execute()
end)
query:Execute()
end
function PLUGIN:RefreshDatafile(client, id, bIsLocal, bCachedID, bNotify)
if !client then return end
if (client:Team() == FACTION_SERVERADMIN) then
bNotify = false
end
--If the player is trying to view his/her own datafile
if (bIsLocal) then
local character = client:GetCharacter()
local file = {}
file["genericdata"] = character:GetGenericdata()
file["datafileviolations"] = character:GetDatafileviolations()
file["datafilemedicalrecords"] = character:GetDatafilemedicalrecords()
file["datafilelogs"] = character:GetDatafilelogs()
file["charID"] = character:GetID()
if character:IsVortigaunt() and !file["genericdata"].cohesionPoints then
self:UpdateOldVortData(character, file["genericdata"])
end
self:SendFile(client, file)
return
end
local target = false
if (bCachedID) then
if isnumber(tonumber(id)) then
if ix.char.loaded[id] then
target = ix.char.loaded[id]
end
end
end
if !target then
-- Check for cached characters
if (tonumber(id) != nil and string.utf8len(tostring(id)) <= 5) then
-- id to cid comparison
for _, v in pairs(ix.char.loaded) do
local cid = v.GetCid and v:GetCid()
local genericdata = v:GetGenericdata()
if (v:IsVortigaunt() and v:GetCid() == id and genericdata.cid == "N/A") then return end
if (cid and id) then
if (tostring(cid) == id) then
target = v
break
end
end
end
elseif (id != nil and string.sub(id, 1, 1) == "!") then
id = string.sub(id, 2)
for _, v in pairs(ix.char.loaded) do
if (v:IsVortigaunt() and v:GetCollarID() == id) then
target = v
break
end
end
else
-- id to name comparison
for _, v in pairs(ix.char.loaded) do
local genericdata = v:GetGenericdata()
if string.find(v:GetName(), id) then
if (v:IsVortigaunt() and genericdata.cid == "N/A") then return end
target = v
break
end
end
end
end
-- Make sure further code isn't ran
if target then
local file = {}
file["genericdata"] = target:GetGenericdata()
file["datafileviolations"] = target:GetDatafileviolations()
file["datafilemedicalrecords"] = target:GetDatafilemedicalrecords()
file["datafilelogs"] = target:GetDatafilelogs()
file["charID"] = target:GetID()
if (target:IsVortigaunt() and !file["genericdata"].cohesionPoints) then
self:UpdateOldVortData(target, file["genericdata"])
end
if (bNotify) then
local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())
if (target:IsVortigaunt()) then
if (file["genericdata"].cid == "N/A" and file["genericdata"].collarID != "N/A") then
ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset collar:") .. " #" .. target:GetCollarID())
elseif (file["genericdata"].cid == "N/A" and file["genericdata"].collarID == "N/A") then
ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset collar:") .. " #" .. target:GetFakeCollarID())
else
ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset identification card:") .. " #" .. file["genericdata"].cid)
end
else
ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on '" .. string.upper(target:GetName()) .. "', #" .. target:GetCid())
end
end
self:SendFile(client, file)
return
end
-- If no cached character, search in datafile
if (tonumber(id) != nil and string.utf8len( id ) <= 5) then
local query = mysql:Select("ix_characters")
query:Select("name")
query:Select("faction")
query:Select("id")
query:Select("cid")
query:Select("background")
query:Where("cid", id)
query:Where("schema", Schema and Schema.folder or "helix")
query:Callback(function(result)
if (!istable(result) or #result == 0) then
return
end
local resultFactionString = result[1].faction
if (resultFactionString == "overwatch" and client:Team() != FACTION_OVERWATCH) then
client:NotifyLocalized("You do not have access to this datafile!")
return false
end
if (resultFactionString == "ota" or resultFactionString == "administrator" or resultFactionString == "guard") then
local character = client:GetCharacter()
if (client:Team() != FACTION_OVERWATCH and client:Team() != FACTION_OTA and character:GetClass() != FACTION_MCP and client:Team() != CLASS_CP_CMD and character:GetClass() != CLASS_CP_CPT and character:GetClass() != CLASS_CP_RL) then
if client:Team() != FACTION_ADMIN then
client:NotifyLocalized("You do not have access to this datafile!")
return false
end
end
end
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:Where("id", result[1].id)
dataSelect:WhereIn("key", datafields)
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
local file = {}
for _, v in ipairs(dataSelectResult) do
file[v.key] = util.JSONToTable(v.data or "")
file["charID"] = result[1].id
if (v.key == "genericdata") then
if (resultFactionString == "vortigaunt" and util.JSONToTable(v.data).cid == "N/A") then return end
if file[v.key].name != result[1].name then
file[v.key].name = result[1].name
local updateQuery = mysql:Update("ix_characters_data")
updateQuery:Update("data", util.TableToJSON(file[v.key]) or "")
updateQuery:Where("id", result[1].id)
updateQuery:Where("key", "genericdata")
updateQuery:Execute()
end
end
end
if (bNotify) then
local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())
ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on '" .. string.upper(result[1].name) .. "', #" .. result[1].cid)
end
self:SendFile(client, file)
end)
dataSelect:Execute()
end)
query:Execute()
else
if (string.sub(id, 1, 1) == "!") then
self:LookUpCollarID(client, id, bNotify)
end
local query = mysql:Select("ix_characters")
query:Select("id")
query:Select("name")
query:Select("faction")
query:Select("background")
query:Select("cid")
query:WhereLike("name", id)
query:Where("schema", Schema and Schema.folder or "helix")
query:Callback(function(result)
if (!istable(result) or #result == 0) then
return
end
local resultFactionString = result[1].faction
if (resultFactionString == "overwatch" and client:Team() != FACTION_OVERWATCH) then
client:NotifyLocalized("You do not have access to this datafile!")
return false
end
if (resultFactionString == "ota" or resultFactionString == "administrator" or resultFactionString == "guard") then
local character = client:GetCharacter()
if (client:Team() != FACTION_OVERWATCH and client:Team() != FACTION_OTA and character:GetClass() != FACTION_MCP and client:Team() != CLASS_CP_CMD and character:GetClass() != CLASS_CP_CPT and character:GetClass() != CLASS_CP_RL) then
if client:Team() != FACTION_ADMIN then
client:NotifyLocalized("You do not have access to this datafile!")
return false
end
end
end
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:Where("id", result[1].id)
dataSelect:WhereIn("key", datafields)
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
local file = {}
for _, v in ipairs(dataSelectResult) do
file[v.key] = util.JSONToTable(v.data or "")
file["charID"] = result[1].id
if (v.key == "genericdata") then
if (resultFactionString == "vortigaunt" and util.JSONToTable(v.data).cid == "N/A") then return end
if file[v.key].name != result[1].name then
file[v.key].name = result[1].name
local updateQuery = mysql:Update("ix_characters_data")
updateQuery:Update("data", util.TableToJSON(file[v.key]) or "")
updateQuery:Where("id", result[1].id)
updateQuery:Where("key", "genericdata")
updateQuery:Execute()
end
end
end
if (bNotify) then
local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())
ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on '" .. string.upper(result[1].name) .. "', #" .. result[1].cid)
end
self:SendFile(client, file)
end)
dataSelect:Execute()
end)
query:Execute()
end
end
netstream.Hook("RequestCIDCreditsDatafile", function(client, cid)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
cid = Schema:ZeroNumber(cid, 5)
local housing = ix.plugin.list["housing"]
if !housing then return end
housing:LookUpCardItemIDByCID(tostring(cid), function(result)
local idCardID = result[1].idcard or false
if !result then return end
if !ix.item.instances[idCardID] then
ix.item.LoadItemByID(idCardID, false, function(item)
if !item then return end
local credits = item:GetData("credits", 0)
netstream.Start(client, "UpdateDatafileCredits", credits)
end)
else
local credits = ix.item.instances[idCardID]:GetData("credits", 0)
netstream.Start(client, "UpdateDatafileCredits", credits)
end
end)
end)
netstream.Hook("ixDatafileRequestTransactionLogs", function(client, cid)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
cid = Schema:ZeroNumber(cid, 5)
ix.plugin.list.cid:SelectTransactions(client, "cid", cid, ix.config.Get("TransactionLogDaysDatafile", 14), nil, function(result)
netstream.Start(client, "ixDatafileReplyTransactionLogs", result)
end)
end)
netstream.Hook("TerminalReportCrime", function(client, name, cid, text, activeTerminal)
if !text or !name or !cid then return false end
if string.len(text) <= 0 then client:Notify("You cannot send an empty crime report.") return end
if cid != activeTerminal.activeCID then
return false
end
local timestamp = ix.date.GetFormatted("%d.%m.%Y")
local queryObj = mysql:Insert("ix_crimereports")
queryObj:Insert("message_poster", name)
queryObj:Insert("message_text", text)
queryObj:Insert("message_date", timestamp)
queryObj:Insert("message_cid", cid)
queryObj:Execute()
ix.combineNotify:AddImportantNotification("WRN:// Crime report submitted by " .. name .. " #" .. cid, Color(0, 150, 255), client, activeTerminal:GetPos())
end)
function PLUGIN:GetCrimeReports(client, bArchived, bResolved, curCollect)
local query = mysql:Select("ix_crimereports")
query:Select("message_id")
query:Select("message_text")
query:Select("message_date")
query:Select("message_poster")
query:Select("message_cid")
query:Callback(function(result)
if (!istable(result) or #result == 0) then
return
end
local toSort = {}
for key, _ in pairs(result) do
local posterIsTable = string.find(result[key].message_poster, "{")
if posterIsTable then result[key].message_poster = util.JSONToTable(result[key].message_poster) end
if posterIsTable or (bArchived or bResolved) then
if bArchived and result[key].message_poster.archived then
toSort[#toSort + 1] = result[key]
continue
end
if bResolved and result[key].message_poster.resolved then
toSort[#toSort + 1] = result[key]
continue
end
continue
end
toSort[#toSort + 1] = result[key]
end
local toSend = {}
for i = curCollect, curCollect + 5 do
if toSort[i] then
toSend[#toSend + 1] = toSort[i]
end
end
netstream.Start(client, "ReplyCrimeReports", toSend)
end)
query:Execute()
end
netstream.Hook("GetCrimeReports", function(client, bArchived, bResolved, curCollect)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
PLUGIN:GetCrimeReports(client, bArchived, bResolved, curCollect)
end)
netstream.Hook("DeleteCrimeReport", function(client, key, bDatapad, lastUsedTab, curCollect)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local queryObj = mysql:Delete("ix_crimereports")
queryObj:Where("message_id", key)
queryObj:Execute()
PLUGIN:GetCrimeReports(client, (lastUsedTab == "archived" and true or false), (lastUsedTab == "resolved" and true or false), curCollect)
end)
netstream.Hook("ResolveCrimeReport", function(client, key, poster, bUnResolve, lastUsedTab, curCollect)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Crime Report ID #" .. key .. " marked as " .. (bUnResolve and "unresolved" or "resolved") .. " by " .. string.upper(author), Color(171, 222, 47))
local queryObj = mysql:Update("ix_crimereports")
queryObj:Where("message_id", key)
queryObj:Update("message_poster", util.TableToJSON({poster = (istable(poster) and poster.poster or poster), resolved = (!bUnResolve and true or false), archived = (istable(poster) and poster.archived or false)}))
queryObj:Execute()
PLUGIN:GetCrimeReports(client, (lastUsedTab == "archived" and true or false), (lastUsedTab == "resolved" and true or false), curCollect)
end)
netstream.Hook("ArchiveCrimeReport", function(client, key, poster, bUnArchive, lastUsedTab, curCollect)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Crime Report ID #" .. key .. (bUnArchive and " unarchived" or " archived") .. " by " .. string.upper(author), Color(171, 222, 47))
local queryObj = mysql:Update("ix_crimereports")
queryObj:Where("message_id", key)
queryObj:Update("message_poster", util.TableToJSON({poster = (istable(poster) and poster.poster or poster), resolved = (istable(poster) and poster.resolved or false), archived = (!bUnArchive and true or false)}))
queryObj:Execute()
PLUGIN:GetCrimeReports(client, (lastUsedTab == "archived" and true or false), (lastUsedTab == "resolved" and true or false), curCollect)
end)
netstream.Hook("ResetDatafileToDefault", function(client, charID)
if !CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands") then return end
local character = ix.char.loaded[charID]
if !character then
client:NotifyLocalized("The owner of the character needs to be online for the reset to work.")
return
end
local player = character:GetPlayer()
if !player then return end
PLUGIN:CreateDatafile(player)
end)

View File

@@ -0,0 +1,883 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
function PLUGIN:DatabaseConnected()
local query = mysql:Create("ix_datapad")
query:Create("update_id", "INT(11) UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("update_text", "TEXT")
query:Create("update_date", "TEXT")
query:Create("update_poster", "TEXT")
query:PrimaryKey("update_id")
query:Execute()
query = mysql:Create("ix_comgroupmessages")
query:Create("message_id", "INT(11) UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("message_text", "TEXT")
query:Create("message_date", "TEXT")
query:Create("message_poster", "TEXT")
query:Create("message_groupid", "TEXT")
query:PrimaryKey("message_id")
query:Execute()
query = mysql:Create("ix_comgroupreplies")
query:Create("reply_id", "INT(11) UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("reply_text", "TEXT")
query:Create("reply_date", "TEXT")
query:Create("reply_poster", "TEXT")
query:Create("reply_parent", "TEXT")
query:Create("reply_groupid", "TEXT")
query:PrimaryKey("reply_id")
query:Execute()
query = mysql:Create("ix_camessaging")
query:Create("message_id", "INT(11) UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("message_text", "TEXT")
query:Create("message_date", "TEXT")
query:Create("message_poster", "TEXT")
query:Create("message_cid", "TEXT")
query:Create("message_reply", "TEXT")
query:PrimaryKey("message_id")
query:Execute()
query = mysql:Create("ix_crimereports")
query:Create("message_id", "INT(11) UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("message_text", "TEXT")
query:Create("message_date", "TEXT")
query:Create("message_poster", "TEXT")
query:Create("message_cid", "TEXT")
query:PrimaryKey("message_id")
query:Execute()
end
function PLUGIN:HasAccessToDatafile(client)
if !client or client and !IsValid(client) then return false end
local faction = ix.faction.Get(client:Team())
if (faction.alwaysDatafile or client:GetCharacter():HasFlags("U")) then
return true
elseif (client:HasActiveCombineSuit() or faction.allowDatafile) then
if (client:GetCharacter():GetInventory():HasItem("pda") or client:GetActiveWeapon():GetClass() == "weapon_datapad") then
return true
end
end
end
function PLUGIN:GetUpdates(client)
local query = mysql:Select("ix_datapad")
query:Select("update_id")
query:Select("update_text")
query:Select("update_date")
query:Select("update_poster")
query:Callback(function(result)
if (!istable(result)) then
return
end
if (!table.IsEmpty(PLUGIN.updatelist)) then
table.Empty(PLUGIN.updatelist)
end
PLUGIN.updatelist = result
end)
query:Execute()
self:GetActivePermits(client)
end
function PLUGIN:Refresh(client, text)
PLUGIN:GetUpdates(client)
timer.Simple(0.05, function()
netstream.Start(client, "OpenPDA", PLUGIN.updatelist, text)
end)
end
function PLUGIN:GetConsoleUpdates(client)
PLUGIN:GetUpdates(client)
end
function PLUGIN:CharacterVarChanged(character, key, oldValue, value)
local genericdata = character:GetGenericdata()
if (key == "name" and genericdata) then
genericdata.name = value
character:SetGenericdata(genericdata)
if (IsValid(character:GetPlayer())) then
character:Save()
end
end
end
netstream.Hook("ClearArchivedCrimeReports", function(client)
local character = client:GetCharacter()
if (!character:IsCombine()) then
return client:NotifyLocalized("Only combine can clear crime reports.")
elseif !client:IsCombineRankAbove("i1") then
return client:NotifyLocalized("Your rank must be above i1 to clear crime reports.")
end
local query = mysql:Select("ix_crimereports")
query:Select("message_id")
query:Select("message_text")
query:Select("message_date")
query:Select("message_poster")
query:Select("message_cid")
query:Callback(function(result)
if (!istable(result) or #result == 0) then
return
end
local newMessages = 0
local clearedMessages = 0
for _, v in pairs(result) do
local msgPoster = util.JSONToTable(v["message_poster"])
local isArchived = msgPoster["archived"]
if !isArchived then continue end
local date = v["message_date"]
local messageDay = date[1] != "0" and date[1] .. date[2] .. "d" or date[2] .. "d"
local messageMonth = date[4] != "0" and date[4] .. date[5] .. "m" or date[5] .. "m"
local messageYear = date[7] .. date[8] .. date[9] .. date[10] .. "y"
local totalMessageTime = ix.util.GetStringTime(messageDay .. messageMonth .. messageYear)
local currentDay = ix.date.GetFormatted("%d")[1] != "0" and ix.date.GetFormatted("%d")[1] .. ix.date.GetFormatted("%d")[2] .. "d" or ix.date.GetFormatted("%d")[2] .. "d"
local currentMonth = ix.date.GetFormatted("%m") != "0" and ix.date.GetFormatted("%m")[1] .. ix.date.GetFormatted("%m")[2] .. "m" or ix.date.GetFormatted("%m")[2] .. "m"
local currentYear = ix.date.GetFormatted("%Y") .. "y"
local currentTotalTime = ix.util.GetStringTime(currentDay .. currentMonth .. currentYear)
if (currentTotalTime - totalMessageTime) < (ix.config.Get("crimeReportArchiveTime", 1) * 604800) then
newMessages = newMessages + 1
continue
end
local queryObj = mysql:Delete("ix_crimereports")
queryObj:Where("message_id", v["message_id"])
queryObj:Execute()
clearedMessages = clearedMessages + 1
end
client:NotifyLocalized(clearedMessages > 0 and "Successfully cleared " .. clearedMessages .. " archived crime reports. " .. "There are " .. newMessages .. " new archived crime reports that can't be cleared yet." or newMessages and "All archived reports are not older than " .. ix.config.Get("crimeReportArchiveTime", 1) .. " week(s)" or "No archived crime reports found.")
end)
query:Execute()
end)
netstream.Hook("AddUpdate", function(client, text)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("LOG:// Retrieving updated Overwatch Datafile update Manifest")
timer.Simple(1, function()
ix.combineNotify:AddNotification("NTC:// New Datafile Update published by " .. string.upper(author), Color(171, 222, 47))
end)
local timestamp = os.date( "%d.%m.%Y" )
local queryObj = mysql:Insert("ix_datapad")
queryObj:Insert("update_text", text)
queryObj:Insert("update_date", timestamp)
queryObj:Insert("update_poster", client:Name())
queryObj:Execute()
PLUGIN:Refresh(client)
end)
netstream.Hook("RemoveUpdate", function(client, id)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("LOG:// Retrieving updated Overwatch Datafile update Manifest")
timer.Simple(1, function()
ix.combineNotify:AddNotification("NTC:// Datafile Update ID #" .. id .. " deleted by " .. string.upper(author), Color(171, 222, 47))
end)
local queryObj = mysql:Delete("ix_datapad")
queryObj:Where("update_id", id)
queryObj:Execute()
PLUGIN:Refresh(client)
end)
netstream.Hook("EditUpdate", function(client, id, newText)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("LOG:// Retrieving updated Overwatch Datafile update Manifest")
timer.Simple(1, function()
ix.combineNotify:AddNotification("NTC:// Datafile Update ID #" .. id .. " updated by " .. string.upper(author), Color(171, 222, 47))
end)
local queryObj = mysql:Update("ix_datapad")
queryObj:Where("update_id", id)
queryObj:Update("update_text", newText)
queryObj:Execute()
PLUGIN:Refresh(client)
end)
netstream.Hook("SetDatafileLoyaltyPointsServer", function(client, target, amount)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local genericData = target:GetCharacter():GetGenericdata()
if (genericData.socialCredits) then
genericData.socialCredits = !genericData.combine and math.Clamp(amount, 0, 200) or amount
target:GetCharacter():SetGenericdata(genericData)
target:GetCharacter():Save()
end
end)
function PLUGIN:GetActiveShopPermits(client, appID)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local dataSelect = mysql:Select("ix_apartments_"..game.GetMap())
dataSelect:Where("app_id", appID)
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
for _, v in ipairs(dataSelectResult) do
local data = util.JSONToTable(v.app_permits)
if data and !table.IsEmpty(data) then
netstream.Start(client, "CreateActiveShopPermitsDatapad", data)
end
end
end)
dataSelect:Execute()
end
function PLUGIN:GetActivePermits(client)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:WhereIn("key", "genericdata")
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
local people = {}
for _, v in ipairs(dataSelectResult) do
local data = util.JSONToTable(v.data)
if data and data.permits and !table.IsEmpty(data.permits) then
for k2, v2 in pairs(data.permits) do
if isnumber(v2) and v2 <= os.time() then
data.permits[k2] = nil
end
end
if !table.IsEmpty(data.permits) then
people[v.id] = data
end
end
end
netstream.Start(client, "CreateActivePermitsDatapad", people)
end)
dataSelect:Execute()
end
netstream.Hook("GetActiveShopPermitsDatapad", function(client, appID)
PLUGIN:GetActiveShopPermits(client, appID)
end)
netstream.Hook("ToggleShopPermitDatapad", function(client, permit, bValue, appID)
local housing = ix.plugin.Get("housing")
if !housing then return end
if housing.apartments[appID].type != "shop" then return client:NotifyLocalized("It's not a shop!") end
housing.apartments[appID].permits[permit] = bValue
housing:UpdateApartment(appID)
housing:HandleShopPermitUpdate(appID, permit)
end)
netstream.Hook("GetActivePermitsDatapad", function(client)
PLUGIN:GetActivePermits(client)
end)
util.AddNetworkString("CreateActiveWagesDatapad")
function PLUGIN:GetActiveWages(client, curCollect)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:WhereIn("key", "genericdata")
dataSelect:Limit(5)
dataSelect:Offset(curCollect)
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then return end
local people = {}
local loyalists = {}
for _, v in ipairs(dataSelectResult) do
if !v.data then continue end
local data = util.JSONToTable(v.data)
if !data then continue end
local wages = data.wages and tonumber(data.wages)
if isnumber(wages) and wages > 0 then
people[v.id] = data
end
local socialCredits = data.socialCredits and tonumber(data.socialCredits)
local loyaltyStatus = data.loyaltyStatus and string.lower(data.loyaltyStatus)
if !data.socialCredits and !data.loyaltyStatus then continue end
if isnumber(socialCredits) and socialCredits >= 175 then
loyalists[v.id] = data
end
if isstring(loyaltyStatus) and loyaltyStatus != "none" then
loyalists[v.id] = data
end
end
net.Start("CreateActiveWagesDatapad")
net.WriteTable(people)
net.WriteTable(loyalists)
net.Send(client)
end)
dataSelect:Execute()
end
netstream.Hook("GetActiveWagesDatapad", function(client, curCollect)
PLUGIN:GetActiveWages(client, curCollect)
end)
netstream.Hook("RemovePermitDatapad", function(client, genericdata, loggedAction)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
if (loggedAction != nil) then
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' " .. (loggedAction == "permit" and "Datafile Permit" or loggedAction and "Additional Wages" or "Loyalty Status") .. " revoked by " .. string.upper(author), Color(171, 222, 47))
end
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetGenericdata(genericdata)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "genericdata")
queryObj:Update("data", util.TableToJSON(genericdata))
queryObj:Execute()
end)
netstream.Hook("UpdateDatafileLogs", function(client, id, logs, key, subject)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
if (!client:IsCombineRankAbove("RL") and !client:GetCharacter():HasFlags("L")) then
client:Notify("You cannot remove this log because you are not high enough rank or you are not wearing your combine suit!")
return false
end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(subject) .. "' Datafile log removed by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[id]
if (cachedCharacter) then
cachedCharacter:SetDatafilelogs(logs)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", id)
queryObj:Where("key", "datafilelogs")
queryObj:Update("data", util.TableToJSON(logs))
queryObj:Execute()
end)
netstream.Hook("UpdateDatafileMedical", function(client, id, logs, subject, isFromCMUPDA)
if (!PLUGIN:HasAccessToDatafile(client) and !isFromCMUPDA) then return end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(subject) .. "' Datafile 'MEDICAL' entry removed by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[id]
if (cachedCharacter) then
cachedCharacter:SetDatafilemedicalrecords(logs)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", id)
queryObj:Where("key", "datafilemedicalrecords")
queryObj:Update("data", util.TableToJSON(logs))
queryObj:Execute()
end)
netstream.Hook("UpdateDatafileViolations", function(client, id, logs, subject)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(subject) .. "' Datafile 'VIOLATION' entry removed by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[id]
if (cachedCharacter) then
cachedCharacter:SetDatafileviolations(logs)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", id)
queryObj:Where("key", "datafileviolations")
queryObj:Update("data", util.TableToJSON(logs))
queryObj:Execute()
end)
netstream.Hook("DatafilePromoteDemote", function(client, id, name)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local cachedCharacter = ix.char.loaded[id]
if (cachedCharacter) then
cachedCharacter:SetName(name)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
return
end
end
local queryObj = mysql:Update("ix_characters")
queryObj:Where("id", id)
queryObj:Update("name", name)
queryObj:Execute()
end)
function PLUGIN:CreateDatafile(client)
if (client:IsValid()) then
local character = client:GetCharacter()
local geneticAge = character:GetAge() or "N/A"
local geneticHeight = character:GetHeight() or "N/A"
local geneticEyecolor = character:GetEyeColor() or "N/A"
local standardCredits = 50
local designatedStatus = "N/A"
local anticitizen = false
if (string.utf8lower(character:GetBackground()) == "supporter citizen") then
standardCredits = 60
elseif (string.utf8lower(character:GetBackground()) == "outcast") then
standardCredits = 35
elseif (character:GetFaction() == FACTION_CP) then
standardCredits = 0
end
local genericData
if character:IsVortigaunt() then
genericData = {
id = character:GetID(),
cid = "N/A",
collarID = character:GetCollarID() or "N/A",
cohesionPoints = 0,
cohesionPointsDate = os.date("%d/%m/%Y"),
nulled = "INACTIVE",
geneticDesc = geneticAge .." | ".. geneticHeight,
occupation = "N/A",
occupationDate = os.date("%d/%m/%Y"),
designatedStatus = designatedStatus,
designatedStatusDate = os.date("%d/%m/%Y"),
permits = {},
bol = false,
anticitizen = anticitizen,
combine = false,
loyaltyStatus = "NONE",
wages = 0,
bypassCommunion = false,
housing = false,
shop = false,
}
if character:GetBackground() == "Collaborator" then
genericData.cid = character:GetCid()
end
else
genericData = {
id = character:GetID(),
name = character:GetName(),
cid = character:GetCid() or "N/A",
socialCredits = standardCredits,
socialCreditsDate = os.time(),
geneticDesc = geneticAge.." | "..geneticHeight.." | "..geneticEyecolor.." EYES",
occupation = "N/A",
occupationDate = os.date("%d/%m/%Y"),
designatedStatus = designatedStatus,
designatedStatusDate = os.date("%d/%m/%Y"),
permits = {},
bol = false,
anticitizen = anticitizen,
combine = false,
loyaltyStatus = "NONE",
wages = 0,
bypassCommunion = false,
housing = false,
shop = false,
}
end
if ix.faction.Get(client:Team()).isCombineFaction then
genericData.combine = true
end
if client:IsDispatch() then
genericData.combine = "overwatch"
end
local Timestamp = os.time()
local defaultLogs = {
[1] = {
text = "TRANSFERRED TO DISTRICT",
date = os.date( "%H:%M:%S - %d/%m/%Y" , Timestamp ),
poster = "Overwatch",
},
}
local defaultViolations = {}
local defaultMedicalRecords = {}
character:SetGenericdata(genericData)
character:SetDatafilelogs(defaultLogs)
character:SetDatafileviolations(defaultViolations)
character:SetDatafilemedicalrecords(defaultMedicalRecords)
character:SetHasDatafile(true)
character:Save()
end
end
netstream.Hook("OpenDatafile", function(client, id, bIsLocal)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
PLUGIN:RefreshDatafile(client, id, bIsLocal, nil, true)
end)
function PLUGIN:EditDatafile(client, genericdata, bBypass, bNoRefresh, action)
if (!bBypass and !PLUGIN:HasAccessToDatafile(client)) then return end
if (action) then
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' " .. action .. " by " .. string.upper(author), Color(171, 222, 47))
end
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetGenericdata(genericdata)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
if (!bNoRefresh) then
PLUGIN:RefreshDatafile(client, genericdata.id, nil, true)
end
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "genericdata")
queryObj:Update("data", util.TableToJSON(genericdata))
queryObj:Execute()
if (!bNoRefresh) then
PLUGIN:RefreshDatafile(client, genericdata.cid, nil)
end
end
netstream.Hook("EditDatafile", function(client, genericdata, action)
PLUGIN:EditDatafile(client, genericdata, nil, nil, action)
end)
function PLUGIN:AddLog(client, logsTable, genericdata, posterName, points, text, bNoRefresh, bBypass, bGenericNote)
if (!bBypass and !PLUGIN:HasAccessToDatafile(client)) then return end
local Timestamp = os.time()
if (!bNoRefresh or bBypass) then
logsTable[#logsTable + 1] = {
text = text,
date = Timestamp,
points = points or nil,
poster = posterName
}
end
if (bGenericNote) then
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' Datafile 'GENERIC' entry registered by " .. string.upper(author), Color(171, 222, 47))
end
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetDatafilelogs(logsTable)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
if !bNoRefresh then
PLUGIN:RefreshDatafile(client, genericdata.id, nil, true)
end
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "datafilelogs")
queryObj:Update("data", util.TableToJSON(logsTable))
queryObj:Execute()
if bNoRefresh then return end
PLUGIN:RefreshDatafile(client, genericdata.cid, nil)
end
netstream.Hook("AddLog", function(client, logsTable, genericdata, posterName, points, text, bNoRefresh, bGenericNote)
PLUGIN:AddLog(client, logsTable, genericdata, posterName, points, text, bNoRefresh, false, bGenericNote)
end)
netstream.Hook("AddViolation", function(client, violationsTable, genericdata, posterName, text, posterID)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
violationsTable[#violationsTable + 1] = {
text = text,
date = os.date("%d/%m/%Y"),
poster = posterName,
posterID = posterID
}
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' Datafile 'VIOLATION' entry registered by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetDatafileviolations(violationsTable)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
PLUGIN:RefreshDatafile(client, genericdata.id, nil, true)
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "datafileviolations")
queryObj:Update("data", util.TableToJSON(violationsTable))
queryObj:Execute()
PLUGIN:RefreshDatafile(client, genericdata.cid, nil)
end)
netstream.Hook("SetWagesDatafile", function(client, genericdata, wages)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
genericdata.wages = wages
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' Additional Wages set to " .. wages .. " by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetGenericdata(genericdata)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
PLUGIN:RefreshDatafile(client, genericdata.id, nil, true)
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "genericdata")
queryObj:Update("data", util.TableToJSON(genericdata))
queryObj:Execute()
PLUGIN:RefreshDatafile(client, genericdata.cid, nil)
end)
function PLUGIN:UpdateGenericData(genericdata)
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetGenericdata(genericdata)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
PLUGIN:RefreshDatafile(false, genericdata.id, nil, true)
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "genericdata")
queryObj:Update("data", util.TableToJSON(genericdata))
queryObj:Execute()
end
netstream.Hook("SetLoyalistStatusDatafile", function(client, genericdata, status)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
genericdata.loyaltyStatus = status
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' Loyalty Status updated to '" .. status .. "' by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetGenericdata(genericdata)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
PLUGIN:RefreshDatafile(client, genericdata.id, nil, true)
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "genericdata")
queryObj:Update("data", util.TableToJSON(genericdata))
queryObj:Execute()
PLUGIN:RefreshDatafile(client, genericdata.cid, nil)
end)
netstream.Hook("SetBypassDatafile", function(client, genericdata, bBypass)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
genericdata.bypassCommunion = bBypass
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' Communion Bypass " .. (bBypass and "enabled" or "disabled") .. " by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetGenericdata(genericdata)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
PLUGIN:RefreshDatafile(client, genericdata.id, nil, true)
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "genericdata")
queryObj:Update("data", util.TableToJSON(genericdata))
queryObj:Execute()
PLUGIN:RefreshDatafile(client, genericdata.cid, nil)
end)
netstream.Hook("AddMedicalRecord", function(client, medicalTable, genericdata, posterName, text, isFromCMUPDA)
if (!PLUGIN:HasAccessToDatafile(client) and !isFromCMUPDA) then return end
medicalTable[#medicalTable + 1] = {
text = text,
date = os.date("%d/%m/%Y"),
poster = posterName
}
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' Datafile 'MEDICAL' entry registered by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetDatafilemedicalrecords(medicalTable)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
PLUGIN:RefreshDatafile(client, genericdata.id, nil, true)
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "datafilemedicalrecords")
queryObj:Update("data", util.TableToJSON(medicalTable))
queryObj:Execute()
PLUGIN:RefreshDatafile(client, genericdata.cid, nil)
end)
netstream.Hook("SetDatafilePermit", function(client, genericdata, permitsTable)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
genericdata.permits = permitsTable
local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
ix.combineNotify:AddNotification("NTC:// Subject '" .. string.upper(genericdata.name or genericdata.collarID) .. "' Datafile Permits updated by " .. string.upper(author), Color(171, 222, 47))
local cachedCharacter = ix.char.loaded[genericdata.id]
if (cachedCharacter) then
cachedCharacter:SetGenericdata(genericdata)
if (IsValid(cachedCharacter:GetPlayer())) then
cachedCharacter:Save()
return
end
end
local queryObj = mysql:Update("ix_characters_data")
queryObj:Where("id", genericdata.id)
queryObj:Where("key", "genericdata")
queryObj:Update("data", util.TableToJSON(genericdata))
queryObj:Execute()
end)
netstream.Hook("GetPersonalNotesDatapad", function(client)
if (!PLUGIN:HasAccessToDatafile(client)) then return end
local character = client:GetCharacter()
if !character then return end
local notes = character:GetDatapadnotes()
if !notes then return end
netstream.Start(client, "ReplyPersonalNotesDatapad", notes)
end)
netstream.Hook("SavePersonalNotesDatapad", function(client, value)
local character = client:GetCharacter()
if !character then return end
character:SetDatapadnotes(value)
client:Notify("Saved your personal notes.")
end)

View File

@@ -0,0 +1,247 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
PLUGIN.name = "Combine Utilities"
PLUGIN.author = "Fruity, wowm0d"
PLUGIN.description = "Adds combine entities and visual stuff."
ix.util.IncludeDir("ixhl2rp/plugins/combineutilities/pda", true)
ix.util.IncludeDir("ixhl2rp/plugins/combineutilities/teams", true)
ix.util.IncludeDir("ixhl2rp/plugins/combineutilities/consoles", true)
ix.util.IncludeDir("ixhl2rp/plugins/combineutilities/workshifts", true)
ix.plugin.LoadEntities("ixhl2rp/plugins/combineutilities/workshifts/entities")
ix.util.Include("sv_groupmessaging.lua")
ix.util.Include("sv_plugin.lua")
ix.flag.Add("L", "Access to delete Datafile Logs.")
ix.lang.AddTable("english", {
cmdCharTogglePermit = "Gives or removes a character's permit, (dis)allowing them to use the bartering menu.",
togglePermit = "You have %s %s's bartering permit.",
togglePermitTarget = "%s has %s your bartering permit.",
cmdMassReward = "Give SC to multiple CP units at once. Use 'all' to give to all CP's.\nEnter a space-separated list of (partial) names to give to specific units.",
cmdAmputate = "Boosts your damage against the person you are looking at.\nBoost is only valid for 60 seconds. Target must be tied or KO.\nIf the target dies, the admins are alerted to PK the target.",
identityInspection = "%s %s performing identity inspection on %s, #%s",
})
ix.lang.AddTable("spanish", {
cmdAmputate = "Aumenta tu daño contra la persona a la que estás mirando.\nEl aumento sólo es válido durante 60 segundos. El objetivo debe estar atado o inconsciente.\nSi el objetivo muere, se avisa a los administradores para que hagan PK al objetivo.",
cmdCharTogglePermit = "Da o quita el permiso de un personaje, (des)permitiéndole usar el menú de comercio.",
identityInspection = "%s %s realizando inspección de identidad en %s, #%s",
togglePermitTarget = "%s ha %s tu permiso de comercio.",
togglePermit = "Tienes %s permisos de comercio de tipo %s.",
cmdMassReward = "Dar CE a múltiples CPCs a la vez. Usa \"all\" para dar a todas las unidades de Protección Civil.\nIntroduce una lista separada por espacios de nombres (parciales) para dar a unidades específicas."
})
ix.char.RegisterVar("hasDatafile", {
default = false,
field = "hasDatafile",
fieldType = ix.type.bool,
bNoDisplay = true,
bNoNetworking = true,
})
ix.config.Add("communionSCRequirement", 150, "Amount of SC needed to use the terminal communion.", nil, {
data = {min = 101, max = 720},
category = "Datafile"
})
ix.config.Add("maxWorkshiftSocialCredits", 15, "The max amount of social credits given at workshift.", nil, {
data = {min = 1, max = 20},
category = "Workshift"
})
ix.config.Add("datafileNoConnection", false, "Disable the datafile's connection to the OCIN network", nil, {
category = "Datafile"
})
ix.config.Add("crimeReportArchiveTime", 1, "The amount of weeks that crime reports must be older than to be automatically cleared via 'clear' button.", nil, {
data = {min = 1, max = 12},
category = "Datafile"
})
local classes = {
[CLASS_CP_CMD] = true,
[CLASS_CP_CPT] = true,
[CLASS_CP_RL] = true,
[CLASS_OVERSEER] = true,
[FACTION_MCP] = true
}
ix.command.Add("MassReward", {
description = "@cmdMassReward",
arguments = {
ix.type.number,
ix.type.text
},
OnCheckAccess = function(self, client)
local character = client:GetCharacter()
local name = client:Name()
if (client:Team() != FACTION_OVERWATCH and !classes[character:GetClass()] and !Schema:IsCombineRank(name, "i2") and !Schema:IsCombineRank(name, "i1")) then
return false
end
return true
end,
OnRun = function(self, client, sc, targets)
if (sc == 0) then
client:Notify("Enter a valid amount of SC!")
return false
end
local given = {}
if (targets == "*" or targets == "all") then
for _, v in ipairs(player.GetAll()) do
if (v:Team() != FACTION_CP or v == client) then continue end
local char = v:GetCharacter()
if (!char) then continue end
given[#given + 1] = v:Name()
local genericdata = char:GetGenericdata()
if (genericdata) then
genericdata.socialCredits = (genericdata.socialCredits or 0) + sc
char:SetGenericdata(genericdata)
char:Save()
end
if (sc > 0) then
v:Notify("You received "..sc.." sterilized credits.")
else
v:Notify("You have lost "..math.abs(sc).." sterilized credits.")
end
end
else
targets = string.Explode(" ", targets)
for _, v in ipairs(player.GetAll()) do
if (v:Team() != FACTION_CP) then continue end
local name = string.utf8lower(v:Name())
for _, target in ipairs(targets) do
if (string.find(name, string.utf8lower(target), 1, true)) then
local char = v:GetCharacter()
given[#given + 1] = v:Name()
local genericdata = char:GetGenericdata()
if (genericdata) then
genericdata.socialCredits = (genericdata.socialCredits or 0) + sc
char:SetGenericdata(genericdata)
char:Save()
end
if (sc > 0) then
v:Notify("You received "..sc.." sterilized credits.")
else
v:Notify("You have lost "..math.abs(sc).." sterilized credits.")
end
break
end
end
end
end
if (sc > 0) then
client:ChatNotify("You have given "..sc.." sterilized credits to: "..table.concat(given, ", "))
else
client:ChatNotify("You have taken "..sc.." sterilized credits from: "..table.concat(given, ", "))
end
end
})
ix.command.Add("Amputate", {
description = "@cmdAmputate",
arguments = {
bit.bor(ix.type.text, ix.type.optional)
},
OnCheckAccess = function(self, client)
return ix.faction.Get(client:Team()).isCombineFaction
end,
OnRun = function(self, client, reason)
local target = client:GetEyeTraceNoCursor().Entity
if (!IsValid(target) or !(target:IsPlayer() or target:GetClass() == "prop_ragdoll")) then
client:Notify("You must be looking at a valid target!")
return
end
local bIsRagdoll = target:GetClass() == "prop_ragdoll"
if (target:GetPos():DistToSqr(client:GetPos()) > 400 * 400) then
client:Notify("Your target is too far away!")
return
end
if ((bIsRagdoll and !IsValid(target.ixPlayer)) or (!bIsRagdoll and !target:IsRestricted())) then
client:Notify("Your target must be unconscious or tied up!")
return
end
if (bIsRagdoll) then
target = target.ixPlayer
end
target.beingAmputated = client
target.beingAmputatedEnd = CurTime() + 60
target.beingAmputatedReason = reason
client:Notify("Target for amputation set. Apply verdict!")
end
})
ix.command.Add("SetCombineDoor", {
description = "Set a door to combine and its' name to show up on the CA PDA.",
privilege = "Manage Doors",
adminOnly = true,
arguments = ix.type.text,
OnRun = function(self, client, name)
-- Get the door the player is looking at.
local entity = client:GetEyeTrace().Entity
-- Validate it is a door.
if (IsValid(entity) and entity:IsDoor() and !entity:GetNetVar("disabled")) then
entity:SetNetVar("combineDoor", name)
entity.ixCombineDoor = name
client:NotifyLocalized("Set this door to a combine door.")
hook.Run("SaveDoorData")
end
end
})
function PLUGIN:CreateDiskNameRequest(currentName, itemID, password)
Derma_StringRequest("Set Floppy Disk Name", "Set the name of the disk.", currentName or "Floppy Disk", function(text)
if (text == "") then return end
netstream.Start("SetFloppyDiskName", text, itemID, password)
end)
end
if (CLIENT) then
netstream.Hook("SetFloppyDiskName", function(currentName, itemID, password)
if password then
Derma_StringRequest("This disk is password protected.", "Enter it.", "", function(password2)
if (password2 == "") then return end
PLUGIN:CreateDiskNameRequest(currentName, itemID, password2)
end)
return
end
PLUGIN:CreateDiskNameRequest(currentName, itemID, false)
end)
end

View File

@@ -0,0 +1,35 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
netstream.Hook("AddGroupMessageComputer", function(client, message, groupID, name)
if client:GetCharacter():GetGroupID() != groupID then return false end
local timestamp = os.date( "%d.%m.%Y" )
local queryObj = mysql:Insert("ix_comgroupmessages")
queryObj:Insert("message_text", message)
queryObj:Insert("message_date", timestamp)
queryObj:Insert("message_poster", name)
queryObj:Insert("message_groupid", groupID)
queryObj:Execute()
end)
netstream.Hook("AddGroupReplyComputer", function(client, message, groupID, name, parent)
if client:GetCharacter():GetGroupID() != groupID then return false end
local timestamp = os.date( "%d.%m.%Y" )
local queryObj = mysql:Insert("ix_comgroupreplies")
queryObj:Insert("reply_text", message)
queryObj:Insert("reply_date", timestamp)
queryObj:Insert("reply_poster", name)
queryObj:Insert("reply_groupid", groupID)
queryObj:Insert("reply_parent", parent)
queryObj:Execute()
end)

View File

@@ -0,0 +1,509 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
function PLUGIN:GetHookCallPriority(hook)
if (hook == "HandlePlayerDeath") then
return 1100
end
end
function PLUGIN:PlayerLoadedCharacter(client, character)
-- Datafile
local bHasDatafile = character:GetHasDatafile()
if (!bHasDatafile) then
PLUGIN:CreateDatafile(client)
end
-- Teams
if (client:IsCombine()) then
self:LeaveTeam(client)
net.Start("ixPTSync")
net.WriteBool(true)
net.WriteTable(self.teams)
net.Send(client)
else
if (client:GetNetVar("ProtectionTeam")) then
self:LeaveTeam(client)
end
net.Start("ixPTSync")
net.WriteBool(false)
net.Send(client)
end
end
function PLUGIN:PostCalculatePlayerDamage(victim, damage, hitgroup)
if (victim.beingAmputated and victim.beingAmputatedEnd > CurTime() and damage:GetAttacker() == victim.beingAmputated) then
damage:ScaleDamage(hitgroup == HITGROUP_HEAD and 10 or 5)
end
end
function PLUGIN:HandlePlayerDeath(victim, damage)
if (victim.beingAmputated and victim.beingAmputatedEnd > CurTime() and damage:GetAttacker() == victim.beingAmputated) then
for _, v in ipairs(player.GetAll()) do
if (CAMI.PlayerHasAccess(v, "Helix - Ban Character")) then
v:ChatNotify(victim.beingAmputated:Name().." has amputated "..victim:Name().." for: "..(victim.beingAmputatedReason or "no reason given"))
end
end
victim.beingAmputated:Notify("Verdict delivered!")
victim.beingAmputated = nil
victim.beingAmputatedEnd = nil
victim.beingAmputatedReason = nil
return true --Do not let medical plugin interfere and put player in bleedout
end
end
-- Entity related functions
function PLUGIN:PlayerButtonDown( client, key )
if (IsFirstTimePredicted() and key == KEY_LALT) then
local entity = client:GetEyeTraceNoCursor().Entity
if !IsValid(entity) then
return false
end
if !entity.canUse then
return false
end
if (client:GetShootPos():Distance(entity:GetPos()) > 100) then
return false
end
if entity:GetNWInt("owner") and client:GetCharacter():GetID() != entity:GetNWInt("owner") then
return false
end
if entity.hasDiskInserted then client:NotifyLocalized("This computer has a disk inserted!") return false end
if (entity:GetClass() == "ix_medical_computer" or entity:GetClass() == "ix_computer") then
local getUsers = entity.users
local getNotes = entity.notes
local activeClass = "med_computer"
if entity:GetClass() == "ix_computer" then
activeClass = "cit_computer"
end
local pos = entity:GetPos()
ix.item.Spawn(activeClass, pos + Vector( 0, 0, 2 ), function(item, entityCreated) item:SetData("users", getUsers) item:SetData("notes", getNotes) end, entity:GetAngles())
entity:Remove()
end
end
end
function PLUGIN:RegisterSaveEnts()
ix.saveEnts:RegisterEntity("ix_medical_computer", true, true, true, {
OnSave = function(entity, data) --OnSave
data.motion = false
data.users = entity.users
data.notes = entity.notes
data.owner = entity:GetNWInt("owner")
end,
OnRestore = function(entity, data)
entity.users = data.users
entity.notes = data.notes
entity:SetNWInt("owner", data.owner)
end
})
ix.saveEnts:RegisterEntity("ix_computer", true, true, true, {
OnSave = function(entity, data) --OnSave
data.motion = false
data.users = entity.users
data.notes = entity.notes
data.owner = entity:GetNWInt("owner")
end,
OnRestore = function(entity, data)
entity.users = data.users
entity.notes = data.notes
entity:SetNWInt("owner", data.owner)
end
})
ix.saveEnts:RegisterEntity("ix_terminal", true, true, true, {
OnSave = function(entity, data) --OnSave
return {pos = data.pos, angles = data.angles, motion = false}
end,
})
ix.saveEnts:RegisterEntity("ix_console", true, true, true, {
OnSave = function(entity, data) --OnSave
return {pos = data.pos, angles = data.angles, motion = false}
end,
})
ix.saveEnts:RegisterEntity("npc_combine_camera", true, true, true, {
OnSave = function(entity, data) --OnSave
return {pos = data.pos, angles = data.angles, motion = false}
end,
OnRestore = function(entity, data)
entity:SetOwner(nil)
end,
})
ix.saveEnts:RegisterEntity("ix_workshiftterminal", true, true, true, {
OnSave = function(entity, data) --OnSave
return {pos = data.pos, angles = data.angles, motion = false}
end,
})
end
function PLUGIN:CanInsertDisk(client, item)
if !client then return false end
if !client:Alive() then return false end
local targetEnt = client:GetEyeTraceNoCursor().Entity
if !targetEnt then client:Notify("You are not looking at a computer!") return false end
if !IsValid(targetEnt) then client:Notify("You are not looking at a computer!") return false end
local entClass = targetEnt:GetClass()
if (entClass != "ix_medical_computer" and entClass != "ix_computer") then client:Notify("You are not looking at a computer!") return false end
if targetEnt.hasDiskInserted then client:Notify("There is already a disk in this computer!") return false end
return targetEnt
end
function PLUGIN:InsertDisk(client, item)
local computerEnt = self:CanInsertDisk(client, item)
if !computerEnt or (computerEnt and !IsValid(computerEnt)) then return false end
local bSuccess, error = item:Transfer(nil, nil, nil, item.player)
if (!bSuccess and isstring(error)) then
client:Notify("Could not drop the disk and insert it.")
return
end
local disk = bSuccess
local rotation = Vector(0, 0, 0)
local angle = computerEnt:GetAngles()
angle:RotateAroundAxis(angle:Up(), rotation.x)
disk:SetAngles(angle)
disk:SetPos(computerEnt:GetPos() + computerEnt:GetUp() * -1.5 + computerEnt:GetForward() * -15)
constraint.Weld( disk, computerEnt, 0, 0, 0, true, false )
local physObj = disk:GetPhysicsObject()
if !physObj then return end
physObj:EnableMotion(false)
computerEnt.hasDiskInserted = item:GetID()
item.computer = computerEnt
end
netstream.Hook("RequestFloppyDiskData", function(client, computerEnt, password)
if !computerEnt then return false end
if !IsValid(computerEnt) then return false end
if !IsEntity(computerEnt) then return false end
local diskItem = ix.item.instances[computerEnt.hasDiskInserted]
if !diskItem then return false end
local diskPassword = diskItem:GetData("password", false)
local diskData = diskItem:GetData("content", false)
if !diskPassword then
netstream.Start(client, "ReplyFloppyDiskData", true, false, diskData)
return
end
if (diskPassword and !password) or !password then
netstream.Start(client, "ReplyFloppyDiskData", false)
return
end
if (diskPassword != password) then
netstream.Start(client, "ReplyFloppyDiskData", false, true)
return
end
if (diskPassword == password) then
netstream.Start(client, "ReplyFloppyDiskData", true, false, diskData)
return
end
end)
netstream.Hook("FloppyDiskSetPassword", function(client, newPass, computerEnt)
if !computerEnt then return false end
if !IsValid(computerEnt) then return false end
if !IsEntity(computerEnt) then return false end
local diskItem = ix.item.instances[computerEnt.hasDiskInserted]
if !diskItem then return false end
diskItem:SetData("password", newPass)
end)
netstream.Hook("FloppyDiskSetData", function(client, newContent, computerEnt)
if !computerEnt then return false end
if !IsValid(computerEnt) then return false end
if !IsEntity(computerEnt) then return false end
local diskItem = ix.item.instances[computerEnt.hasDiskInserted]
if !diskItem then return false end
diskItem:SetData("content", newContent)
end)
netstream.Hook("SetFloppyDiskName", function(client, text, itemID, password)
local character = client:GetCharacter()
if !character then return false end
local inventory = character:GetInventory()
if !inventory then return false end
local item = ix.item.instances[itemID]
if !item then return end
local password2 = item:GetData("password", false)
if password2 and !password then return end
if password2 != password then
client:NotifyLocalized("Wrong password.")
return
end
if !inventory.GetItemByID then return false end
if !inventory:GetItemByID(itemID) then
local targetEnt = client:GetEyeTraceNoCursor().Entity
if !IsValid(targetEnt) then return false end
if targetEnt:GetClass() != "ix_item" then return false end
if (targetEnt.ixItemID and targetEnt.ixItemID != itemID) then return false end
end
item:SetData("customName", Schema:FirstToUpper(text))
client:NotifyLocalized("Set the disk name to "..Schema:FirstToUpper(text))
end)
netstream.Hook("FindLetterRecepient", function(client, text, itemID)
local character = client:GetCharacter()
if !character then return end
local inventory = character:GetInventory()
if !inventory then return end
if !inventory:GetItemByID(itemID) then return end
if inventory:GetItemByID(itemID).name != "Paper" then return end
if string.len(text) == 5 and isnumber(tonumber(text)) then
text = Schema:ZeroNumber(tonumber(text), 5)
end
local id = false
local name = false
local cid = false
for _, v in pairs(ix.char.loaded) do
if !isnumber(text) and string.len(tostring(text)) != 5 then
if (ix.util.StringMatches(v:GetName(), text)) then
id = v:GetID()
name = v:GetName()
cid = v:GetCid()
break
end
else
if ix.util.StringMatches(tostring(v:GetCid()), tostring(text)) then
id = v:GetID()
name = v:GetName()
cid = v:GetCid()
break
end
end
end
if !id or !name or !cid then
local receiverQuery = mysql:Select("ix_characters")
receiverQuery:Select("id")
receiverQuery:Select("name")
receiverQuery:Select("cid")
if !isnumber(text) and string.len(tostring(text)) != 5 then
receiverQuery:WhereLike("name", text)
else
receiverQuery:WhereLike("cid", text)
end
receiverQuery:Callback(function(result)
if (!result or !istable(result) or #result == 0) then
return
end
local first = result[1]
id = first.id
name = first.name
cid = first.cid
end)
receiverQuery:Execute()
end
timer.Simple(3, function()
if !id or !name or !cid then client:Notify("Could not find the person you were trying to send a letter to.") return end
cid = cid or "00000"
netstream.Start(client, "ReplyLetterRecepient", id, name, cid, itemID)
end)
end)
function PLUGIN:AddLogToDatafile(client, toCharID, fromCID, fromName)
local whomData = {
fromGenericData = false,
fromLogsTable = false,
toGenericData = false,
toLogsTable = false
}
for _, v in pairs(ix.char.loaded) do
if ix.util.StringMatches(tostring(v:GetCid()), tostring(fromCID)) then
whomData.fromGenericData = v:GetGenericdata()
whomData.fromLogsTable = v:GetDatafilelogs()
break
end
end
if ix.char.loaded[tonumber(toCharID)] then
whomData.toGenericData = ix.char.loaded[tonumber(toCharID)]:GetGenericdata()
whomData.toLogsTable = ix.char.loaded[tonumber(toCharID)]:GetDatafilelogs()
end
local addLogsTo = {["to"] = toCharID, ["from"] = fromCID}
if whomData.fromGenericData and whomData.fromLogsTable then addLogsTo["from"] = nil end
if whomData.toGenericData and whomData.toLogsTable then addLogsTo["to"] = nil end
if !whomData.fromGenericData or !whomData.fromLogsTable or !whomData.toGenericData or !whomData.toLogsTable then
for whom, id in pairs(addLogsTo) do
local query = mysql:Select("ix_characters")
query:Select("name")
query:Select("faction")
query:Select("id")
query:Select("cid")
if whom != "to" then
query:Where("cid", id)
else
query:Where("id", id)
end
query:Where("schema", Schema and Schema.folder or "helix")
query:Callback(function(result)
if (!istable(result) or #result == 0) then
return
end
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:Where("id", result[1].id)
dataSelect:WhereIn("key", {"genericdata", "datafilelogs"})
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
for _, v in ipairs(dataSelectResult) do
if whom == "to" then
if v.key == "genericdata" then
whomData.toGenericData = util.JSONToTable(v.data or "")
elseif v.key == "datafilelogs" then
whomData.toLogsTable = util.JSONToTable(v.data or "")
end
else
if v.key == "genericdata" then
whomData.fromGenericData = util.JSONToTable(v.data or "")
elseif v.key == "datafilelogs" then
whomData.fromLogsTable = util.JSONToTable(v.data or "")
end
end
end
end)
dataSelect:Execute()
end)
query:Execute()
end
end
timer.Simple(4, function()
if whomData.fromGenericData and whomData.fromLogsTable and whomData.toGenericData and whomData.toLogsTable then
local combineutilities = ix.plugin.list["combineutilities"]
if combineutilities and combineutilities.AddLog then
for i = 1, 2 do
local logsT = (i == 1 and whomData.fromLogsTable or whomData.toLogsTable)
local genericT = (i == 1 and whomData.fromGenericData or whomData.toGenericData)
local fromName1 = whomData.fromGenericData.name or ""
local fromCID1 = whomData.fromGenericData.cid or ""
local toName = whomData.toGenericData.name or ""
local toCID = whomData.toGenericData.cid or ""
if (i == 1) then -- Only need the notification once
ix.combineNotify:AddNotification("LOG:// Subject '" .. fromName1 .. "' sent a letter to '" .. toName .. "'", nil, client)
end
combineutilities:AddLog(client, logsT, genericT, "TERMINAL", nil, "LETTER SENT/RECEIVED - "..fromName1.." | "..fromCID1.." -> "..toName.." | "..toCID, true, true)
end
end
end
end)
end
netstream.Hook("SendLetterToID", function(client, charID, itemID, fromCID, fromName)
local character = client:GetCharacter()
if !character then return end
local inventory = character:GetInventory()
if !inventory then return end
if !inventory:GetItemByID(itemID) then return end
if inventory:GetItemByID(itemID).name != "Paper" then return end
local paperInstance = ix.item.instances[tonumber(itemID)]
if !paperInstance then return end
local paperWritingID = paperInstance:GetData("writingID")
if !paperWritingID then return end
local paperTitle = paperInstance:GetData("title", "Paper")
local currentOwner = paperInstance:GetData("owner", false)
if ix.char.loaded[tonumber(charID)] then
ix.char.loaded[tonumber(charID)]:SetPurchasedItems("letter_"..itemID, {title = paperTitle, fromCID = fromCID, fromName = fromName, writingID = paperWritingID, owner = currentOwner})
client:Notify("Letter has been successfully sent.")
PLUGIN:AddLogToDatafile(client, charID, fromCID, fromName)
ix.item.instances[tonumber(itemID)]:Remove()
else
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:Where("id", tonumber(charID))
dataSelect:WhereIn("key", "purchasedItems")
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
local purchasedItems = util.JSONToTable(dataSelectResult[1].data)
if !purchasedItems then return end
purchasedItems["letter_"..itemID] = {title = paperTitle, fromCID = fromCID, fromName = fromName, writingID = paperWritingID, owner = currentOwner}
local updateQuery = mysql:Update("ix_characters_data")
updateQuery:Update("data", util.TableToJSON(purchasedItems))
updateQuery:Where("id", tonumber(charID))
updateQuery:Where("key", "purchasedItems")
updateQuery:Execute()
ix.item.instances[tonumber(itemID)]:Remove()
PLUGIN:AddLogToDatafile(client, charID, fromCID, fromName)
end)
dataSelect:Execute()
client:Notify("Letter has been successfully sent.")
end
end)

View File

@@ -0,0 +1,167 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
function PLUGIN:UpdateTeamMenu()
if (IsValid(ix.gui.protectionTeams)) then
ix.gui.protectionTeams.memberScroll:Clear()
ix.gui.protectionTeams.teamScroll:Clear()
if ix.gui.protectionTeams.leaveButton then
ix.gui.protectionTeams.leaveButton:Remove()
end
if ix.gui.protectionTeams.createButton then
ix.gui.protectionTeams.createButton:Remove()
end
if ix.gui.protectionTeams.joinButton then
ix.gui.protectionTeams.joinButton:Remove()
end
ix.gui.protectionTeams.CreateButtons()
end
end
function PLUGIN:CreateTeam(client, index)
self.teams[index] = {
owner = client,
members = {client}
}
hook.Run("OnCreateTeam", client, index)
end
function PLUGIN:ReassignTeam(index, newIndex)
local curTeam = self.teams[index]
self:DeleteTeam(index)
self:CreateTeam(curTeam["owner"], newIndex)
self.teams[newIndex]["members"] = curTeam["members"]
hook.Run("OnReassignTeam", index, newIndex)
end
function PLUGIN:DeleteTeam(index)
self.teams[index] = nil
hook.Run("OnDeleteTeam", index)
end
function PLUGIN:LeaveTeam(client, index)
if table.HasValue(self.teams[index]["members"], client) then
table.RemoveByValue(self.teams[index]["members"], client)
end
hook.Run("OnLeaveTeam", client, index)
end
function PLUGIN:JoinTeam(client, index)
if !index or index and !self.teams[index] then return end
if !self.teams[index]["members"] then return end
table.insert(self.teams[index]["members"], client)
hook.Run("OnJoinTeam", client, index)
end
function PLUGIN:SetTeamOwner(index, client)
if !self.teams[index] then return end
self.teams[index]["owner"] = client
hook.Run("OnSetTeamOwner", client, index)
end
-- Hooks
function PLUGIN:OnCreateTeam(client, index)
self:UpdateTeamMenu()
end
function PLUGIN:OnReassignTeam(index, newIndex)
self:UpdateTeamMenu()
end
function PLUGIN:OnDeleteTeam(index)
self:UpdateTeamMenu()
end
function PLUGIN:OnLeaveTeam(client, index)
self:UpdateTeamMenu()
end
function PLUGIN:OnJoinTeam(client, index)
self:UpdateTeamMenu()
end
function PLUGIN:OnSetTeamOwner(client, index)
self:UpdateTeamMenu()
end
function PLUGIN:PopulateCharacterInfo(client, character, container)
if (LocalPlayer():HasActiveCombineMask() and client:GetNetVar("ProtectionTeam")) then
local curTeam = container:AddRowAfter("name", "curTeam")
curTeam:SetText(L("TeamStatus", client:GetNetVar("ProtectionTeam"), client:GetNetVar("ProtectionTeamOwner") and L("TeamOwnerStatus") or L("TeamMemberStatus")))
curTeam:SetBackgroundColor(client:GetNetVar("ProtectionTeamOwner") and Color(50,150,100) or Color(50,100,150))
end
end
net.Receive("ixPTSync", function()
local bTeams = net.ReadBool()
if (!bTeams) then
PLUGIN.teams = {}
return
end
local teams = net.ReadTable()
PLUGIN.teams = teams or {}
end)
net.Receive("ixPTCreate", function()
local index = net.ReadUInt(8)
local client = net.ReadEntity()
PLUGIN:CreateTeam(client, index)
end)
net.Receive("ixPTDelete", function()
local index = net.ReadUInt(8)
PLUGIN:DeleteTeam(index)
end)
net.Receive("ixPTLeave", function()
local index = net.ReadUInt(8)
local client = net.ReadEntity()
PLUGIN:LeaveTeam(client, index)
end)
net.Receive("ixPTJoin", function()
local index = net.ReadUInt(8)
local client = net.ReadEntity()
PLUGIN:JoinTeam(client, index)
end)
net.Receive("ixPTOwner", function()
local index = net.ReadUInt(8)
local client = net.ReadEntity()
PLUGIN:SetTeamOwner(index, client)
end)
net.Receive("ixPTReassign", function()
local index = net.ReadUInt(8)
local newIndex = net.ReadUInt(8)
PLUGIN:ReassignTeam(index, newIndex)
end)

View File

@@ -0,0 +1,166 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
ix.util.IncludeDir("ixhl2rp/plugins/combineutilities/teams/derma", true)
PLUGIN.teams = {}
function PLUGIN:GetReceivers()
local recievers = {}
for _, client in pairs(player.GetAll()) do
if (client:IsCombine()) then
table.insert(recievers, client)
end
end
return recievers
end
ix.command.Add("PTCreate", {
description = "@cmdPTCreate",
arguments = bit.bor(ix.type.number, ix.type.optional),
OnCheckAccess = function(self, client)
return client:IsCombine()
end,
OnRun = function(self, client, index)
if (!client:IsCombine()) then
return "@CannotUseTeamCommands"
end
if (!index) then
return client:RequestString("@cmdPTCreate", "@cmdCreatePTDesc", function(text) ix.command.Run(client, "PTCreate", {text}) end, "")
end
return PLUGIN:CreateTeam(client, index)
end
})
ix.command.Add("PTJoin", {
description = "@cmdPTJoin",
arguments = ix.type.number,
OnCheckAccess = function(self, client)
return client:IsCombine()
end,
OnRun = function(self, client, index)
if (!client:IsCombine()) then
return "@CannotUsePTCommands"
end
return PLUGIN:JoinTeam(client, index)
end
})
ix.command.Add("PTLeave", {
description = "@cmdPTLeave",
OnCheckAccess = function(self, client)
return client:IsCombine()
end,
OnRun = function(self, client)
if (!client:IsCombine()) then
return "@CannotUsePTCommands"
end
return PLUGIN:LeaveTeam(client)
end
})
ix.command.Add("PTLead", {
description = "@cmdPTLead",
arguments = bit.bor(ix.type.player, ix.type.optional),
OnCheckAccess = function(self, client)
return client:IsCombine()
end,
OnRun = function(self, client, target)
if (!client:IsCombine()) then
return "@CannotUseTeamCommands"
end
if (target == client or !target) then
target = client
end
local index = target:GetNetVar("ProtectionTeam")
if (!PLUGIN.teams[index]) then return "@TargetNoCurrentTeam" end
if (!client:IsDispatch()) then
if (client:GetNetVar("ProtectionTeam") != target:GetNetVar("ProtectionTeam")) then return "@TargetNotSameTeam" end
if (PLUGIN.teams[index]["owner"]) then
if (target == client) then return "@TeamAlreadyHasOwner" end
if (!client:GetNetVar("ProtectionTeamOwner")) then return "@CannotPromoteTeamMembers" end
end
end
if ((target == client or !target) and (PLUGIN:SetTeamOwner(index, target))) then
return "@TeamOwnerAssume"
end
return PLUGIN:SetTeamOwner(index, target)
end
})
ix.command.Add("PTKick", {
description = "@cmdPTKick",
arguments = ix.type.player,
OnCheckAccess = function(self, client)
return client:IsCombine()
end,
OnRun = function(self, client, target)
if (!client:IsCombine()) then
return "@CannotUseTeamCommands"
end
local index = target:GetNetVar("ProtectionTeam")
if (!PLUGIN.teams[index]) then return "@TargetNoCurrentTeam" end
if (client:GetNetVar("ProtectionTeam") != target:GetNetVar("ProtectionTeam") and !client:IsDispatch()) then return "@TargetNotSameTeam" end
if (!client:GetNetVar("ProtectionTeamOwner") and !client:IsDispatch()) then return "@CannotKickTeamMembers" end
PLUGIN:LeaveTeam(target)
return "@KickedFromTeam", target:GetName()
end
})
ix.command.Add("PTReassign", {
description = "@cmdPTReassign",
arguments = {bit.bor(ix.type.number, ix.type.optional), bit.bor(ix.type.number, ix.type.optional)},
OnCheckAccess = function(self, client)
return client:IsCombine()
end,
OnRun = function(self, client, newIndex, oldIndex)
if (!client:IsCombine()) then
return "@CannotUseTeamCommands"
end
local index = client:GetNetVar("ProtectionTeam")
if (!oldIndex and index) then
oldIndex = index
end
if (!client:IsDispatch()) then
if (!PLUGIN.teams[oldIndex]) then return "@NoCurrentTeam" end
if (!client:GetNetVar("ProtectionTeamOwner")) then return "@CannotReassignTeamIndex" end
end
if (newIndex and oldIndex) then
return PLUGIN:ReassignTeam(oldIndex, newIndex)
else
return client:RequestString("@cmdPTReassign", "@cmdReassignPTDesc", function(text) ix.command.Run(client, "PTReassign", {text, oldIndex}) end, "")
end
end
})

View File

@@ -0,0 +1,230 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
util.AddNetworkString("ixPTSync")
util.AddNetworkString("ixPTCreate")
util.AddNetworkString("ixPTDelete")
util.AddNetworkString("ixPTJoin")
util.AddNetworkString("ixPTLeave")
util.AddNetworkString("ixPTOwner")
util.AddNetworkString("ixPTReassign")
function PLUGIN:CreateTeam(client, index, bNetworked, bNoNotif)
if (IsValid(client) and client:GetNetVar("ProtectionTeam")) then
return "@AlreadyHasTeam"
end
if (self.teams[index]) then
return "@TeamAlreadyExists", tostring(index)
end
if (index > 99 or index < 1) then
return "@TeamMustClamp"
end
self.teams[index] = {
owner = client,
members = {client}
}
if (IsValid(client)) then
client:SetNetVar("ProtectionTeam", index)
client:SetNetVar("ProtectionTeamOwner", true)
end
if (!bNetworked) then
net.Start("ixPTCreate")
net.WriteUInt(index, 8)
net.WriteEntity(client)
net.Send(self:GetReceivers())
end
hook.Run("OnCreateTeam", client, index)
if (!bNoNotif) then
ix.combineNotify:AddNotification("NTC:// " .. client:GetCombineTag() .. " has established Protection-Team " .. index, Color(0, 145, 255, 255))
end
return "@TeamCreated", tostring(index)
end
function PLUGIN:ReassignTeam(index, newIndex, bNetworked)
if (newIndex > 99 or newIndex < 1) then
return "@TeamMustClamp"
end
if (self.teams[newIndex]) then
return "@TeamAlreadyExists", tostring(index)
end
local curTeam = self.teams[index]
self:DeleteTeam(index, true, true)
self:CreateTeam(curTeam["owner"], newIndex, true, true)
self.teams[newIndex]["members"] = curTeam["members"]
for _, client in pairs(curTeam["members"]) do
client:SetNetVar("ProtectionTeam", newIndex)
end
if (!bNetworked) then
net.Start("ixPTReassign")
net.WriteUInt(index, 8)
net.WriteUInt(newIndex, 8)
net.Send(self:GetReceivers())
end
hook.Run("OnReassignTeam", index, newIndex)
ix.combineNotify:AddNotification("NTC:// Protection-Team " .. index .. " re-assigned as Protection-Team " .. newIndex, Color(0, 145, 255, 255))
return "@TeamReassigned", tostring(index), tostring(newIndex)
end
function PLUGIN:SetTeamOwner(index, client, bNetworked)
local curOwner = self.teams[index]["owner"]
if (IsValid(curOwner)) then
curOwner:SetNetVar("ProtectionTeamOwner", nil)
end
self.teams[index]["owner"] = client
if (IsValid(client)) then
client:SetNetVar("ProtectionTeamOwner", true)
end
if (!bNetworked) then
net.Start("ixPTOwner")
net.WriteUInt(index, 8)
net.WriteEntity(client)
net.Send(self:GetReceivers())
end
hook.Run("OnSetTeamOwner", client, index)
if (IsValid(client)) then
ix.combineNotify:AddNotification("NTC:// " .. client:GetCombineTag() .. " designated as Protection-Team " .. index .. " Leader", Color(0, 145, 255, 255))
return "@TeamOwnerSet", client:GetName()
end
end
function PLUGIN:DeleteTeam(index, bNetworked, bNoNotif)
self.teams[index] = nil
for _, client in pairs(self:GetReceivers()) do
if (client:GetNetVar("ProtectionTeam") == index) then
client:SetNetVar("ProtectionTeam", nil)
if (client:GetNetVar("ProtectionTeamOwner")) then
client:SetNetVar("ProtectionTeamOwner", nil)
end
end
end
if (!bNetworked) then
net.Start("ixPTDelete")
net.WriteUInt(index, 8)
net.Send(self:GetReceivers())
end
if (!bNoNotif) then
ix.combineNotify:AddNotification("NTC:// Protection-Team " .. index .. " has been disbanded", Color(0, 145, 255, 255))
end
hook.Run("OnDeleteTeam", index)
end
function PLUGIN:JoinTeam(client, index, bNetworked)
if (client:GetNetVar("ProtectionTeam")) then
return "@TeamMustLeave"
end
if (index > 99 or index < 1) then
return "@TeamMustClamp"
end
if (!self.teams[index]) then
return "@TeamNonExistent", tostring(index)
end
table.insert(self.teams[index]["members"], client)
client:SetNetVar("ProtectionTeam", index)
if (!bNetworked) then
net.Start("ixPTJoin")
net.WriteUInt(index, 8)
net.WriteEntity(client)
net.Send(self:GetReceivers())
end
hook.Run("OnJoinTeam", client, index)
ix.combineNotify:AddNotification("NTC:// " .. client:GetCombineTag() .. " has interlocked into Protection-Team " .. index, Color(0, 145, 255, 255))
return "@JoinedTeam", index
end
function PLUGIN:LeaveTeam(client, bNetworked)
if (!client:GetNetVar("ProtectionTeam")) then
return "@NoCurrentTeam"
end
local index = client:GetNetVar("ProtectionTeam")
local curTeam = self.teams[index]
if (curTeam) then
table.RemoveByValue(self.teams[index]["members"], client)
client:SetNetVar("ProtectionTeam", nil)
if (!bNetworked) then
net.Start("ixPTLeave")
net.WriteUInt(index, 8)
net.WriteEntity(client)
net.Send(self:GetReceivers())
end
if (client:GetNetVar("ProtectionTeamOwner")) then
self:SetTeamOwner(index, nil)
end
hook.Run("OnLeaveTeam", client, index)
ix.combineNotify:AddNotification("NTC:// " .. client:GetCombineTag() .. " has detached from Protection-Team " .. index, Color(0, 145, 255, 255))
return "@LeftTeam", index
end
end
function PLUGIN:Tick()
local curTime = CurTime()
if (!self.tick or self.tick < curTime) then
self.tick = curTime + 30
for index, teamTbl in pairs(self.teams) do
if (table.IsEmpty(teamTbl["members"])) then
self:DeleteTeam(index)
end
end
end
end
function PLUGIN:PlayerDisconnected(client)
if (client:GetNetVar("ProtectionTeam")) then
self:LeaveTeam(client)
end
end

View File

@@ -0,0 +1,102 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
include('shared.lua')
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
local color_red = Color(255, 0, 0, 255)
function ENT:Initialize()
self.buttons = {}
end
function ENT:Draw()
self:DrawModel()
local width, height = 260, 135
local ang = self:GetAngles()
local pos = self:GetPos() + ang:Up() * 60 - ang:Right() * 4.1 - ang:Forward() * 13
ang:RotateAroundAxis(ang:Right(), 90)
ang:RotateAroundAxis(ang:Up(), -65)
ang:RotateAroundAxis(ang:Right(), -90)
local display = self.Displays[self:GetDisplay()] or self.Displays[6]
cam.Start3D2D(pos, ang, 0.1)
render.PushFilterMin(TEXFILTER.NONE)
render.PushFilterMag(TEXFILTER.NONE)
surface.SetDrawColor(Color(255, 255, 255, 250))
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/datafile/workshifterminal.png"))
surface.DrawTexturedRect(0, 0, width, height)
surface.SetDrawColor(Color(16, 16, 16, 100))
surface.DrawRect(10, 5, width - 20, height - 10)
surface.SetDrawColor(Color(72, 255, 243, 10))
surface.DrawOutlinedRect(10, 5, width - 20, height - 10)
surface.SetDrawColor(Color(255, 255, 255, 16))
surface.DrawRect(10, (height - 5) / 1.9 + math.sin(CurTime() * 4) * (height + 8) / 2.3, width - 20, 1)
local alpha = 191 + 64 * math.sin(CurTime() * 4)
local color = ColorAlpha(display[2], alpha)
draw.SimpleText("Workshift Terminal", "MenuFont", width / 2, height * 0.35, Color(255, 255, 255, alpha), TEXT_ALIGN_CENTER)
draw.SimpleText(display[1], "MenuFont", width / 2, height * 0.6, color, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
if (self.buttons) then
for k, _ in pairs(self.buttons) do
local closest = self:GetNearestButton()
local thisText = "Enter CID"
if (closest == k) then
cam.Start3D2D(self.buttons[k], ang, 0.1)
draw.SimpleText(thisText, "MenuFont", 0, -30, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER)
cam.End3D2D()
end
end
end
render.PopFilterMin()
render.PopFilterMag()
cam.End3D2D()
render.SetMaterial(glowMaterial)
if (self.buttons) then
local position = self:GetPos()
local f, r, u = self:GetForward(), self:GetRight(), self:GetUp()
self.buttons[1] = position + f*-5.6 + r*5.6 + u*46
local closest = self:GetNearestButton()
for k, v in pairs(self.buttons) do
local thisColor = Color(255, 255, 255, 255)
if (closest != k) then
thisColor.a = thisColor == color_red and 100 or 75
else
thisColor.a = 230 + (math.sin(RealTime() * 7.5) * 25)
end
if (LocalPlayer():KeyDown(IN_USE) and closest == k) then
thisColor = table.Copy(thisColor)
thisColor.r = math.min(thisColor.r + 100, 255)
thisColor.g = math.min(thisColor.g + 100, 255)
thisColor.b = math.min(thisColor.b + 100, 255)
end
render.DrawSprite(v, 4, 4, thisColor)
end
end
end

View File

@@ -0,0 +1,122 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile( "cl_init.lua" ) -- Make sure clientside
AddCSLuaFile( "shared.lua" ) -- and shared scripts are sent.
include('shared.lua')
local PLUGIN = PLUGIN
function ENT:OnInitialize()
self:SetDisplay(9)
end
function ENT:SaveTerminalLocations()
ix.saveEnts:SaveEntity(self)
end
function ENT:SetGroups(bUse)
end
function ENT:CheckStartedWorkshift()
if !PLUGIN:CheckStartedWorkshift(self) then
self:SetDisplay(9)
self:EmitSound("buttons/button8.wav")
self:ResetInfo()
return false
end
return true
end
function ENT:StopWorkshift(client)
if !self.workshiftStarted then
self:ResetInfo()
self:EmitSound("buttons/button8.wav")
return
end
PLUGIN:StopWorkshift(self, client)
end
function ENT:StartWorkshift(client)
if self.workshiftStarted then
self:ResetInfo()
self:EmitSound("buttons/button8.wav")
return
end
self:SetDisplay(3)
timer.Simple(1, function()
if IsValid(self) then
self:SetDisplay(1)
end
end)
self.workshiftStarted = true
self:ResetInfo()
end
function ENT:ResetInfo()
self.canUse = true
self.activePlayer = nil
self.activeCharacter = nil
end
function ENT:OnUse(client)
local button = self:GetNearestButton(client)
if (button) then
self:EmitSound("buttons/lightswitch2.wav")
if !self:CheckStartedWorkshift() then
self:EmitSound("buttons/button8.wav")
self:ResetInfo()
return false
end
self:CheckForCID(client)
else
client:NotifyLocalized("You need to use one of the buttons!")
self:ResetInfo()
end
end
function ENT:ReadyForAnother()
timer.Simple(1, function()
if IsValid(self) then
self:SetDisplay(1)
self:ResetInfo()
end
end)
end
function ENT:OnSuccess(idCard, genericData, client)
self:SetDisplay(6)
self:EmitSound("buttons/button14.wav")
self:ReadyForAnother()
if (client:IsVortigaunt()) then
ix.combineNotify:AddNotification("LOG:// Subject " .. string.upper("biotic asset identification card: #") .. genericData.cid .. " joined Work-Cycle")
else
ix.combineNotify:AddNotification("LOG:// Subject '" .. genericData.name .. "' joined Work-Cycle", nil, client)
end
PLUGIN:AddToWorkshift(client, idCard, genericData, self)
end
function ENT:AlreadyParticipated()
self:SetDisplay(10)
self:EmitSound("buttons/button8.wav")
self:ReadyForAnother()
end

View File

@@ -0,0 +1,77 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ENT.Type = "anim"
ENT.PrintName = "Workshift Terminal"
ENT.Base = "ix_terminal"
ENT.Author = "Fruity"
ENT.Contact = "Willard Networks"
ENT.Purpose = "Start and stop workshifts via an entity."
ENT.Instructions = "Press E to enter CID, use the buttons to start/stop."
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
ENT.model = "models/willard/combine/checkin.mdl"
ENT.workshiftStarted = false
ENT.participants = {}
ENT.canMalfunction = true
ENT.Displays = {
[1] = {"WAITING FOR ID", Color( 255, 255, 180 ), true},
[2] = {"CHECKING", Color(255, 200, 0)},
[3] = {"WORKSHIFT STARTED", Color(0, 255, 0)},
[4] = {"RELOADING", Color(255, 200, 0)},
[5] = {"OFFLINE", Color(255, 0, 0), true},
[6] = {"SUCCESS", Color( 0, 255, 180 )},
[7] = {"WORKSHIFT FINISHED", Color(255, 0, 0)},
[8] = {"NO INFO", Color(0, 255, 0)},
[9] = {"SHIFT INACTIVE", Color(255, 0, 0)},
[10] = {"ALREADY PARTICIPATED", Color(255, 0, 0)},
[11] = {"REGISTRATION PAUSED", Color(255, 0, 0)}
}
ENT.buttons = {}
function ENT:SetupDataTables()
self:NetworkVar("Int", 0, "Display")
end
function ENT:GetNearestButton(client)
client = client or (CLIENT and LocalPlayer())
if (self.buttons) then
if (SERVER) then
local position = self:GetPos()
local f, r, u = self:GetForward(), self:GetRight(), self:GetUp()
self.buttons[1] = position + f*-5.6 + r*5.6 + u*46
end
local data = {}
data.start = client:GetShootPos()
data.endpos = data.start + client:GetAimVector()*96
data.filter = client
local trace = util.TraceLine(data)
local hitPos = trace.HitPos
if (hitPos) then
for k, v in pairs(self.buttons) do
if (v:Distance(hitPos) <= 2) then
return k
end
end
end
end
end

View File

@@ -0,0 +1,145 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
function PLUGIN:StartWorkshift()
SetNetVar("WorkshiftStarted", true)
end
function PLUGIN:StopWorkshift(ent)
ent.workshiftPaused = ent.workshiftPaused or false
ent.savedInfo = ent.savedInfo or {}
ent.workshiftStarted = false
ent.workshiftPaused = false
ent.participants = {}
ent.savedInfo = {}
ent:ResetInfo()
ent:SetDisplay(9)
ent:EmitSound("ambient/machines/combine_terminal_idle2.wav")
end
function PLUGIN:EndWorkshift(tSaved, client)
local character = client:GetCharacter()
local datafields = {"genericdata", "datafilelogs"}
if tSaved and istable(tSaved) and !table.IsEmpty(tSaved) then
for genericID, tInfo in pairs(tSaved) do
local coupon = tInfo.coupon or false
local points = tInfo.points or 0
local dataSelect = mysql:Select("ix_characters_data")
dataSelect:Where("id", genericID)
dataSelect:WhereIn("key", datafields)
dataSelect:Callback(function(dataSelectResult)
if (!istable(dataSelectResult) or #dataSelectResult == 0) then
return
end
local file = {}
for _, v in ipairs(dataSelectResult) do
file[v.key] = util.JSONToTable(v.data or "")
end
local limitCount = 0
for _, v in pairs(file["datafilelogs"]) do
if !v.points then
continue
end
if isnumber(v.date) and os.date("%d/%m/%Y", v.date) == os.date("%d/%m/%Y") then
limitCount = limitCount + v.points
end
end
if ((points + limitCount) > 20 or (points + limitCount) < -20) then
PLUGIN:AddLog(client, file["datafilelogs"], file["genericdata"], client:Name(), 0, "Finished Workshift", true, true)
else
if (file["genericdata"].cohesionPoints) then
file["genericdata"].cohesionPoints = !file["genericdata"].combine and math.Clamp(file["genericdata"].cohesionPoints + points, 0, 200) or file["genericdata"].cohesionPoints + points
file["genericdata"].cohesionPointsDate = os.time()
else
file["genericdata"].socialCredits = !file["genericdata"].combine and math.Clamp(file["genericdata"].socialCredits + points, 0, 200) or file["genericdata"].socialCredits + points
file["genericdata"].socialCreditsDate = os.time()
end
PLUGIN:AddLog(client, file["datafilelogs"], file["genericdata"], client:Name(), points, "Finished Workshift", true, true)
PLUGIN:EditDatafile(client, file["genericdata"], true, true)
end
local couponCharacter = ix.char.loaded[genericID]
if couponCharacter and coupon != false then
if coupon == "BASIC" then
couponCharacter:SetPurchasedItems("coupon_basic", 1)
elseif coupon == "MEDIUM" then
couponCharacter:SetPurchasedItems("coupon_medium", 1)
else
couponCharacter:SetPurchasedItems("coupon_priority", 1)
end
end
end)
dataSelect:Execute()
end
end
SetNetVar("WorkshiftStarted", false)
end
function PLUGIN:PauseWorkshift(ent, client, bPaused)
ent.workshiftPaused = bPaused
end
function PLUGIN:SaveWorkshift(tSaved, ent)
ent.savedInfo = tSaved
end
function PLUGIN:CheckStartedWorkshift(ent)
if ent.workshiftStarted then return true end
return false
end
function PLUGIN:AddToWorkshift(client, idCard, genericData, ent)
if ent.workshiftPaused then
ent:SetDisplay(11)
ent:ReadyForAnother()
return false
end
if ent.participants[genericData.id] then
ent:AlreadyParticipated()
ent:ResetInfo()
return false
end
ent.participants[genericData.id] = {genericData.cid, genericData.name}
local pointsToday = 0
local queryObj = mysql:Select("ix_characters_data")
queryObj:Where("id", genericData.id)
queryObj:Where("key", "datafilelogs")
queryObj:Select("data")
queryObj:Callback(function(result)
if (!istable(result) or !result[1]) then return end
if !result[1].data then return end
for _, tLog in pairs(util.JSONToTable(result[1].data)) do
if tLog.points and tLog.points != 0 and tLog.date and isnumber(tLog.date) and os.date("%d/%m/%Y", tLog.date) == os.date("%d/%m/%Y") then
pointsToday = pointsToday + tLog.points
end
end
ent.participants[genericData.id][3] = pointsToday
end)
queryObj:Execute()
end