Initial commit
This commit is contained in:
9
addons/itemstore/lua/autorun/itemstore.lua
Normal file
9
addons/itemstore/lua/autorun/itemstore.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
hook.Add( "PostGamemodeLoaded", "ItemStoreInitialize", function()
|
||||
itemstore = {}
|
||||
|
||||
if SERVER then
|
||||
include( "itemstore/sv_init.lua" )
|
||||
else
|
||||
include( "itemstore/cl_init.lua" )
|
||||
end
|
||||
end )
|
||||
86
addons/itemstore/lua/entities/itemstore_bank.lua
Normal file
86
addons/itemstore/lua/entities/itemstore_bank.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Банк"
|
||||
ENT.Category = "Scora"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel( "models/props_lab/reciever_cart.mdl" )
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
|
||||
self:GetPhysicsObject():EnableMotion( false )
|
||||
end
|
||||
|
||||
function ENT:SpawnFunction( pl, trace, class )
|
||||
local ent = ents.Create( class )
|
||||
ent:SetPos( trace.HitPos + trace.HitNormal * 16 )
|
||||
ent:Spawn()
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:Use( pl )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
pl.Bank:Sync()
|
||||
pl:OpenContainer( pl.Bank:GetID(), itemstore.Translate( "bank" ) )
|
||||
end
|
||||
|
||||
concommand.Add( "itemstore_savebanks", function( pl )
|
||||
if not game.SinglePlayer() and IsValid( pl ) then return end
|
||||
|
||||
local banks = {}
|
||||
|
||||
for _, ent in ipairs( ents.FindByClass( "itemstore_bank" ) ) do
|
||||
table.insert( banks, {
|
||||
Position = ent:GetPos(),
|
||||
Angles = ent:GetAngles()
|
||||
} )
|
||||
end
|
||||
|
||||
file.Write( "itemstore/banks/" .. game.GetMap() .. ".txt", util.TableToJSON( banks ) )
|
||||
|
||||
print( "Banks for map " .. game.GetMap() .. " saved." )
|
||||
end )
|
||||
|
||||
hook.Add( "InitPostEntity", "ItemStoreSpawnBanks", function()
|
||||
local banks = util.JSONToTable( file.Read( "itemstore/banks/" .. game.GetMap() .. ".txt", "DATA" ) or "" ) or {}
|
||||
|
||||
for _, data in ipairs( banks ) do
|
||||
local bank = ents.Create( "itemstore_bank" )
|
||||
bank:SetPos( data.Position )
|
||||
bank:SetAngles( data.Angles )
|
||||
bank:Spawn()
|
||||
end
|
||||
end )
|
||||
else
|
||||
function ENT:DrawTranslucent()
|
||||
self:DrawModel()
|
||||
|
||||
local text = itemstore.Translate( "bank" )
|
||||
local font = "DermaLarge"
|
||||
|
||||
surface.SetFont( font )
|
||||
local textw, texth = surface.GetTextSize( text )
|
||||
local w = 5 + textw + 5
|
||||
local h = 2 + texth + 2
|
||||
local x, y = -w / 2, -h / 2
|
||||
|
||||
cam.Start3D2D( self:GetPos() + self:GetAngles():Up() * 50, Angle( 0, CurTime() * 45, 90 ), 0.35 )
|
||||
surface.SetDrawColor( Color( 0, 0, 0, 200 ) )
|
||||
surface.DrawRect( x, y, w, h )
|
||||
|
||||
draw.SimpleTextOutlined( text, font, 0, 0, Color( 255, 255, 255 ), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color( 0, 0, 0 ) )
|
||||
cam.End3D2D()
|
||||
end
|
||||
end
|
||||
95
addons/itemstore/lua/entities/itemstore_box.lua
Normal file
95
addons/itemstore/lua/entities/itemstore_box.lua
Normal file
@@ -0,0 +1,95 @@
|
||||
ENT.Type = "anim"
|
||||
|
||||
ENT.PrintName = "Маленькая Коробочка"
|
||||
ENT.Category = "Scora"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar( "Entity", 0, "owning_ent" ) -- i feel really stupid.
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Model = "models/props/cs_office/Cardboard_box02.mdl"
|
||||
|
||||
ENT.ContainerWidth = 4
|
||||
ENT.ContainerHeight = 3
|
||||
ENT.ContainerPages = 1
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel( self.Model )
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
|
||||
self:GetPhysicsObject():Wake()
|
||||
|
||||
self.Container = itemstore.Container( self.ContainerWidth, self.ContainerHeight, self.ContainerPages )
|
||||
self.Container:SetOwner( self )
|
||||
|
||||
if self.Items then
|
||||
for _, item in ipairs( self.Items ) do
|
||||
self.Container:AddItem( item:Copy() )
|
||||
end
|
||||
end
|
||||
|
||||
local function callback( con, pl )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
if pl:GetPos():Distance( self:GetPos() ) < 250 then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
self.Container:AddCallback( "read", callback )
|
||||
self.Container:AddCallback( "write", callback )
|
||||
|
||||
self:SetHealth( itemstore.config.BoxHealth )
|
||||
end
|
||||
|
||||
function ENT:SpawnFunction( pl, trace, class )
|
||||
local ent = ents.Create( class )
|
||||
ent:SetPos( trace.HitPos + trace.HitNormal * 16 )
|
||||
ent:Spawn()
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:Use( pl )
|
||||
self.Container:Sync()
|
||||
pl:OpenContainer( self.Container:GetID(), "Box" )
|
||||
end
|
||||
|
||||
function ENT:Break()
|
||||
local effect = EffectData()
|
||||
effect:SetOrigin( self:GetPos() )
|
||||
util.Effect( "Explosion", effect, true, true )
|
||||
|
||||
for _, item in pairs( self.Container.Items ) do
|
||||
item:CreateEntity( self:GetPos() )
|
||||
end
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmg )
|
||||
if not itemstore.config.BoxBreakable then return end
|
||||
|
||||
self:SetHealth( self:Health() - dmg:GetDamage() )
|
||||
|
||||
if self:Health() <= 0 then
|
||||
self:Break()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self.Container:Remove()
|
||||
end
|
||||
end
|
||||
18
addons/itemstore/lua/entities/itemstore_box_huge.lua
Normal file
18
addons/itemstore/lua/entities/itemstore_box_huge.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "itemstore_box"
|
||||
|
||||
ENT.PrintName = "Огромная Коробка"
|
||||
ENT.Category = "Scora"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Model = "models/props_junk/wood_crate001a_damaged.mdl"
|
||||
|
||||
ENT.ContainerWidth = 8
|
||||
ENT.ContainerHeight = 4
|
||||
ENT.ContainerPages = 2
|
||||
end
|
||||
18
addons/itemstore/lua/entities/itemstore_box_large.lua
Normal file
18
addons/itemstore/lua/entities/itemstore_box_large.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "itemstore_box"
|
||||
|
||||
ENT.PrintName = "Большая Коробка"
|
||||
ENT.Category = "Scora"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Model = "models/props/cs_office/cardboard_box01.mdl"
|
||||
|
||||
ENT.ContainerWidth = 5
|
||||
ENT.ContainerHeight = 4
|
||||
ENT.ContainerPages = 1
|
||||
end
|
||||
24
addons/itemstore/lua/entities/itemstore_deathloot.lua
Normal file
24
addons/itemstore/lua/entities/itemstore_deathloot.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "itemstore_box"
|
||||
|
||||
ENT.PrintName = "Смертельная Добыча"
|
||||
ENT.Category = "Scora"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Model = "models/props_junk/garbage_bag001a.mdl"
|
||||
|
||||
ENT.ContainerWidth = 5
|
||||
ENT.ContainerHeight = 5
|
||||
ENT.ContainerPages = 2
|
||||
|
||||
ENT.Timeout = 0
|
||||
|
||||
function ENT:Think()
|
||||
if self.Timeout < CurTime() then self:Remove() end
|
||||
end
|
||||
end
|
||||
106
addons/itemstore/lua/entities/itemstore_item.lua
Normal file
106
addons/itemstore/lua/entities/itemstore_item.lua
Normal file
@@ -0,0 +1,106 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
function ENT:SetItem( item )
|
||||
self.Item = item
|
||||
|
||||
if SERVER then
|
||||
self:Sync()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetItem()
|
||||
return self.Item
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
|
||||
function ENT:Initialize()
|
||||
local item = self:GetItem()
|
||||
if not item then self:Remove() end
|
||||
|
||||
self:SetModel( item:GetModel() )
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
|
||||
self:SetColor( item:GetColor() or color_white )
|
||||
self:SetMaterial( item:GetMaterial() )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if not IsValid( phys ) then
|
||||
self:PhysicsInitSphere( 16, "default" )
|
||||
phys = self:GetPhysicsObject()
|
||||
end
|
||||
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
function ENT:Use( pl )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
local item = self:GetItem()
|
||||
if not item then return end
|
||||
|
||||
if pl.Inventory:AddItem( item ) then
|
||||
pl:EmitSound( "items/itempickup.wav" )
|
||||
self:Remove()
|
||||
else
|
||||
pl:SendError( "Ваш инвентарь полон." )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Sync( pl )
|
||||
local item = self:GetItem()
|
||||
if not item then return end
|
||||
|
||||
net.Start( "ItemStoreSyncItem" )
|
||||
net.WriteEntity( self )
|
||||
net.WriteString( item.Class )
|
||||
net.WriteTable( item.Data )
|
||||
net.Send( pl or player.GetAll() )
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreSyncItem" )
|
||||
net.Receive( "ItemStoreSyncItem", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
|
||||
local ent = net.ReadEntity()
|
||||
if not IsValid( ent ) or ent:GetClass() ~= "itemstore_item" then return end
|
||||
|
||||
ent:Sync( pl )
|
||||
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
end )
|
||||
else
|
||||
function ENT:Initialize()
|
||||
net.Start( "ItemStoreSyncItem" )
|
||||
net.WriteEntity( self )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function ENT:DrawTranslucent()
|
||||
local item = self:GetItem()
|
||||
if not item then return end
|
||||
|
||||
item:PreRender( self )
|
||||
self:DrawModel()
|
||||
item:PostRender( self )
|
||||
end
|
||||
|
||||
net.Receive( "ItemStoreSyncItem", function()
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if not IsValid( ent ) then return end
|
||||
if not ent.SetItem then return end
|
||||
|
||||
local class = net.ReadString()
|
||||
local data = net.ReadTable()
|
||||
|
||||
ent:SetItem( itemstore.Item( class, data ) )
|
||||
end )
|
||||
end
|
||||
1053
addons/itemstore/lua/includes/modules/json.lua
Normal file
1053
addons/itemstore/lua/includes/modules/json.lua
Normal file
File diff suppressed because it is too large
Load Diff
38
addons/itemstore/lua/itemstore/admin.lua
Normal file
38
addons/itemstore/lua/itemstore/admin.lua
Normal file
@@ -0,0 +1,38 @@
|
||||
if SERVER then
|
||||
util.AddNetworkString( "ItemStoreAdminInventory" )
|
||||
net.Receive( "ItemStoreAdminInventory", function( len, admin )
|
||||
if not admin:IsSuperAdmin() then return end
|
||||
|
||||
local pl = net.ReadEntity()
|
||||
|
||||
if not IsValid( pl ) then return end
|
||||
if not pl.Inventory then return end
|
||||
|
||||
pl.Inventory:SetPermissions( admin, true, true )
|
||||
pl.Inventory:Sync( admin )
|
||||
admin:OpenContainer( pl.Inventory:GetID(), itemstore.Translate( "players_inventory", pl:Name() ) )
|
||||
end )
|
||||
|
||||
util.AddNetworkString( "ItemStoreAdminBank" )
|
||||
net.Receive( "ItemStoreAdminBank", function( len, admin )
|
||||
if not admin:IsSuperAdmin() then return end
|
||||
|
||||
local pl = net.ReadEntity()
|
||||
|
||||
if not IsValid( pl ) then return end
|
||||
if not pl.Bank then return end
|
||||
|
||||
pl.Bank:SetPermissions( admin, true, true )
|
||||
pl.Bank:Sync( admin )
|
||||
admin:OpenContainer( pl.Bank:GetID(), itemstore.Translate( "players_bank", pl:Name() ) )
|
||||
end )
|
||||
else
|
||||
concommand.Add( "itemstore_admin", function( pl )
|
||||
if not pl:IsSuperAdmin() then return end
|
||||
|
||||
local panel = vgui.Create( "ItemStoreAdmin" )
|
||||
panel:SetSize( 200, 300 )
|
||||
panel:Center()
|
||||
panel:MakePopup()
|
||||
end )
|
||||
end
|
||||
15
addons/itemstore/lua/itemstore/cl_gui.lua
Normal file
15
addons/itemstore/lua/itemstore/cl_gui.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
include( "skins/" .. itemstore.config.Skin .. ".lua" )
|
||||
|
||||
for _, filename in ipairs( file.Find( "itemstore/vgui/*.lua", "LUA" ) ) do
|
||||
include( "vgui/" .. filename )
|
||||
end
|
||||
|
||||
hook.Add( "ContextMenuCreated", "ItemStoreInventory", function( context )
|
||||
if not IsValid( context ) then return end
|
||||
|
||||
context:Receiver( "ItemStore", function( receiver, droppable, dropped )
|
||||
if not dropped then return end
|
||||
|
||||
LocalPlayer():DropItem( droppable[ 1 ]:GetContainerID(), droppable[ 1 ]:GetSlot() )
|
||||
end )
|
||||
end )
|
||||
4
addons/itemstore/lua/itemstore/cl_init.lua
Normal file
4
addons/itemstore/lua/itemstore/cl_init.lua
Normal file
@@ -0,0 +1,4 @@
|
||||
include( "shared.lua" )
|
||||
|
||||
include( "cl_gui.lua" )
|
||||
include( "cl_player.lua" )
|
||||
136
addons/itemstore/lua/itemstore/cl_player.lua
Normal file
136
addons/itemstore/lua/itemstore/cl_player.lua
Normal file
@@ -0,0 +1,136 @@
|
||||
local meta = FindMetaTable( "Player" )
|
||||
|
||||
function meta:MoveItem( from_con_id, from_slot, to_con_id, to_slot )
|
||||
net.Start( "ItemStoreMove" )
|
||||
net.WriteUInt( from_con_id, 32 )
|
||||
net.WriteUInt( from_slot, 32 )
|
||||
net.WriteUInt( to_con_id, 32 )
|
||||
net.WriteUInt( to_slot, 32 )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function meta:UseItem( con_id, slot, ... )
|
||||
net.Start( "ItemStoreUse" )
|
||||
net.WriteUInt( con_id, 32 )
|
||||
net.WriteUInt( slot, 32 )
|
||||
net.WriteTable( { ... } )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function meta:UseItemWith( from_con_id, from_slot, to_con_id, to_slot )
|
||||
net.Start( "ItemStoreUseWith" )
|
||||
net.WriteUInt( from_con_id, 32 )
|
||||
net.WriteUInt( from_slot, 32 )
|
||||
net.WriteUInt( to_con_id, 32 )
|
||||
net.WriteUInt( to_slot, 32 )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function meta:DropItem( con_id, slot )
|
||||
net.Start( "ItemStoreDrop" )
|
||||
net.WriteUInt( con_id, 32 )
|
||||
net.WriteUInt( slot, 32 )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function meta:DestroyItem( con_id, slot )
|
||||
net.Start( "ItemStoreDestroy" )
|
||||
net.WriteUInt( con_id, 32 )
|
||||
net.WriteUInt( slot, 32 )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function meta:MergeItem( from_con_id, from_slot, to_con_id, to_slot )
|
||||
net.Start( "ItemStoreMerge" )
|
||||
net.WriteUInt( from_con_id, 32 )
|
||||
net.WriteUInt( from_slot, 32 )
|
||||
net.WriteUInt( to_con_id, 32 )
|
||||
net.WriteUInt( to_slot, 32 )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function meta:SplitItem( con_id, slot, amount )
|
||||
net.Start( "ItemStoreSplit" )
|
||||
net.WriteUInt( con_id, 32 )
|
||||
net.WriteUInt( slot, 32 )
|
||||
net.WriteUInt( amount, 16 )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
hook.Add( "InitPostEntity", "ItemStoreRequestInventory", function()
|
||||
net.Start( "ItemStoreSyncInventory" ) net.SendToServer()
|
||||
end )
|
||||
|
||||
local ContextInventory
|
||||
|
||||
net.Receive( "ItemStoreSyncInventory", function()
|
||||
LocalPlayer().InventoryID = net.ReadUInt( 32 )
|
||||
|
||||
if not itemstore.config.ContextInventory then return end
|
||||
|
||||
local inv = vgui.Create( "ItemStoreContainerWindow", g_ContextMenu )
|
||||
inv:SetTitle( itemstore.Translate( "inventory" ) )
|
||||
inv:SetContainerID( LocalPlayer().InventoryID )
|
||||
inv:ShowCloseButton( false )
|
||||
inv:SetDraggable( false )
|
||||
inv:InvalidateLayout( true )
|
||||
|
||||
local side = itemstore.config.ContextInventoryPosition
|
||||
if side == "bottom" then
|
||||
inv:SetPos( ScrW() / 2 - inv:GetWide() / 2, ScrH() - inv:GetTall() )
|
||||
elseif side == "top" then
|
||||
inv:SetPos( ScrW() / 2 - inv:GetWide() / 2, 0 )
|
||||
elseif side == "left" then
|
||||
inv:SetPos( 0, ScrH() / 2 - inv:GetTall() / 2 )
|
||||
elseif side == "right" then
|
||||
inv:SetPos( ScrW() - inv:GetWide(), ScrH() / 2 - inv:GetTall() / 2 )
|
||||
end
|
||||
|
||||
ContextInventory = inv
|
||||
end )
|
||||
|
||||
hook.Add( "Tick", "ItemStoreHideContextInventory", function()
|
||||
if not IsValid( LocalPlayer() ) then return end
|
||||
if not IsValid( ContextInventory ) then return end
|
||||
|
||||
ContextInventory:SetVisible( LocalPlayer():CanUseInventory() )
|
||||
end )
|
||||
|
||||
net.Receive( "ItemStoreOpen", function()
|
||||
local id = net.ReadUInt( 32 )
|
||||
local name = net.ReadString()
|
||||
local hideinv = net.ReadBit() == 1
|
||||
|
||||
local con = itemstore.containers.Get( id )
|
||||
if not con then return end
|
||||
|
||||
local panel = vgui.Create( "ItemStoreContainerWindow" )
|
||||
|
||||
panel:SetContainerID( id )
|
||||
panel:SetTitle( name )
|
||||
panel:Center()
|
||||
|
||||
panel:MakePopup()
|
||||
|
||||
if not hideinv then
|
||||
local inv = vgui.Create( "ItemStoreContainerWindow" )
|
||||
inv:SetContainerID( LocalPlayer().InventoryID )
|
||||
inv:SetTitle( itemstore.Translate( "inventory" ) )
|
||||
inv:ShowCloseButton( false )
|
||||
inv:MakePopup()
|
||||
inv:InvalidateLayout( true )
|
||||
|
||||
local think = inv.Think
|
||||
function inv:Think()
|
||||
think( self )
|
||||
|
||||
local x, y = panel:GetPos()
|
||||
inv:SetPos( panel:GetPos() + ( panel:GetWide() / 2 - inv:GetWide() / 2 ),
|
||||
y + panel:GetTall() + 10 )
|
||||
end
|
||||
|
||||
function panel:OnClose()
|
||||
inv:Close()
|
||||
end
|
||||
end
|
||||
end )
|
||||
176
addons/itemstore/lua/itemstore/config.lua
Normal file
176
addons/itemstore/lua/itemstore/config.lua
Normal file
@@ -0,0 +1,176 @@
|
||||
-- The maximum allowable size for stacked items. Set to math.huge for infinite stacks.
|
||||
-- SOME ITEMS DO NOT OBEY THIS CONFIG OPTION!! Ammo and money are exempt for obvious reasons.
|
||||
itemstore.config.MaxStack = 5
|
||||
|
||||
-- Where to save player data. Values are none, text, mysqloo (recommended) and tmysql4 (deprecated)
|
||||
itemstore.config.DataProvider = "text"
|
||||
|
||||
-- If true, saves the player's inventory every time it's changed.
|
||||
-- DO NOT TURN THIS OFF IF YOU'RE RUNNING THE mysql.experimental DATA PROVIDER!!
|
||||
itemstore.config.SaveOnWrite = true
|
||||
|
||||
-- The gamemode to enable support for. Valid values are darkrp and darkrp24.
|
||||
itemstore.config.GamemodeProvider = "darkrp"
|
||||
|
||||
-- Prefix for chat commands
|
||||
itemstore.config.ChatCommandPrefix = "/"
|
||||
|
||||
-- The jobs that have access to an inventory. If this is empty, all teams have access.
|
||||
-- Admins will still have access to their inventory though.
|
||||
-- Names must be exact.
|
||||
-- example: itemstore.config.LimitToTeams = { TEAM_CITIZEN, TEAM_COP }
|
||||
itemstore.config.LimitToJobs = {}
|
||||
|
||||
-- The interval at which the inventory saves all players automatically, in seconds.
|
||||
itemstore.config.SaveInterval = 180
|
||||
|
||||
-- The language of the inventory.
|
||||
-- There are two languages by default, en (English), fr (French), de (German) and ru (Russian)
|
||||
itemstore.config.Language = "ru"
|
||||
|
||||
-- Enable quick inventory viewing by holding the context menu key, default C.
|
||||
itemstore.config.ContextInventory = true
|
||||
|
||||
-- If context inventory is enabled, this defines where it appears on the player's screen.
|
||||
-- Valid values are "top", "bottom", "left" and "right"
|
||||
itemstore.config.ContextInventoryPosition = "bottom"
|
||||
|
||||
-- Allow the use of the /invholster command
|
||||
itemstore.config.EnableInvholster = false
|
||||
|
||||
-- Force player to holster all of their ammo as well as their gun when they use /invholster, ala DarkRP.
|
||||
itemstore.config.InvholsterTakesAmmo = false
|
||||
|
||||
-- Split ammo on spawned_weapons instead of giving all ammo at once when used
|
||||
itemstore.config.SplitWeaponAmmo = true
|
||||
|
||||
-- Force player to retrieve their items from the bank before being able to use them.
|
||||
itemstore.config.PickupsGotoBank = false
|
||||
|
||||
-- The distance that the player is able to "reach" when picking up items.
|
||||
itemstore.config.PickupDistance = 150
|
||||
|
||||
-- The distance that items will drop at relative to the player
|
||||
itemstore.config.DropDistance = 100
|
||||
|
||||
-- The key to use in combination with +use (E) to pick up items.
|
||||
-- A list of keys for this option is here: http://wiki.garrysmod.com/page/Enums/IN
|
||||
-- Set this to -1 to disable the key combo.
|
||||
itemstore.config.PickupKey = IN_DUCK
|
||||
|
||||
-- Whether or not trading should be enabled. Set this to false to disable.
|
||||
itemstore.config.TradingEnabled = true
|
||||
|
||||
-- How long in seconds the player needs to wait after a trade to trade again
|
||||
itemstore.config.TradeCooldown = 60
|
||||
|
||||
-- How close in hammer units two players need to be to trade. 0 means infinite.
|
||||
itemstore.config.TradeDistance = 0
|
||||
|
||||
-- Whether or not the player should drop their inventory on death.
|
||||
itemstore.config.DeathLoot = false
|
||||
|
||||
-- How long in seconds the player's dropped inventory should exist for.
|
||||
itemstore.config.DeathLootTimeout = 60 * 5
|
||||
|
||||
-- Makes boxes breakable if enough damage is inflicted
|
||||
itemstore.config.BoxBreakable = false
|
||||
|
||||
-- Amount of health for boxes to have
|
||||
itemstore.config.BoxHealth = 100
|
||||
|
||||
-- Should users be able to pick up other users' entities
|
||||
itemstore.config.IgnoreOwner = true
|
||||
|
||||
-- Fixes a duplication bug by detouring ENTITY:Remove()..
|
||||
-- WARNING: Turning this off will open an exploit that allows players to dupe items!
|
||||
-- Only turn it off if it is somehow conflicting.
|
||||
itemstore.config.AntiDupe = true
|
||||
|
||||
-- Migrates text data from 2.0 to the current format.
|
||||
-- This is experimental and may not function correctly. Please be careful if you decide to use this.
|
||||
-- !!IMPORTANT!!
|
||||
-- PLEASE make backups of your data -- this process is DESTRUCTIVE and will delete old data files
|
||||
-- and overwrite any inventory data that players currently have.
|
||||
itemstore.config.MigrateOldData = false
|
||||
|
||||
-- Inventory sizes according to rank.
|
||||
-- The format for this table is:
|
||||
-- <rank> = { <width>, <height>, <pages> }
|
||||
-- If a player's rank is not contained within this table, it defaults to default.
|
||||
-- DO NOT REMOVE DEFAULT! If you remove it, there will be errors!
|
||||
itemstore.config.InventorySizes = {
|
||||
default = { 8, 2, 2 },
|
||||
}
|
||||
|
||||
-- Same as above, for banks. Same format. DON'T REMOVE DEFAULT!
|
||||
itemstore.config.BankSizes = {
|
||||
default = { 8, 2, 2 },
|
||||
}
|
||||
|
||||
-- The skin to use. Preinstalled skins are "flat" and "classic".
|
||||
itemstore.config.Skin = "flat"
|
||||
|
||||
-- The various colours of the VGUI in R, G, B, A 0-255 format.
|
||||
-- Not available when using the flat skin
|
||||
itemstore.config.Colours = {
|
||||
Slot = Color( 29, 26, 31 ),
|
||||
HoveredSlot = Color( 255, 255, 255, 150 ),
|
||||
Title = Color( 255, 255, 255 ),
|
||||
|
||||
TitleBackground = Color( 255, 255, 255 ),
|
||||
Upper = Color( 100, 100, 100, 100 ),
|
||||
Lower = Color( 30, 30, 30, 150 ),
|
||||
InnerBorder = Color( 0, 0, 0, 0 ),
|
||||
OuterBorder = Color( 0, 0, 0, 200 )
|
||||
}
|
||||
|
||||
-- The style of the item highlight. Options are "old", "border", "corner", subtle" and "full"
|
||||
itemstore.config.HighlightStyle = "corner"
|
||||
|
||||
-- Highlight colours for the various types of items.
|
||||
itemstore.config.HighlightColours = {
|
||||
Weapons = Color( 231, 76, 60 ),
|
||||
Ammo = Color( 241, 196, 15 ),
|
||||
Shipments = Color( 230, 126, 34 ),
|
||||
Factories = Color( 52, 152, 219 ), -- printers, gunlabs, microwaves, etc
|
||||
Consumables = Color( 26, 188, 156 ), -- drugs, food
|
||||
Money = Color( 46, 204, 113 ),
|
||||
Other = Color( 236, 240, 241 ), -- never delete this!
|
||||
}
|
||||
|
||||
-- A table of disabled items. Set any value in this table to true to disallow picking up the item.
|
||||
itemstore.config.DisabledItems = {
|
||||
drug = false,
|
||||
drug_lab = false,
|
||||
food = false,
|
||||
gunlab = false,
|
||||
microwave = false,
|
||||
money_printer = true,
|
||||
spawned_food = false,
|
||||
spawned_shipment = false,
|
||||
spawned_weapon = false,
|
||||
spawned_money = true,
|
||||
|
||||
durgz_alcohol = false,
|
||||
durgz_aspirin = false,
|
||||
durgz_cigarette = false,
|
||||
durgz_cocaine = false,
|
||||
durgz_heroine = false,
|
||||
durgz_lsd = false,
|
||||
durgz_mushroom = false,
|
||||
durgz_pcp = false,
|
||||
durgz_weed = false,
|
||||
|
||||
|
||||
prop_physics = true,
|
||||
}
|
||||
|
||||
-- Custom items. Defining these will allow server owners to make certain
|
||||
-- entities pickupable... but may not work 100%. If this is the case, you will probably
|
||||
-- need to code the item definition yourself.
|
||||
-- Format for each entry is:
|
||||
-- <entity class> = { "<name>", "<description>", <stackable (optional)> }
|
||||
itemstore.config.CustomItems = {
|
||||
sent_ball = { "Bouncy Ball", "A bouncy ball!", true },
|
||||
}
|
||||
392
addons/itemstore/lua/itemstore/containers.lua
Normal file
392
addons/itemstore/lua/itemstore/containers.lua
Normal file
@@ -0,0 +1,392 @@
|
||||
itemstore.containers = {}
|
||||
itemstore.containers.Active = {}
|
||||
|
||||
local Container = {}
|
||||
|
||||
AccessorFunc( Container, "Owner", "Owner" )
|
||||
AccessorFunc( Container, "Suppressed", "Suppressed", FORCE_BOOL )
|
||||
AccessorFunc( Container, "Width", "Width", FORCE_NUMBER )
|
||||
AccessorFunc( Container, "Height", "Height", FORCE_NUMBER )
|
||||
AccessorFunc( Container, "Pages", "Pages", FORCE_NUMBER )
|
||||
|
||||
function Container:GetID()
|
||||
return self.ID
|
||||
end
|
||||
|
||||
function Container:IsValid()
|
||||
return self:GetID() and itemstore.containers.Active[ self:GetID() ] == self
|
||||
end
|
||||
|
||||
function Container:Remove()
|
||||
itemstore.containers.Remove( self:GetID() )
|
||||
end
|
||||
|
||||
function Container:GetPageSize()
|
||||
return self:GetWidth() * self:GetHeight()
|
||||
end
|
||||
|
||||
function Container:GetPageFromSlot( slot )
|
||||
return math.ceil( slot / self:GetPageSize() )
|
||||
end
|
||||
|
||||
function Container:GetSize()
|
||||
return self:GetPageSize() * self:GetPages()
|
||||
end
|
||||
|
||||
function Container:CoordsToSlot( x, y, p )
|
||||
return ( ( p - 1 ) * self:GetPageSize() ) + ( ( y - 1 ) * self:GetWidth() + x )
|
||||
end
|
||||
|
||||
function Container:GetItems()
|
||||
return self.Items
|
||||
end
|
||||
|
||||
function Container:GetItem( slot )
|
||||
return self.Items[ slot ]
|
||||
end
|
||||
|
||||
function Container:SetItem( slot, item )
|
||||
if item and not item:IsValid() then return end
|
||||
|
||||
slot = math.floor( slot )
|
||||
|
||||
if slot >= 1 and slot <= self:GetSize() then
|
||||
if self:RunCallbacks( "set", slot, item ) == false then return end
|
||||
|
||||
self.Items[ slot ] = item
|
||||
|
||||
if item then
|
||||
item.Container = self
|
||||
item.Slot = slot
|
||||
end
|
||||
|
||||
if SERVER then self:QueueSync() end
|
||||
end
|
||||
end
|
||||
|
||||
function Container:FirstEmptySlot()
|
||||
for i = 1, self:GetSize() do
|
||||
if not self:GetItem( i ) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function Container:CanFit( item )
|
||||
for i = 1, self:GetSize() do
|
||||
local merge_item = self:GetItem( i )
|
||||
|
||||
if merge_item and merge_item:CanMerge( item ) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return self:FirstEmptySlot() ~= false
|
||||
end
|
||||
|
||||
function Container:AddItem( item, dontmerge )
|
||||
if not dontmerge then
|
||||
for i = 1, self:GetSize() do
|
||||
local merge_item = self:GetItem( i )
|
||||
|
||||
if merge_item and merge_item:CanMerge( item ) then
|
||||
merge_item:Merge( item )
|
||||
self:QueueSync()
|
||||
|
||||
return i, merge_item
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local slot = self:FirstEmptySlot()
|
||||
|
||||
if slot then
|
||||
self:SetItem( slot, item )
|
||||
return slot
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function Container:HasItem( item_class )
|
||||
for k, v in pairs( self:GetItems() ) do
|
||||
if v:GetClass() == item_class then
|
||||
return k
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function Container:CountItems( item_class )
|
||||
local amount = 0
|
||||
|
||||
for _, item in pairs( self:GetItems() ) do
|
||||
if item:GetClass() == item_class then
|
||||
amount = amount + item:GetAmount()
|
||||
end
|
||||
end
|
||||
|
||||
return amount
|
||||
end
|
||||
|
||||
-- 76561198068291318
|
||||
|
||||
function Container:TakeItems( item_class, amount )
|
||||
local amount_taken = 0
|
||||
|
||||
self:Suppress( function()
|
||||
for k, v in pairs( self:GetItems() ) do
|
||||
if v:GetClass() == item_class then
|
||||
local amount_to_take = v:GetAmount()
|
||||
amount_to_take = math.Clamp( amount_to_take, 0, amount )
|
||||
|
||||
v:SetAmount( v:GetAmount() - amount_to_take )
|
||||
|
||||
if v:GetAmount() <= 0 then
|
||||
self:SetItem( k, nil )
|
||||
end
|
||||
|
||||
amount_taken = amount_taken + amount_to_take
|
||||
amount = amount - amount_to_take
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end )
|
||||
|
||||
return amount_taken
|
||||
end
|
||||
|
||||
function Container:GetDefaultPermissions()
|
||||
return self.DefaultPermissions
|
||||
end
|
||||
|
||||
function Container:GetPermissions( pl )
|
||||
return self.Permissions[ pl ] or self:GetDefaultPermissions()
|
||||
end
|
||||
|
||||
function Container:SetDefaultPermissions( read, write )
|
||||
self.DefaultPermissions = { Read = read, Write = write }
|
||||
end
|
||||
|
||||
function Container:SetPermissions( pl, read, write )
|
||||
self.Permissions[ pl ] = { Read = read, Write = write }
|
||||
end
|
||||
|
||||
function Container:CanRead( pl, ... )
|
||||
local res = hook.Call( "ItemStoreCanRead", nil, self, pl, ... )
|
||||
if res ~= nil then
|
||||
return res
|
||||
end
|
||||
|
||||
if self.Permissions[ pl ] then
|
||||
return self.Permissions[ pl ].Read
|
||||
end
|
||||
|
||||
local res = self:RunCallbacks( "read", pl, ... )
|
||||
if res ~= nil then
|
||||
return res
|
||||
end
|
||||
|
||||
return self.DefaultPermissions.Read
|
||||
end
|
||||
|
||||
function Container:CanWrite( pl, action, ... )
|
||||
local res = hook.Call( "ItemStoreCanWrite", nil, self, pl, action, ... )
|
||||
if res ~= nil then
|
||||
return res
|
||||
end
|
||||
|
||||
if self.Permissions[ pl ] then
|
||||
return self.Permissions[ pl ].Write
|
||||
end
|
||||
|
||||
local res = self:RunCallbacks( "write", pl, action, ... )
|
||||
if res ~= nil then
|
||||
return res
|
||||
end
|
||||
|
||||
return self.DefaultPermissions.Write
|
||||
end
|
||||
|
||||
function Container:AddCallback( name, func )
|
||||
if not self.Callbacks[ name ] then
|
||||
self.Callbacks[ name ] = {}
|
||||
end
|
||||
|
||||
return table.insert( self.Callbacks[ name ], func )
|
||||
end
|
||||
|
||||
function Container:RemoveCallback( name, id )
|
||||
if self.Callbacks[ name ] then
|
||||
self.Callbacks[ name ][ id ] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function Container:RunCallbacks( name, ... )
|
||||
if self.Callbacks[ name ] then
|
||||
for _, func in pairs( self.Callbacks[ name ] ) do
|
||||
local res = func( self, ... )
|
||||
|
||||
if res ~= nil then
|
||||
return res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Container:GetSyncTargets()
|
||||
players = {}
|
||||
|
||||
for _, pl in ipairs( player.GetAll() ) do
|
||||
if self:CanRead( pl ) then
|
||||
table.insert( players, pl )
|
||||
end
|
||||
end
|
||||
|
||||
return players
|
||||
end
|
||||
|
||||
function Container:Suppress( func )
|
||||
self:SetSuppressed( true )
|
||||
local sync = func()
|
||||
self:SetSuppressed( false )
|
||||
|
||||
if sync then self:QueueSync() end
|
||||
end
|
||||
|
||||
function Container:QueueSync()
|
||||
self.ShouldSync = true
|
||||
end
|
||||
|
||||
function Container:Sync( pl )
|
||||
if SERVER then itemstore.containers.Sync( self:GetID(), pl ) end
|
||||
end
|
||||
|
||||
function itemstore.Container( w, h, pages, dontnetwork )
|
||||
local con = {
|
||||
ShouldSync = false,
|
||||
|
||||
Width = w or 4,
|
||||
Height = h or 4,
|
||||
Pages = pages or 1,
|
||||
|
||||
Owner = nil,
|
||||
Callbacks = {},
|
||||
Permissions = {},
|
||||
DefaultPermissions = { Read = false, Write = false },
|
||||
|
||||
Items = {}
|
||||
}
|
||||
|
||||
setmetatable( con, { __index = Container } )
|
||||
|
||||
if not dontnetwork then
|
||||
con.ID = table.insert( itemstore.containers.Active, con )
|
||||
con:Sync()
|
||||
end
|
||||
|
||||
return con
|
||||
end
|
||||
|
||||
function itemstore.containers.Get( id )
|
||||
return itemstore.containers.Active[ id ]
|
||||
end
|
||||
|
||||
function itemstore.containers.Remove( id )
|
||||
itemstore.containers.Active[ id ] = nil
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
|
||||
util.AddNetworkString( "ItemStoreSync" )
|
||||
function itemstore.containers.Sync( id, pl )
|
||||
local con = itemstore.containers.Active[ id ]
|
||||
|
||||
if not con then return end
|
||||
if con:GetSuppressed() then return end
|
||||
|
||||
-- No longer using WriteTable! Net usage has been cut to less than half
|
||||
-- This is still pretty damn unoptimized though
|
||||
-- Ideally we send only the item that's changing...
|
||||
-- But unfortunately it's a bit more complicated than that due to
|
||||
-- an item's ability to modify other slots in a container
|
||||
net.Start( "ItemStoreSync" )
|
||||
net.WriteUInt( con:GetID(), 32 )
|
||||
|
||||
net.WriteUInt( con:GetWidth(), 8 )
|
||||
net.WriteUInt( con:GetHeight(), 8 )
|
||||
net.WriteUInt( con:GetPages(), 8 )
|
||||
|
||||
net.WriteUInt( table.Count( con.Items ), 8 )
|
||||
|
||||
for k, v in pairs( con.Items ) do
|
||||
net.WriteUInt( k, 8 )
|
||||
|
||||
local id = util.NetworkStringToID( v.Class )
|
||||
|
||||
if id == 0 then
|
||||
if v.Class then
|
||||
error( string.format( "[ItemStore] Tried to send data for unnetworked item %s", v.Class ) )
|
||||
else
|
||||
error( "[ItemStore] Tried to send data for a classless item" )
|
||||
end
|
||||
end
|
||||
|
||||
net.WriteUInt( id, 16 )
|
||||
v:WriteNetworkData()
|
||||
end
|
||||
net.Send( pl or con:GetSyncTargets() )
|
||||
end
|
||||
|
||||
hook.Add( "Tick", "ItemStoreSyncContainers", function()
|
||||
for k, v in pairs( itemstore.containers.Active ) do
|
||||
if v.ShouldSync then
|
||||
v.ShouldSync = false
|
||||
v:Sync()
|
||||
end
|
||||
end
|
||||
end )
|
||||
else
|
||||
itemstore.containers.Panels = {}
|
||||
|
||||
function itemstore.containers.UpdatePanels( id )
|
||||
for k, v in pairs( itemstore.containers.Panels ) do
|
||||
if IsValid( v ) then
|
||||
if v:GetContainerID() == id then
|
||||
v:Refresh()
|
||||
end
|
||||
else
|
||||
itemstore.containers.Panels[ k ] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
net.Receive( "ItemStoreSync", function()
|
||||
local id = net.ReadUInt( 32 )
|
||||
local w, h = net.ReadUInt( 8 ), net.ReadUInt( 8 )
|
||||
local pages = net.ReadUInt( 8 )
|
||||
|
||||
local con = itemstore.Container( w, h, pages, true )
|
||||
|
||||
for i = 1, net.ReadUInt( 8 ) do
|
||||
local slot = net.ReadUInt( 8 )
|
||||
|
||||
local class = util.NetworkIDToString( net.ReadUInt( 16 ) )
|
||||
local item = itemstore.Item( class )
|
||||
|
||||
item:ReadNetworkData()
|
||||
|
||||
con:SetItem( slot, item )
|
||||
end
|
||||
|
||||
con.ID = id
|
||||
itemstore.containers.Active[ id ] = con
|
||||
|
||||
itemstore.containers.UpdatePanels( id )
|
||||
end )
|
||||
end
|
||||
431
addons/itemstore/lua/itemstore/dataproviders/mysqloo.lua
Normal file
431
addons/itemstore/lua/itemstore/dataproviders/mysqloo.lua
Normal file
@@ -0,0 +1,431 @@
|
||||
local PROVIDER = PROVIDER
|
||||
|
||||
-- Edit this with your authentication details
|
||||
local auth = {
|
||||
Host = "localhost",
|
||||
Port = 3306,
|
||||
Username = "root",
|
||||
Password = "",
|
||||
Database = "itemstore"
|
||||
}
|
||||
|
||||
local INVENTORY_DB = "Inventories"
|
||||
local BANK_DB = "Banks"
|
||||
local DEBUG = false
|
||||
|
||||
function PROVIDER:Log( text )
|
||||
print( "[ItemStore MySQL] " .. text )
|
||||
file.Append( "itemstore/mysql.txt", os.date( "[%c]" ) .. " " .. text .. "\r\n" )
|
||||
end
|
||||
|
||||
function PROVIDER:CreateTable( name, columns, primary )
|
||||
self:Log( "Creating tables.." )
|
||||
|
||||
local sql = "CREATE TABLE IF NOT EXISTS `" .. name .. "`("
|
||||
|
||||
for k, v in ipairs( columns ) do
|
||||
sql = sql .. v
|
||||
|
||||
if k ~= #columns then
|
||||
sql = sql .. ", "
|
||||
end
|
||||
end
|
||||
|
||||
if primary then
|
||||
sql = sql .. ", PRIMARY KEY ( " .. primary .. " )"
|
||||
end
|
||||
|
||||
sql = sql .. " )"
|
||||
|
||||
return self:Query( sql )
|
||||
end
|
||||
|
||||
function PROVIDER:OnConnected( db )
|
||||
self.Database = db
|
||||
|
||||
self:Log( "Connection succesful!" )
|
||||
|
||||
local columns = {
|
||||
"`SteamID` VARCHAR( 32 ) NOT NULL",
|
||||
"`Slot` INT NOT NULL",
|
||||
"`Class` VARCHAR( 255 ) NULL",
|
||||
"`Data` BLOB NULL",
|
||||
}
|
||||
|
||||
local primary = "`SteamID`, `Slot`"
|
||||
|
||||
self:CreateTable( INVENTORY_DB, columns, primary )
|
||||
self:CreateTable( BANK_DB, columns, primary )
|
||||
|
||||
self:RunQueue()
|
||||
-- I know I shouldn't store Data as a plain JSON string but I'm concerned about performance here.
|
||||
--self:Query( "CREATE TABLE IF NOT EXISTS Inventories( SteamID VARCHAR( 32 ) NOT NULL, Slot INT NOT NULL, Class VARCHAR( 255 ) NULL, Data BLOB NULL, PRIMARY KEY ( SteamID, Slot ) )" )
|
||||
--self:Query( "CREATE TABLE IF NOT EXISTS Banks( SteamID VARCHAR( 32 ) NOT NULL, Slot INT NOT NULL, Class VARCHAR( 255 ) NULL, Data BLOB NULL, PRIMARY KEY ( SteamID, Slot ) )" )
|
||||
end
|
||||
|
||||
function PROVIDER:OnError( err )
|
||||
self:Log( "Connection failed: " .. err )
|
||||
self:Log( "Retrying in 30 seconds: " .. err )
|
||||
|
||||
timer.Simple( 30, function()
|
||||
self:Initialize()
|
||||
end )
|
||||
end
|
||||
|
||||
function PROVIDER:Initialize()
|
||||
require( "mysqloo" )
|
||||
assert( mysqloo, "[ItemStore] MySQLoo is not installed" )
|
||||
|
||||
self:Log( "Connecting to database..." )
|
||||
|
||||
local db = mysqloo.connect( auth.Host, auth.Username, auth.Password, auth.Database, auth.Port )
|
||||
|
||||
db.onConnected = function( db )
|
||||
self:OnConnected( db )
|
||||
end
|
||||
|
||||
db.onConnectionFailed = function( db, err )
|
||||
self:OnError( err )
|
||||
end
|
||||
|
||||
db:connect()
|
||||
end
|
||||
|
||||
function PROVIDER:Escape( str )
|
||||
return self.Database:escape( str )
|
||||
end
|
||||
|
||||
PROVIDER.QueuedQueries = {}
|
||||
|
||||
function PROVIDER:RunQueue()
|
||||
if not self.Database then return end
|
||||
|
||||
for k, v in ipairs( self.QueuedQueries ) do
|
||||
self:Query( unpack( v ) )
|
||||
end
|
||||
|
||||
self.QueuedQueries = {}
|
||||
end
|
||||
|
||||
function PROVIDER:Query( sql, params, success, fail )
|
||||
if not success then
|
||||
local success = function() end
|
||||
end
|
||||
|
||||
if not fail then
|
||||
local fail = function( q, err )
|
||||
self:Log( "Query failed: " .. err )
|
||||
end
|
||||
end
|
||||
|
||||
if not self.Database then
|
||||
if DEBUG then
|
||||
self:Log( "Database not connected yet, queueing query: " .. sql )
|
||||
end
|
||||
|
||||
-- wait for connection if we don't have a db yet
|
||||
-- mysqloo docs say this should work anyways but :escape() will fail if not connected
|
||||
table.insert( self.QueuedQueries, { sql, params, success, fail } )
|
||||
return
|
||||
end
|
||||
|
||||
if params then
|
||||
for k, v in pairs( params ) do
|
||||
if type( v ) ~= "number" then
|
||||
v = self:Escape( v )
|
||||
v = "\"" .. v .. "\""
|
||||
end
|
||||
|
||||
sql = string.gsub( sql, ":" .. k, v )
|
||||
end
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
self:Log( "Starting query: " .. sql )
|
||||
end
|
||||
|
||||
local q = self.Database:query( sql )
|
||||
|
||||
q.onSuccess = success
|
||||
q.onError = fail
|
||||
|
||||
q:start()
|
||||
end
|
||||
|
||||
function PROVIDER:LoadInventory( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
local sql = "SELECT * FROM `" .. INVENTORY_DB .. "`"
|
||||
sql = sql .. " WHERE `SteamID` = :1"
|
||||
|
||||
local params = { steamid }
|
||||
|
||||
self:Query( sql, params, function( q, data )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
for _, v in ipairs( data ) do
|
||||
local slot = v.Slot
|
||||
|
||||
if v.Class then
|
||||
local class = v.Class
|
||||
local data = util.JSONToTable( v.Data )
|
||||
|
||||
pl.Inventory:SetItem( slot, itemstore.Item( class, data ) )
|
||||
end
|
||||
end
|
||||
|
||||
pl.InventoryLoaded = true
|
||||
end )
|
||||
end
|
||||
|
||||
function PROVIDER:SaveInventory( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
local sql = "REPLACE INTO `" .. INVENTORY_DB .. "`"
|
||||
sql = sql .. "( `SteamID`, `Slot`, `Class`, `Data` )"
|
||||
sql = sql .. " VALUES"
|
||||
|
||||
local params = {}
|
||||
params[ "steamid" ] = steamid
|
||||
|
||||
for slot = 1, pl.Inventory:GetSize() do
|
||||
local item = pl.Inventory:GetItem( slot )
|
||||
|
||||
sql = sql .. "( "
|
||||
sql = sql .. " :steamid,"
|
||||
sql = sql .. " " .. slot .. "," -- no need to escape here since it's a number
|
||||
|
||||
if item then
|
||||
sql = sql .. " :item_" .. slot .. "_class,"
|
||||
sql = sql .. " :item_" .. slot .. "_data"
|
||||
|
||||
params[ "item_" .. slot .. "_class" ] = item:GetClass()
|
||||
params[ "item_" .. slot .. "_data" ] = util.TableToJSON( item.Data )
|
||||
else
|
||||
sql = sql .. " NULL,"
|
||||
sql = sql .. " NULL"
|
||||
end
|
||||
|
||||
sql = sql .. " )"
|
||||
|
||||
if slot ~= pl.Inventory:GetSize() then
|
||||
sql = sql .. ","
|
||||
end
|
||||
end
|
||||
|
||||
self:Query( sql, params )
|
||||
end
|
||||
|
||||
function PROVIDER:LoadBank( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
local sql = "SELECT * FROM `" .. BANK_DB .. "`"
|
||||
sql = sql .. " WHERE `SteamID` = :1"
|
||||
|
||||
local params = { steamid }
|
||||
|
||||
self:Query( sql, params, function( q, data )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
for _, v in ipairs( data ) do
|
||||
local slot = v.Slot
|
||||
|
||||
if v.Class then
|
||||
local class = v.Class
|
||||
local data = util.JSONToTable( v.Data )
|
||||
|
||||
pl.Bank:SetItem( slot, itemstore.Item( class, data ) )
|
||||
end
|
||||
end
|
||||
|
||||
pl.BankLoaded = true
|
||||
end )
|
||||
end
|
||||
|
||||
function PROVIDER:SaveBank( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
local params = {}
|
||||
params[ "steamid" ] = steamid
|
||||
|
||||
local sql = "REPLACE INTO `" .. BANK_DB .. "`"
|
||||
sql = sql .. "( `SteamID`, `Slot`, `Class`, `Data` )"
|
||||
sql = sql .. " VALUES"
|
||||
|
||||
for slot = 1, pl.Bank:GetSize() do
|
||||
local item = pl.Bank:GetItem( slot )
|
||||
|
||||
sql = sql .. "( "
|
||||
sql = sql .. " :steamid,"
|
||||
sql = sql .. " " .. slot .. "," -- no need to escape here since it's a number
|
||||
|
||||
if item then
|
||||
sql = sql .. " :item_" .. slot .. "_class,"
|
||||
sql = sql .. " :item_" .. slot .. "_data"
|
||||
|
||||
params[ "item_" .. slot .. "_class" ] = item:GetClass()
|
||||
params[ "item_" .. slot .. "_data" ] = util.TableToJSON( item.Data )
|
||||
else
|
||||
sql = sql .. " NULL,"
|
||||
sql = sql .. " NULL"
|
||||
end
|
||||
|
||||
sql = sql .. " )"
|
||||
|
||||
if slot ~= pl.Bank:GetSize() then
|
||||
sql = sql .. ","
|
||||
end
|
||||
end
|
||||
|
||||
self:Query( sql, params )
|
||||
end
|
||||
|
||||
function PROVIDER:Import( data )
|
||||
for k, v in pairs( data ) do
|
||||
self:Query( "DELETE FROM `" .. INVENTORY_DB .. "` WHERE SteamID = :1", { k } )
|
||||
self:Query( "DELETE FROM `" .. BANK_DB .. "` WHERE SteamID = :1", { k } )
|
||||
|
||||
if v.Inventory and table.Count( v.Inventory ) > 0 then
|
||||
local sql = "REPLACE INTO `" .. INVENTORY_DB .. "`"
|
||||
sql = sql .. "( `SteamID`, `Slot`, `Class`, `Data` )"
|
||||
sql = sql .. " VALUES"
|
||||
|
||||
local params = {}
|
||||
params[ "steamid" ] = k
|
||||
|
||||
for slot, item in pairs( v.Inventory ) do
|
||||
sql = sql .. "( "
|
||||
sql = sql .. " :steamid,"
|
||||
sql = sql .. " " .. tonumber( slot ) .. ","
|
||||
|
||||
if item then
|
||||
sql = sql .. " :item_" .. slot .. "_class,"
|
||||
sql = sql .. " :item_" .. slot .. "_data"
|
||||
|
||||
params[ "item_" .. slot .. "_class" ] = item.Class
|
||||
params[ "item_" .. slot .. "_data" ] = util.TableToJSON( item.Data )
|
||||
else
|
||||
sql = sql .. " NULL,"
|
||||
sql = sql .. " NULL"
|
||||
end
|
||||
|
||||
sql = sql .. " ),"
|
||||
end
|
||||
|
||||
sql = string.TrimRight( sql, "," )
|
||||
|
||||
self:Query( sql, params )
|
||||
|
||||
--for slot, item in pairs( v.Inventory ) do
|
||||
-- if item then
|
||||
-- self:Query( "REPLACE INTO Inventories( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
-- else
|
||||
-- self:Query( "REPLACE INTO Inventories( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
-- end
|
||||
--end
|
||||
end
|
||||
|
||||
if v.Bank and table.Count( v.Bank ) > 0 then
|
||||
local sql = "REPLACE INTO `" .. BANK_DB .. "`"
|
||||
sql = sql .. "( `SteamID`, `Slot`, `Class`, `Data` )"
|
||||
sql = sql .. " VALUES"
|
||||
|
||||
local params = {}
|
||||
params[ "steamid" ] = k
|
||||
|
||||
for slot, item in pairs( v.Bank ) do
|
||||
sql = sql .. "( "
|
||||
sql = sql .. " :steamid,"
|
||||
sql = sql .. " " .. tonumber( slot ) .. ","
|
||||
|
||||
if item then
|
||||
sql = sql .. " :item_" .. slot .. "_class,"
|
||||
sql = sql .. " :item_" .. slot .. "_data"
|
||||
|
||||
params[ "item_" .. slot .. "_class" ] = item.Class
|
||||
params[ "item_" .. slot .. "_data" ] = util.TableToJSON( item.Data )
|
||||
else
|
||||
sql = sql .. " NULL,"
|
||||
sql = sql .. " NULL"
|
||||
end
|
||||
|
||||
sql = sql .. " ),"
|
||||
end
|
||||
|
||||
sql = string.TrimRight( sql, "," )
|
||||
|
||||
self:Query( sql, params )
|
||||
|
||||
--if v.Bank then
|
||||
-- for slot, item in pairs( v.Bank ) do
|
||||
-- if item then
|
||||
-- self:Query( "REPLACE INTO Banks( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
-- else
|
||||
-- self:Query( "REPLACE INTO Banks( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
-- end
|
||||
-- end
|
||||
--end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PROVIDER:Export( filename )
|
||||
local export = {}
|
||||
|
||||
local inventory_loaded = false
|
||||
local bank_loaded = false
|
||||
|
||||
local function FinishExport( export )
|
||||
file.Write( filename, util.TableToJSON( export ) )
|
||||
end
|
||||
|
||||
local sql = "SELECT * FROM `" .. INVENTORY_DB .. "`"
|
||||
|
||||
self:Query( sql, nil, function( q, data )
|
||||
for _, row in ipairs( data ) do
|
||||
if not ( export[ row.SteamID ] ) then
|
||||
export[ row.SteamID ] = {}
|
||||
end
|
||||
|
||||
if not ( export[ row.SteamID ].Inventory ) then
|
||||
export[ row.SteamID ].Inventory = {}
|
||||
end
|
||||
|
||||
if row.Class then
|
||||
export[ row.SteamID ].Inventory[ row.Slot ] = { Class = row.Class, Data = util.JSONToTable( row.Data ) }
|
||||
end
|
||||
end
|
||||
|
||||
inventory_loaded = true
|
||||
|
||||
if inventory_loaded and bank_loaded then
|
||||
FinishExport( export )
|
||||
end
|
||||
end )
|
||||
|
||||
local sql = "SELECT * FROM `" .. BANK_DB .. "`"
|
||||
|
||||
self:Query( sql, nil, function( q, data )
|
||||
for _, row in ipairs( data ) do
|
||||
if not ( export[ row.SteamID ] ) then
|
||||
export[ row.SteamID ] = {}
|
||||
end
|
||||
|
||||
if not ( export[ row.SteamID ].Bank ) then
|
||||
export[ row.SteamID ].Bank = {}
|
||||
end
|
||||
|
||||
if row.Class then
|
||||
export[ row.SteamID ].Bank[ row.Slot ] = { Class = row.Class, Data = util.JSONToTable( row.Data ) }
|
||||
end
|
||||
end
|
||||
|
||||
bank_loaded = true
|
||||
|
||||
if inventory_loaded and bank_loaded then
|
||||
FinishExport( export )
|
||||
end
|
||||
end )
|
||||
end
|
||||
17
addons/itemstore/lua/itemstore/dataproviders/none.lua
Normal file
17
addons/itemstore/lua/itemstore/dataproviders/none.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
function PROVIDER:LoadInventory( pl )
|
||||
end
|
||||
|
||||
function PROVIDER:SaveInventory( pl )
|
||||
end
|
||||
|
||||
function PROVIDER:LoadBank( pl )
|
||||
end
|
||||
|
||||
function PROVIDER:SaveBank( pl )
|
||||
end
|
||||
|
||||
function PROVIDER:Import( data )
|
||||
end
|
||||
|
||||
function PROVIDER:Export( filename )
|
||||
end
|
||||
90
addons/itemstore/lua/itemstore/dataproviders/text.lua
Normal file
90
addons/itemstore/lua/itemstore/dataproviders/text.lua
Normal file
@@ -0,0 +1,90 @@
|
||||
function PROVIDER:LoadInventory( pl )
|
||||
local json = file.Read( "itemstore/" .. ( pl:SteamID64() or "0" ) .. ".txt", "DATA" )
|
||||
|
||||
if json then
|
||||
local inv = util.JSONToTable( json )
|
||||
|
||||
if inv then
|
||||
for k, v in pairs( inv ) do
|
||||
pl.Inventory:SetItem( k, itemstore.Item( v.Class, v.Data ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pl.InventoryLoaded = true
|
||||
end
|
||||
|
||||
function PROVIDER:SaveInventory( pl )
|
||||
local inv = {}
|
||||
|
||||
for k, v in pairs( pl.Inventory:GetItems() ) do
|
||||
inv[ k ] = { Class = v.Class, Data = v.Data }
|
||||
end
|
||||
|
||||
file.Write( "itemstore/" .. ( pl:SteamID64() or "0" ) .. ".txt", util.TableToJSON( inv ) )
|
||||
end
|
||||
|
||||
function PROVIDER:LoadBank( pl )
|
||||
local json = file.Read( "itemstore/" .. ( pl:SteamID64() or "0" ) .. "_bank.txt", "DATA" )
|
||||
|
||||
if json then
|
||||
local bank = util.JSONToTable( json )
|
||||
|
||||
if bank then
|
||||
for k, v in pairs( bank ) do
|
||||
pl.Bank:SetItem( k, itemstore.Item( v.Class, v.Data ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pl.BankLoaded = true
|
||||
end
|
||||
|
||||
function PROVIDER:SaveBank( pl )
|
||||
local inv = {}
|
||||
|
||||
for k, v in pairs( pl.Bank:GetItems() ) do
|
||||
inv[ k ] = { Class = v.Class, Data = v.Data }
|
||||
end
|
||||
|
||||
file.Write( "itemstore/" .. ( pl:SteamID64() or "0" ) .. "_bank.txt", util.TableToJSON( inv ) )
|
||||
end
|
||||
|
||||
function PROVIDER:Import( data )
|
||||
for k, v in pairs( data ) do
|
||||
file.Write( "itemstore/" .. k .. ".txt", util.TableToJSON( data.Inventory ) )
|
||||
file.Write( "itemstore/" .. k .. "_bank.txt", util.TableToJSON( data.Bank ) )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PROVIDER:Export( filename )
|
||||
local export = {}
|
||||
|
||||
for _, filename in ipairs( file.Find( "itemstore/*.txt", "DATA" ) ) do
|
||||
local data = util.JSONToTable( file.Read( "itemstore/" .. filename, "DATA" ) )
|
||||
|
||||
if data then
|
||||
local inv_steamid = string.match( filename, "(%d+).txt" )
|
||||
local bank_steamid = string.match( filename, "(%d+)_bank.txt" )
|
||||
local steamid = inv_steamid or bank_steamid
|
||||
local isbank = steamid == bank_steamid
|
||||
|
||||
-- you shouldn't put random shit in itemstore's data folder but just in case
|
||||
if steamid then
|
||||
if not export[ steamid ] then
|
||||
export[ steamid ] = {}
|
||||
end
|
||||
|
||||
if isbank then
|
||||
export[ steamid ].Bank = data
|
||||
else
|
||||
export[ steamid ].Inventory = data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
file.Write( filename, util.TableToJSON( export ) )
|
||||
end
|
||||
242
addons/itemstore/lua/itemstore/dataproviders/tmysql4.lua
Normal file
242
addons/itemstore/lua/itemstore/dataproviders/tmysql4.lua
Normal file
@@ -0,0 +1,242 @@
|
||||
local PROVIDER = PROVIDER
|
||||
|
||||
-- Edit this with your authentication details
|
||||
local auth = {
|
||||
Host = "localhost",
|
||||
Port = 3306,
|
||||
Username = "root",
|
||||
Password = "",
|
||||
Database = "itemstore"
|
||||
}
|
||||
|
||||
function PROVIDER:Log( text )
|
||||
print( "[ItemStore MySQL] " .. text )
|
||||
file.Append( "itemstore/mysql.txt", os.date( "[%c]" ) .. " " .. text .. "\r\n" )
|
||||
end
|
||||
|
||||
function PROVIDER:OnConnected()
|
||||
self:Log( "Connection succesful!" )
|
||||
|
||||
-- I know I shouldn't store Data as a plain JSON string but I'm concerned about performance here.
|
||||
self:Query( "CREATE TABLE IF NOT EXISTS Inventories( SteamID VARCHAR( 32 ) NOT NULL, Slot INT NOT NULL, Class VARCHAR( 255 ) NULL, Data BLOB NULL, PRIMARY KEY ( SteamID, Slot ) )" )
|
||||
self:Query( "CREATE TABLE IF NOT EXISTS Banks( SteamID VARCHAR( 32 ) NOT NULL, Slot INT NOT NULL, Class VARCHAR( 255 ) NULL, Data BLOB NULL, PRIMARY KEY ( SteamID, Slot ) )" )
|
||||
end
|
||||
|
||||
function PROVIDER:OnError( err )
|
||||
self:Log( "Connection failed: " .. err )
|
||||
|
||||
timer.Simple( 30, function()
|
||||
self:Initialize()
|
||||
end )
|
||||
end
|
||||
|
||||
function PROVIDER:Initialize()
|
||||
require( "tmysql4" )
|
||||
assert( tmysql, "[ItemStore] TMySQL4 is not installed" )
|
||||
|
||||
self:Log( "Connecting to database..." )
|
||||
|
||||
local db, err = tmysql.initialize( auth.Host, auth.Username, auth.Password, auth.Database, auth.Port )
|
||||
|
||||
if err then
|
||||
PROVIDER:OnError( err )
|
||||
else
|
||||
PROVIDER.Database = db
|
||||
PROVIDER:OnConnected()
|
||||
end
|
||||
end
|
||||
|
||||
-- tmysql is so nice, no need for some stupid query buffer in case the database d/cs
|
||||
function PROVIDER:Query( sql, params, success, fail )
|
||||
if not success then
|
||||
function success( data ) end
|
||||
end
|
||||
|
||||
if not fail then
|
||||
function fail( err ) self:Log( "Query failed: " .. err ) end
|
||||
end
|
||||
|
||||
if not self.Database then
|
||||
fail( "Database not initialized" )
|
||||
return
|
||||
end
|
||||
|
||||
if params then
|
||||
for k, v in pairs( params ) do
|
||||
if type( v ) ~= "number" then
|
||||
v = self.Database:Escape( v )
|
||||
v = "'" .. v .. "'"
|
||||
end
|
||||
|
||||
sql = string.gsub( sql, ":" .. k, v )
|
||||
end
|
||||
end
|
||||
|
||||
self.Database:Query( sql, function( results )
|
||||
if results[ 1 ].status then
|
||||
success( results[ 1 ].data )
|
||||
else
|
||||
fail( results[ 1 ].error )
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
function PROVIDER:LoadInventory( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
self:Query( "SELECT * FROM Inventories WHERE SteamID = :1", { steamid }, function( data )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
for _, v in ipairs( data ) do
|
||||
local slot = v.Slot
|
||||
|
||||
if v.Class then
|
||||
local class = v.Class
|
||||
local data = util.JSONToTable( v.Data )
|
||||
|
||||
pl.Inventory:SetItem( slot, itemstore.Item( class, data ) )
|
||||
end
|
||||
end
|
||||
|
||||
pl.InventoryLoaded = true
|
||||
end )
|
||||
end
|
||||
|
||||
function PROVIDER:SaveInventory( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
for slot = 1, pl.Inventory:GetSize() do
|
||||
local item = pl.Inventory:GetItem( slot )
|
||||
|
||||
if item then
|
||||
local class = item:GetClass()
|
||||
local data = util.TableToJSON( item.Data )
|
||||
|
||||
self:Query( "REPLACE INTO Inventories( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { steamid, slot, class, data } )
|
||||
else
|
||||
self:Query( "REPLACE INTO Inventories( SteamID, Slot, Class, Data ) VALUES( :1, :2, NULL, NULL )", { steamid, slot } )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PROVIDER:LoadBank( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
self:Query( "SELECT * FROM Banks WHERE SteamID = :1", { steamid }, function( data )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
for _, v in ipairs( data ) do
|
||||
local slot = v.Slot
|
||||
|
||||
if v.Class then
|
||||
local class = v.Class
|
||||
local data = util.JSONToTable( v.Data )
|
||||
|
||||
pl.Bank:SetItem( slot, itemstore.Item( class, data ) )
|
||||
end
|
||||
end
|
||||
|
||||
pl.BankLoaded = true
|
||||
end )
|
||||
end
|
||||
|
||||
function PROVIDER:SaveBank( pl )
|
||||
local steamid = pl:SteamID64() or "0"
|
||||
|
||||
for slot = 1, pl.Bank:GetSize() do
|
||||
local item = pl.Bank:GetItem( slot )
|
||||
|
||||
if item then
|
||||
local class = item:GetClass()
|
||||
local data = util.TableToJSON( item.Data )
|
||||
|
||||
self:Query( "REPLACE INTO Banks( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { steamid, slot, class, data } )
|
||||
else
|
||||
self:Query( "REPLACE INTO Banks( SteamID, Slot, Class, Data ) VALUES( :1, :2, NULL, NULL )", { steamid, slot } )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PROVIDER:Import( data )
|
||||
for k, v in pairs( data ) do
|
||||
self:Query( "DELETE FROM Inventories WHERE SteamID = :1", { k } )
|
||||
self:Query( "DELETE FROM Banks WHERE SteamID = :1", { k } )
|
||||
|
||||
if v.Inventory then
|
||||
for slot, item in pairs( v.Inventory ) do
|
||||
if item then
|
||||
self:Query( "REPLACE INTO Inventories( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
else
|
||||
self:Query( "REPLACE INTO Inventories( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if v.Bank then
|
||||
for slot, item in pairs( v.Bank ) do
|
||||
if item then
|
||||
self:Query( "REPLACE INTO Banks( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
else
|
||||
self:Query( "REPLACE INTO Banks( SteamID, Slot, Class, Data ) VALUES( :1, :2, :3, :4 )", { k, slot, item.Class, util.TableToJSON( item.Data ) } )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PROVIDER:Export( filename )
|
||||
local export = {}
|
||||
|
||||
local inventory_loaded = false
|
||||
local bank_loaded = false
|
||||
|
||||
local function FinishExport( export )
|
||||
file.Write( filename, util.TableToJSON( export ) )
|
||||
end
|
||||
|
||||
self:Query( "SELECT * FROM Inventories", nil, function( data )
|
||||
for _, row in ipairs( data ) do
|
||||
if not ( export[ row.SteamID ] ) then
|
||||
export[ row.SteamID ] = {}
|
||||
end
|
||||
|
||||
if not ( export[ row.SteamID ].Inventory ) then
|
||||
export[ row.SteamID ].Inventory = {}
|
||||
end
|
||||
|
||||
if row.Class then
|
||||
export[ row.SteamID ].Inventory[ row.Slot ] = { Class = row.Class, Data = util.JSONToTable( row.Data ) }
|
||||
end
|
||||
end
|
||||
|
||||
inventory_loaded = true
|
||||
|
||||
if inventory_loaded and bank_loaded then
|
||||
FinishExport( export )
|
||||
end
|
||||
end )
|
||||
|
||||
self:Query( "SELECT * FROM Banks", nil, function( data )
|
||||
for _, row in ipairs( data ) do
|
||||
if not ( export[ row.SteamID ] ) then
|
||||
export[ row.SteamID ] = {}
|
||||
end
|
||||
|
||||
if not ( export[ row.SteamID ].Bank ) then
|
||||
export[ row.SteamID ].Bank = {}
|
||||
end
|
||||
|
||||
if row.Class then
|
||||
export[ row.SteamID ].Bank[ row.Slot ] = { Class = row.Class, Data = util.JSONToTable( row.Data ) }
|
||||
end
|
||||
end
|
||||
|
||||
bank_loaded = true
|
||||
|
||||
if inventory_loaded and bank_loaded then
|
||||
FinishExport( export )
|
||||
end
|
||||
end )
|
||||
end
|
||||
70
addons/itemstore/lua/itemstore/gamemodeproviders/darkrp.lua
Normal file
70
addons/itemstore/lua/itemstore/gamemodeproviders/darkrp.lua
Normal file
@@ -0,0 +1,70 @@
|
||||
function PROVIDER:GetMoney( pl )
|
||||
return pl:getDarkRPVar( "money" )
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function PROVIDER:SetMoney( pl, money )
|
||||
pl:setDarkRPVar( "money", money )
|
||||
if DarkRP.storeMoney then DarkRP.storeMoney( pl, money ) end
|
||||
end
|
||||
|
||||
if itemstore.config.EnableInvholster then
|
||||
itemstore.AddCommand( "invholster", function( pl, args )
|
||||
if not pl:CanUseInventory() then return end
|
||||
|
||||
local wep = pl:GetActiveWeapon()
|
||||
|
||||
-- This code is not mine, I'm simply copypasting DarkRP stuff right here.
|
||||
if not IsValid(wep) or not wep:GetModel() or wep:GetModel() == "" then
|
||||
DarkRP.notify(pl, 1, 4, DarkRP.getPhrase("cannot_drop_weapon"))
|
||||
return
|
||||
end
|
||||
|
||||
if itemstore.config.DisabledItems[ wep:GetClass() ] then
|
||||
DarkRP.notify(pl, 1, 4, DarkRP.getPhrase("cannot_drop_weapon"))
|
||||
return
|
||||
end
|
||||
|
||||
if GAMEMODE.Config.restrictdrop then
|
||||
local found = false
|
||||
for k,v in pairs(CustomShipments) do
|
||||
if v.entity == wep:GetClass() then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then return end
|
||||
end
|
||||
|
||||
local canDrop = hook.Call("canDropWeapon", GAMEMODE, pl, wep)
|
||||
if not canDrop then
|
||||
DarkRP.notify(pl, 1, 4, DarkRP.getPhrase("cannot_drop_weapon"))
|
||||
return
|
||||
end
|
||||
-- and back to our regularly scheduled coding
|
||||
|
||||
local item = itemstore.Item( "spawned_weapon" )
|
||||
|
||||
item:SetData( "Class", wep:GetClass() )
|
||||
item:SetData( "Amount", 1 )
|
||||
item:SetData( "Model", wep:GetModel() )
|
||||
item:SetData( "Clip1", wep:Clip1() )
|
||||
item:SetData( "Clip2", wep:Clip2() )
|
||||
|
||||
if itemstore.config.InvholsterTakesAmmo then
|
||||
local ammotype = wep:GetPrimaryAmmoType()
|
||||
|
||||
if ammotype and ammotype ~= "none" then -- to be entirely honest I'm not sure if it returns nil or "none"
|
||||
local ammo = pl:GetAmmoCount( ammotype )
|
||||
|
||||
item:SetData( "Ammo", ammo )
|
||||
pl:RemoveAmmo( ammo, ammotype )
|
||||
end
|
||||
end
|
||||
|
||||
pl:StripWeapon( wep:GetClass() )
|
||||
pl.Inventory:AddItem( item )
|
||||
end )
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,69 @@
|
||||
function PROVIDER:GetMoney( pl )
|
||||
return pl:getDarkRPVar( "money" )
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function PROVIDER:SetMoney( pl, money )
|
||||
return pl:SetDarkRPVar( "money", money )
|
||||
end
|
||||
|
||||
if itemstore.config.EnableInvholster then
|
||||
itemstore.AddCommand( "invholster", function( pl, args )
|
||||
if not pl:CanUseInventory() then return end
|
||||
|
||||
local wep = pl:GetActiveWeapon()
|
||||
|
||||
-- This code is not mine, I'm simply copypasting DarkRP stuff right here.
|
||||
if not IsValid(wep) or not wep:GetModel() or wep:GetModel() == "" then
|
||||
DarkRP.notify(pl, 1, 4, DarkRP.getPhrase("cannot_drop_weapon"))
|
||||
return
|
||||
end
|
||||
|
||||
if itemstore.config.DisabledItems[ wep:GetClass() ] then
|
||||
DarkRP.notify(pl, 1, 4, DarkRP.getPhrase("cannot_drop_weapon"))
|
||||
return
|
||||
end
|
||||
|
||||
if GAMEMODE.Config.restrictdrop then
|
||||
local found = false
|
||||
for k,v in pairs(CustomShipments) do
|
||||
if v.entity == wep:GetClass() then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then return end
|
||||
end
|
||||
|
||||
local canDrop = hook.Call("canDropWeapon", GAMEMODE, pl, wep)
|
||||
if not canDrop then
|
||||
DarkRP.notify(pl, 1, 4, DarkRP.getPhrase("cannot_drop_weapon"))
|
||||
return
|
||||
end
|
||||
-- and back to our regularly scheduled coding
|
||||
|
||||
local item = itemstore.Item( "spawned_weapon" )
|
||||
|
||||
item:SetData( "Class", wep:GetClass() )
|
||||
item:SetData( "Amount", 1 )
|
||||
item:SetData( "Model", wep:GetModel() )
|
||||
item:SetData( "Clip1", wep:Clip1() )
|
||||
item:SetData( "Clip2", wep:Clip2() )
|
||||
|
||||
if itemstore.config.InvholsterTakesAmmo then
|
||||
local ammotype = wep:GetPrimaryAmmoType()
|
||||
|
||||
if ammotype and ammotype ~= "none" then -- to be entirely honest I'm not sure if it returns nil or "none"
|
||||
local ammo = pl:GetAmmoCount( ammotype )
|
||||
|
||||
item:SetData( "Ammo", ammo )
|
||||
pl:RemoveAmmo( ammo, ammotype )
|
||||
end
|
||||
end
|
||||
|
||||
pl:StripWeapon( wep:GetClass() )
|
||||
pl.Inventory:AddItem( item )
|
||||
end )
|
||||
end
|
||||
end
|
||||
103
addons/itemstore/lua/itemstore/gamemodes.lua
Normal file
103
addons/itemstore/lua/itemstore/gamemodes.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
itemstore.gamemodes = {}
|
||||
|
||||
PROVIDER = {}
|
||||
include( "gamemodeproviders/" .. itemstore.config.GamemodeProvider .. ".lua" )
|
||||
if SERVER then AddCSLuaFile( "gamemodeproviders/" .. itemstore.config.GamemodeProvider .. ".lua" ) end
|
||||
itemstore.gamemodes.Provider = PROVIDER
|
||||
PROVIDER = nil
|
||||
|
||||
assert( itemstore.gamemodes.Provider, "[ItemStore] Gamemode provider not found" )
|
||||
|
||||
function itemstore.gamemodes.Run( func_name, ... )
|
||||
local func = itemstore.gamemodes.Provider[ func_name ]
|
||||
if not func then return end
|
||||
|
||||
return func( itemstore.gamemodes.Provider, ... )
|
||||
end
|
||||
|
||||
function itemstore.gamemodes.GetMoney( pl )
|
||||
return itemstore.gamemodes.Run( "GetMoney", pl )
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function itemstore.gamemodes.SetMoney( pl, money )
|
||||
return itemstore.gamemodes.Run( "SetMoney", pl, money )
|
||||
end
|
||||
|
||||
function itemstore.gamemodes.GiveMoney( pl, money )
|
||||
return itemstore.gamemodes.SetMoney( pl, itemstore.gamemodes.GetMoney( pl ) + money )
|
||||
end
|
||||
|
||||
function itemstore.gamemodes.AddCommand( command, info, func )
|
||||
return itemstore.gamemodes.Run( "AddCommand", command, info, func )
|
||||
end
|
||||
|
||||
itemstore.AddCommand( "trade", function( pl, args )
|
||||
args = table.concat( args, " " )
|
||||
|
||||
if not pl:CanUseInventory() then
|
||||
pl:ChatPrint( itemstore.Translate( "cant_access_inventory" ) )
|
||||
return
|
||||
end
|
||||
|
||||
if not itemstore.config.TradingEnabled then
|
||||
return
|
||||
end
|
||||
|
||||
if pl.TradingCooldown and pl.TradingCooldown > CurTime() then
|
||||
pl:ChatPrint( itemstore.Translate( "trading_cooldown" ) )
|
||||
return
|
||||
end
|
||||
|
||||
local target = pl:GetEyeTrace().Entity
|
||||
|
||||
if args ~= "" then
|
||||
for _, pl in ipairs( player.GetAll() ) do
|
||||
if string.find( string.lower( pl:Name() ), string.lower( args ), 1, true ) then
|
||||
target = pl
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not IsValid( target ) or not target:IsPlayer() then
|
||||
pl:ChatPrint( itemstore.Translate( "player_not_found" ) )
|
||||
return
|
||||
end
|
||||
|
||||
if not target:CanUseInventory() then
|
||||
pl:ChatPrint( itemstore.Translate( "partner_cant_access_inventory" ) )
|
||||
return
|
||||
end
|
||||
|
||||
if pl.Trade then
|
||||
pl:ChatPrint( itemstore.Translate( "already_in_trade" ) )
|
||||
return
|
||||
end
|
||||
|
||||
if target.Trade then
|
||||
pl:ChatPrint( itemstore.Translate( "partner_is_in_trade" ) )
|
||||
return
|
||||
end
|
||||
|
||||
if itemstore.config.TradeDistance ~= 0 and pl:GetPos():Distance( target:GetPos() ) > itemstore.config.TradeDistance then
|
||||
pl:ChatPrint( itemstore.Translate( "too_far_away" ) )
|
||||
return
|
||||
end
|
||||
|
||||
itemstore.Trade( pl, target )
|
||||
|
||||
pl.TradingCooldown = CurTime() + itemstore.config.TradeCooldown
|
||||
end )
|
||||
|
||||
itemstore.AddCommand( "inv", function( pl )
|
||||
pl:OpenContainer( pl.Inventory:GetID(), itemstore.Translate( "inventory" ), true )
|
||||
end )
|
||||
|
||||
itemstore.AddCommand( "pickup", function( pl )
|
||||
pl:PickupItem()
|
||||
end )
|
||||
end
|
||||
|
||||
hook.Add( "PostGamemodeLoaded", "ItemStoreGamemodeLoad", function()
|
||||
itemstore.gamemodes.Run( "Load" )
|
||||
end )
|
||||
273
addons/itemstore/lua/itemstore/items.lua
Normal file
273
addons/itemstore/lua/itemstore/items.lua
Normal file
@@ -0,0 +1,273 @@
|
||||
itemstore.items = {}
|
||||
itemstore.items.Registered = {}
|
||||
itemstore.items.Pickups = {}
|
||||
|
||||
local Item = {}
|
||||
Item.Name = "Invalid Item"
|
||||
--Item.Description = "Invalid Description"
|
||||
Item.Model = "models/error.mdl"
|
||||
--Item.Skin = 0
|
||||
--Item.Color = nil
|
||||
--Item.Material = nil
|
||||
Item.HighlightColor = itemstore.config.HighlightColours.Other
|
||||
|
||||
Item.Stackable = false
|
||||
Item.Amount = 1
|
||||
Item.MaxStack = itemstore.config.MaxStack
|
||||
Item.DropStack = false
|
||||
|
||||
Item.DontNetwork = {}
|
||||
|
||||
function Item:GetClass()
|
||||
return self.Class
|
||||
end
|
||||
|
||||
function Item:IsValid()
|
||||
return true
|
||||
end
|
||||
|
||||
function Item:Run( func_name, ... )
|
||||
local func = self[ func_name ]
|
||||
|
||||
if type( func ) ~= "function" then return end
|
||||
|
||||
return func( self, ... )
|
||||
end
|
||||
|
||||
function Item:Load()
|
||||
end
|
||||
|
||||
function Item:Initialize()
|
||||
end
|
||||
|
||||
function Item:GetContainer()
|
||||
local con = self.Container
|
||||
if not con then return end
|
||||
|
||||
local slot = self.Slot
|
||||
if not slot then return end
|
||||
|
||||
if con:GetItem( slot ) == self then return self.Container end
|
||||
end
|
||||
|
||||
function Item:GetSlot()
|
||||
local con = self.Container
|
||||
if not con then return end
|
||||
|
||||
local slot = self.Slot
|
||||
if not slot then return end
|
||||
|
||||
if con:GetItem( slot ) == self then return self.Slot end
|
||||
end
|
||||
|
||||
function Item:Copy()
|
||||
return itemstore.Item( self:GetClass(), table.Copy( self.Data ) )
|
||||
end
|
||||
|
||||
function Item:RegisterPickup( ent_class )
|
||||
itemstore.items.Pickups[ ent_class ] = self:GetClass()
|
||||
end
|
||||
|
||||
function Item:GetData( key, default )
|
||||
return self.Data[ key ] == nil and default or self.Data[ key ]
|
||||
end
|
||||
|
||||
function Item:SetData( key, value )
|
||||
self.Data[ key ] = value
|
||||
end
|
||||
|
||||
function Item:CreateMutator( key, default )
|
||||
self[ "Set" .. key ] = function( self, value )
|
||||
self:SetData( key, value )
|
||||
end
|
||||
|
||||
self[ "Get" .. key ] = function( self, default )
|
||||
return self:GetData( key, default or self[ key ] )
|
||||
end
|
||||
end
|
||||
|
||||
Item:CreateMutator( "Name" )
|
||||
Item:CreateMutator( "Description" )
|
||||
Item:CreateMutator( "Model" )
|
||||
Item:CreateMutator( "Material" )
|
||||
Item:CreateMutator( "Skin" )
|
||||
Item:CreateMutator( "Color" )
|
||||
Item:CreateMutator( "MaxStack" )
|
||||
Item:CreateMutator( "Amount" )
|
||||
|
||||
function Item:GetStaticName()
|
||||
return self.StaticName or self.Name
|
||||
end
|
||||
|
||||
function Item:Pickup( pl, con, slot, ent )
|
||||
end
|
||||
|
||||
function Item:Drop( pl, con, slot, ent )
|
||||
end
|
||||
|
||||
function Item:Destroy( pl, con, slot )
|
||||
end
|
||||
|
||||
function Item:TakeOne()
|
||||
self:SetAmount( self:GetAmount() - 1 )
|
||||
|
||||
if self:GetAmount() <= 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function Item:CanPickup()
|
||||
return true
|
||||
end
|
||||
|
||||
function Item:CanUseWith( item )
|
||||
return false
|
||||
end
|
||||
|
||||
function Item:CanMerge( item )
|
||||
return self.Stackable and item.Stackable and self:GetClass() == item:GetClass()
|
||||
and ( self:GetAmount() + item:GetAmount() ) <= self:GetMaxStack()
|
||||
end
|
||||
|
||||
function Item:Merge( item )
|
||||
self:SetAmount( self:GetAmount() + item:GetAmount() )
|
||||
end
|
||||
|
||||
function Item:CanSplit( amount )
|
||||
return self.Stackable and self:GetAmount() > amount
|
||||
end
|
||||
|
||||
function Item:Split( amount )
|
||||
self:SetAmount( self:GetAmount() - amount )
|
||||
|
||||
local item = self:Copy()
|
||||
item:SetAmount( amount )
|
||||
|
||||
return item
|
||||
end
|
||||
|
||||
function Item:FormatAmount()
|
||||
return "x" .. self:GetAmount()
|
||||
end
|
||||
|
||||
function Item:CreateEntity( pos )
|
||||
local ent = ents.Create( "itemstore_item" )
|
||||
ent:SetPos( pos )
|
||||
self:LoadData( ent )
|
||||
ent:Spawn()
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function Item:SaveData( ent )
|
||||
end
|
||||
|
||||
function Item:LoadData( ent )
|
||||
ent:SetItem( self )
|
||||
end
|
||||
|
||||
function Item:WriteNetworkData()
|
||||
local data = {}
|
||||
|
||||
for k, v in pairs( self.Data ) do
|
||||
if not self.DontNetwork[ k ] then data[ k ] = v end
|
||||
end
|
||||
|
||||
net.WriteUInt( table.Count( data ), 8 )
|
||||
|
||||
for k, v in pairs( data ) do
|
||||
net.WriteString( k )
|
||||
net.WriteType( v )
|
||||
end
|
||||
end
|
||||
|
||||
function Item:ReadNetworkData()
|
||||
for i = 1, net.ReadUInt( 8 ) do
|
||||
self:SetData( net.ReadString(), net.ReadType() )
|
||||
end
|
||||
end
|
||||
|
||||
function Item:PreRender( ent )
|
||||
end
|
||||
|
||||
function Item:PostRender( ent )
|
||||
end
|
||||
|
||||
function itemstore.Item( class_name, data )
|
||||
local class = itemstore.items.Registered[ class_name ]
|
||||
|
||||
if class then
|
||||
local item = {
|
||||
Class = class_name,
|
||||
Data = data or {}
|
||||
}
|
||||
|
||||
setmetatable( item, { __index = class } )
|
||||
|
||||
item:Initialize()
|
||||
|
||||
return item
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.items.Get( class )
|
||||
return itemstore.items.Registered[ class ]
|
||||
end
|
||||
|
||||
function itemstore.items.Exists( class )
|
||||
return itemstore.items.Registered[ class ] ~= nil
|
||||
end
|
||||
|
||||
function itemstore.items.Register( tab )
|
||||
if SERVER then util.AddNetworkString( tab.Class ) end
|
||||
itemstore.items.Registered[ tab.Class ] = tab
|
||||
end
|
||||
|
||||
function itemstore.items.Load()
|
||||
for _, filename in ipairs( file.Find( "itemstore/items/*.lua", "LUA" ) ) do
|
||||
local name = string.match( filename, "^(.+).lua$" )
|
||||
|
||||
if name then
|
||||
ITEM = setmetatable( {}, { __index = Item } )
|
||||
ITEM.Class = name
|
||||
|
||||
if SERVER then AddCSLuaFile( "itemstore/items/" .. filename ) end
|
||||
include( "itemstore/items/" .. filename )
|
||||
|
||||
itemstore.items.Register( ITEM )
|
||||
|
||||
ITEM = nil
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs( itemstore.config.CustomItems ) do
|
||||
local ITEM = setmetatable( {}, { __index = Item } )
|
||||
|
||||
ITEM.Class = k
|
||||
ITEM.Name = v[ 1 ]
|
||||
ITEM.Description = v[ 2 ]
|
||||
ITEM.Stackable = v[ 3 ]
|
||||
ITEM.Base = "base_auto"
|
||||
|
||||
itemstore.items.Register( ITEM )
|
||||
end
|
||||
|
||||
for _, item in pairs( itemstore.items.Registered ) do
|
||||
if item.Base then
|
||||
local base = itemstore.items.Get( item.Base )
|
||||
|
||||
if base then
|
||||
setmetatable( item, { __index = base } )
|
||||
else
|
||||
ErrorNoHalt( "[ItemStore] " .. item.Class .. " tried to derive from non-existent base " .. item.Base )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, item in pairs( itemstore.items.Registered ) do
|
||||
item:Load()
|
||||
end
|
||||
end
|
||||
itemstore.items.Load()
|
||||
28
addons/itemstore/lua/itemstore/items/base_auto.lua
Normal file
28
addons/itemstore/lua/itemstore/items/base_auto.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
ITEM.Name = "Auto Item Base"
|
||||
ITEM.Model = "models/error.mdl"
|
||||
ITEM.Base = "base_entity"
|
||||
|
||||
ITEM.DontNetwork = {
|
||||
EntityData = true
|
||||
}
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetModel( ent:GetModel() )
|
||||
self:SetData( "EntityData", duplicator.CopyEntTable( ent ) )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
local data = self:GetData( "EntityData" )
|
||||
data.Pos = nil
|
||||
data.Angle = nil
|
||||
|
||||
duplicator.DoGeneric( ent, data )
|
||||
|
||||
if data.DT then
|
||||
timer.Simple( 0, function()
|
||||
for k, v in pairs( data.DT ) do
|
||||
ent.dt[ k ] = v
|
||||
end
|
||||
end )
|
||||
end
|
||||
end
|
||||
14
addons/itemstore/lua/itemstore/items/base_darkrp.lua
Normal file
14
addons/itemstore/lua/itemstore/items/base_darkrp.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
ITEM.Name = "DarkRP Item Base"
|
||||
ITEM.Model = "models/error.mdl"
|
||||
ITEM.Base = "base_entity"
|
||||
|
||||
function ITEM:CanPickup( pl, ent )
|
||||
if not ent.dt or not ent.dt.owning_ent then return true end
|
||||
|
||||
if not itemstore.config.IgnoreOwner and ent:Getowning_ent() ~= pl then
|
||||
pl:ChatPrint( "You can't pick that up, it's not your's!" )
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
21
addons/itemstore/lua/itemstore/items/base_entity.lua
Normal file
21
addons/itemstore/lua/itemstore/items/base_entity.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
ITEM.Name = "Entity Item Base"
|
||||
ITEM.Model = "models/error.mdl"
|
||||
|
||||
function ITEM:Load()
|
||||
self:RegisterPickup( self.Class )
|
||||
end
|
||||
|
||||
function ITEM:CreateEntity( pos )
|
||||
local ent = ents.Create( self.Class )
|
||||
ent:SetPos( pos )
|
||||
self:LoadData( ent )
|
||||
ent:Spawn()
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ITEM:SaveData()
|
||||
end
|
||||
|
||||
function ITEM:LoadData()
|
||||
end
|
||||
16
addons/itemstore/lua/itemstore/items/drug.lua
Normal file
16
addons/itemstore/lua/itemstore/items/drug.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
ITEM.Name = itemstore.Translate( "drug_name" )
|
||||
ITEM.Description = itemstore.Translate( "drug_desc" )
|
||||
ITEM.Model = "models/props_lab/jar01a.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Consumables
|
||||
ITEM.Base = "base_darkrp"
|
||||
ITEM.Stackable = true
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Price", ent:Getprice() )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setprice( self:GetData( "Price" ) )
|
||||
ent:Setowning_ent( self:GetData( "Owner" ) )
|
||||
end
|
||||
21
addons/itemstore/lua/itemstore/items/drug_lab.lua
Normal file
21
addons/itemstore/lua/itemstore/items/drug_lab.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
ITEM.Name = itemstore.Translate( "druglab_name" )
|
||||
ITEM.Description = itemstore.Translate( "druglab_desc" )
|
||||
ITEM.Model = "models/props_lab/crematorcase.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Factories
|
||||
ITEM.Base = "base_darkrp"
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Price", ent:Getprice() )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setprice( self:GetData( "Price" ) )
|
||||
|
||||
local owner = self:GetData( "Owner" )
|
||||
if not IsValid( owner ) then
|
||||
owner = player.GetAll()[ 1 ]
|
||||
end
|
||||
|
||||
ent:Setowning_ent( owner )
|
||||
end
|
||||
21
addons/itemstore/lua/itemstore/items/food.lua
Normal file
21
addons/itemstore/lua/itemstore/items/food.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
ITEM.Name = itemstore.Translate( "food_name" )
|
||||
ITEM.Description = itemstore.Translate( "microwavefood_desc" )
|
||||
ITEM.Model = "models/props_junk/garbage_takeoutcarton001a.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Consumables
|
||||
ITEM.Base = "base_darkrp"
|
||||
ITEM.Stackable = true
|
||||
|
||||
function ITEM:Use( pl )
|
||||
pl:setSelfDarkRPVar( "Energy", 100 )
|
||||
umsg.Start( "AteFoodIcon", pl ) umsg.End()
|
||||
|
||||
return self:TakeOne()
|
||||
end
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setowning_ent( self:GetData( "Owner" ) )
|
||||
end
|
||||
21
addons/itemstore/lua/itemstore/items/gunlab.lua
Normal file
21
addons/itemstore/lua/itemstore/items/gunlab.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
ITEM.Name = itemstore.Translate( "gunlab_name" )
|
||||
ITEM.Description = itemstore.Translate( "gunlab_name" )
|
||||
ITEM.Model = "models/props_c17/TrapPropeller_Engine.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Factories
|
||||
ITEM.Base = "base_darkrp"
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Price", ent:Getprice() )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setprice( self:GetData( "Price" ) )
|
||||
|
||||
local owner = self:GetData( "Owner" )
|
||||
if not IsValid( owner ) then
|
||||
owner = player.GetAll()[ 1 ]
|
||||
end
|
||||
|
||||
ent:Setowning_ent( owner )
|
||||
end
|
||||
21
addons/itemstore/lua/itemstore/items/microwave.lua
Normal file
21
addons/itemstore/lua/itemstore/items/microwave.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
ITEM.Name = itemstore.Translate( "microwave_name" )
|
||||
ITEM.Description = itemstore.Translate( "microwave_desc" )
|
||||
ITEM.Model = "models/props/cs_office/microwave.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Factories
|
||||
ITEM.Base = "base_darkrp"
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Price", ent:Getprice() )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setprice( self:GetData( "Price" ) )
|
||||
|
||||
local owner = self:GetData( "Owner" )
|
||||
if not IsValid( owner ) then
|
||||
owner = player.GetAll()[ 1 ]
|
||||
end
|
||||
|
||||
ent:Setowning_ent( owner )
|
||||
end
|
||||
15
addons/itemstore/lua/itemstore/items/money_printer.lua
Normal file
15
addons/itemstore/lua/itemstore/items/money_printer.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
ITEM.Name = itemstore.Translate( "moneyprinter_name" )
|
||||
ITEM.Description = itemstore.Translate( "moneyprinter_desc" )
|
||||
ITEM.Model = "models/props_c17/consolebox01a.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Factories
|
||||
ITEM.Base = "base_darkrp"
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Price", ent:Getprice() )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setprice( self:GetData( "Price" ) )
|
||||
ent:Setowning_ent( self:GetData( "Owner" ) )
|
||||
end
|
||||
13
addons/itemstore/lua/itemstore/items/prop_physics.lua
Normal file
13
addons/itemstore/lua/itemstore/items/prop_physics.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
ITEM.Name = itemstore.Translate( "prop_name" )
|
||||
ITEM.Description = itemstore.Translate( "prop_desc" )
|
||||
ITEM.Base = "base_auto"
|
||||
|
||||
function ITEM:CanPickup( pl, ent )
|
||||
if CPPI then
|
||||
if ent:CPPIGetOwner() ~= pl then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
36
addons/itemstore/lua/itemstore/items/spawned_ammo.lua
Normal file
36
addons/itemstore/lua/itemstore/items/spawned_ammo.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
ITEM.Name = itemstore.Translate( "ammo_name" )
|
||||
ITEM.Description = itemstore.Translate( "ammo_desc" )
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Ammo
|
||||
ITEM.Stackable = true
|
||||
ITEM.DropStack = true
|
||||
ITEM.Base = "base_darkrp"
|
||||
|
||||
function ITEM:GetName()
|
||||
if SERVER then
|
||||
return self:GetData( "Name", self.Name )
|
||||
else
|
||||
return self:GetData( "Name", language.GetPhrase( self:GetData( "AmmoType" ) .. "_ammo" ) )
|
||||
end
|
||||
end
|
||||
|
||||
function ITEM:Use( pl )
|
||||
pl:GiveAmmo( self:GetAmount(), self:GetData( "AmmoType" ) )
|
||||
return true
|
||||
end
|
||||
|
||||
function ITEM:CanMerge( item )
|
||||
return self.Stackable and self:GetClass() == item:GetClass() and
|
||||
self:GetData( "AmmoType" ) == item:GetData( "AmmoType" )
|
||||
end
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetModel( ent:GetModel() )
|
||||
self:SetAmount( ent.amountGiven )
|
||||
self:SetData( "AmmoType", ent.ammoType )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:SetModel( self:GetModel() )
|
||||
ent.amountGiven = self:GetAmount()
|
||||
ent.ammoType = self:GetData( "AmmoType" )
|
||||
end
|
||||
64
addons/itemstore/lua/itemstore/items/spawned_food.lua
Normal file
64
addons/itemstore/lua/itemstore/items/spawned_food.lua
Normal file
@@ -0,0 +1,64 @@
|
||||
ITEM.Name = itemstore.Translate( "food_name" )
|
||||
ITEM.Description = itemstore.Translate( "food_desc" )
|
||||
ITEM.Model = "models/props_junk/watermelon01.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Consumables
|
||||
ITEM.Base = "base_darkrp"
|
||||
|
||||
ITEM.Foods = {
|
||||
[ "models/props_junk/watermelon01.mdl" ] = itemstore.Translate( "food_melon" ),
|
||||
[ "models/props/cs_italy/orange.mdl" ] = itemstore.Translate( "food_orange" ),
|
||||
[ "models/props/cs_italy/bananna_bunch.mdl" ] = itemstore.Translate( "food_bananas" ),
|
||||
[ "models/props/cs_italy/bananna.mdl" ] = itemstore.Translate( "food_banana" ),
|
||||
[ "models/props_junk/glassbottle01a.mdl" ] = itemstore.Translate( "food_glassbottle" ),
|
||||
[ "models/props_junk/popcan01a.mdl" ] = itemstore.Translate( "food_soda" ),
|
||||
[ "models/props_junk/garbage_milkcarton002a.mdl" ] = itemstore.Translate( "food_milk" ),
|
||||
[ "models/props_junk/garbage_glassbottle002a.mdl" ] = itemstore.Translate( "food_beer" ),
|
||||
[ "models/props_junk/garbage_plasticbottle003a.mdl" ] = itemstore.Translate( "food_twolitresoda" ),
|
||||
[ "models/props_junk/garbage_glassbottle001a.mdl" ] = itemstore.Translate( "food_onelitresoda" ),
|
||||
[ "models/props_junk/garbage_glassbottle003a.mdl" ] = itemstore.Translate( "food_glassbottle" )
|
||||
}
|
||||
|
||||
function ITEM:GetName()
|
||||
local name = self.Name
|
||||
|
||||
if self.Foods[ self:GetModel() ] then
|
||||
name = self.Foods[ self:GetModel() ]
|
||||
end
|
||||
|
||||
return self:GetData( "Name", name )
|
||||
end
|
||||
|
||||
function ITEM:GetDescription()
|
||||
return self:GetData( "Description", string.format( self.Description, self:GetData( "Nutrition", 1 ) ) )
|
||||
end
|
||||
|
||||
function ITEM:Use( pl )
|
||||
local energy = pl:getDarkRPVar( "Energy" ) + self:GetData( "Nutrition", 1 )
|
||||
pl:setSelfDarkRPVar( "Energy", math.Clamp( energy, 0, 100 ) )
|
||||
|
||||
umsg.Start( "AteFoodIcon", pl ) umsg.End()
|
||||
|
||||
pl:EmitSound( "npc/barnacle/barnacle_crunch2.wav" )
|
||||
|
||||
return self:TakeOne()
|
||||
end
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
self:SetData( "Nutrition", ent.FoodEnergy )
|
||||
self:SetModel( ent:GetModel() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setowning_ent( self:GetData( "Owner" ) )
|
||||
ent:SetModel( self:GetModel() )
|
||||
ent.FoodEnergy = self:GetData( "Nutrition" )
|
||||
|
||||
-- One day fptje is gonna have some feces mailed to his house or something, christ
|
||||
for k, v in ipairs( FoodItems ) do
|
||||
if v.model == self:GetModel() then
|
||||
ent.foodItem = v
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
25
addons/itemstore/lua/itemstore/items/spawned_money.lua
Normal file
25
addons/itemstore/lua/itemstore/items/spawned_money.lua
Normal file
@@ -0,0 +1,25 @@
|
||||
ITEM.Name = itemstore.Translate( "money_name" )
|
||||
ITEM.Description = itemstore.Translate( "money_desc" )
|
||||
ITEM.Model = "models/props/cs_assault/money.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Money
|
||||
ITEM.Base = "base_darkrp"
|
||||
ITEM.Stackable = true
|
||||
ITEM.DropStack = true
|
||||
ITEM.MaxStack = math.huge
|
||||
|
||||
function ITEM:FormatAmount()
|
||||
return GAMEMODE.Config.currency .. self:GetAmount()
|
||||
end
|
||||
|
||||
function ITEM:Use( pl )
|
||||
itemstore.gamemodes.GiveMoney( pl, self:GetAmount() )
|
||||
return true
|
||||
end
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetAmount( ent:Getamount() )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setamount( self:GetAmount() )
|
||||
end
|
||||
132
addons/itemstore/lua/itemstore/items/spawned_shipment.lua
Normal file
132
addons/itemstore/lua/itemstore/items/spawned_shipment.lua
Normal file
@@ -0,0 +1,132 @@
|
||||
ITEM.Name = itemstore.Translate( "shipment_name" )
|
||||
ITEM.Description = itemstore.Translate( "shipment_desc" )
|
||||
ITEM.Model = "models/Items/item_item_crate.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Shipments
|
||||
ITEM.Stackable = true
|
||||
ITEM.DropStack = true
|
||||
ITEM.Base = "base_darkrp"
|
||||
|
||||
-- Because all of you feel the need to fuck with your shipments on a daily basis.
|
||||
|
||||
function ITEM:Initialize()
|
||||
if not SERVER then return end
|
||||
if not self:GetData( "Class" ) then return end
|
||||
|
||||
local shipment = CustomShipments[ self:GetData( "Contents" ) ]
|
||||
if shipment and shipment.entity == self:GetData( "class" ) then return end
|
||||
|
||||
for k, v in ipairs( CustomShipments ) do
|
||||
if v.entity == self:GetData( "Class" ) then
|
||||
self:SetData( "Contents", k )
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ITEM:GetDescription()
|
||||
local shipment = CustomShipments[ self:GetData( "Contents" ) ]
|
||||
|
||||
local str = itemstore.Translate( "shipment_invalid" )
|
||||
if shipment then
|
||||
str = string.format( self.Description, shipment.name )
|
||||
end
|
||||
|
||||
return self:GetData( "Description", str )
|
||||
end
|
||||
|
||||
function ITEM:CanMerge( item )
|
||||
return self.Stackable and self:GetClass() == item:GetClass() and
|
||||
self:GetData( "Contents" ) == item:GetData( "Contents" ) and
|
||||
self:GetMaxStack() >= ( item:GetAmount() + self:GetAmount() )
|
||||
end
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Owner", ent:Getowning_ent() )
|
||||
self:SetData( "Contents", ent:Getcontents() )
|
||||
self:SetData( "Amount", ent:Getcount() )
|
||||
|
||||
self:SetData( "Class", CustomShipments[ ent:Getcontents() ].entity )
|
||||
|
||||
self:SetData( "Ammo", ent.ammoadd )
|
||||
self:SetData( "Clip1", ent.clip1 )
|
||||
self:SetData( "Clip2", ent.clip2 )
|
||||
end
|
||||
|
||||
function ITEM:CanPickup( pl, ent )
|
||||
return self:GetMaxStack() >= ent:Getcount() and not ent.locked
|
||||
end
|
||||
|
||||
function ITEM:Pickup( pl, con, slot, ent )
|
||||
timer.Destroy( ent:EntIndex() .. "crate" )
|
||||
--ent.locked = false
|
||||
ent.sparking = false
|
||||
end
|
||||
|
||||
-- 76561198068291318
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:Setcontents( self:GetData( "Contents" ) )
|
||||
ent:Setcount( self:GetData( "Amount" ) )
|
||||
ent:Setowning_ent( self:GetData( "Owner" ) )
|
||||
|
||||
ent.ammoadd = self:GetData( "Ammo" )
|
||||
ent.clip1 = self:GetData( "Clip1" )
|
||||
ent.clip2 = self:GetData( "Clip2" )
|
||||
end
|
||||
|
||||
function ITEM:Use( pl )
|
||||
if not CustomShipments[ self:GetData( "Contents" ) ] then return end
|
||||
if pl:isArrested() then return end
|
||||
|
||||
local class = CustomShipments[ self:GetData( "Contents" ) ].entity
|
||||
|
||||
local wep_table = weapons.Get( class )
|
||||
local ammo, ammo_type
|
||||
|
||||
if wep_table then
|
||||
ammo_type = wep_table.Primary.Ammo
|
||||
|
||||
if ammo_type then
|
||||
ammo = pl:GetAmmoCount( ammo_type )
|
||||
end
|
||||
end
|
||||
|
||||
local wep = pl:Give( class )
|
||||
|
||||
if ammo and ammo_type then
|
||||
pl:SetAmmo( ammo, ammo_type )
|
||||
end
|
||||
|
||||
local weapon_exists = false
|
||||
|
||||
if not IsValid( wep ) then
|
||||
wep = pl:GetWeapon( class )
|
||||
weapon_exists = IsValid( wep )
|
||||
end
|
||||
|
||||
if IsValid( wep ) and wep:IsWeapon() then
|
||||
if self:GetData( "Clip1" ) then
|
||||
if weapon_exists then
|
||||
pl:GiveAmmo( self:GetData( "Clip1" ), wep:GetPrimaryAmmoType() )
|
||||
else
|
||||
wep:SetClip1( self:GetData( "Clip1" ) )
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetData( "Clip2" ) then
|
||||
if weapon_exists then
|
||||
pl:GiveAmmo( self:GetData( "Clip2" ), wep:GetSecondaryAmmoType() )
|
||||
else
|
||||
wep:SetClip2( self:GetData( "Clip2" ) )
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetData( "Ammo" ) then
|
||||
pl:GiveAmmo( self:GetData( "Ammo" ), wep:GetPrimaryAmmoType() )
|
||||
elseif wep.Primary and wep.Primary.DefaultClip then
|
||||
pl:GiveAmmo( wep.Primary.DefaultClip, wep:GetPrimaryAmmoType() )
|
||||
end
|
||||
end
|
||||
|
||||
return self:TakeOne()
|
||||
end
|
||||
234
addons/itemstore/lua/itemstore/items/spawned_weapon.lua
Normal file
234
addons/itemstore/lua/itemstore/items/spawned_weapon.lua
Normal file
@@ -0,0 +1,234 @@
|
||||
ITEM.Name = itemstore.Translate( "weapon_name" )
|
||||
ITEM.Description = itemstore.Translate( "weapon_desc" )
|
||||
ITEM.Model = "models/weapons/w_pistol.mdl"
|
||||
ITEM.HighlightColor = itemstore.config.HighlightColours.Weapons
|
||||
ITEM.Base = "base_darkrp"
|
||||
ITEM.Stackable = true
|
||||
|
||||
ITEM.Weapons = {
|
||||
weapon_physgun = itemstore.Translate( "weapon_physgun" ),
|
||||
weapon_physcannon = itemstore.Translate( "weapon_physcannon" ),
|
||||
weapon_crowbar = itemstore.Translate( "weapon_crowbar" ),
|
||||
weapon_stunstick = itemstore.Translate( "weapon_stunstick" ),
|
||||
weapon_pistol = itemstore.Translate( "weapon_pistol" ),
|
||||
weapon_357 = itemstore.Translate( "weapon_357" ),
|
||||
weapon_smg1 = itemstore.Translate( "weapon_smg1" ),
|
||||
weapon_ar2 = itemstore.Translate( "weapon_ar2" ),
|
||||
weapon_annabelle = itemstore.Translate( "weapon_annabelle" ),
|
||||
weapon_shotgun = itemstore.Translate( "weapon_shotgun" ),
|
||||
weapon_crossbow = itemstore.Translate( "weapon_crossbow" ),
|
||||
weapon_frag = itemstore.Translate( "weapon_frag" ),
|
||||
weapon_rpg = itemstore.Translate( "weapon_rpg" ),
|
||||
weapon_slam = itemstore.Translate( "weapon_slam" ),
|
||||
weapon_bugbait = itemstore.Translate( "weapon_bugbait" )
|
||||
}
|
||||
|
||||
function ITEM:IsValid()
|
||||
return self.Weapons[ self:GetData( "Class" ) ] or weapons.Get( self:GetData( "Class" ) )
|
||||
end
|
||||
|
||||
function ITEM:GetWeaponClass( wep )
|
||||
return wep.GetWeaponClass and wep:GetWeaponClass() or wep.weaponclass
|
||||
end
|
||||
|
||||
function ITEM:GetName()
|
||||
local name = self.Name
|
||||
|
||||
if self.Weapons[ self:GetData( "Class" ) ] then
|
||||
name = self.Weapons[ self:GetData( "Class" ) ]
|
||||
end
|
||||
|
||||
local wep_class = weapons.Get( self:GetData( "Class" ) )
|
||||
if wep_class and wep_class.PrintName then
|
||||
name = wep_class.PrintName
|
||||
end
|
||||
|
||||
return self:GetData( "Name", name )
|
||||
end
|
||||
|
||||
function ITEM:GetDescription()
|
||||
local desc = self.Description
|
||||
|
||||
local clip = self:GetData( "Clip1", 0 )
|
||||
local reserve = self:GetData( "Ammo", 0 )
|
||||
|
||||
return self:GetData( "Description", string.format( desc, clip, reserve ) )
|
||||
end
|
||||
|
||||
function ITEM:CanPickup( pl, ent )
|
||||
if self.MaxStack < ent:Getamount() then return false end
|
||||
if ent.PlayerUse then return false end
|
||||
if not weapons.Get( self:GetData( "Class" ) ) and
|
||||
not self.Weapons[ self:GetData( "Class" ) ] then return false end
|
||||
if itemstore.config.DisabledItems[ self:GetData( "Class" ) ] then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ITEM:CanMerge( item )
|
||||
return self.Stackable and item:GetClass() == self:GetClass() and
|
||||
item:GetData( "Class" ) == self:GetData( "Class" ) and
|
||||
self.MaxStack >= self:GetAmount() + item:GetAmount()
|
||||
end
|
||||
|
||||
function ITEM:Merge( item )
|
||||
self:SetAmount( self:GetAmount() + item:GetAmount() )
|
||||
|
||||
self:SetData( "Clip2", item:GetData( "Clip2", 0 ) + self:GetData( "Clip2", 0 ) )
|
||||
self:SetData( "Ammo", item:GetData( "Ammo", 0 ) + self:GetData( "Ammo", 0 )
|
||||
+ item:GetData( "Clip1", 0 ) )
|
||||
end
|
||||
|
||||
-- 76561198068291318
|
||||
|
||||
function ITEM:Split( amount )
|
||||
self:SetAmount( self:GetAmount() - amount )
|
||||
|
||||
local item = self:Copy()
|
||||
item:SetAmount( amount )
|
||||
|
||||
self:SetData( "Clip1", 0 )
|
||||
self:SetData( "Clip2", 0 )
|
||||
self:SetData( "Ammo", 0 )
|
||||
|
||||
return item
|
||||
end
|
||||
|
||||
function ITEM:SaveData( ent )
|
||||
self:SetData( "Class", self:GetWeaponClass( ent ) )
|
||||
self:SetData( "Amount", ent:Getamount() )
|
||||
self:SetData( "Model", ent:GetModel() )
|
||||
|
||||
if ent.clip1 then self:SetData( "Clip1", ent.clip1 ) end
|
||||
if ent.clip2 then self:SetData( "Clip2", ent.clip2 ) end
|
||||
|
||||
local reserve = 0
|
||||
if ent.clip1 and ent:Getamount() > 1 then
|
||||
reserve = reserve + ent.clip1 * ( ent:Getamount() - 1 )
|
||||
end
|
||||
|
||||
if ent.ammoadd then
|
||||
reserve = reserve + ent.ammoadd * ent:Getamount()
|
||||
end
|
||||
|
||||
self:SetData( "Ammo", reserve )
|
||||
end
|
||||
|
||||
function ITEM:LoadData( ent )
|
||||
ent:SetModel( self:GetData( "Model" ) )
|
||||
ent:Setamount( 1 )
|
||||
|
||||
if ent.GetWeaponClass then
|
||||
ent:SetWeaponClass( self:GetData( "Class" ) )
|
||||
else
|
||||
ent.weaponclass = self:GetData( "Class" )
|
||||
end
|
||||
|
||||
ent.clip1 = math.floor( self:GetData( "Clip1", 0 ) / ent:Getamount() )
|
||||
ent.clip2 = math.floor( self:GetData( "Clip2", 0 ) / ent:Getamount() )
|
||||
ent.ammoadd = math.floor( self:GetData( "Ammo", 0 ) / ent:Getamount() )
|
||||
|
||||
self:SetData( "Clip1", 0 )
|
||||
self:SetData( "Clip2", 0 )
|
||||
self:SetData( "Ammo", 0 )
|
||||
|
||||
function ent:Initialize()
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
self:GetPhysicsObject():Wake()
|
||||
|
||||
self:SetCollisionGroup( COLLISION_GROUP_INTERACTIVE_DEBRIS )
|
||||
end
|
||||
end
|
||||
|
||||
local hl2_ammo = {
|
||||
weapon_pistol = 3,
|
||||
weapon_357 = 5,
|
||||
weapon_smg1 = 4,
|
||||
weapon_ar2 = 1,
|
||||
weapon_annabelle = 7,
|
||||
weapon_shotgun = 7,
|
||||
weapon_crossbow = 6,
|
||||
weapon_frag = 10,
|
||||
weapon_rpg = 8,
|
||||
}
|
||||
|
||||
function ITEM:Use( pl )
|
||||
if pl:isArrested() then return false end
|
||||
|
||||
local class = self:GetData( "Class" )
|
||||
|
||||
if not self.Weapons[ class ] and
|
||||
not weapons.Get( class ) then return false end
|
||||
|
||||
-- taken from darkrp. may or may not work.
|
||||
if GAMEMODE.Config.license and not pl:getDarkRPVar("HasGunlicense") and not pl.RPLicenseSpawn then
|
||||
if not GAMEMODE.NoLicense[string.lower(class)] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local has_weapon = pl:HasWeapon( class )
|
||||
|
||||
local wep_table = weapons.Get( class )
|
||||
local ammo, ammo_type
|
||||
|
||||
if wep_table then
|
||||
ammo_type = wep_table.Primary.Ammo
|
||||
else
|
||||
ammo_type = hl2_ammo[ class ]
|
||||
end
|
||||
|
||||
if ammo_type then
|
||||
ammo = pl:GetAmmoCount( ammo_type )
|
||||
end
|
||||
|
||||
pl:Give( class )
|
||||
|
||||
if ammo and ammo_type then
|
||||
pl:SetAmmo( ammo, ammo_type )
|
||||
end
|
||||
|
||||
local wep = pl:GetWeapon( class )
|
||||
|
||||
-- make sure we actually gave the weapon before we start deducting stuff
|
||||
if not IsValid( wep ) then return end
|
||||
|
||||
if self:GetData( "Clip1" ) then
|
||||
if has_weapon then
|
||||
pl:GiveAmmo( self:GetData( "Clip1" ), wep:GetPrimaryAmmoType() )
|
||||
else
|
||||
wep:SetClip1( self:GetData( "Clip1" ) )
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetData( "Clip2" ) then
|
||||
if has_weapon then
|
||||
pl:GiveAmmo( self:GetData( "Clip2" ), wep:GetPrimaryAmmoType() )
|
||||
else
|
||||
wep:SetClip2( self:GetData( "Clip2" ) )
|
||||
end
|
||||
end
|
||||
|
||||
self:SetData( "Clip1", 0 )
|
||||
self:SetData( "Clip2", 0 )
|
||||
|
||||
if itemstore.config.SplitWeaponAmmo then
|
||||
if self:GetData( "Ammo" ) then
|
||||
local reserve = self:GetData( "Ammo" )
|
||||
local amount = self:GetAmount()
|
||||
|
||||
local ammo = math.min( math.ceil( reserve / amount ), reserve )
|
||||
|
||||
pl:GiveAmmo( ammo, wep:GetPrimaryAmmoType() )
|
||||
self:SetData( "Ammo", reserve - ammo )
|
||||
end
|
||||
else
|
||||
pl:GiveAmmo( self:GetData( "Ammo", 0 ), wep:GetPrimaryAmmoType() )
|
||||
self:SetData( "Ammo", 0 )
|
||||
end
|
||||
|
||||
return self:TakeOne()
|
||||
end
|
||||
13
addons/itemstore/lua/itemstore/language.lua
Normal file
13
addons/itemstore/lua/itemstore/language.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
itemstore.Language = {}
|
||||
|
||||
LANGUAGE = {}
|
||||
include( "languages/" .. itemstore.config.Language .. ".lua" )
|
||||
if SERVER then AddCSLuaFile( "languages/" .. itemstore.config.Language .. ".lua" ) end
|
||||
itemstore.Language = LANGUAGE
|
||||
LANGUAGE = nil
|
||||
|
||||
assert( itemstore.Language, "[ItemStore] Language not found" )
|
||||
|
||||
function itemstore.Translate( trans, ... )
|
||||
return string.format( itemstore.Language[ trans ] or trans, ... )
|
||||
end
|
||||
111
addons/itemstore/lua/itemstore/languages/cn.lua
Normal file
111
addons/itemstore/lua/itemstore/languages/cn.lua
Normal file
@@ -0,0 +1,111 @@
|
||||
-- ATTN: Be extremely careful when translating this file.
|
||||
-- All of the %s, %d, etc variables must be retained when translating.
|
||||
|
||||
-- Generic stuff
|
||||
LANGUAGE.ok = "OK"
|
||||
LANGUAGE.cancel = "取消"
|
||||
LANGUAGE.not_permitted = "你没有权限执行这个指令."
|
||||
LANGUAGE.file_not_found = "文件未找到"
|
||||
LANGUAGE.player_not_found = "玩家未找到"
|
||||
LANGUAGE.invalid_data = "数据错误"
|
||||
LANGUAGE.invalid_args = "数据错误"
|
||||
LANGUAGE.cant_fit = "你不能把这个塞进口袋!"
|
||||
|
||||
-- Various inventory lines
|
||||
LANGUAGE.page = "页数 %d"
|
||||
LANGUAGE.inventory = "库存"
|
||||
LANGUAGE.bank = "Bank"
|
||||
LANGUAGE.players_inventory = "%s的库存"
|
||||
LANGUAGE.players_bank = "%s的银行"
|
||||
LANGUAGE.admin_title = "管理员"
|
||||
|
||||
-- Slot options
|
||||
LANGUAGE.move = "移动"
|
||||
LANGUAGE.use = "使用"
|
||||
LANGUAGE.usewith = "使用..."
|
||||
LANGUAGE.drop = "扔出"
|
||||
LANGUAGE.destroy = "删除"
|
||||
LANGUAGE.destroy_title = "删除物品"
|
||||
LANGUAGE.destroy_confirmation = "你真的想要删除这个吗,它将不会被恢复!"
|
||||
LANGUAGE.merge = "合并"
|
||||
LANGUAGE.split = "拆分"
|
||||
LANGUAGE.split_half = "一半 (%d)"
|
||||
LANGUAGE.picked_up = "你捡起了个 %s."
|
||||
|
||||
-- Slot help
|
||||
LANGUAGE.dragtomove = "鼠标按住以拖动"
|
||||
LANGUAGE.mclicktodrop = "鼠标中键以扔出"
|
||||
LANGUAGE.rclickforoptions = "鼠标右键设置"
|
||||
LANGUAGE.dclicktouse = "双击以使用"
|
||||
|
||||
-- Trading
|
||||
LANGUAGE.ready = "准备"
|
||||
LANGUAGE.not_ready = "未准备"
|
||||
LANGUAGE.accept = "接受"
|
||||
LANGUAGE.deny = "拒绝"
|
||||
LANGUAGE.trading_with = "与 %s 交易"
|
||||
LANGUAGE.trade_request = "交易请求"
|
||||
LANGUAGE.wants_to_trade = "%s 想和你交易"
|
||||
LANGUAGE.too_far_away = "你离的太远了."
|
||||
LANGUAGE.trading_cooldown = "冷却中请等待."
|
||||
LANGUAGE.trade_failed = "交易失败,你没有足够的钱!"
|
||||
|
||||
-- Items
|
||||
|
||||
LANGUAGE.drug_name = "毒品"
|
||||
LANGUAGE.drug_desc = "爽爽爽."
|
||||
|
||||
LANGUAGE.druglab_name = "毒品台"
|
||||
LANGUAGE.druglab_desc = "不要被警察看见!"
|
||||
|
||||
LANGUAGE.food_name = "食物"
|
||||
LANGUAGE.food_desc = "Nom.\n\nNutritional value: %%d"
|
||||
LANGUAGE.microwavefood_desc = "Nom."
|
||||
|
||||
LANGUAGE.food_melon = "西瓜"
|
||||
LANGUAGE.food_orange = "橘子"
|
||||
LANGUAGE.food_bananas = "一把香蕉"
|
||||
LANGUAGE.food_banana = "香蕉"
|
||||
LANGUAGE.food_glassbottle = "玻璃瓶"
|
||||
LANGUAGE.food_soda = "汽水"
|
||||
LANGUAGE.food_milk = "牛奶"
|
||||
LANGUAGE.food_beer = "啤酒"
|
||||
LANGUAGE.food_twolitresoda = "2 汽水"
|
||||
LANGUAGE.food_onelitresoda = "1 汽水"
|
||||
|
||||
LANGUAGE.gunlab_name = "武器制造器"
|
||||
LANGUAGE.gunlab_desc = "造枪的."
|
||||
|
||||
LANGUAGE.microwave_name = "微波炉"
|
||||
LANGUAGE.microwave_desc = "为什么他外面是热的里面是冷的!?"
|
||||
|
||||
LANGUAGE.moneyprinter_name = "印钞机"
|
||||
LANGUAGE.moneyprinter_desc = "钱!"
|
||||
|
||||
LANGUAGE.ammo_name = "弹药"
|
||||
LANGUAGE.ammo_desc = "biu biu biu"
|
||||
|
||||
LANGUAGE.money_name = "钱"
|
||||
LANGUAGE.money_desc = "世界之主."
|
||||
|
||||
LANGUAGE.shipment_name = "货物"
|
||||
LANGUAGE.shipment_desc = "货物\n\n数量: %%s"
|
||||
LANGUAGE.shipment_invalid = "错误 请删掉他"
|
||||
|
||||
LANGUAGE.weapon_name = "武器"
|
||||
LANGUAGE.weapon_desc = "一把可以装备的武器.\n弹药: %%d\n备弹: %%d"
|
||||
LANGUAGE.weapon_physgun = "物理枪"
|
||||
LANGUAGE.weapon_physcannon = "重力枪"
|
||||
LANGUAGE.weapon_crowbar = "撬棍"
|
||||
LANGUAGE.weapon_stunstick = "电棍"
|
||||
LANGUAGE.weapon_pistol = "手枪"
|
||||
LANGUAGE.weapon_357 = "357左轮"
|
||||
LANGUAGE.weapon_smg1 = "冲锋枪1"
|
||||
LANGUAGE.weapon_ar2 = "脉冲枪2"
|
||||
LANGUAGE.weapon_annabelle = "猎枪"
|
||||
LANGUAGE.weapon_shotgun = "霰弹枪"
|
||||
LANGUAGE.weapon_crossbow = "弩"
|
||||
LANGUAGE.weapon_frag = "手榴弹"
|
||||
LANGUAGE.weapon_rpg = "RPG"
|
||||
LANGUAGE.weapon_slam = "S.L.A.M."
|
||||
LANGUAGE.weapon_bugbait = "翔"
|
||||
112
addons/itemstore/lua/itemstore/languages/de.lua
Normal file
112
addons/itemstore/lua/itemstore/languages/de.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
-- ATTN: Be extremely careful when translating this file.
|
||||
-- All of the %s, %d, etc variables must be retained when translating.
|
||||
-- translated by GreenAurora! ;) (http://steamcommunity.com/id/nVrAm/)
|
||||
|
||||
-- Generic stuff
|
||||
LANGUAGE.ok = "Ok"
|
||||
LANGUAGE.cancel = "Zurück"
|
||||
LANGUAGE.not_permitted = "Du hast keinen Zugriff auf diese Funktion."
|
||||
LANGUAGE.file_not_found = "Datei konnte nicht gefunden werden!"
|
||||
LANGUAGE.player_not_found = "Der Spieler wurde nicht gefunden!"
|
||||
LANGUAGE.invalid_data = "Ungültige Datei angegeben!"
|
||||
LANGUAGE.invalid_args = "Ungültige Argumente angegeben!"
|
||||
LANGUAGE.cant_fit = "Dieses Item ist zu groß für dein Inventar!"
|
||||
|
||||
-- Various inventory lines
|
||||
LANGUAGE.page = "Seite %d"
|
||||
LANGUAGE.inventory = "Inventar"
|
||||
LANGUAGE.bank = "Lager"
|
||||
LANGUAGE.players_inventory = "%s's Inventar"
|
||||
LANGUAGE.players_bank = "%s's Lager"
|
||||
LANGUAGE.admin_title = "ItemStore Admin"
|
||||
|
||||
-- Slot options
|
||||
LANGUAGE.move = "Verschieben"
|
||||
LANGUAGE.use = "Verwenden"
|
||||
LANGUAGE.usewith = "Verwenden mit..."
|
||||
LANGUAGE.drop = "Fallen lassen"
|
||||
LANGUAGE.destroy = "Zerstören"
|
||||
LANGUAGE.destroy_title = "Item zerstören"
|
||||
LANGUAGE.destroy_confirmation = "Bist du dir sicher, dass du dieses Item zerstören möchtest?"
|
||||
LANGUAGE.merge = "Zusammenfügen"
|
||||
LANGUAGE.split = "Aufteilen"
|
||||
LANGUAGE.split_half = "Halbieren (%d)"
|
||||
LANGUAGE.picked_up = "Du packst ein(e/n) %s in dein Inventar."
|
||||
|
||||
-- Slot help
|
||||
LANGUAGE.dragtomove = "Klicken und ziehen zum verschieben!"
|
||||
LANGUAGE.mclicktodrop = "Mittlere Maustaste zum fallen lassen."
|
||||
LANGUAGE.rclickforoptions = "Rechts-Klick für Optionen."
|
||||
LANGUAGE.dclicktouse = "Doppelklick zum Benutzen."
|
||||
|
||||
-- Trading
|
||||
LANGUAGE.ready = "Bereit"
|
||||
LANGUAGE.not_ready = "Nicht Bereit"
|
||||
LANGUAGE.accept = "Akzeptieren"
|
||||
LANGUAGE.deny = "Ablehnen"
|
||||
LANGUAGE.trading_with = "Handeln mit %s"
|
||||
LANGUAGE.trade_request = "Handelsanfrage"
|
||||
LANGUAGE.wants_to_trade = "%s möchte mit dir handeln!"
|
||||
LANGUAGE.too_far_away = "Du bist zu weit weg, um mit dieser Person zu handeln."
|
||||
LANGUAGE.trading_cooldown = "Du musst einen Moment warten, bevor du wieder handeln kannst."
|
||||
LANGUAGE.trade_failed = "Handel fehlgeschlagen! Einer der beiden Handelspartner hat weniger Geld, als er angeboten hat!"
|
||||
|
||||
-- Items
|
||||
|
||||
LANGUAGE.drug_name = "Drogen"
|
||||
LANGUAGE.drug_desc = "aaaaaaalteeeeer.."
|
||||
|
||||
LANGUAGE.druglab_name = "Drogenlabor"
|
||||
LANGUAGE.druglab_desc = "Also das sollte die Polizei nicht unbedingt sehen.."
|
||||
|
||||
LANGUAGE.food_name = "Nahrung"
|
||||
LANGUAGE.food_desc = "Mhhmm..\n\nNährwert: %%d"
|
||||
LANGUAGE.microwavefood_desc = "Mhhmm.."
|
||||
|
||||
LANGUAGE.food_melon = "Melone"
|
||||
LANGUAGE.food_orange = "Orange"
|
||||
LANGUAGE.food_bananas = "Bananen"
|
||||
LANGUAGE.food_banana = "Banane"
|
||||
LANGUAGE.food_glassbottle = "Glasflasche"
|
||||
LANGUAGE.food_soda = "Dosenwasser"
|
||||
LANGUAGE.food_milk = "Milch"
|
||||
LANGUAGE.food_beer = "Bier"
|
||||
LANGUAGE.food_twolitresoda = "2 Liter Wasser"
|
||||
LANGUAGE.food_onelitresoda = "1 Liter Wasser"
|
||||
|
||||
LANGUAGE.gunlab_name = "Waffenlabor"
|
||||
LANGUAGE.gunlab_desc = "Es produziert Waffen.. WOW!"
|
||||
|
||||
LANGUAGE.microwave_name = "Mikrowelle"
|
||||
LANGUAGE.microwave_desc = "Wieso ist das Essen außen total heiß und innen noch kalt?!"
|
||||
|
||||
LANGUAGE.moneyprinter_name = "Moneyprinter"
|
||||
LANGUAGE.moneyprinter_desc = "Druckt dir die Scheinchen"
|
||||
|
||||
LANGUAGE.ammo_name = "Munition"
|
||||
LANGUAGE.ammo_desc = "Die Dinger, die vorn aus den Waffen rauskommen."
|
||||
|
||||
LANGUAGE.money_name = "Geld"
|
||||
LANGUAGE.money_desc = "Geld?! GELD!"
|
||||
|
||||
LANGUAGE.shipment_name = "Lieferung"
|
||||
LANGUAGE.shipment_desc = "Eine Lieferung.\n\nInhalt: %%s"
|
||||
LANGUAGE.shipment_invalid = "ERROR: Lieferung ungültig. Bitte lösche es."
|
||||
|
||||
LANGUAGE.weapon_name = "Waffe"
|
||||
LANGUAGE.weapon_desc = "Eine nutzbare Waffe.\nMunition im Magazin: %%d\nMunition verfügbar: %%d"
|
||||
LANGUAGE.weapon_physgun = "Physgun"
|
||||
LANGUAGE.weapon_physcannon = "Gravity Gun"
|
||||
LANGUAGE.weapon_crowbar = "Crowbar"
|
||||
LANGUAGE.weapon_stunstick = "Stunstick"
|
||||
LANGUAGE.weapon_pistol = "Pistol"
|
||||
LANGUAGE.weapon_357 = "357"
|
||||
LANGUAGE.weapon_smg1 = "SMG1"
|
||||
LANGUAGE.weapon_ar2 = "AR2"
|
||||
LANGUAGE.weapon_annabelle = "Annabelle"
|
||||
LANGUAGE.weapon_shotgun = "Shotgun"
|
||||
LANGUAGE.weapon_crossbow = "HL2 Armbrust"
|
||||
LANGUAGE.weapon_frag = "Frag Grenade"
|
||||
LANGUAGE.weapon_rpg = "RPG"
|
||||
LANGUAGE.weapon_slam = "S.L.A.M."
|
||||
LANGUAGE.weapon_bugbait = "Bug Bait"
|
||||
118
addons/itemstore/lua/itemstore/languages/en.lua
Normal file
118
addons/itemstore/lua/itemstore/languages/en.lua
Normal file
@@ -0,0 +1,118 @@
|
||||
-- ATTN: Be extremely careful when translating this file.
|
||||
-- All of the %s, %d, etc variables must be retained when translating.
|
||||
|
||||
-- Generic stuff
|
||||
LANGUAGE.ok = "OK"
|
||||
LANGUAGE.cancel = "Cancel"
|
||||
LANGUAGE.not_permitted = "You are not permitted to perform this action."
|
||||
LANGUAGE.file_not_found = "File not found"
|
||||
LANGUAGE.player_not_found = "Player not found"
|
||||
LANGUAGE.invalid_data = "Invalid data"
|
||||
LANGUAGE.invalid_args = "Invalid arguments"
|
||||
LANGUAGE.cant_fit = "You can't fit that in your inventory!"
|
||||
|
||||
-- Various inventory lines
|
||||
LANGUAGE.page = "Page %d"
|
||||
LANGUAGE.inventory = "Inventory"
|
||||
LANGUAGE.bank = "Bank"
|
||||
LANGUAGE.players_inventory = "%s's Inventory"
|
||||
LANGUAGE.players_bank = "%s's Bank"
|
||||
LANGUAGE.admin_title = "ItemStore Admin"
|
||||
|
||||
-- Slot options
|
||||
LANGUAGE.move = "Move"
|
||||
LANGUAGE.use = "Use"
|
||||
LANGUAGE.usewith = "Use with..."
|
||||
LANGUAGE.drop = "Drop"
|
||||
LANGUAGE.destroy = "Destroy"
|
||||
LANGUAGE.destroy_title = "Destroy Item"
|
||||
LANGUAGE.destroy_confirmation = "Are you sure you want to delete this item? You won't be able to get it back!"
|
||||
LANGUAGE.merge = "Merge"
|
||||
LANGUAGE.split = "Split"
|
||||
LANGUAGE.split_half = "Half (%d)"
|
||||
LANGUAGE.picked_up = "You picked up a(n) %s."
|
||||
|
||||
-- Slot help
|
||||
LANGUAGE.dragtomove = "Click and drag to move"
|
||||
LANGUAGE.mclicktodrop = "Middle-click to drop"
|
||||
LANGUAGE.rclickforoptions = "Right-click for options"
|
||||
LANGUAGE.dclicktouse = "Double-click to use"
|
||||
|
||||
-- Trading
|
||||
LANGUAGE.ready = "Ready"
|
||||
LANGUAGE.not_ready = "Not ready"
|
||||
LANGUAGE.accept = "Accept"
|
||||
LANGUAGE.deny = "Deny"
|
||||
LANGUAGE.trading_with = "Trading with %s"
|
||||
LANGUAGE.trade_request = "Trade request"
|
||||
LANGUAGE.wants_to_trade = "%s wants to trade"
|
||||
LANGUAGE.too_far_away = "You are too far away to initiate a trade."
|
||||
LANGUAGE.trading_cooldown = "You must wait a bit before you can trade again."
|
||||
LANGUAGE.trade_failed = "Trade failed. Either you or your partner tried to offer more money than you had!"
|
||||
LANGUAGE.cant_access_inventory = "You can't trade if you don't have access to an inventory."
|
||||
LANGUAGE.partner_cant_access_inventory = "You can't trade with a partner who doesn't have access to an inventory."
|
||||
LANGUAGE.partner_is_in_trade = "You can't trade with a partner who is already in a trade."
|
||||
LANGUAGE.already_in_trade = "You're already trading with someone else."
|
||||
|
||||
-- Items
|
||||
|
||||
LANGUAGE.drug_name = "Drugs"
|
||||
LANGUAGE.drug_desc = "Duuuuuuuude."
|
||||
|
||||
LANGUAGE.druglab_name = "Drug Lab"
|
||||
LANGUAGE.druglab_desc = "Don't let it be seen by the CPs!"
|
||||
|
||||
LANGUAGE.food_name = "Food"
|
||||
LANGUAGE.food_desc = "Nom.\n\nNutritional value: %%d"
|
||||
LANGUAGE.microwavefood_desc = "Nom."
|
||||
|
||||
LANGUAGE.food_melon = "Melon"
|
||||
LANGUAGE.food_orange = "Orange"
|
||||
LANGUAGE.food_bananas = "Bunch of Bananas"
|
||||
LANGUAGE.food_banana = "Banana"
|
||||
LANGUAGE.food_glassbottle = "Glass Bottle"
|
||||
LANGUAGE.food_soda = "Can of Soda"
|
||||
LANGUAGE.food_milk = "Milk"
|
||||
LANGUAGE.food_beer = "Beer"
|
||||
LANGUAGE.food_twolitresoda = "2 Litre Soda"
|
||||
LANGUAGE.food_onelitresoda = "1 Litre Soda"
|
||||
|
||||
LANGUAGE.gunlab_name = "Gun Lab"
|
||||
LANGUAGE.gunlab_desc = "A lab that makes guns. DUH."
|
||||
|
||||
LANGUAGE.microwave_name = "Microwave"
|
||||
LANGUAGE.microwave_desc = "Why is it always burning hot on the outside but freezing in the middle!?"
|
||||
|
||||
LANGUAGE.moneyprinter_name = "Money Printer"
|
||||
LANGUAGE.moneyprinter_desc = "Dealing out that cash money"
|
||||
|
||||
LANGUAGE.ammo_name = "Ammo"
|
||||
LANGUAGE.ammo_desc = "Things that you shoot out of a gun."
|
||||
|
||||
LANGUAGE.money_name = "Money"
|
||||
LANGUAGE.money_desc = "Lods of emone."
|
||||
|
||||
LANGUAGE.prop_name = "Prop"
|
||||
LANGUAGE.prop_desc = "Hit people with this to get banned."
|
||||
|
||||
LANGUAGE.shipment_name = "Shipment"
|
||||
LANGUAGE.shipment_desc = "A shipment of guns.\n\nContents: %%s"
|
||||
LANGUAGE.shipment_invalid = "ERROR: Shipment invalid. Delete this item!"
|
||||
|
||||
LANGUAGE.weapon_name = "Weapon"
|
||||
LANGUAGE.weapon_desc = "An equippable weapon.\nAmmo in magazine: %%d\nAmmo in reserve: %%d"
|
||||
LANGUAGE.weapon_physgun = "Physgun"
|
||||
LANGUAGE.weapon_physcannon = "Gravity Gun"
|
||||
LANGUAGE.weapon_crowbar = "Crowbar"
|
||||
LANGUAGE.weapon_stunstick = "Stunstick"
|
||||
LANGUAGE.weapon_pistol = "Pistol"
|
||||
LANGUAGE.weapon_357 = "357"
|
||||
LANGUAGE.weapon_smg1 = "SMG1"
|
||||
LANGUAGE.weapon_ar2 = "AR2"
|
||||
LANGUAGE.weapon_annabelle = "Annabelle"
|
||||
LANGUAGE.weapon_shotgun = "Shotgun"
|
||||
LANGUAGE.weapon_crossbow = "Crossbow"
|
||||
LANGUAGE.weapon_frag = "Frag Grenade"
|
||||
LANGUAGE.weapon_rpg = "RPG"
|
||||
LANGUAGE.weapon_slam = "S.L.A.M."
|
||||
LANGUAGE.weapon_bugbait = "Bug Bait"
|
||||
114
addons/itemstore/lua/itemstore/languages/fr.lua
Normal file
114
addons/itemstore/lua/itemstore/languages/fr.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
-- ATTN: Be extremely careful when translating this file.
|
||||
-- All of the %s, %d, etc variables must be retained when translating.
|
||||
|
||||
-- Thank you so much max360! All credits for this french translation go to him.
|
||||
-- http://steamcommunity.com/profiles/76561197990386123
|
||||
|
||||
-- Generic stuff
|
||||
LANGUAGE.ok = "OK"
|
||||
LANGUAGE.cancel = "Annuler"
|
||||
LANGUAGE.not_permitted = "Il ne vous est pas permis de réaliser cette action."
|
||||
LANGUAGE.file_not_found = "Fichier non trouvé"
|
||||
LANGUAGE.player_not_found = "Joueur non trouvé"
|
||||
LANGUAGE.invalid_data = "Données invalides"
|
||||
LANGUAGE.invalid_args = "Arguments invalides"
|
||||
LANGUAGE.cant_fit = "Vous ne pouvez pas faire rentrer ça dans votre inventaire!"
|
||||
|
||||
-- Various inventory lines
|
||||
LANGUAGE.page = "Page %d"
|
||||
LANGUAGE.inventory = "Inventaire"
|
||||
LANGUAGE.bank = "Banque"
|
||||
LANGUAGE.players_inventory = "Inventaire de %s"
|
||||
LANGUAGE.players_bank = "Banque de %s"
|
||||
LANGUAGE.admin_title = "Admin ItemStore"
|
||||
|
||||
-- Slot options
|
||||
LANGUAGE.move = "Déplacer"
|
||||
LANGUAGE.use = "Utiliser"
|
||||
LANGUAGE.usewith = "Utiliser avec..."
|
||||
LANGUAGE.drop = "Lâcher"
|
||||
LANGUAGE.destroy = "Détruire"
|
||||
LANGUAGE.destroy_title = "Détruire Item"
|
||||
LANGUAGE.destroy_confirmation = "Etes-vous sûr de vouloir supprimer cet item? Il ne vous sera pas possible de le récupérer!"
|
||||
LANGUAGE.merge = "Fusionner"
|
||||
LANGUAGE.split = "Diviser"
|
||||
LANGUAGE.split_half = "Moitié (%d)"
|
||||
LANGUAGE.picked_up = "Vous avez pris un(e) %s."
|
||||
|
||||
-- Slot help
|
||||
LANGUAGE.dragtomove = "Cliquez et faites glisser pour déplacer"
|
||||
LANGUAGE.mclicktodrop = "Clic du milieu pour lâcher"
|
||||
LANGUAGE.rclickforoptions = "Clic-droit pour les options"
|
||||
LANGUAGE.dclicktouse = "Double-clic pour utiliser"
|
||||
|
||||
-- Trading
|
||||
LANGUAGE.ready = "Prêt"
|
||||
LANGUAGE.not_ready = "Pas prêt"
|
||||
LANGUAGE.accept = "Accepter"
|
||||
LANGUAGE.deny = "Refuser"
|
||||
LANGUAGE.trading_with = "Echange avec %s"
|
||||
LANGUAGE.trade_request = "Demande d'échange"
|
||||
LANGUAGE.wants_to_trade = "%s veut échanger"
|
||||
LANGUAGE.too_far_away = "Vous êtes trop loin pour initier un échange."
|
||||
LANGUAGE.trading_cooldown = "Vous devez attendre un peu avant de pouvoir échanger de nouveau."
|
||||
LANGUAGE.trade_failed = "L'échange a échoué. Soit vous soit votre partenaire a essayé de donner plus d'argent qu'il n'en avait!"
|
||||
|
||||
-- Items
|
||||
|
||||
LANGUAGE.drug_name = "Drogues"
|
||||
LANGUAGE.drug_desc = "Meeeeeeeeec."
|
||||
|
||||
LANGUAGE.druglab_name = "Labo à drogue"
|
||||
LANGUAGE.druglab_desc = "Ne laissez pas la PC le voir!"
|
||||
|
||||
LANGUAGE.food_name = "Nourriture"
|
||||
LANGUAGE.food_desc = "Miam.\n\nValeur nutritionnelle: %%d"
|
||||
LANGUAGE.microwavefood_desc = "Miam."
|
||||
|
||||
LANGUAGE.food_melon = "Melon"
|
||||
LANGUAGE.food_orange = "Orange"
|
||||
LANGUAGE.food_bananas = "Grappe de bananes"
|
||||
LANGUAGE.food_banana = "Banane"
|
||||
LANGUAGE.food_glassbottle = "Bouteille en verre"
|
||||
LANGUAGE.food_soda = "Cannette de soda"
|
||||
LANGUAGE.food_milk = "Lait"
|
||||
LANGUAGE.food_beer = "Bière"
|
||||
LANGUAGE.food_twolitresoda = "Soda 2 Litre"
|
||||
LANGUAGE.food_onelitresoda = "Soda 1 Litre"
|
||||
|
||||
LANGUAGE.gunlab_name = "Labo à armes"
|
||||
LANGUAGE.gunlab_desc = "Un labo qui fabrique des armes. TOH."
|
||||
|
||||
LANGUAGE.microwave_name = "Micro-ondes"
|
||||
LANGUAGE.microwave_desc = "Pourquoi ça brûle toujours sur l'extérieur et reste froid au milieu!?"
|
||||
|
||||
LANGUAGE.moneyprinter_name = "Imprimante à argent"
|
||||
LANGUAGE.moneyprinter_desc = "Dealez cet argent comptant"
|
||||
|
||||
LANGUAGE.ammo_name = "Munitions"
|
||||
LANGUAGE.ammo_desc = "Les choses que vous tirez hors du pistolet."
|
||||
|
||||
LANGUAGE.money_name = "Argent"
|
||||
LANGUAGE.money_desc = "Lods of emone."
|
||||
|
||||
LANGUAGE.shipment_name = "Colis"
|
||||
LANGUAGE.shipment_desc = "Un colis d'armes.\n\nContenu: %%s"
|
||||
LANGUAGE.shipment_invalid = "ERREUR: Colis invalide. Supprimez cet item!"
|
||||
|
||||
LANGUAGE.weapon_name = "Arme"
|
||||
LANGUAGE.weapon_desc = "Une arme équipable.\nMunitions dans le chargeur: %%d\nMunitions en réserve: %%d"
|
||||
LANGUAGE.weapon_physgun = "Physgun"
|
||||
LANGUAGE.weapon_physcannon = "Gravity Gun"
|
||||
LANGUAGE.weapon_crowbar = "Pied de biche"
|
||||
LANGUAGE.weapon_stunstick = "Matraque"
|
||||
LANGUAGE.weapon_pistol = "Pistolet"
|
||||
LANGUAGE.weapon_357 = "357"
|
||||
LANGUAGE.weapon_smg1 = "SMG1"
|
||||
LANGUAGE.weapon_ar2 = "AR2"
|
||||
LANGUAGE.weapon_annabelle = "Annabelle"
|
||||
LANGUAGE.weapon_shotgun = "Fusil à pompe"
|
||||
LANGUAGE.weapon_crossbow = "Arbalette"
|
||||
LANGUAGE.weapon_frag = "Grenade à fragmentation"
|
||||
LANGUAGE.weapon_rpg = "RPG"
|
||||
LANGUAGE.weapon_slam = "S.L.A.M."
|
||||
LANGUAGE.weapon_bugbait = "Appât à insectes"
|
||||
45
addons/itemstore/lua/itemstore/languages/ru.lua
Normal file
45
addons/itemstore/lua/itemstore/languages/ru.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
-- Thank you for this Russian translation, Horo!
|
||||
-- http://steamcommunity.com/id/HoroRu/
|
||||
|
||||
LANGUAGE.ok = "OK"
|
||||
LANGUAGE.cancel = "Отмена"
|
||||
|
||||
LANGUAGE.not_permitted = "У вас нет доступа к этому действию."
|
||||
LANGUAGE.file_not_found = "Файл не найден"
|
||||
LANGUAGE.player_not_found = "Игрок не найден"
|
||||
LANGUAGE.invalid_data = "Неправильные данные"
|
||||
LANGUAGE.invalid_args = "Неправильные аргументы"
|
||||
LANGUAGE.cant_fit = "Это не поместится в ваш инвентарь!"
|
||||
|
||||
LANGUAGE.page = "Страница %d"
|
||||
LANGUAGE.inventory = "Инвентарь"
|
||||
LANGUAGE.bank = "Банк"
|
||||
LANGUAGE.players_inventory = "Инвентарь %s"
|
||||
LANGUAGE.players_bank = "Банк %s"
|
||||
LANGUAGE.admin_title = "ItemStore Админ"
|
||||
|
||||
LANGUAGE.move = "Переместить"
|
||||
LANGUAGE.use = "Использовать"
|
||||
LANGUAGE.usewith = "Использовать с..."
|
||||
LANGUAGE.drop = "Бросить"
|
||||
LANGUAGE.destroy = "Уничтожить"
|
||||
LANGUAGE.merge = "Совместить"
|
||||
LANGUAGE.split = "Разделить"
|
||||
LANGUAGE.split_half = "Поделить пополам (%d)"
|
||||
|
||||
LANGUAGE.picked_up = "Вы подняли (n) %s."
|
||||
|
||||
LANGUAGE.destroy_title = "Унчитожить предмет"
|
||||
LANGUAGE.destroy_confirmation = "Вы уверены что хотите удалить предмет? Это действие необратимо!"
|
||||
|
||||
LANGUAGE.ready = "Готово"
|
||||
LANGUAGE.not_ready = "не готово"
|
||||
LANGUAGE.accept = "Принять"
|
||||
LANGUAGE.deny = "Отказаться"
|
||||
LANGUAGE.trading_with = "Обмен с %s"
|
||||
LANGUAGE.trade_request = "Запрос обмена"
|
||||
LANGUAGE.wants_to_trade = "%s хочет обменятся"
|
||||
LANGUAGE.too_far_away = "Вы слишком далеко чтобы обениваться."
|
||||
LANGUAGE.trading_cooldown = "Вы должны немного подождать чтобы обмениваться снова."
|
||||
|
||||
LANGUAGE.trade_failed = "Обмен не заверешен. Вы или ваш партнер затребовали больше денег чем у вас/у него есть!"
|
||||
118
addons/itemstore/lua/itemstore/languages/tr.lua
Normal file
118
addons/itemstore/lua/itemstore/languages/tr.lua
Normal file
@@ -0,0 +1,118 @@
|
||||
-- ATTN: Be extremely careful when translating this file.
|
||||
-- All of the %s, %d, etc variables must be retained when translating.
|
||||
|
||||
-- Generic stuff
|
||||
LANGUAGE.ok = "Tamam"
|
||||
LANGUAGE.cancel = "Iptal"
|
||||
LANGUAGE.not_permitted = "Bu eylemi gerceklestirmeye iznin yok."
|
||||
LANGUAGE.file_not_found = "Dosya bulunamadi"
|
||||
LANGUAGE.player_not_found = "Oyuncu bulunamadi"
|
||||
LANGUAGE.invalid_data = "Gecersiz veri"
|
||||
LANGUAGE.invalid_args = "Gecersiz argumanlar"
|
||||
LANGUAGE.cant_fit = "Envanterine bunu sigdiramazsin!"
|
||||
|
||||
-- Various inventory lines
|
||||
LANGUAGE.page = "Sayfa %d"
|
||||
LANGUAGE.inventory = "Envanter"
|
||||
LANGUAGE.bank = "Banka"
|
||||
LANGUAGE.players_inventory = "%s's Envanteri"
|
||||
LANGUAGE.players_bank = "%s's Bankasi"
|
||||
LANGUAGE.admin_title = "ItemStore Admin"
|
||||
|
||||
-- Slot options
|
||||
LANGUAGE.move = "Tasi"
|
||||
LANGUAGE.use = "Kullan"
|
||||
LANGUAGE.usewith = "Ile kullan..."
|
||||
LANGUAGE.drop = "Birak"
|
||||
LANGUAGE.destroy = "Yok Et"
|
||||
LANGUAGE.destroy_title = "Esyayi Yok Et"
|
||||
LANGUAGE.destroy_confirmation = "Esyayi silmek istedigine emin misin? Geri alamiyacaksin!"
|
||||
LANGUAGE.merge = "Birlestir"
|
||||
LANGUAGE.split = "Bol"
|
||||
LANGUAGE.split_half = "Yarim (%d)"
|
||||
LANGUAGE.picked_up = "Su esyayi aldin %s."
|
||||
|
||||
-- Slot help
|
||||
LANGUAGE.dragtomove = "Haraket ettirmek icin farenin sol tusuna tikla ve surukle"
|
||||
LANGUAGE.mclicktodrop = "Birakmak icin farenin tekerlegine tikla"
|
||||
LANGUAGE.rclickforoptions = "Ayarlar icin sag tik"
|
||||
LANGUAGE.dclicktouse = "2 kez tiklayarak kullan"
|
||||
|
||||
-- Trading
|
||||
LANGUAGE.ready = "Hazir"
|
||||
LANGUAGE.not_ready = "Hazir Degil"
|
||||
LANGUAGE.accept = "Kabul"
|
||||
LANGUAGE.deny = "Red"
|
||||
LANGUAGE.trading_with = "%s ile takas yapiliyor"
|
||||
LANGUAGE.trade_request = "Takas istegi"
|
||||
LANGUAGE.wants_to_trade = "%s takas yapmak istiyor"
|
||||
LANGUAGE.too_far_away = "Takas yapmak icin cok uzaksin."
|
||||
LANGUAGE.trading_cooldown = "Yeniden takas yapmak icin biraz beklemen lazim."
|
||||
LANGUAGE.trade_failed = "Takas basarisiz. Siz veya takas yaptiginiz kisi sahip oldugunuzdan daha fazla para teklif etmeye calisti!"
|
||||
LANGUAGE.cant_access_inventory = "Envantere erisiminiz yoksa takas yapamazsiniz."
|
||||
LANGUAGE.partner_cant_access_inventory = "Envanterine erisimi olmayan biri ile takas yapamazsiniz."
|
||||
LANGUAGE.partner_is_in_trade = "Halihazirda takas yapan biriyle takas yapamazsiniz."
|
||||
LANGUAGE.already_in_trade = "Halihazirda bir takas yaparken baskasiyla takas yapamazsiniz."
|
||||
|
||||
-- Items
|
||||
|
||||
LANGUAGE.drug_name = "Uyusturucular"
|
||||
LANGUAGE.drug_desc = "Dostuuuuum."
|
||||
|
||||
LANGUAGE.druglab_name = "Uyusturucu Laboratuvari"
|
||||
LANGUAGE.druglab_desc = "Polislerin bizi bulmasina sakin izin verme!"
|
||||
|
||||
LANGUAGE.food_name = "Yemek"
|
||||
LANGUAGE.food_desc = "Leziz.\n\nNutritional value: %%d"
|
||||
LANGUAGE.microwavefood_desc = "Leziz."
|
||||
|
||||
LANGUAGE.food_melon = "Karpuz"
|
||||
LANGUAGE.food_orange = "Portakal"
|
||||
LANGUAGE.food_bananas = "Salkim Muz"
|
||||
LANGUAGE.food_banana = "Muz"
|
||||
LANGUAGE.food_glassbottle = "Cam Sise"
|
||||
LANGUAGE.food_soda = "Kutu Soda"
|
||||
LANGUAGE.food_milk = "Sut"
|
||||
LANGUAGE.food_beer = "Bira"
|
||||
LANGUAGE.food_twolitresoda = "2 Litre Soda"
|
||||
LANGUAGE.food_onelitresoda = "1 Litre Soda"
|
||||
|
||||
LANGUAGE.gunlab_name = "Silah Laboratuvari"
|
||||
LANGUAGE.gunlab_desc = "Silah yapmani saglayan bi laboratuvar.Baska ne olabilir amk."
|
||||
|
||||
LANGUAGE.microwave_name = "Mikrodalga"
|
||||
LANGUAGE.microwave_desc = "Neden hep dis tarafi soguk ama ic taraflari soguk!?"
|
||||
|
||||
LANGUAGE.moneyprinter_name = "Para Makinasi"
|
||||
LANGUAGE.moneyprinter_desc = "Sanal para ile ugrasmak istemeyenler icin ideal.Kodumunun boomeri"
|
||||
|
||||
LANGUAGE.ammo_name = "Mermi"
|
||||
LANGUAGE.ammo_desc = "Silahtan firlayan sey var ya he iste o."
|
||||
|
||||
LANGUAGE.money_name = "Para"
|
||||
LANGUAGE.money_desc = "Gotunu sildigin maddeyi almani saglayan ancak ayni maddelerden yapilan sey."
|
||||
|
||||
LANGUAGE.prop_name = "Prop"
|
||||
LANGUAGE.prop_desc = "Baskasina bunla vur asiri eglenceli oluyo. Banlanma."
|
||||
|
||||
LANGUAGE.shipment_name = "Kargo"
|
||||
LANGUAGE.shipment_desc = "Silah Kargosu.\n\nContents: %%s"
|
||||
LANGUAGE.shipment_invalid = "HATA: Kargo gecersiz. Bu esyayi sil!"
|
||||
|
||||
LANGUAGE.weapon_name = "Silah"
|
||||
LANGUAGE.weapon_desc = "Kullanılabilen bir silah.\nAmmo Şarjorde: %%d\nAmmo Reservde: %%d"
|
||||
LANGUAGE.weapon_physgun = "Physgun"
|
||||
LANGUAGE.weapon_physcannon = "Gravity Gun"
|
||||
LANGUAGE.weapon_crowbar = "Crowbar"
|
||||
LANGUAGE.weapon_stunstick = "Stunstick"
|
||||
LANGUAGE.weapon_pistol = "Pistol"
|
||||
LANGUAGE.weapon_357 = "357"
|
||||
LANGUAGE.weapon_smg1 = "SMG1"
|
||||
LANGUAGE.weapon_ar2 = "AR2"
|
||||
LANGUAGE.weapon_annabelle = "Annabelle"
|
||||
LANGUAGE.weapon_shotgun = "Shotgun"
|
||||
LANGUAGE.weapon_crossbow = "Crossbow"
|
||||
LANGUAGE.weapon_frag = "Frag Grenade"
|
||||
LANGUAGE.weapon_rpg = "RPG"
|
||||
LANGUAGE.weapon_slam = "S.L.A.M."
|
||||
LANGUAGE.weapon_bugbait = "Bug Bait"
|
||||
113
addons/itemstore/lua/itemstore/shared.lua
Normal file
113
addons/itemstore/lua/itemstore/shared.lua
Normal file
@@ -0,0 +1,113 @@
|
||||
itemstore.Version = "3.0"
|
||||
itemstore.About = string.format( [[ItemStore v%s
|
||||
|
||||
Authored solely by UselessGhost
|
||||
http://steamcommunity.com/id/uselessghost
|
||||
]], itemstore.Version )
|
||||
|
||||
MsgC( color_white, "ItemStore", Color( 100, 200, 255 ), " ", itemstore.Version, " ", Color( 200, 200, 200 ), "coded by ", Color( 255, 150, 150 ), "UselessGhost", "\n" )
|
||||
|
||||
concommand.Add( "itemstore_about", function()
|
||||
MsgC( color_white, itemstore.About )
|
||||
end )
|
||||
|
||||
itemstore.config = {}
|
||||
|
||||
function itemstore.config.Verify( setting, correct_type )
|
||||
if type( itemstore.config[ setting ] ) ~= correct_type then
|
||||
ErrorNoHalt( string.format( "[ItemStore] Configuration error: %s is %s, should be %s.", setting, var_type, correct_type ) )
|
||||
--include( "config_default.lua" )
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
include( "config.lua" )
|
||||
|
||||
itemstore.config.Verify( "MaxStack", "number" )
|
||||
itemstore.config.Verify( "DataProvider", "string" )
|
||||
itemstore.config.Verify( "GamemodeProvider", "string" )
|
||||
itemstore.config.Verify( "Language", "string" )
|
||||
itemstore.config.Verify( "ContextInventory", "boolean" )
|
||||
itemstore.config.Verify( "ContextInventoryPosition", "string" )
|
||||
itemstore.config.Verify( "InvholsterTakesAmmo", "boolean" )
|
||||
itemstore.config.Verify( "PickupsGotoBank", "boolean" )
|
||||
itemstore.config.Verify( "AntiDupe", "boolean" )
|
||||
itemstore.config.Verify( "InventorySizes", "table" )
|
||||
itemstore.config.Verify( "BankSizes", "table" )
|
||||
itemstore.config.Verify( "PickupDistance", "number" )
|
||||
itemstore.config.Verify( "PickupKey", "number" )
|
||||
itemstore.config.Verify( "Colours", "table" )
|
||||
itemstore.config.Verify( "DisabledItems", "table" )
|
||||
itemstore.config.Verify( "CustomItems", "table" )
|
||||
itemstore.config.Verify( "IgnoreOwner", "boolean" )
|
||||
itemstore.config.Verify( "Skin", "string" )
|
||||
itemstore.config.Verify( "SplitWeaponAmmo", "boolean" )
|
||||
itemstore.config.Verify( "MigrateOldData", "boolean" )
|
||||
itemstore.config.Verify( "EnableInvholster", "boolean" )
|
||||
itemstore.config.Verify( "LimitToJobs", "table" )
|
||||
itemstore.config.Verify( "HighlightStyle", "string" )
|
||||
itemstore.config.Verify( "HighlightColours", "table" )
|
||||
|
||||
include( "language.lua" )
|
||||
include( "gamemodes.lua" )
|
||||
include( "items.lua" )
|
||||
include( "containers.lua" )
|
||||
include( "trading.lua" )
|
||||
include( "admin.lua" )
|
||||
|
||||
local _, dirs = file.Find( "itemstore/modules/*", "LUA" )
|
||||
for _, mod in ipairs( dirs ) do
|
||||
MsgC( color_white, string.format( "Loading ItemStore module: %s\n", mod ) )
|
||||
|
||||
local path = "itemstore/modules/" .. mod
|
||||
|
||||
for _, filename in ipairs( file.Find( path .. "/*.lua", "LUA" ) ) do
|
||||
if not string.match( filename, "^sv_.+%.lua$" ) then
|
||||
AddCSLuaFile( path .. "/" .. filename )
|
||||
end
|
||||
end
|
||||
|
||||
local sv_init = path .. "/sv_init.lua"
|
||||
local cl_init = path .. "/cl_init.lua"
|
||||
local shared = path .. "/shared.lua"
|
||||
|
||||
if file.Exists( shared, "LUA" ) then
|
||||
include( shared )
|
||||
end
|
||||
|
||||
if SERVER and file.Exists( sv_init, "LUA" ) then
|
||||
include( sv_init )
|
||||
end
|
||||
|
||||
if CLIENT and file.Exists( cl_init, "LUA" ) then
|
||||
include( cl_init )
|
||||
end
|
||||
end
|
||||
|
||||
local teams = nil
|
||||
local meta = FindMetaTable( "Player" )
|
||||
|
||||
function meta:CanUseInventory()
|
||||
if self:IsAdmin() then return true end -- always allow admins to access their inventories
|
||||
if not self:Alive() then return false end -- using your inventory while dead can be a bit exploitable
|
||||
|
||||
if #itemstore.config.LimitToJobs > 0 then
|
||||
-- process this into an associative table for faster lookups
|
||||
if not teams then
|
||||
teams = {}
|
||||
|
||||
for k, v in pairs( itemstore.config.LimitToJobs ) do
|
||||
teams[ v ] = true
|
||||
end
|
||||
end
|
||||
|
||||
if not teams[ self:Team() ] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
76
addons/itemstore/lua/itemstore/skins/classic.lua
Normal file
76
addons/itemstore/lua/itemstore/skins/classic.lua
Normal file
@@ -0,0 +1,76 @@
|
||||
local SKIN = {}
|
||||
|
||||
SKIN.GradientUp = Material( "gui/gradient_up" )
|
||||
SKIN.GradientDown = Material( "gui/gradient_down" )
|
||||
SKIN.Blur = Material( "pp/blurscreen" )
|
||||
|
||||
function SKIN:PaintFrame( panel, w, h )
|
||||
self.Blur:SetFloat( "$blur", 2 )
|
||||
self.Blur:Recompute()
|
||||
render.UpdateScreenEffectTexture()
|
||||
|
||||
local x, y = panel:LocalToScreen( 0, 0 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255 )
|
||||
surface.SetMaterial( self.Blur )
|
||||
surface.DrawTexturedRect( x * -1, y * -1, ScrW(), ScrH() )
|
||||
|
||||
surface.SetDrawColor( itemstore.config.Colours.Lower )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
|
||||
surface.SetMaterial( self.GradientDown )
|
||||
surface.SetDrawColor( itemstore.config.Colours.Upper )
|
||||
surface.DrawTexturedRect( 0, 0, w, h )
|
||||
|
||||
surface.SetDrawColor( itemstore.config.Colours.OuterBorder )
|
||||
surface.DrawOutlinedRect( 0, 0, w, h )
|
||||
|
||||
surface.SetDrawColor( itemstore.config.Colours.InnerBorder )
|
||||
surface.DrawOutlinedRect( 1, 1, w - 2, h - 2 )
|
||||
|
||||
surface.SetDrawColor( itemstore.config.Colours.TitleBackground )
|
||||
surface.DrawRect( 2, 2, w - 4 , 22 )
|
||||
end
|
||||
|
||||
function SKIN:PaintButton( panel, w, h )
|
||||
surface.SetDrawColor( Color( 200, 200, 200 ) )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
|
||||
if not panel.Disabled then
|
||||
surface.SetMaterial( panel.Depressed and self.GradientUp or self.GradientDown )
|
||||
surface.SetDrawColor( panel.Hovered and Color( 240, 240, 240 ) or Color( 230, 230, 230 ) )
|
||||
surface.DrawTexturedRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
surface.SetDrawColor( Color( 0, 0, 0, 150 ) )
|
||||
surface.DrawOutlinedRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
function SKIN:PaintTab( panel, w, h )
|
||||
if panel:IsActive() then
|
||||
surface.SetMaterial( self.GradientDown )
|
||||
surface.SetDrawColor( itemstore.config.Colours.Lower )
|
||||
surface.DrawTexturedRect( 2, 0, w - 5, h )
|
||||
else
|
||||
surface.SetMaterial( self.GradientUp )
|
||||
surface.SetDrawColor( itemstore.config.Colours.Upper )
|
||||
surface.DrawTexturedRect( 2, 0, w - 5, h )
|
||||
end
|
||||
end
|
||||
|
||||
function SKIN:PaintPropertySheet( panel, w, h )
|
||||
surface.SetDrawColor( itemstore.config.Colours.Lower )
|
||||
surface.DrawRect( 0, 20, w, h )
|
||||
|
||||
surface.SetMaterial( self.GradientDown )
|
||||
surface.SetDrawColor( itemstore.config.Colours.Upper )
|
||||
surface.DrawTexturedRect( 0, 20, w, h - 20 )
|
||||
|
||||
surface.SetDrawColor( itemstore.config.Colours.OuterBorder )
|
||||
surface.DrawOutlinedRect( 0, 20, w, h - 20 )
|
||||
|
||||
surface.SetDrawColor( itemstore.config.Colours.InnerBorder )
|
||||
surface.DrawOutlinedRect( 1, 21, w - 2, h - 22 )
|
||||
end
|
||||
|
||||
derma.DefineSkin( "itemstore", "Skin for ItemStore", SKIN )
|
||||
117
addons/itemstore/lua/itemstore/skins/flat.lua
Normal file
117
addons/itemstore/lua/itemstore/skins/flat.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
local SKIN = {}
|
||||
|
||||
SKIN.GradientUp = Material( "gui/gradient_up" )
|
||||
SKIN.GradientDown = Material( "gui/gradient_down" )
|
||||
SKIN.Blur = Material( "pp/blurscreen" )
|
||||
|
||||
function SKIN:PaintFrame( panel, w, h )
|
||||
self.Blur:SetFloat( "$blur", 8 )
|
||||
self.Blur:Recompute()
|
||||
render.UpdateScreenEffectTexture()
|
||||
|
||||
local x, y = panel:LocalToScreen( 0, 0 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255 )
|
||||
surface.SetMaterial( self.Blur )
|
||||
surface.DrawTexturedRect( x * -1, y * -1, ScrW(), ScrH() )
|
||||
|
||||
surface.SetDrawColor( Color( 30, 30, 30, 200 ) )
|
||||
surface.DrawRect( 0, 22, w, h - 22 )
|
||||
|
||||
surface.SetDrawColor( Color( 44, 62, 80 ) )
|
||||
surface.DrawRect( 0, 0, w, 22 )
|
||||
end
|
||||
|
||||
function SKIN:PaintButton( panel, w, h )
|
||||
surface.SetDrawColor( Color( 200, 200, 200 ) )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
|
||||
if not panel.Disabled then
|
||||
surface.SetMaterial( panel.Depressed and self.GradientUp or self.GradientDown )
|
||||
surface.SetDrawColor( panel.Hovered and Color( 240, 240, 240 ) or Color( 230, 230, 230 ) )
|
||||
surface.DrawTexturedRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
surface.SetDrawColor( Color( 0, 0, 0, 150 ) )
|
||||
surface.DrawOutlinedRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
function SKIN:PaintTab( panel, w, h )
|
||||
if panel:IsActive() then
|
||||
draw.RoundedBoxEx( 2, 2, 0, w - 5, h - 8, Color( 0, 0, 0, 200 ),
|
||||
true, true, false, false )
|
||||
else
|
||||
draw.RoundedBoxEx( 2, 2, 0, w - 5, h, Color( 0, 0, 0, 150 ),
|
||||
true, true, false, false )
|
||||
end
|
||||
end
|
||||
|
||||
function SKIN:PaintPropertySheet( panel, w, h )
|
||||
surface.SetDrawColor( Color( 0, 0, 0, 200 ) )
|
||||
surface.DrawRect( 0, 20, w, h )
|
||||
end
|
||||
|
||||
function SKIN:PaintCategoryList( panel, w, h )
|
||||
end
|
||||
|
||||
function SKIN:PaintCollapsibleCategory( panel, w, h )
|
||||
surface.SetDrawColor( Color( 0, 0, 0, 150 ) )
|
||||
surface.DrawRect( 0, 0, w, 20 )
|
||||
|
||||
surface.SetDrawColor( Color( 0, 0, 0, 150 ) )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
function SKIN:PaintWindowCloseButton( panel, w, h )
|
||||
local col = Color( 0, 0, 0, 50 )
|
||||
|
||||
if not panel:GetDisabled() and panel.Hovered then
|
||||
if panel:IsDown() then
|
||||
col = Color( 192, 57, 43 )
|
||||
else
|
||||
col = Color( 231, 76, 60 )
|
||||
end
|
||||
end
|
||||
|
||||
draw.RoundedBoxEx( 4, 0, 2, w, 18, col, true, true, true, true )
|
||||
draw.SimpleText( "r", "Marlett", w / 2, 11, color_white,
|
||||
TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
|
||||
function SKIN:PaintWindowMaximizeButton( panel, w, h )
|
||||
if panel:GetDisabled() then return end
|
||||
|
||||
local col = Color( 0, 0, 0, 50 )
|
||||
|
||||
if panel.Hovered then
|
||||
if panel:IsDown() then
|
||||
col = Color( 41, 128, 185 )
|
||||
else
|
||||
col = Color( 52, 152, 219 )
|
||||
end
|
||||
end
|
||||
|
||||
draw.RoundedBoxEx( 4, 0, 2, w, 18, col, false, false, false, false )
|
||||
draw.SimpleText( "1", "Marlett", w / 2, 11, color_white,
|
||||
TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
|
||||
function SKIN:PaintWindowMinimizeButton( panel, w, h )
|
||||
if true then return end
|
||||
|
||||
local col = Color( 0, 0, 0, 50 )
|
||||
|
||||
if panel.Hovered then
|
||||
if panel:IsDown() then
|
||||
col = Color( 41, 128, 185 )
|
||||
else
|
||||
col = Color( 52, 152, 219 )
|
||||
end
|
||||
end
|
||||
|
||||
draw.RoundedBoxEx( 4, 0, 2, w, 18, col, true, false, true, false )
|
||||
draw.SimpleText( "0", "Marlett", w / 2, 11, color_white,
|
||||
TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
|
||||
derma.DefineSkin( "itemstore", "Flat skin for ItemStore", SKIN )
|
||||
34
addons/itemstore/lua/itemstore/sv_commands.lua
Normal file
34
addons/itemstore/lua/itemstore/sv_commands.lua
Normal file
@@ -0,0 +1,34 @@
|
||||
itemstore.Commands = {}
|
||||
|
||||
function itemstore.AddCommand( cmd, callback )
|
||||
itemstore.Commands[ cmd ] = callback
|
||||
end
|
||||
|
||||
function itemstore.RunCommand( pl, cmd, args )
|
||||
local func = itemstore.Commands[ cmd ]
|
||||
if not func or not isfunction( func ) then return end
|
||||
|
||||
return func( pl, args )
|
||||
end
|
||||
|
||||
function itemstore.CommandExists( cmd )
|
||||
return itemstore.Commands[ cmd ] ~= nil
|
||||
end
|
||||
|
||||
hook.Add( "PlayerSay", "ItemStoreCommand", function( pl, text, team )
|
||||
local args = string.Explode( " ", text, false )
|
||||
local cmd = table.remove( args, 1 )
|
||||
|
||||
if not string.StartWith( cmd, itemstore.config.ChatCommandPrefix ) then
|
||||
return
|
||||
end
|
||||
|
||||
cmd = string.sub( cmd, 2 )
|
||||
|
||||
if not itemstore.CommandExists( cmd ) then
|
||||
return
|
||||
end
|
||||
|
||||
itemstore.RunCommand( pl, cmd, args )
|
||||
return ""
|
||||
end )
|
||||
142
addons/itemstore/lua/itemstore/sv_data.lua
Normal file
142
addons/itemstore/lua/itemstore/sv_data.lua
Normal file
@@ -0,0 +1,142 @@
|
||||
itemstore.data = {}
|
||||
|
||||
PROVIDER = {}
|
||||
include( "dataproviders/" .. itemstore.config.DataProvider .. ".lua" )
|
||||
itemstore.data.Provider = PROVIDER
|
||||
PROVIDER = nil
|
||||
|
||||
assert( itemstore.data.Provider, "[ItemStore] Data provider not found" )
|
||||
|
||||
if not file.IsDir( "itemstore", "DATA" ) then file.CreateDir( "itemstore" ) end
|
||||
if not file.IsDir( "itemstore/banks", "DATA" ) then file.CreateDir( "itemstore/banks" ) end
|
||||
|
||||
function itemstore.data.Run( func_name, ... )
|
||||
local func = itemstore.data.Provider[ func_name ]
|
||||
|
||||
if func then
|
||||
return func( itemstore.data.Provider, ... )
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.data.Initialize()
|
||||
itemstore.data.Run( "Initialize" )
|
||||
end
|
||||
|
||||
itemstore.data.Initialize()
|
||||
|
||||
function itemstore.data.LoadInventory( pl )
|
||||
pl.InventoryLoaded = false
|
||||
itemstore.data.Run( "LoadInventory", pl )
|
||||
end
|
||||
|
||||
function itemstore.data.SaveInventory( pl )
|
||||
if pl.InventoryLoaded then
|
||||
itemstore.data.Run( "SaveInventory", pl )
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.data.LoadBank( pl )
|
||||
pl.BankLoaded = false
|
||||
itemstore.data.Run( "LoadBank", pl )
|
||||
end
|
||||
|
||||
function itemstore.data.SaveBank( pl )
|
||||
if pl.BankLoaded then
|
||||
itemstore.data.Run( "SaveBank", pl )
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.data.Load( pl )
|
||||
itemstore.data.LoadInventory( pl )
|
||||
itemstore.data.LoadBank( pl )
|
||||
end
|
||||
|
||||
function itemstore.data.LoadAll()
|
||||
for _, pl in ipairs( player.GetAll() ) do
|
||||
itemstore.data.Load( pl )
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.data.Save( pl )
|
||||
itemstore.data.SaveInventory( pl )
|
||||
itemstore.data.SaveBank( pl )
|
||||
end
|
||||
|
||||
function itemstore.data.SaveAll()
|
||||
for _, pl in ipairs( player.GetAll() ) do
|
||||
itemstore.data.Save( pl )
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.data.Export( filename )
|
||||
return itemstore.data.Run( "Export", filename )
|
||||
end
|
||||
|
||||
function itemstore.data.Import( data )
|
||||
return itemstore.data.Run( "Import", data )
|
||||
end
|
||||
|
||||
require( "json" )
|
||||
|
||||
concommand.Add( "itemstore_import", function( pl, cmd, args )
|
||||
if IsValid( pl ) and not pl:IsSuperAdmin() then
|
||||
itemstore.Print( pl, itemstore.Translate( "not_permitted" ) )
|
||||
return
|
||||
end
|
||||
|
||||
local json = file.Read( args[ 1 ], "DATA" )
|
||||
if not json then
|
||||
itemstore.Print( pl, itemstore.Translate( "file_not_found" ) )
|
||||
return
|
||||
end
|
||||
|
||||
local data = JSON:decode( json )
|
||||
if not data then
|
||||
itemstore.Print( pl, itemstore.Translate( "invalid_data" ) )
|
||||
end
|
||||
|
||||
itemstore.data.Import( data )
|
||||
end )
|
||||
|
||||
concommand.Add( "itemstore_export", function( pl, cmd, args )
|
||||
if IsValid( pl ) and not pl:IsSuperAdmin() then
|
||||
itemstore.Print( pl, itemstore.Translate( "not_permitted" ) )
|
||||
return
|
||||
end
|
||||
|
||||
itemstore.data.Export( args[ 1 ] or os.date( "itemstore_export_%Y-%m-%d-%H-%M-%S.txt" ) )
|
||||
end )
|
||||
|
||||
-- we don't need any of these periodic saving things if we're using saveonwrite
|
||||
timer.Create( "ItemStoreSave", itemstore.config.SaveInterval, 0, function()
|
||||
if itemstore.config.SaveOnWrite then return end
|
||||
|
||||
itemstore.data.SaveAll()
|
||||
end )
|
||||
|
||||
-- save when we shutdown.
|
||||
-- not called on crash tho
|
||||
hook.Add( "ShutDown", "ItemStoreSaveOnShutdown", function()
|
||||
itemstore.data.SaveAll()
|
||||
end )
|
||||
|
||||
-- make sure we actually save on disconnect
|
||||
-- using the game event here cause PlayerDisconnected is called inconsistently, prolly cause of a shitty addon
|
||||
gameevent.Listen( "player_disconnect" )
|
||||
hook.Add( "player_disconnect", "ItemStoreSaveOnDisconnectFix", function( data )
|
||||
local pl = player.GetBySteamID( data.networkid )
|
||||
if not IsValid( pl ) then return end
|
||||
|
||||
itemstore.data.Save( pl )
|
||||
end )
|
||||
|
||||
hook.Add( "Tick", "ItemStoreSaveOnWrite", function()
|
||||
if not itemstore.config.SaveOnWrite then return end
|
||||
|
||||
for _, pl in ipairs( player.GetAll() ) do
|
||||
if pl.NextInventorySave and pl.NextInventorySave < CurTime() then
|
||||
itemstore.data.Save( pl )
|
||||
pl.NextInventorySave = nil
|
||||
end
|
||||
end
|
||||
end )
|
||||
102
addons/itemstore/lua/itemstore/sv_init.lua
Normal file
102
addons/itemstore/lua/itemstore/sv_init.lua
Normal file
@@ -0,0 +1,102 @@
|
||||
include( "sv_commands.lua" )
|
||||
|
||||
include( "shared.lua" )
|
||||
|
||||
include( "sv_data.lua" )
|
||||
include( "sv_player.lua" )
|
||||
--include( "sv_statistics.lua" )
|
||||
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
AddCSLuaFile( "language.lua" )
|
||||
AddCSLuaFile( "cl_player.lua" )
|
||||
AddCSLuaFile( "containers.lua" )
|
||||
AddCSLuaFile( "items.lua" )
|
||||
AddCSLuaFile( "gamemodes.lua" )
|
||||
AddCSLuaFile( "config.lua" )
|
||||
AddCSLuaFile( "admin.lua" )
|
||||
AddCSLuaFile( "trading.lua" )
|
||||
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "cl_gui.lua" )
|
||||
|
||||
AddCSLuaFile( "skins/" .. itemstore.config.Skin .. ".lua" )
|
||||
|
||||
for _, filename in ipairs( file.Find( "itemstore/vgui/*.lua", "LUA" ) ) do
|
||||
AddCSLuaFile( "itemstore/vgui/" .. filename )
|
||||
end
|
||||
|
||||
if itemstore.config.AntiDupe then
|
||||
local meta = FindMetaTable( "Entity" )
|
||||
local oldRemove = meta.Remove
|
||||
|
||||
function meta:Remove()
|
||||
if IsValid( self ) then
|
||||
self.__Deleted = true
|
||||
end
|
||||
|
||||
oldRemove( self )
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.Print( pl, text )
|
||||
if IsValid( pl ) then
|
||||
pl:PrintMessage( HUD_PRINTCONSOLE, text )
|
||||
else
|
||||
print( text )
|
||||
end
|
||||
end
|
||||
|
||||
RunConsoleCommand( "lua_log_sv", 1 )
|
||||
|
||||
concommand.Add( "itemstore_support", function( pl, cmd, args )
|
||||
if IsValid( pl ) and not pl:IsSuperAdmin() then return end
|
||||
|
||||
local function respond( str )
|
||||
if IsValid( pl ) and false then
|
||||
pl:PrintMessage( HUD_PRINTCONSOLE, str )
|
||||
else
|
||||
print( str )
|
||||
end
|
||||
end
|
||||
|
||||
local token = args[ 1 ]
|
||||
if not token then
|
||||
respond( "Error: token not defined. Please create a support ticket and ask for one." )
|
||||
return
|
||||
end
|
||||
|
||||
local user = IsValid( pl ) and pl:Name() .. " (" .. pl:SteamID() .. ")" or "Console"
|
||||
local ip, port = string.match( game.GetIPAddress(), "(%d.%d.%d.%d):(%d)" )
|
||||
local hostname = GetHostName()
|
||||
local ws_addons, legacy_addons = file.Find( "addons/*", "GAME" )
|
||||
local config = file.Read( "itemstore/config.lua", "LUA" ) or ""
|
||||
local errors = file.Read( "lua_errors_server.txt", "GAME" ) or ""
|
||||
|
||||
respond( "Uploading support information..." )
|
||||
|
||||
http.Post( "https://uselessghost.me/itemstore/support.php", {
|
||||
token = token,
|
||||
user = user,
|
||||
ip = ip,
|
||||
port = port,
|
||||
hostname = hostname,
|
||||
ws_addons = util.TableToJSON( ws_addons ),
|
||||
legacy_addons = util.TableToJSON( legacy_addons ),
|
||||
config = config,
|
||||
errors = errors,
|
||||
}, function( data )
|
||||
local json = util.JSONToTable( data )
|
||||
|
||||
if not json then
|
||||
respond( "Error: Invalid data received." )
|
||||
respond( data )
|
||||
return
|
||||
end
|
||||
|
||||
if json.success then
|
||||
respond( "Support information uploaded." )
|
||||
else
|
||||
respond( "Support information upload failed: " .. json.error )
|
||||
end
|
||||
end )
|
||||
end )
|
||||
470
addons/itemstore/lua/itemstore/sv_player.lua
Normal file
470
addons/itemstore/lua/itemstore/sv_player.lua
Normal file
@@ -0,0 +1,470 @@
|
||||
ITEMSTORE_TIMEOUT = 0.25
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
|
||||
function meta:SetupInventory()
|
||||
local usergroup = self:GetUserGroup()
|
||||
|
||||
if serverguard then
|
||||
-- suck my dick serverguard, why don't you use gmod's default rank stuff
|
||||
usergroup = serverguard.player:GetRank( self )
|
||||
end
|
||||
|
||||
local inv_size = itemstore.config.InventorySizes[ usergroup ]
|
||||
|
||||
if not inv_size then
|
||||
inv_size = itemstore.config.InventorySizes[ "default" ]
|
||||
end
|
||||
|
||||
self.Inventory = itemstore.Container( unpack( inv_size ) )
|
||||
self.Inventory:SetOwner( self )
|
||||
self.Inventory:SetPermissions( self, true, true )
|
||||
|
||||
self.Inventory:AddCallback( "set", function()
|
||||
if IsValid( self ) then self:QueueInventorySave() end
|
||||
end )
|
||||
|
||||
self.Inventory:AddCallback( "read", function( con, pl )
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
local wep = pl:GetActiveWeapon()
|
||||
local dist = self:GetPos():Distance( pl:GetPos() )
|
||||
|
||||
if IsValid( wep ) and wep:GetClass() == "itemstore_checker" and dist < 250 then
|
||||
return true
|
||||
end
|
||||
end )
|
||||
|
||||
local bank_size = itemstore.config.BankSizes[ usergroup ]
|
||||
|
||||
if not bank_size then
|
||||
bank_size = itemstore.config.BankSizes[ "default" ]
|
||||
end
|
||||
|
||||
self.Bank = itemstore.Container( unpack( bank_size ) )
|
||||
self.Bank:SetOwner( self )
|
||||
self.Bank:AddCallback( "set", function()
|
||||
if IsValid( self ) then self:QueueInventorySave() end
|
||||
end )
|
||||
|
||||
local function callback( con, pl )
|
||||
if self ~= pl then return end
|
||||
|
||||
for _, ent in ipairs( ents.FindByClass( "itemstore_bank" ) ) do
|
||||
if ent:GetPos():Distance( pl:EyePos() ) < 256 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
self.Bank:AddCallback( "read", callback )
|
||||
self.Bank:AddCallback( "write", callback )
|
||||
|
||||
itemstore.data.Load( self )
|
||||
|
||||
hook.Run( "ItemStoreInventoryCreated", self, self.Inventory, self.Bank )
|
||||
|
||||
if itemstore.config.MigrateOldData then
|
||||
local path = "itemstore/" .. self:UniqueID() .. ".txt"
|
||||
|
||||
if file.Exists( path, "DATA" ) then
|
||||
local inv = util.JSONToTable( file.Read( path, "DATA" ) )
|
||||
|
||||
if inv then
|
||||
for k, v in ipairs( inv ) do
|
||||
self.Inventory:SetItem( k, itemstore.Item( v.UniqueName, v.Data ) )
|
||||
end
|
||||
|
||||
file.Delete( path, "DATA" )
|
||||
end
|
||||
end
|
||||
|
||||
local path = "itemstore/banks/" .. self:UniqueID() .. ".txt"
|
||||
|
||||
if file.Exists( path, "DATA" ) then
|
||||
local inv = util.JSONToTable( file.Read( path, "DATA" ) )
|
||||
|
||||
if inv then
|
||||
for k, v in ipairs( inv ) do
|
||||
self.Bank:SetItem( k, itemstore.Item( v.UniqueName, v.Data ) )
|
||||
end
|
||||
|
||||
file.Delete( path, "DATA" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self.Inventory, self.Bank
|
||||
end
|
||||
|
||||
function meta:PickupItem( ent )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
ent = ent or util.QuickTrace( self:GetShootPos(),
|
||||
self:GetAimVector() * itemstore.config.PickupDistance, self ).Entity
|
||||
|
||||
if not IsValid( ent ) or ent.__Deleted or not itemstore.items.Pickups[ ent:GetClass() ] then
|
||||
return false end
|
||||
|
||||
local class = itemstore.items.Pickups[ ent:GetClass() ]
|
||||
if itemstore.config.DisabledItems[ class ] then return false end
|
||||
|
||||
local item = itemstore.Item( class )
|
||||
if not item then return end
|
||||
|
||||
item:SaveData( ent )
|
||||
|
||||
local con = itemstore.config.PickupsGotoBank and self.Bank or self.Inventory
|
||||
|
||||
if not con:CanFit( item ) then return false end
|
||||
if hook.Call( "ItemStoreCanPickup", GAMEMODE, self, item, ent ) == false then return false end
|
||||
if not item:CanPickup( self, ent ) then return false end
|
||||
|
||||
local slot = con:AddItem( item )
|
||||
self:QueueInventorySave()
|
||||
|
||||
if slot then
|
||||
item:Pickup( self, con, slot, ent )
|
||||
ent:Remove()
|
||||
|
||||
--self:ChatPrint( itemstore.Translate( "picked_up", item:GetName() ) )
|
||||
self:EmitSound( "items/gunpickup2.wav" )
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function meta:MoveItem( from_con_id, from_slot, to_con_id, to_slot )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
local from_con = itemstore.containers.Get( from_con_id )
|
||||
local to_con = itemstore.containers.Get( to_con_id )
|
||||
if not from_con or not to_con then return end
|
||||
|
||||
local from_item = from_con:GetItem( from_slot )
|
||||
local to_item = to_con:GetItem( to_slot )
|
||||
if not from_item and not to_item then return end
|
||||
|
||||
if from_con:CanWrite( self, "move", to_con, to_slot, to_item, from_slot, from_item ) ~= false and
|
||||
to_con:CanWrite( self, "move", from_con, from_slot, from_item, to_slot, to_item ) ~= false then
|
||||
|
||||
from_con:SetSuppressed( true )
|
||||
to_con:SetSuppressed( true )
|
||||
|
||||
from_con:SetItem( from_slot, to_item )
|
||||
to_con:SetItem( to_slot, from_item )
|
||||
|
||||
from_con:SetSuppressed( false )
|
||||
to_con:SetSuppressed( false )
|
||||
|
||||
from_con:QueueSync()
|
||||
if from_con ~= to_con then
|
||||
to_con:QueueSync()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreMove" )
|
||||
net.Receive( "ItemStoreMove", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
local from_con_id = net.ReadUInt( 32 )
|
||||
local from_slot = net.ReadUInt( 32 )
|
||||
local to_con_id = net.ReadUInt( 32 )
|
||||
local to_slot = net.ReadUInt( 32 )
|
||||
|
||||
pl:MoveItem( from_con_id, from_slot, to_con_id, to_slot )
|
||||
end )
|
||||
|
||||
function meta:UseItem( con_id, slot, ... )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
local con = itemstore.containers.Get( con_id )
|
||||
if not con then return end
|
||||
|
||||
local item = con:GetItem( slot )
|
||||
|
||||
if not item or not item.Use then return end
|
||||
if con:CanWrite( self, "use", slot, item ) == false then return end
|
||||
|
||||
if item:Use( self, con, slot, ... ) then
|
||||
con:SetItem( slot, nil )
|
||||
end
|
||||
|
||||
con:QueueSync()
|
||||
self:QueueInventorySave()
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreUse" )
|
||||
net.Receive( "ItemStoreUse", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
local con_id = net.ReadUInt( 32 )
|
||||
local slot = net.ReadUInt( 32 )
|
||||
local args = {}--net.ReadTable()
|
||||
|
||||
pl:UseItem( con_id, slot, unpack( args ) )
|
||||
end )
|
||||
|
||||
function meta:UseItemWith( from_con_id, from_slot, to_con_id, to_slot )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
local from_con = itemstore.containers.Get( from_con_id )
|
||||
local to_con = itemstore.containers.Get( to_con_id )
|
||||
|
||||
if not from_con or not to_con then return end
|
||||
|
||||
local from_item = from_con:GetItem( from_slot )
|
||||
local to_item = to_con:GetItem( to_slot )
|
||||
if not from_item or not to_item or from_item == to_item then return end
|
||||
|
||||
if not from_item.UseWith or not from_item:CanUseWith( to_item ) then return end
|
||||
|
||||
if from_con:CanWrite( self, "usewith", from_slot, from_item, to_con,
|
||||
to_slot, to_item ) == false then return end
|
||||
|
||||
from_con:SetSuppressed( true )
|
||||
to_con:SetSuppressed( true )
|
||||
|
||||
if from_item:UseWith( self, to_item, from_con, from_slot, to_con, to_slot ) then
|
||||
from_con:SetItem( from_slot, nil )
|
||||
end
|
||||
|
||||
from_con:SetSuppressed( false )
|
||||
to_con:SetSuppressed( false )
|
||||
|
||||
from_con:QueueSync()
|
||||
if from_con ~= to_con then to_con:QueueSync() end
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreUseWith" )
|
||||
net.Receive( "ItemStoreUseWith", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
local from_con_id = net.ReadUInt( 32 )
|
||||
local from_slot = net.ReadUInt( 32 )
|
||||
local to_con_id = net.ReadUInt( 32 )
|
||||
local to_slot = net.ReadUInt( 32 )
|
||||
|
||||
pl:UseItemWith( from_con_id, from_slot, to_con_id, to_slot )
|
||||
end )
|
||||
|
||||
function meta:DropItem( con_id, slot )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
local con = itemstore.containers.Get( con_id )
|
||||
if not con then return end
|
||||
|
||||
local item = con:GetItem( slot )
|
||||
if not item then return end
|
||||
|
||||
if con:CanWrite( self, "drop", slot, item ) == false then return end
|
||||
|
||||
local pos = util.QuickTrace( self:GetShootPos(),
|
||||
self:GetAimVector() * itemstore.config.DropDistance, self ).HitPos
|
||||
local ent = item:CreateEntity( pos )
|
||||
item:Drop( self, con, slot, ent )
|
||||
|
||||
if CPPI then
|
||||
ent:CPPISetOwner( self )
|
||||
end
|
||||
|
||||
if item.DropStack or item:TakeOne() then
|
||||
con:SetItem( slot, nil )
|
||||
end
|
||||
|
||||
con:QueueSync()
|
||||
self:QueueInventorySave()
|
||||
|
||||
self:EmitSound( "items/ammocrate_open.wav" )
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreDrop" )
|
||||
net.Receive( "ItemStoreDrop", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
local con_id = net.ReadUInt( 32 )
|
||||
local slot = net.ReadUInt( 32 )
|
||||
|
||||
pl:DropItem( con_id, slot )
|
||||
end )
|
||||
|
||||
function meta:DestroyItem( con_id, slot )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
local con = itemstore.containers.Get( con_id )
|
||||
if not con then return end
|
||||
|
||||
local item = con:GetItem( slot )
|
||||
if not item then return end
|
||||
|
||||
if item and con:CanWrite( self, "destroy", slot, item ) ~= false then
|
||||
item:Destroy( self, con, slot )
|
||||
con:SetItem( slot, nil )
|
||||
|
||||
self:EmitSound( "physics/concrete/concrete_break2.wav" )
|
||||
end
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreDestroy" )
|
||||
net.Receive( "ItemStoreDestroy", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
local con_id = net.ReadUInt( 32 )
|
||||
local slot = net.ReadUInt( 32 )
|
||||
|
||||
pl:DestroyItem( con_id, slot )
|
||||
end )
|
||||
|
||||
function meta:MergeItem( from_con_id, from_slot, to_con_id, to_slot )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
local from_con = itemstore.containers.Get( from_con_id )
|
||||
local to_con = itemstore.containers.Get( to_con_id )
|
||||
if not from_con or not to_con then return end
|
||||
|
||||
local from_item = from_con:GetItem( from_slot )
|
||||
local to_item = to_con:GetItem( to_slot )
|
||||
if not from_item or not to_item then return end
|
||||
|
||||
if not ( from_con == to_con and from_slot == to_slot ) and
|
||||
from_con:CanWrite( self, "merge", to_con_id, from_slot, from_item, to_slot, to_item ) ~= false and
|
||||
to_con:CanWrite( self, "merge", from_con_id, from_slot, from_item, to_slot, to_item ) ~= false and
|
||||
to_item:CanMerge( from_item ) then
|
||||
|
||||
from_con:SetSuppressed( true )
|
||||
to_con:SetSuppressed( true )
|
||||
|
||||
to_item:Merge( from_item )
|
||||
from_con:SetItem( from_slot, nil )
|
||||
|
||||
from_con:SetSuppressed( false )
|
||||
to_con:SetSuppressed( false )
|
||||
|
||||
from_con:QueueSync()
|
||||
if from_con ~= to_con then to_con:QueueSync() end
|
||||
end
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreMerge" )
|
||||
net.Receive( "ItemStoreMerge", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
local from_con_id = net.ReadUInt( 32 )
|
||||
local from_slot = net.ReadUInt( 32 )
|
||||
local to_con_id = net.ReadUInt( 32 )
|
||||
local to_slot = net.ReadUInt( 32 )
|
||||
|
||||
pl:MergeItem( from_con_id, from_slot, to_con_id, to_slot )
|
||||
end )
|
||||
|
||||
function meta:SplitItem( con_id, slot, amount )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
local con = itemstore.containers.Get( con_id )
|
||||
if not con then return end
|
||||
|
||||
local item = con:GetItem( slot )
|
||||
if not item then return end
|
||||
|
||||
if con:FirstEmptySlot() and item:CanSplit( amount ) and con:CanWrite( self, "split", slot, item, amount ) ~= false then
|
||||
con:AddItem( item:Split( amount ), true )
|
||||
end
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreSplit" )
|
||||
net.Receive( "ItemStoreSplit", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
local con_id = net.ReadUInt( 32 )
|
||||
local slot = net.ReadUInt( 32 )
|
||||
local amount = math.max( net.ReadUInt( 16 ), 1 )
|
||||
|
||||
pl:SplitItem( con_id, slot, amount )
|
||||
end )
|
||||
|
||||
util.AddNetworkString( "ItemStoreOpen" )
|
||||
function meta:OpenContainer( id, name, hideinv )
|
||||
if not self:CanUseInventory() then return false end
|
||||
|
||||
net.Start( "ItemStoreOpen" )
|
||||
net.WriteUInt( id, 32 )
|
||||
net.WriteString( name )
|
||||
net.WriteBit( hideinv )
|
||||
net.Send( self )
|
||||
end
|
||||
|
||||
function meta:QueueInventorySave()
|
||||
self.NextInventorySave = CurTime() + 1
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreSyncInventory" )
|
||||
net.Receive( "ItemStoreSyncInventory", function( len, pl )
|
||||
if pl.ItemStoreTimeout and pl.ItemStoreTimeout > CurTime() then return end
|
||||
pl.ItemStoreTimeout = CurTime() + ITEMSTORE_TIMEOUT
|
||||
|
||||
pl.Inventory:Sync()
|
||||
|
||||
net.Start( "ItemStoreSyncInventory" )
|
||||
net.WriteUInt( pl.Inventory:GetID(), 32 )
|
||||
net.Send( pl )
|
||||
end )
|
||||
|
||||
hook.Add( "PlayerInitialSpawn", "ItemStoreLoadIn=ventory", function( pl )
|
||||
-- since the player loads quickly in sp, don't bother with the delay.
|
||||
-- this is only important in mp, since it's unlikely a player would be using mysql ranks in sp
|
||||
local delay = game.SinglePlayer() and 0 or 1
|
||||
|
||||
timer.Simple( delay, function()
|
||||
if IsValid( pl ) then pl:SetupInventory() end
|
||||
end )
|
||||
end )
|
||||
|
||||
hook.Add( "PlayerUse", "ItemStorePickup", function( pl, ent )
|
||||
-- fuck you wiremod
|
||||
-- why would you EVER replace the player parameter with some random entity
|
||||
-- what is your fucking damage
|
||||
if not IsValid( pl ) or not pl:IsPlayer() then return end
|
||||
|
||||
if ent.__Deleted then
|
||||
-- Anti-dupe, never let anything marked as deleted to be used
|
||||
return false
|
||||
end
|
||||
|
||||
-- thanks brax
|
||||
if itemstore.config.PickupKey > -1 and pl:KeyDown( itemstore.config.PickupKey )
|
||||
and pl:PickupItem( ent ) then
|
||||
|
||||
return false
|
||||
end
|
||||
end )
|
||||
|
||||
hook.Add( "PlayerDeath", "ItemStoreDeathLoot", function( pl )
|
||||
if not itemstore.config.DeathLoot then return end
|
||||
if table.Count( pl.Inventory:GetItems() ) <= 0 then return end
|
||||
if not pl:CanUseInventory() then return false end -- don't drop items if they're not usable
|
||||
|
||||
local ent = ents.Create( "itemstore_deathloot" )
|
||||
ent:SetPos( pl:GetPos() )
|
||||
ent:Spawn()
|
||||
|
||||
ent.Container:SetWidth( pl.Inventory:GetWidth() )
|
||||
ent.Container:SetHeight( pl.Inventory:GetHeight() )
|
||||
ent.Container:SetPages( pl.Inventory:GetPages() )
|
||||
|
||||
for k, v in pairs( pl.Inventory:GetItems() ) do
|
||||
ent.Container:SetItem( k, v )
|
||||
pl.Inventory:SetItem( k, nil )
|
||||
end
|
||||
|
||||
ent.Timeout = CurTime() + itemstore.config.DeathLootTimeout
|
||||
end )
|
||||
287
addons/itemstore/lua/itemstore/trading.lua
Normal file
287
addons/itemstore/lua/itemstore/trading.lua
Normal file
@@ -0,0 +1,287 @@
|
||||
itemstore.trading = {}
|
||||
|
||||
local Trade = {}
|
||||
|
||||
function Trade:GetSide( pl )
|
||||
if self.Right.Player == pl then
|
||||
return self.Right
|
||||
elseif self.Left.Player == pl then
|
||||
return self.Left
|
||||
end
|
||||
end
|
||||
|
||||
function Trade:SetMoneyOffer( pl, offer )
|
||||
local side = self:GetSide( pl )
|
||||
|
||||
if side then
|
||||
side.Money = math.Clamp( offer, 0, itemstore.gamemodes.GetMoney( pl ) )
|
||||
if SERVER then self:Sync() end
|
||||
end
|
||||
end
|
||||
|
||||
function Trade:GetMoneyOffer( pl )
|
||||
local side = self:GetSide( pl )
|
||||
|
||||
if side then
|
||||
return side.Money
|
||||
end
|
||||
end
|
||||
|
||||
function Trade:SetReady( pl, ready )
|
||||
local side = self:GetSide( pl )
|
||||
|
||||
if side then
|
||||
side.Ready = ready
|
||||
if SERVER then self:Sync() end
|
||||
end
|
||||
end
|
||||
|
||||
function Trade:GetReady( pl )
|
||||
local side = self:GetSide( pl )
|
||||
|
||||
if side then
|
||||
return side.Ready
|
||||
end
|
||||
end
|
||||
|
||||
function Trade:IsReady()
|
||||
return self.Left.Ready and self.Right.Ready
|
||||
end
|
||||
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString( "ItemStoreTrade" )
|
||||
function Trade:Sync()
|
||||
net.Start( "ItemStoreTrade" )
|
||||
net.WriteEntity( self.Left.Player )
|
||||
net.WriteUInt( self.Left.Money, 32 )
|
||||
net.WriteUInt( self.Left.Container:GetID(), 32 )
|
||||
net.WriteBit( self.Left.Ready )
|
||||
|
||||
net.WriteEntity( self.Right.Player )
|
||||
net.WriteUInt( self.Right.Money, 32 )
|
||||
net.WriteUInt( self.Right.Container:GetID(), 32 )
|
||||
net.WriteBit( self.Right.Ready )
|
||||
net.Send( { self.Left.Player, self.Right.Player } )
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreCloseTrade" )
|
||||
function Trade:Close()
|
||||
if IsValid( self.Left.Player ) then
|
||||
for k, v in pairs( self.Left.Container:GetItems() ) do
|
||||
self.Left.Player.Inventory:AddItem( v )
|
||||
end
|
||||
end
|
||||
|
||||
itemstore.containers.Remove( self.Left.Container:GetID() )
|
||||
|
||||
if IsValid( self.Right.Player ) then
|
||||
for k, v in pairs( self.Right.Container:GetItems() ) do
|
||||
self.Right.Player.Inventory:AddItem( v )
|
||||
end
|
||||
end
|
||||
|
||||
itemstore.containers.Remove( self.Right.Container:GetID() )
|
||||
|
||||
self.Left.Player.Trade = nil
|
||||
self.Right.Player.Trade = nil
|
||||
|
||||
net.Start( "ItemStoreCloseTrade" )
|
||||
net.Send( { self.Left.Player, self.Right.Player } )
|
||||
end
|
||||
|
||||
function Trade:Accept()
|
||||
if not self:IsReady() then return end
|
||||
|
||||
if IsValid( self.Left.Player ) and IsValid( self.Right.Player ) then
|
||||
local leftmoney = itemstore.gamemodes.GetMoney( self.Left.Player )
|
||||
local rightmoney = itemstore.gamemodes.GetMoney( self.Right.Player )
|
||||
|
||||
if leftmoney >= self.Left.Money and rightmoney >= self.Right.Money then
|
||||
for k, v in pairs( self.Left.Container:GetItems() ) do
|
||||
self.Left.Container:SetItem( k, nil )
|
||||
self.Right.Player.Inventory:AddItem( v )
|
||||
end
|
||||
|
||||
for k, v in pairs( self.Right.Container:GetItems() ) do
|
||||
self.Right.Container:SetItem( k, nil )
|
||||
self.Left.Player.Inventory:AddItem( v )
|
||||
end
|
||||
|
||||
itemstore.gamemodes.GiveMoney( self.Left.Player, -self.Left.Money )
|
||||
itemstore.gamemodes.GiveMoney( self.Left.Player, self.Right.Money )
|
||||
|
||||
itemstore.gamemodes.GiveMoney( self.Right.Player, self.Left.Money )
|
||||
itemstore.gamemodes.GiveMoney( self.Right.Player, -self.Right.Money )
|
||||
else
|
||||
self.Left.Player:ChatPrint( itemstore.Translate( "trade_failed" ) )
|
||||
self.Right.Player:ChatPrint( itemstore.Translate( "trade_failed" ) )
|
||||
end
|
||||
end
|
||||
|
||||
self:Close()
|
||||
end
|
||||
|
||||
util.AddNetworkString( "ItemStoreTradeMessage" )
|
||||
function Trade:Message( pl, message )
|
||||
net.Start( "ItemStoreTradeMessage" )
|
||||
net.WriteEntity( pl )
|
||||
net.WriteString( message )
|
||||
net.Send( { self.Left.Player, self.Right.Player } )
|
||||
end
|
||||
else
|
||||
function Trade:SendMessage( message )
|
||||
net.Start( "ItemStoreTradeMessage" )
|
||||
net.WriteString( message )
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
|
||||
function itemstore.Trade( left, right, con_left, con_right )
|
||||
local trade = {
|
||||
Left = {
|
||||
Player = left,
|
||||
Money = 0,
|
||||
Container = con_left or itemstore.Container( 4, 3, 1 ),
|
||||
Ready = false
|
||||
},
|
||||
|
||||
Right = {
|
||||
Player = right,
|
||||
Money = 0,
|
||||
Container = con_right or itemstore.Container( 4, 3, 1 ),
|
||||
Ready = false
|
||||
}
|
||||
}
|
||||
|
||||
setmetatable( trade, { __index = Trade } )
|
||||
|
||||
left.Trade = trade
|
||||
right.Trade = trade
|
||||
|
||||
if SERVER then
|
||||
trade.Left.Container:SetPermissions( left, true, true )
|
||||
trade.Left.Container:SetPermissions( right, true, false )
|
||||
|
||||
trade.Left.Container:AddCallback( "set", function( slot, item )
|
||||
trade:SetReady( trade.Left.Player, false )
|
||||
trade:SetReady( trade.Right.Player, false )
|
||||
end )
|
||||
|
||||
trade.Left.Container:Sync()
|
||||
|
||||
trade.Right.Container:SetPermissions( left, true, false )
|
||||
trade.Right.Container:SetPermissions( right, true, true )
|
||||
|
||||
trade.Right.Container:AddCallback( "set", function( slot, item )
|
||||
trade:SetReady( trade.Left.Player, false )
|
||||
trade:SetReady( trade.Right.Player, false )
|
||||
end )
|
||||
|
||||
trade.Right.Container:Sync()
|
||||
|
||||
trade:Sync()
|
||||
end
|
||||
|
||||
return trade
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
--[[
|
||||
util.AddNetworkString( "ItemStoreStartTrade" )
|
||||
net.Receive( "ItemStoreStartTrade", function( len, pl )
|
||||
local partner = net.ReadEntity()
|
||||
|
||||
if not IsValid( partner ) or not partner:IsPlayer() then
|
||||
itemstore.Trade( pl, partner )
|
||||
end
|
||||
end )
|
||||
]]
|
||||
|
||||
util.AddNetworkString( "ItemStoreReadyTrade" )
|
||||
net.Receive( "ItemStoreReadyTrade", function( len, pl )
|
||||
if pl.Trade then
|
||||
pl.Trade:SetReady( pl, net.ReadBit() == 1 )
|
||||
end
|
||||
end )
|
||||
|
||||
util.AddNetworkString( "ItemStoreAcceptTrade" )
|
||||
net.Receive( "ItemStoreAcceptTrade", function( len, pl )
|
||||
if pl.Trade then
|
||||
pl.Trade:Accept()
|
||||
end
|
||||
end )
|
||||
|
||||
util.AddNetworkString( "ItemStoreCloseTrade" )
|
||||
net.Receive( "ItemStoreCloseTrade", function( len, pl )
|
||||
if pl.Trade then
|
||||
pl.Trade:Close()
|
||||
end
|
||||
end )
|
||||
|
||||
util.AddNetworkString( "ItemStoreTradeMoney" )
|
||||
net.Receive( "ItemStoreTradeMoney", function( len, pl )
|
||||
if pl.Trade then
|
||||
pl.Trade:SetMoneyOffer( pl, net.ReadUInt( 32 ) )
|
||||
end
|
||||
end )
|
||||
|
||||
util.AddNetworkString( "ItemStoreTradeMessage" )
|
||||
net.Receive( "ItemStoreTradeMessage", function( len, pl )
|
||||
if pl.Trade then
|
||||
pl.Trade:Message( pl, net.ReadString() )
|
||||
end
|
||||
end )
|
||||
else
|
||||
itemstore.trading.Panel = nil
|
||||
|
||||
net.Receive( "ItemStoreTrade", function()
|
||||
left_pl = net.ReadEntity()
|
||||
left_money = net.ReadUInt( 32 )
|
||||
left_con = itemstore.containers.Get( net.ReadUInt( 32 ) )
|
||||
left_ready = net.ReadBit() == 1
|
||||
|
||||
right_pl = net.ReadEntity()
|
||||
right_money = net.ReadUInt( 32 )
|
||||
right_con = itemstore.containers.Get( net.ReadUInt( 32 ) )
|
||||
right_ready = net.ReadBit() == 1
|
||||
|
||||
local trade = itemstore.Trade( left_pl, right_pl, left_con, right_con )
|
||||
|
||||
trade.Left.Money = left_money
|
||||
trade.Left.Ready = left_ready
|
||||
|
||||
trade.Right.Money = right_money
|
||||
trade.Right.Ready = right_ready
|
||||
|
||||
LocalPlayer().Trade = trade
|
||||
|
||||
if not IsValid( itemstore.trading.Panel ) then
|
||||
if trade.Left.Player == LocalPlayer() then
|
||||
itemstore.trading.Panel = vgui.Create( "ItemStoreTrade" )
|
||||
itemstore.trading.Panel:Center()
|
||||
itemstore.trading.Panel:MakePopup()
|
||||
else
|
||||
itemstore.trading.Panel = vgui.Create( "ItemStoreTradeRequest" )
|
||||
itemstore.trading.Panel:SetSize( 200, 100 )
|
||||
itemstore.trading.Panel:SetPos( ScrW() - itemstore.trading.Panel:GetWide(), 0 )
|
||||
end
|
||||
end
|
||||
|
||||
itemstore.trading.Panel:Refresh()
|
||||
end )
|
||||
|
||||
net.Receive( "ItemStoreCloseTrade", function()
|
||||
LocalPlayer().Trade = nil
|
||||
|
||||
if IsValid( itemstore.trading.Panel ) then
|
||||
itemstore.trading.Panel:Close()
|
||||
end
|
||||
end )
|
||||
|
||||
net.Receive( "ItemStoreTradeMessage", function()
|
||||
if IsValid( itemstore.trading.Panel ) then
|
||||
itemstore.trading.Panel:ChatMessage( net.ReadEntity(), net.ReadString() )
|
||||
end
|
||||
end )
|
||||
end
|
||||
37
addons/itemstore/lua/itemstore/vgui/Admin.lua
Normal file
37
addons/itemstore/lua/itemstore/vgui/Admin.lua
Normal file
@@ -0,0 +1,37 @@
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetTitle( itemstore.Translate( "admin_title" ) )
|
||||
self:SetSkin( "itemstore" )
|
||||
|
||||
self.Scroll = vgui.Create( "DScrollPanel", self )
|
||||
self.Scroll:Dock( FILL )
|
||||
|
||||
self.List = vgui.Create( "DListLayout", self.Scroll )
|
||||
self.List:Dock( FILL )
|
||||
for _, pl in ipairs( player.GetAll() ) do
|
||||
local b = self.List:Add( "DButton" )
|
||||
b:SetText( pl:Name() )
|
||||
b:DockMargin( 0, 0, 0, 2 )
|
||||
|
||||
function b.DoClick()
|
||||
local menu = DermaMenu()
|
||||
|
||||
menu:AddOption( itemstore.Translate( "inventory" ), function()
|
||||
net.Start( "ItemStoreAdminInventory" )
|
||||
net.WriteEntity( pl )
|
||||
net.SendToServer()
|
||||
end )
|
||||
|
||||
menu:AddOption( itemstore.Translate( "bank" ), function()
|
||||
net.Start( "ItemStoreAdminBank" )
|
||||
net.WriteEntity( pl )
|
||||
net.SendToServer()
|
||||
end )
|
||||
|
||||
menu:Open()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register( "ItemStoreAdmin", PANEL, "DFrame" )
|
||||
69
addons/itemstore/lua/itemstore/vgui/Container.lua
Normal file
69
addons/itemstore/lua/itemstore/vgui/Container.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.Pages = {}
|
||||
self.Slots = {}
|
||||
|
||||
table.insert( itemstore.containers.Panels, self )
|
||||
end
|
||||
|
||||
function PANEL:SetContainerID( id )
|
||||
self.ContainerID = id
|
||||
self:Refresh()
|
||||
end
|
||||
|
||||
function PANEL:GetContainerID()
|
||||
return self.ContainerID
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
local id = self:GetContainerID()
|
||||
local con = itemstore.containers.Get( id )
|
||||
|
||||
if con then
|
||||
for i = 1, con:GetSize() do
|
||||
local page_id = con:GetPageFromSlot( i )
|
||||
local page = self.Pages[ page_id ]
|
||||
|
||||
if not page then
|
||||
page = vgui.Create( "DIconLayout" )
|
||||
page:SetSpaceX( 1 )
|
||||
page:SetSpaceY( 1 )
|
||||
|
||||
self.Pages[ page_id ] = page
|
||||
|
||||
self:AddSheet( itemstore.Translate( "page", page_id ), page )
|
||||
end
|
||||
|
||||
local slot = self.Slots[ i ]
|
||||
|
||||
if not slot then
|
||||
slot = page:Add( "ItemStoreSlot" )
|
||||
slot:SetSize( 40, 40 )
|
||||
slot:SetContainerID( self:GetContainerID() )
|
||||
slot:SetSlot( i )
|
||||
|
||||
self.Slots[ i ] = slot
|
||||
end
|
||||
|
||||
slot:SetItem( con:GetItem( i ) )
|
||||
slot:Refresh()
|
||||
end
|
||||
end
|
||||
|
||||
self:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local id = self:GetContainerID()
|
||||
local con = itemstore.containers.Get( id )
|
||||
|
||||
if con then
|
||||
local w = con:GetWidth() * 41 + 15
|
||||
local h = con:GetHeight() * 41 + 35
|
||||
|
||||
self:SetSize( w, h )
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register( "ItemStoreContainer", PANEL, "DPropertySheet" )
|
||||
29
addons/itemstore/lua/itemstore/vgui/ContainerWindow.lua
Normal file
29
addons/itemstore/lua/itemstore/vgui/ContainerWindow.lua
Normal file
@@ -0,0 +1,29 @@
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSkin( "itemstore" )
|
||||
|
||||
self.Container = vgui.Create( "ItemStoreContainer", self )
|
||||
self.Container:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
self:SetSize( self.Container:GetWide() + 10, self.Container:GetTall() + 32 )
|
||||
self.Container:SetPos( 5, 27 )
|
||||
|
||||
self.BaseClass.PerformLayout( self )
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
self.Container:Refresh()
|
||||
end
|
||||
|
||||
function PANEL:SetContainerID( id )
|
||||
self.Container:SetContainerID( id )
|
||||
end
|
||||
|
||||
function PANEL:GetContainerID()
|
||||
return self.Container:GetContainerID()
|
||||
end
|
||||
|
||||
vgui.Register( "ItemStoreContainerWindow", PANEL, "DFrame" )
|
||||
95
addons/itemstore/lua/itemstore/vgui/ItemTooltip.lua
Normal file
95
addons/itemstore/lua/itemstore/vgui/ItemTooltip.lua
Normal file
@@ -0,0 +1,95 @@
|
||||
DEFINE_BASECLASS( "DListLayout" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "ContainerID", "ContainerID", FORCE_NUMBER )
|
||||
AccessorFunc( PANEL, "Slot", "Slot", FORCE_NUMBER )
|
||||
AccessorFunc( PANEL, "Item", "Item" )
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetWide( 200 )
|
||||
self:SetDrawOnTop( true )
|
||||
self:DockPadding( 5, 5, 5, 5 )
|
||||
|
||||
self.Name = self:Add( "DLabel" )
|
||||
self.Name:SetFont( "DermaDefaultBold" )
|
||||
self.Name:SetWrap( true )
|
||||
|
||||
self.Model = self:Add( "DModelPanel" )
|
||||
self.Model:SetSize( 125, 125 )
|
||||
|
||||
self.Description = self:Add( "DLabel" )
|
||||
self.Description:SetWrap( true )
|
||||
end
|
||||
|
||||
PANEL.Blur = Material( "pp/blurscreen" )
|
||||
function PANEL:Paint( w, h )
|
||||
self.Blur:SetFloat( "$blur", 8 )
|
||||
self.Blur:Recompute()
|
||||
render.UpdateScreenEffectTexture()
|
||||
|
||||
local x, y = self:LocalToScreen( 0, 0 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255 )
|
||||
surface.SetMaterial( self.Blur )
|
||||
surface.DrawTexturedRect( x * -1, y * -1, ScrW(), ScrH() )
|
||||
|
||||
surface.SetDrawColor( Color( 30, 30, 30, 200 ) )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
self.Name:SizeToContents()
|
||||
self.Description:SizeToContents()
|
||||
|
||||
BaseClass.PerformLayout( self )
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
local item = self:GetItem()
|
||||
|
||||
if not item then
|
||||
self.Model.Entity:Remove()
|
||||
self.Name:SetText( "" )
|
||||
self.Description:SetText( "" )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local name = item:GetName()
|
||||
local desc = item:GetDescription() or ""
|
||||
|
||||
if item:GetAmount() > 1 then
|
||||
name = name .. " x" .. item:GetAmount()
|
||||
end
|
||||
|
||||
if self:GetSlot() then
|
||||
desc = desc .. "\n\n" .. itemstore.Translate( "dragtomove" )
|
||||
desc = desc .. "\n" .. itemstore.Translate( "mclicktodrop" )
|
||||
desc = desc .. "\n" .. itemstore.Translate( "rclickforoptions" )
|
||||
|
||||
if item.Use then
|
||||
desc = desc .. "\n" .. itemstore.Translate( "dclicktouse" )
|
||||
end
|
||||
end
|
||||
|
||||
self.Name:SetText( name )
|
||||
self.Name:SizeToContents()
|
||||
|
||||
self.Description:SetText( desc )
|
||||
self.Description:SizeToContents()
|
||||
|
||||
self.Model:SetModel( item:GetModel() )
|
||||
|
||||
self.Model.Entity:SetMaterial( item:GetMaterial() )
|
||||
self.Model:SetColor( item:GetColor() or color_white )
|
||||
|
||||
min, max = self.Model.Entity:GetRenderBounds()
|
||||
|
||||
self.Model:SetCamPos( Vector( 0.55, 0.55, 0.55 ) * min:Distance( max ) )
|
||||
self.Model:SetLookAt( ( min + max ) / 2 )
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
end
|
||||
|
||||
vgui.Register( "ItemStoreTooltip", PANEL, "DListLayout" )
|
||||
277
addons/itemstore/lua/itemstore/vgui/Slot.lua
Normal file
277
addons/itemstore/lua/itemstore/vgui/Slot.lua
Normal file
@@ -0,0 +1,277 @@
|
||||
local PANEL = {}
|
||||
|
||||
surface.CreateFont( "ItemStoreAmount", {
|
||||
font = system.IsLinux() and "DejaVu Sans" or "Tahoma",
|
||||
size = 11,
|
||||
weight = 500
|
||||
} )
|
||||
|
||||
local GradientUp = Material( "gui/gradient_up" )
|
||||
local GradientDown = Material( "gui/gradient_down" )
|
||||
|
||||
AccessorFunc( PANEL, "Item", "Item" )
|
||||
AccessorFunc( PANEL, "ContainerID", "ContainerID", FORCE_NUMBER )
|
||||
AccessorFunc( PANEL, "Slot", "Slot", FORCE_NUMBER )
|
||||
|
||||
function PANEL:Init()
|
||||
self.BaseClass.Init( self )
|
||||
|
||||
self:Droppable( "ItemStore" )
|
||||
self:Receiver( "ItemStore", function( receiver, droptable, dropped )
|
||||
local droppable = droptable[ 1 ]
|
||||
|
||||
if not dropped then return end
|
||||
|
||||
local droppable = droptable[ 1 ]
|
||||
|
||||
local from_con = droppable:GetContainerID()
|
||||
local to_con = droppable:GetContainerID()
|
||||
|
||||
if not from_con then return end
|
||||
if not to_con then return end
|
||||
|
||||
local from_slot = droppable:GetSlot()
|
||||
local to_slot = receiver:GetSlot()
|
||||
|
||||
if not from_slot then return end
|
||||
if not to_slot then return end
|
||||
|
||||
local from_item = droppable:GetItem()
|
||||
local to_item = receiver:GetItem()
|
||||
|
||||
if from_item and to_item and ( from_item:CanMerge( to_item ) or
|
||||
from_item:CanUseWith( to_item ) ) then
|
||||
local menu = DermaMenu()
|
||||
|
||||
if from_item:CanUseWith( to_item ) then
|
||||
menu:AddOption( itemstore.Translate( "usewith" ), function()
|
||||
LocalPlayer():UseItemWith( droppable:GetContainerID(), droppable:GetSlot(),
|
||||
receiver:GetContainerID(), receiver:GetSlot() )
|
||||
end ):SetIcon( "icon16/wrench_orange.png" )
|
||||
|
||||
menu:AddSpacer()
|
||||
end
|
||||
|
||||
menu:AddOption( itemstore.Translate( "move" ), function()
|
||||
LocalPlayer():MoveItem( droppable:GetContainerID(), droppable:GetSlot(),
|
||||
receiver:GetContainerID(), receiver:GetSlot() )
|
||||
end ):SetIcon( "icon16/arrow_switch.png" )
|
||||
|
||||
if from_item:CanMerge( to_item ) then
|
||||
menu:AddOption( itemstore.Translate( "merge" ), function()
|
||||
LocalPlayer():MergeItem( droppable:GetContainerID(), droppable:GetSlot(),
|
||||
receiver:GetContainerID(), receiver:GetSlot() )
|
||||
end ):SetIcon( "icon16/arrow_join.png" )
|
||||
end
|
||||
|
||||
menu:Open()
|
||||
else
|
||||
LocalPlayer():MoveItem( droppable:GetContainerID(), droppable:GetSlot(),
|
||||
receiver:GetContainerID(), receiver:GetSlot() )
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
if itemstore.config.HighlightStyle == "old" or itemstore.config.HighlightStyle == "border" then
|
||||
surface.SetDrawColor( self.Hovered and itemstore.config.Colours.HoveredSlot or itemstore.config.Colours.Slot )
|
||||
else
|
||||
surface.SetDrawColor( itemstore.config.Colours.Slot )
|
||||
end
|
||||
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
|
||||
local item = self:GetItem()
|
||||
|
||||
if item and item.HighlightColor then
|
||||
local col = Color( item.HighlightColor.r, item.HighlightColor.g, item.HighlightColor.b )
|
||||
local bright = Color( col.r * 1.25, col.g * 1.25, col.b * 1.25 )
|
||||
local dark = Color( bright.r / 2, bright.g / 2, bright.b / 2 )
|
||||
|
||||
if itemstore.config.HighlightStyle == "full" then
|
||||
surface.SetDrawColor( dark )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
|
||||
surface.SetMaterial( GradientDown )
|
||||
surface.SetDrawColor( self.Hovered and bright or col )
|
||||
surface.DrawTexturedRect( 0, 0, w, h )
|
||||
elseif itemstore.config.HighlightStyle == "subtle" then
|
||||
surface.SetMaterial( GradientUp )
|
||||
surface.SetDrawColor( self.Hovered and bright or col )
|
||||
surface.DrawTexturedRect( 0, 0, w, h )
|
||||
elseif itemstore.config.HighlightStyle == "corner" then
|
||||
surface.SetMaterial( GradientUp )
|
||||
surface.SetDrawColor( self.Hovered and bright or col )
|
||||
surface.DrawTexturedRectRotated( w, h, w * 1.25, h * 1.25, 45 )
|
||||
elseif itemstore.config.HighlightStyle == "border" then
|
||||
surface.SetDrawColor( col )
|
||||
surface.DrawOutlinedRect( 0, 0, w, h )
|
||||
end
|
||||
end
|
||||
|
||||
if not itemstore.config.HighlightStyle ~= "border" or not item then
|
||||
surface.SetDrawColor( itemstore.config.Colours.OuterBorder )
|
||||
surface.DrawOutlinedRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
surface.SetDrawColor( itemstore.config.Colours.InnerBorder )
|
||||
surface.DrawOutlinedRect( 1, 1, w - 2, h - 2 )
|
||||
|
||||
self.BaseClass.Paint( self, w, h )
|
||||
|
||||
local item = self:GetItem()
|
||||
if item and item:GetAmount() > 1 then
|
||||
draw.SimpleTextOutlined( item:FormatAmount(), "ItemStoreAmount", 4,
|
||||
h - 2, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM, 1, color_black )
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
local item = self:GetItem()
|
||||
|
||||
if item then
|
||||
self:SetModel( item:GetModel() )
|
||||
self:SetColor( item:GetColor() or color_white )
|
||||
|
||||
if IsValid( self.Entity ) then
|
||||
self.Entity:SetMaterial( item:GetMaterial() )
|
||||
|
||||
local min, max = self.Entity:GetRenderBounds()
|
||||
|
||||
self:SetCamPos( Vector( 0.55, 0.55, 0.55 ) * min:Distance( max ) )
|
||||
self:SetLookAt( ( min + max ) / 2 )
|
||||
end
|
||||
else
|
||||
self.Entity = nil
|
||||
self:SetTooltip( nil )
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:DoDoubleClick()
|
||||
local con_id = self:GetContainerID()
|
||||
local slot = self:GetSlot()
|
||||
local item = self:GetItem()
|
||||
|
||||
if not con_id then return end
|
||||
if not slot then return end
|
||||
if not item then return end
|
||||
if not item.Use then return end
|
||||
|
||||
LocalPlayer():UseItem( con_id, slot )
|
||||
end
|
||||
|
||||
function PANEL:DoMiddleClick()
|
||||
local con_id = self:GetContainerID()
|
||||
local slot = self:GetSlot()
|
||||
local item = self:GetItem()
|
||||
|
||||
if not con_id then return end
|
||||
if not slot then return end
|
||||
if not item then return end
|
||||
|
||||
LocalPlayer():DropItem( con_id, slot )
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
local con_id = self:GetContainerID()
|
||||
local slot = self:GetSlot()
|
||||
local item = self:GetItem()
|
||||
|
||||
if not con_id then return end
|
||||
if not slot then return end
|
||||
if not item then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
|
||||
if item.Use then
|
||||
menu:AddOption( itemstore.Translate( "use" ), function()
|
||||
LocalPlayer():UseItem( con_id, slot )
|
||||
end ):SetIcon( "icon16/wrench.png" )
|
||||
|
||||
menu:AddSpacer()
|
||||
end
|
||||
|
||||
menu:AddOption( itemstore.Translate( "drop" ), function()
|
||||
LocalPlayer():DropItem( con_id, slot )
|
||||
end ):SetIcon( "icon16/arrow_out.png" )
|
||||
|
||||
menu:AddOption( itemstore.Translate( "destroy" ), function()
|
||||
Derma_Query( itemstore.Translate( "destroy_confirmation" ), itemstore.Translate( "destroy_title" ), itemstore.Translate( "ok" ), function()
|
||||
LocalPlayer():DestroyItem( con_id, slot )
|
||||
end, itemstore.Translate( "cancel" ) ):SetSkin( "itemstore" )
|
||||
end ):SetIcon( "icon16/delete.png" )
|
||||
|
||||
if item:CanSplit( 1 ) then
|
||||
menu:AddSpacer()
|
||||
|
||||
local submenu, entry = menu:AddSubMenu( itemstore.Translate( "split" ) )
|
||||
entry:SetIcon( "icon16/arrow_divide.png" )
|
||||
|
||||
local half = math.floor( item:GetAmount() / 2 )
|
||||
|
||||
submenu:AddOption( itemstore.Translate( "split_half", half ), function()
|
||||
LocalPlayer():SplitItem( con_id, slot, half )
|
||||
end )
|
||||
|
||||
submenu:AddSpacer()
|
||||
|
||||
for _, amount in ipairs( { 1, 2, 5, 10, 25, 50, 100, 250, 1000 } ) do
|
||||
if item:CanSplit( amount ) then
|
||||
submenu:AddOption( amount, function()
|
||||
LocalPlayer():SplitItem( con_id, slot, amount )
|
||||
end )
|
||||
end
|
||||
end
|
||||
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
item:Run( "PopulateMenu", menu )
|
||||
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
local Tooltip
|
||||
|
||||
function PANEL:CreateTooltip()
|
||||
if IsValid( Tooltip ) then
|
||||
Tooltip:SetVisible( true )
|
||||
return
|
||||
end
|
||||
|
||||
Tooltip = vgui.Create( "ItemStoreTooltip" )
|
||||
self:UpdateTooltip()
|
||||
end
|
||||
|
||||
function PANEL:UpdateTooltip()
|
||||
if not IsValid( Tooltip ) then return end
|
||||
|
||||
Tooltip:SetContainerID( self:GetContainerID() )
|
||||
Tooltip:SetSlot( self:GetSlot() )
|
||||
Tooltip:SetItem( self:GetItem() )
|
||||
Tooltip:Refresh()
|
||||
end
|
||||
|
||||
function PANEL:HideTooltip()
|
||||
if IsValid( Tooltip ) then Tooltip:SetVisible( false ) end
|
||||
end
|
||||
|
||||
function PANEL:OnCursorEntered()
|
||||
if not self:GetItem() then return end
|
||||
|
||||
self:CreateTooltip()
|
||||
self:UpdateTooltip()
|
||||
end
|
||||
|
||||
function PANEL:OnCursorMoved()
|
||||
if not IsValid( Tooltip ) then return end
|
||||
|
||||
local x, y = gui.MousePos()
|
||||
Tooltip:SetPos( x, y - Tooltip:GetTall() )
|
||||
end
|
||||
|
||||
function PANEL:OnCursorExited()
|
||||
self:HideTooltip()
|
||||
end
|
||||
|
||||
vgui.Register( "ItemStoreSlot", PANEL, "DModelPanel" )
|
||||
158
addons/itemstore/lua/itemstore/vgui/Trade.lua
Normal file
158
addons/itemstore/lua/itemstore/vgui/Trade.lua
Normal file
@@ -0,0 +1,158 @@
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSkin( "itemstore" )
|
||||
|
||||
self.LeftContainer = vgui.Create( "ItemStoreContainer", self )
|
||||
self.RightContainer = vgui.Create( "ItemStoreContainer", self )
|
||||
|
||||
self.LeftMoneyIcon = vgui.Create( "DImage", self )
|
||||
self.LeftMoneyIcon:SetImage( "icon16/money.png" )
|
||||
|
||||
self.RightMoneyIcon = vgui.Create( "DImage", self )
|
||||
self.RightMoneyIcon:SetImage( "icon16/money.png" )
|
||||
|
||||
self.LeftMoney = vgui.Create( "DTextEntry", self )
|
||||
self.LeftMoney.OnLoseFocus = function( money )
|
||||
net.Start( "ItemStoreTradeMoney" )
|
||||
net.WriteUInt( tonumber( money:GetText() ) or 0, 32 )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
self.RightMoney = vgui.Create( "DLabel", self )
|
||||
self.RightMoney:SetText( "0" )
|
||||
|
||||
self.LeftReady = vgui.Create( "DCheckBoxLabel", self )
|
||||
self.LeftReady:SetText( itemstore.Translate( "ready" ) )
|
||||
self.LeftReady.OnChange = function( ready )
|
||||
net.Start( "ItemStoreReadyTrade" )
|
||||
net.WriteBit( ready:GetChecked() )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
self.RightReady = vgui.Create( "DLabel", self )
|
||||
self.RightReady:SetText( itemstore.Translate( "not_ready" ) )
|
||||
|
||||
self.Accept = vgui.Create( "DButton", self )
|
||||
self.Accept:SetText( itemstore.Translate( "accept" ) )
|
||||
self.Accept:SetFont( "DermaLarge" )
|
||||
self.Accept:SetDisabled( true )
|
||||
self.Accept.DoClick = function()
|
||||
net.Start( "ItemStoreAcceptTrade" ) net.SendToServer()
|
||||
|
||||
surface.PlaySound( "buttons/button9.wav" )
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
self.Chat = vgui.Create( "RichText", self )
|
||||
function self.Chat:Paint()
|
||||
draw.RoundedBox( 4, 0, 0, self:GetWide(), self:GetTall(), Color( 230, 230, 230 ) )
|
||||
end
|
||||
|
||||
self.ChatEntry = vgui.Create( "DTextEntry", self )
|
||||
function self.ChatEntry:OnEnter()
|
||||
LocalPlayer().Trade:SendMessage( self:GetText() )
|
||||
|
||||
self:SetText( "" )
|
||||
self:RequestFocus()
|
||||
end
|
||||
|
||||
self.Inventory = vgui.Create( "ItemStoreContainerWindow" )
|
||||
self.Inventory:SetContainerID( LocalPlayer().InventoryID )
|
||||
self.Inventory:SetTitle( itemstore.Translate( "inventory" ) )
|
||||
self.Inventory:ShowCloseButton( false )
|
||||
self.Inventory:InvalidateLayout( true )
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
self.BaseClass.Think( self )
|
||||
|
||||
local x, y = self:GetPos()
|
||||
self.Inventory:SetPos( x + self:GetWide() / 2 - self.Inventory:GetWide() / 2, y + self:GetTall() + 5 )
|
||||
end
|
||||
|
||||
function PANEL:ChatMessage( pl, message )
|
||||
if pl == LocalPlayer() then
|
||||
self.Chat:InsertColorChange( 255, 0, 0, 255 )
|
||||
else
|
||||
self.Chat:InsertColorChange( 0, 0, 255, 255 )
|
||||
end
|
||||
|
||||
self.Chat:AppendText( pl:Name() )
|
||||
self.Chat:InsertColorChange( 100, 100, 100, 255 )
|
||||
self.Chat:AppendText( ": " .. message .. "\n" )
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
local trade = LocalPlayer().Trade
|
||||
|
||||
if trade then
|
||||
local ourside = LocalPlayer() == trade.Left.Player and trade.Left or trade.Right
|
||||
local otherside = LocalPlayer() == trade.Right.Player and trade.Left or trade.Right
|
||||
|
||||
self:SetTitle( itemstore.Translate( "trading_with", otherside.Player:Name() ) )
|
||||
|
||||
self.LeftContainer:SetContainerID( ourside.Container:GetID() )
|
||||
self.RightContainer:SetContainerID( otherside.Container:GetID() )
|
||||
|
||||
self.LeftMoney:SetText( ourside.Money )
|
||||
self.RightMoney:SetText( otherside.Money )
|
||||
|
||||
self.LeftReady:SetChecked( ourside.Ready )
|
||||
self.RightReady:SetText( otherside.Ready and itemstore.Translate( "ready" )
|
||||
or itemstore.Translate( "not_ready" ) )
|
||||
|
||||
self.Accept:SetDisabled( not ( ourside.Ready and otherside.Ready ) )
|
||||
end
|
||||
end
|
||||
|
||||
-- it's me, i'm coding hitler. this is the grave of so many brave
|
||||
-- functions that went to war and died on my behalf.
|
||||
function PANEL:PerformLayout()
|
||||
self.BaseClass.PerformLayout( self )
|
||||
|
||||
self.LeftContainer:SetPos( 5, 33 )
|
||||
self.LeftContainer:SizeToContents()
|
||||
local left_w, left_h = self.LeftContainer:GetSize()
|
||||
|
||||
self.RightContainer:SetPos( 5 + left_w + 24, 33 )
|
||||
self.RightContainer:SizeToContents()
|
||||
local right_w, right_h = self.RightContainer:GetSize()
|
||||
|
||||
self.LeftMoneyIcon:SetPos( 5, 33 + left_h + 5 )
|
||||
self.LeftMoneyIcon:SetSize( 16, 16 )
|
||||
|
||||
self.LeftMoney:SetPos( 5 + 16 + 5, 33 + left_h + 5 )
|
||||
self.LeftMoney:SetSize( left_w - 5 - 16 - 5, 16 )
|
||||
|
||||
self.RightMoneyIcon:SetPos( 5 + right_w + 24, 33 + right_h + 5 )
|
||||
self.RightMoneyIcon:SetSize( 16, 16 )
|
||||
|
||||
self.RightMoney:SetPos( 5 + left_w + 24 + 5 + 16 + 5, 33 + right_h + 5 )
|
||||
self.RightMoney:SetSize( right_w - 5 - 16 - 5, 16 )
|
||||
|
||||
self.LeftReady:SetPos( 5, 33 + left_h + 5 + 16 + 5 )
|
||||
self.LeftReady:SizeToContents()
|
||||
|
||||
self.RightReady:SetPos( 5 + left_w + 24, 33 + right_h + 5 + 16 + 5 )
|
||||
|
||||
self.RightReady:SizeToContents()
|
||||
|
||||
self.Accept:SetPos( 5, 33 + left_h + 5 + ( 16 + 5 ) * 2 )
|
||||
self.Accept:SetSize( 390, 37 )
|
||||
|
||||
self.Chat:SetPos( 400, 27 )
|
||||
self.Chat:SetSize( 195, 220 )
|
||||
|
||||
self.ChatEntry:SetPos( 400, 250 )
|
||||
self.ChatEntry:SetSize( 195, 25 )
|
||||
|
||||
self:SetSize( 600, 280 )
|
||||
end
|
||||
|
||||
function PANEL:OnRemove()
|
||||
net.Start( "ItemStoreCloseTrade" ) net.SendToServer()
|
||||
self.Inventory:Close()
|
||||
end
|
||||
|
||||
vgui.Register( "ItemStoreTrade", PANEL, "DFrame" )
|
||||
50
addons/itemstore/lua/itemstore/vgui/TradeRequest.lua
Normal file
50
addons/itemstore/lua/itemstore/vgui/TradeRequest.lua
Normal file
@@ -0,0 +1,50 @@
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSkin( "itemstore" )
|
||||
self:SetTitle( itemstore.Translate( "trade_request" ) )
|
||||
|
||||
self:ShowCloseButton( false )
|
||||
|
||||
self.Label = vgui.Create( "DLabel", self )
|
||||
|
||||
self.Accept = vgui.Create( "DButton", self )
|
||||
self.Accept:SetText( itemstore.Translate( "accept" ) )
|
||||
|
||||
function self.Accept.DoClick()
|
||||
itemstore.trading.Panel = vgui.Create( "ItemStoreTrade" )
|
||||
itemstore.trading.Panel:Refresh()
|
||||
itemstore.trading.Panel:Center()
|
||||
itemstore.trading.Panel:MakePopup()
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
self.Deny = vgui.Create( "DButton", self )
|
||||
self.Deny:SetText( itemstore.Translate( "deny" ) )
|
||||
|
||||
function self.Deny.DoClick()
|
||||
net.Start( "ItemStoreCloseTrade" ) net.SendToServer()
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
self.Label:SetText( itemstore.Translate( "wants_to_trade",
|
||||
LocalPlayer().Trade.Left.Player:Name() ) )
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
self.BaseClass.PerformLayout( self )
|
||||
|
||||
self.Label:SizeToContents()
|
||||
self.Label:SetPos( self:GetWide() / 2 - self.Label:GetWide() / 2, 30 )
|
||||
|
||||
self.Accept:SetSize( 75, 30 )
|
||||
self.Accept:SetPos( self:GetWide() / 2 - self.Accept:GetWide() - 15, self:GetTall() / 2 + 10 )
|
||||
|
||||
self.Deny:SetSize( 75, 30 )
|
||||
self.Deny:SetPos( self:GetWide() / 2 + 15, self:GetTall() / 2 + 10 )
|
||||
end
|
||||
|
||||
vgui.Register( "ItemStoreTradeRequest", PANEL, "DFrame" )
|
||||
62
addons/itemstore/lua/weapons/itemstore_checker.lua
Normal file
62
addons/itemstore/lua/weapons/itemstore_checker.lua
Normal file
@@ -0,0 +1,62 @@
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
end
|
||||
|
||||
SWEP.PrintName = "Чекер инвенторя"
|
||||
|
||||
SWEP.Purpose = "Проверка инвентаря другого игрокаr"
|
||||
SWEP.Instructions = "ЛКМ, Проверить инвентарь игрока перед вами"
|
||||
SWEP.Category = "Scora"
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminSpawnable = true
|
||||
SWEP.ViewModel = "models/weapons/cstrike/c_c4.mdl"
|
||||
SWEP.WorldModel = ""
|
||||
SWEP.UseHands = true
|
||||
|
||||
SWEP.Primary.Clipsize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.Clipsize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Slot = 1
|
||||
SWEP.SlotPos = 10
|
||||
SWEP.DrawAmmo = false
|
||||
SWEP.DrawCrosshair = true
|
||||
|
||||
SWEP.Range = 250
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType( "normal" )
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if CLIENT then return end
|
||||
|
||||
local tr = util.TraceLine{
|
||||
start = self.Owner:GetShootPos(),
|
||||
endpos = self.Owner:GetShootPos() + self.Owner:GetAimVector() * self.Range,
|
||||
filter = self.Owner
|
||||
}
|
||||
|
||||
if not tr.Hit then return end
|
||||
if not IsValid( tr.Entity ) or not tr.Entity:IsPlayer() then return end
|
||||
|
||||
local inv = tr.Entity.Inventory
|
||||
if not inv then return end
|
||||
|
||||
inv:Sync( self.Owner )
|
||||
self.Owner:OpenContainer( inv:GetID(), itemstore.Translate( "inventory" ), true )
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
51
addons/itemstore/lua/weapons/itemstore_pickup.lua
Normal file
51
addons/itemstore/lua/weapons/itemstore_pickup.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
end
|
||||
|
||||
SWEP.PrintName = "Инвентарь"
|
||||
|
||||
SWEP.Purpose = "Собираем вещи"
|
||||
SWEP.Instructions = "ПКМ, Забрать предмет. ЛКМ, Открыть инвентарь"
|
||||
SWEP.Category = "Scora"
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminSpawnable = true
|
||||
SWEP.ViewModel = "models/weapons/c_arms.mdl"
|
||||
SWEP.WorldModel = ""
|
||||
SWEP.UseHands = true
|
||||
|
||||
SWEP.Primary.Clipsize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.Clipsize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Slot = 1
|
||||
SWEP.SlotPos = 10
|
||||
SWEP.DrawAmmo = false
|
||||
SWEP.DrawCrosshair = true
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType( "normal" )
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if CLIENT then return end
|
||||
|
||||
self.Owner:PickupItem()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if CLIENT then return end
|
||||
|
||||
self.Owner:OpenContainer( self.Owner.Inventory:GetID(),
|
||||
itemstore.Translate( "inventory" ), true )
|
||||
end
|
||||
Reference in New Issue
Block a user