Files
wnsrc/gamemodes/darkrp/plugins/better_zip_ties/cl_plugin.lua

446 lines
14 KiB
Lua
Raw Normal View History

2024-08-04 22:55:00 +03:00
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
PLUGIN.ZipTiedActors = {}
PLUGIN.blur = ix.util.GetMaterial("pp/blurscreen")
do
PLUGIN.ZipTiedAngles = {}
PLUGIN.ZipTiedAngles["ValveBiped.Bip01_L_UpperArm"] = Angle(20, 8.8, 0)
PLUGIN.ZipTiedAngles["ValveBiped.Bip01_L_UpperArm"] = Angle(20, 8.8, 0)
PLUGIN.ZipTiedAngles["ValveBiped.Bip01_L_Forearm"] = Angle(15, 0, 0)
PLUGIN.ZipTiedAngles["ValveBiped.Bip01_L_Hand"] = Angle(0, 0, 75)
PLUGIN.ZipTiedAngles["ValveBiped.Bip01_R_Forearm"] = Angle(-15, 0, 0)
PLUGIN.ZipTiedAngles["ValveBiped.Bip01_R_Hand"] = Angle(0, 0, -75)
PLUGIN.ZipTiedAngles["ValveBiped.Bip01_R_UpperArm"] = Angle(-20, 16.6, 0)
end
PLUGIN.BaggedActors = {}
PLUGIN.LocalCharIsBagged = false
local BAG_MODEL_BASE = "models/willardnetworks/m1nt/burlap_bag_" -- thanks kawa!
local BAG_MODEL_MALE = "male.mdl"
local BAG_MODEL_FEM = "female.mdl"
local BAG_POS_FEM = Vector(-56, -25.1, 2)
local BAG_ANGLES_FEM = Angle(182.6, 113.8, 88)
local BAG_POS_MALE = Vector(-46, -42, -0.5)
local BAG_ANGLES_MALE = Angle(170, 130, 90)
local ResponseSelectRemoveBag = 1
local ResponseSelectUntie = 2
local ResponseSelectDrag = 3
local ResponseSelectRelease = 4
local BlackScreenShader = {
[ "$pp_colour_addr" ] = 0,
[ "$pp_colour_addg" ] = 0,
[ "$pp_colour_addb" ] = 0,
[ "$pp_colour_brightness" ] = 0.04,
[ "$pp_colour_contrast" ] = 0.1,
[ "$pp_colour_colour" ] = 0,
[ "$pp_colour_mulr" ] = 0,
[ "$pp_colour_mulg" ] = 0,
[ "$pp_colour_mulb" ] = 0
}
hook.Add("HUDPaint", "draw_bag_on_head", function()
if (PLUGIN.LocalCharIsBagged) then
surface.SetMaterial(PLUGIN.blur)
surface.SetDrawColor(255, 255, 255, 255)
local x, y = 0, 0
for i = -0.2, 1, 0.2 do
PLUGIN.blur:SetFloat("$blur", i * 35) -- extreme blur
-- only enough to see large objects right in front of them
PLUGIN.blur:Recompute()
render.UpdateScreenEffectTexture()
surface.DrawTexturedRect(x * -1, y * -1, ScrW(), ScrH())
end
DrawColorModify(BlackScreenShader)
draw.SimpleText(
"Un sac est sur votre tête.",
"WNBleedingTextNoClamp",
ScrW() * 0.5,
ScrH() - SScaleMin(250 / 3),
Color(255, 78, 69, 255),
TEXT_ALIGN_CENTER
)
end
end)
net.Receive("WNZipTieEnter", function(len)
local targetId = net.ReadString()
local targetPly = player.GetBySteamID64(targetId)
if (!targetPly) then return end
if (IsValid(targetPly) and targetPly:IsRestricted()) then
PLUGIN.ZipTiedActors[targetId] = targetPly
end
end)
net.Receive("WNZipTieExit", function(len)
local targetId = net.ReadString()
local targetPly = player.GetBySteamID64(targetId)
if (!targetPly) then return end
if (IsValid(targetPly)) then
PLUGIN.ZipTiedActors[targetId] = nil
PLUGIN:SetZipTiedBoneAngles(targetPly, true) -- reset bone angles
end
end)
net.Receive("WNBagEnter", function(len)
local targetId = net.ReadString()
local targetPly = player.GetBySteamID64(targetId)
if (!targetPly) then
return
end
-- no need to draw a bag on our own character. the screen is black anyways
if (targetId == LocalPlayer():SteamID64()) then
PLUGIN.LocalCharIsBagged = true
return
end
if (IsValid(targetPly)) then
PLUGIN.BaggedActors[targetId] = {}
PLUGIN.BaggedActors[targetId].actor = targetPly
PLUGIN.BaggedActors[targetId].bagEnt = nil
PLUGIN:SetupBagHead(targetId)
end
end)
net.Receive("WNBagExit", function(len)
local targetId = net.ReadString()
local targetPly = player.GetBySteamID64(targetId)
if (!targetPly) then return end
if (targetId == LocalPlayer():SteamID64()) then
PLUGIN.LocalCharIsBagged = false
return
end
if (IsValid(targetPly)) then
PLUGIN:RemoveBagHead(targetId)
end
end)
net.Receive("WNDragOrBagPrompt", function(len)
local isBagged = net.ReadBool()
local isTied = net.ReadBool()
local isFollowing = net.ReadBool()
local frame = vgui.Create("Panel")
frame:SetSize(SScaleMin(372 / 3), SScaleMin(300 / 3))
frame:Center()
frame:MakePopup()
frame.Paint = function(self, w, h)
surface.DrawRect(0, 0, w, h)
surface.SetDrawColor(Color(111, 111, 136, 255 / 100 * 30))
surface.DrawRect(0, 0, w, h)
surface.DrawOutlinedRect(0, 0, w, h)
surface.SetMaterial(Material("willardnetworks/tabmenu/crafting/box_pattern.png", "noclamp"))
surface.DrawTexturedRectUV(0, 0, w, h, 0, 0, w / SScaleMin(300 / 3), h / SScaleMin(500 / 3))
end
local exit = frame:Add("DImageButton")
exit:SetImage("willardnetworks/tabmenu/navicons/exit.png")
exit:SetSize(SScaleMin(20 / 3), SScaleMin(20 / 3))
exit:SetPos(SScaleMin(345 / 3), SScaleMin(10 / 3))
exit:DockMargin(0, SScaleMin(15 / 3), SScaleMin(10 / 3), SScaleMin(15 / 3))
exit.DoClick = function()
net.Start("WNDragOrBagResponse")
net.WriteInt(0, 5)
net.SendToServer()
frame:Remove()
surface.PlaySound("helix/ui/press.wav")
end
local lastPosY = 100
local addButton = function (text, selection)
local button = vgui.Create("DButton", frame)
button:SetText(text)
button:SetFont("MenuFontNoClamp")
button:SetTextColor(Color(255,255,255))
button:CenterHorizontal()
button:SetPos((frame:GetWide() / 2) - (SScaleMin(150 / 3) / 2), lastPosY)
lastPosY = lastPosY + 60
button:SetSize(SScaleMin(150 / 3), SScaleMin(30 / 3))
button.Paint = function(self, w, h)
draw.RoundedBox(0, 0, 0, w, h, Color(63, 58, 115, 220))
surface.SetMaterial(Material("willardnetworks/tabmenu/crafting/box_pattern.png", "noclamp"))
surface.DrawTexturedRectUV(0, 0, w, h, 0, 0, w / SScaleMin(414 / 3), h / SScaleMin(677 / 3))
end
button.DoClick = function()
net.Start("WNDragOrBagResponse")
net.WriteInt(selection, 4)
net.SendToServer()
frame:Remove()
surface.PlaySound("helix/ui/press.wav")
end
end
if (isBagged) then
addButton("Enlever le sac", ResponseSelectRemoveBag)
end
if (isTied) then
addButton("Détacher", ResponseSelectUntie)
end
if (isFollowing) then
addButton("Relâcher", ResponseSelectRelease)
else
addButton("Trainer", ResponseSelectDrag)
end
end)
function PLUGIN:Think()
for _, actor in pairs(self.ZipTiedActors) do
PLUGIN:SetZipTiedBoneAngles(actor, false)
end
end
function PLUGIN:SetupBagHead(actorId)
local actor = self.BaggedActors[actorId].actor
if (!actor or !actor.IsFemale) then
return
end
local mdl_str = BAG_MODEL_BASE
if (actor:IsFemale()) then
mdl_str = mdl_str..BAG_MODEL_FEM
self.BaggedActors[actorId].pos = BAG_POS_FEM
self.BaggedActors[actorId].ang = BAG_ANGLES_FEM
else
mdl_str = mdl_str..BAG_MODEL_MALE
self.BaggedActors[actorId].pos = BAG_POS_MALE
self.BaggedActors[actorId].ang = BAG_ANGLES_MALE
end
local bag = ClientsideModel(
mdl_str,
RENDER_GROUP_OPAQUE_ENTITY
)
if (!bag or !bag.SetNoDraw) then
return
end
bag:SetNoDraw(true) -- remember, we're drawing manually here
if (!actor.GetModelScale or !actor.LookupBone) then
return
end
-- need to scale it up to set it to the model scale of the character (set by resizer plugin)
bag:SetModelScale(actor:GetModelScale() or 1)
local followBone = actor:LookupBone("ValveBiped.Bip01_Neck1")
-- for characters with nonbipedal models (or models with no neck), we cant draw head bags!
if (!followBone) then
return
end
bag:FollowBone(actor, followBone)
bag:SetPredictable(true)
bag:SetLocalPos(self.BaggedActors[actorId].pos)
bag:SetLocalAngles(self.BaggedActors[actorId].ang)
local headBone = actor:LookupBone("ValveBiped.Bip01_Head1")
if (!headBone) then
return
end
self.BaggedActors[actorId].bagEnt = bag
self.BaggedActors[actorId].headBone = headBone
end
function PLUGIN:RemoveBagHead(actorId)
if (!self.BaggedActors[actorId]) then
return
end
local actor = self.BaggedActors[actorId].actor
local bag = self.BaggedActors[actorId].bagEnt
if (IsValid(actor) and
actor.ManipulateBoneScale and
isnumber(self.BaggedActors[actorId].headBone)
) then
actor:ManipulateBoneScale(
self.BaggedActors[actorId].headBone, Vector(1, 1, 1))
-- reset head scale
end
if (bag and bag.Remove) then
bag:Remove()
end
self.BaggedActors[actorId] = nil
end
function PLUGIN:SetZipTiedBoneAngles(ply, bReset)
if (!IsValid(ply) or !ply.GetAbsVelocity or !ply.IsPlayer or !ply:IsPlayer()) then
return
end
if (bReset or ply:GetAbsVelocity() != Vector(0, 0, 0)) then
-- ManipulateBoneAngles sorta breaks on animations. So the hands behind the back thing should only be set when idle
local boneID
for bone, _ in pairs(self.ZipTiedAngles) do
boneID = ply:LookupBone(bone)
if (boneID) then
ply:ManipulateBoneAngles(boneID, Angle(0, 0, 0))
end
end
else
local boneID
for bone, angle in pairs(self.ZipTiedAngles) do
boneID = ply:LookupBone(bone)
if (boneID) then
ply:ManipulateBoneAngles(boneID, angle)
end
end
end
end
hook.Add("PostDrawOpaqueRenderables", "draw_head_bags", function(_)
-- I know this is a bit uncommon to do this in this particular hook
-- But for some reason when we ragdoll it just, stops calling post PVS hooks sometimes
-- Which means we can't use PostPlayerDraw here
local plyEnt
local pos
local ang
local ent
for id, actor in pairs(PLUGIN.BaggedActors) do
ent = actor.bagEnt
pos = actor.pos
ang = actor.ang
if (!ent or
!ent.SetLocalPos or
!isvector(pos) or
!isangle(ang) or
!isnumber(actor.headBone)
) then
-- yes we really do have to check this every frame
-- sorry (thanks garry)
PLUGIN:RemoveBagHead(id)
continue
else
plyEnt = ent:GetParent()
if (!plyEnt or !IsEntity(plyEnt) or !plyEnt:IsValid()) then
continue -- dont draw if there is no valid parent (yet)
end
-- call in a pcall so we can handle any of these lovely errors
local success, err = pcall(function()
-- local to the parent's bone
ent:SetLocalPos(pos)
ent:SetLocalAngles(ang)
ent:SetupBones()
ent:DrawModel()
-- do head shrinkage so it fits in da bag
plyEnt:ManipulateBoneScale(actor.headBone, Vector(0.1, 0.1, 0.1))
end)
if (!success) then
-- panic!
-- printing here in case we get any bug reports:
print("Error drawing head bag!")
print(err)
PLUGIN:RemoveBagHead(id)
end
end
end
end)
-- sanity function to check for ragdolls, players, and/or invalid players
local function checkBaggedEntList()
-- check all existing ragdolls to see if any of their players are bagged
-- if so then, we need to set them as bagged ;)
for _, ent in ipairs(ents.FindByClass("prop_ragdoll")) do
if (!ent or !IsEntity(ent) or !ent:IsValid()) then
-- NEVER trust gmod builtins
continue
end
local ply = ent:GetNetVar("player")
if (ply and
IsEntity(ply) and
IsValid(ply) and
ply.IsPlayer and
ply:IsPlayer() and
ply != LocalPlayer()
) then
local actor = PLUGIN.BaggedActors and PLUGIN.BaggedActors[ply:SteamID64()]
if (actor and istable(actor)) then
if (actor.bagEnt and
IsEntity(actor.bagEnt) and
actor.bagEnt:IsValid() and
actor.bagEnt:GetParent() != ent
) then
local followBone = ent:LookupBone("ValveBiped.Bip01_Neck1")
-- for characters with nonbipedal models (or models with no neck), we cant draw head bags!
if (!followBone) then
continue
end
actor.bagEnt:SetModelScale(ent:GetModelScale() or 1)
actor.bagEnt:FollowBone(ent, followBone)
end
end
end
end
-- check the BaggedActors table for any inconsistencies
for id, actor in pairs(PLUGIN.BaggedActors) do
if (!actor.actor or !IsEntity(actor.actor) or !actor.actor:IsValid()) then
PLUGIN:RemoveBagHead(id)
-- player isn't valid, for some reason
end
if (!actor.bagEnt or !IsEntity(actor.bagEnt) or !actor.bagEnt:IsValid()) then
PLUGIN:RemoveBagHead(id)
-- bag entity isn't valid, for some reason
end
local parent = actor.bagEnt:GetParent()
if (!IsEntity(parent) or !parent:IsValid()) then
-- happens when the character gets up after being ragdolled
PLUGIN:SetupBagHead(id) -- try to set up
-- if it is still not valid, remove
parent = actor.bagEnt:GetParent()
if (!IsEntity(parent) or !parent:IsValid()) then
PLUGIN:RemoveBagHead(id)
end
end
end
end
function PLUGIN:InitializedPlugins()
timer.Create("ValidateBaggedActors", 0.25, 0, function()
checkBaggedEntList()
end)
end