Initial commit
This commit is contained in:
128
gamemodes/darkrp/entities/weapons/pocket/cl_menu.lua
Normal file
128
gamemodes/darkrp/entities/weapons/pocket/cl_menu.lua
Normal file
@@ -0,0 +1,128 @@
|
||||
local meta = FindMetaTable("Player")
|
||||
local pocket = {}
|
||||
local frame
|
||||
local reload
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
Stubs
|
||||
---------------------------------------------------------------------------]]
|
||||
DarkRP.stub{
|
||||
name = "openPocketMenu",
|
||||
description = "Open the DarkRP pocket menu.",
|
||||
realm = "Client",
|
||||
parameters = {
|
||||
},
|
||||
returns = {
|
||||
},
|
||||
metatable = DarkRP
|
||||
}
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
Interface functions
|
||||
---------------------------------------------------------------------------]]
|
||||
function meta:getPocketItems()
|
||||
if self ~= LocalPlayer() then return nil end
|
||||
|
||||
return pocket
|
||||
end
|
||||
|
||||
function DarkRP.openPocketMenu()
|
||||
if IsValid(frame) and frame:IsVisible() then return end
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if not wep:IsValid() or wep:GetClass() ~= "pocket" then return end
|
||||
|
||||
if not pocket then
|
||||
pocket = {}
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if table.IsEmpty(pocket) then return end
|
||||
frame = vgui.Create("DFrame")
|
||||
|
||||
local count = GAMEMODE.Config.pocketitems or GM.Config.pocketitems
|
||||
frame:SetSize(345, 32 + 64 * math.ceil(count / 5) + 3 * math.ceil(count / 5))
|
||||
frame:SetTitle(DarkRP.getPhrase("drop_item"))
|
||||
frame.btnMaxim:SetVisible(false)
|
||||
frame.btnMinim:SetVisible(false)
|
||||
frame:SetDraggable(false)
|
||||
frame:MakePopup()
|
||||
frame:Center()
|
||||
|
||||
local Scroll = vgui.Create("DScrollPanel", frame)
|
||||
Scroll:Dock(FILL)
|
||||
|
||||
local sbar = Scroll:GetVBar()
|
||||
sbar:SetWide(3)
|
||||
frame.List = vgui.Create("DIconLayout", Scroll)
|
||||
frame.List:Dock(FILL)
|
||||
frame.List:SetSpaceY(3)
|
||||
frame.List:SetSpaceX(3)
|
||||
reload()
|
||||
frame:SetSkin(GAMEMODE.Config.DarkRPSkin)
|
||||
end
|
||||
net.Receive("DarkRP_PocketMenu", DarkRP.openPocketMenu)
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
UI
|
||||
---------------------------------------------------------------------------]]
|
||||
function reload()
|
||||
if not IsValid(frame) or not frame:IsVisible() then return end
|
||||
if not pocket or next(pocket) == nil then frame:Close() return end
|
||||
|
||||
local itemCount = table.Count(pocket)
|
||||
|
||||
frame.List:Clear()
|
||||
local items = {}
|
||||
|
||||
for k, v in pairs(pocket) do
|
||||
local ListItem = frame.List:Add("DPanel")
|
||||
ListItem:SetSize(64, 64)
|
||||
|
||||
local icon = vgui.Create("SpawnIcon", ListItem)
|
||||
icon:SetModel(v.model)
|
||||
icon:SetSize(64, 64)
|
||||
icon:SetTooltip()
|
||||
icon.DoClick = function(self)
|
||||
icon:SetTooltip()
|
||||
|
||||
net.Start("DarkRP_spawnPocket")
|
||||
net.WriteFloat(k)
|
||||
net.SendToServer()
|
||||
pocket[k] = nil
|
||||
|
||||
itemCount = itemCount - 1
|
||||
|
||||
if itemCount == 0 then
|
||||
frame:Close()
|
||||
return
|
||||
end
|
||||
|
||||
fn.Map(self.Remove, items)
|
||||
items = {}
|
||||
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
|
||||
wep:SetHoldType("pistol")
|
||||
timer.Simple(0.2, function()
|
||||
if wep:IsValid() then
|
||||
wep:SetHoldType("normal")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
table.insert(items, icon)
|
||||
end
|
||||
if itemCount < GAMEMODE.Config.pocketitems then
|
||||
for _ = 1, GAMEMODE.Config.pocketitems - itemCount do
|
||||
local ListItem = frame.List:Add("DPanel")
|
||||
ListItem:SetSize(64, 64)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function retrievePocket()
|
||||
pocket = net.ReadTable()
|
||||
reload()
|
||||
end
|
||||
net.Receive("DarkRP_Pocket", retrievePocket)
|
||||
146
gamemodes/darkrp/entities/weapons/pocket/shared.lua
Normal file
146
gamemodes/darkrp/entities/weapons/pocket/shared.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile("cl_menu.lua")
|
||||
include("sv_init.lua")
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
include("cl_menu.lua")
|
||||
end
|
||||
|
||||
SWEP.PrintName = "Pocket"
|
||||
SWEP.Slot = 1
|
||||
SWEP.SlotPos = 1
|
||||
SWEP.DrawAmmo = false
|
||||
SWEP.DrawCrosshair = true
|
||||
|
||||
SWEP.Base = "weapon_cs_base2"
|
||||
|
||||
SWEP.Author = "DarkRP Developers"
|
||||
SWEP.Instructions = "Left click to pick up\nRight click to drop\nReload to open the menu"
|
||||
SWEP.Contact = ""
|
||||
SWEP.Purpose = ""
|
||||
SWEP.IsDarkRPPocket = true
|
||||
|
||||
SWEP.IconLetter = ""
|
||||
|
||||
SWEP.ViewModelFOV = 62
|
||||
SWEP.ViewModelFlip = false
|
||||
SWEP.AnimPrefix = "rpg"
|
||||
SWEP.WorldModel = ""
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = true
|
||||
SWEP.Category = "DarkRP (Utility)"
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = 0
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = ""
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = 0
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = ""
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("normal")
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel() end
|
||||
|
||||
function SWEP:PreDrawViewModel(vm)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
if not SERVER then return true end
|
||||
|
||||
local Owner = self:GetOwner()
|
||||
Owner:DrawViewModel(true)
|
||||
Owner:DrawWorldModel(true)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
self:SetNextPrimaryFire(CurTime() + 0.2)
|
||||
|
||||
if not SERVER then return end
|
||||
|
||||
local Owner = self:GetOwner()
|
||||
|
||||
if not IsValid(Owner) then return end
|
||||
|
||||
local ent = Owner:GetEyeTrace().Entity
|
||||
local canPickup, message = hook.Call("canPocket", GAMEMODE, Owner, ent)
|
||||
|
||||
if not canPickup then
|
||||
if message then DarkRP.notify(Owner, 1, 4, message) end
|
||||
return
|
||||
end
|
||||
|
||||
Owner:addPocketItem(ent)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if not SERVER then return end
|
||||
|
||||
local Owner = self:GetOwner()
|
||||
|
||||
if not IsValid(Owner) then return end
|
||||
|
||||
local maxK = 0
|
||||
|
||||
for k in pairs(Owner:getPocketItems()) do
|
||||
if k < maxK then continue end
|
||||
maxK = k
|
||||
end
|
||||
|
||||
if maxK == 0 then
|
||||
DarkRP.notify(Owner, 1, 4, DarkRP.getPhrase("pocket_no_items"))
|
||||
return
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local canPickup, message = hook.Call("canDropPocketItem", nil, Owner, maxK, Owner.darkRPPocket[maxK])
|
||||
if canPickup == false then
|
||||
if message then DarkRP.notify(Owner, 1, 4, message) end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
Owner:dropPocketItem(maxK)
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if CLIENT then
|
||||
DarkRP.openPocketMenu()
|
||||
end
|
||||
|
||||
if SERVER and game.SinglePlayer() then
|
||||
net.Start("DarkRP_PocketMenu")
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
end
|
||||
|
||||
local meta = FindMetaTable("Player")
|
||||
DarkRP.stub{
|
||||
name = "getPocketItems",
|
||||
description = "Get a player's pocket items.",
|
||||
parameters = {
|
||||
},
|
||||
returns = {
|
||||
{
|
||||
name = "items",
|
||||
description = "A table containing crucial information about the items in the pocket.",
|
||||
type = "table"
|
||||
}
|
||||
},
|
||||
metatable = meta,
|
||||
realm = "Shared"
|
||||
}
|
||||
375
gamemodes/darkrp/entities/weapons/pocket/sv_init.lua
Normal file
375
gamemodes/darkrp/entities/weapons/pocket/sv_init.lua
Normal file
@@ -0,0 +1,375 @@
|
||||
local meta = FindMetaTable("Player")
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
Stubs
|
||||
---------------------------------------------------------------------------]]
|
||||
DarkRP.stub{
|
||||
name = "dropPocketItem",
|
||||
description = "Make the player drop an item from the pocket.",
|
||||
parameters = {
|
||||
{
|
||||
name = "ent",
|
||||
description = "The entity to drop.",
|
||||
type = "Entity",
|
||||
optional = false
|
||||
}
|
||||
},
|
||||
returns = {
|
||||
},
|
||||
metatable = meta
|
||||
}
|
||||
|
||||
DarkRP.stub{
|
||||
name = "addPocketItem",
|
||||
description = "Add an item to the pocket of the player.",
|
||||
parameters = {
|
||||
{
|
||||
name = "ent",
|
||||
description = "The entity to add.",
|
||||
type = "Entity",
|
||||
optional = false
|
||||
}
|
||||
},
|
||||
returns = {
|
||||
},
|
||||
metatable = meta
|
||||
}
|
||||
|
||||
DarkRP.stub{
|
||||
name = "removePocketItem",
|
||||
description = "Remove an item from the pocket of the player.",
|
||||
parameters = {
|
||||
{
|
||||
name = "item",
|
||||
description = "The index of the entity to remove from pocket.",
|
||||
type = "number",
|
||||
optional = false
|
||||
}
|
||||
},
|
||||
returns = {
|
||||
},
|
||||
metatable = meta
|
||||
}
|
||||
|
||||
DarkRP.hookStub{
|
||||
name = "canPocket",
|
||||
description = "Whether a player can pocket a certain item.",
|
||||
parameters = {
|
||||
{
|
||||
name = "ply",
|
||||
description = "The player.",
|
||||
type = "Player"
|
||||
},
|
||||
{
|
||||
name = "item",
|
||||
description = "The item to be pocketed.",
|
||||
type = "Entity"
|
||||
}
|
||||
},
|
||||
returns = {
|
||||
{
|
||||
name = "answer",
|
||||
description = "Whether the entity can be pocketed.",
|
||||
type = "boolean"
|
||||
},
|
||||
{
|
||||
name = "message",
|
||||
description = "The message to send to the player when the answer is false.",
|
||||
type = "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DarkRP.hookStub{
|
||||
name = "onPocketItemAdded",
|
||||
description = "Called when an entity is added to the pocket.",
|
||||
parameters = {
|
||||
{
|
||||
name = "ply",
|
||||
description = "The pocket holder.",
|
||||
type = "Player"
|
||||
},
|
||||
{
|
||||
name = "ent",
|
||||
description = "The entity.",
|
||||
type = "Entity"
|
||||
},
|
||||
{
|
||||
name = "serialized",
|
||||
description = "The serialized version of the pocketed entity.",
|
||||
type = "table"
|
||||
}
|
||||
},
|
||||
returns = {
|
||||
}
|
||||
}
|
||||
|
||||
DarkRP.hookStub{
|
||||
name = "canDropPocketItem",
|
||||
description = "Whether someone is allowed to drop something from their pocket.",
|
||||
parameters = {
|
||||
{
|
||||
name = "ply",
|
||||
description = "The pocket holder.",
|
||||
type = "Player"
|
||||
},
|
||||
{
|
||||
name = "item",
|
||||
description = "The pocket item's index in the pocket.",
|
||||
type = "table"
|
||||
},
|
||||
{
|
||||
name = "serialized",
|
||||
description = "The pocket item.",
|
||||
type = "table"
|
||||
}
|
||||
},
|
||||
returns = {
|
||||
{
|
||||
name = "answer",
|
||||
description = "Whether the item can be dropped.",
|
||||
type = "boolean"
|
||||
},
|
||||
{
|
||||
name = "message",
|
||||
description = "The message to send to the player when the answer is false.",
|
||||
type = "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DarkRP.hookStub{
|
||||
name = "onPocketItemRemoved",
|
||||
description = "Called when an item is removed from the pocket.",
|
||||
parameters = {
|
||||
{
|
||||
name = "ply",
|
||||
description = "The pocket holder.",
|
||||
type = "Player"
|
||||
},
|
||||
{
|
||||
name = "item",
|
||||
description = "The index of the pocket item.",
|
||||
type = "number"
|
||||
}
|
||||
},
|
||||
returns = {
|
||||
}
|
||||
}
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
Functions
|
||||
---------------------------------------------------------------------------]]
|
||||
-- workaround: GetNetworkVars doesn't give entities because the /duplicator/ doesn't want to save entities
|
||||
local function getDTVars(ent)
|
||||
if not ent.GetNetworkVars then return nil end
|
||||
local name, value = debug.getupvalue(ent.GetNetworkVars, 1)
|
||||
if name ~= "datatable" then
|
||||
ErrorNoHalt("Warning: Datatable cannot be stored properly in pocket. Tell a developer!")
|
||||
end
|
||||
|
||||
local res = {}
|
||||
|
||||
for k,v in pairs(value) do
|
||||
res[k] = v.GetFunc(ent, v.index)
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
local function serialize(ent)
|
||||
local serialized = duplicator.CopyEntTable(ent)
|
||||
serialized.DT = getDTVars(ent)
|
||||
|
||||
-- this function is also called in duplicator.CopyEntTable, but some
|
||||
-- entities change the DT vars of a copied entity (e.g. Lexic's moneypot)
|
||||
-- That is undone with the getDTVars function call.
|
||||
-- Re-call OnEntityCopyTableFinish assuming its implementation is pure.
|
||||
if ent.OnEntityCopyTableFinish then
|
||||
ent:OnEntityCopyTableFinish(serialized)
|
||||
end
|
||||
|
||||
return serialized
|
||||
end
|
||||
|
||||
local function deserialize(ply, item)
|
||||
local ent = ents.Create(item.Class)
|
||||
duplicator.DoGeneric(ent, item)
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
duplicator.DoGenericPhysics(ent, ply, item)
|
||||
table.Merge(ent:GetTable(), item)
|
||||
|
||||
if ent:IsWeapon() and ent.Weapon ~= nil and not ent.Weapon:IsValid() then ent.Weapon = ent end
|
||||
if ent.Entity ~= nil and not ent.Entity:IsValid() then ent.Entity = ent end
|
||||
|
||||
local trace = {}
|
||||
trace.start = ply:EyePos()
|
||||
trace.endpos = trace.start + ply:GetAimVector() * 85
|
||||
trace.filter = ply
|
||||
|
||||
local tr = util.TraceLine(trace)
|
||||
|
||||
ent:SetPos(tr.HitPos)
|
||||
|
||||
DarkRP.placeEntity(ent, tr, ply)
|
||||
|
||||
local phys = ent:GetPhysicsObject()
|
||||
timer.Simple(0, function() if phys:IsValid() then phys:Wake() end end)
|
||||
|
||||
if ent.OnDuplicated then
|
||||
ent:OnDuplicated(item)
|
||||
end
|
||||
|
||||
if ent.PostEntityPaste then
|
||||
ent:PostEntityPaste(ply, ent, {ent})
|
||||
end
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
local function dropAllPocketItems(ply)
|
||||
for k in pairs(ply.darkRPPocket or {}) do
|
||||
ply:dropPocketItem(k)
|
||||
end
|
||||
end
|
||||
|
||||
util.AddNetworkString("DarkRP_Pocket")
|
||||
local function sendPocketItems(ply)
|
||||
net.Start("DarkRP_Pocket")
|
||||
net.WriteTable(ply:getPocketItems())
|
||||
net.Send(ply)
|
||||
end
|
||||
|
||||
util.AddNetworkString("DarkRP_PocketMenu")
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
Interface functions
|
||||
---------------------------------------------------------------------------]]
|
||||
function meta:addPocketItem(ent)
|
||||
if not IsValid(ent) then DarkRP.error("Entity not valid", 2) end
|
||||
if ent.USED then return end
|
||||
|
||||
-- This item cannot be used until it has been removed
|
||||
ent.USED = true
|
||||
|
||||
local serialized = serialize(ent)
|
||||
|
||||
hook.Call("onPocketItemAdded", nil, self, ent, serialized)
|
||||
|
||||
ent.IsPocketing = true
|
||||
ent:Remove()
|
||||
|
||||
self.darkRPPocket = self.darkRPPocket or {}
|
||||
|
||||
local id = table.insert(self.darkRPPocket, serialized)
|
||||
sendPocketItems(self)
|
||||
return id
|
||||
end
|
||||
|
||||
function meta:removePocketItem(item)
|
||||
if not self.darkRPPocket or not self.darkRPPocket[item] then DarkRP.error("Player does not contain " .. item .. " in their pocket.", 2) end
|
||||
|
||||
hook.Call("onPocketItemRemoved", nil, self, item)
|
||||
|
||||
self.darkRPPocket[item] = nil
|
||||
sendPocketItems(self)
|
||||
end
|
||||
|
||||
function meta:dropPocketItem(item)
|
||||
if not self.darkRPPocket or not self.darkRPPocket[item] then DarkRP.error("Player does not contain " .. item .. " in their pocket.", 2) end
|
||||
|
||||
local id = self.darkRPPocket[item]
|
||||
local ent = deserialize(self, id)
|
||||
|
||||
-- reset USED status
|
||||
ent.USED = nil
|
||||
|
||||
hook.Call("onPocketItemDropped", nil, self, ent, item, id)
|
||||
|
||||
self:removePocketItem(item)
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
-- serverside implementation
|
||||
function meta:getPocketItems()
|
||||
self.darkRPPocket = self.darkRPPocket or {}
|
||||
|
||||
local res = {}
|
||||
for k, v in pairs(self.darkRPPocket) do
|
||||
res[k] = {
|
||||
model = v.Model,
|
||||
class = v.Class
|
||||
}
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
Commands
|
||||
---------------------------------------------------------------------------]]
|
||||
util.AddNetworkString("DarkRP_spawnPocket")
|
||||
net.Receive("DarkRP_spawnPocket", function(len, ply)
|
||||
local item = net.ReadFloat()
|
||||
if not ply.darkRPPocket or not ply.darkRPPocket[item] then return end
|
||||
local canPickup, message = hook.Call("canDropPocketItem", nil, ply, item, ply.darkRPPocket[item])
|
||||
if canPickup == false then
|
||||
if message then DarkRP.notify(ply, 1, 4, message) end
|
||||
sendPocketItems(ply)
|
||||
return
|
||||
end
|
||||
ply:dropPocketItem(item)
|
||||
end)
|
||||
|
||||
--[[---------------------------------------------------------------------------
|
||||
Hooks
|
||||
---------------------------------------------------------------------------]]
|
||||
function GAMEMODE:canPocket(ply, item)
|
||||
if not IsValid(item) then return false end
|
||||
local class = item:GetClass()
|
||||
|
||||
if item.Removed then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
if not item:CPPICanPickup(ply) then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
if item.jailWall then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
if GAMEMODE.Config.PocketBlacklist[class] then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
if string.find(class, "func_") then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
if item:IsRagdoll() then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
if item:IsNPC() then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
if not duplicator.IsAllowed(class) then return false, DarkRP.getPhrase("cannot_pocket_x") end
|
||||
-- Entities being held by the gravgun have different properties than
|
||||
-- entities not being held. One such property is mass, which is set to 1.
|
||||
-- The simple solution is to disallow pocketing entities that are being
|
||||
-- held.
|
||||
if item.DarkRPBeingGravGunHeldBy ~= nil then return false, DarkRP.getPhrase("cannot_pocket_gravgunned") end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ply:EyePos():DistToSqr(trace.HitPos) > 22500 then return false end
|
||||
|
||||
local ent = trace.Entity
|
||||
local phys = ent:GetPhysicsObject()
|
||||
if not phys:IsValid() then return false end
|
||||
|
||||
local mass = ent.RPOriginalMass and ent.RPOriginalMass or phys:GetMass()
|
||||
if mass > 100 then return false, DarkRP.getPhrase("object_too_heavy") end
|
||||
|
||||
local job = ply:Team()
|
||||
local max = RPExtraTeams[job].maxpocket or GAMEMODE.Config.pocketitems
|
||||
if table.Count(ply.darkRPPocket or {}) >= max then return false, DarkRP.getPhrase("pocket_full") end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- Drop pocket items on death
|
||||
hook.Add("PlayerDeath", "DropPocketItems", function(ply)
|
||||
if not GAMEMODE.Config.droppocketdeath or not ply.darkRPPocket then return end
|
||||
dropAllPocketItems(ply)
|
||||
end)
|
||||
|
||||
hook.Add("playerArrested", "DropPocketItems", function(ply)
|
||||
if not GAMEMODE.Config.droppocketarrest then return end
|
||||
dropAllPocketItems(ply)
|
||||
end)
|
||||
Reference in New Issue
Block a user