mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
141
gamemodes/darkrp/plugins/phone/cl_hooks.lua
Normal file
141
gamemodes/darkrp/plugins/phone/cl_hooks.lua
Normal file
@@ -0,0 +1,141 @@
|
||||
--[[
|
||||
| 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.targetedLandlineEndpointID = nil
|
||||
PLUGIN.targetedLandlinePBX = nil
|
||||
PLUGIN.targetedLandlineExt = nil
|
||||
PLUGIN.targetedLandlineName = nil
|
||||
|
||||
do
|
||||
surface.CreateFont("phoneMonoDebug", {
|
||||
font = "Consolas",
|
||||
size = 16,
|
||||
extended = true,
|
||||
weight = 1200
|
||||
})
|
||||
end
|
||||
|
||||
function PLUGIN:InitializedPlugins()
|
||||
local color = Color(255, 0, 255)
|
||||
local function drawConnectorESP(client, entity, x, y, factor)
|
||||
ix.util.DrawText(
|
||||
"Landline Phone",
|
||||
x,
|
||||
y - math.max(10, 32 * factor),
|
||||
color,
|
||||
TEXT_ALIGN_CENTER,
|
||||
TEXT_ALIGN_CENTER,
|
||||
nil,
|
||||
math.max(255 * factor, 80)
|
||||
)
|
||||
end
|
||||
|
||||
ix.observer:RegisterESPType("landline_phone", drawConnectorESP, "Landline Phone")
|
||||
end
|
||||
|
||||
net.Receive("EnterLandlineDial", function()
|
||||
PLUGIN.targetedLandlineEndpointID = net.ReadInt(15)
|
||||
PLUGIN.targetedLandlinePBX = net.ReadInt(5)
|
||||
PLUGIN.targetedLandlineExt = net.ReadInt(11)
|
||||
PLUGIN.targetedLandlineName = net.ReadString()
|
||||
PLUGIN.landlineEntIdx = net.ReadInt(17)
|
||||
|
||||
if (PLUGIN.panel) then
|
||||
LocalPlayer():Notify("You're currently using a phone!")
|
||||
else
|
||||
vgui.Create("ixLandlineDial")
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("ixConnectedCallStatusChange", function()
|
||||
local active = net.ReadBool()
|
||||
local inCall = net.ReadBool()
|
||||
|
||||
if (active) then
|
||||
PLUGIN.offHook = true
|
||||
end
|
||||
|
||||
if (active and inCall) then
|
||||
PLUGIN.otherSideActive = true
|
||||
PLUGIN.otherSideRinging = false
|
||||
PLUGIN.currentCallStatus = ""
|
||||
|
||||
net.Start("RunGetPeerName")
|
||||
net.SendToServer()
|
||||
|
||||
timer.Simple(0.25, function()
|
||||
-- wait for the vgui panel to come up (if we're picking up in this state)
|
||||
LocalPlayer():StopSound("landline_ringtone.wav")
|
||||
LocalPlayer():StopSound("landline_dialtone.wav")
|
||||
end)
|
||||
else
|
||||
PLUGIN.otherSideRinging = false
|
||||
PLUGIN.otherSideActive = false
|
||||
PLUGIN.currentCallStatus = "WAITING"
|
||||
PLUGIN.currentCallPeerName = "Unknown"
|
||||
|
||||
if (PLUGIN.panel) then
|
||||
LocalPlayer():StopSound("landline_dialtone.wav")
|
||||
LocalPlayer():EmitSound("landline_dialtone.wav", 40, 100, 1, CHAN_STATIC)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("OnGetPeerName", function()
|
||||
PLUGIN.currentCallPeerName = net.ReadString()
|
||||
end)
|
||||
|
||||
net.Receive("LineTestChat", function()
|
||||
local text = net.ReadString()
|
||||
local chatIcon = ix.util.GetMaterial("willardnetworks/chat/message_icon.png")
|
||||
local color = Color(105, 157, 178)
|
||||
local formattedText = string.format("[PHONE] %s: \"%s\"", "Line Test", text or "Error!")
|
||||
|
||||
if (ix.option.Get("standardIconsEnabled")) then
|
||||
chat.AddText(chatIcon, color, formattedText)
|
||||
else
|
||||
chat.AddText(color, formattedText)
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("LineStatusUpdate", function()
|
||||
PLUGIN.currentLineStatus = net.ReadString()
|
||||
if (PLUGIN.currentLineStatus ~= ix.phone.switch.DialStatus.Success and
|
||||
PLUGIN.currentLineStatus ~= ix.phone.switch.DialStatus.DebugMode) then
|
||||
|
||||
LocalPlayer():StopSound("landline_ringtone.wav")
|
||||
LocalPlayer():EmitSound("landline_dialtone.wav", 40, 100, 1, CHAN_STATIC)
|
||||
elseif (PLUGIN.currentLineStatus == ix.phone.switch.DialStatus.LineBusy) then
|
||||
LocalPlayer():EmitSound("landline_line_busy.wav", 40, 100, 1, CHAN_STATIC)
|
||||
|
||||
elseif (PLUGIN.currentLineStatus == ix.phone.switch.DialStatus.Success or
|
||||
PLUGIN.currentLineStatus == ix.phone.switch.DialStatus.DebugMode) then
|
||||
timer.Simple(0.25, function()
|
||||
-- wait for the vgui panel to come up (if we're picking up in this state)
|
||||
LocalPlayer():StopSound("landline_dialtone.wav")
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("ForceHangupLandlinePhone", function()
|
||||
if (PLUGIN.panel and PLUGIN.panel.Close) then
|
||||
PLUGIN.panel:Close()
|
||||
|
||||
PLUGIN.offHook = false
|
||||
PLUGIN.otherSideRinging = false
|
||||
PLUGIN.otherSideActive = false
|
||||
PLUGIN.currentCallStatus = "WAITING"
|
||||
PLUGIN.currentCallPeerName = "Unknown"
|
||||
|
||||
net.Start("RunHangupLandline")
|
||||
net.SendToServer()
|
||||
end
|
||||
end)
|
||||
321
gamemodes/darkrp/plugins/phone/derma/cl_landline.lua
Normal file
321
gamemodes/darkrp/plugins/phone/derma/cl_landline.lua
Normal file
@@ -0,0 +1,321 @@
|
||||
--[[
|
||||
| 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.offHook = false
|
||||
PLUGIN.otherSideRinging = false
|
||||
PLUGIN.otherSideActive = false
|
||||
PLUGIN.currentCallStatus = "WAITING"
|
||||
PLUGIN.currentCallPeerName = "Unknown"
|
||||
PLUGIN.currentLineStatus = ""
|
||||
|
||||
local dialSeq = {}
|
||||
local buttonMap = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#"}
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function dialSeq:insert(signal)
|
||||
self[#self+1] = signal
|
||||
end
|
||||
|
||||
function dialSeq:reset()
|
||||
for k, signal in ipairs(self) do
|
||||
self[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function dialSeq:asStr()
|
||||
local dialSeqStr = ""
|
||||
for _, signal in ipairs(self) do
|
||||
dialSeqStr = dialSeqStr..signal
|
||||
end
|
||||
return dialSeqStr
|
||||
end
|
||||
|
||||
function dialSeq:playDTMFTone(signal)
|
||||
local _signal = signal
|
||||
if (signal == "*") then _signal = "asterisk" end
|
||||
if (signal == "#") then _signal = "pound" end
|
||||
|
||||
surface.PlaySound("dtmftones/dtmfgen_".._signal..".wav")
|
||||
end
|
||||
|
||||
function PANEL:Init()
|
||||
PLUGIN.currentLineStatus = ""
|
||||
|
||||
if (IsValid(PLUGIN.panel)) then
|
||||
PLUGIN.panel:Remove()
|
||||
end
|
||||
|
||||
self:SetSize(500, 780)
|
||||
self:Center()
|
||||
self:CenterHorizontal(0.6)
|
||||
self:SetBackgroundBlur(false)
|
||||
self:SetDeleteOnClose(true)
|
||||
self:SetTitle(" ")
|
||||
self:ShowCloseButton(false)
|
||||
self:IsDraggable(true)
|
||||
|
||||
self.verStamp = self:Add("DLabel")
|
||||
self.verStamp:Dock(TOP)
|
||||
self.verStamp:DockMargin(0, 7, 55, 0)
|
||||
self.verStamp:SetFont("DermaDefaultBold")
|
||||
self.verStamp:SetHeight(30)
|
||||
self.verStamp:SetColor(Color(215, 240, 231))
|
||||
self.verStamp:SetText(L("UU pbxOS BETA v0.254ga - NODEID - "..tostring(PLUGIN.targetedLandlineEndpointID)))
|
||||
self.verStamp:SetContentAlignment(9)
|
||||
|
||||
self.status = self:Add("DLabel")
|
||||
self.status:Dock(TOP)
|
||||
self.status:DockMargin(0, -10, 0, 0)
|
||||
self.status:SetFont("DermaDefaultBold")
|
||||
self.status:SetHeight(30)
|
||||
self.status:SetColor(Color(215, 240, 231))
|
||||
local _connStatus = "DISCONNECTED!"
|
||||
local _curPBX = "N/A"
|
||||
if (PLUGIN.targetedLandlinePBX and PLUGIN.targetedLandlinePBX > 0) then
|
||||
_connStatus = "ACTIVE"
|
||||
_curPBX = "0"..tostring(PLUGIN.targetedLandlinePBX)
|
||||
end
|
||||
self.status:SetText(L("Connection Status: ".._connStatus))
|
||||
self.status:SetContentAlignment(5)
|
||||
|
||||
self.name = self:Add("DLabel")
|
||||
self.name:Dock(TOP)
|
||||
self.name:DockMargin(0, 4, 75, 0)
|
||||
self.name:SetText(L(tostring(PLUGIN.targetedLandlineName)))
|
||||
self.name:SetHeight(35)
|
||||
self.name:SetFont("CloseCaption_Bold")
|
||||
self.name:SetColor(Color(15, 13, 44, 220))
|
||||
self.name:SetContentAlignment(9)
|
||||
|
||||
self.pBX = self:Add("DLabel")
|
||||
self.pBX:Dock(TOP)
|
||||
self.pBX:DockMargin(75, 4, 0, 0)
|
||||
self.pBX:SetText(L("PBX :> ".._curPBX))
|
||||
self.pBX:SetHeight(35)
|
||||
self.pBX:SetFont("CloseCaption_Bold")
|
||||
self.pBX:SetColor(Color(15, 13, 44, 220))
|
||||
self.pBX:SetContentAlignment(7)
|
||||
|
||||
self.ext = self:Add("DLabel")
|
||||
self.ext:Dock(TOP)
|
||||
self.ext:DockMargin(75, 4, 0, 0)
|
||||
self.ext:SetText(L("EXT :> "..tostring(PLUGIN.targetedLandlineExt)))
|
||||
self.ext:SetHeight(35)
|
||||
self.ext:SetFont("CloseCaption_Bold")
|
||||
self.ext:SetColor(Color(15, 13, 44, 220))
|
||||
self.ext:SetContentAlignment(7)
|
||||
|
||||
self.dialSeqText = self:Add("DLabel")
|
||||
self.dialSeqText:Dock(TOP)
|
||||
self.dialSeqText:DockMargin(75, 4, 0, 0)
|
||||
self.dialSeqText:SetText(L("DIAL :> "))
|
||||
self.dialSeqText:SetHeight(50)
|
||||
self.dialSeqText:SetFont("CloseCaption_Bold")
|
||||
self.dialSeqText:SetColor(Color(15, 13, 44, 220))
|
||||
self.dialSeqText:SetContentAlignment(7)
|
||||
|
||||
local close = vgui.Create("DButton")
|
||||
close:SetText(L("close"))
|
||||
close:SetSize(70, 70)
|
||||
close.DoClick = function()
|
||||
dialSeq:playDTMFTone("#")
|
||||
self:Close()
|
||||
|
||||
PLUGIN.offHook = false
|
||||
PLUGIN.otherSideRinging = false
|
||||
PLUGIN.otherSideActive = false
|
||||
PLUGIN.currentCallStatus = "WAITING"
|
||||
PLUGIN.currentCallPeerName = "Unknown"
|
||||
|
||||
net.Start("RunHangupLandline")
|
||||
net.SendToServer()
|
||||
|
||||
LocalPlayer():StopSound("landline_ringtone.wav")
|
||||
LocalPlayer():StopSound("landline_dialtone.wav")
|
||||
end
|
||||
|
||||
local dial = vgui.Create("DButton")
|
||||
dial:SetText(L("Dial"))
|
||||
dial:SetColor(Color(0, 255, 0))
|
||||
dial:SetSize(70, 70)
|
||||
dial.DoClick = function()
|
||||
if (PLUGIN.otherSideRinging or PLUGIN.otherSideActive or
|
||||
PLUGIN.currentCallStatus ~= "WAITING") then
|
||||
return
|
||||
end
|
||||
|
||||
net.Start("BeginDialToPeer")
|
||||
net.WriteString(dialSeq:asStr())
|
||||
net.WriteInt(PLUGIN.targetedLandlinePBX, 5)
|
||||
net.WriteInt(PLUGIN.targetedLandlineExt, 11)
|
||||
net.SendToServer()
|
||||
|
||||
net.Start("LandlineKeyPress")
|
||||
net.WriteInt(PLUGIN.landlineEntIdx, 17)
|
||||
net.SendToServer()
|
||||
|
||||
PLUGIN.offHook = true
|
||||
PLUGIN.otherSideRinging = true
|
||||
PLUGIN.otherSideActive = false
|
||||
PLUGIN.currentCallStatus = "RINGING"
|
||||
|
||||
-- doing this instead of surface.PlaySound so we can stop it
|
||||
LocalPlayer():EmitSound("landline_ringtone.wav", 40, 100, 1, CHAN_STATIC)
|
||||
end
|
||||
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetText(L("Reset"))
|
||||
reset:SetColor(Color(255, 0, 0))
|
||||
reset:SetSize(70, 70)
|
||||
reset.DoClick = function()
|
||||
dialSeq:reset()
|
||||
dialSeq:playDTMFTone("0")
|
||||
self.dialSeqText:SetText(L("DIAL :> "))
|
||||
|
||||
net.Start("LandlineKeyPress")
|
||||
net.WriteInt(PLUGIN.landlineEntIdx, 17)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
self.optsGrid = self:Add("DGrid")
|
||||
self.optsGrid:SetPos(350, 400)
|
||||
self.optsGrid:SetCols(1)
|
||||
self.optsGrid:SetColWide(80)
|
||||
self.optsGrid:SetRowHeight(80)
|
||||
|
||||
self.optsGrid:AddItem(reset)
|
||||
self.optsGrid:AddItem(dial)
|
||||
self.optsGrid:AddItem(close)
|
||||
|
||||
self.numberGrid = self:Add("DGrid")
|
||||
self.numberGrid:SetPos(100, 400)
|
||||
self.numberGrid:SetCols(3)
|
||||
self.numberGrid:SetColWide(80)
|
||||
self.numberGrid:SetRowHeight(80)
|
||||
|
||||
for _, key in ipairs(buttonMap) do
|
||||
local button = vgui.Create("DButton")
|
||||
button:SetText(key)
|
||||
button:SetSize(70, 70)
|
||||
button:SetFont("DermaLarge")
|
||||
|
||||
button.DoClick = function()
|
||||
dialSeq:playDTMFTone(key)
|
||||
dialSeq:insert(key)
|
||||
self.dialSeqText:SetText(L("DIAL :> "..dialSeq:asStr()))
|
||||
|
||||
LocalPlayer():StopSound("landline_dialtone.wav")
|
||||
|
||||
net.Start("LandlineKeyPress")
|
||||
net.WriteInt(PLUGIN.landlineEntIdx, 17)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
self.numberGrid:AddItem(button)
|
||||
end
|
||||
|
||||
self:MakePopup()
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
PLUGIN.panel = self
|
||||
|
||||
LocalPlayer():EmitSound("landline_dialtone.wav", 40, 100, 1, CHAN_STATIC)
|
||||
end
|
||||
|
||||
function PANEL:OnRemove()
|
||||
PLUGIN.panel = nil
|
||||
dialSeq:reset()
|
||||
|
||||
LocalPlayer():StopSound("landline_dialtone.wav")
|
||||
LocalPlayer():StopSound("landline_line_busy.wav")
|
||||
end
|
||||
|
||||
-- YES I know this is a bit of a mess but, what can you do?? its DERMA
|
||||
function PANEL:Paint(w, h)
|
||||
-- background
|
||||
draw.RoundedBox(6, 0, 0, w, h, Color(35, 35, 45, 200))
|
||||
|
||||
surface.SetDrawColor(61, 61, 77, 255)
|
||||
surface.DrawOutlinedRect(0, 0, w, h, 2)
|
||||
|
||||
-- "screen"
|
||||
draw.RoundedBox(6, 60, 20, 390, 350, Color(215, 240, 231))
|
||||
-- outline
|
||||
surface.SetDrawColor(15, 13, 44, 255)
|
||||
surface.DrawOutlinedRect(65, 30, 380, 320, 4)
|
||||
|
||||
-- boxes:
|
||||
local drawOutlineBoxPair = function (x, y, w, h, thick, darker, black)
|
||||
surface.SetDrawColor(150, 150, 140, 100)
|
||||
if (darker) then
|
||||
surface.SetDrawColor(150, 150, 140, 150)
|
||||
end
|
||||
if (black) then
|
||||
surface.SetDrawColor(0, 0, 0, 255)
|
||||
end
|
||||
surface.DrawRect(x, y, w, h)
|
||||
surface.SetDrawColor(15, 13, 44, 255)
|
||||
surface.DrawOutlinedRect(x, y, w, h, thick)
|
||||
end
|
||||
-- top box
|
||||
drawOutlineBoxPair(65, 30, 376, 55, 3, false, true)
|
||||
-- name
|
||||
drawOutlineBoxPair(67, 85, 376, 38, 2)
|
||||
-- exchange
|
||||
drawOutlineBoxPair(67, 123, 376, 38, 2, true)
|
||||
-- ext
|
||||
drawOutlineBoxPair(67, 161, 376, 38, 2)
|
||||
-- dial
|
||||
drawOutlineBoxPair(67, 199, 376, 38, 2, true)
|
||||
-- status
|
||||
drawOutlineBoxPair(65, 295, 376, 55, 3, false, true)
|
||||
|
||||
-- line status text
|
||||
surface.SetFont("phoneMonoDebug")
|
||||
surface.SetTextColor(15, 13, 44, 220)
|
||||
local lineStatusHeight = 13
|
||||
local lineStatusLineNo = 1
|
||||
for lineStatusLine in string.gmatch(PLUGIN.currentLineStatus, "[^\n]+") do
|
||||
surface.SetTextPos(80, 227 + (lineStatusHeight * lineStatusLineNo))
|
||||
surface.DrawText(lineStatusLine)
|
||||
lineStatusLineNo = lineStatusLineNo + 1
|
||||
end
|
||||
|
||||
-- call status text (YES i know)
|
||||
surface.SetFont("CloseCaption_Normal")
|
||||
surface.SetTextColor(215, 240, 231, 255)
|
||||
surface.SetTextPos(75, 300)
|
||||
surface.DrawText("STATUS :> ")
|
||||
surface.SetFont("CloseCaption_Bold")
|
||||
if (PLUGIN.targetedLandlinePBX and PLUGIN.targetedLandlinePBX == 0) then
|
||||
surface.DrawText("NOT SET UP")
|
||||
else
|
||||
surface.DrawText(tostring(PLUGIN.currentCallStatus))
|
||||
end
|
||||
surface.SetTextPos(190, 300)
|
||||
if (PLUGIN.otherSideActive == true and PLUGIN.currentCallStatus == "") then
|
||||
surface.SetFont("CloseCaption_Normal")
|
||||
surface.DrawText(tostring(PLUGIN.currentCallPeerName) or "Unknown")
|
||||
surface.SetFont("CloseCaption_Bold")
|
||||
end
|
||||
|
||||
-- time text
|
||||
surface.SetTextColor(215, 240, 231, 255)
|
||||
surface.SetTextPos(70, 35)
|
||||
local ostime = os.time()
|
||||
surface.SetFont("DermaDefaultBold")
|
||||
surface.DrawText(os.date("%H:%M:%S", ostime))
|
||||
surface.SetTextPos(70, 50)
|
||||
surface.DrawText(ix.config.Get("day").."/"..ix.config.Get("month").."/"..ix.config.Get("year"))
|
||||
end
|
||||
|
||||
vgui.Register("ixLandlineDial", PANEL, "DFrame")
|
||||
@@ -0,0 +1,287 @@
|
||||
--[[
|
||||
| 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.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Landline Phone"
|
||||
ENT.Author = "M!NT"
|
||||
ENT.Category = "HL2 RP"
|
||||
ENT.Contact = ""
|
||||
ENT.Purpose = ""
|
||||
ENT.Instructions = ""
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = true
|
||||
ENT.Holdable = true
|
||||
ENT.offHook = false
|
||||
ENT.inUseBy = nil
|
||||
ENT.isRinging = false
|
||||
ENT.defaultRingTime = 60 -- how long the phone will ring (in seconds)
|
||||
ENT.endpointID = nil
|
||||
ENT.ringCallback = nil -- FnOnce that is called when the phone stops ringing for whatever reason
|
||||
ENT.hangUpCallback = nil -- FnOnce that is called when the user runs hang up during a call
|
||||
ENT.currentName = "Unknown" -- public name as stored currently in the PBX
|
||||
ENT.currentPBX = 0 -- PBX this entity is attached to
|
||||
ENT.currentExtension = nil -- extension in the PBX
|
||||
|
||||
function ENT:GetIndicatorPos()
|
||||
local btnPos = self:GetPos()
|
||||
|
||||
btnPos = btnPos + self:GetForward() * 4.3
|
||||
btnPos = btnPos + self:GetRight() * -1.1
|
||||
btnPos = btnPos + self:GetUp() * 2.0
|
||||
|
||||
return btnPos
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString("UpdateLandlineEntStatus")
|
||||
util.AddNetworkString("EnterLandlineDial")
|
||||
util.AddNetworkString("ForceHangupLandlinePhone")
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/props/cs_office/phone.mdl")
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableMotion(true)
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
self.endpointID = ix.phone.switch.endpoints:Register(self)
|
||||
self.currentExtension = math.random(100, 999)
|
||||
|
||||
local usrCheckTimerName = "LandlineEnt"..tostring(self:EntIndex()).."UserCheck"
|
||||
timer.Create(usrCheckTimerName, 3, 0, function()
|
||||
-- check to see if, for some reason, inUseBy is still set but the usr is gone
|
||||
-- if so, use the magical powers of lua to hang ourselves up
|
||||
if (IsValid(self.inUseBy) and self.inUseBy:IsPlayer()) then
|
||||
local plys = ix.phone.switch.endpoints:GetPlayersInRadius(self.endpointID, 30)
|
||||
if (!plys or table.Count(plys) < 1 or
|
||||
!IsValid(plys[self.inUseBy:SteamID64()])) then
|
||||
|
||||
net.Start("ForceHangupLandlinePhone")
|
||||
net.Send(self.inUseBy)
|
||||
|
||||
self:HangUp()
|
||||
end
|
||||
else
|
||||
-- we shouldn't be offHook if we dont have inUseBy set
|
||||
if (!IsValid(self.inUseBy) and self.offHook) then
|
||||
self:HangUp()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
self:CallOnRemove("OnRemoveLandlineCleanup", function(ent)
|
||||
if (self.currentExtension and self.currentPBX) then
|
||||
return
|
||||
end
|
||||
|
||||
local connID = ix.phone.switch:GetActiveConnection(self.currentPBX,
|
||||
self.currentExtension)
|
||||
|
||||
if (connID) then
|
||||
ix.phone.switch:Disconnect(connID)
|
||||
end
|
||||
|
||||
timer.Remove(usrCheckTimerName)
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:PerformPickup(client)
|
||||
if timer.Exists("ixCharacterInteraction" .. client:SteamID()) then return end
|
||||
|
||||
client:PerformInteraction(.5, self, function(_)
|
||||
client:GetCharacter():GetInventory():Add("landline_phone")
|
||||
self:Remove()
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:Use(activator)
|
||||
if (self.nextUse and self.nextUse > CurTime()) then
|
||||
return
|
||||
end
|
||||
|
||||
self.nextUse = CurTime() + 1
|
||||
|
||||
if (activator:GetMoveType() == MOVETYPE_FLY) then
|
||||
return self:PerformPickup(activator)
|
||||
end
|
||||
|
||||
if (!self.offHook) then
|
||||
-- User is trying to pick up the phone
|
||||
self.inUseBy = activator
|
||||
|
||||
self:SetModel("models/props/cs_office/phone_p1.mdl")
|
||||
|
||||
ix.phone.switch:SetCharVars(self.inUseBy:GetCharacter(),
|
||||
true, self.currentPBX, self.currentExtension)
|
||||
|
||||
ix.phone.switch.endpoints:AddListener(self.endpointID, self.inUseBy)
|
||||
|
||||
if (self.isRinging) then
|
||||
timer.Remove("PhoneRinging"..self.endpointID)
|
||||
self:StopSound("landline_ringtone.wav")
|
||||
|
||||
self.isRinging = false
|
||||
self:broadcastStatusOnChange()
|
||||
|
||||
local _, _ = pcall(self.ringCallback, true)
|
||||
self.ringCallback = nil
|
||||
end
|
||||
|
||||
self:EmitSound("landline_hangup.wav", 60, 100, 1, CHAN_STATIC)
|
||||
|
||||
timer.Simple(0.1, function() -- dont ask me why we have to wait one frame. we just do. thanks garry
|
||||
self.offHook = true
|
||||
net.Start("EnterLandlineDial")
|
||||
net.WriteInt(tonumber(self.endpointID), 15)
|
||||
net.WriteInt(tonumber(self.currentPBX), 5)
|
||||
net.WriteInt(tonumber(self.currentExtension), 11)
|
||||
net.WriteString(self.currentName)
|
||||
net.WriteInt(self:EntIndex(), 17)
|
||||
net.Send(self.inUseBy)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:EnterRing(callback)
|
||||
-- this entity getting 'called'
|
||||
self:EmitSound("landline_ringtone.wav", 75, 100, 1, CHAN_STATIC)
|
||||
self.isRinging = true
|
||||
self.ringCallback = callback
|
||||
|
||||
self:broadcastStatusOnChange()
|
||||
|
||||
timer.Create("PhoneRinging"..self.endpointID, self.defaultRingTime, 1, function ()
|
||||
-- phone has rung too long
|
||||
self.isRinging = false
|
||||
self.offHook = false
|
||||
self:broadcastStatusOnChange()
|
||||
|
||||
local _, _ = pcall(self.ringCallback, false)
|
||||
self.ringCallback = nil
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:hangupDuringRing()
|
||||
if (!self.isRinging or !timer.Exists("PhoneRinging"..self.endpointID)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
timer.Remove("PhoneRinging"..self.endpointID)
|
||||
self:StopSound("landline_ringtone.wav")
|
||||
self:EmitSound("landline_hangup.wav", 60, 100, 1, CHAN_STATIC)
|
||||
|
||||
self.isRinging = false
|
||||
self.offHook = false
|
||||
self:broadcastStatusOnChange()
|
||||
|
||||
local _, _ = pcall(self.ringCallback, false)
|
||||
end
|
||||
|
||||
function ENT:hangupDuringOffHook()
|
||||
self:EmitSound("landline_hangup.wav", 60, 100, 1, CHAN_STATIC)
|
||||
if (self.inUseBy) then
|
||||
ix.phone.switch:ResetCharVars(self.inUseBy:GetCharacter())
|
||||
|
||||
ix.phone.switch.endpoints:RmListener(self.endpointID, self.inUseBy)
|
||||
end
|
||||
|
||||
self.offHook = false
|
||||
|
||||
self:broadcastStatusOnChange()
|
||||
if (self.hangUpCallback) then
|
||||
local _, _ = pcall(self.hangUpCallback)
|
||||
self.hangUpCallback = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ButtonPress()
|
||||
-- play a button clack sound because atle wants it
|
||||
local soundName = "landline_clack_"..tostring(math.random(1, 4))..".wav"
|
||||
self:EmitSound(soundName, 50, 100, 1, CHAN_STATIC)
|
||||
end
|
||||
|
||||
function ENT:HangUp()
|
||||
self:SetModel("models/props/cs_office/phone.mdl")
|
||||
|
||||
if (!self.isRinging and !self.offHook) then
|
||||
self:EmitSound("landline_hangup.wav", 70, 100, 1, CHAN_STATIC)
|
||||
return
|
||||
end
|
||||
|
||||
if (self.offHook) then
|
||||
self:hangupDuringOffHook()
|
||||
end
|
||||
|
||||
if (self.isRinging) then
|
||||
self:hangupDuringRing()
|
||||
end
|
||||
|
||||
self.inUseBy = nil
|
||||
end
|
||||
|
||||
function ENT:broadcastStatusOnChange()
|
||||
net.Start("UpdateLandlineEntStatus")
|
||||
net.WriteBool(self.isRinging)
|
||||
net.WriteBool(self.offHook)
|
||||
net.WriteInt(self.currentPBX, 11)
|
||||
net.WriteInt(self.currentExtension, 15)
|
||||
net.Broadcast()
|
||||
end
|
||||
else
|
||||
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
|
||||
local colorGreen = Color(0, 255, 0, 255)
|
||||
local colorRed = Color(255, 50, 50, 255)
|
||||
local isRinging = false
|
||||
local offHook = false
|
||||
local nextFlashTime = CurTime()
|
||||
|
||||
net.Receive("UpdateLandlineEntStatus", function()
|
||||
isRinging = net.ReadBool()
|
||||
offHook = net.ReadBool()
|
||||
|
||||
-- reset the indicator status flashing
|
||||
colorRed.a = 255
|
||||
if (isRinging) then
|
||||
nextFlashTime = CurTime() + 1
|
||||
end
|
||||
end)
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
|
||||
local btnPos = self:GetIndicatorPos()
|
||||
|
||||
render.SetMaterial(glowMaterial)
|
||||
|
||||
if (isRinging) then
|
||||
-- slow flash
|
||||
if (CurTime() > nextFlashTime) then
|
||||
colorRed.a = 255
|
||||
if (CurTime() > nextFlashTime + 0.5) then
|
||||
nextFlashTime = CurTime() + 0.5
|
||||
end
|
||||
else
|
||||
colorRed.a = 0
|
||||
end
|
||||
render.DrawSprite(btnPos, 1, 1, colorRed)
|
||||
elseif (offHook) then
|
||||
render.DrawSprite(btnPos, 1, 1, colorRed)
|
||||
else
|
||||
render.DrawSprite(btnPos, 1, 1, colorGreen)
|
||||
end
|
||||
end
|
||||
end
|
||||
48
gamemodes/darkrp/plugins/phone/items/phone/sh_landline.lua
Normal file
48
gamemodes/darkrp/plugins/phone/items/phone/sh_landline.lua
Normal file
@@ -0,0 +1,48 @@
|
||||
--[[
|
||||
| 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 = "Landline Phone"
|
||||
ITEM.model = Model("models/props/cs_office/phone.mdl")
|
||||
ITEM.description = "A simple landline phone."
|
||||
ITEM.width = 2
|
||||
ITEM.height = 2
|
||||
ITEM.category = "Phones"
|
||||
ITEM.functions.Deploy = {
|
||||
name = "Deploy",
|
||||
OnRun = function(itemTable)
|
||||
local client = itemTable.player
|
||||
if client.CantPlace then
|
||||
client:NotifyLocalized("You need to wait before you can place this!")
|
||||
return false
|
||||
end
|
||||
|
||||
client.CantPlace = true
|
||||
|
||||
timer.Simple(3, function()
|
||||
if client then
|
||||
client.CantPlace = false
|
||||
end
|
||||
end)
|
||||
|
||||
local phone = ents.Create("landline_phone")
|
||||
local tr = client:GetEyeTrace()
|
||||
local dist = client:EyePos():Distance(tr.HitPos)
|
||||
|
||||
phone:SetPos(client:EyePos() + (tr.Normal * math.Clamp(dist, 0, 75)))
|
||||
phone:Spawn()
|
||||
|
||||
ix.saveEnts:SaveEntity(phone)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
198
gamemodes/darkrp/plugins/phone/libs/sv_connections.lua
Normal file
198
gamemodes/darkrp/plugins/phone/libs/sv_connections.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
--[[
|
||||
| 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.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
-- a volatile table for caching ongoing connections
|
||||
ix.phone.switch.connections = ix.phone.switch.connections or {}
|
||||
|
||||
function ix.phone.switch:ConnectionValid(connID)
|
||||
if (self.connections[connID] == false) then
|
||||
return false
|
||||
end
|
||||
|
||||
return istable(self.connections[connID])
|
||||
end
|
||||
|
||||
function ix.phone.switch:buildNewConnectionNode(connID, extID, extNum)
|
||||
-- helper function to create source requests for connections
|
||||
-- constructs a table that can be used by ix.phone.switch:connect()
|
||||
if (!self:ConnectionValid(connID)) then
|
||||
return
|
||||
end
|
||||
|
||||
if (!self.connections[connID].nodes) then
|
||||
self.connections[connID].nodes = {}
|
||||
end
|
||||
|
||||
local nodeID = #self.connections[connID].nodes + 1
|
||||
self.connections[connID].nodes[nodeID] = {}
|
||||
self.connections[connID].nodes[nodeID]["exchange"] = extID
|
||||
self.connections[connID].nodes[nodeID]["extension"] = extNum
|
||||
end
|
||||
|
||||
function ix.phone.switch:buildNewConnection()
|
||||
-- helper function to that creates a new connection
|
||||
|
||||
-- attempt to reuse a freshly terminated connection
|
||||
for id, conn in ipairs(self.connections) do
|
||||
if (conn == false) then
|
||||
self.connections[id] = {}
|
||||
return id
|
||||
end
|
||||
end
|
||||
|
||||
-- no terminated connections
|
||||
connectionID = #self.connections + 1
|
||||
self.connections[connectionID] = {}
|
||||
|
||||
return connectionID
|
||||
end
|
||||
|
||||
function ix.phone.switch:Disconnect(connID, noNotify)
|
||||
-- disconnects provided connection at connID
|
||||
-- if notify is set, then it wont notify listeners that the connection is terminated
|
||||
if (!istable(self.connections[connID])) then
|
||||
return
|
||||
end
|
||||
|
||||
local _nodes = self.connections[connID].nodes
|
||||
for _, node in ipairs(_nodes) do
|
||||
local recievers = self:getReceivers(node.exchange, node.extension)
|
||||
|
||||
if (!istable(recievers) or table.Count(recievers) < 1) then
|
||||
continue
|
||||
end
|
||||
|
||||
for _, reciever in ipairs(recievers) do
|
||||
local ent = self.endpoints:GetEndpoint(reciever.endID)
|
||||
if (ent and ent.HangUp and ent.isRinging) then
|
||||
ent:HangUp()
|
||||
end
|
||||
end
|
||||
|
||||
local listeners = self:getListenersFromRecvs(recievers)
|
||||
|
||||
if (!listeners or table.Count(listeners) < 1) then
|
||||
continue
|
||||
end
|
||||
|
||||
for _, listener in ipairs(listeners) do
|
||||
self:DisconnectClient(listener)
|
||||
end
|
||||
end
|
||||
|
||||
self.connections[connID] = false
|
||||
end
|
||||
|
||||
-- disconnects the client's status and notifies them of said status change
|
||||
-- IMPORTANT: Make sure you destroy the connection too!
|
||||
function ix.phone.switch:DisconnectClient(client)
|
||||
if (!client or !IsValid(client)) then
|
||||
return ErrorNoHaltWithStack("Attempt to disconnect invalid client "..tostring(client))
|
||||
end
|
||||
|
||||
local character = client:GetCharacter()
|
||||
if (!istable(character)) then
|
||||
return ErrorNoHaltWithStack("Attempt to disconnect client with invalid character "..tostring(character))
|
||||
end
|
||||
|
||||
self:ResetCharVars(character)
|
||||
self:NotifyStatusChange(client, false, false)
|
||||
end
|
||||
|
||||
function ix.phone.switch:NotifyStatusChange(client, bCallActive, bInCall)
|
||||
net.Start("ixConnectedCallStatusChange")
|
||||
net.WriteBool(bCallActive)
|
||||
net.WriteBool(bInCall)
|
||||
net.Send(client)
|
||||
end
|
||||
|
||||
function ix.phone.switch:NotifyAllListenersOfStatusChange(endID, bCallActive, bInCall)
|
||||
local listeners = self.endpoints:GetListeners(endID)
|
||||
if (!listeners or table.Count(listeners) < 1) then
|
||||
return -- no need to do anything; no listeners
|
||||
end
|
||||
|
||||
for _, listener in ipairs(listeners) do
|
||||
-- notify all listeners of their call status change
|
||||
self:NotifyStatusChange(listener, bCallActive, bInCall)
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch:getListenersFromRecvs(recievers)
|
||||
local listeners = {}
|
||||
for k, recv in ipairs(recievers) do
|
||||
-- there will almost always be one reciever.. but treating this as a list in case we ever do 'conference calls'
|
||||
local _listeners = self.endpoints:GetListeners(recv.endID)
|
||||
if (istable(_listeners)) then
|
||||
for _, listener in ipairs(_listeners) do
|
||||
listeners[table.Count(listeners) + 1] = listener
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return listeners
|
||||
end
|
||||
|
||||
function ix.phone.switch:getReceivers(extID, extNum)
|
||||
local conn = self:GetActiveConnection(extID, extNum)
|
||||
if (!istable(conn)) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:getSourceRecieversFromConnection(conn.targetConnID,
|
||||
conn.sourceNodeID)
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetListeners(extID, extNum)
|
||||
return self:getListenersFromRecvs(self:getReceivers(extID, extNum))
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetReceivers(extID, extNum)
|
||||
local conn = self:GetActiveConnection(extID, extNum)
|
||||
if (!istable(conn)) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:getSourceRecieversFromConnection(conn.targetConnID,
|
||||
conn.sourceNodeID)
|
||||
end
|
||||
|
||||
-- returns the active connection in the form of {"targetConnID", "sourceNodeID"} if one is present
|
||||
function ix.phone.switch:GetActiveConnection(extID, extNum)
|
||||
for connID, conn in ipairs(self.connections) do
|
||||
if (conn == false) then
|
||||
continue
|
||||
end
|
||||
|
||||
for nodeID, node in ipairs(conn.nodes) do
|
||||
if (node["exchange"] == extID and node["extension"] == extNum) then
|
||||
-- source is present in this connection
|
||||
return {targetConnID = connID, sourceNodeID = nodeID}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- returns the actively connected (except for the source) recievers for a given connection
|
||||
function ix.phone.switch:getSourceRecieversFromConnection(connID, sourceNodeID)
|
||||
local res = {}
|
||||
for nodeID, node in ipairs(self.connections[connID].nodes) do
|
||||
if (nodeID != sourceNodeID) then
|
||||
-- we want to return this as it exists in the exchange as that will give us
|
||||
-- extra details the node tree does not contain such as name and endID
|
||||
res[#res + 1] = self:GetDest(node["exchange"], node["extension"])
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
123
gamemodes/darkrp/plugins/phone/libs/sv_endpoints.lua
Normal file
123
gamemodes/darkrp/plugins/phone/libs/sv_endpoints.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
--[[
|
||||
| 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.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
-- a flat list of all the entities. each entity has an associated 'listeners' table which contains all of the players actively connected to that entity
|
||||
ix.phone.switch.endpoints = ix.phone.switch.endpoints or {}
|
||||
|
||||
function ix.phone.switch.endpoints:exists(id)
|
||||
return self[id] != nil
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:entExists(entIdx)
|
||||
for id, ent in ipairs(self) do
|
||||
if (entIdx == ent:EntIndex()) then
|
||||
return id
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:Register(ent)
|
||||
-- assigns an ID. if the ent already exists then it will return the existing id
|
||||
-- we need to have our own ID here rather than the index because the entity index might change but
|
||||
-- in that case the id shouldn't
|
||||
|
||||
local entExists = self:entExists(ent:EntIndex())
|
||||
if (entExists != nil) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local newID = math.random(1000, 9999)
|
||||
if (self:exists(newID)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
self[newID] = ent
|
||||
return newID
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:DeRegister(id)
|
||||
self[id] = nil
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:GetEndpoint(id)
|
||||
-- returns the associated entity table
|
||||
if (self:exists(id)) then
|
||||
return self[id]
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:AddListener(id, client)
|
||||
if (!istable(self[id].listeners)) then
|
||||
self[id].listeners = {}
|
||||
end
|
||||
|
||||
for _, listener in ipairs(self[id].listeners) do
|
||||
if (listener == client) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self[id].listeners[table.Count(self[id].listeners) + 1] = client
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:RmListener(id, client)
|
||||
if (!istable(self[id].listeners)) then
|
||||
return
|
||||
end
|
||||
|
||||
for k, listener in ipairs(self[id].listeners) do
|
||||
if (listener == client) then
|
||||
self[id].listeners[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:GetListeners(id)
|
||||
return self[id].listeners
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:RingEndpoint(id, callback)
|
||||
-- rings and endpoint and, if the phone is picked up, it will call callback as true. otherwise false
|
||||
-- if the destination is unavailable or busy then it will return nil
|
||||
local ent = self:GetEndpoint(id)
|
||||
|
||||
if (ent.inUse or ent.isRinging) then
|
||||
return nil
|
||||
end
|
||||
|
||||
ent:EnterRing(callback)
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:GetPlayersInRadiusFromPos(pos, radius)
|
||||
local entsInside = ents.FindInSphere(pos, radius)
|
||||
local res = {}
|
||||
|
||||
for _, _ent in ipairs(entsInside) do
|
||||
if (_ent:IsPlayer() and _ent.GetCharacter and _ent:GetCharacter()) then
|
||||
res[_ent:SteamID64()] = _ent
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
-- returns a list of players within X radius of the endpoint
|
||||
function ix.phone.switch.endpoints:GetPlayersInRadius(id, radius)
|
||||
local ent = self:GetEndpoint(id)
|
||||
if (!ent) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:GetPlayersInRadiusFromPos(ent:GetPos(), radius)
|
||||
end
|
||||
100
gamemodes/darkrp/plugins/phone/libs/sv_exchange.lua
Normal file
100
gamemodes/darkrp/plugins/phone/libs/sv_exchange.lua
Normal file
@@ -0,0 +1,100 @@
|
||||
--[[
|
||||
| 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.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
-- a table used for managing pbxs and their members
|
||||
ix.phone.switch.exchanges = ix.phone.switch.exchanges or {}
|
||||
|
||||
--[[ The following is some boiler plate code for creating and managing extensions and exchanges
|
||||
In practice these things are just keys in a table and in the DB but it is probably best
|
||||
if you use the functions here and not directly modify ix.phone.switch.exchanges directly!
|
||||
|
||||
This is necessary to keep the switching code readable
|
||||
]]
|
||||
function ix.phone.switch:AddExchange(exID)
|
||||
if (self:ExchangeExists(exID)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID] = {}
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:RmExchange(exID)
|
||||
if (!self:ExchangeExists(exID)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:ExchangeExists(exID)
|
||||
return self.exchanges[exID] != nil
|
||||
end
|
||||
|
||||
function ix.phone.switch:DestExists(exID, extNum)
|
||||
if (self.exchanges[exID] != nil) then
|
||||
return self.exchanges[exID][extNum] != nil
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch:AddDest(exID, extNum, extName, endID)
|
||||
-- returns false if destination exists or exchange doesn't
|
||||
-- set noDB if you do not wish to store this destination to the database
|
||||
if (self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID][extNum] = {}
|
||||
self.exchanges[exID][extNum]["name"] = extName or ""
|
||||
self.exchanges[exID][extNum]["endID"] = endID
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetDest(exID, extNum)
|
||||
if (!self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
return self.exchanges[exID][extNum]
|
||||
end
|
||||
|
||||
function ix.phone.switch:RmDest(exID, extNum)
|
||||
-- returns false if destination does not exist
|
||||
if (!self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID][extNum] = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:MvDest(fromExID, fromExtNum, toExID, toExtNum)
|
||||
if (!self:RmDest(fromExID, fromExtNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
return self:AddDest(toExID, toExtNum)
|
||||
end
|
||||
|
||||
function ix.phone.switch:SetName(exID, extNum, name)
|
||||
if (!self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.endpoints[self.exchanges[exID][extNum]["endID"]].currentName = name
|
||||
return true
|
||||
end
|
||||
402
gamemodes/darkrp/plugins/phone/libs/sv_switch.lua
Normal file
402
gamemodes/darkrp/plugins/phone/libs/sv_switch.lua
Normal file
@@ -0,0 +1,402 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- this is a loose implementation of a virtual private business exchange (vPBX)
|
||||
ix.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
ix.phone.switch.lineTestPBX = 9
|
||||
ix.phone.switch.lineTestExt = 999 -- reserved for testing
|
||||
|
||||
do
|
||||
-- set up ent to use for 2 way call testing
|
||||
timer.Simple(10, function()
|
||||
local lineTestEnt = ents.Create("landline_phone")
|
||||
lineTestEnt:SetPos(Vector(0, 0, 0))
|
||||
lineTestEnt:Spawn()
|
||||
lineTestEnt:SetNoDraw(true)
|
||||
-- if we dont do this then our landline point ent will fall through the world
|
||||
-- and get deleted
|
||||
local _phys = lineTestEnt:GetPhysicsObject()
|
||||
_phys:EnableGravity(false)
|
||||
_phys:EnableMotion(false)
|
||||
_phys:Sleep()
|
||||
|
||||
lineTestEnt.currentName = "Line Test"
|
||||
lineTestEnt.currentPBX = ix.phone.switch.lineTestPBX
|
||||
lineTestEnt.currentExtension = ix.phone.switch.lineTestExt
|
||||
|
||||
-- yes we need a real entity for this. doesn't have to be a landline but might as well
|
||||
ix.phone.switch.lineTestEnt = lineTestEnt
|
||||
end)
|
||||
end
|
||||
|
||||
-- (optional)
|
||||
-- takes in a dial sequence in the format of (exchange)(extension)
|
||||
-- ex: 1 234
|
||||
-- it returns it into a table as {"exchange", "extension"}
|
||||
function ix.phone.switch:decodeSeq(dialSeq)
|
||||
-- dial sequences must be strings, but must be a real number as well and must be 4 digits
|
||||
if (type(dialSeq) != "string" or tonumber(dialSeq) == nil) then
|
||||
return nil
|
||||
elseif (string.len(dialSeq) > 4 or string.len(dialSeq) < 3) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local exchange = nil
|
||||
if (string.len(dialSeq) != 3) then -- otherwise it is a local dial (to endpoint in own exchange)
|
||||
exchange = tonumber(string.sub(dialSeq, 0, 1))
|
||||
if (exchange == nil or exchange < 1) then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- the remaining digits should be the extension
|
||||
local ext = tonumber(string.sub(dialSeq, 2, 4))
|
||||
if (ext == nil or ext < 1) then
|
||||
return nil
|
||||
end
|
||||
|
||||
return {["exchange"] = exchange, ["extension"] = ext}
|
||||
end
|
||||
|
||||
function ix.phone.switch:BuildNewTwoWayConnection(sourceExc, sourceExt, destExc, destExt)
|
||||
local connID = self:buildNewConnection()
|
||||
self:buildNewConnectionNode(connID, sourceExc, sourceExt)
|
||||
self:buildNewConnectionNode(connID, destExc, destExt)
|
||||
|
||||
return connID
|
||||
end
|
||||
|
||||
function ix.phone.switch:Dial(sourceExc, sourceExt, dialSeq)
|
||||
if (!self:DestExists(sourceExc, sourceExt)) then
|
||||
return self.DialStatus.SourceNotExist
|
||||
end
|
||||
|
||||
--[[
|
||||
Decode the user provided dial sequence into a switchable pair of of pbx and ext
|
||||
]]
|
||||
if (!istable(dialSeq) and #dialSeq < 1) then
|
||||
return self.DialStatus.NoDialSeq
|
||||
end
|
||||
|
||||
local decodedDest = self:decodeSeq(dialSeq)
|
||||
|
||||
if (!istable(decodedDest)) then
|
||||
return self.DialStatus.CannotDecodeDial
|
||||
end
|
||||
|
||||
if (decodedDest.exchange == self.lineTestPBX and decodedDest.extension == self.lineTestExt) then
|
||||
self:StartLineTest(sourceExc, sourceExt)
|
||||
return self.DialStatus.DebugMode
|
||||
end
|
||||
|
||||
if (decodedDest.exchange == nil) then
|
||||
decodedDest.exchange = sourceExc
|
||||
end
|
||||
|
||||
if (!self:DestExists(decodedDest.exchange, decodedDest.extension)) then
|
||||
return self.DialStatus.NumberNotFound
|
||||
end
|
||||
|
||||
--[[
|
||||
Get the endpoint IDs and corresponding entities for source & destination
|
||||
]]
|
||||
local destination = self:GetDest(decodedDest.exchange, decodedDest.extension)
|
||||
local source = self:GetDest(sourceExc, sourceExt)
|
||||
|
||||
if (!destination.endID or !source.endID) then
|
||||
return self.DialStatus.EndpointNotFound
|
||||
end
|
||||
|
||||
local destEnt = self.endpoints:GetEndpoint(tonumber(destination.endID))
|
||||
local sourceEnt = self.endpoints:GetEndpoint(tonumber(source.endID))
|
||||
|
||||
--[[
|
||||
Check if the line is busy
|
||||
]]
|
||||
local _conn = self:GetActiveConnection(decodedDest.exchange, decodedDest.extension)
|
||||
if (_conn and istable(_conn) or destEnt.offHook) then
|
||||
return self.DialStatus.LineBusy
|
||||
end
|
||||
|
||||
--[[
|
||||
Build new connection for source & dest with the pbxs and exts.
|
||||
]]
|
||||
local connID = self:BuildNewTwoWayConnection(sourceExc, sourceExt,
|
||||
decodedDest.exchange, decodedDest.extension)
|
||||
|
||||
--[[
|
||||
Setup the callbacks and start the call
|
||||
]]
|
||||
local ringCallback = function(status)
|
||||
if (!status) then -- call did not go through so we need to clean up
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
self:NotifyAllListenersOfStatusChange(tonumber(destination.endID), status, status)
|
||||
self:NotifyAllListenersOfStatusChange(tonumber(source.endID), status, status)
|
||||
end
|
||||
|
||||
destEnt:EnterRing(ringCallback) -- set the target as ringing
|
||||
|
||||
local hangUpCallback = function(status)
|
||||
-- cleanup
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
destEnt.hangUpCallback = hangUpCallback
|
||||
sourceEnt.hangUpCallback = hangUpCallback
|
||||
|
||||
return self.DialStatus.Success
|
||||
end
|
||||
|
||||
-- returns back a list of player entities that are listening to the phone this character is speaking into
|
||||
function ix.phone.switch:GetCharacterActiveListeners(character)
|
||||
if (!istable(character)) then
|
||||
return
|
||||
end
|
||||
|
||||
local connMD = character:GetLandlineConnection()
|
||||
if (!connMD) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:GetListeners(connMD.exchange, connMD.extension)
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetPlayerActiveListeners(client)
|
||||
local character = client:GetCharacter()
|
||||
if (!istable(character)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
return self:GetCharacterActiveListeners(character)
|
||||
end
|
||||
|
||||
-- rudely hangs up every single active call related to this character
|
||||
-- typically used when the player disconnects or switches chars mid call
|
||||
function ix.phone.switch:DisconnectActiveCallIfPresentOnClient(client)
|
||||
local character = client:GetCharacter()
|
||||
if (!istable(character)) then
|
||||
return
|
||||
end
|
||||
|
||||
local connMD = character:GetLandlineConnection()
|
||||
if (!istable(connMD) and !connMD["active"]) then
|
||||
-- probably ran hangup on a phone someone else was speaking on
|
||||
-- we should allow this in the future (maybe?) but for now we exit
|
||||
client:NotifyLocalized("You are not speaking on the phone.")
|
||||
return
|
||||
end
|
||||
|
||||
-- terminate any existing connections here
|
||||
local conn = self:GetActiveConnection(connMD["exchange"], connMD["extension"])
|
||||
if (!istable(conn)) then
|
||||
client:NotifyLocalized("Error: AttemptedHangupOnActivePhoneNoConn")
|
||||
-- This shouldn't be possible but if it happens then there is some lingering issue with
|
||||
-- this character's var being active when they are not in an active connection
|
||||
self:ResetCharVars(character)
|
||||
return
|
||||
end
|
||||
|
||||
self:Disconnect(conn["targetConnID"])
|
||||
end
|
||||
|
||||
-- returns whether or not the 'listener' is in an active phone call with 'speaker'
|
||||
function ix.phone.switch:ListenerCanHearSpeaker(speaker, listener)
|
||||
local speakerChar = speaker:GetCharacter()
|
||||
local listeners = self:GetCharacterActiveListeners(speakerChar)
|
||||
if (!istable(listeners)) then
|
||||
-- doubly make sure that the call activity is set correctly on the caller
|
||||
speaker:NotifyLocalized("You are not currently on a phone call!")
|
||||
ErrorNoHaltWithStack("Speaker ("..tostring(speaker:GetName())..") has invalid listener list!")
|
||||
self:ResetCharVars(speakerChar)
|
||||
return false
|
||||
end
|
||||
|
||||
for _, _listener in ipairs(listeners) do
|
||||
if (_listener == listener) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
Some helpers for setting the correct things in the correct order
|
||||
]]
|
||||
|
||||
-- Reset ix.character.landlineConnection variables to default state
|
||||
function ix.phone.switch:ResetCharVars(character)
|
||||
character:SetLandlineConnection({
|
||||
active = false,
|
||||
exchange = nil,
|
||||
extension = nil
|
||||
})
|
||||
end
|
||||
|
||||
-- Set ix.character.landlineConnection variables
|
||||
function ix.phone.switch:SetCharVars(character, bActive, exc, ext)
|
||||
character:SetLandlineConnection({
|
||||
active = bActive,
|
||||
exchange = exc,
|
||||
extension = ext
|
||||
})
|
||||
end
|
||||
|
||||
-- Create a fake destination for testing purposes
|
||||
-- Do nothing if one exists already
|
||||
function ix.phone.switch:initLineTestNumber()
|
||||
if (!self:ExchangeExists(self.lineTestPBX)) then
|
||||
self:AddExchange(self.lineTestPBX)
|
||||
end
|
||||
|
||||
if (!self.lineTestEnt.endpointID) then
|
||||
self.lineTestEnt.endpointID = self.endpoints:Register(self.lineTestEnt)
|
||||
print("Line Test Initalized! EndID: "..tostring(self.lineTestEnt.endpointID))
|
||||
end
|
||||
|
||||
local destination = self:GetDest(self.lineTestPBX, self.lineTestExt)
|
||||
if (!destination) then
|
||||
self:AddDest(self.lineTestPBX, self.lineTestExt, "Line Test", self.lineTestEnt.endpointID)
|
||||
end
|
||||
end
|
||||
|
||||
-- used for debugging purposes (by doing lua_run in rcon)
|
||||
-- calls a specific landline
|
||||
function ix.phone.switch:DebugSinglePartyCall(exchange, ext)
|
||||
if (!self:DestExists(exchange, ext)) then
|
||||
ErrorNoHalt("Destination does not exist!")
|
||||
return -- source does not exist or is not valid
|
||||
end
|
||||
|
||||
self:initLineTestNumber()
|
||||
local connID = self:buildNewConnection()
|
||||
self:buildNewConnectionNode(connID, exchange, ext)
|
||||
self:buildNewConnectionNode(connID, self.lineTestPBX, self.lineTestExt)
|
||||
|
||||
local dest = self:GetDest(exchange, ext)
|
||||
|
||||
if (!istable(dest)) then
|
||||
self:Disconnect(connID) -- source dissapeared for some reason
|
||||
ErrorNoHalt("Destination does not exist, or is invalid!")
|
||||
return
|
||||
end
|
||||
|
||||
print("Destination Endpoint Found!: "..table.ToString(dest, "Destination Endpoint", true))
|
||||
|
||||
local destEnt = self.endpoints:GetEndpoint(tonumber(dest.endID))
|
||||
print("Destination Entity Found! ID: "..tostring(destEnt:EntIndex()))
|
||||
|
||||
destEnt:EnterRing(function(status)
|
||||
if (!status) then -- call did not go through so we need to clean up
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
self:NotifyAllListenersOfStatusChange(tonumber(dest.endID), status, status)
|
||||
local client = destEnt.inUseBy
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("This is a test to determine connection stability. It will automatically disconnect in 10 seconds.")
|
||||
net.Send(client)
|
||||
|
||||
net.Start("LineStatusUpdate")
|
||||
net.WriteString(self.DialStatus.DebugMode)
|
||||
net.Send(client)
|
||||
|
||||
timer.Simple(15, function()
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("Line test has completed. Disconnecting now.")
|
||||
net.Send(client)
|
||||
|
||||
self:Disconnect(connID)
|
||||
end)
|
||||
end)
|
||||
|
||||
local hangUpCallback = function()
|
||||
-- cleanup
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
destEnt.hangUpCallback = hangUpCallback
|
||||
end
|
||||
|
||||
-- used for debugging purposes
|
||||
-- allows landline to make a call out to a test entity placed at map root
|
||||
function ix.phone.switch:StartLineTest(exchange, ext)
|
||||
if (!self:DestExists(exchange, ext)) then
|
||||
ErrorNoHalt("Source does not exist!")
|
||||
return -- source does not exist or is not valid
|
||||
end
|
||||
|
||||
self:initLineTestNumber()
|
||||
local connID = self:BuildNewTwoWayConnection(exchange, ext, self.lineTestPBX, self.lineTestExt)
|
||||
|
||||
local conn = self:GetActiveConnection(exchange, ext)
|
||||
if (!istable(conn)) then
|
||||
ErrorNoHalt("Failed to construct connection nodes! ", tostring(connID))
|
||||
return
|
||||
end
|
||||
|
||||
print("Connection nodes constructed!: "..table.ToString(conn, "ConnID: "..tostring(connID), true))
|
||||
local source = self:GetDest(exchange, ext)
|
||||
|
||||
if (!istable(source)) then
|
||||
self:Disconnect(connID) -- source dissapeared for some reason
|
||||
ErrorNoHalt("Source does not exist, or is invalid!")
|
||||
return
|
||||
end
|
||||
|
||||
print("Source Endpoint Found!: "..table.ToString(source, "Source Endpoint", true))
|
||||
|
||||
local sourceEnt = self.endpoints:GetEndpoint(tonumber(source["endID"]))
|
||||
print("Source Entity Found! ID: "..tostring(sourceEnt:EntIndex()))
|
||||
|
||||
local listeners = self:GetListeners(self.lineTestPBX, self.lineTestExt)
|
||||
local client = listeners[1]
|
||||
if (!client) then
|
||||
self:Disconnect(connID)
|
||||
print("Destination listener pool: "..table.ToString(listeners, "Listener Pool", true))
|
||||
ErrorNoHalt("Destination has no listeners!")
|
||||
return
|
||||
end
|
||||
|
||||
local hangUpCallback = function()
|
||||
-- cleanup
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
sourceEnt.hangUpCallback = hangUpCallback
|
||||
|
||||
print("Line Test Listener Found! ID: "..tostring(client))
|
||||
timer.Simple(2, function()
|
||||
net.Start("ixConnectedCallStatusChange")
|
||||
net.WriteBool(true)
|
||||
net.WriteBool(true)
|
||||
net.Send(client)
|
||||
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("This is a test to determine connection stability. It will automatically disconnect in 10 seconds.")
|
||||
net.Send(client)
|
||||
end)
|
||||
|
||||
timer.Simple(15, function()
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("Line test has completed. Disconnecting now.")
|
||||
net.Send(client)
|
||||
|
||||
net.Start("ixConnectedCallStatusChange")
|
||||
net.WriteBool(false)
|
||||
net.WriteBool(false)
|
||||
net.Send(client)
|
||||
|
||||
self:Disconnect(connID)
|
||||
end)
|
||||
end
|
||||
339
gamemodes/darkrp/plugins/phone/sh_plugin.lua
Normal file
339
gamemodes/darkrp/plugins/phone/sh_plugin.lua
Normal file
@@ -0,0 +1,339 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
ring ring ring ring - LUA PHONE
|
||||
,==.-------.
|
||||
( ) ==== \
|
||||
|| | [][][] |
|
||||
,8|| | [][][] |
|
||||
8 || | [][][] |
|
||||
8 ( ) O O O /
|
||||
'88`=='-------'
|
||||
]]
|
||||
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
PLUGIN.name = "Phones"
|
||||
PLUGIN.description = "Adds landlines, pagers, and ways to route them"
|
||||
PLUGIN.author = "M!NT"
|
||||
|
||||
ix.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
ix.util.Include("cl_hooks.lua")
|
||||
ix.util.Include("sv_hooks.lua")
|
||||
ix.util.Include("sv_plugin.lua")
|
||||
|
||||
CAMI.RegisterPrivilege({
|
||||
Name = "Helix - Use Phones",
|
||||
MinAccess = "user"
|
||||
})
|
||||
|
||||
ix.command.Add("Raccrocher", {
|
||||
alias = "HP",
|
||||
description = "Hangs up the phone you're looking at.",
|
||||
arguments = {},
|
||||
privilege = "Use Phones",
|
||||
OnRun = function(self, client)
|
||||
PLUGIN:runHangupOnClient(client)
|
||||
end
|
||||
})
|
||||
|
||||
CAMI.RegisterPrivilege({
|
||||
Name = "Helix - Manage Phones",
|
||||
MinAccess = "admin"
|
||||
})
|
||||
|
||||
ix.command.Add("EditLandline", {
|
||||
description = "Edit the landline phone you are currently looking at.",
|
||||
arguments = {
|
||||
ix.type.number,
|
||||
ix.type.number,
|
||||
ix.type.text
|
||||
},
|
||||
privilege = "Manage Phones",
|
||||
OnRun = function(self, client, pbx, extension, publicName)
|
||||
if (!pbx or !extension or !publicName or string.len(publicName) < 1) then
|
||||
client:NotifyLocalized("You provided an invalid argument")
|
||||
end
|
||||
|
||||
-- perform input validations
|
||||
if (pbx < 1 or pbx > 9) then
|
||||
client:NotifyLocalized("Provided PBX is invalid! (must be a number between 1 and 10)")
|
||||
return
|
||||
end
|
||||
|
||||
if (!ix.phone.switch:ExchangeExists(pbx)) then
|
||||
client:NotifyLocalized("Provided PBX '"..tostring(pbx).."' does not exist.")
|
||||
return
|
||||
end
|
||||
|
||||
if (extension < 100 or extension > 999) then
|
||||
client:NotifyLocalized("Provided extension is invalid! (must be a number between 100 and 1000")
|
||||
return
|
||||
end
|
||||
|
||||
if (string.len(publicName) < 1) then
|
||||
client:NotifyLocalized("Provided public name is invalid! (must have a length greater than 1)")
|
||||
return
|
||||
end
|
||||
|
||||
local data = {}
|
||||
data.start = client:GetShootPos()
|
||||
data.endpos = data.start + client:GetAimVector() * 96
|
||||
data.filter = client
|
||||
local target = util.TraceLine(data).Entity
|
||||
|
||||
if (!IsValid(target) or target.PrintName != "Landline Phone") then
|
||||
client:NotifyLocalized("You are not looking at a phone.")
|
||||
return
|
||||
end
|
||||
|
||||
if (ix.phone.switch:DestExists(target.currentPBX, target.currentExtension)) then
|
||||
print("exists")
|
||||
ix.phone.switch:RmDest(target.currentPBX, target.currentExtension)
|
||||
end
|
||||
|
||||
if (!ix.phone.switch:AddDest(pbx, extension, publicName, target.endpointID)) then
|
||||
client:NotifyLocalized("Could not register the phone with the provided arguments")
|
||||
return
|
||||
end
|
||||
|
||||
target.currentName = publicName
|
||||
target.currentPBX = pbx
|
||||
target.currentExtension = extension
|
||||
|
||||
client:NotifyLocalized("You have successfully updated the landline.")
|
||||
end
|
||||
})
|
||||
|
||||
ix.command.Add("AddPBX", {
|
||||
description = "Add new PBX if one does not already exist",
|
||||
arguments = {ix.type.number},
|
||||
privilege = "Manage Phones",
|
||||
OnRun = function(self, client, pbx)
|
||||
if (!pbx or pbx < 1 or pbx > 9) then
|
||||
client:NotifyLocalized("Provided PBX is invalid! (must be a number between 1 and 10)")
|
||||
return
|
||||
end
|
||||
|
||||
if (ix.phone.switch:AddExchange(pbx)) then
|
||||
client:NotifyLocalized("PBX '"..tostring(pbx).."' was created succesfully!")
|
||||
else
|
||||
client:NotifyLocalized("PBX '"..tostring(pbx).."' already exists!")
|
||||
return
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
ix.command.Add("RemovePBX", {
|
||||
description = "Remove an existing PBX (will stop all active calls on this PBX and deregister all phones currently connected!)",
|
||||
arguments = {ix.type.number},
|
||||
privilege = "Manage Phones",
|
||||
OnRun = function(self, client, pbx)
|
||||
if (!pbx or pbx < 1 or pbx > 9) then
|
||||
client:NotifyLocalized("Provided PBX is invalid! (must be a number between 1 and 10)")
|
||||
return
|
||||
end
|
||||
|
||||
if (!ix.phone.switch:ExchangeExists(pbx)) then
|
||||
client:NotifyLocalized("PBX '"..tostring(pbx).."' does not exist!")
|
||||
return
|
||||
end
|
||||
|
||||
-- stop all active connections
|
||||
for ext, md in ipairs(ix.phone.switch.exchanges[pbx]) do
|
||||
local connMd = ix.phone.switch:GetActiveConnection(pbx, ext)
|
||||
if (istable(connMd)) then
|
||||
ix.phone.switch:Disconnect(connMD.targetConnID)
|
||||
end
|
||||
end
|
||||
|
||||
ix.phone.switch:RmExchange(pbx)
|
||||
|
||||
client:NotifyLocalized("PBX '"..tostring(pbx).."' has been deconstructed.")
|
||||
end
|
||||
})
|
||||
|
||||
ix.char.RegisterVar("landlineConnection", {
|
||||
field = "landlineConnection",
|
||||
fieldType = ix.type.table,
|
||||
default = {
|
||||
active = false,
|
||||
exchange = nil,
|
||||
extension = nil
|
||||
},
|
||||
bNoDisplay = true,
|
||||
isLocal = true,
|
||||
OnSet = function(self, value)
|
||||
local client = self:GetPlayer()
|
||||
|
||||
if (!IsValid(client)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
self.vars.landlineConnection = {
|
||||
active = value["active"],
|
||||
exchange = value["exchange"],
|
||||
extension = value["extension"]
|
||||
}
|
||||
end,
|
||||
OnGet = function(self, default)
|
||||
local connMetaData = self.vars.landlineConnection
|
||||
return connMetaData
|
||||
end,
|
||||
OnAdjust = function(self, client, data, value, newData)
|
||||
newData.landlineConnection = value
|
||||
end
|
||||
})
|
||||
|
||||
do
|
||||
local phoneChatCommands = {
|
||||
phonesay = {
|
||||
alias = "PS",
|
||||
description = "Speak into a phone if you're holding one.",
|
||||
range = ix.config.Get("chatRange", 280),
|
||||
},
|
||||
phonewhisper = {
|
||||
alias = "PW",
|
||||
description = "Whisper into a phone if you're holding one.",
|
||||
range = ix.config.Get("chatRange", 280) / 4,
|
||||
},
|
||||
phoneyell = {
|
||||
alias = "PY",
|
||||
description = "Yell into a phone if you're holding one.",
|
||||
range = ix.config.Get("chatRange", 280) * 4,
|
||||
}
|
||||
}
|
||||
|
||||
for phoneChatCommand, commandSettings in pairs(phoneChatCommands) do
|
||||
ix.command.Add(phoneChatCommand, {
|
||||
alias = commandSettings.alias,
|
||||
description = commandSettings.description,
|
||||
arguments = ix.type.text,
|
||||
privilege = "Use Phones",
|
||||
OnRun = function(self, client, message)
|
||||
local character = client:GetCharacter()
|
||||
if (!istable(character)) then
|
||||
return
|
||||
end
|
||||
if (character:GetLandlineConnection().active) then
|
||||
local recvs = ix.phone.switch:GetCharacterActiveListeners(character)
|
||||
if (!recvs) then
|
||||
recvs = {}
|
||||
end
|
||||
|
||||
local eavesDropRecvs = ix.phone.switch.endpoints:GetPlayersInRadiusFromPos(
|
||||
client:GetPos(), commandSettings.range)
|
||||
|
||||
if (istable(eavesDropRecvs)) then
|
||||
table.Add(recvs, eavesDropRecvs)
|
||||
end
|
||||
|
||||
-- doing this here because, for some reason, chat CanHear just isn't working
|
||||
-- "If you want it done right, do it yourself"
|
||||
ix.chat.Send(client, phoneChatCommand, message, false, recvs)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
-- used to simulate a distortion effect on certain letters when using phoneyell
|
||||
local chatDistortionChars = {
|
||||
O = "Ő̸̗",
|
||||
F = "F̸̲̂̉ ̷̖̇̀",
|
||||
P = "P̵̧̝̫̘͛͜F̶̆̃ ̴̩̫̎̌͜͝ ̴͈̈́",
|
||||
CK = "C̴̣̖̕͜K̵̘̲͂̈́",
|
||||
K = "K̵̘̲͂̈́",
|
||||
T = "T̸̮͒͝͝",
|
||||
X = "Ẍ̷̻́_̷̛̰",
|
||||
SH = "S̷̥̓ ̶̖͂Ḣ̴̗ ̴̘̔",
|
||||
Z = "Z̶̗̒̃̅",
|
||||
S = "S̶͖̐̿ ̷̤̰͂͌",
|
||||
H = " ̵̬̻͇̎ ̵͈̦͍̔̅̊̇͝H"
|
||||
}
|
||||
-- TODO: get atle to add a real icon for this to willardcuntent
|
||||
local chatIcon = ix.util.GetMaterial("willardnetworks/chat/message_icon.png")
|
||||
local chatSettings = {
|
||||
phonewhisper = {
|
||||
range = ix.config.Get("chatRange", 280) / 4,
|
||||
color = Color(149, 196, 215),
|
||||
indicator = "chatWhispering",
|
||||
format = "[PHONE] %s: (whisper) \"%s\""
|
||||
},
|
||||
phonesay = {
|
||||
range = ix.config.Get("chatRange", 280),
|
||||
color = Color(105, 157, 178),
|
||||
indicator = "chatTalking",
|
||||
format = "[PHONE] %s: \"%s\""
|
||||
},
|
||||
phoneyell = {
|
||||
range = ix.config.Get("chatRange", 280) * 4,
|
||||
color = Color(166, 89, 89),
|
||||
indicator = "chatYelling",
|
||||
format = "[PHONE] %s: \"%s\""
|
||||
}
|
||||
}
|
||||
|
||||
for chatType, chatTypeData in pairs(chatSettings) do
|
||||
ix.chat.Register(chatType, {
|
||||
color = chatTypeData.color,
|
||||
indicator = chatTypeData.indicator,
|
||||
format = chatTypeData.format,
|
||||
CanSay = function(self, speaker, text)
|
||||
return speaker:GetCharacter():GetLandlineConnection()["active"]
|
||||
end,
|
||||
OnChatAdd = function(self, speaker, text, anonymous, data)
|
||||
local name = anonymous and
|
||||
L"someone" or
|
||||
hook.Run("GetCharacterName", speaker, "ic") or
|
||||
(IsValid(speaker) and speaker:Name() or "Console")
|
||||
|
||||
local rText = ix.chat.Format(text)
|
||||
if (chatType == "phoneyell") then
|
||||
rText = rText:upper()
|
||||
for char, repl in pairs(chatDistortionChars) do
|
||||
rText = rText:gsub(tostring(char), tostring(repl))
|
||||
end
|
||||
|
||||
-- ix.chat.Format() will always add punctuation.
|
||||
-- Replace that with an exclamation mark for greater effect :)
|
||||
rText = rText:sub(1, -2)
|
||||
rText = rText.."!"
|
||||
end
|
||||
rText = string.format(chatTypeData.format, name, rText)
|
||||
|
||||
if (ix.option.Get("standardIconsEnabled")) then
|
||||
chat.AddText(chatIcon, self.color, rText)
|
||||
else
|
||||
chat.AddText(self.color, rText)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
-- dial statuses which will be displayed on the target phone's derma
|
||||
ix.phone.switch.DialStatus = {
|
||||
SourceNotExist = "Err #186A0:>\n Source does not exist as a destination.\n Is it registered in the PSTN?",
|
||||
NoDialSeq = "Err #1D4C0:>\n No dial sequence provided.",
|
||||
CannotDecodeDial = "Err #1E078:>\n Invalid dial sequence provided.",
|
||||
NumberNotFound = "Err #1E208:>\n Destination not registered in the PSTN;\n Cannot find a route.",
|
||||
EndpointNotFound = "Err #1E23A:>\n Route exists, but is missing a valid endpoint;\n Cannot reach endpoint.",
|
||||
DebugMode = "Entering debug mode.",
|
||||
Success = "Connection established.",
|
||||
LineBusy = "Line busy. Please try again later",
|
||||
NotSetup = "Err #1E240:>\n Cannot establish connection.\n Please verifiy connection to PBX."
|
||||
}
|
||||
end
|
||||
147
gamemodes/darkrp/plugins/phone/sv_hooks.lua
Normal file
147
gamemodes/darkrp/plugins/phone/sv_hooks.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
--[[
|
||||
| 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("BeginDialToPeer")
|
||||
util.AddNetworkString("ixConnectedCallStatusChange")
|
||||
util.AddNetworkString("RunHangupLandline")
|
||||
util.AddNetworkString("RunGetPeerName")
|
||||
util.AddNetworkString("OnGetPeerName")
|
||||
util.AddNetworkString("LineTestChat")
|
||||
util.AddNetworkString("LineStatusUpdate")
|
||||
util.AddNetworkString("LandlineKeyPress")
|
||||
|
||||
net.Receive("LandlineKeyPress", function (len, client)
|
||||
local ent = Entity(net.ReadInt(17))
|
||||
if (ent and ent.inUseBy == client and ent.ButtonPress) then
|
||||
ent:ButtonPress()
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("BeginDialToPeer", function (len, client)
|
||||
local dialSeq = net.ReadString()
|
||||
if (string.len(dialSeq) < 3 or string.len(dialSeq) > 4 or tonumber(dialSeq) == nil) then
|
||||
return
|
||||
end
|
||||
|
||||
local exchange = net.ReadInt(5)
|
||||
local extension = net.ReadInt(11)
|
||||
local character = client:GetCharacter()
|
||||
local vars = character:GetLandlineConnection()
|
||||
|
||||
-- verify that this is coming from the correct place (or that no one is trying to manually call the hook)
|
||||
if (vars["exchange"] != exchange and vars["extension"] != extension) then
|
||||
return
|
||||
end
|
||||
|
||||
local status = ix.phone.switch:Dial(exchange, extension, dialSeq)
|
||||
if (status) then
|
||||
net.Start("LineStatusUpdate")
|
||||
net.WriteString(status)
|
||||
net.Send(client)
|
||||
|
||||
if (status != ix.phone.switch.DialStatus.Success and
|
||||
status != ix.phone.switch.DialStatus.DebugMode) then
|
||||
net.Start("ixConnectedCallStatusChange")
|
||||
net.WriteBool(true)
|
||||
net.WriteBool(false)
|
||||
net.Send(client)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("RunHangupLandline", function (len, client)
|
||||
PLUGIN:runHangupOnClient(client)
|
||||
end)
|
||||
|
||||
net.Receive("RunGetPeerName", function (len, client)
|
||||
if (!client or !IsValid(client)) then
|
||||
return
|
||||
end
|
||||
|
||||
local char = client:GetCharacter()
|
||||
local charMD = char:GetLandlineConnection()
|
||||
|
||||
if (charMD.active) then
|
||||
if (!charMD.extension or !charMD.exchange) then
|
||||
return
|
||||
end
|
||||
|
||||
recievers = ix.phone.switch:GetReceivers(charMD.exchange, charMD.extension)
|
||||
if (!recievers or #recievers < 1) then
|
||||
return
|
||||
end
|
||||
|
||||
net.Start("OnGetPeerName")
|
||||
net.WriteString(recievers[1]["name"])
|
||||
net.Send(client)
|
||||
end
|
||||
end)
|
||||
|
||||
function PLUGIN:runHangupOnClient(client)
|
||||
if (!client or !IsValid(client)) then
|
||||
return
|
||||
end
|
||||
local data = {}
|
||||
data.start = client:GetShootPos()
|
||||
data.endpos = data.start + client:GetAimVector() * 96
|
||||
data.filter = client
|
||||
local target = util.TraceLine(data).Entity
|
||||
|
||||
if (!target or target.PrintName != "Landline Phone") then
|
||||
return
|
||||
end
|
||||
|
||||
target:HangUp()
|
||||
end
|
||||
|
||||
-- PHONE CLEANUP
|
||||
-- this function literally just dumps all current ongoing connections that happen to have this client in them
|
||||
local function cleanupActivePhoneConnectionsForClient(client)
|
||||
if (!client or !IsValid(client)) then
|
||||
return
|
||||
end
|
||||
|
||||
local char = client:GetCharacter()
|
||||
local charCallMD = nil
|
||||
-- why do I have to do all this checking?? UGH thanks helix
|
||||
if (char and char.GetLandlineConnection) then
|
||||
charCallMD = char:GetLandlineConnection()
|
||||
end
|
||||
if (istable(charCallMD) and charCallMD["active"]) then
|
||||
ix.phone.switch:DisconnectActiveCallIfPresentOnClient(client)
|
||||
end
|
||||
|
||||
if (char) then
|
||||
char:SetLandlineConnection({
|
||||
active = false,
|
||||
exchange = nil,
|
||||
extension = nil
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- peak laziness:
|
||||
function PLUGIN:PlayerDisconnected(client)
|
||||
cleanupActivePhoneConnectionsForClient(client)
|
||||
end
|
||||
|
||||
function PLUGIN:OnCharacterFallover(client, entity, bFallenOver)
|
||||
cleanupActivePhoneConnectionsForClient(client)
|
||||
end
|
||||
|
||||
function PLUGIN:PlayerDeath(client)
|
||||
cleanupActivePhoneConnectionsForClient(client)
|
||||
end
|
||||
|
||||
function PLUGIN:PlayerLoadedCharacter(client, character, lastChar)
|
||||
cleanupActivePhoneConnectionsForClient(client)
|
||||
end
|
||||
49
gamemodes/darkrp/plugins/phone/sv_plugin.lua
Normal file
49
gamemodes/darkrp/plugins/phone/sv_plugin.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
--[[
|
||||
| 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.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
function PLUGIN:RegisterSaveEnts()
|
||||
ix.saveEnts:RegisterEntity("landline_phone", true, true, true, {
|
||||
OnSave = function(entity, data) --OnSave
|
||||
data.endpointID = entity.endpointID
|
||||
data.extension = entity.currentExtension
|
||||
data.exchange = entity.currentPBX
|
||||
data.name = entity.currentName
|
||||
end,
|
||||
OnRestore = function(entity, data) --OnRestore
|
||||
local exID = tonumber(data.exchange)
|
||||
local ext = tonumber(data.extension)
|
||||
local name = data.name
|
||||
if (!exID or !ext) then
|
||||
ErrorNoHalt("Landline save data missing endpoint or extension. Ext: "..tostring(ext).." Pbx: "..tostring(exID))
|
||||
return
|
||||
end
|
||||
|
||||
local newEndID = ix.phone.switch.endpoints:Register(entity)
|
||||
if (!newEndID) then
|
||||
-- ent exists already as an endpoint
|
||||
ErrorNoHalt("Landline multiply registered as endpoint! EndID: "..tostring(newEndID))
|
||||
return
|
||||
end
|
||||
entity.endpointID = newEndID
|
||||
|
||||
ix.phone.switch:AddExchange(exID)
|
||||
ix.phone.switch:AddDest(exID, ext, name, newEndID)
|
||||
|
||||
entity.currentExtension = ext
|
||||
entity.currentPBX = exID
|
||||
entity.currentName = name
|
||||
end
|
||||
})
|
||||
end
|
||||
Reference in New Issue
Block a user