Initial commit

This commit is contained in:
2026-03-15 14:54:49 +03:00
commit 64f8029c06
4027 changed files with 254888 additions and 0 deletions

View 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 )

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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 )

View File

@@ -0,0 +1,4 @@
include( "shared.lua" )
include( "cl_gui.lua" )
include( "cl_player.lua" )

View 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 )

View 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 },
}

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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

View 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 )

View 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()

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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 = ""

View 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"

View 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"

View 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"

View 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 = "Обмен не заверешен. Вы или ваш партнер затребовали больше денег чем у вас/у него есть!"

View 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"

View 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

View 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 )

View 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 )

View 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 )

View 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 )

View 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 )

View 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 )

View 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

View 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" )

View 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" )

View 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" )

View 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" )

View 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" )

View 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" )

View 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" )

View 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

View 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