This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 8064ba84d8
commit 73479cff9e
7338 changed files with 1718883 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 "Boîte en carton"
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("Sélectionner un emplacement de ramassage", "", list, "Select pickup location", "Select", function(value, text)
net.Start("ixSmugglerChosePickup")
net.WriteEntity(value)
net.SendToServer()
end, "Annuler", 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 "").." (Stock Total : "..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 "").." (Stock Total : "..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("Laisser la liste vide pour utiliser tous les emplacements et ne pas attribuer de cachettes \nDouble cliquer pour supprimer lentrée")
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", "Saisir l'identifiant de l'emplacement des réserves qui seront utilisées.", "", 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("Recherche...")
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 = "Caisse de livraison"
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,111 @@
--[[
| 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 = 12, buy = 4, cat = "Ingrédients", level = 2},
["ing_vinegar"] = {sell = 12, buy = 4, cat = "Ingrédients", level = 3},
["ing_herbs"] = {sell = 10, buy = 3, cat = "Ingrédients", level = 2},
["ing_egg"] = {sell = 25, buy = 12, cat = "Ingrédients", level = 4},
["ing_margarine"] = {sell = 9, buy = 3, cat = "Ingrédients", level = 2},
["ing_salt"] = {sell = 9, buy = 3, cat = "Ingrédients", level = 1},
["ing_spices"] = {sell = 12, buy = 6, cat = "Ingrédients", level = 3},
["ing_vegetable_pack"] = {sell = 12, buy = 4, cat = "Ingrédients", level = 3},
["ing_noodles"] = {sell = 9, buy = 3, cat = "Ingrédients", level = 2},
["ing_protein"] = {sell = 10, buy = 3, cat = "Ingrédients", level = 2},
["ing_sweet"] = {sell = 8, buy = 4, cat = "Ingrédients", level = 3},
["drink_milk"] = {sell = 10, buy = 4, cat = "Ingrédients", level = 2},
["fruit_berries"] = {sell = 12, buy = 6, cat = "Ingrédients", level = 1},
["ing_headcrab_meat"] = {sell = 15, buy = 3, cat = "Ingrédients", level = 0},
["ing_antlion_meat"] = {sell = 15, buy = 3, cat = "Ingrédients", level = 0},
["drink_beer"] = {sell = 60, buy = 25, cat = "Alcool", level = 3},
["drink_bourbon"] = {sell = 70, buy = 30, cat = "Alcool", level = 4},
["drink_whiskey"] = {sell = 70, buy = 30, cat = "Alcool", level = 4},
["drink_vodka"] = {sell = 70, buy = 30, cat = "Alcool", level = 4},
--Components
["comp_plastic"] = {sell = 7, buy = 2, cat = "Composants pour crafting", level = 0},
["comp_wood"] = {sell = 8, buy = 3, cat = "Composants pour crafting", level = 0},
["comp_cloth"] = {sell = 8, buy = 3, cat = "Composants pour crafting", level = 0},
["comp_metal"] = {sell = 9, buy = 3, cat = "Composants pour crafting", level = 0},
["comp_glass"] = {sell = 7, buy = 2, cat = "Composants pour crafting", level = 0},
["comp_electronics"] = {sell = 10, buy = 3, cat = "Composants pour crafting", level = 0},
["comp_adhesive"] = {sell = 25, buy = 10, cat = "Composants pour crafting", level = 4},
["comp_alcohol"] = {sell = 35, buy = 18, cat = "Composants pour crafting", level = 7},
["comp_unrefinedchemical"] = {sell = 23, buy = 11, cat = "Composants pour crafting", level = 7},
["comp_craftwork_wood"] = {sell = 51, buy = 26, cat = "Composants pour crafting", level = 9},
["comp_stitched_cloth"] = {sell = 43, buy = 23, cat = "Composants pour crafting", level = 12},
["comp_nails_screws"] = {sell = 26, buy = 12, cat = "Composants pour crafting", level = 6},
["comp_strong_adhesive"] = {sell = 88, buy = 38, cat = "Composants pour crafting", level = 15},
["comp_refinedchemical"] = {sell = 50, buy = 26, cat = "Composants pour crafting", level = 15},
["comp_improved_nails_screws"] = {sell = 113, buy = 44, cat = "Composants pour crafting", level = 15},
["comp_refined_plastic"] = {sell = 42, buy = 16, cat = "Composants pour crafting", level = 15},
["comp_reshaped_metal"] = {sell = 52, buy = 22, cat = "Composants pour crafting", level = 15},
["comp_refined_metal"] = {sell = 260, buy = 115, cat = "Composants pour crafting", level = 20},
["comp_fabric"] = {sell = 200, buy = 81, cat = "Composants pour crafting", level = 20},
["comp_explosive"] = {sell = 220, buy = 95, cat = "Composants pour crafting", level = 20},
--Medical
["comp_purifier"] = {sell = 50, buy = 26, cat = "Composants médicaux", level = 10},
["comp_syringe"] = {sell = 30, buy = 14, cat = "Composants médicaux", level = 5},
["bandage"] = {sell = 44, buy = 12, cat = "Médecine", level = 5, stackSize = 6},
["disinfectant_bottle"] = {sell = 98, buy = 45, cat = "Médecine", level = 5, stackSize = 6},
["painkillers"] = {sell = 90, buy = 33, cat = "Médecine", level = 8, stackSize = 4},
["disinfected_bandage"] = {sell = 112, buy = 58, cat = "Médecine", level = 10, stackSize = 4},
["bloodbag"] = {sell = 440, buy = 320, cat = "Médecine", level = 15, stackSize = 4},
["bloodstabilizer"] = {sell = 237, buy = 97, cat = "Médecine", level = 12, stackSize = 4},
["adrenaline"] = {sell = 90, buy = 33, cat = "Médecine", level = 13, stackSize = 3},
["morphine"] = {sell = 90, buy = 35, cat = "Médecine", level = 16, stackSize = 3},
["firstaid"] = {sell = 480, buy = 200, cat = "Médecine", level = 19, stackSize = 3},
["surgerykit"] = {sell = 778, buy = 300, cat = "Médecine", level = 20, stackSize = 3},
-- Tools
["head_gasmask"] = {sell = 320, buy = 180, cat = "Equipement", level = 20},
["highquality_filter"] = {sell = 550, buy = 200, cat = "Equipement", level = 20},
["face_bandana"] = {sell = 72, buy = 26, cat = "Equipement", level = 4},
["head_military_cap"] = {sell = 80, buy = 38, cat = "Equipement", level = 9},
["smallbag"] = {sell = 160, buy = 85, cat = "Equipement", level = 4},
["largebag"] = {sell = 250, buy = 146, cat = "Equipement", level = 13},
["flashlight"] = {sell = 22, buy = 8, cat = "Equipement", level = 2},
["handheld_radio"] = {sell = 420, buy = 240, cat = "Equipement", level = 20},
["old_radio"] = {sell = 260, buy = 100, cat = "Equipement", level = 11},
["waterbottle"] = {sell = 20, buy = 5, cat = "Outils", level = 0},
["watervalve"] = {sell = 30, buy = 10, cat = "Outils", level = 8},
["tool_wrench"] = {sell = 160, buy = 70, cat = "Outils", level = 12},
["tool_toolkit"] = {sell = 103, buy = 60, cat = "Outils", level = 7},
["tinderbox"] = {sell = 47, buy = 30, cat = "Outils", level = 9},
["lighter"] = {sell = 40, buy = 13, cat = "Outils", level = 0},
["beard_razor"] = {sell = 48, buy = 13, cat = "Outils", level = 4},
["tool_scissors"] = {sell = 18, buy = 5, cat = "Outils", level = 0},
["tool_cookingpot"] = {sell = 45, buy = 20, cat = "Outils", level = 6},
["tool_spoon"] = {sell = 22, buy = 10, cat = "Outils", level = 2},
["tool_knife"] = {sell = 34, buy = 14, cat = "Outils", level = 3},
["tool_fryingpan"] = {sell = 45, buy = 20, cat = "Outils", level = 4},
["tool_mixer"] = {sell = 160, buy = 80, cat = "Outils", 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, "Le nombre dheures entre le passage du contrebandier.", nil, {
data = {min = 0.1, max = 8, decimals = 1},
category = "Contrebandier"
})
ix.config.Add("SmugglerDefaultMoney", 800, "Le montant dargent quun contrebandier génère par défaut.", nil, {
data = {min = 0, max = 2000},
category = "Contrebandier"
})
ix.config.Add("SmugglerPickupDelay", 45, "Nombre de minutes avant que les articles soient disponibles pour le ramassage.", nil, {
data = {min = 1, max = 300},
category = "Contrebandier"
})
ix.config.Add("SmugglingSellExpScale", 1, "Lexpérience de la contrebande déchelle pour vendre des articles en fonction du prix de larticle.", nil, {
data = {min = 0.1, max = 10, decimals = 2},
category = "Contrebandier"
})
ix.config.Add("SmugglingBuyExpScale", 1, "Lexpérience de la contrebande déchelle pour acheter des articles en fonction du prix de larticle.", nil, {
data = {min = 0.1, max = 10, decimals = 2},
category = "Contrebandier"
})
ix.config.Add("SmugglingShowWaypoints", true, "Le joueur devrait-il voir lemplacement exact des cachettes de contrebande?", nil, {
category = "Contrebandier"
})
ix.lang.AddTable("english", {
smugglerNoSellItems = "Il n'y a aucun article à vendre.",
smugglerNoBuyItems = "Il n'y a aucun article à acheter.",
smugglerSettings = "Paramètres de contrebandier",
smugglerUseMoney = "Le contrebandier devrait utiliser de l'argent?",
smugglerBoth = "Acheter et vendre",
smugglerBuy = "Achat uniquement",
smugglerSell = "Vente uniquement",
smugglerWelcome = "Bienvenue chez moi mon gamin, que puis-je t'offrir aujourd'hui ?",
smugglerBye = "Mouais, tu reviendra j'espère!",
smugglerEditor = "Éditeur contrebandier",
smugglerEditCurStock = "Modifier le stock actuel",
smugglerStockReq = "Entrez le montant maximum de l'objet que le contrebandier peut acheter à chaque fois qu'il apparaît.",
smugglerStockCurReq = "Entrez le nombre d'articles disponibles à l'achat actuellement ou la prochaine fois que ce contrebandier apparaîtra.",
smugglerNoTrade = "Ce contrebandier refuse de commercer avec vous!",
smugglerNoTrust = "Ce contrebandier ne vous fait pas encore assez confiance pour échanger cet objet!",
smugglerNoMoney = "Ce contrebandier ne peut pas se permettre cet objet!",
smugglerNoStock = "Ce contrebandier n'a pas cet objet en stock. Commandez-le plutôt pour vous le faire livrez!",
smugglerNoItems = "Ce contrebandier n'a pas envi de vous vendre des objets.",
smugglerMaxStock = "Ce contrebandier ne peut plus transporter plus d'objet de ce genre!",
smugglerSelectPickupItem = "Sélectionnez un élément à récupérer:",
smugglerPickupItem = "Vous avez ramassé un %s.",
smugglerPickupNoSpace = "Vous n'avez pas assez d'espace pour %s !",
smugglerNoPickupItems = "Il n'y a pas d'articles disponibles pour le ramassage ici !",
smugglerSelectDelivery = "Sélectionnez le lieu de livraison",
smugglerDeliverTo = "Acheter et livrer à %s",
smugglerPrepMove = "Ce contrebandier va bientôt partir, il ne fera plus de trocs.",
smugglerAvailableDelivery = "Disponible uniquement sur commande pour livraison",
smugglerAvailable = "Disponible à l'achat : %d",
smugglerStock = "Le contrebandier peut acheter : %d\nVous avez : %d",
smugglerItemsDelivery = "Vos articles seront livrés au point relais dans %d minutes.",
smugglerUniqueIDExists = "Un cache avec cet ID unique existe déjà!",
smugglerStackSize = "Vendu en lots de %d.",
smugglerDeliveryNotify = "Vous avez des objets à récupérer ! Trouvez la cache marquée",
smugglerNeedAtLeast = "Vous avez besoin d'au moins %d de cet article pour vendre."
})
ix.lang.AddTable("french", {
smugglerNoSellItems = "Il n'y a aucun article à vendre.",
smugglerNoBuyItems = "Il n'y a aucun article à acheter.",
smugglerSettings = "Paramètres de contrebandier",
smugglerUseMoney = "Le contrebandier devrait utiliser de l'argent?",
smugglerBoth = "Acheter et vendre",
smugglerBuy = "Achat uniquement",
smugglerSell = "Vente uniquement",
smugglerWelcome = "Bienvenue chez moi mon gamin, que puis-je t'offrir aujourd'hui ?",
smugglerBye = "Mouais, tu reviendra j'espère!",
smugglerEditor = "Éditeur contrebandier",
smugglerEditCurStock = "Modifier le stock actuel",
smugglerStockReq = "Entrez le montant maximum de l'objet que le contrebandier peut acheter à chaque fois qu'il apparaît.",
smugglerStockCurReq = "Entrez le nombre d'articles disponibles à l'achat actuellement ou la prochaine fois que ce contrebandier apparaîtra.",
smugglerNoTrade = "Ce contrebandier refuse de commercer avec vous!",
smugglerNoTrust = "Ce contrebandier ne vous fait pas encore assez confiance pour échanger cet objet!",
smugglerNoMoney = "Ce contrebandier ne peut pas se permettre cet objet!",
smugglerNoStock = "Ce contrebandier n'a pas cet objet en stock. Commandez-le plutôt pour vous le faire livrez!",
smugglerNoItems = "Ce contrebandier n'a pas envi de vous vendre des objets.",
smugglerMaxStock = "Ce contrebandier ne peut plus transporter plus d'objet de ce genre!",
smugglerSelectPickupItem = "Sélectionnez un élément à récupérer:",
smugglerPickupItem = "Vous avez ramassé un %s.",
smugglerPickupNoSpace = "Vous n'avez pas assez d'espace pour %s !",
smugglerNoPickupItems = "Il n'y a pas d'articles disponibles pour le ramassage ici !",
smugglerSelectDelivery = "Sélectionnez le lieu de livraison",
smugglerDeliverTo = "Acheter et livrer à %s",
smugglerPrepMove = "Ce contrebandier va bientôt partir, il ne fera plus de trocs.",
smugglerAvailableDelivery = "Disponible uniquement sur commande pour livraison",
smugglerAvailable = "Disponible à l'achat : %d",
smugglerStock = "Le contrebandier peut acheter : %d\nVous avez : %d",
smugglerItemsDelivery = "Vos articles seront livrés au point relais dans %d minutes.",
smugglerUniqueIDExists = "Un cache avec cet ID unique existe déjà!",
smugglerStackSize = "Vendu en lots de %d.",
smugglerDeliveryNotify = "Vous avez des objets à récupérer ! Trouvez la cache marquée",
smugglerNeedAtLeast = "Vous avez besoin d'au moins %d de cet article pour vendre."
})
ix.lang.AddTable("spanish", {
smugglerNoSellItems = "Il n'y a aucun article à vendre.",
smugglerNoBuyItems = "Il n'y a aucun article à acheter.",
smugglerSettings = "Paramètres de contrebandier",
smugglerUseMoney = "Le contrebandier devrait utiliser de l'argent?",
smugglerBoth = "Acheter et vendre",
smugglerBuy = "Achat uniquement",
smugglerSell = "Vente uniquement",
smugglerWelcome = "Bienvenue chez moi mon gamin, que puis-je t'offrir aujourd'hui ?",
smugglerBye = "Mouais, tu reviendra j'espère!",
smugglerEditor = "Éditeur contrebandier",
smugglerEditCurStock = "Modifier le stock actuel",
smugglerStockReq = "Entrez le montant maximum de l'objet que le contrebandier peut acheter à chaque fois qu'il apparaît.",
smugglerStockCurReq = "Entrez le nombre d'articles disponibles à l'achat actuellement ou la prochaine fois que ce contrebandier apparaîtra.",
smugglerNoTrade = "Ce contrebandier refuse de commercer avec vous!",
smugglerNoTrust = "Ce contrebandier ne vous fait pas encore assez confiance pour échanger cet objet!",
smugglerNoMoney = "Ce contrebandier ne peut pas se permettre cet objet!",
smugglerNoStock = "Ce contrebandier n'a pas cet objet en stock. Commandez-le plutôt pour vous le faire livrez!",
smugglerNoItems = "Ce contrebandier n'a pas envi de vous vendre des objets.",
smugglerMaxStock = "Ce contrebandier ne peut plus transporter plus d'objet de ce genre!",
smugglerSelectPickupItem = "Sélectionnez un élément à récupérer:",
smugglerPickupItem = "Vous avez ramassé un %s.",
smugglerPickupNoSpace = "Vous n'avez pas assez d'espace pour %s !",
smugglerNoPickupItems = "Il n'y a pas d'articles disponibles pour le ramassage ici !",
smugglerSelectDelivery = "Sélectionnez le lieu de livraison",
smugglerDeliverTo = "Acheter et livrer à %s",
smugglerPrepMove = "Ce contrebandier va bientôt partir, il ne fera plus de trocs.",
smugglerAvailableDelivery = "Disponible uniquement sur commande pour livraison",
smugglerAvailable = "Disponible à l'achat : %d",
smugglerStock = "Le contrebandier peut acheter : %d\nVous avez : %d",
smugglerItemsDelivery = "Vos articles seront livrés au point relais dans %d minutes.",
smugglerUniqueIDExists = "Un cache avec cet ID unique existe déjà!",
smugglerStackSize = "Vendu en lots de %d.",
smugglerDeliveryNotify = "Vous avez des objets à récupérer ! Trouvez la cache marquée",
smugglerNeedAtLeast = "Vous avez besoin d'au moins %d de cet article pour vendre."
})
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 = "Fait tourner le contrebandier actuel vers un nouveau.",
superAdminOnly = true,
OnRun = function(self, client)
PLUGIN:RotateActiveSmuggler()
end
})
ix.command.Add("CheckPlayerSmugglerPickupItems", {
description = "Imprime des données sur des objets de contrebandier pour un joueur spécifique.",
adminOnly = true,
arguments = {
ix.type.character,
},
OnRun = function(self, client, character)
client:ChatPrint(character:GetName() .. "'Ramassage des articles:")
for k, v in pairs(character:GetSmugglingPickupItems()) do
for key, val in pairs(v) do
client:ChatPrint(character:GetName() .. ": [" .. key .. "] - avec la quantité de " .. val .. " est stocké dans une caisse avec ID : " .. k)
end
end
client:ChatPrint(character:GetName() .. "'Retard de ramassage:")
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 avant darriver à la cache avec 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("[CONTREBANDIER] Tentative dajouter un élément inconnu '"..uniqueID.."'.")
self.itemList[uniqueID] = nil
continue
end
if (!data.buy and !data.sell) then
ErrorNoHalt("[CONTREBANDIER] Tentative dajouter un article '"..uniqueID.."' sans prix dachat ou de vente.")
self.itemList[uniqueID] = nil
continue
end
ix.action:RegisterSkillAction("smuggling", "recipe_smuggling_"..uniqueID, {
name = item.name,
data = data,
itemID = uniqueID,
bNoLog = true,
description = "Vous permet dacheter et de vendre le '"..item.name.."' article via le réseau de contrebande.",
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 = "Vous permet dacheter et de vendre le '"..item.name.."' article via le réseau de contrebande."
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 = "Modifier le contrebandier",
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 = "Définir un identifiant unique",
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("Entrez un nouvel identifiant unique", "Entrez un nouvel identifiant unique", "", 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 = "Définir l'identifiant de l'emplacement",
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("Saisir le nouvel ID de lieu", "", 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("Entrez le nouveau nom d'affichage", "", 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 = "Définir le modèle",
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("Entrer nouveau modèle", "", 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("Le contrebandier commence à se préparer à déménager, mieux vaut finir tes échanges.")
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 a utilisé le contrebandier '%s'.", client:Name(), arg[1])
end)
ix.log.AddType("smugglerBuy", function(client, item, smuggler, delivery)
return string.format("%s acheté un '%s' au contrebandier '%s'%s.", client:Name(), item, smuggler, delivery and " pour livraison à "..delivery or "")
end)
ix.log.AddType("smugglerSell", function(client, item, smuggler)
return string.format("%s a vendu un '%s' au contrebandier '%s'.", client:Name(), item, smuggler)
end)
ix.log.AddType("smugglerPickup", function(client, item, pickup)
return string.format("%s ramassé un '%s' de '%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)