This commit is contained in:
lifestorm
2024-08-04 23:12:27 +03:00
parent 8064ba84d8
commit 9c918c46e5
7081 changed files with 2173485 additions and 14 deletions

View File

@@ -0,0 +1,49 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
function PLUGIN:HUDPaint()
if (ix.config.Get("SmugglingShowWaypoints")) then
local waypoints = LocalPlayer().ixStashWaypoints
if (waypoints and !table.IsEmpty(waypoints)) then
for k, v in pairs(waypoints) do
local screenPos = v.pos:ToScreen()
local x, y = screenPos.x, screenPos.y
local text = v.name
surface.SetFont("BudgetLabel")
local width = surface.GetTextSize(text)
surface.SetTextColor(color_white)
surface.SetTextPos(x - width / 2, y - 17)
surface.DrawText(text)
end
end
end
end
function PLUGIN:PreDrawHalos()
if (ix.config.Get("SmugglingShowWaypoints")) then
local stashEntities = LocalPlayer().ixStashEntities
if (!stashEntities or table.IsEmpty(stashEntities)) then return end
local entities = {}
for k, v in ipairs(stashEntities) do
if (IsValid(Entity(v)) and Entity(v):GetClass() == "ix_pickupcache") then
entities[#entities + 1] = Entity(v)
end
end
if (entities and !table.IsEmpty(entities)) then
halo.Add(entities, color_white)
end
end
end

View File

@@ -0,0 +1,272 @@
--[[
| 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/
--]]
-- luacheck: globals SMUGGLER_TEXT
-- luacheck: read globals SMUGGLER_BUY SMUGGLER_SELL SMUGGLER_BOTH SMUGGLER_WELCOME SMUGGLER_LEAVE SMUGGLER_NOTRADE SMUGGLER_PRICE
-- luacheck: read globals SMUGGLER_STOCK SMUGGLER_MODE SMUGGLER_MAXSTOCK SMUGGLER_SELLANDBUY SMUGGLER_SELLONLY SMUGGLER_BUYONLY
local PLUGIN = PLUGIN
SMUGGLER_TEXT = {}
SMUGGLER_TEXT[SMUGGLER_SELLANDBUY] = "smugglerBoth"
SMUGGLER_TEXT[SMUGGLER_BUYONLY] = "smugglerBuy"
SMUGGLER_TEXT[SMUGGLER_SELLONLY] = "smugglerSell"
net.Receive("ixSmugglerOpen", function()
local entity = net.ReadEntity()
if (!IsValid(entity)) then
return
end
entity.money = net.ReadUInt(16)
entity.maxStock = net.ReadUInt(16)
entity.pickupLocation = net.ReadString()
entity.items = net.ReadTable()
entity.stashList = net.ReadTable()
ix.gui.smuggler = vgui.Create("ixSmuggler")
ix.gui.smuggler:SetReadOnly(false)
ix.gui.smuggler:Setup(entity)
end)
net.Receive("ixSmugglerEditor", function()
local entity = net.ReadEntity()
if (!IsValid(entity) or !CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Manage Smugglers", nil)) then
return
end
entity.money = net.ReadUInt(16)
entity.maxStock = net.ReadUInt(16)
entity.items = net.ReadTable()
entity.messages = net.ReadTable()
ix.gui.smuggler = vgui.Create("ixSmuggler")
ix.gui.smuggler:SetReadOnly(true)
ix.gui.smuggler:Setup(entity)
ix.gui.smugglerEditor = vgui.Create("ixSmugglerEditor")
end)
net.Receive("ixSmugglerEdit", function()
local panel = ix.gui.smuggler
if (!IsValid(panel)) then
return
end
local entity = panel.entity
if (!IsValid(entity)) then
return
end
local key = net.ReadString()
local data = net.ReadType()
if (key == "mode") then
entity.items[data[1]] = entity.items[data[1]] or {}
entity.items[data[1]][SMUGGLER_MODE] = data[2]
if (!data[2]) then
panel:removeItem(data[1])
elseif (data[2] == SMUGGLER_SELLANDBUY) then
panel:addItem(data[1])
else
panel:addItem(data[1], data[2] == SMUGGLER_SELLONLY and "selling" or "buying")
panel:removeItem(data[1], data[2] == SMUGGLER_SELLONLY and "buying" or "selling")
end
elseif (key == "stockMax") then
entity.maxStock = data
for k in pairs(entity.items) do
panel:addItem(k)
end
elseif (key == "stock") then
local uniqueID = data[1]
local value = data[2]
entity.items[uniqueID] = entity.items[uniqueID] or {}
entity.items[uniqueID][SMUGGLER_STOCK] = value
end
end)
net.Receive("ixSmugglerEditFinish", function()
local panel = ix.gui.smuggler
local editor = ix.gui.smugglerEditor
if (!IsValid(panel) or !IsValid(editor)) then
return
end
local entity = panel.entity
if (!IsValid(entity)) then
return
end
local key = net.ReadString()
local data = net.ReadType()
if (key == "name") then
editor.name:SetText(data)
elseif (key == "description") then
editor.description:SetText(data)
elseif (key == "mode") then
if (data[2] == nil) then
editor.lines[data[1]]:SetValue(3, L"none")
else
editor.lines[data[1]]:SetValue(3, L(SMUGGLER_TEXT[data[2]]))
end
elseif (key == "stock") then
local current, max = entity:GetStock(data)
if (max == entity.maxStock) then
editor.lines[data]:SetValue(4, current)
else
editor.lines[data]:SetValue(4, current.."/"..max)
end
elseif (key == "stockMax") then
for k, v in pairs(editor.lines) do
local current, max = entity:GetStock(k)
if (max == entity.maxStock) then
v:SetValue(5, current)
else
v:SetValue(5, current.."/"..max)
end
end
elseif (key == "model") then
editor.model:SetText(entity:GetModel())
elseif (key == "stashList") then
local lines = editor.stashList:GetLines()
for k, v in pairs(lines) do
if (k != 1) then
editor.stashList:RemoveLine(k)
end
end
for k, v in pairs(data) do
editor.stashList:AddLine(v)
end
end
surface.PlaySound("buttons/button14.wav")
end)
net.Receive("ixSmugglerMoney", function()
local panel = ix.gui.smuggler
if (!IsValid(panel)) then
return
end
local entity = panel.entity
if (!IsValid(entity)) then
return
end
local value = net.ReadUInt(16)
value = value != -1 and value or nil
entity.money = value
local editor = ix.gui.smugglerEditor
if (IsValid(editor)) then
local useMoney = tonumber(value) != nil
editor.money:SetDisabled(!useMoney)
editor.money:SetEnabled(useMoney)
editor.money:SetText(useMoney and value or "")
end
end)
net.Receive("ixSmugglerStock", function()
local panel = ix.gui.smuggler
if (!IsValid(panel)) then
return
end
local entity = panel.entity
if (!IsValid(entity)) then
return
end
local uniqueID = net.ReadString()
local amount = net.ReadUInt(16)
entity.items[uniqueID] = entity.items[uniqueID] or {}
entity.items[uniqueID][SMUGGLER_STOCK] = amount
local editor = ix.gui.smugglerEditor
if (IsValid(editor)) then
local _, max = entity:GetStock(uniqueID)
if (max == entity.maxStock) then
editor.lines[uniqueID]:SetValue(4, amount)
else
editor.lines[uniqueID]:SetValue(4, amount.."/"..max)
end
end
end)
net.Receive("ixSmugglerAddItem", function()
local uniqueID = net.ReadString()
if (IsValid(ix.gui.smuggler)) then
ix.gui.smuggler:addItem(uniqueID, "buying")
end
end)
netstream.Hook("ixSmugglingPickupItems", function(items)
LocalPlayer().pickupItems = items
vgui.Create("PickupCache")
end)
netstream.Hook("ixSmugglingCacheUIDs", function(cacheIDList)
PLUGIN.cacheIDList = cacheIDList
end)
netstream.Hook("ixSmugglerUpdateLocation", function(entity, location)
entity.pickupLocation = location
if (IsValid(ix.gui.smuggler) and ix.gui.smuggler.entity == entity) then
ix.gui.smuggler.smugglerSellDeliver:SetText(L("smugglerDeliverTo", entity.pickupLocation))
end
end)
netstream.Hook("ixShowStashWaypoints", function(waypoints, stashEntities)
LocalPlayer().ixStashWaypoints = waypoints
LocalPlayer().ixStashEntities = stashEntities
end)
local function cacheESP(client, entity, x, y, factor)
ix.util.DrawText("Pickup Cache - "..(PLUGIN.cacheIDList[entity:EntIndex()] and PLUGIN.cacheIDList[entity:EntIndex()].uniqueID or "no id set"), x, y - math.max(10, 32 * factor), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, nil, factor)
end
ix.observer:RegisterESPType("ix_pickupcache", cacheESP, "cache", "Show Pickup Cache ESP")
local function smugglerESP(client, entity, x, y, factor)
cam.Start3D()
render.SuppressEngineLighting(true)
render.SetColorModulation(1, 1, 1)
render.SetBlend(factor)
entity:DrawModel()
render.MaterialOverride()
render.SuppressEngineLighting(false)
cam.End3D()
ix.util.DrawText("Smuggler - "..entity:GetDisplayName(), x, y - math.max(10, 32 * factor), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, nil, factor)
end
ix.observer:RegisterESPType("ix_smuggler", smugglerESP, "smuggler")

View File

@@ -0,0 +1,202 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PANEL = {}
function PANEL:Init()
self:SetSize(ScrW(), ScrH())
self:SetAlpha(0)
self:AlphaTo(255, 0.5, 0)
self.Paint = function(panel, w, h)
surface.SetDrawColor(Color(63, 58, 115, 220))
surface.DrawRect(0, 0, w, h)
Derma_DrawBackgroundBlur(panel, 1)
end
self.innerContent = self:Add("Panel")
self.innerContent:SetSize(SScaleMin(500 / 3), SScaleMin(600 / 3))
self.innerContent:Center()
self.innerContent:MakePopup()
Schema:AllowMessage(self.innerContent)
self.innerContent.Paint = function(_, w, h)
surface.SetDrawColor(0, 0, 0, 130)
surface.DrawRect(0, 0, w, h)
end
self:CreateTopBar()
self:CreateItems()
end
function PANEL:CreateTopBar()
local topbar = self.innerContent:Add("Panel")
topbar:SetSize(self.innerContent:GetWide(), SScaleMin(50 / 3))
topbar:Dock(TOP)
topbar.Paint = function(_, 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(L("smugglerSelectPickupItem"))
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()
netstream.Start("ClosePickupCache")
LocalPlayer().pickupItems = nil
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(SScaleMin(10 / 3) / 3), SScaleMin(10 / 3))
parent.Paint = function(_, 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:CreateItems()
local client = LocalPlayer()
if (!client.pickupItems) then
return
end
local character = client:GetCharacter()
local inventory = character:GetInventory()
local tblCount = table.Count(client.pickupItems)
local scrollPanel = self.innerContent:Add("DScrollPanel")
scrollPanel:Dock(TOP)
scrollPanel:SetSize(self.innerContent:GetWide(), self.innerContent:GetTall() - SScaleMin(50 / 3))
for k, v in pairs(client.pickupItems) do
if (!ix.item.list[k]) then
continue
end
local width = ix.item.list[k].width or 1
local height = ix.item.list[k].height or 1
local frame = scrollPanel:Add("Panel")
frame:Dock(TOP)
frame:DockMargin(0, 0, 0, -1)
frame:SetTall(SScaleMin(110 / 3) - 5)
frame.Paint = function(_, w, h)
surface.SetDrawColor(Color(0, 0, 0, 100))
surface.DrawRect(0, 0, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawOutlinedRect(0, 0, w, h)
end
local modelPanel = frame:Add("Panel")
modelPanel:Dock(LEFT)
modelPanel:SetWide(scrollPanel:GetWide() / 3)
modelPanel.Paint = function(_, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawLine(w - 1, SScaleMin(10 / 3), w - 1, h - SScaleMin(10 / 3))
end
local modelIcon = modelPanel:Add("SpawnIcon")
local model = ix.item.list[k].model or "models/props_junk/cardboard_box004a.mdl"
modelIcon:Dock(FILL)
modelIcon:DockMargin(SScaleMin(43 / 3), SScaleMin(10 / 3), SScaleMin(43 / 3), SScaleMin(10 / 3))
modelIcon:SetModel(model)
modelIcon.Paint = nil
modelIcon.PaintOver = nil
modelIcon:SetTooltip(nil)
local textPanel = frame:Add("Panel")
textPanel:Dock(LEFT)
textPanel:DockPadding(SScaleMin(10 / 3), 0, SScaleMin(10 / 3), 0)
textPanel:SetSize(scrollPanel:GetWide() / 2, frame:GetTall())
textPanel.Paint = function(_, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawLine(w - 1, SScaleMin(10 / 3), w - 1, h - SScaleMin(10 / 3))
end
local title = textPanel:Add("DLabel")
local actualTitle = ix.item.list[k].name or "Cardboard Box"
title:Dock(TOP)
title:SetText(actualTitle)
title:SetFont("WNBleedingMinutesBoldNoClamp")
title:SetWrap(true)
title:SetAutoStretchVertical(true)
title.PerformLayout = function(panel)
panel:DockMargin(0, textPanel:GetTall() * 0.5 - panel:GetTall() * 0.5, 0, textPanel:GetTall() * 0.5 - panel:GetTall() * 0.5)
end
local amountPanel = frame:Add("Panel")
amountPanel:Dock(FILL)
amountPanel:SetSize(scrollPanel:GetWide() - modelPanel:GetWide() - textPanel:GetWide(), frame:GetTall())
if (tblCount >= 6) then
amountPanel:SetWide(amountPanel:GetWide() - SScaleMin(15 / 3))
end
local amount = amountPanel:Add("DLabel")
local actualAmount = v or 1
amount:SetContentAlignment(5)
amount:SetText(actualAmount)
amount:SetFont("WNBleedingMinutesBoldNoClamp")
amount:SizeToContents()
amount:Center()
if (!inventory:FindEmptySlot(width, height)) then
amount:SetTextColor(Color(150, 150, 150, 255))
title:SetTextColor(Color(150, 150, 150, 255))
end
local invisibleButton = frame:Add("DButton")
invisibleButton:SetSize(modelPanel:GetWide() + textPanel:GetWide() + amountPanel:GetWide(), frame:GetTall())
invisibleButton:SetText("")
invisibleButton.Paint = function(panel, w, h)
if (panel:IsHovered() and inventory:FindEmptySlot(width, height)) then
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 15)))
surface.DrawOutlinedRect(SScaleMin(4 / 3), SScaleMin(4 / 3), w - SScaleMin(8 / 3), h - SScaleMin(8 / 3))
end
end
invisibleButton.DoClick = function()
if (inventory:FindEmptySlot(width, height)) then
actualAmount = actualAmount - 1
if (actualAmount == 0) then
frame:Remove()
else
amount:SetText(actualAmount)
end
client:NotifyLocalized(L("smugglerPickupItem", actualTitle))
surface.PlaySound("helix/ui/press.wav")
netstream.Start("SmugglingCachePickup", k)
else
client:NotifyLocalized(L("smugglerPickupNoSpace", actualTitle))
end
end
end
end
vgui.Register("PickupCache", PANEL, "EditablePanel")

View File

@@ -0,0 +1,388 @@
--[[
| 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/
--]]
-- luacheck: read globals SMUGGLER_BUY SMUGGLER_SELL SMUGGLER_BOTH SMUGGLER_WELCOME SMUGGLER_LEAVE SMUGGLER_NOTRADE SMUGGLER_PRICE
-- luacheck: read globals SMUGGLER_STOCK SMUGGLER_MODE SMUGGLER_MAXSTOCK SMUGGLER_SELLANDBUY SMUGGLER_SELLONLY SMUGGLER_BUYONLY SMUGGLER_TEXT
local PANEL = {}
local PLUGIN = PLUGIN
AccessorFunc(PANEL, "bReadOnly", "ReadOnly", FORCE_BOOL)
function PANEL:Init()
self:SetSize(ScrW() * 0.45, ScrH() * 0.65)
self:SetTitle("")
self:DockPadding(SScaleMin(10 / 3), SScaleMin(18 / 3), SScaleMin(10 / 3), SScaleMin(10 / 3))
self:Center()
DFrameFixer(self)
local header = self:Add("Panel")
header:SetTall(SScaleMin(45 / 3))
header:Dock(TOP)
header.Paint = function(this, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawLine(0, h - 1, w, h - 1)
end
self.smugglerName = header:Add("DLabel")
self.smugglerName:Dock(LEFT)
self.smugglerName:SetText("John Doe")
self.smugglerName:SetTextColor(color_white)
self.smugglerName:SetFont("TitlesFontNoBoldNoClamp")
self.smugglerName:SizeToContents()
self.ourName = header:Add("DLabel")
self.ourName:Dock(RIGHT)
self.ourName:SetWide(self:GetWide() * 0.5 - SScaleMin(15 / 3))
self.ourName:SetText(L"you".." ("..ix.currency.Get(LocalPlayer():GetCharacter():GetMoney())..")")
self.ourName:SetTextInset(0, 0)
self.ourName:SetTextColor(color_white)
self.ourName:SetFont("TitlesFontNoBoldNoClamp")
local footer = self:Add("Panel")
footer:SetTall(SScaleMin(34 / 3))
footer:Dock(BOTTOM)
self.smugglerSell = footer:Add("DButton")
self.smugglerSell:SetFont("TitlesFontNoBoldNoClamp")
self.smugglerSell:Dock(LEFT)
self.smugglerSell:SetContentAlignment(5)
self.smugglerSell:DockMargin(0, 0, SScaleMin(10 / 3), 0)
-- The text says purchase but the smuggler is selling it to us.
self.smugglerSell:SetText(L"purchase")
self.smugglerSell:SetTextColor(color_white)
self.smugglerSell:SizeToContents()
self.smugglerSell:SetWide(self.smugglerSell:GetWide() + SScaleMin(20 / 3))
self.smugglerSell.DoClick = function(this)
if (IsValid(self.activeSell)) then
net.Start("ixSmugglerTrade")
net.WriteString(self.activeSell.item)
net.WriteBool(false)
net.WriteBool(false)
net.SendToServer()
end
end
self.smugglerSellDeliver = footer:Add("DButton")
self.smugglerSellDeliver:SetFont("TitlesFontNoBoldNoClamp")
self.smugglerSellDeliver:Dock(FILL)
self.smugglerSellDeliver:SetContentAlignment(5)
-- The text says purchase but the smuggler is selling it to us.
self.smugglerSellDeliver:SetText(L"smugglerSelectDelivery")
self.smugglerSellDeliver:SetTextColor(color_white)
self.smugglerSellDeliver:SizeToContents()
self.smugglerSellDeliver:DockMargin(0, 0, SScaleMin(10 / 3), 0)
self.smugglerSellDeliver.DoClick = function(this)
if (!self.entity.pickupLocation or self.entity.pickupLocation == "") then
local stashList = {}
for k, v in pairs(self.entity.stashList) do
stashList[v] = true
end
local list = {}
for _, v in ipairs(ents.FindByClass("ix_pickupcache")) do
if (stashList[v:GetLocationId()]) then
list[#list + 1] = {text = v:GetDisplayName(), value = v}
end
end
Derma_Select("Wybierz lokalizację odbioru", "", list, "Wybierz lokalizację odbioru", "Wybierz", function(value, text)
net.Start("ixSmugglerChosePickup")
net.WriteEntity(value)
net.SendToServer()
end, "Anuluj", function() end)
else
if (IsValid(self.activeSell)) then
net.Start("ixSmugglerTrade")
net.WriteString(self.activeSell.item)
net.WriteBool(false)
net.WriteBool(true)
net.SendToServer()
end
end
end
self.smugglerBuy = footer:Add("DButton")
self.smugglerBuy:SetFont("TitlesFontNoBoldNoClamp")
self.smugglerBuy:SetWide(self:GetWide() * 0.5 - SScaleMin(18 / 3))
self.smugglerBuy:Dock(RIGHT)
self.smugglerBuy:SetContentAlignment(5)
self.smugglerBuy:SetText(L"sell")
self.smugglerBuy:SetTextColor(color_white)
self.smugglerBuy.DoClick = function(this)
if (IsValid(self.activeBuy)) then
net.Start("ixSmugglerTrade")
net.WriteString(self.activeBuy.item)
net.WriteBool(true)
net.SendToServer()
end
end
self.selling = self:Add("DScrollPanel")
self.selling:SetWide(self:GetWide() * 0.5 - 7)
self.selling:Dock(LEFT)
self.selling:DockMargin(0, SScaleMin(10 / 3), SScaleMin(10 / 3), SScaleMin(10 / 3))
self.selling.Paint = function(this, w, h)
surface.SetDrawColor(Color(111, 111, 136, (255 / 100 * 30)))
surface.DrawLine(w - 1, 0, w - 1, h)
end
self.sellingItems = self.selling:Add("DListLayout")
self.sellingItems:SetSize(self.selling:GetSize())
self.sellingItems:SetTall(ScrH())
self.buying = self:Add("DScrollPanel")
self.buying:SetWide(self:GetWide() * 0.5 - SScaleMin(7 / 3))
self.buying:Dock(RIGHT)
self.buying:DockMargin(SScaleMin(10 / 3), SScaleMin(10 / 3), 0, SScaleMin(10 / 3))
self.buyingItems = self.buying:Add("DListLayout")
self.buyingItems:SetSize(self.buying:GetSize())
self.buyingItems.rightSide = true
self.sellingList = {}
self.buyingList = {}
end
function PANEL:addItem(uniqueID, listID)
local entity = self.entity
local items = entity.items
local data = items[uniqueID]
if ((!listID or listID == "selling") and !IsValid(self.sellingList[uniqueID])
and ix.item.list[uniqueID] and PLUGIN.itemList[uniqueID] and PLUGIN.itemList[uniqueID].sell) then
if (data and data[SMUGGLER_MODE] and data[SMUGGLER_MODE] != SMUGGLER_BUYONLY) then
local item = self.sellingItems:Add("ixSmugglerItem")
item:Setup(uniqueID)
self.sellingList[uniqueID] = item
self.sellingItems:InvalidateLayout()
end
end
if ((!listID or listID == "buying") and !IsValid(self.buyingList[uniqueID])
and LocalPlayer():GetCharacter():GetInventory():HasItem(uniqueID)
and PLUGIN.itemList[uniqueID] and PLUGIN.itemList[uniqueID].buy) then
if (data and data[SMUGGLER_MODE] and data[SMUGGLER_MODE] != SMUGGLER_SELLONLY) then
local item = self.buyingItems:Add("ixSmugglerItem")
item.isLocal = true
item:Setup(uniqueID)
self.buyingList[uniqueID] = item
self.buyingItems:InvalidateLayout()
end
end
end
function PANEL:removeItem(uniqueID, listID)
if (!listID or listID == "selling") then
if (IsValid(self.sellingList[uniqueID])) then
self.sellingList[uniqueID]:Remove()
self.sellingItems:InvalidateLayout()
end
end
if (!listID or listID == "buying") then
if (IsValid(self.buyingList[uniqueID])) then
self.buyingList[uniqueID]:Remove()
self.buyingItems:InvalidateLayout()
end
end
end
function PANEL:Setup(entity)
self.entity = entity
self:SetTitle(entity:GetDisplayName())
self.lblTitle:SizeToContents()
self.smugglerName:SetText(entity:GetDisplayName()..(entity.money and " ("..ix.currency.Get(entity.money)..")" or "").." (całkowity zapas: "..entity:GetTotalStock().."/"..entity.maxStock..")")
self.smugglerBuy:SetEnabled(!self:GetReadOnly())
self.smugglerSell:SetEnabled(!self:GetReadOnly())
self.smugglerSellDeliver:SetEnabled(!self:GetReadOnly())
self:SetButtonStatus(self.smugglerBuy, !self:GetReadOnly())
self:SetButtonStatus(self.smugglerSell, !self:GetReadOnly())
self:SetButtonStatus(self.smugglerSellDeliver, !self:GetReadOnly())
if (entity.pickupLocation and entity.pickupLocation != "") then
self.smugglerSellDeliver:SetText(L("smugglerDeliverTo", entity.pickupLocation))
end
for k, _ in SortedPairs(entity.items) do
self:addItem(k, "selling")
end
for _, v in SortedPairs(LocalPlayer():GetCharacter():GetInventory():GetItems()) do
self:addItem(v.uniqueID, "buying")
end
end
function PANEL:OnRemove()
net.Start("ixSmugglerClose")
net.SendToServer()
if (IsValid(ix.gui.smugglerEditor)) then
ix.gui.smugglerEditor:Remove()
end
end
function PANEL:Think()
local entity = self.entity
if (!IsValid(entity)) then
self:Remove()
return
end
if ((self.nextUpdate or 0) < CurTime()) then
self.smugglerName:SetText(entity:GetDisplayName()..(entity.money and " ("..ix.currency.Get(entity.money)..")" or "").." (całkowity zapas: "..entity:GetTotalStock().."/"..entity.maxStock..")")
self.smugglerName:SizeToContents()
self.ourName:SetText(L"you".." ("..ix.currency.Get(LocalPlayer():GetCharacter():GetMoney())..")")
self.nextUpdate = CurTime() + 0.25
end
end
function PANEL:OnItemSelected(panel)
local price = self.entity:GetPrice(panel.item, panel.isLocal)
if (panel.isLocal) then
self.smugglerBuy:SetText(L"sell".." ("..ix.currency.Get(price)..")")
else
self.smugglerSell:SetText(L"purchase".." ("..ix.currency.Get(price)..")")
self.smugglerSell:SizeToContents()
self.smugglerSell:SetWide(self.smugglerSell:GetWide() + SScaleMin(20 / 3))
end
end
function PANEL:SetButtonStatus(parent, bDisabled)
if (bDisabled) then
parent:SetTextColor(color_white)
else
parent:SetTextColor(Color(255, 255, 255, 30))
end
end
vgui.Register("ixSmuggler", PANEL, "DFrame")
PANEL = {}
function PANEL:Init()
self:SetTall(SScaleMin(36 / 3))
self:DockMargin(self:GetParent().rightSide and SScaleMin(15 / 3) or 0, self:GetParent().firstItem and SScaleMin(4 / 3) or 0, !self:GetParent().rightSide and SScaleMin(10 / 3) or 0, 0)
if !self:GetParent().firstItem then
self:GetParent().firstItem = true
end
self.icon = self:Add("SpawnIcon")
self.icon:SetPos(SScaleMin(2 / 3), SScaleMin(2 / 3))
self.icon:SetSize(SScaleMin(32 / 3), SScaleMin(32 / 3))
self.icon:SetModel("models/error.mdl")
self.name = self:Add("DLabel")
self.name:Dock(FILL)
self.name:DockMargin(SScaleMin(42 / 3), 0, 0, 0)
self.name:SetFont("TitlesFontNoClamp")
self.name:SetTextColor(color_white)
self.click = self:Add("DButton")
self.click:Dock(FILL)
self.click:SetText("")
self.click.Paint = function() end
self.click.DoClick = function(this)
if (self.isLocal) then
ix.gui.smuggler.activeBuy = self
else
ix.gui.smuggler.activeSell = self
end
ix.gui.smuggler:OnItemSelected(self)
end
end
function PANEL:SetCallback(callback)
self.click.DoClick = function(this)
callback()
self.selected = true
end
end
function PANEL:Setup(uniqueID)
local item = ix.item.list[uniqueID]
if (item and PLUGIN.itemList[uniqueID]) then
self.item = uniqueID
self.icon:SetModel(item:GetModel(), item:GetSkin())
self.name:SetText(item:GetName())
self.itemName = item:GetName()
self.click:SetHelixTooltip(function(tooltip)
ix.hud.PopulateItemTooltip(tooltip, item)
local entity = ix.gui.smuggler.entity
if (entity and entity.items[self.item]) then
local stock = tooltip:AddRowAfter("name", "stock")
local stockLvl, maxStock = entity:GetStock(uniqueID)
if (self.isLocal) then
local canBuy = math.min(entity.maxStock - stockLvl, maxStock - stockLvl)
local inventory = LocalPlayer():GetCharacter():GetInventory()
stock:SetText(L("smugglerStock", canBuy, inventory:GetItemCount(uniqueID)))
else
if (stockLvl > 0) then
stock:SetText(L("smugglerAvailable", stockLvl))
else
stock:SetText(L("smugglerAvailableDelivery"))
end
end
stock:SetBackgroundColor(derma.GetColor("Info", self))
stock:SizeToContents()
end
if (PLUGIN.itemList[uniqueID].stackSize) then
local stackSize = tooltip:AddRowAfter("name", "stackSize")
stackSize:SetText(L("smugglerStackSize", PLUGIN.itemList[uniqueID].stackSize))
stackSize:SetBackgroundColor(derma.GetColor("Info", self))
stackSize:SizeToContents()
end
end)
end
end
function PANEL:Think()
if ((self.nextUpdate or 0) < CurTime()) then
local entity = ix.gui.smuggler.entity
if (entity and self.isLocal) then
local count = LocalPlayer():GetCharacter():GetInventory():GetItemCount(self.item)
if (count == 0) then
self:Remove()
end
end
self.nextUpdate = CurTime() + 0.1
end
end
function PANEL:Paint(w, h)
if (ix.gui.smuggler.activeBuy == self or ix.gui.smuggler.activeSell == self) then
surface.SetDrawColor(ix.config.Get("color"))
else
surface.SetDrawColor(0, 0, 0, 100)
end
surface.DrawRect(0, 0, w, h)
end
vgui.Register("ixSmugglerItem", PANEL, "DPanel")

View File

@@ -0,0 +1,286 @@
--[[
| 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/
--]]
-- luacheck: read globals SMUGGLER_BUY SMUGGLER_SELL SMUGGLER_BOTH SMUGGLER_WELCOME SMUGGLER_LEAVE SMUGGLER_NOTRADE SMUGGLER_PRICE
-- luacheck: read globals SMUGGLER_STOCK SMUGGLER_MODE SMUGGLER_MAXSTOCK SMUGGLER_SELLANDBUY SMUGGLER_SELLONLY SMUGGLER_BUYONLY SMUGGLER_TEXT
local PANEL = {}
local PLUGIN = PLUGIN
function PANEL:Init()
local entity = ix.gui.smuggler.entity
self:SetSize(320, ScrH() * 0.65)
self:MoveLeftOf(ix.gui.smuggler, 8)
self:CenterVertical()
self:SetTitle(L"smugglerEditor")
self.lblTitle:SetTextColor(color_white)
DFrameFixer(self, false, true)
self.name = self:Add("DTextEntry")
self.name:Dock(TOP)
self.name:SetText(entity:GetDisplayName())
self.name:SetPlaceholderText(L"name")
self.name.OnEnter = function(this)
if (entity:GetDisplayName() != this:GetText()) then
self:updateSmuggler("name", this:GetText())
if IsValid(ix.gui.smuggler) then
ix.gui.smuggler:SetTitle(this:GetText())
ix.gui.smuggler.lblTitle:SizeToContents()
ix.gui.smuggler.smugglerName:SizeToContents()
end
end
end
self.description = self:Add("DTextEntry")
self.description:Dock(TOP)
self.description:DockMargin(0, 4, 0, 0)
self.description:SetText(entity:GetDescription())
self.description:SetPlaceholderText(L"description")
self.description.OnEnter = function(this)
if (entity:GetDescription() != this:GetText()) then
self:updateSmuggler("description", this:GetText())
end
end
self.model = self:Add("DTextEntry")
self.model:Dock(TOP)
self.model:DockMargin(0, 4, 0, 0)
self.model:SetText(entity:GetModel())
self.model:SetPlaceholderText(L"model")
self.model.OnEnter = function(this)
if (entity:GetModel():lower() != this:GetText():lower()) then
self:updateSmuggler("model", this:GetText():lower())
end
end
local useMoney = tonumber(entity.money) != nil
self.money = self:Add("DTextEntry")
self.money:Dock(TOP)
self.money:DockMargin(0, 4, 0, 0)
self.money:SetText(!useMoney and "" or entity.money)
self.money:SetPlaceholderText(L"money")
self.money:SetDisabled(!useMoney)
self.money:SetEnabled(useMoney)
self.money:SetNumeric(true)
self.money.OnEnter = function(this)
local value = tonumber(this:GetText()) or entity.money
if (value == entity.money) then
return
end
self:updateSmuggler("money", value)
end
self.useMoney = self:Add("DCheckBoxLabel")
self.useMoney:SetText(L"smugglerUseMoney")
self.useMoney:Dock(TOP)
self.useMoney:DockMargin(0, 4, 0, 0)
self.useMoney:SetChecked(useMoney)
self.useMoney.OnChange = function(this, value)
self:updateSmuggler("useMoney")
end
self.maxStock = self:Add("DTextEntry")
self.maxStock:Dock(TOP)
self.maxStock:DockMargin(0, 4, 0, 0)
self.maxStock:SetText(entity.maxStock)
self.maxStock:SetPlaceholderText(L"maxStock")
self.maxStock:SetNumeric(true)
self.maxStock.OnEnter = function(this)
local value = tonumber(this:GetText()) or entity.maxStock
if (value == entity.maxStock) then
return
end
self:updateSmuggler("stockMax", value)
end
self.stashList = self:Add("DListView")
self.stashList:Dock(TOP)
self.stashList:DockMargin(0, 4, 0, 0)
self.stashList:AddColumn("Location Id")
self.stashList:SetTooltip("Leave list empty to use all locations and not assigned stashes\nDouble click to remove entry")
self.stashList:SetTall(ScrH() * 0.075)
self.stashList:SetSortable(false)
function self.stashList:GetStashList()
local stashes = {}
for k, v in pairs(self:GetLines(1)) do
if (k != 1) then
table.insert(stashes, v:GetValue(1))
end
end
return stashes
end
local addButton = self.stashList:AddLine("Add...")
function addButton:OnSelect()
Derma_StringRequest("Location Id", "Enter any location Id of the stashes that will be used", "", function(text)
local stashList = self:GetListView()
text = string.utf8upper(text)
for k, v in pairs(stashList:GetLines()) do
if (v:GetValue(1) == text) then
return
end
end
stashList:AddLine(text)
PANEL:updateSmuggler("stashList", stashList:GetStashList())
end)
end
function self.stashList:DoDoubleClick(lineId, linePanel)
if (lineId == 1) then return end
self:RemoveLine(lineId)
PANEL:updateSmuggler("stashList", self:GetStashList())
end
if (entity.stashList and !table.IsEmpty(entity.stashList)) then
for k, v in pairs(entity.stashList) do
self.stashList:AddLine(v)
end
end
self.searchBar = self:Add("DTextEntry")
self.searchBar:Dock(TOP)
self.searchBar:DockMargin(0, 4, 0, 0)
self.searchBar:SetUpdateOnType(true)
self.searchBar:SetPlaceholderText("Search...")
self.searchBar.OnValueChange = function(this, value)
self:ReloadItemList(value)
end
self.items = self:Add("DListView")
self.items:Dock(FILL)
self.items:DockMargin(0, 4, 0, 0)
self.items:AddColumn(L"name").Header:SetTextColor(color_black)
self.items:AddColumn(L"category").Header:SetTextColor(color_black)
self.items:AddColumn(L"mode").Header:SetTextColor(color_black)
self.items:AddColumn(L"stock").Header:SetTextColor(color_black)
self.items:SetMultiSelect(false)
self.items.OnRowRightClick = function(this, index, line)
if (IsValid(self.menu)) then
self.menu:Remove()
end
local uniqueID = line.item
self.menu = DermaMenu()
-- Modes of the item.
local mode, panel = self.menu:AddSubMenu(L"mode")
panel:SetImage("icon16/key.png")
-- Disable buying/selling of the item.
mode:AddOption(L"none", function()
self:updateSmuggler("mode", {uniqueID, nil})
end):SetImage("icon16/cog_error.png")
if (PLUGIN.itemList[uniqueID].buy and PLUGIN.itemList[uniqueID].sell) then
-- Allow the smuggler to sell and buy this item.
mode:AddOption(L"smugglerBoth", function()
self:updateSmuggler("mode", {uniqueID, SMUGGLER_SELLANDBUY})
end):SetImage("icon16/cog.png")
end
if (PLUGIN.itemList[uniqueID].buy) then
-- Only allow the smuggler to buy this item from players.
mode:AddOption(L"smugglerBuy", function()
self:updateSmuggler("mode", {uniqueID, SMUGGLER_BUYONLY})
end):SetImage("icon16/cog_delete.png")
end
if (PLUGIN.itemList[uniqueID].sell) then
-- Only allow the smuggler to sell this item to players.
mode:AddOption(L"smugglerSell", function()
self:updateSmuggler("mode", {uniqueID, SMUGGLER_SELLONLY})
end):SetImage("icon16/cog_add.png")
end
local itemTable = ix.item.list[uniqueID]
-- Only allow the smuggler to sell this item to players.
self.menu:AddOption(L"smugglerEditCurStock", function()
Derma_StringRequest(
itemTable.GetName and itemTable:GetName() or L(itemTable.name),
L"smugglerStockCurReq",
entity:GetStock(uniqueID),
function(text)
self:updateSmuggler("stock", {uniqueID, text})
end
)
end):SetImage("icon16/table_edit.png")
self.menu:Open()
self.menu.Think = function()
if (IsValid(self.menu)) then
self.menu:MoveToFront()
end
end
end
self:ReloadItemList()
end
function PANEL:ReloadItemList(filter)
local entity = ix.gui.smuggler.entity
self.lines = {}
self.items:Clear()
for k, info in SortedPairs(PLUGIN.itemList) do
local v = ix.item.list[k]
local itemName = v.GetName and v:GetName() or L(v.name)
if (filter and !itemName:lower():find(filter:lower(), 1, false)) then
continue
end
local mode = entity.items[k] and entity.items[k][SMUGGLER_MODE]
local current, max = entity:GetStock(k)
local panel = self.items:AddLine(
itemName,
info.cat or v.category or L"none",
mode and L(SMUGGLER_TEXT[mode]) or L"none",
max != entity.maxStock and current.."/"..max or current
)
panel.item = k
self.lines[k] = panel
end
end
function PANEL:OnRemove()
if (IsValid(ix.gui.smuggler)) then
ix.gui.smuggler:Remove()
end
end
function PANEL:updateSmuggler(key, value)
net.Start("ixSmugglerEdit")
net.WriteString(key)
net.WriteType(value)
net.SendToServer()
end
function PANEL:Think()
if (self.menu and !self.menu:IsVisible()) or !self.menu then
self:MoveToFront()
end
end
vgui.Register("ixSmugglerEditor", PANEL, "DFrame")

View File

@@ -0,0 +1,100 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
AddCSLuaFile()
ENT.Base = "base_entity"
ENT.Type = "anim"
ENT.PrintName = "Pickup Cache"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.RenderGroup = RENDERGROUP_BOTH
ENT.bNoPersist = true
ENT.AdminOnly = true
function ENT:SetupDataTables()
self:NetworkVar("String", 0, "DisplayName")
self:NetworkVar("String", 1, "LocationId")
end
if (SERVER) then
function ENT:Initialize()
self:SetModel("models/items/item_item_crate.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
self.uniqueID = ""
end
function ENT:Use(activator, caller)
if (self.uniqueID == "") then return end
if (IsValid(caller) and caller:IsPlayer() and caller:GetCharacter()) then
local pickupItems = caller:GetCharacter():GetSmugglingPickupItems()
if (pickupItems["__invalid_cache"]) then
pickupItems[self.uniqueID] = pickupItems[self.uniqueID] or {}
for k, v in pairs(pickupItems["__invalid_cache"]) do
pickupItems[self.uniqueID][k] = (pickupItems[self.uniqueID][k] or 0) + v
end
pickupItems["__invalid_cache"] = nil
caller:GetCharacter().vars.smugglingPickupItems = pickupItems
end
if (pickupItems[self.uniqueID]) then
caller.ixPickupCache = self
netstream.Start(caller, "ixSmugglingPickupItems", pickupItems[self.uniqueID])
else
caller:NotifyLocalized("smugglerNoPickupItems")
end
end
end
function ENT:SetNewModel(model)
self:SetModel(model)
self:PhysicsInit(SOLID_BBOX)
self:SetSolid(SOLID_BBOX)
end
function ENT:UpdateUniqueID(uniqueID)
uniqueID = string.gsub(string.Trim(string.utf8lower(uniqueID)), "%s", "_")
if (uniqueID == self.uniqueID) then return end
local oldID = self.uniqueID
self.uniqueID = uniqueID
PLUGIN:UpdateCacheID(self, uniqueID, oldID)
end
else
function ENT:Draw()
self:DrawModel()
end
ENT.PopulateEntityInfo = true
function ENT:OnPopulateEntityInfo(container)
local name = container:AddRow("name")
name:SetImportant()
name:SetText(self:GetDisplayName())
name:SizeToContents()
end
end

View File

@@ -0,0 +1,351 @@
--[[
| 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/
--]]
-- luacheck: read globals SMUGGLER_BUY SMUGGLER_SELL SMUGGLER_BOTH SMUGGLER_WELCOME SMUGGLER_LEAVE SMUGGLER_NOTRADE SMUGGLER_PRICE
-- luacheck: read globals SMUGGLER_STOCK SMUGGLER_MODE SMUGGLER_MAXSTOCK SMUGGLER_SELLANDBUY SMUGGLER_SELLONLY SMUGGLER_BUYONLY SMUGGLER_TEXT
local PLUGIN = PLUGIN
ENT.Type = "anim"
ENT.PrintName = "Smuggler"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.isSmuggler = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("String", 0, "DisplayName")
self:NetworkVar("String", 1, "Description")
end
function ENT:Initialize()
self:SetModel("models/mossman.mdl")
self:SetMoveType(MOVETYPE_NONE)
self:DrawShadow(true)
if (SERVER) then
self:SetUseType(SIMPLE_USE)
self:SetSolid(SOLID_OBB)
self:PhysicsInit(SOLID_OBB)
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
self:SetDisplayName("John Doe")
self:SetDescription("")
self.items = {}
self.messages = {}
self.receivers = {}
self.stashList = {}
self.maxStock = 30
self:SetInactive()
end
timer.Simple(1, function()
if (IsValid(self)) then
self:SetAnim()
end
end)
end
function ENT:CanAccess(client)
if (client:HasActiveCombineSuit()) then
return false
end
if (ix.faction.Get(client:Team()).noSmuggler) then
return false
end
return true
end
function ENT:GetStock(uniqueID)
local maxStock = PLUGIN.itemList[uniqueID].maxStock or self.maxStock
if (self.items[uniqueID]) then
return self.items[uniqueID][SMUGGLER_STOCK] or 0, maxStock
end
return 0, maxStock
end
function ENT:GetTotalStock()
local stock = 0
for _, v in pairs(self.items) do
stock = stock + (v[SMUGGLER_STOCK] or 0)
end
return stock
end
function ENT:GetPrice(uniqueID, bClientIsSelling)
local price = 0
if (ix.item.list[uniqueID] and self.items[uniqueID]) then
local info = PLUGIN.itemList[uniqueID]
if (bClientIsSelling) then
-- info.buy = price of smuggler buying from player = player selling to smuggler
price = info.buy or 0
else
-- info.sell = price of smuggler selling to player = player buying from smuggler
price = info.sell or 0
end
end
return price
end
function ENT:HasMoney(amount)
-- Smuggler not using money system so they can always afford it.
if (!self.money) then
return true
end
return self.money >= amount
end
function ENT:SetAnim()
for k, v in ipairs(self:GetSequenceList()) do
if (v:lower():find("idle") and v != "idlenoise") then
return self:ResetSequence(k)
end
end
if (self:GetSequenceCount() > 1) then
self:ResetSequence(4)
end
end
if (SERVER) then
function ENT:SpawnFunction(client, trace)
local angles = (trace.HitPos - client:GetPos()):Angle()
angles.r = 0
angles.p = 0
angles.y = angles.y + 180
local entity = ents.Create("ix_smuggler")
entity:SetPos(trace.HitPos)
entity:SetAngles(angles)
entity:Spawn()
ix.saveEnts:SaveEntity(entity)
PLUGIN:SaveData()
return entity
end
function ENT:SetInactive()
self.ixIsActiveSmuggler = nil
self.ixSmugglerPrepRotation = nil
self:SetCollisionGroup(COLLISION_GROUP_WORLD)
self:SetNoDraw(true)
for _, v in pairs(self.items) do
if (v[SMUGGLER_STOCK]) then
v[SMUGGLER_STOCK] = 0
end
end
self:SetMoney(0)
self.pickupCache = nil
end
function ENT:SetActive()
self.ixIsActiveSmuggler = true
self.ixSmugglerDeliveryOffset = math.Rand(0.9, 1.2)
self:SetCollisionGroup(COLLISION_GROUP_NONE)
self:SetNoDraw(false)
self:ResetSmuggler()
end
function ENT:ResetSmuggler()
if (!self.ixIsActiveSmuggler) then return end
self.ixSmugglerPrepRotation = nil
self.ixSmugglerDeliveryOffset = math.Rand(0.9, 1.2)
for _, v in pairs(self.items) do
if (v[SMUGGLER_STOCK]) then
v[SMUGGLER_STOCK] = 0
end
end
-- limit money to player count between 10 and 50
local playerCount = math.Clamp(#player.GetAll(), 10, 50)
-- remap money: 0 players theoretically gives no money, but we always have a minimum player count of 10
-- 50 players gives max money
self:SetMoney(math.Remap(playerCount, 0, 50, 0, ix.config.Get("SmugglerDefaultMoney")))
local stashList = {}
for k, v in pairs(self.stashList) do
stashList[v] = true
end
local caches = {}
for k, v in pairs(PLUGIN.cacheIDList) do
if (stashList[v.locationId]) then
table.insert(caches, k)
end
end
if (#caches > 0) then
self.pickupCache = Entity(table.Random(caches))
end
end
function ENT:Use(activator)
if (!self.ixIsActiveSmuggler) then
return
end
if (self.ixSmugglerPrepRotation) then
activator:NotifyLocalized("smugglerPrepMove")
return
end
local character = activator:GetCharacter()
if (!self:CanAccess(activator) or hook.Run("CanPlayerUseSmuggler", activator) == false) then
if (self.messages[SMUGGLER_NOTRADE]) then
activator:ChatPrint(self:GetDisplayName()..": "..self.messages[SMUGGLER_NOTRADE])
else
activator:NotifyLocalized("smugglerNoTrade")
end
return
end
local items = {}
-- Only send what is needed.
for k, v in pairs(self.items) do
if (!table.IsEmpty(v) and (CAMI.PlayerHasAccess(activator, "Helix - Manage Smugglers", nil) or v[SMUGGLER_MODE])) then
if (!activator:GetCharacter():CanDoAction("recipe_smuggling_"..k)) then continue end
items[k] = v
end
end
if (table.IsEmpty(items)) then
activator:NotifyLocalized("smugglerNoItems")
return
end
self.receivers[#self.receivers + 1] = activator
if (self.messages[SMUGGLER_WELCOME]) then
activator:ChatPrint(self:GetDisplayName()..": "..self.messages[SMUGGLER_WELCOME])
end
activator.ixSmuggler = self
activator.ixSmugglerDelivery = nil
-- force sync to prevent outdated inventories while buying/selling
if (character) then
character:GetInventory():Sync(activator, true)
end
net.Start("ixSmugglerOpen")
net.WriteEntity(self)
net.WriteUInt(self.money or 0, 16)
net.WriteUInt(self.maxStock or 0, 16)
net.WriteString(IsValid(self.pickupCache) and self.pickupCache:GetDisplayName() or "")
net.WriteTable(items)
net.WriteTable(self.stashList)
net.Send(activator)
ix.log.Add(activator, "smugglerUse", self:GetDisplayName())
end
function ENT:SetMoney(value)
self.money = value
net.Start("ixSmugglerMoney")
net.WriteUInt(value and value or -1, 16)
net.Send(self.receivers)
end
function ENT:GiveMoney(value)
if (self.money) then
self:SetMoney(self:GetMoney() + value)
end
end
function ENT:TakeMoney(value)
if (self.money) then
self:GiveMoney(-value)
end
end
function ENT:SetStock(uniqueID, value)
self.items[uniqueID] = self.items[uniqueID] or {}
self.items[uniqueID][SMUGGLER_STOCK] = math.Clamp(value, 0, PLUGIN.itemList[uniqueID].maxStock or self.maxStock)
net.Start("ixSmugglerStock")
net.WriteString(uniqueID)
net.WriteUInt(self.items[uniqueID][SMUGGLER_STOCK], 16)
net.Send(self.receivers)
end
function ENT:AddStock(uniqueID, value)
self:SetStock(uniqueID, self:GetStock(uniqueID) + (value or 1))
end
function ENT:TakeStock(uniqueID, value)
self:AddStock(uniqueID, -(value or 1))
end
else
function ENT:Draw()
self:DrawModel()
end
function ENT:Think()
if ((self.nextAnimCheck or 0) < CurTime()) then
self:SetAnim()
self.nextAnimCheck = CurTime() + 60
end
self:SetNextClientThink(CurTime() + 0.25)
return true
end
ENT.PopulateEntityInfo = true
function ENT:OnPopulateEntityInfo(container)
if (self:GetNoDraw()) then return end
local name = container:AddRow("name")
name:SetImportant()
name:SetText(self:GetDisplayName())
name:SizeToContents()
local descriptionText = self:GetDescription()
if (descriptionText != "") then
local description = container:AddRow("description")
description:SetText(self:GetDescription())
description:SizeToContents()
end
end
end
function ENT:GetMoney()
return self.money
end

View File

@@ -0,0 +1,108 @@
--[[
| 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
--[[
FIELD LIST:
-sell: (optional) price when smuggler sells to player. Note that if not provided, buy price should be!
-buy: (optional) price when smuggler buys from player. Note that if not provided, sell price should be!
-cat: (optional) override category, uses item category otherwise (for recipe on skill panel and in smuggling edit UI)
-level: (optional) minimal level required, defaults to 0 (no level required)
-maxStock: (optional) limit stock on this item on top of total stock limit, smuggler will no longer buy if it reaches this limit
-buyExp: (optional) override buy experience (when buying from player), defaults to buy price
-sellExp: (optional) override sell experience (when selling to the player), defaults to sell prace
]]
PLUGIN.itemList = {
--Basics
["ing_flour"] = {sell = 15, buy = 4, cat = "Składniki", level = 2},
["ing_vinegar"] = {sell = 15, buy = 4, cat = "Składniki", level = 3},
["ing_herbs"] = {sell = 10, buy = 3, cat = "Składniki", level = 2},
["ing_egg"] = {sell = 25, buy = 12, cat = "Składniki", level = 4},
["ing_margarine"] = {sell = 9, buy = 3, cat = "Składniki", level = 2},
["ing_salt"] = {sell = 9, buy = 3, cat = "Składniki", level = 1},
["ing_spices"] = {sell = 12, buy = 6, cat = "Składniki", level = 3},
["ing_vegetable_pack"] = {sell = 12, buy = 4, cat = "Składniki", level = 3},
["ing_noodles"] = {sell = 9, buy = 3, cat = "Składniki", level = 2},
["ing_protein"] = {sell = 10, buy = 3, cat = "Składniki", level = 2},
["ing_sweet"] = {sell = 8, buy = 4, cat = "Składniki", level = 3},
["drink_milk"] = {sell = 10, buy = 4, cat = "Składniki", level = 2},
["fruit_berries"] = {sell = 12, buy = 6, cat = "Składniki", level = 1},
["ing_headcrab_meat"] = {sell = 15, buy = 3, cat = "Składniki", level = 0},
["ing_antlion_meat"] = {sell = 15, buy = 3, cat = "Składniki", level = 0},
["drink_beer"] = {sell = 60, buy = 25, cat = "Alkohol", level = 3},
["bottle_bourbon"] = {sell = 70, buy = 30, cat = "Alkohol", level = 4},
["bottle_whiskey"] = {sell = 70, buy = 30, cat = "Alkohol", level = 4},
["bottle_vodka"] = {sell = 70, buy = 30, cat = "Alkohol", level = 4},
--Components
["comp_plastic"] = {sell = 7, buy = 2, cat = "Komponenty Wytwarzania", level = 0},
["comp_wood"] = {sell = 8, buy = 3, cat = "Komponenty Wytwarzania", level = 0},
["comp_cloth"] = {sell = 8, buy = 3, cat = "Komponenty Wytwarzania", level = 0},
["comp_scrap"] = {sell = 9, buy = 3, cat = "Komponenty Wytwarzania", level = 0},
["comp_electronics"] = {sell = 10, buy = 3, cat = "Komponenty Wytwarzania", level = 0},
["comp_adhesive"] = {sell = 25, buy = 10, cat = "Komponenty Wytwarzania", level = 4},
["comp_alcohol"] = {sell = 35, buy = 18, cat = "Komponenty Wytwarzania", level = 7},
["comp_chemicals"] = {sell = 23, buy = 11, cat = "Komponenty Wytwarzania", level = 7},
["comp_stitched_cloth"] = {sell = 43, buy = 23, cat = "Komponenty Wytwarzania", level = 12},
["comp_screws"] = {sell = 26, buy = 12, cat = "Komponenty Wytwarzania", level = 6},
["comp_chemcomp"] = {sell = 50, buy = 26, cat = "Komponenty Wytwarzania", level = 15},
["comp_rivbolts"] = {sell = 113, buy = 44, cat = "Komponenty Wytwarzania", level = 15},
["comp_refined_plastic"] = {sell = 42, buy = 16, cat = "Komponenty Wytwarzania", level = 15},
["comp_iron"] = {sell = 52, buy = 22, cat = "Komponenty Wytwarzania", level = 15},
["comp_steel"] = {sell = 260, buy = 115, cat = "Komponenty Wytwarzania", level = 20},
["comp_fabric"] = {sell = 200, buy = 81, cat = "Komponenty Wytwarzania", level = 20},
["comp_explosive"] = {sell = 220, buy = 95, cat = "Komponenty Wytwarzania", level = 20},
--Medical
["comp_purifier"] = {sell = 50, buy = 26, cat = "Komponenty Medyczne", level = 10},
["comp_syringe"] = {sell = 30, buy = 14, cat = "Komponenty Medyczne", level = 5},
["bandage"] = {sell = 44, buy = 12, cat = "Medycyna", level = 5, stackSize = 6},
["disinfectant_bottle"] = {sell = 98, buy = 45, cat = "Medycyna", level = 5, stackSize = 6},
["painkillers"] = {sell = 90, buy = 33, cat = "Medycyna", level = 8, stackSize = 4},
["disinfected_bandage"] = {sell = 112, buy = 58, cat = "Medycyna", level = 10, stackSize = 4},
["bloodbag"] = {sell = 243, buy = 100, cat = "Medycyna", level = 15, stackSize = 4},
["bloodstabilizer"] = {sell = 237, buy = 97, cat = "Medycyna", level = 12, stackSize = 4},
["adrenaline"] = {sell = 90, buy = 33, cat = "Medycyna", level = 13, stackSize = 3},
["morphine"] = {sell = 90, buy = 35, cat = "Medycyna", level = 16, stackSize = 3},
["firstaid"] = {sell = 480, buy = 200, cat = "Medycyna", level = 19, stackSize = 3},
["surgerykit"] = {sell = 778, buy = 300, cat = "Medycyna", level = 20, stackSize = 3},
-- Tools
["head_gasmask"] = {sell = 320, buy = 180, cat = "Ekwipunek", level = 20},
["highquality_filter"] = {sell = 550, buy = 200, cat = "Ekwipunek", level = 20},
["face_bandana"] = {sell = 72, buy = 26, cat = "Ekwipunek", level = 4},
["head_military_cap"] = {sell = 80, buy = 38, cat = "Ekwipunek", level = 9},
["smallbag"] = {sell = 160, buy = 85, cat = "Ekwipunek", level = 4},
["largebag"] = {sell = 250, buy = 146, cat = "Ekwipunek", level = 13},
["flashlight"] = {sell = 22, buy = 8, cat = "Ekwipunek", level = 2},
["handheld_radio"] = {sell = 420, buy = 240, cat = "Ekwipunek", level = 20},
["old_radio"] = {sell = 260, buy = 100, cat = "Ekwipunek", level = 11},
["waterbottle"] = {sell = 20, buy = 5, cat = "Narzędzia", level = 0},
["watervalve"] = {sell = 30, buy = 10, cat = "Narzędzia", level = 8},
["tool_wrench"] = {sell = 160, buy = 70, cat = "Narzędzia", level = 12},
["tool_toolkit"] = {sell = 103, buy = 60, cat = "Narzędzia", level = 7},
["tinderbox"] = {sell = 47, buy = 30, cat = "Narzędzia", level = 9},
["lighter"] = {sell = 40, buy = 13, cat = "Narzędzia", level = 0},
["beard_razor"] = {sell = 48, buy = 13, cat = "Narzędzia", level = 4},
["tool_scissors"] = {sell = 18, buy = 5, cat = "Narzędzia", level = 0},
["tool_cookingpot"] = {sell = 45, buy = 20, cat = "Narzędzia", level = 6},
["tool_spoon"] = {sell = 22, buy = 10, cat = "Narzędzia", level = 2},
["tool_knife"] = {sell = 34, buy = 14, cat = "Narzędzia", level = 3},
["tool_fryingpan"] = {sell = 45, buy = 20, cat = "Narzędzia", level = 4},
["tool_mixer"] = {sell = 160, buy = 80, cat = "Narzędzia", level = 20},
}

View File

@@ -0,0 +1,385 @@
--[[
| 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/
--]]
-- luacheck: globals SMUGGLER_BUY SMUGGLER_SELL SMUGGLER_BOTH SMUGGLER_WELCOME SMUGGLER_LEAVE SMUGGLER_NOTRADE SMUGGLER_PRICE
-- luacheck: globals SMUGGLER_STOCK SMUGGLER_MODE SMUGGLER_MAXSTOCK SMUGGLER_SELLANDBUY SMUGGLER_SELLONLY SMUGGLER_BUYONLY
local PLUGIN = PLUGIN
PLUGIN.name = "Smugglers"
PLUGIN.author = "Chessnut & Gr4Ss"
PLUGIN.description = "Adds NPC smugglers that can sell things. Heavily based on Chessnut's vendor plugin."
CAMI.RegisterPrivilege({
Name = "Helix - Manage Smugglers",
MinAccess = "superadmin"
})
PLUGIN.cacheIDList = PLUGIN.cacheIDList or {}
SMUGGLER_BUY = 1
SMUGGLER_SELL = 2
SMUGGLER_BOTH = 3
-- Keys for smuggler messages.
SMUGGLER_WELCOME = 1
SMUGGLER_LEAVE = 2
SMUGGLER_NOTRADE = 3
-- Keys for item information.
SMUGGLER_PRICE = 1
SMUGGLER_STOCK = 2
SMUGGLER_MODE = 3
SMUGGLER_MAXSTOCK = 4
-- Sell and buy the item.
SMUGGLER_SELLANDBUY = 1
-- Only sell the item to the player.
SMUGGLER_SELLONLY = 2
-- Only buy the item from the player.
SMUGGLER_BUYONLY = 3
ix.util.Include("cl_plugin.lua")
ix.util.Include("cl_hooks.lua")
ix.util.Include("sh_items.lua")
ix.util.Include("sh_properties.lua")
ix.util.Include("sv_hooks.lua")
ix.util.Include("sv_plugin.lua")
ix.config.Add("SmugglerMoveInterval", 2, "The amount of hours in between the smuggler moving.", nil, {
data = {min = 0.1, max = 8, decimals = 1},
category = "Smuggler"
})
ix.config.Add("SmugglerDefaultMoney", 800, "The amount of money a smuggler spawns with by default.", nil, {
data = {min = 0, max = 2000},
category = "Smuggler"
})
ix.config.Add("SmugglerPickupDelay", 45, "The amount of minutes until items are available for pickup.", nil, {
data = {min = 1, max = 300},
category = "Smuggler"
})
ix.config.Add("SmugglingSellExpScale", 1, "The scale smuggling experience for selling items based on the price of the item.", nil, {
data = {min = 0.1, max = 10, decimals = 2},
category = "Smuggler"
})
ix.config.Add("SmugglingBuyExpScale", 1, "The scale smuggling experience for buying items based on the price of the item.", nil, {
data = {min = 0.1, max = 10, decimals = 2},
category = "Smuggler"
})
ix.config.Add("SmugglingShowWaypoints", true, "Should player see exact location of the smuggling stashes?", nil, {
category = "Smuggler"
})
ix.lang.AddTable("english", {
smugglerNoSellItems = "Nie ma żadnych przedmiotów na sprzedaż.",
smugglerNoBuyItems = "Nie ma żadnych przedmiotów do zakupu.",
smugglerSettings = "Ustawienia przemytnika",
smugglerUseMoney = "Przemytnik powinien użyć pieniędzy?",
smugglerBoth = "Kupno i sprzedaż",
smugglerBuy = "Tylko kupno",
smugglerSell = "Tylko sprzedaż",
smugglerWelcome = "Witaj w moim sklepie, co mogę Ci dziś zaoferować?",
smugglerBye = "Wpadnijcie jeszcze kiedyś!",
smugglerEditor = "Edytor przemytnika",
smugglerEditCurStock = "Edytuj bieżące zapasy",
smugglerStockReq = "Wprowadź maksymalną ilość przedmiotu, jaką przemytnik może kupić za każdym razem, gdy się pojawi.",
smugglerStockCurReq = "Wprowadź liczbę przedmiotów dostępnych do kupienia obecnie lub następnym razem, gdy pojawi się ten przemytnik.",
smugglerNoTrade = "Ten przemytnik odmawia handlu z tobą!",
smugglerNoTrust = "Ten przemytnik nie ufa ci na tyle, by handlować tym przedmiotem!",
smugglerNoMoney = "Tego przemytnika nie stać na ten przedmiot!",
smugglerNoStock = "Ten przemytnik nie ma tego przedmiotu w zapasie. Zamiast tego zamów go z dostawą!",
smugglerNoItems = "Ten przemytnik nie chce sprzedać Ci żadnych przedmiotów.",
smugglerMaxStock = "Ten przemytnik nie może dźwigać więcej tego przedmiotu!",
smugglerSelectPickupItem = "Wybierz przedmiot do odebrania:",
smugglerPickupItem = "Odebrałeś %s.",
smugglerPickupNoSpace = "Nie masz wystarczającej ilości miejsca na %s!",
smugglerNoPickupItems = "W tym miejscu nie ma żadnych przedmiotów dostępnych do odbioru!",
smugglerSelectDelivery = "Wybierz lokalizację dostawy",
smugglerDeliverTo = "Kup i dostarcz do %s",
smugglerPrepMove = "Ten przemytnik przygotowuje się do przemieszczenia, nie będzie już rozpoczynał nowych transakcji.",
smugglerAvailableDelivery = "Dostępne tylko na zamówienie",
smugglerAvailable = "Dostępne do kupienia: %d",
smugglerStock = "Przemytnik może kupić: %d\nPosiadasz: %d",
smugglerItemsDelivery = "Twoje przedmioty zostaną dostarczone do punktu odbioru za %d minut.",
smugglerUniqueIDExists = "Skrzynka odbiorcza o tym unikalnym identyfikatorze już istnieje!",
smugglerStackSize = "Sprzedawane w partiach %d.",
smugglerDeliveryNotify = "Masz kilka przedmiotów do odebrania! Znajdź oznaczoną skrytkę.",
smugglerNeedAtLeast = "Do sprzedaży potrzeba co najmniej %d tego przedmiotu."
})
ix.lang.AddTable("spanish", {
smugglerBye = "¡Vuelve pronto!",
smugglerMaxStock = "¡El contrabandista no puede llevar más de ese objeto!",
smugglerNoMoney = "¡El contrabandista no puede permitirse ese objeto!",
smugglerPrepMove = "El contrabandista se está preparando para trasladarse, ya no iniciará nuevos intercambios.",
smugglerEditCurStock = "Editar Actual Stock",
smugglerStockCurReq = "Introduce cuántos objetos están disponibles para su compra al momento o la próxima vez que aparezca este contrabandista.",
smugglerNoPickupItems = "¡No hay artículos disponibles que recoger aquí!",
smugglerPickupItem = "Has recogido un %s.",
smugglerNoTrust = "¡El contrabandista aún no confía lo suficiente en ti como para intercambiar este objeto!",
smugglerWelcome = "Bienvenido a mi tienda, ¿qué puedo ofrecerte hoy?",
smugglerBuy = "Solo Compra",
smugglerNoTrade = "¡El contrabandista se niega a comerciar contigo!",
smugglerStock = "Contrabandista puede comprar: %d\nTienes: %d",
smugglerAvailable = "Disponible para comprar: %d",
smugglerNoItems = "El contrabandista no está dispuesto a venderte ningún objeto.",
smugglerSelectPickupItem = "Elige un objeto a recuperar:",
smugglerDeliverTo = "Comprar y enviar a %s",
smugglerNoSellItems = "No hay objetos para vender.",
smugglerBoth = "Compra y Venta",
smugglerUseMoney = "¿Debería el contrabandista usar dinero?",
smugglerUniqueIDExists = "¡Ya existe un alijo de recogida con este ID único!",
smugglerItemsDelivery = "Tus objetos serán entregados en el punto de recogida en %d minutos.",
smugglerNoStock = "El contrabandista no tiene ese artículo en stock. ¡Pídelo para que te lo envíen!",
smugglerPickupNoSpace = "¡No tienes espacio suficiente para %s!",
smugglerSell = "Solo Venta",
smugglerAvailableDelivery = "Disponible solo por pedido para su entrega",
smugglerStockReq = "Introduce la cantidad máxima del objeto que el contrabandista puede comprar cada vez que aparezca.",
smugglerNoBuyItems = "No hay objetos para comprar.",
smugglerDeliveryNotify = "¡Tienes objetos que recoger! Encuentra el alijo marcado",
smugglerStackSize = "Se vende en lotes de %d.",
smugglerNeedAtLeast = "Necesitas al menos %d de este objeto para venderlo.",
smugglerSelectDelivery = "Selecciona el lugar de entrega",
smugglerEditor = "Editor del Contrabandista",
smugglerSettings = "Configuración del contrabandista"
})
ix.lang.AddTable("polish", {
smugglerNoSellItems = "Nie ma żadnych przedmiotów na sprzedaż.",
smugglerNoBuyItems = "Nie ma żadnych przedmiotów do zakupu.",
smugglerSettings = "Ustawienia przemytnika",
smugglerUseMoney = "Przemytnik powinien użyć pieniędzy?",
smugglerBoth = "Kupno i sprzedaż",
smugglerBuy = "Tylko kupno",
smugglerSell = "Tylko sprzedaż",
smugglerWelcome = "Witaj w moim sklepie, co mogę Ci dziś zaoferować?",
smugglerBye = "Wpadnijcie jeszcze kiedyś!",
smugglerEditor = "Edytor przemytnika",
smugglerEditCurStock = "Edytuj bieżące zapasy",
smugglerStockReq = "Wprowadź maksymalną ilość przedmiotu, jaką przemytnik może kupić za każdym razem, gdy się pojawi.",
smugglerStockCurReq = "Wprowadź liczbę przedmiotów dostępnych do kupienia obecnie lub następnym razem, gdy pojawi się ten przemytnik.",
smugglerNoTrade = "Ten przemytnik odmawia handlu z tobą!",
smugglerNoTrust = "Ten przemytnik nie ufa ci na tyle, by handlować tym przedmiotem!",
smugglerNoMoney = "Tego przemytnika nie stać na ten przedmiot!",
smugglerNoStock = "Ten przemytnik nie ma tego przedmiotu w zapasie. Zamiast tego zamów go z dostawą!",
smugglerNoItems = "Ten przemytnik nie chce sprzedać Ci żadnych przedmiotów.",
smugglerMaxStock = "Ten przemytnik nie może dźwigać więcej tego przedmiotu!",
smugglerSelectPickupItem = "Wybierz przedmiot do odebrania:",
smugglerPickupItem = "Odebrałeś %s.",
smugglerPickupNoSpace = "Nie masz wystarczającej ilości miejsca na %s!",
smugglerNoPickupItems = "W tym miejscu nie ma żadnych przedmiotów dostępnych do odbioru!",
smugglerSelectDelivery = "Wybierz lokalizację dostawy",
smugglerDeliverTo = "Kup i dostarcz do %s",
smugglerPrepMove = "Ten przemytnik przygotowuje się do przemieszczenia, nie będzie już rozpoczynał nowych transakcji.",
smugglerAvailableDelivery = "Dostępne tylko na zamówienie",
smugglerAvailable = "Dostępne do kupienia: %d",
smugglerStock = "Przemytnik może kupić: %d\nPosiadasz: %d",
smugglerItemsDelivery = "Twoje przedmioty zostaną dostarczone do punktu odbioru za %d minut.",
smugglerUniqueIDExists = "Skrzynka odbiorcza o tym unikalnym identyfikatorze już istnieje!",
smugglerStackSize = "Sprzedawane w partiach %d.",
smugglerDeliveryNotify = "Masz kilka przedmiotów do odebrania! Znajdź oznaczoną skrytkę.",
smugglerNeedAtLeast = "Do sprzedaży potrzeba co najmniej %d tego przedmiotu."
})
ix.char.RegisterVar("smugglingPickupItems", {
default = {},
bNoDisplay = true,
field = "smugglingPickup",
fieldType = ix.type.text,
bNoNetworking = true,
OnSet = function(character, itemID, locationID, amount)
if (!itemID or !ix.item.list[itemID]) then
return false
end
local items = character:GetSmugglingPickupItems()
local location = items[locationID] or {}
if (amount) then
location[itemID] = math.max((location[itemID] or 0) + amount, 0)
if (location[itemID] == 0) then
location[itemID] = nil
end
else
if (location[itemID] > 0) then
location[itemID] = location[itemID] - 1
if (location[itemID] == 0) then
location[itemID] = nil
end
else
return false
end
end
if (!table.IsEmpty(location)) then
items[locationID] = location
else
items[locationID] = nil
end
character.vars.smugglingPickupItems = items
end,
OnGet = function(character)
return character.vars.smugglingPickupItems or {}
end
})
ix.char.RegisterVar("smugglingPickupDelay", {
default = {},
bNoDisplay = true,
field = "smugglingPickupDelay",
fieldType = ix.type.text,
bNoNetworking = true,
OnSet = function(character, itemID, locationID, offset)
if (!itemID or !ix.item.list[itemID]) then
return
end
local items = character:GetSmugglingPickupDelay()
local time = os.time() + ix.config.Get("SmugglerPickupDelay") * 60 * offset
items[#items + 1] = {time, itemID, locationID}
character.vars.smugglingPickupDelay = items
character:SetSmugglingNextPickup(time)
end,
OnGet = function(character)
return character.vars.smugglingPickupDelay or {}
end
})
ix.char.RegisterVar("smugglingNextPickup", {
default = 0,
bNoDisplay = true,
isLocal = true
})
ix.command.Add("SmugglerForceRotate", {
description = "Forcefully rotates the current smuggler to a new one.",
superAdminOnly = true,
OnRun = function(self, client)
PLUGIN:RotateActiveSmuggler()
end
})
ix.command.Add("CheckPlayerSmugglerPickupItems", {
description = "Prints out data about smuggler items for specific player.",
adminOnly = true,
arguments = {
ix.type.character,
},
OnRun = function(self, client, character)
client:ChatPrint(character:GetName() .. "'s Pickup Items:")
for k, v in pairs(character:GetSmugglingPickupItems()) do
for key, val in pairs(v) do
client:ChatPrint(character:GetName() .. ": [" .. key .. "] - with amount of " .. val .. " is stored in crate with ID: " .. k)
end
end
client:ChatPrint(character:GetName() .. "'s Pickup Delay:")
for k, v in ipairs(character:GetSmugglingPickupDelay()) do
local delay = v[1] - os.time()
delay = math.Round(delay / 60)
if (delay % 5 != 0) then
delay = delay - (delay % 5) + 5
end
client:ChatPrint(character:GetName() .. ": ".. "Item["..v[2].."] - ".. delay .. " minutes until arriving to cache with ID: " .. v[3])
end
end
})
function PLUGIN:PhysgunPickup(client, entity)
if (entity:GetClass() == "ix_smuggler" or entity:GetClass() == "ix_pickupcache") then
return CAMI.PlayerHasAccess(client, "Helix - Manage Smugglers")
end
end
function PLUGIN:InitializedPlugins()
for uniqueID, data in pairs(self.itemList) do
local item = ix.item.list[uniqueID]
if (!item) then
ErrorNoHalt("[SMUGGLER] Attempted to add unknown item '"..uniqueID.."'.")
self.itemList[uniqueID] = nil
continue
end
if (!data.buy and !data.sell) then
ErrorNoHalt("[SMUGGLER] Attempted to add item '"..uniqueID.."' without buy or sell price.")
self.itemList[uniqueID] = nil
continue
end
ix.action:RegisterSkillAction("smuggling", "recipe_smuggling_"..uniqueID, {
name = item.name,
data = data,
itemID = uniqueID,
bNoLog = true,
description = "Allows you to buy and sell the '"..item.name.."' item via the smuggling network.",
CanDo = data.level or 0,
DoResult = function(action, character, skillLevel, bIsSelling)
if (skillLevel < action.CanDo) then return 0 end
-- set to selling if not specified to use sell exp as default exp
if (bIsSelling == nil) then bIsSelling = self.itemList[action.itemID].sell != nil end
local exp
if (bIsSelling != false and self.itemList[action.itemID]) then
exp = self.itemList[action.itemID].sellExp or self.itemList[action.itemID].sell
elseif (bIsSelling == false and self.itemList[action.itemID]) then
exp = self.itemList[action.itemID].buyExp or self.itemList[action.itemID].buy
end
if (!exp) then return 0 end
if (bIsSelling != false) then
exp = exp * ix.config.Get("SmugglingSellExpScale")
else
exp = exp * ix.config.Get("SmugglingBuyExpScale")
end
return exp
end}
)
local RECIPE = ix.recipe:New()
RECIPE.uniqueID = "smuggling_"..uniqueID
RECIPE.name = item.name
RECIPE.description = "Umożliwia kupowanie i sprzedawanie '"..item.name.."' za pośrednictwem sieci przemytniczej.."
RECIPE.model = item.model
RECIPE.category = data.cat or item.category
RECIPE.hidden = false
RECIPE.skill = "smuggling"
RECIPE.level = data.level or 0
RECIPE.cost = data.sell or "N/A"
RECIPE.buyPrice = data.buy or "N/A"
RECIPE.result = {[uniqueID] = 1}
RECIPE.bNoAction = true
RECIPE.costIcon = "willardnetworks/tabmenu/charmenu/chips.png"
RECIPE:Register()
end
if (SERVER) then
timer.Create("ixSmugglerRotation", 300, 0, function()
if (!self.nextRotation) then return end
if (self.nextRotation < os.time()) then
self:RotateActiveSmuggler()
elseif (self.nextRotation < os.time() + 300) then
self:PreRotateActiveSmuggler()
end
end)
end
end

View File

@@ -0,0 +1,213 @@
--[[
| 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
properties.Add("smuggler_edit", {
MenuLabel = "Edit Smuggler",
Order = 999,
MenuIcon = "icon16/user_edit.png",
Filter = function(self, entity, client)
if (!IsValid(entity)) then return false end
if (entity:GetClass() != "ix_smuggler") then return false end
if (!gamemode.Call( "CanProperty", client or LocalPlayer(), "smuggler_edit", entity)) then return false end
return CAMI.PlayerHasAccess(client or LocalPlayer(), "Helix - Manage Smugglers", nil)
end,
Action = function(self, entity)
self:MsgStart()
net.WriteEntity(entity)
self:MsgEnd()
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
if (!IsValid(entity)) then return end
if (!self:Filter(entity, client)) then return end
entity.receivers[#entity.receivers + 1] = client
local itemsTable = {}
for k, v in pairs(entity.items) do
if (!table.IsEmpty(v)) then
itemsTable[k] = v
end
end
client.ixSmuggler = entity
net.Start("ixSmugglerEditor")
net.WriteEntity(entity)
net.WriteUInt(entity.money or 0, 16)
net.WriteUInt(entity.maxStock or 0, 16)
net.WriteTable(itemsTable)
net.WriteTable(entity.messages)
net.Send(client)
end
})
properties.Add("pickup_id", {
MenuLabel = "Set Unique ID",
Order = 996,
MenuIcon = "icon16/user_edit.png",
Filter = function(self, entity, client)
if (!IsValid(entity)) then return false end
if (entity:GetClass() != "ix_pickupcache") then return false end
if (!gamemode.Call( "CanProperty", client or LocalPlayer(), "pickup_id", entity)) then return false end
if (PLUGIN.cacheIDList[entity:EntIndex()] and PLUGIN.cacheIDList[entity:EntIndex()].uniqueID != "") then return false end
return CAMI.PlayerHasAccess(client or LocalPlayer(), "Helix - Manage Smugglers", nil)
end,
Action = function(self, entity)
Derma_StringRequest("Enter new unique ID", "Enter new unique ID", "", function(text)
if (!text or text == "") then return end
self:MsgStart()
net.WriteEntity(entity)
net.WriteString(text)
self:MsgEnd()
end)
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
local uniqueID = net.ReadString()
if (!IsValid(entity)) then return end
if (uniqueID == "") then return end
if (!self:Filter(entity, client)) then return end
if (PLUGIN.pickupCaches[uniqueID] and PLUGIN.pickupCaches[uniqueID] != entity) then
client:NotifyLocalized("smugglerUniqueIDExists")
return
end
entity:UpdateUniqueID(uniqueID)
ix.saveEnts:SaveEntity(entity)
end
})
properties.Add("pickup_location", {
MenuLabel = "Set Location Id",
Order = 997,
MenuIcon = "icon16/user_edit.png",
Filter = function(self, entity, client)
if (!IsValid(entity)) then return false end
if (entity:GetClass() != "ix_pickupcache") then return false end
if (!gamemode.Call( "CanProperty", client or LocalPlayer(), "pickup_location", entity)) then return false end
return CAMI.PlayerHasAccess(client or LocalPlayer(), "Helix - Manage Smugglers", nil)
end,
Action = function(self, entity)
Derma_StringRequest("Enter new location ID", "", entity:GetLocationId(), function(text)
if (!text or text == "") then return end
self:MsgStart()
net.WriteEntity(entity)
net.WriteString(text)
self:MsgEnd()
end)
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
local locationId = net.ReadString()
if (!IsValid(entity)) then return end
if (locationId == "") then return end
if (!self:Filter(entity, client)) then return end
entity:SetLocationId(string.utf8upper(locationId))
ix.saveEnts:SaveEntity(entity)
end
})
properties.Add("pickup_name", {
MenuLabel = "Set Name",
Order = 998,
MenuIcon = "icon16/user_edit.png",
Filter = function(self, entity, client)
if (!IsValid(entity)) then return false end
if (entity:GetClass() != "ix_pickupcache") then return false end
if (!gamemode.Call( "CanProperty", client or LocalPlayer(), "pickup_name", entity)) then return false end
return CAMI.PlayerHasAccess(client or LocalPlayer(), "Helix - Manage Smugglers", nil)
end,
Action = function(self, entity)
Derma_StringRequest("Enter new display name", "", entity:GetDisplayName(), function(text)
if (!text or text == "") then return end
self:MsgStart()
net.WriteEntity(entity)
net.WriteString(text)
self:MsgEnd()
end)
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
local name = net.ReadString()
if (!IsValid(entity)) then return end
if (name == "") then return end
if (!self:Filter(entity, client)) then return end
entity:SetDisplayName(name)
ix.saveEnts:SaveEntity(entity)
end
})
properties.Add("pickup_model", {
MenuLabel = "Set Model",
Order = 999,
MenuIcon = "icon16/user_edit.png",
Filter = function(self, entity, client)
if (!IsValid(entity)) then return false end
if (entity:GetClass() != "ix_pickupcache") then return false end
if (!gamemode.Call( "CanProperty", client or LocalPlayer(), "pickup_model", entity)) then return false end
return CAMI.PlayerHasAccess(client or LocalPlayer(), "Helix - Manage Smugglers", nil)
end,
Action = function(self, entity)
Derma_StringRequest("Enter new model", "", entity:GetModel(), function(text)
if (!text or text == "") then return end
self:MsgStart()
net.WriteEntity(entity)
net.WriteString(text)
self:MsgEnd()
end)
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
local model = net.ReadString()
if (!IsValid(entity)) then return end
if (model == "") then return end
if (!self:Filter(entity, client)) then return end
entity:SetNewModel(model)
ix.saveEnts:SaveEntity(entity)
end
})

View File

@@ -0,0 +1,288 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
function PLUGIN:PlayerLoadedCharacter(client, character)
if (CAMI.PlayerHasAccess(client, "Helix - Manage Smugglers")) then
netstream.Start(client, "ixSmugglingCacheUIDs", self.cacheIDList)
end
local uniqueID = "ixSmuggling"..client:SteamID64()
timer.Create(uniqueID, 60, 0, function()
if (!IsValid(client)) then timer.Remove(uniqueID) return end
local char = client:GetCharacter()
if (!char) then return end
local pickupItems = char:GetSmugglingPickupDelay()
if (#pickupItems == 0) then return end
local k = 1
while (#pickupItems >= k and pickupItems[k][1] < os.time()) do
char:SetSmugglingPickupItems(pickupItems[k][2], pickupItems[k][3], 1)
k = k + 1
end
if (k > 1) then
local newTbl = {}
for i = k, #pickupItems do
newTbl[#newTbl + 1] = pickupItems[i]
end
char.vars.smugglingPickupDelay = newTbl
char:Save()
end
client:UpdateStashWaypoints()
end)
local pickupItems = character:GetSmugglingPickupItems()
for k, v in pairs(pickupItems) do
if (k == "__invalid_cache") then continue end
local bFound = false
for _, v1 in pairs(self.pickupCaches) do
if (k == v1.uniqueID) then
bFound = true
break
end
end
if (bFound) then continue end
pickupItems["__invalid_cache"] = pickupItems["__invalid_cache"] or {}
for k1, v1 in pairs(v) do
pickupItems["__invalid_cache"][k1] = (pickupItems["__invalid_cache"][k1] or 0) + v1
end
pickupItems[k] = nil
end
character.vars.smugglingPickupItems = pickupItems
client:UpdateStashWaypoints(pickupItems)
end
function PLUGIN:RegisterSaveEnts()
ix.saveEnts:RegisterEntity("ix_smuggler", true, true, true, {
OnSave = function(entity, data) --OnSave
data.name = entity:GetDisplayName()
data.description = entity:GetDescription()
data.model = entity:GetModel()
data.items = entity.items
data.money = entity.money
data.maxStock = entity.maxStock
data.stashList = entity.stashList
data.motion = nil
if (entity.ixIsActiveSmuggler) then
data.active = self.nextRotation
end
end,
OnRestore = function(entity, data) --OnRestore
entity:SetModel(data.model)
entity:SetSolid(SOLID_BBOX)
entity:PhysicsInit(SOLID_BBOX)
local physObj = entity:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion()
physObj:Sleep()
end
entity:SetDisplayName(data.name)
entity:SetDescription(data.description)
local items = {}
for uniqueID, itemData in pairs(data.items) do
items[tostring(uniqueID)] = itemData
end
entity.items = items
entity.money = data.money
entity.maxStock = data.maxStock
entity.stashList = data.stashList
if (data.active and !self.nextRotation and data.active > os.time() + 300) then
self.nextRotation = data.active
entity:SetActive()
else
entity:SetInactive()
end
end,
})
ix.saveEnts:RegisterEntity("ix_pickupcache", true, true, true, {
OnSave = function(entity, data) --OnSave
data.name = entity:GetDisplayName()
data.uniqueID = entity.uniqueID
data.model = entity:GetModel()
data.locationId = entity:GetLocationId()
data.motion = false
end,
OnRestore = function(entity, data) --OnRestore
entity:SetNewModel(data.model)
local physObj = entity:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion()
physObj:Sleep()
end
entity:SetDisplayName(data.name)
entity:SetLocationId(data.locationId)
entity:UpdateUniqueID(data.uniqueID)
end,
ShouldSave = function(entity)
return self.pickupCaches[entity.uniqueID]
end
})
end
function PLUGIN:SaveData()
local smugglers = {}
for _, entity in ipairs(ents.FindByClass("ix_smuggler")) do
local bodygroups = {}
for _, v in ipairs(entity:GetBodyGroups() or {}) do
bodygroups[v.id] = entity:GetBodygroup(v.id)
end
smugglers[#smugglers + 1] = {
name = entity:GetDisplayName(),
description = entity:GetDescription(),
pos = entity:GetPos(),
angles = entity:GetAngles(),
model = entity:GetModel(),
skin = entity:GetSkin(),
bodygroups = bodygroups,
items = entity.items,
money = entity.money,
maxStock = entity.maxStock,
stashList = entity.stashList
}
if (entity.ixIsActiveSmuggler) then
smugglers[#smugglers].active = self.nextRotation
end
end
ix.data.Set("smugglers", smugglers)
local caches = {}
for uid, entity in pairs(self.pickupCaches) do
if (!IsValid(entity)) then
self.pickupCaches[uid] = nil
continue
end
local bodygroups = {}
for _, v in ipairs(entity:GetBodyGroups() or {}) do
bodygroups[v.id] = entity:GetBodygroup(v.id)
end
caches[#caches + 1] = {
name = entity:GetDisplayName(),
uniqueID = uid,
pos = entity:GetPos(),
angles = entity:GetAngles(),
model = entity:GetModel(),
skin = entity:GetSkin(),
bodygroups = bodygroups,
locationId = entity:GetLocationId()
}
end
ix.data.Set("smuggling_caches", caches)
end
function PLUGIN:LoadData()
if (!ix.config.Get("SaveEntsOldLoadingEnabled")) then return end
local caches = ix.data.Get("smuggling_caches") or {}
for _, v in ipairs(caches) do
local entity = ents.Create("ix_pickupcache")
entity:SetPos(v.pos)
entity:SetAngles(v.angles)
entity:Spawn()
entity:SetNewModel(v.model)
entity:SetSkin(v.skin or 0)
local physObj = entity:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
entity:SetDisplayName(v.name)
entity:SetLocationId(v.locationId)
for id, bodygroup in pairs(v.bodygroups or {}) do
entity:SetBodygroup(id, bodygroup)
end
entity:UpdateUniqueID(v.uniqueID)
end
for _, v in ipairs(ix.data.Get("smugglers") or {}) do
local entity = ents.Create("ix_smuggler")
entity:SetPos(v.pos)
entity:SetAngles(v.angles)
entity:Spawn()
entity:SetModel(v.model)
entity:SetSkin(v.skin or 0)
entity:SetSolid(SOLID_BBOX)
entity:PhysicsInit(SOLID_BBOX)
local physObj = entity:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
entity:SetDisplayName(v.name)
entity:SetDescription(v.description)
for id, bodygroup in pairs(v.bodygroups or {}) do
entity:SetBodygroup(id, bodygroup)
end
local items = {}
for uniqueID, data in pairs(v.items) do
items[tostring(uniqueID)] = data
end
entity.items = items
entity.money = v.money
entity.maxStock = v.maxStock
entity.stashList = v.stashList
if (v.active and !self.nextRotation and v.active > os.time() + 300) then
self.nextRotation = v.active
entity:SetActive()
else
entity:SetInactive()
end
end
end
function PLUGIN:PostLoadData()
timer.Simple(10, function()
if (!self.nextRotation) then
self:RotateActiveSmuggler()
end
end)
end

View File

@@ -0,0 +1,496 @@
--[[
| 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/
--]]
-- luacheck: read globals SMUGGLER_BUY SMUGGLER_SELL SMUGGLER_BOTH SMUGGLER_WELCOME SMUGGLER_LEAVE SMUGGLER_NOTRADE SMUGGLER_PRICE
-- luacheck: read globals SMUGGLER_STOCK SMUGGLER_MODE SMUGGLER_MAXSTOCK SMUGGLER_SELLANDBUY SMUGGLER_SELLONLY SMUGGLER_BUYONLY SMUGGLER_TEXT
local PLUGIN = PLUGIN
util.AddNetworkString("ixSmugglerOpen")
util.AddNetworkString("ixSmugglerClose")
util.AddNetworkString("ixSmugglerTrade")
util.AddNetworkString("ixSmugglerEdit")
util.AddNetworkString("ixSmugglerEditFinish")
util.AddNetworkString("ixSmugglerEditor")
util.AddNetworkString("ixSmugglerMoney")
util.AddNetworkString("ixSmugglerStock")
util.AddNetworkString("ixSmugglerAddItem")
util.AddNetworkString("ixSmugglerChosePickup")
PLUGIN.pickupCaches = PLUGIN.pickupCaches or {}
function PLUGIN:UpdateCacheID(entity, newID, oldID)
self.pickupCaches[newID] = entity
if (oldID and oldID != "") then
self.pickupCaches[oldID] = nil
end
self.cacheIDList[entity:EntIndex()] = {
uniqueID = newID,
locationId = entity:GetLocationId()
}
CAMI.GetPlayersWithAccess("Helix - Manage Smugglers", function(receivers)
netstream.Start(receivers, "ixSmugglingCacheUIDs", self.cacheIDList)
end)
end
function PLUGIN:CanSmugglerSellItem(client, smuggler, itemID)
local tradeData = smuggler.items[itemID]
local char = client:GetCharacter()
if (!tradeData or !char) then
return false
end
if (!char:HasMoney(tradeData[1] or 0)) then
return false
end
return true
end
function PLUGIN:RotateActiveSmuggler()
local activeSmuggler
local smugglers = ents.FindByClass("ix_smuggler")
for k, v in ipairs(smugglers) do
if (v.ixIsActiveSmuggler) then
activeSmuggler = v
table.remove(smugglers, k)
break
end
end
if (#smugglers > 0) then
self.nextRotation = os.time() + ix.config.Get("SmugglerMoveInterval") * 3600 * math.Rand(0.8, 1.2)
if (activeSmuggler) then
activeSmuggler:SetInactive()
end
local newSmuggler = smugglers[math.random(#smugglers)]
newSmuggler:SetActive()
elseif (IsValid(activeSmuggler)) then
activeSmuggler:ResetSmuggler()
end
end
function PLUGIN:PreRotateActiveSmuggler()
for _, v in ipairs(ents.FindByClass("ix_smuggler")) do
if (v.ixIsActiveSmuggler) then
v.ixSmugglerPrepRotation = true
for _, client in ipairs(v.receivers) do
client:NotifyLocalized("The smuggler is starting to prepare to move, better finish your trades.")
end
break
end
end
end
local playerMeta = FindMetaTable("Player")
function playerMeta:UpdateStashWaypoints(pickupItems)
pickupItems = pickupItems or self:GetCharacter():GetSmugglingPickupItems()
local stashEntities = {}
local waypoints = {}
for k, v in pairs(pickupItems) do
local stashEntity = PLUGIN.pickupCaches[k]
if (IsValid(stashEntity)) then
table.insert(stashEntities, stashEntity:EntIndex())
local amount = 0
for _, itemAmount in pairs(v) do
amount = amount + itemAmount
end
table.insert(waypoints, {
pos = stashEntity:GetPos() + Vector(0, 0, 30),
name = string.format("%s (%d items)", stashEntity:GetDisplayName(), amount)
})
end
end
if (!table.IsEmpty(stashEntities)) then
self:NotifyLocalized("smugglerDeliveryNotify")
end
if (ix.config.Get("SmugglingShowWaypoints")) then
netstream.Start(self, "ixShowStashWaypoints", waypoints, stashEntities)
end
end
ix.log.AddType("smugglerUse", function(client, ...)
local arg = {...}
return string.format("%s used the '%s' smuggler.", client:Name(), arg[1])
end)
ix.log.AddType("smugglerBuy", function(client, item, smuggler, delivery)
return string.format("%s bought a '%s' from the '%s' smuggler%s.", client:Name(), item, smuggler, delivery and " for delivery to "..delivery or "")
end)
ix.log.AddType("smugglerSell", function(client, item, smuggler)
return string.format("%s sold a '%s' to the '%s' smuggler.", client:Name(), item, smuggler)
end)
ix.log.AddType("smugglerPickup", function(client, item, pickup)
return string.format("%s picked up a '%s' from '%s.", client:Name(), item, pickup)
end)
net.Receive("ixSmugglerClose", function(length, client)
local entity = client.ixSmuggler
if (IsValid(entity)) then
for k, v in ipairs(entity.receivers) do
if (v == client) then
table.remove(entity.receivers, k)
break
end
end
if (client.ixSmugglerDelivery) then
local delay = client:GetCharacter():GetSmugglingNextPickup() - os.time()
delay = math.Round(delay / 60)
if (delay % 5 != 0) then
delay = delay - (delay % 5) + 5
end
client:NotifyLocalized("smugglerItemsDelivery", delay)
client.ixSmugglerDelivery = nil
end
client.ixSmuggler = nil
end
end)
local function UpdateEditReceivers(receivers, key, value)
net.Start("ixSmugglerEdit")
net.WriteString(key)
net.WriteType(value)
net.Send(receivers)
end
net.Receive("ixSmugglerEdit", function(length, client)
if (!CAMI.PlayerHasAccess(client, "Helix - Manage Smugglers", nil)) then
return
end
local entity = client.ixSmuggler
if (!IsValid(entity)) then
return
end
local key = net.ReadString()
local data = net.ReadType()
local feedback = true
if (key == "name") then
entity:SetDisplayName(data)
elseif (key == "description") then
entity:SetDescription(data)
elseif (key == "mode") then
local uniqueID = data[1]
local mode = data[2]
if ((mode == SMUGGLER_BUYONLY or mode == SMUGGLER_SELLANDBUY) and !PLUGIN.itemList[uniqueID].buy) then
return
elseif ((mode == SMUGGLER_SELLONLY or mode == SMUGGLER_SELLANDBUY) and !PLUGIN.itemList[uniqueID].sell) then
return
end
entity.items[uniqueID] = entity.items[uniqueID] or {}
entity.items[uniqueID][SMUGGLER_MODE] = data[2]
UpdateEditReceivers(entity.receivers, key, data)
elseif (key == "stockMax") then
data = math.Round(math.abs(tonumber(data) or 0))
entity.maxStock = data
UpdateEditReceivers(entity.receivers, key, data)
elseif (key == "stock") then
local uniqueID = data[1]
entity.items[uniqueID] = entity.items[uniqueID] or {}
data[2] = math.max(math.Round(tonumber(data[2]) or 0), 0)
entity.items[uniqueID][SMUGGLER_STOCK] = data[2]
UpdateEditReceivers(entity.receivers, key, data)
data = uniqueID
elseif (key == "model") then
entity:SetModel(data)
entity:SetSolid(SOLID_BBOX)
entity:PhysicsInit(SOLID_BBOX)
entity:SetAnim()
elseif (key == "useMoney") then
if (entity.money) then
entity:SetMoney()
else
entity:SetMoney(0)
end
elseif (key == "money") then
data = math.Round(math.abs(tonumber(data) or 0))
entity:SetMoney(data)
feedback = false
elseif (key == "stashList") then
entity.stashList = data
end
ix.saveEnts:SaveEntity(entity)
PLUGIN:SaveData()
if (feedback) then
local receivers = {}
for _, v in ipairs(entity.receivers) do
if (CAMI.PlayerHasAccess(v, "Helix - Manage Smugglers", nil)) then
receivers[#receivers + 1] = v
end
end
net.Start("ixSmugglerEditFinish")
net.WriteString(key)
net.WriteType(data)
net.Send(receivers)
end
end)
net.Receive("ixSmugglerTrade", function(length, client)
if ((client.ixSmugglerTry or 0) < CurTime()) then
client.ixSmugglerTry = CurTime() + 0.33
else
return
end
local entity = client.ixSmuggler
if (!IsValid(entity) or client:GetPos():DistToSqr(entity:GetPos()) > 192 * 192) then
return
end
if (!entity.ixIsActiveSmuggler) then return end
local uniqueID = net.ReadString()
local isSellingToSmuggler = net.ReadBool()
if (!client:GetCharacter():CanDoAction("recipe_smuggling_"..uniqueID)) then
return client:NotifyLocalized("smugglerNoTrust")
end
if (entity.items[uniqueID] and PLUGIN.itemList[uniqueID] and
hook.Run("CanPlayerTradeWithSmuggler", client, entity, uniqueID, isSellingToSmuggler, PLUGIN.itemList[uniqueID]) != false) then
local price = entity:GetPrice(uniqueID, isSellingToSmuggler)
if (isSellingToSmuggler) then
local found = false
local name
if (!PLUGIN.itemList[uniqueID].buy) then
client:NotifyLocalized("smugglerNoTrade")
end
if (!entity:HasMoney(price)) then
return client:NotifyLocalized("smugglerNoMoney")
end
local stock, max = entity:GetStock(uniqueID)
if (stock and stock >= max) then
return client:NotifyLocalized("smugglerMaxStock")
end
if (entity:GetTotalStock() >= entity.maxStock) then
return client:NotifyLocalized("smugglerMaxStock")
end
local invOkay = true
local amount = 0
local candidates = {}
local amountNeeded = PLUGIN.itemList[uniqueID].stackSize
if (!amountNeeded and ix.item.list[uniqueID].bInstanceMaxstack) then
amountNeeded = ix.item.list[uniqueID].maxStackSize
end
for _, v in pairs(client:GetCharacter():GetInventory():GetItems()) do
if (v.uniqueID == uniqueID and v:GetID() != 0 and ix.item.instances[v:GetID()] and v:GetData("equip", false) == false) then
if (v.maxStackSize and amountNeeded) then
candidates[#candidates + 1] = v
amount = amount + v:GetStackSize()
else
invOkay = v:Remove()
found = true
name = L(v.name, client)
break
end
end
end
if (!found and amountNeeded) then
if (amountNeeded > amount) then
price = math.floor(price * amount / amountNeeded)
end
found = true
name = L(candidates[1].name, client)
local i = #candidates
while (amountNeeded > 0 and i > 0) do
local toRemove = math.min(amountNeeded, candidates[i]:GetStackSize())
amountNeeded = amountNeeded - toRemove
invOkay = invOkay and candidates[i]:RemoveStack(toRemove)
i = i - 1
if (!invOkay) then break end
end
end
if (!found) then
return
end
if (!invOkay) then
client:GetCharacter():GetInventory():Sync(client, true)
return client:NotifyLocalized("tellAdmin", "trd!iid")
end
client:GetCharacter():GiveMoney(price)
client:NotifyLocalized("businessSell", name, ix.currency.Get(price))
entity:TakeMoney(price)
entity:AddStock(uniqueID)
client:GetCharacter():DoAction("recipe_smuggling_"..uniqueID, false)
ix.saveEnts:SaveEntity(entity)
PLUGIN:SaveData()
ix.log.Add(client, "smugglerSell", uniqueID, entity:GetDisplayName())
--TODO: grant experience if not railroad item
hook.Run("CharacterSmugglerTraded", client, entity, uniqueID, isSellingToSmuggler)
else
local bDelivery = net.ReadBool()
if (!PLUGIN.itemList[uniqueID].sell) then
client:NotifyLocalized("smugglerNoTrade")
end
if (!client:GetCharacter():HasMoney(price)) then
return client:NotifyLocalized("canNotAfford")
end
if (bDelivery) then
if (!IsValid(entity.pickupCache)) then
client:NotifyLocalized("smugglerInvalidPickupLocation")
return
end
client:GetCharacter():SetSmugglingPickupDelay(uniqueID, entity.pickupCache.uniqueID, entity.ixSmugglerDeliveryOffset)
client.ixSmugglerDelivery = true
ix.log.Add(client, "smugglerBuy", uniqueID, entity:GetDisplayName(), entity.pickupCache.uniqueID)
else
local stock = entity:GetStock(uniqueID)
if (stock <= 0) then
return client:NotifyLocalized("smugglerNoStock")
end
local data = nil
if (PLUGIN.itemList[uniqueID].stackSize) then
data = {stack = PLUGIN.itemList[uniqueID].stackSize}
end
if (!client:GetCharacter():GetInventory():Add(uniqueID, nil, data)) then
ix.item.Spawn(uniqueID, client, function(item)
if (data and data.stack) then
item:SetStack(data.stack)
end
end)
else
net.Start("ixSmugglerAddItem")
net.WriteString(uniqueID)
net.Send(client)
end
entity:TakeStock(uniqueID)
ix.log.Add(client, "smugglerBuy", uniqueID, entity:GetDisplayName())
end
client:GetCharacter():TakeMoney(price)
entity:GiveMoney(price)
client:GetCharacter():DoAction("recipe_smuggling_"..uniqueID, true)
local name = L(ix.item.list[uniqueID].name, client)
client:NotifyLocalized("businessPurchase", name, ix.currency.Get(price))
ix.saveEnts:SaveEntity(entity)
PLUGIN:SaveData()
hook.Run("CharacterSmugglerTraded", client, entity, uniqueID, isSellingToSmuggler)
end
else
client:NotifyLocalized("smugglerNoTrade")
end
end)
net.Receive("ixSmugglerChosePickup", function(len, client)
local entity = net.ReadEntity()
if (!IsValid(client.ixSmuggler)) then
return
elseif (IsValid(client.ixSmuggler.pickupCache)) then
netstream.Start(client, "ixSmugglerUpdateLocation", client.ixSmuggler, client.ixSmuggler.pickupCache:GetDisplayName())
return
end
client.ixSmuggler.pickupCache = entity
if (IsValid(client.ixSmuggler.pickupCache)) then
netstream.Start(client, "ixSmugglerUpdateLocation", client.ixSmuggler, client.ixSmuggler.pickupCache:GetDisplayName())
end
end)
netstream.Hook("SmugglingCachePickup", function(client, itemID)
local character = client:GetCharacter()
if (!character) then return end
local cache = client.ixPickupCache
if (!IsValid(cache) or cache.uniqueID == "") then
return
end
local pickupItems = character:GetSmugglingPickupItems()
if (pickupItems[cache.uniqueID] and pickupItems[cache.uniqueID][itemID] and pickupItems[cache.uniqueID][itemID] > 0) then
if (character:SetSmugglingPickupItems(itemID, cache.uniqueID) == false) then return end
local data = nil
if (PLUGIN.itemList[itemID].stackSize) then
data = {stack = PLUGIN.itemList[itemID].stackSize}
end
if (!client:GetCharacter():GetInventory():Add(itemID, nil, data)) then
ix.item.Spawn(itemID, client, function(item)
if (data and data.stack) then
item:SetStack(data.stack)
end
end)
end
ix.log.Add(client, "smugglerPickup", itemID, cache.uniqueID)
client:UpdateStashWaypoints()
character:Save()
end
end)
netstream.Hook("ClosePickupCache", function(client)
client.ixPickupCache = nil
end)