This commit is contained in:
lifestorm
2024-08-04 23:54:45 +03:00
parent 8064ba84d8
commit 6a58f406b1
7522 changed files with 4011896 additions and 15 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("Select a pickup location", "", list, "Select pickup location", "Select", function(value, text)
net.Start("ixSmugglerChosePickup")
net.WriteEntity(value)
net.SendToServer()
end, "Cancel", 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 "").." (total stock: "..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 "").." (total stock: "..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 = "Ingredients", level = 2},
["ing_vinegar"] = {sell = 15, buy = 4, cat = "Ingredients", level = 3},
["ing_herbs"] = {sell = 10, buy = 3, cat = "Ingredients", level = 2},
["ing_egg"] = {sell = 25, buy = 12, cat = "Ingredients", level = 4},
["ing_margarine"] = {sell = 9, buy = 3, cat = "Ingredients", level = 2},
["ing_salt"] = {sell = 9, buy = 3, cat = "Ingredients", level = 1},
["ing_spices"] = {sell = 12, buy = 6, cat = "Ingredients", level = 3},
["ing_vegetable_pack"] = {sell = 12, buy = 4, cat = "Ingredients", level = 3},
["ing_noodles"] = {sell = 9, buy = 3, cat = "Ingredients", level = 2},
["ing_protein"] = {sell = 10, buy = 3, cat = "Ingredients", level = 2},
["ing_sweet"] = {sell = 8, buy = 4, cat = "Ingredients", level = 3},
["drink_milk"] = {sell = 10, buy = 4, cat = "Ingredients", level = 2},
["fruit_berries"] = {sell = 12, buy = 6, cat = "Ingredients", level = 1},
["ing_headcrab_meat"] = {sell = 15, buy = 3, cat = "Ingredients", level = 0},
["ing_antlion_meat"] = {sell = 15, buy = 3, cat = "Ingredients", level = 0},
["drink_beer"] = {sell = 60, buy = 25, cat = "Alcohol", level = 3},
["bottle_bourbon"] = {sell = 70, buy = 30, cat = "Alcohol", level = 4},
["bottle_whiskey"] = {sell = 70, buy = 30, cat = "Alcohol", level = 4},
["bottle_vodka"] = {sell = 70, buy = 30, cat = "Alcohol", level = 4},
--Components
["comp_plastic"] = {sell = 7, buy = 2, cat = "Crafting Components", level = 0},
["comp_wood"] = {sell = 8, buy = 3, cat = "Crafting Components", level = 0},
["comp_cloth"] = {sell = 8, buy = 3, cat = "Crafting Components", level = 0},
["comp_scrap"] = {sell = 9, buy = 3, cat = "Crafting Components", level = 0},
["comp_electronics"] = {sell = 10, buy = 3, cat = "Crafting Components", level = 0},
["comp_adhesive"] = {sell = 25, buy = 10, cat = "Crafting Components", level = 4},
["comp_alcohol"] = {sell = 35, buy = 18, cat = "Crafting Components", level = 7},
["comp_chemicals"] = {sell = 23, buy = 11, cat = "Crafting Components", level = 7},
["comp_stitched_cloth"] = {sell = 43, buy = 23, cat = "Crafting Components", level = 12},
["comp_screws"] = {sell = 26, buy = 12, cat = "Crafting Components", level = 6},
["comp_chemcomp"] = {sell = 50, buy = 26, cat = "Crafting Components", level = 15},
["comp_rivbolts"] = {sell = 113, buy = 44, cat = "Crafting Components", level = 15},
["comp_refined_plastic"] = {sell = 42, buy = 16, cat = "Crafting Components", level = 15},
["comp_iron"] = {sell = 52, buy = 22, cat = "Crafting Components", level = 15},
["comp_steel"] = {sell = 260, buy = 115, cat = "Crafting Components", level = 20},
["comp_fabric"] = {sell = 200, buy = 81, cat = "Crafting Components", level = 20},
["comp_explosive"] = {sell = 220, buy = 95, cat = "Crafting Components", level = 20},
--Medical
["comp_purifier"] = {sell = 50, buy = 26, cat = "Medical Components", level = 10},
["comp_syringe"] = {sell = 30, buy = 14, cat = "Medical Components", level = 5},
["bandage"] = {sell = 44, buy = 12, cat = "Medicine", level = 5, stackSize = 6},
["disinfectant_bottle"] = {sell = 98, buy = 45, cat = "Medicine", level = 5, stackSize = 6},
["painkillers"] = {sell = 90, buy = 33, cat = "Medicine", level = 8, stackSize = 4},
["disinfected_bandage"] = {sell = 112, buy = 58, cat = "Medicine", level = 10, stackSize = 4},
["bloodbag"] = {sell = 243, buy = 100, cat = "Medicine", level = 15, stackSize = 4},
["bloodstabilizer"] = {sell = 237, buy = 97, cat = "Medicine", level = 12, stackSize = 4},
["adrenaline"] = {sell = 90, buy = 33, cat = "Medicine", level = 13, stackSize = 3},
["morphine"] = {sell = 90, buy = 35, cat = "Medicine", level = 16, stackSize = 3},
["firstaid"] = {sell = 480, buy = 200, cat = "Medicine", level = 19, stackSize = 3},
["surgerykit"] = {sell = 778, buy = 300, cat = "Medicine", level = 20, stackSize = 3},
-- Tools
["head_gasmask"] = {sell = 320, buy = 180, cat = "Equipment", level = 20},
["highquality_filter"] = {sell = 550, buy = 200, cat = "Equipment", level = 20},
["face_bandana"] = {sell = 72, buy = 26, cat = "Equipment", level = 4},
["head_military_cap"] = {sell = 80, buy = 38, cat = "Equipment", level = 9},
["smallbag"] = {sell = 160, buy = 85, cat = "Equipment", level = 4},
["largebag"] = {sell = 250, buy = 146, cat = "Equipment", level = 13},
["flashlight"] = {sell = 22, buy = 8, cat = "Equipment", level = 2},
["handheld_radio"] = {sell = 420, buy = 240, cat = "Equipment", level = 20},
["old_radio"] = {sell = 260, buy = 100, cat = "Equipment", level = 11},
["waterbottle"] = {sell = 20, buy = 5, cat = "Tools", level = 0},
["watervalve"] = {sell = 30, buy = 10, cat = "Tools", level = 8},
["tool_wrench"] = {sell = 160, buy = 70, cat = "Tools", level = 12},
["tool_toolkit"] = {sell = 103, buy = 60, cat = "Tools", level = 7},
["tinderbox"] = {sell = 47, buy = 30, cat = "Tools", level = 9},
["lighter"] = {sell = 40, buy = 13, cat = "Tools", level = 0},
["beard_razor"] = {sell = 48, buy = 13, cat = "Tools", level = 4},
["tool_scissors"] = {sell = 18, buy = 5, cat = "Tools", level = 0},
["tool_cookingpot"] = {sell = 45, buy = 20, cat = "Tools", level = 6},
["tool_spoon"] = {sell = 22, buy = 10, cat = "Tools", level = 2},
["tool_knife"] = {sell = 34, buy = 14, cat = "Tools", level = 3},
["tool_fryingpan"] = {sell = 45, buy = 20, cat = "Tools", level = 4},
["tool_mixer"] = {sell = 160, buy = 80, cat = "Tools", level = 20},
}

View File

@@ -0,0 +1,348 @@
--[[
| 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 = "Satılacak hiçbir ürün yok.",
smugglerNoBuyItems = "Satın alınacak hiçbir ürün yok.",
smugglerSettings = "Kaçakçı Ayarları",
smugglerUseMoney = "Kaçakçı para kullanmalı mı?",
smugglerBoth = "Al ve Sat",
smugglerBuy = "Sadece Al",
smugglerSell = "Sadece Sat",
smugglerWelcome = "Mağazama hoş geldiniz, bugün size ne alabilirim?",
smugglerBye = "Yakında tekrar gel!",
smugglerEditor = "Kaçakçı Editörü",
smugglerEditCurStock = "Mevcut Stoğu Düzenle",
smugglerStockReq = "Kaçakçının her oluşumda alabileceği ürünün maksimum miktarını girin.",
smugglerStockCurReq = "Şu anda veya bu kaçakçı bir sonraki kez oluşturulduğunda kaç ürünün satın alınabilir olduğunu girin.",
smugglerNoTrade = "Bu kaçakçı sizinle ticaret yapmayı reddetti!",
smugglerNoTrust = "Bu kaçakçı bu ürünü ticaret yapacak kadar size güvenmiyor!",
smugglerNoMoney = "Bu kaçakçının o ürünü alacak parası yok!",
smugglerNoStock = "Bu kaçakçının stoğunda bu ürün yok. Bunun yerine teslimat için sipariş verin!",
smugglerNoItems = "Bu kaçakçı size herhangi bir ürün satmak istemiyor.",
smugglerMaxStock = "Bu kaçakçı daha fazla bu ürünü taşıyamaz!",
smugglerSelectPickupItem = "Alınacak bir ürün seçin:",
smugglerPickupItem = "%s aldınız.",
smugglerPickupNoSpace = "%s için yeterli alanınız yok!",
smugglerNoPickupItems = "Burada alınabilecek uygun ürün yok!",
smugglerSelectDelivery = "Teslimat Yerini Seç",
smugglerDeliverTo = "Al & %s'a Teslim Et",
smugglerPrepMove = "Bu kaçakçı hareket etmeye hazırlanıyor, artık yeni ticaretlere başlamayacak.",
smugglerAvailableDelivery = "Sadece teslimat için siparişte mevcut",
smugglerAvailable = "Satın alınabilir: %d",
smugglerStock = "Kaçakçı alabilir: %d\nSende olan: %d",
smugglerItemsDelivery = "Ürünleriniz %d dakika içinde teslim noktasına gönderilecek.",
smugglerUniqueIDExists = "Bu benzersiz ID ile zaten bir teslimat önbelleği var!",
smugglerStackSize = "%d boyutunda yığınlar halinde satılır.",
smugglerDeliveryNotify = "Alınacak bazı ürünleriniz var! İşaretli yeri bulun",
smugglerNeedAtLeast = "Bu ürünü satmak için en az %d tane olmalı."
})
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.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 = "'"..item.name.."' eşyasını kaçakçılık ağıyla alıp satmanızı sağlar.",
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 = "'"..item.name.."' eşyasını kaçakçılık ağıyla alıp satmanızı sağlar."
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)