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,126 @@
--[[
| 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 netstream = netstream
local vgui = vgui
local hook = hook
local IsValid = IsValid
local pairs = pairs
local LocalPlayer = LocalPlayer
local Derma_Select = Derma_Select
local timer = timer
local Derma_Query = Derma_Query
local PLUGIN = PLUGIN
netstream.Hook("ixCreditTransactionLog", function(data, bShowReadButton)
local transactionUI = vgui.Create("ixCIDTransactionLog")
transactionUI:CreateContent(data, bShowReadButton)
end)
netstream.Hook("ixRequestCredits", function(client, amount, reason)
local clientName = hook.Run("GetCharacterName", client, "ic") or client:GetName()
if (IsValid(PLUGIN.posTransactionPanel)) then
client:NotifyLocalized("posTransOngoing")
netstream.Start("ixDenyCreditOperation")
return
end
local cards = {}
for _, v in pairs(LocalPlayer():GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
cards[#cards + 1] = {
text = v:GetName(),
value = v
}
end
local amountPercent = amount / 100
local vat = math.Round(amountPercent * ix.config.Get("transactionVatPercent", 2))
local cardsCount = #cards
if (cardsCount > 1) then
PLUGIN.posTransactionPanel = Derma_Select("Credits Requested", clientName.." requests "..amount.." credit(s) from you for '"..reason.."'. Transaction vat: " .. vat .. " credit(s). What card will you choose to pay?",
cards, "Select ID Card",
"Confirm Operation", function(value, name)
netstream.Start("ixConfirmCreditOperation", value:GetID())
timer.Remove("ixPosTransactionQuery")
end, "Refuse Request", function()
netstream.Start("ixDenyCreditOperation")
timer.Remove("ixPosTransactionQuery")
end)
elseif (cardsCount == 1) then
PLUGIN.posTransactionPanel = Derma_Query(clientName.." requests "..amount.." credit(s) from you for '"..reason.."'. Transaction vat: " .. vat .. " credit(s). Are you confirming this transaction?", "Credits Requested",
"Confirm Operation", function()
netstream.Start("ixConfirmCreditOperation", cards[1].value:GetID())
timer.Remove("ixPosTransactionQuery")
end, "Refuse Request", function()
netstream.Start("ixDenyCreditOperation")
timer.Remove("ixPosTransactionQuery")
end)
else
LocalPlayer():NotifyLocalized("You have received a credits request, but you do not have an ID card to perform it.")
netstream.Start("ixDenyCreditOperation")
return
end
timer.Create("ixPosTransactionQuery", 14, 1, function()
client:NotifyLocalized("posTransExpired")
PLUGIN.posTransactionPanel:Remove()
netstream.Start("ixDenyCreditOperation")
end)
end)
netstream.Hook("ixSelectCID", function(hasFail)
local cidSelector = vgui.Create("CIDSelector")
if (hasFail) then
cidSelector.ExitCallback = function()
netstream.Start("ixSelectCIDFail")
end
end
cidSelector.SelectCallback = function(cardID)
netstream.Start("ixSelectCIDSuccess", cardID)
end
end)
net.Receive("changeLockAccess", function()
local entity = net.ReadEntity()
ix.menu.Open({["Set Member Access"] = true, ["Set Management Access"] = true}, entity)
end)
net.Receive("changeLockAccessCmru", function()
local entity = net.ReadEntity()
local accessLevels = {}
for i=1, 5 do
accessLevels["Set Level "..tostring(i).." Access"] = true
end
ix.menu.Open(accessLevels, entity)
end)
net.Receive("changeLockAccessCon", function()
local entity = net.ReadEntity()
local accessLevels = {}
for i=1, 5 do
accessLevels["Set Level "..tostring(i).." Access"] = true
end
ix.menu.Open(accessLevels, entity)
end)
function PLUGIN:CreateExtraCharacterTabInfo(character, informationSubframe, CreatePart)
local citizenID = LocalPlayer():GetCharacter():GetCid() or "N/A"
local cidPanel = informationSubframe:Add("Panel")
CreatePart(cidPanel, "Citizen ID:", citizenID, "cid")
end

View File

@@ -0,0 +1,129 @@
--[[
| 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()
if ix.gui.cidSelector then
ix.gui.cidSelector:Remove()
end
ix.gui.cidSelector = self
self:SetSize(ScrW(), ScrH())
self:SetAlpha(0)
self:AlphaTo(255, 0.5, 0)
self.Paint = function(self, w, h)
surface.SetDrawColor(Color(63, 58, 115, 220))
surface.DrawRect(0, 0, w, h)
Derma_DrawBackgroundBlur( self, 1 )
end
self.innerContent = self:Add("Panel")
self.innerContent:SetSize(SScaleMin(500 / 3), SScaleMin(50 / 3))
self.innerContent:Center()
self.innerContent:MakePopup()
self.innerContent.Paint = function(self, w, h)
surface.SetDrawColor(0, 0, 0, 130)
surface.DrawRect(0, 0, w, h)
end
Schema:AllowMessage(self.innerContent)
self:CreateTopBar()
self:CreateSelector()
end
function PANEL:CreateTopBar()
local topbar = self.innerContent:Add("Panel")
topbar:SetSize(self.innerContent:GetWide(), SScaleMin(50 / 3))
topbar:Dock(TOP)
topbar.Paint = function( self, w, h )
surface.SetDrawColor(0, 0, 0, 130)
surface.DrawRect(0, 0, w, h)
end
local titleText = topbar:Add("DLabel")
titleText:SetFont("CharCreationBoldTitleNoClamp")
titleText:Dock(LEFT)
titleText:SetText("Which CID do you want to use?")
titleText:DockMargin(SScaleMin(10 / 3), 0, 0, 0)
titleText:SetContentAlignment(4)
titleText:SizeToContents()
local exit = topbar:Add("DImageButton")
exit:SetImage("willardnetworks/tabmenu/navicons/exit.png")
exit:SetSize(SScaleMin(20 / 3), SScaleMin(20 / 3))
exit:DockMargin(0, SScaleMin(15 / 3), SScaleMin(10 / 3), SScaleMin(15 / 3))
exit:Dock(RIGHT)
exit.DoClick = function()
if self.ExitCallback then
self.ExitCallback()
end
self:Remove()
surface.PlaySound("helix/ui/press.wav")
end
local function createDivider(parent)
parent:SetSize(1, topbar:GetTall())
parent:Dock(RIGHT)
parent:DockMargin(0, SScaleMin(10 / 3), SScaleMin(10 / 3), SScaleMin(10 / 3))
parent.Paint = function(self, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawLine(0, 0, 0, h)
end
end
local divider = topbar:Add("Panel")
createDivider(divider)
end
function PANEL:CreateSelector()
local selectorPanel = self.innerContent:Add("DScrollPanel")
selectorPanel:Dock(FILL)
local character = LocalPlayer():GetCharacter()
local inventoryItems = character:GetInventory():GetItemsByUniqueID("id_card")
for k, v in pairs(inventoryItems) do
local cidButton = selectorPanel:Add("DButton")
local cidName = v:GetData("name") or ""
local cid = v:GetData("cid") or ""
cidButton:Dock(TOP)
cidButton:SetTall(SScaleMin(50 / 3))
cidButton:DockMargin(SScaleMin(50 / 3), k == 1 and SScaleMin(10 / 3) or 0, SScaleMin(50 / 3), SScaleMin(10 / 3))
cidButton:SetFont("MenuFontNoClamp")
cidButton:SetText(cidName.." | "..cid.." | "..v:GetData("cardNumber"))
cidButton.Paint = function( self, w, h )
surface.SetDrawColor(0, 0, 0, 130)
surface.DrawRect(0, 0, w, h)
end
cidButton.DoClick = function()
self:AlphaTo(0, 0.5, 0)
timer.Simple(0.5, function()
if self.SelectCallback then
self.SelectCallback(v:GetID(), cid, cidName, self.activeEntity)
end
self:Remove()
end)
end
self.innerContent:SetTall(math.Clamp(self.innerContent:GetTall() + cidButton:GetTall() + (k == 1 and SScaleMin(10 / 3) or 0) + SScaleMin(10 / 3), 0, SScaleMin(600 / 3)))
self.innerContent:Center()
end
end
vgui.Register("CIDSelector", PANEL, "EditablePanel")

View File

@@ -0,0 +1,182 @@
--[[
| 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(SScaleMin(1179 / 3), SScaleMin(1116 / 3))
self:MakePopup()
self:Center()
Schema:AllowMessage(self)
self.content = self:Add("DScrollPanel")
self.content:SetSize(SScaleMin(800 / 3), SScaleMin(740 / 3))
self.content:Center()
self.contentPanels = {}
local topPanel = self.content:Add("Panel")
topPanel:Dock(TOP)
topPanel:SetTall(SScaleMin(32 / 3))
topPanel.Paint = function(this, w, h)
self:DrawBottomLine(w, h)
end
local title = topPanel:Add("DLabel")
title:Dock(LEFT)
title:SetText("GENERIC TRANSACTION LOG")
title:SetFont("LargerTitlesFontNoClamp")
title:SizeToContents()
local exit = topPanel:Add("DButton")
exit:Dock(RIGHT)
exit:SetWide(SScaleMin(24 / 3))
exit:DockMargin(0, SScaleMin(4 / 3), 0, SScaleMin(4 / 3))
exit:SetText("")
exit.Paint = function(this, w, h)
surface.SetDrawColor(color_white)
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/tabmenu/navicons/exit.png"))
surface.DrawTexturedRect(0, 0, w, h)
end
exit.DoClick = function()
self:Remove()
end
end
function PANEL:DrawBottomLine(w, h)
surface.SetDrawColor(color_white)
surface.DrawLine(0, h - 1, w, h - 1)
end
function PANEL:CreateContentPanel(height, bShouldCreateBottomLine)
local contentPanel = self.content:Add("Panel")
contentPanel:Dock(TOP)
contentPanel:SetTall(height)
if bShouldCreateBottomLine then
contentPanel.Paint = function(this, w, h)
self:DrawBottomLine(w, h)
end
end
self.contentPanels[#self.contentPanels + 1] = contentPanel
return contentPanel
end
function PANEL:CreateContent(data, bShowReadButton)
if (data and !table.IsEmpty(data)) then
for _, tData in pairs(data) do
local transPanel = self:CreateContentPanel(SScaleMin(140 / 3), true)
-- LEFT SIDE
local leftPanel = transPanel:Add("Panel")
transPanel.leftPanel = leftPanel
leftPanel:SetTall(transPanel:GetTall())
leftPanel:Dock(LEFT)
leftPanel.Paint = function(this, w, h)
surface.SetDrawColor(color_white)
surface.DrawLine(w, 1, w, h - 1)
end
leftPanel.datePanel = self:CreateText(leftPanel, os.date("%d/%m/%y", tData.datetime), TOP, 4)
leftPanel.datePanel:SetTall(SScaleMin(50 / 3))
leftPanel.timePanel = self:CreateText(leftPanel, os.date("%H:%M:%S", tData.datetime), TOP, 4)
if (bShowReadButton) then
leftPanel.readUnRead = leftPanel:Add("DButton")
leftPanel.readUnRead:Dock(FILL)
leftPanel.readUnRead:SetText(tonumber(tData.read) == 1 and "READ" or "UNREAD")
leftPanel.readUnRead:SetFont("TitlesFontNoClamp")
leftPanel.readUnRead:SizeToContents()
leftPanel.readUnRead:SetContentAlignment(4)
leftPanel.readUnRead.Paint = nil
leftPanel.readUnRead.DoClick = function()
if (tData.read == 1) then
tData.read = 0
else
tData.read = 1
end
leftPanel.readUnRead:SetText(tonumber(tData.read) == 1 and "READ" or "UNREAD")
netstream.Start("ixTransactionSetRead", tData.id, false, tData.read == 1, tData.pos)
end
end
leftPanel:SetWidth(SScaleMin(90 / 3))
-- RIGHT SIDE
local rightPanel = transPanel:Add("Panel")
transPanel.rightPanel = rightPanel
rightPanel:Dock(FILL)
-- INFO ROW
rightPanel.transInfoPanel = rightPanel:Add("Panel")
rightPanel.transInfoPanel:Dock(TOP)
rightPanel.transInfoPanel:SetTall(SScaleMin(50 / 3))
self:CreateText(rightPanel.transInfoPanel, tData.sender_name.." | CID: "..tData.sender_cid, LEFT, 4, Color(171, 27, 27, 255))
self:CreateText(rightPanel.transInfoPanel, "", FILL, 5, Color(169, 171, 27, 255))
self:CreateText(rightPanel.transInfoPanel, tData.receiver_name.." | CID: "..tData.receiver_cid, RIGHT, 6, Color(63, 171, 27, 255))
-- AMOUNT ROW
rightPanel.descPanel = rightPanel:Add("Panel")
rightPanel.descPanel:Dock(TOP)
rightPanel.descPanel.amountLabel = self:CreateText(rightPanel.descPanel, "AMOUNT: "..tData.amount.." ", RIGHT, 6, Color(169, 171, 27, 255))
rightPanel.descPanel.amountLabel:DockMargin(0, 0, 0, SScaleMin(5 / 3))
rightPanel.descPanel.reasonLabel = self:CreateText(rightPanel.descPanel, "REASON: ", LEFT, 5, Color(169, 171, 27, 255))
rightPanel.descPanel.reasonLabel:DockMargin(0, 0, 0, SScaleMin(5 / 3))
rightPanel.descPanel:SetTall(rightPanel.descPanel.amountLabel:GetTall())
rightPanel.reasonPanel = rightPanel:Add("Panel")
rightPanel.reasonPanel:Dock(TOP)
rightPanel.reasonPanel:SetTall(SScaleMin(50 / 3))
rightPanel.reasonPanel:DockMargin(0, SScaleMin(10 / 3), 0, 0)
rightPanel.reasonPanel.reasonTextEntry = rightPanel.reasonPanel:Add("DTextEntry")
rightPanel.reasonPanel.reasonTextEntry:Dock(FILL)
rightPanel.reasonPanel.reasonTextEntry:SetText(tData.reason)
rightPanel.reasonPanel.reasonTextEntry:SetEditable(true)
rightPanel.reasonPanel.reasonTextEntry:SetVerticalScrollbarEnabled(true)
rightPanel.reasonPanel.reasonTextEntry:SetMultiline(true)
rightPanel.reasonPanel.reasonTextEntry:SetFont("MenuFontNoClamp")
rightPanel.reasonPanel.reasonTextEntry:SetTextColor( color_white )
rightPanel.reasonPanel.reasonTextEntry:SetCursorColor( color_white )
rightPanel.reasonPanel.reasonTextEntry.Paint = function(this, w, h)
surface.SetDrawColor(20, 20, 20, 75)
surface.DrawRect(0, 0, w, h)
this:DrawTextEntryText( this:GetTextColor(), this:GetHighlightColor(), this:GetCursorColor() )
end
-- Because scrollbar won't be useable unless textentry is editable thanks derma
local coverForTextEntry = rightPanel.reasonPanel:Add("Panel")
coverForTextEntry:Dock(FILL)
coverForTextEntry:DockMargin(0, 0, 19, 0)
end
end
end
function PANEL:CreateText(parent, text, dock, contentAlignment, color)
local label = parent:Add("DLabel")
label:Dock(dock)
label:SetText(text or "")
label:SetFont("TitlesFontNoClamp")
label:SetTextColor(color or color_white)
label:SetContentAlignment(contentAlignment)
label:SizeToContents()
return label
end
function PANEL:Paint(w, h)
surface.SetDrawColor(color_white)
surface.SetMaterial(Material("willardnetworks/posterminal.png"))
surface.DrawTexturedRect(0, 0, w, h)
end
vgui.Register("ixCIDTransactionLog", PANEL, "EditablePanel")

View File

@@ -0,0 +1,106 @@
--[[
| 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 = "CMRU Access Card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A Civil Medical & Research Union Keycard."
ITEM.category = "Combine"
ITEM.skin = 2
ITEM.iconCam = {
pos = Vector(-509.64, -427.61, 310.24),
ang = Angle(25, 400, 0),
fov = 0.59
}
function ITEM:GetName()
local accessLevel = self:GetData("accessLevel", 1)
return "CMRU Level " .. accessLevel .. " Access Keycard"
end
function ITEM:GetDescription()
local idCard = ix.item.instances[self:GetData("cardID")]
return idCard and string.format(self.description.."\n\nCurrently bound to identity card #%s.", idCard:GetData("cardNumber")) or
(self:GetData("cardID") and self.description.."\n\nCurrently bound." or self.description)
end
ITEM.functions.Bind = {
name = "Bind ID Card",
icon = "icon16/vcard_edit.png",
OnClick = function(itemTable)
local cards = {}
for _, v in pairs(LocalPlayer():GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
table.insert(cards, {
text = v:GetName(),
value = v
})
end
local cardsCount = table.Count(cards)
if (cardsCount > 1) then
Derma_Select("Bind ID Card to CMRU Card", "Please select a ID card to bind to this CMRU Card:",
cards, "Select ID card",
"Confirm Operation", function(value, name)
netstream.Start("ixBindCMRUCard", itemTable:GetID(), value:GetID())
end, "Cancel")
elseif (cardsCount == 1) then
Derma_Query("Are you sure you wish to bind your ID to this CMRU Card?", "Bind ID Card to CMRU Card",
"Confirm Operation", function()
netstream.Start("ixBindCMRUCard", itemTable:GetID(), cards[1].value:GetID())
end, "Cancel")
else
LocalPlayer():NotifyLocalized("You do not have ID card to bind to this CMRU Card.")
end
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!IsValid(itemTable.player)) then
return false
end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!inventory:HasItem("id_card")) then
return false
end
if (itemTable:GetData("cardID")) then
return false
end
return true
end
}
ITEM.functions.SetAccessLevel = {
name = "Toggle Card Access Level",
icon = "icon16/vcard_add.png",
OnRun = function(itemTable)
local client = itemTable.player
local accessLevel = itemTable:GetData("accessLevel", 1)
accessLevel = accessLevel != 5 and accessLevel + 1 or 1
itemTable:SetData("accessLevel", accessLevel)
client:NotifyLocalized("You have set this card's Access Level to Access Level " .. accessLevel .. ".")
return false
end,
OnCanRun = function(itemTable)
return (!IsValid(itemTable.entity) and IsValid(itemTable.player) and (itemTable.player:Team() == FACTION_ADMIN or itemTable.player:IsCombine() or itemTable.player:GetCharacter():HasFlags("M"))) == true
end
}

View File

@@ -0,0 +1,106 @@
--[[
| 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 = "Conscript Access Card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A Conscript Access Keycard."
ITEM.category = "Combine"
ITEM.skin = 2
ITEM.iconCam = {
pos = Vector(-509.64, -427.61, 310.24),
ang = Angle(25, 400, 0),
fov = 0.59
}
function ITEM:GetName()
local accessLevel = self:GetData("accessLevel", 1)
return "Conscript Level " .. accessLevel .. " Access Keycard"
end
function ITEM:GetDescription()
local idCard = ix.item.instances[self:GetData("cardID")]
return idCard and string.format(self.description.."\n\nCurrently bound to identity card #%s.", idCard:GetData("cardNumber")) or
(self:GetData("cardID") and self.description.."\n\nCurrently bound." or self.description)
end
ITEM.functions.Bind = {
name = "Bind ID Card",
icon = "icon16/vcard_edit.png",
OnClick = function(itemTable)
local cards = {}
for _, v in pairs(LocalPlayer():GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
table.insert(cards, {
text = v:GetName(),
value = v
})
end
local cardsCount = table.Count(cards)
if (cardsCount > 1) then
Derma_Select("Bind ID Card to Conscript Card", "Please select a ID card to bind to this Conscript Card:",
cards, "Select ID card",
"Confirm Operation", function(value, name)
netstream.Start("ixBindConCard", itemTable:GetID(), value:GetID())
end, "Cancel")
elseif (cardsCount == 1) then
Derma_Query("Are you sure you wish to bind your ID to this Conscript Card?", "Bind ID Card to Conscript Card",
"Confirm Operation", function()
netstream.Start("ixBindConCard", itemTable:GetID(), cards[1].value:GetID())
end, "Cancel")
else
LocalPlayer():NotifyLocalized("You do not have ID card to bind to this Conscript Card.")
end
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!IsValid(itemTable.player)) then
return false
end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!inventory:HasItem("id_card")) then
return false
end
if (itemTable:GetData("cardID")) then
return false
end
return true
end
}
ITEM.functions.SetAccessLevel = {
name = "Toggle Card Access Level",
icon = "icon16/vcard_add.png",
OnRun = function(itemTable)
local client = itemTable.player
local accessLevel = itemTable:GetData("accessLevel", 1)
accessLevel = accessLevel != 5 and accessLevel + 1 or 1
itemTable:SetData("accessLevel", accessLevel)
client:NotifyLocalized("You have set this card's Access Level to Access Level " .. accessLevel .. ".")
return false
end,
OnCanRun = function(itemTable)
return (!IsValid(itemTable.entity) and IsValid(itemTable.player) and (itemTable.player:Team() == FACTION_ADMIN or itemTable.player:IsCombine() or itemTable.player:GetCharacter():HasFlags("M"))) == true
end
}

View File

@@ -0,0 +1,181 @@
--[[
| 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 = "CWU Access Card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A Civil Workers' Union Access Keycard."
ITEM.category = "Combine"
ITEM.skin = 2
ITEM.iconCam = {
pos = Vector(-509.64, -427.61, 310.24),
ang = Angle(25, 400, 0),
fov = 0.59
}
function ITEM:GetName()
local accessLevel = self:GetData("accessLevel", "Member Access")
return "CWU " .. accessLevel .. " Keycard"
end
function ITEM:GetFactionInfo()
return self:GetData("faction", false) and ix.factionBudget.list[self:GetData("faction")] and "Binded to: " .. ix.factionBudget.list[self:GetData("faction")].name or "This card is not binded to any faction."
end
function ITEM:GetColorAppendix()
local info = {["green"] = self:GetFactionInfo()}
return info
end
function ITEM:GetDescription()
local idCard = ix.item.instances[self:GetData("cardID")]
return idCard and string.format(self.description.."\n\nCurrently bound to identity card #%s.", idCard:GetData("cardNumber")) or
(self:GetData("cardID") and self.description.."\n\nCurrently bound." or self.description)
end
ITEM.functions.Bind = {
name = "Bind ID Card",
icon = "icon16/vcard_edit.png",
OnClick = function(itemTable)
local cards = {}
for _, v in pairs(LocalPlayer():GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
table.insert(cards, {
text = v:GetName(),
value = v
})
end
local cardsCount = table.Count(cards)
if (cardsCount > 1) then
Derma_Select("Bind ID Card to CWU Card", "Please select a ID card to bind to this CWU Card:",
cards, "Select ID card",
"Confirm Operation", function(value, name)
netstream.Start("ixBindCWUCard", itemTable:GetID(), value:GetID())
end, "Cancel")
elseif (cardsCount == 1) then
Derma_Query("Are you sure you wish to bind your ID to this CWU Card?", "Bind ID Card to CWU Card",
"Confirm Operation", function()
netstream.Start("ixBindCWUCard", itemTable:GetID(), cards[1].value:GetID())
end, "Cancel")
else
LocalPlayer():NotifyLocalized("You do not have ID card to bind to this CWU Card.")
end
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!IsValid(itemTable.player)) then
return false
end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!inventory:HasItem("id_card")) then
return false
end
if (itemTable:GetData("cardID")) then
return false
end
return true
end
}
ITEM.functions.SetAccessLevel = {
name = "Toggle Card Access Level",
icon = "icon16/vcard_add.png",
isMulti = true,
multiOptions = function(item, player)
local keys = table.GetKeys(ix.city.cwuAccess)
local accessLevels = {}
for _, accessLevel in pairs(keys) do
accessLevels[#accessLevels + 1] = {name = accessLevel, data = {aLevel = accessLevel .. " Access"}}
end
return accessLevels
end,
OnRun = function(itemTable, accessLevel)
local client = itemTable.player
itemTable:SetData("accessLevel", accessLevel.aLevel)
client:NotifyLocalized("You have set this card's Access Level to " .. accessLevel.aLevel .. ".")
return false
end,
OnCanRun = function(itemTable)
return (!IsValid(itemTable.entity) and IsValid(itemTable.player) and (itemTable.player:Team() == FACTION_ADMIN or itemTable.player:IsCombine() or itemTable.player:GetCharacter():HasFlags("M"))) == true
end
}
ITEM.functions.SetFaction = {
name = "Set Card Faction",
icon = "icon16/vcard_add.png",
isMulti = true,
multiOptions = function(item, player)
local factions = {}
for id, faction in pairs(ix.factionBudget.list) do
factions[#factions + 1] = {name = faction.name, data = faction}
end
return factions
end,
OnRun = function(item, data)
item:SetData("faction", data.id)
return false
end,
OnCanRun = function(itemTable)
return (!IsValid(itemTable.entity) and IsValid(itemTable.player) and (itemTable.player:Team() == FACTION_ADMIN or itemTable.player:IsCombine() or itemTable.player:GetCharacter():HasFlags("M"))) == true
end
}
ITEM.functions.insert = {
name = "Insert card",
icon = "icon16/add.png",
OnRun = function(itemTable)
local client = itemTable.player
local ent = client:GetEyeTrace().Entity
if (!ent.CWUInsert) or client:EyePos():DistToSqr(ent:GetPos()) > 62500 then
return false
end
local bSuccess, error = itemTable:Transfer(nil, nil, nil, client)
if (!bSuccess and isstring(error)) then
client:NotifyLocalized(error)
return false
else
client:EmitSound("npc/zombie/foot_slide" .. math.random(1, 3) .. ".wav", 75, math.random(90, 120), 1)
end
if bSuccess and IsEntity(bSuccess) then
ent:CWUInsert(bSuccess)
end
return false
end,
OnCanRun = function(itemTable)
local client = itemTable.player
if (!client:GetEyeTrace().Entity.CWUInsert) then
return false
end
return true
end
}

View File

@@ -0,0 +1,106 @@
--[[
| 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 = "DOB Access Card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A Department of Business Access Keycard."
ITEM.category = "Combine"
ITEM.skin = 2
ITEM.iconCam = {
pos = Vector(-509.64, -427.61, 310.24),
ang = Angle(25, 400, 0),
fov = 0.59
}
function ITEM:GetName()
local accessLevel = self:GetData("accessLevel", "Member Access")
return "DOB " .. accessLevel .. " Keycard"
end
function ITEM:GetDescription()
local idCard = ix.item.instances[self:GetData("cardID")]
return idCard and string.format(self.description.."\n\nCurrently bound to identity card #%s.", idCard:GetData("cardNumber")) or
(self:GetData("cardID") and self.description.."\n\nCurrently bound." or self.description)
end
ITEM.functions.Bind = {
name = "Bind ID Card",
icon = "icon16/vcard_edit.png",
OnClick = function(itemTable)
local cards = {}
for _, v in pairs(LocalPlayer():GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
table.insert(cards, {
text = v:GetName(),
value = v
})
end
local cardsCount = table.Count(cards)
if (cardsCount > 1) then
Derma_Select("Bind ID Card to DOB Card", "Please select a ID card to bind to this DOB Card:",
cards, "Select ID card",
"Confirm Operation", function(value, name)
netstream.Start("ixBindDOBCard", itemTable:GetID(), value:GetID())
end, "Cancel")
elseif (cardsCount == 1) then
Derma_Query("Are you sure you wish to bind your ID to this DOB Card?", "Bind ID Card to DOB Card",
"Confirm Operation", function()
netstream.Start("ixBindDOBCard", itemTable:GetID(), cards[1].value:GetID())
end, "Cancel")
else
LocalPlayer():NotifyLocalized("You do not have ID card to bind to this DOB Card.")
end
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!IsValid(itemTable.player)) then
return false
end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!inventory:HasItem("id_card")) then
return false
end
if (itemTable:GetData("cardID")) then
return false
end
return true
end
}
ITEM.functions.SetAccessLevel = {
name = "Toggle Card Access Level",
icon = "icon16/vcard_add.png",
OnRun = function(itemTable)
local client = itemTable.player
local accessLevel = itemTable:GetData("accessLevel", "Member Access")
local target = accessLevel == "Member Access" and "Management Access" or "Member Access"
itemTable:SetData("accessLevel", target)
client:NotifyLocalized("You have set this card's Access Level to " .. target .. ".")
return false
end,
OnCanRun = function(itemTable)
return (!IsValid(itemTable.entity) and IsValid(itemTable.player) and (itemTable.player:Team() == FACTION_ADMIN or itemTable.player:IsCombine() or itemTable.player:GetCharacter():HasFlags("M"))) == true
end
}

View File

@@ -0,0 +1,66 @@
--[[
| 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 = "#00000's Identity Card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A citizen identification card assigned to %s, CID #%s.\n\nCard Number: %s\nGenetic description:\n%s.\n\nThis card is property of the Combine Civil Administration. Illegal possession and identity fraud are punishable by law and will result in prosecution by Civil Protection. If found, please return this card immediately to the nearest Civil Protection team."
ITEM.category = "Combine"
ITEM.iconCam = {
pos = Vector(0, 0, 10),
ang = Angle(90, 90, 0),
fov = 45,
}
if (CLIENT) then
function ITEM:PaintOver(item, w, h)
surface.SetDrawColor(110, 255, 110, 100)
surface.DrawRect(w - 14, h - 14, 8, 8)
end
end
function ITEM:GetName()
return "#" .. self:GetData("cid", "00000") .. "'s Identity Card"
end
function ITEM:GetDescription()
return string.format(self.description,
self:GetData("name", "Nobody"),
self:GetData("cid", "00000"),
self:GetData("cardNumber", "00-0000-0000-00"),
self:GetData("geneticDesc", "N/A | N/A | N/A EYES | N/A HAIR"))
end
local prime = 9999999787 -- prime % 4 = 3! DO NOT CHANGE EVER
local offset = 100000 -- slightly larger than sqrt(prime) is ok. DO NOT CHANGE EVER
local block = 100000000
local function generateCardNumber(id)
id = (id + offset) % prime
local cardNum = 0
for _ = 1, math.floor(id/block) do
cardNum = (cardNum + (id * block) % prime) % prime
end
cardNum = (cardNum + (id * (id % block) % prime)) % prime
if (2 * id < prime) then
return cardNum
else
return prime - cardNum
end
end
function ITEM:OnInstanced()
local cardNum = Schema:ZeroNumber(generateCardNumber(self:GetID()), 10)
self:SetData("cardNumber", string.utf8sub(cardNum, 1, 2) .. "-" .. string.utf8sub(cardNum, 3, 6) .. "-" .. string.utf8sub(cardNum, 7, 10) .. "-" .. Schema:ZeroNumber(cardNum % 97, 2))
end

View File

@@ -0,0 +1,52 @@
--[[
| 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 = "Counterfeit Identity Card Creation Device"
ITEM.model = Model("models/props_lab/reciever01a.mdl")
ITEM.description = "A device used to modify blank Identity Cards to look like real, functional ones."
ITEM.category = "Tools"
ITEM.functions.CreateID = {
name = "Create Counterfeit ID",
icon = "icon16/vcard.png",
OnRun = function(itemTable)
local client = itemTable.player
client:RequestString("Name", "Enter the name of the person that this counterfeit ID will be for", function(name)
client:RequestString("CID", "Enter the CID of the person that this counterfeit ID will be for", function(cid)
client:RequestString("Generic Description", "Enter the generic description of the person that this counterfeit ID will be for", function(desc)
local inventory = client:GetCharacter():GetInventory()
local card = inventory:HasItem("id_card_blank")
if (!card) then
client:Notify("You need a Blank Identity Card to turn into a counterfeit one!")
client:EmitSound("buttons/combine_button_locked.wav")
return false
end
card:Remove()
inventory:Add("fake_id_card", 1, {
name = name,
cid = cid,
geneticDesc = desc
})
client:Notify("Counterfeit Identity Card created.")
client:EmitSound("ambient/machines/combine_terminal_idle2.wav")
end, "YOUNG ADULT/ADULT/MIDDLE-AGED/ELDERLY | 0\'00\" | [COLOR] EYES | [COLOR] HAIR")
end, "00000")
end, "")
return false
end
}

View File

@@ -0,0 +1,289 @@
--[[
| 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 = "#00000's Identity Card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A citizen identification card assigned to %s, CID #%s.\n\nCard Number: %s\nGenetic description:\n%s.\n\nThis card is property of the Combine Civil Administration. Illegal possession and identity fraud are punishable by law and will result in prosecution by Civil Protection. If found, please return this card immediately to the nearest Civil Protection team."
ITEM.category = "Combine"
ITEM.iconCam = {
pos = Vector(0, 0, 10),
ang = Angle(90, 90, 0),
fov = 45,
}
if (CLIENT) then
function ITEM:PaintOver(item, w, h)
if (item:GetData("active")) then
surface.SetDrawColor(110, 255, 110, 100)
surface.DrawRect(w - 14, h - 14, 8, 8)
end
end
end
function ITEM:GetName()
return "#" .. self:GetData("cid", "00000") .. "'s Identity Card"
end
-- It's also possible to use ITEM.KeepOnDeath = true
function ITEM:KeepOnDeath(client)
return self:GetData("owner") == client:GetCharacter():GetID() and self:GetData("active")
end
function ITEM:GetDescription()
return string.format(self.description,
self:GetData("name", "Nobody"),
self:GetData("cid", "00000"),
self:GetData("cardNumber", "00-0000-0000-00"),
self:GetData("geneticDesc", "N/A | N/A | N/A EYES | N/A HAIR"))
end
local prime = 9999999787 -- prime % 4 = 3! DO NOT CHANGE EVER
local offset = 100000 -- slightly larger than sqrt(prime) is ok. DO NOT CHANGE EVER
local block = 100000000
local function generateCardNumber(id)
id = (id + offset) % prime
local cardNum = 0
for _ = 1, math.floor(id/block) do
cardNum = (cardNum + (id * block) % prime) % prime
end
cardNum = (cardNum + (id * (id % block) % prime)) % prime
if (2 * id < prime) then
return cardNum
else
return prime - cardNum
end
end
function ITEM:GetCredits()
return self:GetData("credits", 0)
end
function ITEM:HasCredits(amount)
return amount <= self:GetData("credits", 0)
end
if (SERVER) then
function ITEM:SetCredits(amount)
self:SetData("credits", math.floor(amount))
return true
end
function ITEM:GiveCredits(amount, sender, reason)
if (amount < 0 and !self:HasCredits(math.abs(amount))) then
return false
end
if (amount == 0) then
return true
end
if (sender) then
local insert = mysql:Insert("ix_cid_transactions")
insert:Insert("datetime", os.time())
insert:Insert("sender_name", sender)
insert:Insert("sender_cid", "00000")
insert:Insert("sender_cardid", 0)
insert:Insert("receiver_name", self:GetData("name", "UNKNOWN"))
insert:Insert("receiver_cid", self:GetData("cid", "INVALID"))
insert:Insert("receiver_cardid", self:GetID())
insert:Insert("amount", amount)
if (reason and reason != "") then
insert:Insert("reason", string.len(reason) > 250 and string.sub(reason, 1, 250) or reason)
else
insert:Insert("reason", "no reason given")
end
insert:Insert("pos", 0)
insert:Insert("read", 1)
insert:Execute()
end
return self:SetCredits(amount + self:GetCredits())
end
function ITEM:TakeCredits(amount, receiver, reason)
if (amount > 0 and !self:HasCredits(amount)) then
return false
end
if (amount == 0) then
return true
end
if (receiver) then
local insert = mysql:Insert("ix_cid_transactions")
insert:Insert("datetime", os.time())
insert:Insert("sender_name", self:GetData("name", "UNKNOWN"))
insert:Insert("sender_cid", self:GetData("cid", "INVALID"))
insert:Insert("sender_cardid", self:GetID())
insert:Insert("receiver_name", receiver)
insert:Insert("receiver_cid", "00000")
insert:Insert("receiver_cardid", 0)
insert:Insert("amount", amount)
if (reason and reason != "") then
insert:Insert("reason", string.len(reason) > 250 and string.sub(reason, 1, 250) or reason)
else
insert:Insert("reason", "no reason given")
end
insert:Insert("pos", 0)
insert:Insert("read", 1)
insert:Execute()
end
return self:SetCredits(self:GetCredits() - amount)
end
function ITEM:OnInstanced()
local cardNum = Schema:ZeroNumber(generateCardNumber(self:GetID()), 10)
self:SetData("cardNumber", string.utf8sub(cardNum, 1, 2).."-"..string.utf8sub(cardNum, 3, 6).."-"..string.utf8sub(cardNum, 7, 10)..
"-"..Schema:ZeroNumber(cardNum % 97, 2))
end
function ITEM:TransferData(newCard, wipe)
newCard:SetData("credits", self:GetData("credits", 0))
newCard:SetData("nextRationTime", self:GetData("nextRationTime", 0))
if (wipe) then
self:SetData("active", false)
self:SetData("credits", 0)
self:SetData("nextRationTime", 0)
end
end
function ITEM:OnRemoved()
if (self:GetData("active") != false) then
local ownerId = self:GetData("owner")
local data = {credits = self:GetData("credits", 0), ration = self:GetData("nextRationTime", 0)}
if (ix.char.loaded[ownerId]) then
ix.char.loaded[ownerId]:SetIdCardBackup(data)
ix.char.loaded[ownerId]:SetIdCard(nil)
end
local updateQuery = mysql:Update("ix_characters_data")
updateQuery:Update("data", util.TableToJSON(data))
updateQuery:Where("id", ownerId)
updateQuery:Where("key", "idCardBackup")
updateQuery:Execute()
local idCardQuery = mysql:Update("ix_characters")
idCardQuery.updateList[#idCardQuery.updateList + 1] = {"`idcard`", "NULL"}
idCardQuery:Where("id", ownerId)
idCardQuery:Where("schema", Schema and Schema.folder or "helix")
idCardQuery:Execute()
self:SetData("active", false)
end
end
function ITEM:LoadOwnerGenericData(callback, error, ...)
if (!callback) then return end
local arg = {...}
local queryObj = mysql:Select("ix_characters_data")
queryObj:Where("id", self:GetData("owner", 0))
queryObj:Where("key", "genericdata")
queryObj:Select("data")
queryObj:Callback(function(result)
if (!istable(result) or !result[1]) then
if (error) then
error(self, unpack(arg))
end
else
callback(self, util.JSONToTable(result[1].data or ""), unpack(arg))
end
end)
queryObj:Execute()
end
netstream.Hook("ixSetIDCardCredits", function(client, itemID, amount)
ix.item.instances[itemID]:SetCredits(amount)
end)
end
ITEM.functions.SetCredits = {
name = "Set Credits",
icon = "icon16/money_add.png",
OnClick = function(itemTable)
local client = itemTable.player
Derma_StringRequest("Set Credits", "What do you want to set the credits to?", itemTable:GetData("credits", 0), function(text)
local amount = tonumber(text)
if (amount and amount >= 0) then
netstream.Start("ixSetIDCardCredits", itemTable:GetID(), math.floor(amount))
else
client:NotifyLocalized("numNotValid")
end
end)
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!CAMI.PlayerHasAccess(itemTable.player, "Helix - Set Credits")) then
return false
end
if (!itemTable:GetData("active", false)) then
return false
end
return true
end
}
ITEM.functions.insert = {
name = "Insert CID",
icon = "icon16/add.png",
OnRun = function(itemTable)
local client = itemTable.player
local ent = client:GetEyeTrace().Entity
if (!ent.CIDInsert) or client:EyePos():DistToSqr(ent:GetPos()) > 62500 then
return false
end
local bSuccess, error = itemTable:Transfer(nil, nil, nil, client)
if (!bSuccess and isstring(error)) then
client:NotifyLocalized(error)
return false
else
client:EmitSound("npc/zombie/foot_slide" .. math.random(1, 3) .. ".wav", 75, math.random(90, 120), 1)
end
if bSuccess and IsEntity(bSuccess) then
ent:CIDInsert(bSuccess)
end
return false
end,
OnCanRun = function(itemTable)
local client = itemTable.player
if (!client:GetEyeTrace().Entity.CIDInsert) then
return false
end
if (!itemTable:GetData("active", false)) then
return false
end
return true
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 = "Blank CID card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A blank citizen identification card without any data."
ITEM.category = "Combine"
ITEM.iconCam = {
pos = Vector(-509.64, -427.61, 310.24),
ang = Angle(25, 400, 0),
fov = 0.59
}

View File

@@ -0,0 +1,114 @@
--[[
| 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 = "Identity Card Creation Device"
ITEM.model = Model("models/props_lab/reciever01d.mdl")
ITEM.description = "A device used to bind blank Identity Cards to a specific person."
ITEM.category = "Combine"
ITEM.functions.CreateIDTarget = {
name = "Create Identity Card for target",
icon = "icon16/vcard_add.png",
OnRun = function(itemTable)
local client = itemTable.player
if (ix.config.Get("creditsNoConnection")) then
client:EmitSound("hl1/fvox/buzz.wav", 60, 100, 0.5)
return false
end
if (itemTable:CheckAccess(client, itemTable) == false) then
client:EmitSound("buttons/combine_button_locked.wav", 60, 100, 0.5)
return false
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) and target:IsPlayer() and target:GetCharacter()) then
client:SetAction("@scanning", 5)
client:EmitSound("buttons/button18.wav", 60, 100, 0.5)
client:DoStaredAction(target, function()
itemTable:CreateIDCard(client, target)
end, 5, function()
client:SetAction()
client:EmitSound("buttons/combine_button_locked.wav", 60, 100, 0.5)
end)
else
client:NotifyLocalized("plyNotValid")
end
return false
end,
OnCanRun = function(itemTable)
return !IsValid(itemTable.entity)
end
}
ITEM.functions.CreateIDSelf = {
name = "Create Identity Card for yourself",
icon = "icon16/vcard.png",
OnRun = function(itemTable)
local client = itemTable.player
if (ix.config.Get("creditsNoConnection")) then
client:EmitSound("hl1/fvox/buzz.wav", 60, 100, 0.5)
return false
end
if (itemTable:CheckAccess(client, itemTable) == false) then
client:EmitSound("buttons/combine_button_locked.wav", 60, 100, 0.5)
return false
end
client:SetAction("@scanning", 5, function()
itemTable:CreateIDCard(client, client)
end)
client:EmitSound("buttons/button18.wav", 60, 100, 0.5)
return false
end
}
function ITEM:CreateIDCard(client, target)
local character = target:GetCharacter()
local cid = character:GetCid()
if (!cid) then
client:NotifyLocalized("idNotFound")
client:EmitSound("buttons/combine_button_locked.wav", 60, 100, 0.5)
return
end
local inventory = client:GetCharacter():GetInventory()
local blankCard = inventory:HasItem("id_card_blank")
if (!blankCard) then
client:NotifyLocalized("idNoBlank")
client:EmitSound("buttons/combine_button_locked.wav", 60, 100, 0.5)
return
end
blankCard:Remove()
character:CreateIDCard()
client:EmitSound("buttons/button4.wav", 60, 100, 0.5)
client:NotifyLocalized("idCardAdded")
ix.combineNotify:AddNotification("NTC:// Identification Card #" .. character:GetCid() .. " created by " .. client:GetCombineTag())
end
function ITEM:CheckAccess(client, itemTable)
if (!client:HasActiveCombineSuit() and !ix.faction.Get(client:Team()).allowCIDCreator) then
client:NotifyLocalized("idNotAllowed")
return false
end
end

View File

@@ -0,0 +1,106 @@
--[[
| 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 = "MOE Access Card"
ITEM.model = Model("models/n7/props/n7_cid_card.mdl")
ITEM.description = "A Ministry of Enlightenment Access Keycard."
ITEM.category = "Combine"
ITEM.skin = 2
ITEM.iconCam = {
pos = Vector(-509.64, -427.61, 310.24),
ang = Angle(25, 400, 0),
fov = 0.59
}
function ITEM:GetName()
local accessLevel = self:GetData("accessLevel", "Member Access")
return "MOE " .. accessLevel .. " Keycard"
end
function ITEM:GetDescription()
local idCard = ix.item.instances[self:GetData("cardID")]
return idCard and string.format(self.description.."\n\nCurrently bound to identity card #%s.", idCard:GetData("cardNumber")) or
(self:GetData("cardID") and self.description.."\n\nCurrently bound." or self.description)
end
ITEM.functions.Bind = {
name = "Bind ID Card",
icon = "icon16/vcard_edit.png",
OnClick = function(itemTable)
local cards = {}
for _, v in pairs(LocalPlayer():GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
table.insert(cards, {
text = v:GetName(),
value = v
})
end
local cardsCount = table.Count(cards)
if (cardsCount > 1) then
Derma_Select("Bind ID Card to MOE Card", "Please select a ID card to bind to this MOE Card:",
cards, "Select ID card",
"Confirm Operation", function(value, name)
netstream.Start("ixBindMOECard", itemTable:GetID(), value:GetID())
end, "Cancel")
elseif (cardsCount == 1) then
Derma_Query("Are you sure you wish to bind your ID to this MOE Card?", "Bind ID Card to MOE Card",
"Confirm Operation", function()
netstream.Start("ixBindMOECard", itemTable:GetID(), cards[1].value:GetID())
end, "Cancel")
else
LocalPlayer():NotifyLocalized("You do not have ID card to bind to this MOE Card.")
end
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!IsValid(itemTable.player)) then
return false
end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!inventory:HasItem("id_card")) then
return false
end
if (itemTable:GetData("cardID")) then
return false
end
return true
end
}
ITEM.functions.SetAccessLevel = {
name = "Toggle Card Access Level",
icon = "icon16/vcard_add.png",
OnRun = function(itemTable)
local client = itemTable.player
local accessLevel = itemTable:GetData("accessLevel", "Member Access")
local target = accessLevel == "Member Access" and "Management Access" or "Member Access"
itemTable:SetData("accessLevel", target)
client:NotifyLocalized("You have set this card's Access Level to " .. target .. ".")
return false
end,
OnCanRun = function(itemTable)
return (!IsValid(itemTable.entity) and IsValid(itemTable.player) and (itemTable.player:Team() == FACTION_ADMIN or itemTable.player:IsCombine() or itemTable.player:GetCharacter():HasFlags("M"))) == true
end
}

View File

@@ -0,0 +1,226 @@
--[[
| 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 = "POS Terminal"
ITEM.model = Model("models/willardnetworks/props/posterminal.mdl")
ITEM.description = "A device that allows someone to request money from another person to be deposited upon another card."
ITEM.category = "Combine"
function ITEM:GetDescription()
local idCard = ix.item.instances[self:GetData("cardID")]
return idCard and string.format(self.description.."\n\nCurrently bound to identity card #%s.", idCard:GetData("cardNumber")) or self.description
end
if (SERVER) then
function ITEM:AddTransactionID(id)
local ids = self:GetData("transactionIDs", {})
ids[#ids + 1] = id
self:SetData("transactionIDs", ids, false, false, true)
end
end
ITEM.functions.RequestCredits = {
name = "Request credits",
icon = "icon16/money.png",
OnClick = function(itemTable)
local client = itemTable.player
if (ix.config.Get("creditsNoConnection")) then
client:EmitSound("hl1/fvox/buzz.wav", 60, 100, 0.5)
client:NotifyLocalized("errorNoConnection")
return false
end
Derma_StringRequest("Request credits", "How many credits do you want to request?", itemTable:GetData("lastAmount", 0), function(text)
local amount = tonumber(text)
if (amount) then
Derma_StringRequest("Request credits - COMMENT", "Please state the reason for the transaction:", "", function(reason)
if (text == "") then
client:NotifyLocalized("reasonNotValid")
return
end
netstream.Start("ixRequestCredits", itemTable:GetID(), math.floor(amount), reason)
end)
else
client:NotifyLocalized("numNotValid")
end
end)
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!itemTable:GetData("cardID", false)) then
return false
end
return true
end
}
ITEM.functions.Bind = {
name = "Bind ID Card",
icon = "icon16/vcard_edit.png",
OnClick = function(itemTable)
local client = itemTable.player
if (ix.config.Get("creditsNoConnection")) then
client:EmitSound("hl1/fvox/buzz.wav", 60, 100, 0.5)
client:NotifyLocalized("errorNoConnection")
return false
end
local cards = {}
for _, v in pairs(client:GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
table.insert(cards, {
text = v:GetName(),
value = v
})
end
local cardsCount = table.Count(cards)
if (cardsCount > 1) then
Derma_Select("Bind ID Card to POS", "Please select a ID card to bind to this POS terminal:",
cards, "Select ID card",
"Confirm Operation", function(value, name)
netstream.Start("ixBindTerminal", itemTable:GetID(), value:GetID())
end, "Cancel")
elseif (cardsCount == 1) then
Derma_Query("Are you sure you wish to bind your ID to this POS terminal?", "Bind ID Card to POS",
"Confirm Operation", function()
netstream.Start("ixBindTerminal", itemTable:GetID(), cards[1].value:GetID())
end, "Cancel")
else
client:NotifyLocalized("You do not have ID card to bind to this terminal.")
end
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then return false end
if (!IsValid(itemTable.player)) then return false end
if (itemTable:GetData("cardIDLock", false)) then return false end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!inventory:HasItem("id_card")) then return false end
if (!itemTable:GetData("cardID", false)) then return true end
if (inventory:GetItemCount("id_card") == 1 and inventory:GetItemByID(itemTable:GetData("cardID"))) then
return false
end
return true
end
}
ITEM.functions.ShowLog = {
name = "Show Transactions",
icon = "icon16/eye.png",
OnRun = function(itemTable, data)
local inventory = itemTable.player:GetCharacter():GetInventory()
PLUGIN:SelectTransactions(itemTable.player, "pos", itemTable:GetID(), data and data[1], itemTable:GetData("cardIDLock", false) and !inventory:GetItemByID(itemTable:GetData("cardID")))
return false
end,
isMulti = true,
multiOptions = function(item, player)
local options = {{name = "1 day", data = {1}}}
for i = 2, 6 do
options[#options + 1] = {name = i.." days", data = {i}}
end
options[#options + 1] = {name = "1 week", data = {7}}
options[#options + 1] = {name = "2 week", data = {14}}
options[#options + 1] = {name = "1 month", data = {30}}
options[#options + 1] = {name = "other", data = {-1}, OnClick = function(itemTable)
Derma_StringRequest("Transaction Log Days", "How many days of transaction logs do you wish to see?", "7", function(text)
local amount = tonumber(text)
if (!amount or amount <= 0) then return end
net.Start("ixInventoryAction")
net.WriteString("ShowLog")
net.WriteUInt(itemTable.id, 32)
net.WriteUInt(itemTable.invID, 32)
net.WriteTable({amount})
net.SendToServer()
end)
return false
end}
return options
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then return false end
if (!IsValid(itemTable.player)) then return false end
if (!itemTable:GetData("cardID", false)) then return false end
return true
end
}
ITEM.functions.Lock = {
name = "Lock ID Card",
icon = "icon16/lock.png",
OnRun = function(itemTable)
itemTable:SetData("cardIDLock", true)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then return false end
if (!IsValid(itemTable.player)) then return false end
if (itemTable:GetData("cardIDLock", false)) then return false end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!itemTable:GetData("cardID", false)) then return false end
if (!inventory:GetItemByID(itemTable:GetData("cardID"))) then return false end
return true
end
}
ITEM.functions.LockUn = {
name = "UnLock ID Card",
icon = "icon16/lock_open.png",
OnRun = function(itemTable)
itemTable:SetData("cardIDLock", false)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then return false end
if (!IsValid(itemTable.player)) then return false end
if (!itemTable:GetData("cardIDLock", false)) then return false end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!itemTable:GetData("cardID", false)) then return false end
if (!inventory:GetItemByID(itemTable:GetData("cardID"))) then return false end
return true
end
}

View File

@@ -0,0 +1,157 @@
--[[
| 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
REQUEST_CP = 0
REQUEST_MED = 1
REQUEST_WORK = 2
ITEM.name = "Request Device"
ITEM.model = Model("models/gibs/shield_scanner_gib1.mdl")
ITEM.description = "A small device with rounded corners, housing one button. A small combine logo is visible.\n\nThe instructions read: please first register this device by holding your ID card against this device. Once registration is completed, you can request assistance from Civil Protection by pressing the button and stating your request. Your name and CID is automatically included with the request.\nPlease be aware the misuse of the request device, making false statements to Civil Protection and identity fraud are punishable by law and will result in prosecution by Civil Protection."
ITEM.price = 20
ITEM.category = "Combine"
function ITEM:GetDescription()
local idCard = ix.item.instances[self:GetData("cardID")]
return idCard and string.format(self.description.."\n\nCurrently bound to identity card #%s.", idCard:GetData("cardNumber")) or self.description
end
local function GetRequestTable(data)
return {
name = data.actionName,
icon = "icon16/help.png",
OnClick = function(itemTable)
if (ix.config.Get("creditsNoConnection")) then
itemTable.player:EmitSound("hl1/fvox/buzz.wav", 60, 100, 0.5)
return
end
Derma_StringRequest(data.requestTitle, data.requestMessage, PLUGIN.text,
function(text)
if (text and string.utf8len(text) > 0) then
netstream.Start("ixRequest", itemTable:GetID(), text, data.requestType)
end
PLUGIN.text = nil
end,
function(text)
if (text == PLUGIN.text) then
PLUGIN.text = text
elseif (text and string.utf8len(text) > 0)then
PLUGIN.text = text
else
PLUGIN.text = nil
end
end, "MAKE REQUEST", "CANCEL"
)
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!itemTable:GetData("cardID", false)) then
return false
end
return true
end
}
end
ITEM.functions.RequestCp = GetRequestTable({
actionName = "Make CP Request",
requestTitle = "Request Civil Protection Assistance",
requestMessage = "Please enter your assistance request for Civil Protection. Your name and CID will automatically be included in the request.",
requestType = REQUEST_CP
})
ITEM.functions.RequestMed = GetRequestTable({
actionName = "Make CMRU Request",
requestTitle = "Request Civil Medical & Research Union Assistance",
requestMessage = "Please enter your assistance request for Civil Medical Research Union. Your name and CID will automatically be included in the request. Do not forget to tell your location!",
requestType = REQUEST_MED
})
ITEM.functions.RequestCwu = GetRequestTable({
actionName = "Make CWU Request",
requestTitle = "Request Civil Workers Union Assistance",
requestMessage = "Please enter your assistance request for Civil Workers Union. Your name and CID will automatically be included in the request.",
requestType = REQUEST_WORK
})
ITEM.functions.Bind = {
name = "Bind ID Card",
icon = "icon16/vcard_edit.png",
OnClick = function(itemTable)
local cards = {}
for _, v in pairs(LocalPlayer():GetCharacter():GetInventory():GetItemsByUniqueID("id_card")) do
table.insert(cards, {
text = v:GetName(),
value = v
})
end
local cardsCount = table.Count(cards)
if (cardsCount > 1) then
Derma_Select("Bind ID Card to RD", "Please select a ID card to bind to this Request Device:",
cards, "Select ID card",
"Confirm Operation", function(value, name)
netstream.Start("ixBindRequestDevice", itemTable:GetID(), value:GetID())
end, "Cancel")
elseif (cardsCount == 1) then
Derma_Query("Are you sure you wish to bind your ID to this Request Device?", "Bind ID Card to RD",
"Confirm Operation", function()
netstream.Start("ixBindRequestDevice", itemTable:GetID(), cards[1].value:GetID())
end, "Cancel")
else
LocalPlayer():NotifyLocalized("You do not have ID card to bind to this request device.")
end
end,
OnRun = function(itemTable)
return false
end,
OnCanRun = function(itemTable)
if (IsValid(itemTable.entity)) then
return false
end
if (!IsValid(itemTable.player)) then
return false
end
local inventory = itemTable.player:GetCharacter():GetInventory()
if (!inventory:HasItem("id_card")) then
return false
end
if (!itemTable:GetData("cardID", false)) then
return true
end
if (inventory:GetItemCount("id_card") == 1 and inventory:GetItemByID(itemTable:GetData("cardID"))) then
return false
end
return true
end
}
if (CLIENT) then
netstream.Hook("rdMoreThanOneText", function(text)
PLUGIN.rdText = text
end)
end

View File

@@ -0,0 +1,281 @@
--[[
| 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 ix = ix
local math = math
local tostring = tostring
local pairs = pairs
local netstream = netstream
local CurTime = CurTime
local IsValid = IsValid
local util = util
local hook = hook
local ipairs = ipairs
local table = table
local PLUGIN = PLUGIN
ix.command.Add("CharSetCredits", {
description = "@cmdCharSetMoney",
privilege = "Set Credits",
arguments = {
ix.type.character,
ix.type.number
},
OnRun = function(self, client, target, amount)
amount = math.Round(amount)
if (amount <= 0) then
return "@invalidArg", 2
end
target:SetCredits(amount)
client:NotifyLocalized("setCredits", target:GetName(), tostring(amount))
end
})
ix.command.Add("CharGiveCredits", {
description = "@cmdCharGiveCredits",
privilege = "Set Credits",
arguments = {
ix.type.character,
ix.type.number
},
OnRun = function(self, client, target, amount)
amount = math.Round(amount)
target:GiveCredits(amount)
client:NotifyLocalized("giveCredits", target:GetName(), tostring(amount))
end
})
ix.command.Add("Request", {
description = "@cmdRequest",
arguments = {
ix.type.text
},
combineBeep = true,
OnRun = function(self, client, text)
local character = client:GetCharacter()
if (!character) then return end
local items = character:GetInventory():GetItems()
local requestDevices = {}
for _, item in pairs(items) do
if (item.uniqueID == "request_device" and item:GetData("cardID")) then
requestDevices[#requestDevices + 1] = item
end
end
if (#requestDevices > 1) then
client:NotifyLocalized("rdMoreThanOne")
netstream.Start(client, "rdMoreThanOneText", text)
return
elseif (#requestDevices == 0) then
client:NotifyLocalized("rdNoRD")
return
end
if (ix.config.Get("creditsNoConnection")) then
client:EmitSound("hl1/fvox/buzz.wav", 60, 100, 0.5)
return
end
local idCard = ix.item.instances[requestDevices[1]:GetData("cardID")]
if (!idCard) then
client:NotifyLocalized("rdError")
return
end
if (client.ixNextRequest and client.ixNextRequest > CurTime()) then
client:NotifyLocalized("rdFreqLimit")
return
else
client.ixNextRequest = CurTime() + 10
end
idCard:LoadOwnerGenericData(PLUGIN.RequestSuccess, PLUGIN.RequestError, client, text)
end
})
ix.command.Add("WithdrawCredit", {
description = "Withdraws credits from the specified character's active CID card.",
OnCheckAccess = function(self, client)
return client:GetCharacter() and (client:GetCharacter():GetFaction() == FACTION_ADMIN or client:GetCharacter():HasFlags("U"))
end,
arguments = {
ix.type.character,
ix.type.number
},
OnRun = function(self, client, target, amount)
amount = math.Round(amount)
if (amount <= 0) then
return "@invalidArg", 2
end
if (target:HasCredits(amount)) then
local receiverCardId = client:GetCharacter():GetIdCard()
local senderCardId = target:GetIdCard()
PLUGIN:CreditTransaction(receiverCardId, senderCardId, amount, target, client, nil, "CCA Withdraw")
target:GetPlayer():Notify("The Combine Civil Administration withdrew "..amount.." credits from your card.")
else
client:Notify("Character do not have this amount of credits.")
end
end
})
ix.command.Add("CreateCid", {
description = "Creates new CID card for the specified character.",
adminOnly = true,
arguments = {
ix.type.player
},
OnRun = function(self, client, target)
if (IsValid(target) and target:IsPlayer() and target:GetCharacter()) then
local character = target:GetCharacter()
local cid = character:GetCid()
if (!cid) then
client:NotifyLocalized("idNotFound")
return
end
character:CreateIDCard()
client:EmitSound("buttons/button4.wav", 60, 100, 0.5)
client:NotifyLocalized("idCardAdded")
if (target != client) then
target:NotifyLocalized("idCardRecreated")
end
else
client:NotifyLocalized("plyNotValid")
end
end
})
if (ix.plugin.list.doors) then
-- Overriding Helix door plugin command to use credits instead
ix.command.Add("DoorBuy", {
description = "@cmdDoorBuy",
OnRun = function(self, client, arguments)
-- Get the entity 96 units infront of the player.
local data = {}
data.start = client:GetShootPos()
data.endpos = data.start + client:GetAimVector() * 96
data.filter = client
local trace = util.TraceLine(data)
local entity = trace.Entity
-- Check if the entity is a valid door.
if (IsValid(entity) and entity:IsDoor() and !entity:GetNetVar("disabled")) then
if (!entity:GetNetVar("ownable") or entity:GetNetVar("faction") or entity:GetNetVar("class")) then
return "@dNotAllowedToOwn"
end
if (IsValid(entity:GetDTEntity(0))) then
return "@dOwnedBy", entity:GetDTEntity(0):Name()
end
entity = IsValid(entity.ixParent) and entity.ixParent or entity
-- Get the price that the door is bought for.
local price = entity:GetNetVar("price", ix.config.Get("doorCost"))
local character = client:GetCharacter()
-- Check if the player can actually afford it.
if (character:HasCredits(price)) then
-- Set the door to be owned by this player.
entity:SetDTEntity(0, client)
entity.ixAccess = {
[client] = DOOR_OWNER
}
ix.plugin.list.doors:CallOnDoorChildren(entity, function(child)
child:SetDTEntity(0, client)
end)
local doors = character:GetVar("doors") or {}
doors[#doors + 1] = entity
character:SetVar("doors", doors, true)
-- Take their money and notify them.
character:TakeCredits(price, "Housing", "Door purchased")
ix.city.main:AddCredits(price)
hook.Run("OnPlayerPurchaseDoor", client, entity, true, ix.plugin.list.doors.CallOnDoorChildren)
ix.log.Add(client, "buydoor")
return "@dPurchased", price..(price == 1 and " credit" or " credits")
else
-- Otherwise tell them they can not.
return "@canNotAfford"
end
else
-- Tell the player the door isn't valid.
return "@dNotValid"
end
end
})
ix.command.Add("DoorSell", {
description = "@cmdDoorSell",
OnRun = function(self, client, arguments)
-- Get the entity 96 units infront of the player.
local data = {}
data.start = client:GetShootPos()
data.endpos = data.start + client:GetAimVector() * 96
data.filter = client
local trace = util.TraceLine(data)
local entity = trace.Entity
-- Check if the entity is a valid door.
if (IsValid(entity) and entity:IsDoor() and !entity:GetNetVar("disabled")) then
-- Check if the player owners the door.
if (client == entity:GetDTEntity(0)) then
entity = IsValid(entity.ixParent) and entity.ixParent or entity
-- Get the price that the door is sold for.
local price = math.Round(entity:GetNetVar("price", ix.config.Get("doorCost")) * ix.config.Get("doorSellRatio"))
local character = client:GetCharacter()
-- Remove old door information.
entity:RemoveDoorAccessData()
local doors = character:GetVar("doors") or {}
for k, v in ipairs(doors) do
if (v == entity) then
table.remove(doors, k)
end
end
character:SetVar("doors", doors, true)
-- Take their money and notify them.
character:GiveCredits(price, "Housing", "Door sold")
hook.Run("OnPlayerPurchaseDoor", client, entity, false, PLUGIN.CallOnDoorChildren)
ix.log.Add(client, "selldoor")
return "@dSold", price..(price == 1 and " credit" or " credits")
else
-- Otherwise tell them they can not.
return "@notOwner"
end
else
-- Tell the player the door isn't valid.
return "@dNotValid"
end
end
})
end

View File

@@ -0,0 +1,210 @@
--[[
| 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 CAMI = CAMI
local ix = ix
local IsValid = IsValid
local net = net
local tonumber = tonumber
local Color = Color
local chat = chat
local string = string
local PLUGIN = PLUGIN
PLUGIN.name = "CID"
PLUGIN.author = "Gr4Ss"
PLUGIN.description = "Adds identification cards and credits as digital currency."
CAMI.RegisterPrivilege({
Name = "Helix - Set Credits",
MinAccess = "superadmin"
})
ix.config.Add("creditsNoConnection", false, "Disable the use of credits in some situations, simulating the connection to the Combine network being down.", nil, {
category = "Miscellaneous"
})
ix.config.Add("requestDeviceAction", "just used request device.", "The action that should be sent after someone uses request device.", nil, {
category = "Miscellaneous"
})
ix.char.RegisterVar("cid", {
field = "cid",
fieldType = ix.type.string,
default = nil,
bNoDisplay = true
})
ix.char.RegisterVar("idCardBackup", {
field = "idCardBackup",
default = {},
bNoDisplay = true,
bNoNetworking = true
})
ix.char.RegisterVar("idCard", {
field = "idcard",
fieldType = ix.type.number,
default = nil,
bNoDisplay = true,
OnSet = function(self, value)
local client = self:GetPlayer()
if (IsValid(client)) then
self.vars.idCard = value
net.Start("ixCharacterVarChanged")
net.WriteUInt(self:GetID(), 32)
net.WriteString("idCard")
net.WriteType(self.vars.idCard)
net.Broadcast()
end
end,
OnGet = function(self, default)
local idCard = self.vars.idCard
return tonumber(idCard) or 0
end,
OnAdjust = function(self, client, data, value, newData)
newData.idCard = value
end
})
ix.util.Include("cl_plugin.lua")
ix.util.Include("sh_commands.lua")
ix.util.Include("sv_hooks.lua")
ix.util.Include("sv_net.lua")
ix.util.Include("sv_plugin.lua")
ix.lang.AddTable("english", {
cmdCharSetCredits = "Set a character's Credits.",
cmdCharGiveCredits = "Give a character Credits.",
cmdRequest = "Make a request for assistance to Civil Protection. Will use a ID card-bound request device from your inventory.",
setCredits = "You have set %s's credits to %s.",
giveCredits = "You have given %s %s credits.",
scanning = "Scanning...",
idNotFound = "ERROR: Biological signature not found.",
idNoBlank = "ERROR: No blank card inserted.",
idCardAdded = "SUCCESS: ID Card created.",
idCardRecreated = "SUCCESS: ID Card recreated.",
idNotAllowed = "Device does not respond when you try to use it.",
posBound = "SUCCESS: POS terminal bound to the specified ID Card.",
posBoundInactiveCard = "ERROR: ID Card is no longer active. Please dispose of inactive card immediately.",
posRequestSent = "INFO: Performing credit transaction...",
posRequestExecuting = "INFO: Executing transaction... please wait...",
posTransactionSuccess = "SUCCESS: Transaction complete.",
posError = "ERROR: Unexpected error occurred. Transaction was terminated.",
posBoundCardNotActive = "ERROR: Bound ID Card no longer active. Please dispose of inactive card immediately.",
posCardNotActive = "ERROR: Used ID Card no longer active. Please dispose of inactive card immediately.",
posTransOngoing = "%s tried to start a new transaction, but you are still finishing another transaction.",
posTransExpired = "Your transaction has expired.",
posTransactionRefused = "Your POS transaction was refused or timed out.",
numNotValid = "You specified invalid amount of credits!",
reasonNotValid = "You specified an invalid reason for the transaction!",
transactionNoMoney = "ERROR: Insufficient credits.",
transactionOwnChars = "ERROR: You cannot transfer credits between your own characters!",
transactionSelf = "ERROR: You cannot transfer credits to yourself!",
rdBound = "SUCCESS: Request Device successfully bound to the specified ID Card.",
rdError = "ERROR: Unexpected error occurred. Please find a Civil Protection officer to file your request manually.",
rdMoreThanOne = "You have more than one bound request device, please select in your inventory which one you want to use.",
rdNoRD = "You do not have a request device, or it is not bound to an ID card!",
rdFreqLimit = "Please wait at least 10 seconds between requests.",
cwuBound = "SUCCESS: CWU Card successfully bound to the specified ID Card.",
dobBound = "SUCCESS: DOB Card successfully bound to the specified ID Card.",
cmruBound = "SUCCESS: CMRU Card successfully bound to the specified ID Card.",
conBound = "SUCCESS: CCR Card successfully bound to the specified ID Card.",
targetTransactionInProgress = "This person already has a transaction in progress!",
idCardIssued = "New identity card issued for %s by %s",
errorNoConnection = "ERROR: NO CONNECTION"
})
ix.lang.AddTable("spanish", {
posBoundCardNotActive = "ERROR: La tarjeta ID vinculada ya no está activa. Por favor, deshágase de la tarjeta inactiva inmediatamente.",
posTransExpired = "Tu transacción ha caducado.",
posTransactionSuccess = "ÉXITO: Transacción completada.",
posTransOngoing = "%s ha intentado iniciar una nueva transacción, pero todavía estás terminando otra transacción.",
posRequestExecuting = "INFO: Ejecutando la transacción... por favor espere...",
numNotValid = "¡Has especificado una cantidad de créditos inválida!",
posError = "ERROR: Se ha producido un error inesperado. La transacción ha finalizado.",
posCardNotActive = "ERROR: La tarjeta ID vinculada ya no está activa. Por favor, deshágase de la tarjeta inactiva inmediatamente.",
reasonNotValid = "¡Has especificado un motivo no válido para la transacción!",
transactionOwnChars = "ERROR: ¡No puedes transferir créditos entre tus propios personajes!",
transactionNoMoney = "ERROR: Créditos insuficientes.",
targetTransactionInProgress = "¡Esta persona ya tiene una transacción en curso!",
transactionSelf = "ERROR: ¡No puedes transferirte créditos a ti mismo!",
rdError = "ERROR: Se ha producido un error inesperado. Por favor, busque a un agente de Protección Civil para presentar tu solicitud manualmente.",
giveCredits = "Has dado %s %s créditos.",
scanning = "Escaneando...",
cmdCharSetCredits = "Establecer los créditos de un personaje.",
cmdCharGiveCredits = "Dar créditos a un personaje.",
posTransactionRefused = "Su transacción en del datafono ha sido rechazada o ha expirado.",
idNoBlank = "ERROR: No se ha insertado ninguna tarjeta en blanco.",
posBoundInactiveCard = "ERROR: La tarjeta de identificación ya no está activa. Por favor, deshágase de la tarjeta inactiva inmediatamente.",
rdNoRD = "¡No tiene un dispositivo de socorro, o no está vinculado a una tarjeta de identificación!",
idCardAdded = "ÉXITO: Tarjeta de identificación creada.",
posRequestSent = "INFO: Realizando una transacción de crédito...",
idCardRecreated = "ÉXITO: Tarjeta de identificación recreada.",
posBound = "ÉXITO: El datafono está vinculado a la tarjeta de identificación especificada.",
idNotAllowed = "El dispositivo no responde cuando intentas utilizarlo.",
idNotFound = "ERROR: Señal Biológica no encontrada.",
rdMoreThanOne = "Tienes más de un dispositivo de socorro vinculado, por favor selecciona en tu inventario cuál quieres usar.",
rdFreqLimit = "Por favor, espere al menos 10 segundos entre peticiones.",
cmdRequest = "Realiza una solicitud de ayuda a Protección Civil. Utilizará un dispositivo de socorro vinculado a una tarjeta de identificación de tu inventario.",
rdBound = "ÉXITO: El dispositivo de socorro se ha vinculado con éxito a la tarjeta de identificación especificada.",
setCredits = "Los créditos de %s han sido establecidos a %s.",
cwuBound = "ÉXITO: Tarjeta UTC vinculada con éxito a la tarjeta ID especificada.",
idCardIssued = "Nuevo documento de identidad emitido para %s por %s"
})
do
local CLASS = {}
CLASS.color = Color(175, 125, 100)
CLASS.format = "%s, #%s requests %s\"%s\""
CLASS.formatCP = "%s requests %s\"%s\""
function CLASS:CanHear(speaker, listener, data)
if data.otherListeners and data.otherListeners[listener] then return true end
return listener == speaker or listener:HasActiveCombineSuit() or ix.faction.Get(listener:Team()).canHearRequests == true
end
local requestTypes = {
[REQUEST_CP] = "CP",
[REQUEST_MED] = "CMRU",
[REQUEST_WORK] = "CWU"
}
function CLASS:OnChatAdd(speaker, text, aonymous, data)
local requestType = ""
if (data.requestType) then
requestType = requestTypes[data.requestType].." "
end
if (speaker:IsCombine()) then
chat.AddText(self.color, string.format(self.formatCP, "Protection Unit", requestType, text))
else
chat.AddText(self.color, string.format(self.format, data.name, data.cid, requestType, text))
end
end
ix.chat.Register("request", CLASS)
end

View File

@@ -0,0 +1,65 @@
--[[
| 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 ix = ix
local pairs = pairs
local math = math
local PLUGIN = PLUGIN
-- Always ensure the character's current CID item is loaded
function PLUGIN:CharacterLoaded(character)
local idCardID = character:GetIdCard()
local inventory = character:GetInventory()
if (idCardID and (!inventory or !inventory:GetItemByID(idCardID)) and !ix.item.instances[idCardID]) then
ix.item.LoadItemByID(idCardID)
end
if (inventory) then
for _, v in pairs(inventory:GetItems()) do
if (v:GetData("cardID") and !ix.item.instances[v:GetData("cardID")]) then
ix.item.LoadItemByID(v:GetData("cardID"))
end
end
end
end
function PLUGIN:OnCharacterCreated(client, character)
local charID = character.id
local id = self:GenerateCid(charID)
character:SetCid(id)
end
function PLUGIN:InventoryItemAdded(oldInv, inventory, newItem)
if (oldInv != nil) then return end
if (newItem.uniqueID == "id_card" and
newItem:GetData("owner") == inventory.owner and
newItem:GetData("active") != false) then
local character = ix.char.loaded[inventory.owner]
local oldCardId = character:GetIdCard()
if (oldCardId) then
local oldCard = ix.item.instances[oldCardId]
if (oldCard) then
oldCard:TransferData(newItem, true)
end
else
local dataBackup = character:GetIdCardBackup({})
for k, v in pairs(dataBackup) do
newItem:SetData(k, v)
end
end
character:SetIdCard(newItem:GetID())
end
end

View File

@@ -0,0 +1,485 @@
--[[
| 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 netstream = netstream
local CAMI = CAMI
local ix = ix
local math = math
local util = util
local IsValid = IsValid
local CurTime = CurTime
local istable = istable
local Color = Color
local string = string
local PLUGIN = PLUGIN
--Honeypot netstream hook, overwrite unsecure hook in sh_id_card.lua
netstream.Hook("ixSetIDCardCredits", function(client, itemID, amount)
local bNoAccess = !CAMI.PlayerHasAccess(client, "Helix - Set Credits")
if (bNoAccess) then
ix.log.Add(client, "netstreamHoneypot", "ixSetIDCardCredits", bNoAccess)
return
end
if (!ix.item.instances[itemID] or amount < 0) then
return
end
ix.item.instances[itemID]:SetCredits(math.floor(amount))
ix.log.Add(client, "creditIDCardSetCredits", itemID, amount)
end)
-- Request credits
netstream.Hook("ixRequestCredits", function(client, posTerminalID, amount, reason)
if (!client:GetCharacter():GetInventory():GetItemByID(posTerminalID)) then
return
end
if (reason == "") then
client:NotifyLocalized("reasonNotValid")
return
end
local posTerminal = ix.item.instances[posTerminalID]
if (!posTerminal) then
return
end
local receiverCard = ix.item.instances[posTerminal:GetData("cardID", -1)]
if (!receiverCard) then
client:NotifyLocalized("posError")
return
end
if (receiverCard:GetData("active") == false) then
client:NotifyLocalized("posBoundCardNotActive")
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) and target:IsPlayer() and target:GetCharacter()) then
if (IsValid(target.ixSendCreditsTo) and target.ixSendCreditsToTime > CurTime()) then
client:NotifyLocalized("targetTransactionInProgress")
return
end
posTerminal:SetData("lastAmount", amount, nil, nil, true)
target.ixSendCreditsTo = client
target.ixSendCreditsToTime = CurTime() + 15
target.ixSendCreditsReason = reason
target.ixReceiverCardID = receiverCard:GetID()
target.ixSendCreditsAmount = amount
target.ixSendCreditsPosTerminal = posTerminal
netstream.Start(target, "ixRequestCredits", client, amount, reason)
client:NotifyLocalized("posRequestSent")
else
client:NotifyLocalized("plyNotValid")
end
end)
netstream.Hook("ixConfirmCreditOperation", function(sender, senderCardID)
if (!IsValid(sender.ixSendCreditsTo)) then
return
end
local receiver = sender.ixSendCreditsTo
local receiverCardID = sender.ixReceiverCardID
local reason = sender.ixSendCreditsReason
local amount = sender.ixSendCreditsAmount
local posTerminal = sender.ixSendCreditsPosTerminal
sender.ixSendCreditsTo = nil
sender.ixSendCreditsToTime = nil
sender.ixSendCreditsReason = nil
sender.ixReceiverCardID = nil
sender.ixSendCreditsAmount = nil
if (!sender:GetCharacter():GetInventory():GetItemByID(senderCardID)) then
if (IsValid(receiver)) then
receiver:NotifyLocalized("posError")
end
sender:NotifyLocalized("posError")
return
end
local senderCard = ix.item.instances[senderCardID]
if (senderCard:GetData("active") == false) then
if (IsValid(receiver)) then
receiver:NotifyLocalized("posCardNotActive")
end
sender:NotifyLocalized("posCardNotActive")
return
end
if (!senderCard:HasCredits(amount)) then
if (IsValid(receiver)) then
receiver:NotifyLocalized("transactionNoMoney")
end
sender:NotifyLocalized("transactionNoMoney")
return
end
PLUGIN:CreditTransaction(receiverCardID, senderCardID, amount, sender, receiver, posTerminal, reason)
end)
netstream.Hook("ixDenyCreditOperation", function(sender)
if (IsValid(sender.ixSendCreditsTo)) then
sender.ixSendCreditsTo:NotifyLocalized("posTransactionRefused")
end
sender.ixSendCreditsTo = nil
sender.ixSendCreditsToTime = nil
sender.ixSendCreditsReason = nil
sender.ixReceiverCardID = nil
sender.ixSendCreditsAmount = nil
end)
netstream.Hook("ixBindTerminal", function(client, itemID, cardID)
if (!client:GetCharacter():GetInventory():GetItemByID(cardID) or !client:GetCharacter():GetInventory():GetItemByID(itemID)) then
return
end
local itemTable = ix.item.instances[itemID]
if (itemTable:GetData("active") == false) then
client:NotifyLocalized("posBoundInactiveCard")
return
end
if (itemTable:GetData("cardIDLock", false)) then return end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("posBound")
end)
-- Send Credits
netstream.Hook("ixSendCredits", function(client, senderCardID, receiverCid, amount, senderCid)
if (!client:GetCharacter():GetInventory():GetItemByID(senderCardID)) then
client:NotifyLocalized("posError")
return
end
local senderCard = ix.item.instances[senderCardID]
if (!senderCard) then
client:NotifyLocalized("posError")
return
end
amount = math.floor(amount)
if (amount <= 0) then
client:NotifyLocalized("numNotValid")
return
end
if (!senderCard:HasCredits(amount)) then
client:NotifyLocalized("transactionNoMoney")
return
end
if (senderCard:GetData("cid", "00000") == receiverCid) then
client:NotifyLocalized("transactionSelf")
return
end
local receiverQuery = mysql:Select("ix_characters")
receiverQuery:Select("id")
receiverQuery:Select("idcard")
receiverQuery:Select("steamid")
receiverQuery:Where("cid", receiverCid)
receiverQuery:Limit(1)
receiverQuery:Callback(function(result)
if (!result or !istable(result) or #result == 0) then
client:NotifyLocalized("posError")
return
end
local first = result[1]
if (client:SteamID64() == first.steamid and result[1].id != client:GetCharacter():GetID()) then
client:NotifyLocalized("transactionOwnChars")
-- return
end
local receiver = ix.char.loaded[first.id]
ix.combineNotify:AddNotification("LOG:// Subject ID #" .. senderCid .. " sent " .. amount .. " Credits to #" .. receiverCid, nil, client)
PLUGIN:CreditTransaction(result[1].idcard, senderCardID, amount, client, receiver, nil, "Terminal Transfer", senderCid, receiverCid)
end)
receiverQuery:Execute()
end)
-- Request stuff
local red = Color(255, 0, 0, 255)
local orange = Color(255, 165, 0, 255)
local yellow = Color(255, 255, 0, 255)
local function createCombineAlert(client, text, color)
ix.combineNotify:AddImportantNotification(text, color, client)
end
function PLUGIN.RequestSuccess(idCard, genericData, client, text, requestType)
local isBOL = genericData.bol
local isAC = genericData.anticitizen
local alertText, color = "%s, #%s (SC: %d) requesting assistance", yellow
if (client:IsCombine()) then
alertText = "%s (SC: %d) requesting assistance"
elseif (isAC) then
alertText, color = "Anti-Citizen %s, #%s requesting assistance", red
elseif (isBOL) then
alertText, color = "BOL Suspect %s, #%s requesting assistance", orange
elseif (genericData.loyaltyStatus and genericData.loyaltyStatus != "NONE") then
if (genericData.loyaltyStatus == "CCA MEMBER") then
alertText, color = "CCA Member "..alertText, red
else
alertText, color = string.utf8sub(genericData.loyaltyStatus, 1, 7).." Conformist "..alertText, orange
end
elseif (genericData.socialCredits > 90) then
if (genericData.socialCredits >= 175) then
alertText = "Tier 3 Conformist "..alertText
elseif (genericData.socialCredits >= 125) then
alertText = "Tier 2 Conformist "..alertText
else
alertText = "Tier 1 Conformist "..alertText
end
end
if (idCard:GetData("active", false) == false) then
alertText, color = alertText.." with inactive Identification Card", color != red and orange or red
end
alertText = "WRN:// " .. alertText
if (client:IsCombine()) then
createCombineAlert(client, string.format(alertText, genericData.name, math.Clamp(tonumber(genericData.socialCredits), 0, 200)), color)
else
createCombineAlert(client, string.format(alertText, genericData.name, genericData.cid, math.Clamp(tonumber(genericData.socialCredits), 0, 200)), color)
end
local otherListeners = {}
if (requestType == REQUEST_MED or requestType == REQUEST_WORK) then
for _, ply in pairs(player.GetAll()) do
if (ply == client) then continue end
local character = ply:GetCharacter()
if !character then continue end
local inventory = character:GetInventory()
if !inventory then continue end
local radio = nil
if (requestType == REQUEST_MED) then
radio = inventory:HasItem("cmru_radio")
elseif (requestType == REQUEST_WORK) then
radio = inventory:HasItem("cwu_radio")
end
if (radio and radio:GetData("enabled")) then
otherListeners[ply] = true
end
end
end
client:EmitSound("buttons/button3.wav")
ix.chat.Send(client, "me", ix.config.Get("requestDeviceAction", "used request device."), false)
ix.chat.Send(client, "request", text, false, nil, {name = genericData.name, cid = genericData.cid, requestType = requestType, otherListeners = otherListeners})
end
function PLUGIN.RequestError(idCard, client, text)
client:NotifyLocalized("rdError")
end
netstream.Hook("ixRequest", function(client, itemID, text, requestType)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
local idCard = items[itemTable:GetData("cardID")]
if (!itemTable or !idCard or itemTable.uniqueID != "request_device" or idCard.uniqueID != "id_card") then
client:NotifyLocalized("rdError")
return
end
if (client.ixNextRequest and client.ixNextRequest > CurTime()) then
client:NotifyLocalized("rdFreqLimit")
return
else
client.ixNextRequest = CurTime() + 10
end
idCard:LoadOwnerGenericData(PLUGIN.RequestSuccess, PLUGIN.RequestError, client, text, requestType)
end)
netstream.Hook("ixBindRequestDevice", function(client, itemID, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
if (!itemTable or itemTable.uniqueID != "request_device" or itemTable:GetData("active") == false or itemTable:GetData("cardID") or !items[cardID] or items[cardID].uniqueID != "id_card") then
client:NotifyLocalized("posBoundInactiveCard")
return
end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("rdBound")
end)
netstream.Hook("ixBindCWUCard", function(client, itemID, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
if (!itemTable or itemTable.uniqueID != "cwu_card" or itemTable:GetData("cardID") or !items[cardID] or items[cardID].uniqueID != "id_card") then
client:NotifyLocalized("posBoundInactiveCard")
return
end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("cwuBound")
end)
netstream.Hook("ixBindCONCard", function(client, itemID, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
if (!itemTable or itemTable.uniqueID != "con_card" or itemTable:GetData("cardID") or !items[cardID] or items[cardID].uniqueID != "id_card") then
client:NotifyLocalized("posBoundInactiveCard")
return
end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("conBound")
end)
netstream.Hook("ixBindDOBCard", function(client, itemID, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
if (!itemTable or itemTable.uniqueID != "dob_card" or itemTable:GetData("cardID") or !items[cardID] or items[cardID].uniqueID != "id_card") then
client:NotifyLocalized("posBoundInactiveCard")
return
end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("dobBound")
end)
netstream.Hook("ixBindCMRUCard", function(client, itemID, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
if (!itemTable or itemTable.uniqueID != "cmru_card" or itemTable:GetData("cardID") or !items[cardID] or items[cardID].uniqueID != "id_card") then
client:NotifyLocalized("posBoundInactiveCard")
return
end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("cmruBound")
end)
netstream.Hook("ixBindConCard", function(client, itemID, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
if (!itemTable or itemTable.uniqueID != "con_card" or itemTable:GetData("cardID") or !items[cardID] or items[cardID].uniqueID != "id_card") then
client:NotifyLocalized("posBoundInactiveCard")
return
end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("conBound")
end)
netstream.Hook("ixBindMOECard", function(client, itemID, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local itemTable = items[itemID]
if (!itemTable or itemTable.uniqueID != "moe_card" or itemTable:GetData("cardID") or !items[cardID] or items[cardID].uniqueID != "id_card") then
client:NotifyLocalized("posBoundInactiveCard")
return
end
itemTable:SetData("cardID", cardID)
client:EmitSound("buttons/combine_button1.wav", 60, 100, 0.5)
client:NotifyLocalized("moeBound")
end)
netstream.Hook("ixSelectCIDSuccess", function(client, cardID)
local character = client:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (!inventory) then return end
local items = inventory:GetItems()
local cardItem = items[cardID]
if (cardItem and cardItem.uniqueID == "id_card") then
client.ixSelectCIDSuccess(cardItem)
end
end)
netstream.Hook("ixSelectCIDFail", function(client)
client.ixSelectCIDFail()
end)

View File

@@ -0,0 +1,390 @@
--[[
| 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 ix = ix
local string = string
local os = os
local CurTime = CurTime
local IsValid = IsValid
local netstream = netstream
local PLUGIN = PLUGIN
util.AddNetworkString("changeLockAccess")
util.AddNetworkString("changeLockAccessCmru")
util.AddNetworkString("changeLockAccessCon")
ix.log.AddType("creditIDCardSetCredits", function(client, itemId, amount)
return string.format("%s has set card #%d's credits to %d.", client:SteamName(), itemId, amount)
end)
-- CID GENERATION
local prime = 99787 -- prime % 4 = 3! DO NOT CHANGE EVER
local offset = 320 -- slightly larger than sqrt(prime) is ok. DO NOT CHANGE EVER
local block = 1000
function PLUGIN:GenerateCid(id)
id = (id + offset) % prime
local cid = 0
for _ = 1, math.floor(id/block) do
cid = (cid + (id * block) % prime) % prime
end
cid = (cid + (id * (id % block) % prime)) % prime
if (2 * id < prime) then
return Schema:ZeroNumber(cid, 5)
else
return Schema:ZeroNumber(prime - cid, 5)
end
end
ix.log.AddType("creditTransaction", function(client, senderCard, receiverCard, amount, posDevice, reason, senderCID, receiverCID)
local senderCardCid
local receiverCardCid
if !senderCID then
senderCardCid = senderCard:GetData("cid", "INVALID")
else
senderCardCid = (tostring(senderCard:GetData("cid", "00000")) == "00000" and senderCID or senderCard:GetData("cid", "INVALID"))
end
if !receiverCID then
receiverCardCid = receiverCard:GetData("cid", "INVALID")
else
receiverCardCid = (tostring(receiverCard:GetData("cid", "00000") ) == "00000" and receiverCID or receiverCard:GetData("cid", "INVALID"))
end
local senderName = senderCard:GetData("name", "UNKNOWN")
if (IsValid(client) and client:HasActiveCombineMask()) then
senderName = "IDENTITY REDACTED"
senderCardCid = "REDACTED"
end
local insert = mysql:Insert("ix_cid_transactions")
insert:Insert("datetime", os.time())
insert:Insert("sender_name", senderName)
insert:Insert("sender_cid", senderCardCid)
insert:Insert("sender_cardid", senderCard:GetID())
insert:Insert("receiver_name", receiverCard:GetData("name", "UNKNOWN"))
insert:Insert("receiver_cid", receiverCardCid)
insert:Insert("receiver_cardid", receiverCard:GetID())
insert:Insert("amount", amount)
if (reason and reason != "") then
insert:Insert("reason", string.len(reason) > 250 and string.sub(reason, 1, 250) or reason)
else
insert:Insert("reason", "no reason given")
end
if (posDevice) then
insert:Insert("pos", posDevice:GetID())
insert:Insert("read", 0)
insert:Callback(function(result, _, insertID)
posDevice:AddTransactionID(insertID)
end)
else
insert:Insert("pos", 0)
insert:Insert("read", 1)
end
insert:Execute()
return string.format("%s (CID: %s, item: %s) has send %d credits to %s (CID: %s, item: %s) via %s.",
senderCard:GetData("name"),
senderCardCid,
senderCard:GetID(),
amount,
receiverCard:GetData("name"),
receiverCardCid,
receiverCard:GetID(),
posDevice and string.format("POS device for '%s'", reason) or "terminal"
)
end)
function PLUGIN:DatabaseConnected()
local query = mysql:Create("ix_cid_transactions")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("datetime", "INT NOT NULL")
query:Create("sender_name", "VARCHAR(255) NOT NULL")
query:Create("sender_cid", "VARCHAR(255) NOT NULL")
query:Create("sender_cardid", "INT NOT NULL")
query:Create("receiver_name", "VARCHAR(255) NOT NULL")
query:Create("receiver_cid", "VARCHAR(255) NOT NULL")
query:Create("receiver_cardid", "INT NOT NULL")
query:Create("amount", "INT NOT NULL")
query:Create("pos", "INT NOT NULL")
query:Create("read", "TINYINT(1) NOT NULL")
query:Create("reason", "VARCHAR(255) DEFAULT NULL")
query:PrimaryKey("id")
query:Execute()
end
function PLUGIN:SelectTransactions(client, key, value, maxAge, bNoIncludeRead, customCallback)
if (client.ixNextTransactionSelect and client.ixNextTransactionSelect > CurTime()) then
client.ixNextTransactionSelect = CurTime() + 1
return
end
client.ixNextTransactionSelect = CurTime() + 1
maxAge = maxAge or 7
local query = mysql:Select("ix_cid_transactions")
if (key == "cid") then
query.whereList[#query.whereList + 1] = "(`sender_cid` = '"..query:Escape(value).."' OR `receiver_cid` = '"..query:Escape(value).."')"
else
query:Where(key, value)
end
query:WhereGTE("datetime", os.time() - maxAge * 24 * 3600)
if (bNoIncludeRead) then
query:Where("read", 0)
end
query:Select("id")
query:Select("datetime")
query:Select("sender_name")
query:Select("sender_cid")
query:Select("receiver_name")
query:Select("receiver_cid")
query:Select("amount")
query:Select("reason")
if (key == "pos") then
query:Select("pos")
query:Select("read")
end
query:Callback(function(result)
if (!IsValid(client)) then return end
if customCallback then
customCallback(result)
return
end
netstream.Start(client, "ixCreditTransactionLog", result, key == "pos" and !bNoIncludeRead)
end)
query:OrderByDesc("datetime")
query:Execute()
end
function PLUGIN:MarkTransactionsRead(id, bAllFromPos, bRead, pos)
local query = mysql:Update("ix_cid_transactions")
if (bAllFromPos) then
query:Where("pos", id)
else
query:Where("pos", pos)
query:Where("id", id)
end
query:Update("read", bRead and 1 or 0)
query:Execute()
end
netstream.Hook("ixTransactionSetRead", function(client, id, bAllFromPos, bRead, pos)
local inventory = client:GetCharacter():GetInventory()
local item = inventory:GetItemByID(pos or id)
if (!item or (item:GetData("cardIDLock") and !inventory:GetItemByID(item:GetData("cardID")))) then
return
end
PLUGIN:MarkTransactionsRead(id, bAllFromPos, bRead, pos)
end)
function PLUGIN:CreateIDCard(character, inventory, credits)
local genericdata = character:GetGenericdata()
local age, height, eyeColor = character:GetAge(), character:GetHeight(), character:GetEyeColor()
local data = {
owner = character:GetID(),
cid = character:GetCid(),
name = character:GetName(),
geneticDesc = age.." | "..height.." | "..eyeColor.." EYES",
active = true,
credits = credits or 0
}
if (character:GetFaction() == FACTION_VORT) then
data.geneticDesc = age.." | "..height
if (istable(genericdata)) then
genericdata.cid = data["cid"]
character:SetGenericdata(genericdata)
character:Save()
end
end
local success, error = inventory:Add("id_card", 1, data)
if (!success) then
character:GetPlayer():NotifyLocalized(error or "unknownError")
end
end
-- Generic transaction stuff
local function DoCreditTransaction(recipientCard, sendingCard, transactionAmount, sending, recipient, bPosDevice, reason, senderCid, receiverCid)
if (!recipientCard or !sendingCard) then
if (IsValid(sending)) then sending:NotifyLocalized("posError") end
if (IsValid(recipient)) then recipient:NotifyLocalized("posError") end
return
end
local amount = transactionAmount
local senderCard = sendingCard
local receiverCard = recipientCard
local receiver = recipient
local sender = sending
local amountPercent = amount / 100
local vat = ix.config.Get("transactionVatPercent", 2)
vat = math.Round(amountPercent * vat)
if (amount < 0) then
amount = amount * -1
senderCard = recipientCard
receiverCard = sendingCard
sender = recipient
receiver = sending
end
if (senderCard:HasCredits(amount + vat)) then
senderCard:TakeCredits(amount + vat)
ix.city.main:AddCredits(vat)
receiverCard:GiveCredits(amount)
if (IsValid(sender)) then
sender:NotifyLocalized("posTransactionSuccess")
netstream.Start(sender, "TerminalUpdateCredits", amount)
end
if (IsValid(receiver)) then receiver:NotifyLocalized("posTransactionSuccess") end
ix.log.Add(sending, "creditTransaction", sendingCard, recipientCard, transactionAmount, bPosDevice, reason, senderCid, receiverCid)
else
if (IsValid(sender)) then sender:NotifyLocalized("transactionNoMoney") end
if (IsValid(receiver)) then receiver:NotifyLocalized("transactionNoMoney") end
end
end
function PLUGIN:CreditTransaction(receiverCardID, senderCardID, amount, sender, receiver, bPosDevice, reason, senderCid, receiverCid)
senderCid = senderCid or false
receiverCid = receiverCid or false
if (ix.config.Get("creditsNoConnection")) then
if (IsValid(sender)) then sender:NotifyLocalized("errorNoConnection") end
if (IsValid(receiver)) then receiver:NotifyLocalized("errorNoConnection") end
return
end
if (!receiverCardID or !senderCardID) then
if (IsValid(sender)) then sender:NotifyLocalized("posError") end
if (IsValid(receiver)) then receiver:NotifyLocalized("posError") end
return
end
if (!ix.item.instances[receiverCardID]) then
ix.item.LoadItemByID(receiverCardID, nil, function(receiverCard)
if (ix.item.instances[senderCardID]) then
DoCreditTransaction(receiverCard, ix.item.instances[senderCardID], amount, sender, receiver, bPosDevice, reason, senderCid, receiverCid)
else
ix.item.LoadItemByID(senderCardID, function(senderCard)
DoCreditTransaction(receiverCard, senderCard, amount, sender, receiver, bPosDevice, reason, senderCid, receiverCid)
end)
end
end)
return
end
if (!ix.item.instances[senderCardID]) then
ix.item.LoadItemByID(senderCardID, function(senderCard)
DoCreditTransaction(ix.item.instances[receiverCardID], ix.item.instances[senderCardID], amount, sender, receiver, bPosDevice, reason, senderCid, receiverCid)
end)
return
end
DoCreditTransaction(ix.item.instances[receiverCardID], ix.item.instances[senderCardID], amount, sender, receiver, bPosDevice, reason, senderCid, receiverCid)
end
-- CHAR funcs
do
local CHAR = ix.meta.character
function CHAR:CreateIDCard(credits)
PLUGIN:CreateIDCard(self, self:GetInventory(), credits)
end
function CHAR:GetCredits()
local itemID = self:GetIdCard()
if (!itemID or !ix.item.instances[itemID]) then
return 0
end
return ix.item.instances[itemID]:GetCredits()
end
function CHAR:HasCredits(amount)
local itemID = self:GetIdCard()
if (!itemID or !ix.item.instances[itemID]) then
return false
end
return amount <= ix.item.instances[itemID]:GetCredits()
end
function CHAR:SetCredits(amount)
local itemID = self:GetIdCard()
if (!itemID or !ix.item.instances[itemID]) then
return false
end
ix.item.instances[itemID]:SetCredits(amount)
return true
end
function CHAR:GiveCredits(amount, sender, reason)
local itemID = self:GetIdCard()
if (!itemID or !ix.item.instances[itemID]) then
return false
end
return ix.item.instances[itemID]:GiveCredits(amount, sender, reason)
end
function CHAR:TakeCredits(amount, receiver, reason)
local itemID = self:GetIdCard()
if (!itemID or !ix.item.instances[itemID]) then
return false
end
return ix.item.instances[itemID]:TakeCredits(amount, receiver, reason)
end
end
local playerMeta = FindMetaTable("Player")
function playerMeta:SelectCIDCard(onSuccess, onFail)
local items = self:GetCharacter():GetInventory():GetItemsByUniqueID("id_card")
local count = table.Count(items)
if (count == 1) then
onSuccess(items[1])
elseif (count == 0) then
if (onFail) then
onFail()
end
else
self.ixSelectCIDSuccess = onSuccess
if (onFail) then
self.ixSelectCIDFail = onFail
end
netstream.Start(self, "ixSelectCID", isfunction(onFail))
end
end